diff --git a/alas.py b/alas.py index dfe45797c..e8a81d6a1 100644 --- a/alas.py +++ b/alas.py @@ -400,6 +400,10 @@ class AzurLaneAutoScript: from module.minigame.minigame import Minigame Minigame(config=self.config, device=self.device).run() + def private_quarters(self): + from module.private_quarters.private_quarters import PrivateQuarters + PrivateQuarters(config=self.config, device=self.device).run() + def daily(self): from module.daily.daily import Daily Daily(config=self.config, device=self.device).run() diff --git a/assets/cn/combat_ui/PAUSE_Star.png b/assets/cn/combat_ui/PAUSE_Star.png new file mode 100644 index 000000000..07c231dd4 Binary files /dev/null and b/assets/cn/combat_ui/PAUSE_Star.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png new file mode 100644 index 000000000..f3dec5a65 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png new file mode 100644 index 000000000..273dbc166 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.png new file mode 100644 index 000000000..eafc19457 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png new file mode 100644 index 000000000..4907ee581 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png new file mode 100644 index 000000000..5cfbf8b10 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png new file mode 100644 index 000000000..a430a573c Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png new file mode 100644 index 000000000..f1fdf60bb Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png new file mode 100644 index 000000000..d970cb57b Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png new file mode 100644 index 000000000..3257d80b8 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png new file mode 100644 index 000000000..c21a74b65 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png new file mode 100644 index 000000000..1d44ccd39 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png new file mode 100644 index 000000000..a8ae2170a Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png new file mode 100644 index 000000000..ade0ee18d Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png new file mode 100644 index 000000000..dfad64a5d Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png new file mode 100644 index 000000000..34660449b Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png new file mode 100644 index 000000000..c9b20099f Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png new file mode 100644 index 000000000..1024c94a2 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png new file mode 100644 index 000000000..70e73456e Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png new file mode 100644 index 000000000..18963ccae Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png new file mode 100644 index 000000000..dc072d312 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png new file mode 100644 index 000000000..b01cecad4 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png new file mode 100644 index 000000000..8dc1c2bfc Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png new file mode 100644 index 000000000..e40a56697 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png new file mode 100644 index 000000000..00410e089 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png new file mode 100644 index 000000000..c41cad867 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png new file mode 100644 index 000000000..6340628b1 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png new file mode 100644 index 000000000..d7089394e Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png new file mode 100644 index 000000000..0cef5d8ba Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png new file mode 100644 index 000000000..bc1e5a557 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png new file mode 100644 index 000000000..976204bb2 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png differ diff --git a/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png new file mode 100644 index 000000000..f4c69bb19 Binary files /dev/null and b/assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png differ diff --git a/assets/cn/research/TEMPLATE_S8.png b/assets/cn/research/TEMPLATE_S8.png new file mode 100644 index 000000000..25f6675c4 Binary files /dev/null and b/assets/cn/research/TEMPLATE_S8.png differ diff --git a/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png b/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png new file mode 100644 index 000000000..22b2e7c47 Binary files /dev/null and b/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png differ diff --git a/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png b/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png new file mode 100644 index 000000000..83c578443 Binary files /dev/null and b/assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png differ diff --git a/assets/cn/ui/PQ_GOTO_MAIN.png b/assets/cn/ui/PQ_GOTO_MAIN.png new file mode 100644 index 000000000..54be25fd9 Binary files /dev/null and b/assets/cn/ui/PQ_GOTO_MAIN.png differ diff --git a/assets/cn/ui/PRIVATE_QUARTERS_CHECK.png b/assets/cn/ui/PRIVATE_QUARTERS_CHECK.png new file mode 100644 index 000000000..dd9a15534 Binary files /dev/null and b/assets/cn/ui/PRIVATE_QUARTERS_CHECK.png differ diff --git a/assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png b/assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png new file mode 100644 index 000000000..3d92cb507 Binary files /dev/null and b/assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png new file mode 100644 index 000000000..dc08007b1 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png new file mode 100644 index 000000000..62fb5be01 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.png new file mode 100644 index 000000000..eafc19457 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png new file mode 100644 index 000000000..4907ee581 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png new file mode 100644 index 000000000..5cfbf8b10 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png new file mode 100644 index 000000000..a430a573c Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png new file mode 100644 index 000000000..81a8845d3 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png new file mode 100644 index 000000000..9ca0a26f8 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png new file mode 100644 index 000000000..3257d80b8 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png new file mode 100644 index 000000000..8ae8f47b1 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png new file mode 100644 index 000000000..1d44ccd39 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png new file mode 100644 index 000000000..a8ae2170a Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png new file mode 100644 index 000000000..ade0ee18d Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png new file mode 100644 index 000000000..dfad64a5d Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png new file mode 100644 index 000000000..34660449b Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png new file mode 100644 index 000000000..c9b20099f Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png new file mode 100644 index 000000000..1024c94a2 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png new file mode 100644 index 000000000..70e73456e Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png new file mode 100644 index 000000000..1b9e93f32 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png new file mode 100644 index 000000000..1e7d50410 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png new file mode 100644 index 000000000..8dc1c2bfc Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png new file mode 100644 index 000000000..e40a56697 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png new file mode 100644 index 000000000..00410e089 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png new file mode 100644 index 000000000..331ea2d31 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png new file mode 100644 index 000000000..0ec48b84f Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png new file mode 100644 index 000000000..e8b552d60 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png new file mode 100644 index 000000000..0cef5d8ba Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png new file mode 100644 index 000000000..bc1e5a557 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png new file mode 100644 index 000000000..976204bb2 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png differ diff --git a/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png new file mode 100644 index 000000000..f4c69bb19 Binary files /dev/null and b/assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png differ diff --git a/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png b/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png new file mode 100644 index 000000000..22b2e7c47 Binary files /dev/null and b/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png differ diff --git a/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png b/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png new file mode 100644 index 000000000..83c578443 Binary files /dev/null and b/assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png differ diff --git a/assets/en/ui/PRIVATE_QUARTERS_CHECK.png b/assets/en/ui/PRIVATE_QUARTERS_CHECK.png new file mode 100644 index 000000000..83c572bf7 Binary files /dev/null and b/assets/en/ui/PRIVATE_QUARTERS_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png new file mode 100644 index 000000000..ce0004eb3 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png new file mode 100644 index 000000000..62fb5be01 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.png new file mode 100644 index 000000000..eafc19457 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png new file mode 100644 index 000000000..4907ee581 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png new file mode 100644 index 000000000..5cfbf8b10 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png new file mode 100644 index 000000000..a430a573c Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png new file mode 100644 index 000000000..726faefad Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png new file mode 100644 index 000000000..be37e359f Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png new file mode 100644 index 000000000..3257d80b8 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png new file mode 100644 index 000000000..8ae8f47b1 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png new file mode 100644 index 000000000..1d44ccd39 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png new file mode 100644 index 000000000..a8ae2170a Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png new file mode 100644 index 000000000..ade0ee18d Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png new file mode 100644 index 000000000..dfad64a5d Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png new file mode 100644 index 000000000..34660449b Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png new file mode 100644 index 000000000..c9b20099f Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png new file mode 100644 index 000000000..1024c94a2 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png new file mode 100644 index 000000000..70e73456e Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png new file mode 100644 index 000000000..ac96c33ba Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png new file mode 100644 index 000000000..1b9e93f32 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png new file mode 100644 index 000000000..1e7d50410 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png new file mode 100644 index 000000000..8dc1c2bfc Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png new file mode 100644 index 000000000..e40a56697 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png new file mode 100644 index 000000000..00410e089 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png new file mode 100644 index 000000000..12ffdc471 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png new file mode 100644 index 000000000..0ec48b84f Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png new file mode 100644 index 000000000..7a1c50b93 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png new file mode 100644 index 000000000..0cef5d8ba Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png new file mode 100644 index 000000000..cd78c648e Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png new file mode 100644 index 000000000..976204bb2 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png differ diff --git a/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png new file mode 100644 index 000000000..f4c69bb19 Binary files /dev/null and b/assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png differ diff --git a/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png b/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png new file mode 100644 index 000000000..22b2e7c47 Binary files /dev/null and b/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png differ diff --git a/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png b/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png new file mode 100644 index 000000000..83c578443 Binary files /dev/null and b/assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png differ diff --git a/assets/jp/ui/PRIVATE_QUARTERS_CHECK.png b/assets/jp/ui/PRIVATE_QUARTERS_CHECK.png new file mode 100644 index 000000000..e35c208a5 Binary files /dev/null and b/assets/jp/ui/PRIVATE_QUARTERS_CHECK.png differ diff --git a/assets/research_blueprint/dmitri.png b/assets/research_blueprint/dmitri.png new file mode 100644 index 000000000..3f2ffc002 Binary files /dev/null and b/assets/research_blueprint/dmitri.png differ diff --git a/assets/research_blueprint/goudenleeuw.png b/assets/research_blueprint/goudenleeuw.png new file mode 100644 index 000000000..752a031e4 Binary files /dev/null and b/assets/research_blueprint/goudenleeuw.png differ diff --git a/assets/research_blueprint/kansas.png b/assets/research_blueprint/kansas.png new file mode 100644 index 000000000..7f6757e92 Binary files /dev/null and b/assets/research_blueprint/kansas.png differ diff --git a/assets/research_blueprint/mecklenburg.png b/assets/research_blueprint/mecklenburg.png new file mode 100644 index 000000000..257bbe46f Binary files /dev/null and b/assets/research_blueprint/mecklenburg.png differ diff --git a/assets/research_blueprint/vittorio.png b/assets/research_blueprint/vittorio.png new file mode 100644 index 000000000..6e4868ed8 Binary files /dev/null and b/assets/research_blueprint/vittorio.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png new file mode 100644 index 000000000..dc08007b1 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png new file mode 100644 index 000000000..62fb5be01 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.BUTTON.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.png new file mode 100644 index 000000000..eafc19457 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png new file mode 100644 index 000000000..4907ee581 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png new file mode 100644 index 000000000..5cfbf8b10 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png new file mode 100644 index 000000000..a430a573c Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png new file mode 100644 index 000000000..81a8845d3 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png new file mode 100644 index 000000000..9ca0a26f8 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png new file mode 100644 index 000000000..3257d80b8 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png new file mode 100644 index 000000000..8ae8f47b1 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.BUTTON.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png new file mode 100644 index 000000000..1d44ccd39 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png new file mode 100644 index 000000000..a8ae2170a Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png new file mode 100644 index 000000000..ade0ee18d Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png new file mode 100644 index 000000000..dfad64a5d Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png new file mode 100644 index 000000000..34660449b Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png new file mode 100644 index 000000000..c9b20099f Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png new file mode 100644 index 000000000..1024c94a2 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png new file mode 100644 index 000000000..70e73456e Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png new file mode 100644 index 000000000..1b9e93f32 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png new file mode 100644 index 000000000..1e7d50410 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png new file mode 100644 index 000000000..8dc1c2bfc Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png new file mode 100644 index 000000000..e40a56697 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.BUTTON.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png new file mode 100644 index 000000000..00410e089 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png new file mode 100644 index 000000000..331ea2d31 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png new file mode 100644 index 000000000..0ec48b84f Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.BUTTON.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png new file mode 100644 index 000000000..e8b552d60 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png new file mode 100644 index 000000000..0cef5d8ba Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png new file mode 100644 index 000000000..bc1e5a557 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png new file mode 100644 index 000000000..976204bb2 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png differ diff --git a/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png new file mode 100644 index 000000000..f4c69bb19 Binary files /dev/null and b/assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png differ diff --git a/assets/tw/reward/MISSION_EMPTY.png b/assets/tw/reward/MISSION_EMPTY.png new file mode 100644 index 000000000..57d4a4b43 Binary files /dev/null and b/assets/tw/reward/MISSION_EMPTY.png differ diff --git a/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png b/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png new file mode 100644 index 000000000..22b2e7c47 Binary files /dev/null and b/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.BUTTON.png differ diff --git a/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png b/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png new file mode 100644 index 000000000..83c578443 Binary files /dev/null and b/assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png differ diff --git a/assets/tw/ui/PRIVATE_QUARTERS_CHECK.png b/assets/tw/ui/PRIVATE_QUARTERS_CHECK.png new file mode 100644 index 000000000..83c572bf7 Binary files /dev/null and b/assets/tw/ui/PRIVATE_QUARTERS_CHECK.png differ diff --git a/campaign/Readme.md b/campaign/Readme.md index a7de3903f..afa64fdae 100644 --- a/campaign/Readme.md +++ b/campaign/Readme.md @@ -52,6 +52,7 @@ To add a new event, add a new row in here, and run `python -m module.config.conf | 20250109 | war archives 20220224 cn | Abyssal Refrain | 深度回音 | Abyssal Refrain | 鳴動せし星霜の淵 | 深度回音 | | 20250320 | war archives 20220324 cn | Virtual Tower | 虚像构筑之塔 | Virtual Tower | 幻像の塔 | 虛像構築之塔 | | 20250417 | war archives 20220526 cn | Pledge of the Radiant Court | 泠誓光庭 | Pledge of the Radiant Court | 诚閃の剣 搖光の城 | 泠誓光庭 | +| 20250619 | war archives 20220728 cn | Aquilifer's Ballade | 雄鹰的叙事歌 | Aquilifer's Ballade | 鋼鷲の冒険譚 | 雄鷹的敘事歌 | | 20200227 | event 20200227 cn | Northern Overture | 北境序曲 | Northern Overture | 凍絶の北海 | - | | 20200312 | event 20200312 cn | The Solomon Ranger | 复刻斯图尔特的硝烟 | The Solomon Ranger Rerun | 南洋に靡く硝煙(復刻) | - | | 20200326 | event 20200326 cn | Microlayer Medley | 微层混合 | Microlayer Medley | 闇靄払う銀翼 | - | @@ -246,3 +247,4 @@ To add a new event, add a new row in here, and run `python -m module.config.conf | 20250612 | event 20250520 cn | A Rose on the High Tower | - | - | - | 高塔上的薔薇 | | 20250619 | event 20230525 cn | Confluence of Nothingness | 复刻空相交汇点 | Confluence of Nothingness Rerun | 覆天せし万象の塵(復刻) | - | | 20250626 | coalition 20250626 | The Neon City Investigator | 迷彩都市的寻踪者 | The Neon City Investigator | ネオンシティの探索者 | - | +| 20250703 | event 20250424 cn | Toward Tulipa’s Seas | - | - | - | 揚起鬱金之旗 | diff --git a/campaign/war_archives_20220728_cn/a1.py b/campaign/war_archives_20220728_cn/a1.py new file mode 100644 index 000000000..66793f16a --- /dev/null +++ b/campaign/war_archives_20220728_cn/a1.py @@ -0,0 +1,107 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger + +MAP = CampaignMap('A1') +MAP.shape = 'H8' +MAP.camera_data = ['D3', 'D6'] +MAP.camera_data_spawn_point = ['D6'] +MAP.map_data = """ + ++ -- -- -- -- ME -- -- + ++ -- ++ ++ Me -- ME -- + -- ME ++ ++ -- -- -- ++ + ME -- -- MB -- Me -- ME + -- -- MS -- -- MS -- -- + ME ++ ++ __ __ ++ ++ -- + -- -- Me -- -- Me -- -- + -- ME -- SP SP -- ME -- +""" +MAP.map_data_loop = """ + ++ -- -- -- -- ME -- -- + ++ -- ++ ++ Me -- ME -- + -- ME ++ ++ -- -- -- ++ + ME -- -- MB -- Me -- ME + -- -- MS -- -- MS -- -- + ME ++ -- __ __ ++ ++ ++ + -- -- Me -- -- Me -- -- + -- ME -- SP SP -- 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 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 1}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 1}, + {'battle': 3, 'enemy': 1, 'boss': 1}, + {'battle': 4, 'enemy': 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, \ +A8, B8, C8, D8, E8, F8, G8, H8, \ + = MAP.flatten() + + +class Config: + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['DD', 'Juno_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (120, 255 - 17), + 'width': (1.5, 10), + 'prominence': 10, + 'distance': 35, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 17, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } + HOMO_EDGE_COLOR_RANGE = (0, 17) + MAP_ENSURE_EDGE_INSIGHT_CORNER = 'bottom' + MAP_ENEMY_GENRE_DETECTION_SCALING = { + 'DD': 1.111, + 'CL': 1.111, + 'CA': 1.111, + 'CV': 1.111, + 'BB': 1.111, + } + MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'Treasure', 'Vestal_ghost'] + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_3(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/a2.py b/campaign/war_archives_20220728_cn/a2.py new file mode 100644 index 000000000..58e121e30 --- /dev/null +++ b/campaign/war_archives_20220728_cn/a2.py @@ -0,0 +1,85 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .a1 import Config as ConfigBase + +MAP = CampaignMap('A2') +MAP.shape = 'L7' +MAP.camera_data = ['D3', 'F5', 'H5'] +MAP.camera_data_spawn_point = ['D2'] +MAP.map_data = """ + -- SP -- ++ ++ ++ Me -- -- -- -- -- + SP -- -- -- -- MS -- ++ ++ -- ++ ++ + -- -- Me MS -- -- -- ++ ++ ME ++ ++ + Me -- -- -- ++ ++ -- -- ME -- -- MB + -- ++ ++ Me ++ ++ Me -- __ -- ME -- + -- ++ ++ -- -- ME -- -- -- -- ME ++ + -- -- ME -- -- -- -- ME ++ ME -- -- +""" +MAP.map_data_loop = """ + -- SP -- ++ ++ ++ Me -- -- -- -- -- + SP -- -- -- -- MS -- -- ++ -- ++ ++ + -- -- Me MS -- -- -- -- ++ ME -- ++ + Me -- -- -- ++ ++ ++ -- ME -- -- MB + -- ++ ++ Me -- -- Me -- __ -- ME -- + -- ++ ++ -- -- 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 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 1}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 1}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1, 'boss': 1}, +] +A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, \ +A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, K2, L2, \ +A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, K3, L3, \ +A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, \ +A5, B5, C5, D5, E5, F5, G5, H5, I5, J5, K5, L5, \ +A6, B6, C6, D6, E6, F6, G6, H6, I6, J6, K6, L6, \ +A7, B7, C7, D7, E7, F7, G7, H7, I7, J7, K7, L7, \ + = MAP.flatten() + + +class Config(ConfigBase): + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['CL', 'Juno_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (1.226, 1.249) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.186, 1.208) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.151, 1.172) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/a3.py b/campaign/war_archives_20220728_cn/a3.py new file mode 100644 index 000000000..096c7f286 --- /dev/null +++ b/campaign/war_archives_20220728_cn/a3.py @@ -0,0 +1,89 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .a1 import Config as ConfigBase + +MAP = CampaignMap('A3') +MAP.shape = 'I8' +MAP.camera_data = ['D3', 'E6'] +MAP.camera_data_spawn_point = ['E2'] +MAP.map_data = """ + -- -- -- -- SP SP -- -- -- + -- ME ++ ++ -- -- ++ ++ -- + ME -- -- MS -- ME ++ ++ -- + -- ++ ++ Me -- MS ME Me -- + -- ++ ++ -- __ -- -- -- ME + -- -- Me -- ME Me ME ME -- + -- ++ ++ -- -- -- ME -- -- + -- -- ++ -- MB -- ++ ++ ++ +""" +MAP.map_data_loop = """ + -- -- -- -- SP SP -- -- -- + -- ME ++ -- -- -- ++ ++ -- + ME -- -- MS -- ME ++ ++ -- + -- -- ++ Me -- MS ME Me -- + -- -- ++ -- __ -- -- -- ME + -- -- Me -- ME Me ME ME -- + -- ++ ++ -- -- -- ME -- -- + -- -- ++ -- MB -- ++ ++ ++ +""" +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': 2, 'siren': 1}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 1}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1, '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 = ['CA', 'Neptune_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (1.226, 1.249) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.186, 1.208) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.151, 1.172) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/b1.py b/campaign/war_archives_20220728_cn/b1.py new file mode 100644 index 000000000..55ccb0371 --- /dev/null +++ b/campaign/war_archives_20220728_cn/b1.py @@ -0,0 +1,101 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger + +MAP = CampaignMap('B1') +MAP.shape = 'J8' +MAP.camera_data = ['E2', 'E6', 'G4'] +MAP.camera_data_spawn_point = ['D2'] +MAP.map_data = """ + -- -- ME -- -- Me -- -- ++ ++ + -- -- ++ MS -- -- Me -- MB ++ + SP -- -- -- MS ++ ++ -- -- ME + SP -- -- -- MS ++ ++ ME -- -- + -- -- ++ MS __ ME Me -- -- ME + -- Me ++ Me -- -- -- -- 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 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 1}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 2, 'boss': 1}, + {'battle': 5, 'enemy': 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: + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['Neptune_ghost', 'LeMars_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (120, 255 - 17), + 'width': (1.5, 10), + 'prominence': 10, + 'distance': 35, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 17, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } + HOMO_EDGE_COLOR_RANGE = (0, 17) + MAP_ENSURE_EDGE_INSIGHT_CORNER = 'bottom' + MAP_ENEMY_GENRE_DETECTION_SCALING = { + 'DD': 1.111, + 'CL': 1.111, + 'CA': 1.111, + 'CV': 1.111, + 'BB': 1.111, + } + MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'Treasure', 'Vestal_ghost'] + MAP_SWIPE_MULTIPLY = (1.141, 1.163) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.104, 1.124) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.071, 1.091) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/b2.py b/campaign/war_archives_20220728_cn/b2.py new file mode 100644 index 000000000..a4e19d9fc --- /dev/null +++ b/campaign/war_archives_20220728_cn/b2.py @@ -0,0 +1,80 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .b1 import Config as ConfigBase + +MAP = CampaignMap('B2') +MAP.shape = 'I8' +MAP.camera_data = ['D2', 'D3', 'E3', 'E6'] +MAP.camera_data_spawn_point = ['E6'] +MAP.map_data = """ + -- ME -- -- -- ME -- ME -- + ++ -- -- ME -- -- ++ -- ME + ++ ME Me ++ Me -- -- -- Me + -- -- -- ME -- -- -- MS -- + MB -- __ -- -- MS -- -- ++ + -- -- -- Me -- ++ Me -- -- + ++ ++ ME -- MS -- -- -- SP + ++ ++ -- ME -- ME -- 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 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 1}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 2}, + {'battle': 5, 'enemy': 1, '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 = ['Neptune_ghost', 'LeMars_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (1.038, 1.058) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.004, 1.023) + MAP_SWIPE_MULTIPLY_MAATOUCH = (0.975, 0.993) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_5(self): + return self.fleet_boss.clear_boss() diff --git a/campaign/war_archives_20220728_cn/b3.py b/campaign/war_archives_20220728_cn/b3.py new file mode 100644 index 000000000..c3898eb36 --- /dev/null +++ b/campaign/war_archives_20220728_cn/b3.py @@ -0,0 +1,83 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .b1 import Config as ConfigBase + +MAP = CampaignMap('B3') +MAP.shape = 'I9' +MAP.camera_data = ['D3', 'D5', 'F3', 'F5'] +MAP.camera_data_spawn_point = ['E7'] +MAP.map_data = """ + -- ++ ++ ++ -- ++ ++ ++ -- + -- ME -- -- ME -- -- ME -- + ME -- -- ME -- ME -- -- ME + ++ -- Me ++ -- ++ Me -- ++ + ME -- -- -- MB -- -- -- ME + -- -- Me ++ MS ++ Me -- -- + ME -- MS -- __ -- MS -- 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 50 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 2}, + {'battle': 5, 'enemy': 1, '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, \ +A9, B9, C9, D9, E9, F9, G9, H9, I9, \ + = MAP.flatten() + + +class Config(ConfigBase): + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['LeMars_ghost', 'Hermes_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (0.994, 1.013) + MAP_SWIPE_MULTIPLY_MINITOUCH = (0.961, 0.979) + MAP_SWIPE_MULTIPLY_MAATOUCH = (0.933, 0.950) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_5(self): + return self.fleet_boss.clear_boss() diff --git a/campaign/war_archives_20220728_cn/c1.py b/campaign/war_archives_20220728_cn/c1.py new file mode 100644 index 000000000..989033416 --- /dev/null +++ b/campaign/war_archives_20220728_cn/c1.py @@ -0,0 +1,107 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger + +MAP = CampaignMap('C1') +MAP.shape = 'H8' +MAP.camera_data = ['D3', 'D6'] +MAP.camera_data_spawn_point = ['D6'] +MAP.map_data = """ + ++ -- -- -- -- ME -- -- + ++ -- ++ ++ Me -- ME -- + -- ME ++ ++ -- -- -- ++ + ME -- -- MB -- Me -- ME + -- -- MS -- -- MS -- -- + ME ++ ++ __ __ ++ ++ -- + -- -- Me -- -- Me -- -- + -- ME -- SP SP -- ME -- +""" +MAP.map_data_loop = """ + ++ -- -- -- -- ME -- -- + ++ -- ++ ++ Me -- ME -- + -- ME ++ ++ -- -- -- ++ + ME -- -- MB -- Me -- ME + -- -- MS -- -- MS -- -- + ME ++ -- __ __ ++ ++ ++ + -- -- Me -- -- Me -- -- + -- ME -- SP SP -- 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 +""" +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, '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, \ +A8, B8, C8, D8, E8, F8, G8, H8, \ + = MAP.flatten() + + +class Config: + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['CL', 'CA', 'Juno_ghost', 'Neptune_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (120, 255 - 17), + 'width': (1.5, 10), + 'prominence': 10, + 'distance': 35, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 17, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } + HOMO_EDGE_COLOR_RANGE = (0, 17) + MAP_ENSURE_EDGE_INSIGHT_CORNER = 'bottom' + MAP_ENEMY_GENRE_DETECTION_SCALING = { + 'DD': 1.111, + 'CL': 1.111, + 'CA': 1.111, + 'CV': 1.111, + 'BB': 1.111, + } + MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'Treasure', 'Vestal_ghost'] + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/c2.py b/campaign/war_archives_20220728_cn/c2.py new file mode 100644 index 000000000..d4d96232c --- /dev/null +++ b/campaign/war_archives_20220728_cn/c2.py @@ -0,0 +1,86 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .c1 import Config as ConfigBase + +MAP = CampaignMap('C2') +MAP.shape = 'L7' +MAP.camera_data = ['D3', 'F5', 'H5'] +MAP.camera_data_spawn_point = ['D2'] +MAP.map_data = """ + -- SP -- ++ ++ ++ Me -- -- -- -- -- + SP -- -- -- -- MS -- ++ ++ -- ++ ++ + -- -- Me MS -- -- -- ++ ++ ME ++ ++ + Me -- -- -- ++ ++ -- -- ME -- -- MB + -- ++ ++ Me ++ ++ Me -- __ -- ME -- + -- ++ ++ -- -- ME -- -- -- -- ME ++ + -- -- ME -- -- -- -- ME ++ ME -- -- +""" +MAP.map_data_loop = """ + -- SP -- ++ ++ ++ Me -- -- -- -- -- + SP -- -- -- -- MS -- -- ++ -- ++ ++ + -- -- Me MS -- -- -- -- ++ ME -- ++ + Me -- -- -- ++ ++ ++ -- ME -- -- MB + -- ++ ++ Me -- -- Me -- __ -- ME -- + -- ++ ++ -- -- 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 +""" +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, 'boss': 1}, +] +A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, \ +A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, K2, L2, \ +A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, K3, L3, \ +A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, L4, \ +A5, B5, C5, D5, E5, F5, G5, H5, I5, J5, K5, L5, \ +A6, B6, C6, D6, E6, F6, G6, H6, I6, J6, K6, L6, \ +A7, B7, C7, D7, E7, F7, G7, H7, I7, J7, K7, L7, \ + = MAP.flatten() + + +class Config(ConfigBase): + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['CA', 'BB', 'Juno_ghost', 'Neptune_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_WALK_USE_CURRENT_FLEET = True + MAP_SWIPE_MULTIPLY = (1.226, 1.249) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.186, 1.208) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.151, 1.172) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() diff --git a/campaign/war_archives_20220728_cn/c3.py b/campaign/war_archives_20220728_cn/c3.py new file mode 100644 index 000000000..3e1ea62e6 --- /dev/null +++ b/campaign/war_archives_20220728_cn/c3.py @@ -0,0 +1,91 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .c1 import Config as ConfigBase + +MAP = CampaignMap('C3') +MAP.shape = 'I8' +MAP.camera_data = ['D3', 'E6'] +MAP.camera_data_spawn_point = ['E2'] +MAP.map_data = """ + -- -- -- -- SP SP -- -- -- + -- ME ++ ++ -- -- ++ ++ -- + ME -- -- MS -- ME ++ ++ -- + -- ++ ++ Me -- MS ME Me -- + -- ++ ++ -- __ -- -- -- ME + -- -- Me -- ME Me ME ME -- + -- ++ ++ -- -- -- ME -- -- + -- -- ++ -- MB -- ++ ++ ++ +""" +MAP.map_data_loop = """ + -- -- -- -- SP SP -- -- -- + -- ME ++ -- -- -- ++ ++ -- + ME -- -- MS -- ME ++ ++ -- + -- -- ++ Me -- MS ME Me -- + -- -- ++ -- __ -- -- -- ME + -- -- Me -- ME Me ME ME -- + -- ++ ++ -- -- -- ME -- -- + -- -- ++ -- MB -- ++ ++ ++ +""" +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': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1}, + {'battle': 5, '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 = ['CA', 'BB', 'Juno_ghost', 'Neptune_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_WALK_USE_CURRENT_FLEET = True + MAP_SWIPE_MULTIPLY = (1.226, 1.249) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.186, 1.208) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.151, 1.172) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_5(self): + return self.fleet_boss.clear_boss() diff --git a/campaign/war_archives_20220728_cn/d1.py b/campaign/war_archives_20220728_cn/d1.py new file mode 100644 index 000000000..83ae36421 --- /dev/null +++ b/campaign/war_archives_20220728_cn/d1.py @@ -0,0 +1,101 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger + +MAP = CampaignMap('D1') +MAP.shape = 'J8' +MAP.camera_data = ['E2', 'E6', 'G4'] +MAP.camera_data_spawn_point = ['D2'] +MAP.map_data = """ + -- -- ME -- -- Me -- -- ++ ++ + -- -- ++ MS -- -- Me -- MB ++ + SP -- -- -- MS ++ ++ -- -- ME + SP -- -- -- MS ++ ++ ME -- -- + -- -- ++ MS __ ME Me -- -- ME + -- Me ++ Me -- -- -- -- 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 +""" +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 2}, + {'battle': 5, 'enemy': 1, '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: + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['Neptune_ghost', 'LeMars_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (120, 255 - 17), + 'width': (1.5, 10), + 'prominence': 10, + 'distance': 35, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 17, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } + HOMO_EDGE_COLOR_RANGE = (0, 17) + MAP_ENSURE_EDGE_INSIGHT_CORNER = 'bottom' + MAP_ENEMY_GENRE_DETECTION_SCALING = { + 'DD': 1.111, + 'CL': 1.111, + 'CA': 1.111, + 'CV': 1.111, + 'BB': 1.111, + } + MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'Treasure', 'Vestal_ghost'] + MAP_SWIPE_MULTIPLY = (1.141, 1.163) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.104, 1.124) + MAP_SWIPE_MULTIPLY_MAATOUCH = (1.071, 1.091) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0): + return True + + return self.battle_default() + + def battle_5(self): + return self.fleet_boss.clear_boss() diff --git a/campaign/war_archives_20220728_cn/d2.py b/campaign/war_archives_20220728_cn/d2.py new file mode 100644 index 000000000..b8064bfa0 --- /dev/null +++ b/campaign/war_archives_20220728_cn/d2.py @@ -0,0 +1,89 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .d1 import Config as ConfigBase + +MAP = CampaignMap('D2') +MAP.shape = 'I8' +MAP.camera_data = ['D2', 'D3', 'E3', 'E6'] +MAP.camera_data_spawn_point = ['E6'] +MAP.map_data = """ + -- ME -- -- -- ME -- ME -- + ++ -- -- ME -- -- ++ -- ME + ++ ME Me ++ Me -- -- -- Me + -- -- -- ME -- -- -- MS -- + MB -- __ -- -- MS -- -- ++ + -- -- -- Me -- ++ Me -- -- + ++ ++ ME -- MS -- -- -- SP + ++ ++ -- ME -- ME -- 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 +""" +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': 2}, + {'battle': 5, 'enemy': 1}, + {'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 = ['LeMars_ghost', 'Hermes_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (1.038, 1.058) + MAP_SWIPE_MULTIPLY_MINITOUCH = (1.004, 1.023) + MAP_SWIPE_MULTIPLY_MAATOUCH = (0.975, 0.993) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1): + return True + + return self.battle_default() + + def battle_5(self): + if self.clear_siren(): + return True + 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() diff --git a/campaign/war_archives_20220728_cn/d3.py b/campaign/war_archives_20220728_cn/d3.py new file mode 100644 index 000000000..f326a67c7 --- /dev/null +++ b/campaign/war_archives_20220728_cn/d3.py @@ -0,0 +1,92 @@ +from ..campaign_war_archives.campaign_base import CampaignBase +from module.map.map_base import CampaignMap +from module.map.map_grids import SelectedGrids, RoadGrids +from module.logger import logger +from .d1 import Config as ConfigBase + +MAP = CampaignMap('D3') +MAP.shape = 'I9' +MAP.camera_data = ['D3', 'D5', 'F3', 'F5'] +MAP.camera_data_spawn_point = ['E7'] +MAP.map_data = """ + -- ++ ++ ++ -- ++ ++ ++ -- + -- ME -- -- ME -- -- ME -- + ME -- -- ME -- ME -- -- ME + ++ -- Me ++ -- ++ Me -- ++ + ME -- -- -- MB -- -- -- ME + -- -- Me ++ MS ++ Me -- -- + ME -- MS -- __ -- MS -- 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 50 +""" +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': 2}, + {'battle': 5, 'enemy': 1}, + {'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, \ +A9, B9, C9, D9, E9, F9, G9, H9, I9, \ + = MAP.flatten() + + +class Config(ConfigBase): + # ===== Start of generated config ===== + MAP_SIREN_TEMPLATE = ['LeMars_ghost', 'Hermes_ghost'] + MOVABLE_ENEMY_TURN = (2,) + MAP_HAS_SIREN = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_MAP_STORY = True + MAP_HAS_FLEET_STEP = True + MAP_HAS_AMBUSH = False + MAP_HAS_MYSTERY = False + # ===== End of generated config ===== + + MAP_SWIPE_MULTIPLY = (0.994, 1.013) + MAP_SWIPE_MULTIPLY_MINITOUCH = (0.961, 0.979) + MAP_SWIPE_MULTIPLY_MAATOUCH = (0.933, 0.950) + + +class Campaign(CampaignBase): + MAP = MAP + ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C' + + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1): + return True + + return self.battle_default() + + def battle_5(self): + if self.clear_siren(): + return True + 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() diff --git a/config/template.json b/config/template.json index 27f141839..2f6c056ec 100644 --- a/config/template.json +++ b/config/template.json @@ -1932,7 +1932,7 @@ }, "Campaign": { "Name": "D3", - "Event": "war_archives_20220526_cn", + "Event": "war_archives_20220728_cn", "Mode": "normal", "UseClearMode": true, "UseFleetLock": true, @@ -2544,8 +2544,8 @@ "UseCoin": "always_use", "UsePart": "always_use", "AllowDelay": true, - "PresetFilter": "series_7_blueprint_la9", - "CustomFilter": "S7-DR0.5 > S7-PRY0.5 > S7-Q0.5 > S7-H0.5 > Q0.5 > S7-DR2.5\n> S7-G1.5 > S7-Q1 > S7-DR5 > 0.5 > S7-G4 > S7-Q2 > S7-PRY2.5 > reset\n> S7-DR8 > Q1 > 1 > S7-E-315 > S7-G2.5 > G1.5 > 1.5 > S7-E-031\n> S7-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S7-PRY5\n> S7-PRY8 > Q4 > G4 > 4 > S7-C6 > DR5 > PRY5 > 5 > C6 > 6 > S7-C8\n> S7-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12" + "PresetFilter": "series_8_blueprint_305", + "CustomFilter": "S8-DR0.5 > S8-PRY0.5 > S8-Q0.5 > S8-H0.5 > Q0.5 > S8-DR2.5\n> S8-G1.5 > S8-Q1 > S8-DR5 > 0.5 > S8-G4 > S8-Q2 > S8-PRY2.5 > reset\n> S8-DR8 > Q1 > 1 > S8-E-315 > S8-G2.5 > G1.5 > 1.5 > S8-E-031\n> S8-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-PRY5\n> S8-PRY8 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8\n> S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12" }, "Storage": { "Storage": {} @@ -2898,6 +2898,24 @@ "Storage": {} } }, + "PrivateQuarters": { + "Scheduler": { + "Enable": false, + "NextRun": "2020-01-01 00:00:00", + "Command": "PrivateQuarters", + "SuccessInterval": 30, + "FailureInterval": 30, + "ServerUpdate": "00:00" + }, + "PrivateQuarters": { + "BuyRoses": true, + "TargetInteract": true, + "TargetShip": "anchorage" + }, + "Storage": { + "Storage": {} + } + }, "OpsiGeneral": { "OpsiGeneral": { "UseLogger": true, diff --git a/module/combat/combat.py b/module/combat/combat.py index aeac85d4d..d138c3911 100644 --- a/module/combat/combat.py +++ b/module/combat/combat.py @@ -106,6 +106,9 @@ class Combat(Level, HPBalancer, Retirement, SubmarineCall, CombatAuto, CombatMan # PAUSE_Pharaoh has random animation, assets should avoid the area in the middle and use match_luma if PAUSE_Pharaoh.match_luma(self.device.image, offset=(10, 10)): return PAUSE_Pharaoh + # PAUSE_Star may get detected as PAUSE_Nurse, should before it + if PAUSE_Star.match_luma(self.device.image, offset=(10, 10)): + return PAUSE_Star if PAUSE_Nurse.match_luma(self.device.image, offset=(10, 10)): return PAUSE_Nurse # PAUSE_Devil is in red diff --git a/module/combat_ui/assets.py b/module/combat_ui/assets.py index 622cf84c2..748e5dd31 100644 --- a/module/combat_ui/assets.py +++ b/module/combat_ui/assets.py @@ -16,6 +16,7 @@ PAUSE_New = Button(area={'cn': (1231, 29, 1253, 56), 'en': (1231, 29, 1253, 56), PAUSE_Nurse = Button(area={'cn': (1236, 33, 1251, 50), 'en': (1236, 33, 1251, 50), 'jp': (1236, 33, 1251, 50), 'tw': (1236, 33, 1251, 50)}, color={'cn': (200, 206, 209), 'en': (200, 206, 209), 'jp': (200, 206, 209), 'tw': (200, 206, 209)}, button={'cn': (1236, 33, 1251, 50), 'en': (1236, 33, 1251, 50), 'jp': (1236, 33, 1251, 50), 'tw': (1236, 33, 1251, 50)}, file={'cn': './assets/cn/combat_ui/PAUSE_Nurse.png', 'en': './assets/cn/combat_ui/PAUSE_Nurse.png', 'jp': './assets/cn/combat_ui/PAUSE_Nurse.png', 'tw': './assets/cn/combat_ui/PAUSE_Nurse.png'}) PAUSE_Pharaoh = Button(area={'cn': (1229, 55, 1259, 62), 'en': (1229, 55, 1259, 62), 'jp': (1229, 55, 1259, 62), 'tw': (1229, 55, 1259, 62)}, color={'cn': (164, 119, 78), 'en': (164, 119, 78), 'jp': (164, 119, 78), 'tw': (164, 119, 78)}, button={'cn': (1229, 55, 1259, 62), 'en': (1229, 55, 1259, 62), 'jp': (1229, 55, 1259, 62), 'tw': (1229, 55, 1259, 62)}, file={'cn': './assets/cn/combat_ui/PAUSE_Pharaoh.png', 'en': './assets/cn/combat_ui/PAUSE_Pharaoh.png', 'jp': './assets/cn/combat_ui/PAUSE_Pharaoh.png', 'tw': './assets/cn/combat_ui/PAUSE_Pharaoh.png'}) PAUSE_Seaside = Button(area={'cn': (1214, 31, 1239, 59), 'en': (1214, 31, 1239, 59), 'jp': (1214, 31, 1239, 59), 'tw': (1214, 31, 1239, 59)}, color={'cn': (172, 196, 212), 'en': (172, 196, 212), 'jp': (172, 196, 212), 'tw': (172, 196, 212)}, button={'cn': (1214, 31, 1239, 59), 'en': (1214, 31, 1239, 59), 'jp': (1214, 31, 1239, 59), 'tw': (1214, 31, 1239, 59)}, file={'cn': './assets/cn/combat_ui/PAUSE_Seaside.png', 'en': './assets/cn/combat_ui/PAUSE_Seaside.png', 'jp': './assets/cn/combat_ui/PAUSE_Seaside.png', 'tw': './assets/cn/combat_ui/PAUSE_Seaside.png'}) +PAUSE_Star = Button(area={'cn': (1234, 36, 1250, 57), 'en': (1234, 36, 1250, 57), 'jp': (1234, 36, 1250, 57), 'tw': (1234, 36, 1250, 57)}, color={'cn': (169, 179, 179), 'en': (169, 179, 179), 'jp': (169, 179, 179), 'tw': (169, 179, 179)}, button={'cn': (1234, 36, 1250, 57), 'en': (1234, 36, 1250, 57), 'jp': (1234, 36, 1250, 57), 'tw': (1234, 36, 1250, 57)}, file={'cn': './assets/cn/combat_ui/PAUSE_Star.png', 'en': './assets/cn/combat_ui/PAUSE_Star.png', 'jp': './assets/cn/combat_ui/PAUSE_Star.png', 'tw': './assets/cn/combat_ui/PAUSE_Star.png'}) QUIT = Button(area={'cn': (420, 490, 593, 548), 'en': (473, 508, 567, 532), 'jp': (433, 490, 606, 547), 'tw': (433, 490, 606, 547)}, color={'cn': (199, 122, 114), 'en': (216, 168, 164), 'jp': (196, 120, 113), 'tw': (200, 126, 118)}, button={'cn': (420, 490, 593, 548), 'en': (473, 508, 567, 532), 'jp': (433, 490, 606, 547), 'tw': (433, 490, 606, 547)}, file={'cn': './assets/cn/combat_ui/QUIT.png', 'en': './assets/en/combat_ui/QUIT.png', 'jp': './assets/jp/combat_ui/QUIT.png', 'tw': './assets/tw/combat_ui/QUIT.png'}) QUIT_Christmas = Button(area={'cn': (400, 506, 477, 525), 'en': (410, 507, 469, 524), 'jp': (400, 506, 477, 525), 'tw': (400, 506, 477, 525)}, color={'cn': (195, 139, 166), 'en': (207, 166, 185), 'jp': (195, 139, 166), 'tw': (195, 139, 166)}, button={'cn': (400, 506, 477, 525), 'en': (410, 507, 469, 524), 'jp': (400, 506, 477, 525), 'tw': (400, 506, 477, 525)}, file={'cn': './assets/cn/combat_ui/QUIT_Christmas.png', 'en': './assets/en/combat_ui/QUIT_Christmas.png', 'jp': './assets/cn/combat_ui/QUIT_Christmas.png', 'tw': './assets/cn/combat_ui/QUIT_Christmas.png'}) QUIT_Cyber = Button(area={'cn': (393, 506, 470, 524), 'en': (393, 506, 470, 524), 'jp': (393, 506, 470, 524), 'tw': (393, 506, 470, 524)}, color={'cn': (255, 198, 190), 'en': (255, 198, 190), 'jp': (255, 198, 190), 'tw': (255, 198, 190)}, button={'cn': (393, 506, 470, 524), 'en': (393, 506, 470, 524), 'jp': (393, 506, 470, 524), 'tw': (393, 506, 470, 524)}, file={'cn': './assets/cn/combat_ui/QUIT_Cyber.png', 'en': './assets/cn/combat_ui/QUIT_Cyber.png', 'jp': './assets/cn/combat_ui/QUIT_Cyber.png', 'tw': './assets/tw/combat_ui/QUIT_Cyber.png'}) diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 5be526de7..c4970e95f 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -3748,12 +3748,12 @@ "display": "hide", "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -6899,12 +6899,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -7363,12 +7363,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -10195,15 +10195,16 @@ "war_archives_20220224_cn", "war_archives_20220324_cn", "war_archives_20220414_cn", - "war_archives_20220526_cn" + "war_archives_20220526_cn", + "war_archives_20220728_cn" ], "option_bold": [ - "war_archives_20220526_cn" + "war_archives_20220728_cn" ], - "cn": "war_archives_20220526_cn", - "en": "war_archives_20220526_cn", - "jp": "war_archives_20220526_cn", - "tw": "war_archives_20220526_cn" + "cn": "war_archives_20220728_cn", + "en": "war_archives_20220728_cn", + "jp": "war_archives_20220728_cn", + "tw": "war_archives_20220728_cn" }, "Mode": { "type": "select", @@ -10920,12 +10921,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -11401,12 +11402,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -11882,12 +11883,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -12363,12 +12364,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -12834,12 +12835,12 @@ ], "option_bold": [ "event_20230525_cn", - "event_20250520_cn" + "event_20250424_cn" ], "cn": "event_20230525_cn", "en": "event_20230525_cn", "jp": "event_20230525_cn", - "tw": "event_20250520_cn" + "tw": "event_20250424_cn" }, "Mode": { "type": "select", @@ -13658,9 +13659,12 @@ }, "PresetFilter": { "type": "select", - "value": "series_7_blueprint_la9", + "value": "series_8_blueprint_305", "option": [ "custom", + "series_8_blueprint_305", + "series_8_blueprint_only", + "series_8_305_only", "series_7_blueprint_la9", "series_7_blueprint_only", "series_7_la9_only", @@ -13684,7 +13688,7 @@ }, "CustomFilter": { "type": "textarea", - "value": "S7-DR0.5 > S7-PRY0.5 > S7-Q0.5 > S7-H0.5 > Q0.5 > S7-DR2.5\n> S7-G1.5 > S7-Q1 > S7-DR5 > 0.5 > S7-G4 > S7-Q2 > S7-PRY2.5 > reset\n> S7-DR8 > Q1 > 1 > S7-E-315 > S7-G2.5 > G1.5 > 1.5 > S7-E-031\n> S7-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S7-PRY5\n> S7-PRY8 > Q4 > G4 > 4 > S7-C6 > DR5 > PRY5 > 5 > C6 > 6 > S7-C8\n> S7-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12" + "value": "S8-DR0.5 > S8-PRY0.5 > S8-Q0.5 > S8-H0.5 > Q0.5 > S8-DR2.5\n> S8-G1.5 > S8-Q1 > S8-DR5 > 0.5 > S8-G4 > S8-Q2 > S8-PRY2.5 > reset\n> S8-DR8 > Q1 > 1 > S8-E-315 > S8-G2.5 > G1.5 > 1.5 > S8-E-031\n> S8-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-PRY5\n> S8-PRY8 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8\n> S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12" } }, "Storage": { @@ -15205,6 +15209,71 @@ } } }, + "PrivateQuarters": { + "Scheduler": { + "Enable": { + "type": "checkbox", + "value": false, + "option": [ + true, + false + ] + }, + "NextRun": { + "type": "datetime", + "value": "2020-01-01 00:00:00", + "validate": "datetime" + }, + "Command": { + "type": "input", + "value": "PrivateQuarters", + "display": "hide" + }, + "SuccessInterval": { + "type": "input", + "value": 30, + "display": "hide" + }, + "FailureInterval": { + "type": "input", + "value": 30, + "display": "hide" + }, + "ServerUpdate": { + "type": "input", + "value": "00:00", + "display": "hide" + } + }, + "PrivateQuarters": { + "BuyRoses": { + "type": "checkbox", + "value": true + }, + "TargetInteract": { + "type": "checkbox", + "value": true + }, + "TargetShip": { + "type": "select", + "value": "anchorage", + "option": [ + "anchorage", + "noshiro", + "sirius", + "new_jersey" + ] + } + }, + "Storage": { + "Storage": { + "type": "storage", + "value": {}, + "valuetype": "ignore", + "display": "disabled" + } + } + }, "OpsiGeneral": { "OpsiGeneral": { "UseLogger": { diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 31e8855a4..b946fbc77 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -645,9 +645,12 @@ Research: option: [ always_use, only_05_hour, only_no_project, do_not_use ] AllowDelay: true PresetFilter: - value: series_7_blueprint_la9 + value: series_8_blueprint_305 option: - custom + - series_8_blueprint_305 + - series_8_blueprint_only + - series_8_305_only - series_7_blueprint_la9 - series_7_blueprint_only - series_7_la9_only @@ -668,12 +671,12 @@ Research: - series_2_blueprint_only - series_2_457_only CustomFilter: |- - S7-DR0.5 > S7-PRY0.5 > S7-Q0.5 > S7-H0.5 > Q0.5 > S7-DR2.5 - > S7-G1.5 > S7-Q1 > S7-DR5 > 0.5 > S7-G4 > S7-Q2 > S7-PRY2.5 > reset - > S7-DR8 > Q1 > 1 > S7-E-315 > S7-G2.5 > G1.5 > 1.5 > S7-E-031 - > S7-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S7-PRY5 - > S7-PRY8 > Q4 > G4 > 4 > S7-C6 > DR5 > PRY5 > 5 > C6 > 6 > S7-C8 - > S7-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12 + S8-DR0.5 > S8-PRY0.5 > S8-Q0.5 > S8-H0.5 > Q0.5 > S8-DR2.5 + > S8-G1.5 > S8-Q1 > S8-DR5 > 0.5 > S8-G4 > S8-Q2 > S8-PRY2.5 > reset + > S8-DR8 > Q1 > 1 > S8-E-315 > S8-G2.5 > G1.5 > 1.5 > S8-E-031 + > S8-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-PRY5 + > S8-PRY8 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8 + > S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12 Dorm: Collect: true Feed: true @@ -885,6 +888,12 @@ SupplyPack: option: [ 0, 1, 2, 3, 4, 5, 6 ] Minigame: Collect: false +PrivateQuarters: + BuyRoses: true + TargetInteract: true + TargetShip: + value: anchorage + option: [ anchorage, noshiro, sirius, new_jersey ] # ==================== Daily ==================== Daily: diff --git a/module/config/argument/menu.json b/module/config/argument/menu.json index fff52d556..01f4e0d12 100644 --- a/module/config/argument/menu.json +++ b/module/config/argument/menu.json @@ -94,7 +94,8 @@ "Shipyard", "Gacha", "Freebies", - "Minigame" + "Minigame", + "PrivateQuarters" ] }, "Opsi": { diff --git a/module/config/argument/override.yaml b/module/config/argument/override.yaml index f94ffabed..67b81a170 100644 --- a/module/config/argument/override.yaml +++ b/module/config/argument/override.yaml @@ -413,6 +413,11 @@ Freebies: Awaken: Scheduler: ServerUpdate: 00:00, 06:00, 12:00, 18:00, 21:00 +PrivateQuarters: + Scheduler: + SuccessInterval: 30 + FailureInterval: 30 + ServerUpdate: 00:00 # ==================== Daily ==================== diff --git a/module/config/argument/task.yaml b/module/config/argument/task.yaml index 3fa0696c1..0d02b7df2 100644 --- a/module/config/argument/task.yaml +++ b/module/config/argument/task.yaml @@ -416,6 +416,9 @@ DailyMission: - SupplyPack Minigame: - Scheduler + PrivateQuarters: + - Scheduler + - PrivateQuarters # ==================== Opsi ==================== diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 799ada59f..c2d10abb6 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -365,8 +365,8 @@ class GeneratedConfig: Research_UseCoin = 'always_use' # always_use, only_05_hour, only_no_project, do_not_use Research_UsePart = 'always_use' # always_use, only_05_hour, only_no_project, do_not_use Research_AllowDelay = True - Research_PresetFilter = 'series_7_blueprint_la9' # custom, series_7_blueprint_la9, series_7_blueprint_only, series_7_la9_only, series_6_blueprint_203, series_6_blueprint_only, series_6_203_only, series_5_blueprint_152, series_5_blueprint_only, series_5_152_only, series_4_blueprint_tenrai, series_4_blueprint_only, series_4_tenrai_only, series_3_blueprint_234, series_3_blueprint_only, series_3_234_only, series_2_than_3_457_234, series_2_blueprint_457, series_2_blueprint_only, series_2_457_only - Research_CustomFilter = 'S7-DR0.5 > S7-PRY0.5 > S7-Q0.5 > S7-H0.5 > Q0.5 > S7-DR2.5\n> S7-G1.5 > S7-Q1 > S7-DR5 > 0.5 > S7-G4 > S7-Q2 > S7-PRY2.5 > reset\n> S7-DR8 > Q1 > 1 > S7-E-315 > S7-G2.5 > G1.5 > 1.5 > S7-E-031\n> S7-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S7-PRY5\n> S7-PRY8 > Q4 > G4 > 4 > S7-C6 > DR5 > PRY5 > 5 > C6 > 6 > S7-C8\n> S7-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12' + Research_PresetFilter = 'series_8_blueprint_305' # custom, series_8_blueprint_305, series_8_blueprint_only, series_8_305_only, series_7_blueprint_la9, series_7_blueprint_only, series_7_la9_only, series_6_blueprint_203, series_6_blueprint_only, series_6_203_only, series_5_blueprint_152, series_5_blueprint_only, series_5_152_only, series_4_blueprint_tenrai, series_4_blueprint_only, series_4_tenrai_only, series_3_blueprint_234, series_3_blueprint_only, series_3_234_only, series_2_than_3_457_234, series_2_blueprint_457, series_2_blueprint_only, series_2_457_only + Research_CustomFilter = 'S8-DR0.5 > S8-PRY0.5 > S8-Q0.5 > S8-H0.5 > Q0.5 > S8-DR2.5\n> S8-G1.5 > S8-Q1 > S8-DR5 > 0.5 > S8-G4 > S8-Q2 > S8-PRY2.5 > reset\n> S8-DR8 > Q1 > 1 > S8-E-315 > S8-G2.5 > G1.5 > 1.5 > S8-E-031\n> S8-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-PRY5\n> S8-PRY8 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8\n> S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12' # Group `Dorm` Dorm_Collect = True @@ -506,6 +506,11 @@ class GeneratedConfig: # Group `Minigame` Minigame_Collect = False + # Group `PrivateQuarters` + PrivateQuarters_BuyRoses = True + PrivateQuarters_TargetInteract = True + PrivateQuarters_TargetShip = 'anchorage' # anchorage, noshiro, sirius, new_jersey + # Group `Daily` Daily_UseDailySkip = True Daily_EscortMission = 'first' # skip, first, second, third diff --git a/module/config/config_manual.py b/module/config/config_manual.py index f9913881b..325e98b98 100644 --- a/module/config/config_manual.py +++ b/module/config/config_manual.py @@ -17,6 +17,7 @@ class ManualConfig: > Dorm > Meowfficer > Guild > Gacha > Reward > ShopFrequent > ShopOnce > Shipyard > Freebies + > PrivateQuarters > OpsiExplore > Minigame > Awaken > OpsiAshBeacon diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 2e5d3502e..952d19370 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -262,6 +262,10 @@ "name": "Minigame", "help": "Receive credits and spend them" }, + "PrivateQuarters": { + "name": "Private Quarters", + "help": "" + }, "OpsiGeneral": { "name": "OpSi General", "help": "" @@ -1152,7 +1156,8 @@ "war_archives_20220224_cn": "archives Abyssal Refrain", "war_archives_20220324_cn": "archives Virtual Tower", "war_archives_20220414_cn": "archives Aurora Noctis", - "war_archives_20220526_cn": "archives Pledge of the Radiant Court" + "war_archives_20220526_cn": "archives Pledge of the Radiant Court", + "war_archives_20220728_cn": "archives Aquilifers Ballade" }, "Mode": { "name": "Level Mode", @@ -2401,6 +2406,9 @@ "name": "Preset Filter Select", "help": "See research drops rates and spawn rates in https://azur-stats.lyoko.io/. People without a basic knowledge of these are recommended to use pre-optimized presets instead of writing custom filters", "custom": "custom", + "series_8_blueprint_305": "Series 8 Blueprints+305", + "series_8_blueprint_only": "Series 8 Blueprints Only", + "series_8_305_only": "Series 8 305 Only", "series_7_blueprint_la9": "Series 7 Blueprints+La9", "series_7_blueprint_only": "Series 7 Blueprints Only", "series_7_la9_only": "Series 7 La9 Only", @@ -3107,6 +3115,28 @@ "help": "" } }, + "PrivateQuarters": { + "_info": { + "name": "Private Quarters Settings", + "help": "Execute the automated task relating to the private quarters feature\nToggle desired subtasks, can enable just 1 or both" + }, + "BuyRoses": { + "name": "Buy Weekly Roses", + "help": "On week reset, roses will be available for purchase\nThe purchase is made in bulk wholsesale or none at all\nMinimum of 24K coin is required, if not enough subtask will be delayed to the next day and try again then" + }, + "TargetInteract": { + "name": "Enable Daily Interact", + "help": "Enables execution of the interation sequence with target ship girl" + }, + "TargetShip": { + "name": "Choose Ship Girl", + "help": "Select the target ship girl for interaction sequence", + "anchorage": "Anchorage", + "noshiro": "Noshiro", + "sirius": "Sirius", + "new_jersey": "New Jersey" + } + }, "Daily": { "_info": { "name": "Daily Settings", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 169306a1e..95a04b661 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -262,6 +262,10 @@ "name": "Task.Minigame.name", "help": "Task.Minigame.help" }, + "PrivateQuarters": { + "name": "Task.PrivateQuarters.name", + "help": "Task.PrivateQuarters.help" + }, "OpsiGeneral": { "name": "一般設定", "help": "" @@ -1152,7 +1156,8 @@ "war_archives_20220224_cn": "檔案 鳴動せし星霜の淵", "war_archives_20220324_cn": "檔案 幻像の塔", "war_archives_20220414_cn": "檔案 極夜照らす幻光", - "war_archives_20220526_cn": "檔案 诚閃の剣 搖光の城" + "war_archives_20220526_cn": "檔案 诚閃の剣 搖光の城", + "war_archives_20220728_cn": "檔案 鋼鷲の冒険譚" }, "Mode": { "name": "Campaign.Mode.name", @@ -2401,15 +2406,18 @@ "name": "Research.PresetFilter.name", "help": "Research.PresetFilter.help", "custom": "custom", - "series_7_blueprint_la9": "series_7_blueprint_la9", - "series_7_blueprint_only": "series_7_blueprint_only", - "series_7_la9_only": "series_7_la9_only", - "series_6_blueprint_203": "series_6_blueprint_203", - "series_6_blueprint_only": "series_6_blueprint_only", - "series_6_203_only": "series_6_203_only", - "series_5_blueprint_152": "series_5_blueprint_152", - "series_5_blueprint_only": "series_5_blueprint_only", - "series_5_152_only": "series_5_152_only", + "series_8_blueprint_305": "Series 8 Blueprints+305", + "series_8_blueprint_only": "Series 8 Blueprints Only", + "series_8_305_only": "Series 8 305 Only", + "series_7_blueprint_la9": "Series 7 Blueprints+La9", + "series_7_blueprint_only": "Series 7 Blueprints Only", + "series_7_la9_only": "Series 7 La9 Only", + "series_6_blueprint_203": "Series 6 Blueprints+203", + "series_6_blueprint_only": "Series 6 Blueprints Only", + "series_6_203_only": "Series 6 203 Only", + "series_5_blueprint_152": "Series 5 Blueprints+152", + "series_5_blueprint_only": "Series 5 Blueprints Only", + "series_5_152_only": "Series 5 152 Only", "series_4_blueprint_tenrai": "Series 4 Blueprints+Tenrai", "series_4_blueprint_only": "Series 4 Blueprints Only", "series_4_tenrai_only": "Series 4 Tenrai Only", @@ -3107,6 +3115,28 @@ "help": "Minigame.Collect.help" } }, + "PrivateQuarters": { + "_info": { + "name": "PrivateQuarters._info.name", + "help": "PrivateQuarters._info.help" + }, + "BuyRoses": { + "name": "PrivateQuarters.BuyRoses.name", + "help": "PrivateQuarters.BuyRoses.help" + }, + "TargetInteract": { + "name": "PrivateQuarters.TargetInteract.name", + "help": "PrivateQuarters.TargetInteract.help" + }, + "TargetShip": { + "name": "PrivateQuarters.TargetShip.name", + "help": "PrivateQuarters.TargetShip.help", + "anchorage": "anchorage", + "noshiro": "noshiro", + "sirius": "sirius", + "new_jersey": "new_jersey" + } + }, "Daily": { "_info": { "name": "Daily._info.name", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 079917f7f..d7de9d948 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -262,6 +262,10 @@ "name": "小游戏", "help": "游戏币不会溢出时自动领取游戏币,有游戏币且奖励没满时自动进行小游戏" }, + "PrivateQuarters": { + "name": "宿舍计划", + "help": "" + }, "OpsiGeneral": { "name": "通用设置", "help": "" @@ -1152,7 +1156,8 @@ "war_archives_20220224_cn": "档案 深度回音", "war_archives_20220324_cn": "档案 虚像构筑之塔", "war_archives_20220414_cn": "档案 永夜幻光", - "war_archives_20220526_cn": "档案 泠誓光庭" + "war_archives_20220526_cn": "档案 泠誓光庭", + "war_archives_20220728_cn": "档案 雄鹰的叙事歌" }, "Mode": { "name": "关卡模式", @@ -2401,6 +2406,9 @@ "name": "科研过滤器", "help": "科研掉落和项目刷新见 https://azur-stats.lyoko.io/,对这些没有基本了解的人不建议编写自定义过滤器,建议使用预优化科研过滤器", "custom": "自定义", + "series_8_blueprint_305": "八期 蓝图+305", + "series_8_blueprint_only": "八期 仅蓝图", + "series_8_305_only": "八期 仅305", "series_7_blueprint_la9": "七期 蓝图+La9", "series_7_blueprint_only": "七期 仅蓝图", "series_7_la9_only": "七期 仅La9", @@ -3107,6 +3115,28 @@ "help": "" } }, + "PrivateQuarters": { + "_info": { + "name": "宿舍计划设置", + "help": "" + }, + "BuyRoses": { + "name": "购买每周浪漫满分", + "help": "浪漫满分购买次数每周一重置\n每次运行会尝试一次性全部购买,如果物资不够(不足24K)则取消购买并推迟至次日运行" + }, + "TargetInteract": { + "name": "清空每日精力", + "help": "与选择的舰娘互动清空今日精力" + }, + "TargetShip": { + "name": "选择每日互动的舰娘", + "help": "选择需要与之每日互动的舰娘", + "anchorage": "安克雷奇", + "noshiro": "能代", + "sirius": "天狼星", + "new_jersey": "新泽西" + } + }, "Daily": { "_info": { "name": "每日任务", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 1ce8b1790..1487d7a34 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -262,6 +262,10 @@ "name": "小遊戲", "help": "遊戲幣不會溢出時自動領取遊戲幣,有遊戲幣且獎勵沒滿時自動進行小遊戲" }, + "PrivateQuarters": { + "name": "宿舍計劃", + "help": "" + }, "OpsiGeneral": { "name": "通用設定", "help": "" @@ -1103,7 +1107,7 @@ "event_20241121_cn": "危險發明逼近中", "event_20241219_cn": "Substellar Crepuscule", "event_20250227_cn": "Paradiso of Shackled Light", - "event_20250424_cn": "Toward Tulipa’s Seas", + "event_20250424_cn": "揚起鬱金之旗", "event_20250520_cn": "高塔上的薔薇", "raid_20200624": "特別演習埃塞克斯級(復刻)", "raid_20210708": "復刻穿越彼方的水線", @@ -1152,7 +1156,8 @@ "war_archives_20220224_cn": "檔案 深度回音", "war_archives_20220324_cn": "檔案 虛像構築之塔", "war_archives_20220414_cn": "檔案 永夜幻光", - "war_archives_20220526_cn": "檔案 泠誓光庭" + "war_archives_20220526_cn": "檔案 泠誓光庭", + "war_archives_20220728_cn": "檔案 雄鷹的敘事歌" }, "Mode": { "name": "地圖模式", @@ -2401,6 +2406,9 @@ "name": "科研過濾器", "help": "科研掉落和項目刷新見 https://azur-stats.lyoko.io/,對這些沒有基本了解的人不建議編寫自定義過濾器,建議使用預優化科研過濾器", "custom": "自定義", + "series_8_blueprint_305": "八期 藍圖+305", + "series_8_blueprint_only": "八期 僅藍圖", + "series_8_305_only": "八期 僅305", "series_7_blueprint_la9": "七期 藍圖+La9", "series_7_blueprint_only": "七期 僅藍圖", "series_7_la9_only": "七期 僅La9", @@ -3107,6 +3115,28 @@ "help": "" } }, + "PrivateQuarters": { + "_info": { + "name": "宿舍計劃", + "help": "PrivateQuarters._info.help" + }, + "BuyRoses": { + "name": "PrivateQuarters.BuyRoses.name", + "help": "PrivateQuarters.BuyRoses.help" + }, + "TargetInteract": { + "name": "PrivateQuarters.TargetInteract.name", + "help": "PrivateQuarters.TargetInteract.help" + }, + "TargetShip": { + "name": "PrivateQuarters.TargetShip.name", + "help": "PrivateQuarters.TargetShip.help", + "anchorage": "anchorage", + "noshiro": "noshiro", + "sirius": "sirius", + "new_jersey": "new_jersey" + } + }, "Daily": { "_info": { "name": "每日任務", diff --git a/module/device/connection.py b/module/device/connection.py index e8530d018..e032f15d4 100644 --- a/module/device/connection.py +++ b/module/device/connection.py @@ -823,6 +823,9 @@ class Connection(ConnectionAttr): instance = self.find_emulator_instance( serial=self.serial, ) + if instance is None: + logger.warning(f'Failed to check check_mumu_bridge_network, emulator instance not found') + return False file = instance.mumu_vms_config('customer_config.json') try: with open(file, mode='r', encoding='utf-8') as f: diff --git a/module/device/method/ascreencap.py b/module/device/method/ascreencap.py index 82e4e8a53..325b96764 100644 --- a/module/device/method/ascreencap.py +++ b/module/device/method/ascreencap.py @@ -2,7 +2,6 @@ import os import time from functools import wraps -import lz4.block from adbutils.errors import AdbError from module.base.utils import * @@ -157,7 +156,8 @@ class AScreenCap(Connection): _, uncompressed_size, _, width, height = compressed_data_header channel = 3 - data = lz4.block.decompress(raw_compressed_data[20:], uncompressed_size=uncompressed_size) + from lz4.block import decompress + data = decompress(raw_compressed_data[20:], uncompressed_size=uncompressed_size) image = np.frombuffer(data, dtype=np.uint8) if image is None: @@ -183,20 +183,21 @@ class AScreenCap(Connection): return image def __process_screenshot(self, screenshot): + from lz4.block import LZ4BlockError for method in self.__screenshot_method_fixed: try: result = self.__load_screenshot(screenshot, method=method) result = self.__uncompress(result) self.__screenshot_method_fixed = [method] + self.__screenshot_method return result - except lz4.block.LZ4BlockError: + except LZ4BlockError: self.__bytepointer = 0 continue self.__screenshot_method_fixed = self.__screenshot_method if len(screenshot) < 500: logger.warning(f'Unexpected screenshot: {screenshot}') - raise OSError(f'cannot load screenshot') + raise ImageTruncated(f'cannot load screenshot') @retry def screenshot_ascreencap(self): diff --git a/module/device/method/nemu_ipc.py b/module/device/method/nemu_ipc.py index c9d9dc961..e6c4a69fb 100644 --- a/module/device/method/nemu_ipc.py +++ b/module/device/method/nemu_ipc.py @@ -226,7 +226,7 @@ class NemuIpcImpl: # MuMuPlayer12 5.0 os.path.abspath(os.path.join(nemu_folder, './nx_device/12.0/shell/sdk/external_renderer_ipc.dll')), ] - ipc_dll = '' + self.lib = None for ipc_dll in list_dll: if not os.path.exists(ipc_dll): continue @@ -237,7 +237,7 @@ class NemuIpcImpl: logger.error(e) logger.error(f'ipc_dll={ipc_dll} exists, but cannot be loaded') continue - if not ipc_dll: + if self.lib is None: # not found raise NemuIpcIncompatible( f'NemuIpc requires MuMu12 version >= 3.8.13, please check your version. ' @@ -486,7 +486,7 @@ class NemuIpc(Platform): instance_id=index, display_id=0 ).__enter__() - except (NemuIpcIncompatible, NemuIpcError) as e: + except (NemuIpcIncompatible, NemuIpcError, JobTimeout) as e: logger.error(e) logger.error('Emulator info incorrect') @@ -505,7 +505,7 @@ class NemuIpc(Platform): instance_id=self.emulator_instance.MuMuPlayer12_id, display_id=0 ).__enter__() - except (NemuIpcIncompatible, NemuIpcError) as e: + except (NemuIpcIncompatible, NemuIpcError, JobTimeout) as e: logger.error(e) logger.error('Unable to initialize NemuIpc') raise RequestHumanTakeover diff --git a/module/device/method/pool.py b/module/device/method/pool.py index 95590cd49..7b6c20518 100644 --- a/module/device/method/pool.py +++ b/module/device/method/pool.py @@ -1,11 +1,15 @@ +import abc import ctypes import subprocess +from collections import deque from functools import wraps +from itertools import count from threading import Lock, Thread -from typing import Generic, TypeVar +from typing import Generic, NoReturn, TypeVar from module.logger import logger +ValueT = TypeVar("ValueT", covariant=True) ResultT = TypeVar("ResultT") @@ -25,7 +29,37 @@ def remove_tb_frames(exc, n: int): return exc.with_traceback(tb) -class Error: +class Outcome(abc.ABC, Generic[ValueT]): + @abc.abstractmethod + def unwrap(self) -> ValueT: + """Return or raise the contained value or exception. + + These two lines of code are equivalent:: + + x = fn(*args) + x = outcome.capture(fn, *args).unwrap() + + """ + pass + + +class Value(Outcome[ValueT], Generic[ValueT]): + """Concrete :class:`Outcome` subclass representing a regular value. + + """ + __slots__ = ('value',) + + def __init__(self, value: ValueT): + self.value: ValueT = value + + def __repr__(self) -> str: + return f'Value({self.value!r})' + + def unwrap(self) -> ValueT: + return self.value + + +class Error(Outcome[NoReturn]): """Concrete :class:`Outcome` subclass representing a raised exception. """ @@ -59,6 +93,23 @@ class Error: del captured_error, self +def capture(sync_fn, *args, **kwargs): + """ + Run ``sync_fn(*args, **kwargs)`` and capture the result. + + Args: + sync_fn (Callable[..., ResultT]): + + Returns: + Value[ResultT] | Error: + """ + try: + return Value(sync_fn(*args, **kwargs)) + except BaseException as exc: + exc = remove_tb_frames(exc, 1) + return Error(exc) + + class JobError(Exception): pass @@ -77,23 +128,21 @@ class Job(Generic[ResultT]): Faster but can only put() once and get() once. """ - __slots__ = ('worker', 'func', 'args', 'kwargs', 'result', 'put_lock', 'notify_get') + # __slots__ = ('worker', 'func_args_kwargs', 'queue', 'mutex', 'finished') - def __init__(self, worker, func, args, kwargs): + def __init__(self, worker, func_args_kwargs): # Having attribute "worker" means job is ongoing # Not having attribute "worker" means job is finished or killed self.worker = worker - self.func = func - self.args = args - self.kwargs = kwargs + self.func_args_kwargs = func_args_kwargs - # self.result: "Any | Error" + self.queue: "deque[Outcome[ResultT]]" = deque() self.put_lock = Lock() self.notify_get = Lock() self.notify_get.acquire() def __repr__(self): - return f'Job({self.func}, {self.args}, {self.kwargs})' + return f'Job({self.func_args_kwargs})' def get(self) -> ResultT: """ @@ -102,12 +151,8 @@ class Job(Generic[ResultT]): self.notify_get.acquire() # Return job result or raise job error - # `result` will be set in _handle_job - item = self.result - if type(item) is Error: - return item.unwrap() - else: - return item + item = self.queue.popleft() + return item.unwrap() def get_or_kill(self, timeout) -> ResultT: """ @@ -119,12 +164,8 @@ class Job(Generic[ResultT]): """ if self.notify_get.acquire(timeout=timeout): # Return job result or raise job error - # `result` will be set in _handle_job - result = self.result - if type(result) is Error: - return result.unwrap() - else: - return result + item = self.queue.popleft() + return item.unwrap() else: self._kill() raise JobTimeout @@ -140,12 +181,14 @@ class Job(Generic[ResultT]): del self.worker +name_counter = count() + + class WorkerThread: - def __init__(self, thread_pool, index): + def __init__(self, thread_pool): """ Args: thread_pool (WorkerPool): - index (int): Thread index, starting from 0 """ self.job: "Job | None" = None self.thread_pool = thread_pool @@ -157,7 +200,7 @@ class WorkerThread: # Initially we have no job, so it starts out in locked state. self.worker_lock = Lock() self.worker_lock.acquire() - self.default_name = f"Alasio thread {index}" + self.default_name = f"Alasio thread {next(name_counter)}" self.thread = Thread(target=self._work, name=self.default_name, daemon=True) self.thread.start() @@ -170,17 +213,9 @@ class WorkerThread: # value if new job is assigned job = self.job del self.job + func, args, kwargs = job.func_args_kwargs - # Capture func result - try: - result = job.func(*job.args, **job.kwargs) - except BaseException as exc: - exc = remove_tb_frames(exc, 1) - result = Error(exc) - - # Check if job killed, must before marking self idle - if type(result.error) is _JobKill: - return + result = capture(func, *args, **kwargs) # Tell the cache that we're available to be assigned a new # job. We do this *before* calling 'deliver', so that if @@ -189,15 +224,18 @@ class WorkerThread: self.thread_pool.idle_workers[self] = None self.thread_pool.release_full_lock() - # Job finished, putin result and notify - # logger.info('deliver job') - with job.put_lock: - job.result = result - del job.worker - job.notify_get.release() + # Deliver + if isinstance(result, Error) and isinstance(result.error, _JobKill): + # Job killed + pass + else: + # Job finished, putin result and notify + with job.put_lock: + job.queue.append(result) + del job.worker + job.notify_get.release() def _work(self) -> None: - pool = self.thread_pool while True: if self.worker_lock.acquire(timeout=WorkerPool.IDLE_TIMEOUT): # We got a job @@ -207,20 +245,19 @@ class WorkerThread: # there's a race condition: we might be assigned a job *just* # as we're about to exit. So we have to check. try: - del pool.idle_workers[self] + del self.thread_pool.idle_workers[self] except KeyError: # Someone else removed us from the idle worker queue, so # they must be in the process of assigning us a job - loop # around and wait for it. - pool.release_full_lock() + self.thread_pool.release_full_lock() continue else: # We successfully removed ourselves from the idle # worker queue, so no more jobs are incoming; it's safe to # exit. - del pool.all_workers[self] - pool.release_full_lock() - # logger.info(f'End worker thread: {self.default_name}') + del self.thread_pool.all_workers[self] + self.thread_pool.release_full_lock() return def kill(self): @@ -234,7 +271,6 @@ class WorkerThread: bool: If success to kill the thread """ # Send SystemExit to thread - # logger.info(f'kill worker thread: {self.default_name}') thread_id = ctypes.c_long(self.thread.ident) res = ctypes.pythonapi.PyThreadState_SetAsyncExc( thread_id, ctypes.py_object(_JobKill)) @@ -260,7 +296,7 @@ class WorkerPool: """ # Thread exits after 10s idling. - IDLE_TIMEOUT = 1 + IDLE_TIMEOUT = 10 def __init__(self, pool_size: int = 8): # Pool has 8 threads at max. @@ -275,8 +311,6 @@ class WorkerPool: self.notify_pool = Lock() self.notify_pool.acquire() - self.create_lock = Lock() - def release_full_lock(self): """ Call this method if worker finished any job, or exited, or get killed. @@ -292,103 +326,39 @@ class WorkerPool: `self.notify_pool.release()` """ if self.notify_worker.acquire(blocking=False): - try: - self.notify_pool.release() - except RuntimeError: - # Race condition when multiple threads trying to get thread worker - # They released `notify_worker` but not yet acquire `notify_pool` - pass + self.notify_pool.release() - def _get_thread_worker(self) -> "WorkerThread": + def _get_thread_worker(self) -> WorkerThread: try: worker, _ = self.idle_workers.popitem() - # logger.info(f'reuse worker thread: {worker.default_name}') return worker except KeyError: pass # Wait if reached max thread - # Check without `create_lock` first, otherwise will be 10x slower - # if multiple thread trying to get `create_lock` if len(self.all_workers) >= self.pool_size: # See release_full_lock() + self.notify_worker.release() + self.notify_pool.acquire() + # A worker just idle try: - self.notify_worker.release() - except RuntimeError: - # Race condition when multiple threads trying to get thread worker - # It's ok to treat multiple release as one + worker, _ = self.idle_workers.popitem() + return worker + except KeyError: pass - while 1: - # If any worker finishes within timeout, we can get it - # Race condition when all workers just done `release_full_lock` and no one notifies - # To handle that, we acquire with timeout and check if there's idle worker - self.notify_pool.acquire(timeout=0.01) - # Re-acquire `notify_worker` so other workers can - # call `release_full_lock` for next `_get_thread_worker` - self.notify_worker.acquire(blocking=False) - # A worker just idle - try: - worker, _ = self.idle_workers.popitem() - return worker - except KeyError: - # Race condition when multiple threads trying to get thread worker, - # they all pass through full lock check and pop the only idle worker. - # Just let the slower ones do full lock check again - pass - # A thread just existed, pool no longer full - if len(self.all_workers) < self.pool_size: - break + # A worker just exited + # if len(self.all_workers) < WorkerPool.MAX_WORKER: + # break - # Create thread with lock - with self.create_lock: - # Wait if reached max thread - # Check without `create_lock` first, otherwise will be 10x slower - # if multiple thread trying to get `create_lock` - if len(self.all_workers) >= self.pool_size: - # See release_full_lock() - try: - self.notify_worker.release() - except RuntimeError: - # Race condition when multiple threads trying to get thread worker - # It's ok to treat multiple release as one - pass - while 1: - # If any worker finishes within timeout, we can get it - # Race condition when all workers just done `release_full_lock` and no one notifies - # To handle that, we acquire with timeout and check if there's idle worker - self.notify_pool.acquire(timeout=0.01) - # Re-acquire `notify_worker` so other workers can - # call `release_full_lock` for next `_get_thread_worker` - self.notify_worker.acquire(blocking=False) - # A worker just idle - try: - worker, _ = self.idle_workers.popitem() - return worker - except KeyError: - # Race condition when multiple threads trying to get thread worker, - # they all pass through full lock check and pop the only idle worker. - # Just let the slower ones do full lock check again - pass - # A thread just existed, pool no longer full - if len(self.all_workers) < self.pool_size: - break - else: - # A thread just idle while we were waiting for `create_lock` - try: - worker, _ = self.idle_workers.popitem() - # logger.info(f'reuse worker thread: {worker.default_name}') - return worker - except KeyError: - pass - # Create thread - worker = WorkerThread(self, len(self.all_workers)) - self.all_workers[worker] = None + # Create new worker + worker = WorkerThread(self) # logger.info(f'New worker thread: {worker.default_name}') + self.all_workers[worker] = None return worker def start_thread_soon(self, func, *args, **kwargs): """ - Run a function on thread, costs extra ~15us, + Run a function on thread, result can be got from `job` object Args: @@ -404,7 +374,7 @@ class WorkerPool: result = job.get() """ worker = self._get_thread_worker() - job = Job(worker, func, args, kwargs) + job = Job(worker=worker, func_args_kwargs=(func, args, kwargs)) worker.job = job worker.worker_lock.release() @@ -428,7 +398,6 @@ class WorkerPool: job = function(...) result = job.get() """ - @wraps(func) def thread_wrapper(*args, **kwargs) -> "Job[ResultT]": return self.start_thread_soon(func, *args, **kwargs) @@ -472,7 +441,9 @@ class WorkerPool: Job[bytes]: """ worker = self._get_thread_worker() - job = Job(worker, self._subprocess_execute, (cmd,), {'timeout': timeout}) + job = Job(worker=worker, func_args_kwargs=( + self._subprocess_execute, (cmd,), {'timeout': timeout} + )) worker.job = job worker.worker_lock.release() diff --git a/module/exercise/hp_daemon.py b/module/exercise/hp_daemon.py index f047ad6f2..ecf7e5b25 100644 --- a/module/exercise/hp_daemon.py +++ b/module/exercise/hp_daemon.py @@ -72,6 +72,7 @@ class HpDaemon(ModuleBase): PAUSE_Nurse, PAUSE_Devil, PAUSE_Seaside, + PAUSE_Star, ]: self.attacker_hp = self._calculate_hp(image, area=ATTACKER_HP_AREA_New.area, reverse=True) self.defender_hp = self._calculate_hp(image, area=DEFENDER_HP_AREA_New.area, reverse=True) diff --git a/module/private_quarters/assets.py b/module/private_quarters/assets.py new file mode 100644 index 000000000..6bfcdf764 --- /dev/null +++ b/module/private_quarters/assets.py @@ -0,0 +1,33 @@ +from module.base.button import Button +from module.base.template import Template + +# This file was automatically generated by dev_tools/button_extract.py. +# Don't modify it manually. + +PRIVATE_QUARTERS_DAILY_COUNT = Button(area={'cn': (107, 129, 154, 154), 'en': (135, 125, 177, 157), 'jp': (132, 129, 171, 151), 'tw': (135, 125, 177, 157)}, color={'cn': (99, 102, 106), 'en': (105, 109, 114), 'jp': (110, 113, 117), 'tw': (105, 109, 114)}, button={'cn': (107, 129, 154, 154), 'en': (135, 125, 177, 157), 'jp': (132, 129, 171, 151), 'tw': (135, 125, 177, 157)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_DAILY_COUNT.png'}) +PRIVATE_QUARTERS_INTERACT = Button(area={'cn': (832, 446, 857, 471), 'en': (832, 446, 857, 471), 'jp': (832, 446, 857, 471), 'tw': (832, 446, 857, 471)}, color={'cn': (167, 165, 167), 'en': (167, 165, 167), 'jp': (167, 165, 167), 'tw': (167, 165, 167)}, button={'cn': (825, 476, 1127, 506), 'en': (832, 446, 1107, 471), 'jp': (832, 446, 1107, 471), 'tw': (832, 446, 1107, 471)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT.png'}) +PRIVATE_QUARTERS_INTERACT_CHECK = Button(area={'cn': (1223, 653, 1245, 675), 'en': (1223, 653, 1245, 675), 'jp': (1223, 653, 1245, 675), 'tw': (1223, 653, 1245, 675)}, color={'cn': (196, 192, 187), 'en': (196, 192, 187), 'jp': (196, 192, 187), 'tw': (196, 192, 187)}, button={'cn': (1223, 653, 1245, 675), 'en': (1223, 653, 1245, 675), 'jp': (1223, 653, 1245, 675), 'tw': (1223, 653, 1245, 675)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_INTERACT_CHECK.png'}) +PRIVATE_QUARTERS_LOADING_CHECK = Button(area={'cn': (582, 376, 702, 391), 'en': (582, 376, 702, 391), 'jp': (582, 376, 702, 391), 'tw': (582, 376, 702, 391)}, color={'cn': (200, 232, 255), 'en': (200, 232, 255), 'jp': (200, 232, 255), 'tw': (200, 232, 255)}, button={'cn': (582, 376, 702, 391), 'en': (582, 376, 702, 391), 'jp': (582, 376, 702, 391), 'tw': (582, 376, 702, 391)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_LOADING_CHECK.png'}) +PRIVATE_QUARTERS_PAGE_LEFT = Button(area={'cn': (20, 329, 40, 359), 'en': (20, 329, 40, 359), 'jp': (20, 329, 40, 359), 'tw': (20, 329, 40, 359)}, color={'cn': (231, 234, 238), 'en': (231, 234, 238), 'jp': (231, 234, 238), 'tw': (231, 234, 238)}, button={'cn': (20, 329, 40, 359), 'en': (20, 329, 40, 359), 'jp': (20, 329, 40, 359), 'tw': (20, 329, 40, 359)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LEFT.png'}) +PRIVATE_QUARTERS_PAGE_LOCALE_BEACH = Button(area={'cn': (24, 504, 99, 527), 'en': (38, 509, 86, 522), 'jp': (36, 506, 87, 525), 'tw': (38, 509, 86, 522)}, color={'cn': (198, 198, 198), 'en': (154, 154, 154), 'jp': (221, 221, 221), 'tw': (154, 154, 154)}, button={'cn': (24, 504, 99, 527), 'en': (38, 509, 86, 522), 'jp': (36, 506, 87, 525), 'tw': (38, 509, 86, 522)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_BEACH.png'}) +PRIVATE_QUARTERS_PAGE_LOCALE_LOFT = Button(area={'cn': (23, 502, 99, 528), 'en': (41, 505, 81, 525), 'jp': (35, 507, 86, 525), 'tw': (41, 505, 81, 525)}, color={'cn': (206, 206, 207), 'en': (196, 196, 197), 'jp': (211, 212, 212), 'tw': (196, 196, 197)}, button={'cn': (23, 502, 99, 528), 'en': (41, 505, 81, 525), 'jp': (35, 507, 86, 525), 'tw': (41, 505, 81, 525)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_LOCALE_LOFT.png'}) +PRIVATE_QUARTERS_PAGE_RIGHT = Button(area={'cn': (1240, 329, 1260, 359), 'en': (1240, 329, 1260, 359), 'jp': (1240, 329, 1260, 359), 'tw': (1240, 329, 1260, 359)}, color={'cn': (232, 234, 237), 'en': (232, 234, 237), 'jp': (232, 234, 237), 'tw': (232, 234, 237)}, button={'cn': (1240, 329, 1260, 359), 'en': (1240, 329, 1260, 359), 'jp': (1240, 329, 1260, 359), 'tw': (1240, 329, 1260, 359)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_PAGE_RIGHT.png'}) +PRIVATE_QUARTERS_ROOM_BACK = Button(area={'cn': (28, 40, 43, 60), 'en': (28, 40, 43, 60), 'jp': (28, 40, 43, 60), 'tw': (28, 40, 43, 60)}, color={'cn': (185, 184, 186), 'en': (185, 184, 186), 'jp': (185, 184, 186), 'tw': (185, 184, 186)}, button={'cn': (16, 31, 139, 69), 'en': (27, 30, 147, 70), 'jp': (27, 30, 147, 70), 'tw': (27, 30, 147, 70)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_BACK.png'}) +PRIVATE_QUARTERS_ROOM_CHECK = Button(area={'cn': (1218, 651, 1238, 666), 'en': (1218, 651, 1238, 666), 'jp': (1218, 651, 1238, 666), 'tw': (1218, 651, 1238, 666)}, color={'cn': (68, 98, 113), 'en': (68, 98, 113), 'jp': (68, 98, 113), 'tw': (68, 98, 113)}, button={'cn': (1218, 651, 1238, 666), 'en': (1218, 651, 1238, 666), 'jp': (1218, 651, 1238, 666), 'tw': (1218, 651, 1238, 666)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_CHECK.png'}) +PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA = Button(area={'cn': (950, 95, 1275, 595), 'en': (950, 95, 1275, 595), 'jp': (950, 95, 1275, 595), 'tw': (950, 95, 1275, 595)}, color={'cn': (255, 255, 255), 'en': (255, 255, 255), 'jp': (255, 255, 255), 'tw': (255, 255, 255)}, button={'cn': (950, 95, 1275, 595), 'en': (950, 95, 1275, 595), 'jp': (950, 95, 1275, 595), 'tw': (950, 95, 1275, 595)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.png'}) +PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1 = Button(area={'cn': (721, 17, 781, 37), 'en': (721, 17, 781, 37), 'jp': (721, 17, 781, 37), 'tw': (721, 17, 781, 37)}, color={'cn': (206, 202, 201), 'en': (206, 202, 201), 'jp': (206, 202, 201), 'tw': (206, 202, 201)}, button={'cn': (721, 17, 781, 37), 'en': (721, 17, 781, 37), 'jp': (721, 17, 781, 37), 'tw': (721, 17, 781, 37)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1.png'}) +PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2 = Button(area={'cn': (667, 71, 717, 86), 'en': (667, 71, 717, 86), 'jp': (667, 71, 717, 86), 'tw': (667, 71, 717, 86)}, color={'cn': (222, 213, 198), 'en': (222, 213, 198), 'jp': (222, 213, 198), 'tw': (222, 213, 198)}, button={'cn': (667, 71, 717, 86), 'en': (667, 71, 717, 86), 'jp': (667, 71, 717, 86), 'tw': (667, 71, 717, 86)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2.png'}) +PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA = Button(area={'cn': (504, 45, 784, 625), 'en': (504, 45, 784, 625), 'jp': (504, 45, 784, 625), 'tw': (504, 45, 784, 625)}, color={'cn': (255, 255, 255), 'en': (255, 255, 255), 'jp': (255, 255, 255), 'tw': (255, 255, 255)}, button={'cn': (504, 45, 784, 625), 'en': (504, 45, 784, 625), 'jp': (504, 45, 784, 625), 'tw': (504, 45, 784, 625)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA.png'}) +PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX = Button(area={'cn': (1157, 40, 1197, 60), 'en': (1157, 40, 1197, 60), 'jp': (1157, 40, 1197, 60), 'tw': (1157, 40, 1197, 60)}, color={'cn': (173, 161, 155), 'en': (173, 161, 155), 'jp': (173, 161, 155), 'tw': (173, 161, 155)}, button={'cn': (1157, 40, 1197, 60), 'en': (1157, 40, 1197, 60), 'jp': (1157, 40, 1197, 60), 'tw': (1157, 40, 1197, 60)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX.png'}) +PRIVATE_QUARTERS_SHIP_ANCHORAGE = Button(area={'cn': (713, 246, 778, 311), 'en': (713, 246, 778, 311), 'jp': (713, 246, 778, 311), 'tw': (713, 246, 778, 311)}, color={'cn': (214, 184, 176), 'en': (214, 184, 176), 'jp': (214, 184, 176), 'tw': (214, 184, 176)}, button={'cn': (713, 246, 778, 311), 'en': (713, 246, 778, 311), 'jp': (713, 246, 778, 311), 'tw': (713, 246, 778, 311)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_ANCHORAGE.png'}) +PRIVATE_QUARTERS_SHIP_NEW_JERSEY = Button(area={'cn': (973, 307, 1023, 347), 'en': (973, 307, 1023, 347), 'jp': (973, 307, 1023, 347), 'tw': (973, 307, 1023, 347)}, color={'cn': (149, 141, 173), 'en': (149, 141, 173), 'jp': (149, 141, 173), 'tw': (149, 141, 173)}, button={'cn': (973, 307, 1023, 347), 'en': (973, 307, 1023, 347), 'jp': (973, 307, 1023, 347), 'tw': (973, 307, 1023, 347)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png', 'en': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png', 'tw': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NEW_JERSEY.png'}) +PRIVATE_QUARTERS_SHIP_NOSHIRO = Button(area={'cn': (965, 289, 1027, 362), 'en': (962, 295, 1027, 360), 'jp': (962, 295, 1027, 360), 'tw': (962, 295, 1027, 360)}, color={'cn': (143, 120, 127), 'en': (102, 93, 102), 'jp': (102, 93, 102), 'tw': (102, 93, 102)}, button={'cn': (965, 289, 1027, 362), 'en': (962, 295, 1027, 360), 'jp': (962, 295, 1027, 360), 'tw': (962, 295, 1027, 360)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_NOSHIRO.png'}) +PRIVATE_QUARTERS_SHIP_SIRIUS = Button(area={'cn': (908, 411, 966, 478), 'en': (905, 414, 970, 479), 'jp': (905, 414, 970, 479), 'tw': (905, 414, 970, 479)}, color={'cn': (219, 207, 214), 'en': (156, 153, 165), 'jp': (156, 153, 165), 'tw': (156, 153, 165)}, button={'cn': (908, 411, 966, 478), 'en': (905, 414, 970, 479), 'jp': (905, 414, 970, 479), 'tw': (905, 414, 970, 479)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHIP_SIRIUS.png'}) +PRIVATE_QUARTERS_SHOP_AMOUNT_MAX = Button(area={'cn': (848, 504, 888, 524), 'en': (848, 504, 888, 524), 'jp': (848, 504, 888, 524), 'tw': (848, 504, 888, 524)}, color={'cn': (227, 231, 235), 'en': (227, 231, 235), 'jp': (227, 231, 235), 'tw': (227, 231, 235)}, button={'cn': (848, 504, 888, 524), 'en': (848, 504, 888, 524), 'jp': (848, 504, 888, 524), 'tw': (848, 504, 888, 524)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_AMOUNT_MAX.png'}) +PRIVATE_QUARTERS_SHOP_BACK = Button(area={'cn': (40, 35, 60, 55), 'en': (40, 35, 60, 55), 'jp': (40, 35, 60, 55), 'tw': (40, 35, 60, 55)}, color={'cn': (202, 202, 202), 'en': (202, 202, 202), 'jp': (202, 202, 202), 'tw': (202, 202, 202)}, button={'cn': (35, 30, 95, 60), 'en': (35, 30, 95, 60), 'jp': (35, 30, 95, 60), 'tw': (35, 30, 95, 60)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_BACK.png'}) +PRIVATE_QUARTERS_SHOP_CHECK = Button(area={'cn': (124, 18, 218, 48), 'en': (129, 25, 284, 40), 'jp': (126, 20, 260, 44), 'tw': (129, 25, 284, 40)}, color={'cn': (86, 92, 98), 'en': (142, 147, 155), 'jp': (82, 88, 94), 'tw': (142, 147, 155)}, button={'cn': (124, 18, 218, 48), 'en': (129, 25, 284, 40), 'jp': (126, 20, 260, 44), 'tw': (129, 25, 284, 40)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CHECK.png'}) +PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT = Button(area={'cn': (790, 574, 842, 601), 'en': (773, 580, 858, 595), 'jp': (789, 577, 841, 600), 'tw': (773, 580, 858, 595)}, color={'cn': (94, 195, 252), 'en': (139, 214, 255), 'jp': (92, 195, 252), 'tw': (139, 214, 255)}, button={'cn': (651, 566, 981, 611), 'en': (731, 573, 901, 603), 'jp': (731, 573, 901, 603), 'tw': (731, 573, 901, 603)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT.png'}) +PRIVATE_QUARTERS_SHOP_ENTER = Button(area={'cn': (1028, 641, 1078, 691), 'en': (1028, 641, 1078, 691), 'jp': (1028, 641, 1078, 691), 'tw': (1028, 641, 1078, 691)}, color={'cn': (243, 227, 213), 'en': (243, 227, 213), 'jp': (243, 227, 213), 'tw': (243, 227, 213)}, button={'cn': (1028, 641, 1078, 691), 'en': (1028, 641, 1078, 691), 'jp': (1028, 641, 1078, 691), 'tw': (1028, 641, 1078, 691)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_ENTER.png'}) +PRIVATE_QUARTERS_SHOP_GOLD_COINS = Button(area={'cn': (963, 25, 1055, 47), 'en': (963, 25, 1055, 47), 'jp': (973, 25, 1051, 48), 'tw': (963, 25, 1055, 47)}, color={'cn': (186, 197, 204), 'en': (186, 197, 204), 'jp': (169, 181, 185), 'tw': (186, 197, 204)}, button={'cn': (963, 25, 1055, 47), 'en': (963, 25, 1055, 47), 'jp': (973, 25, 1051, 48), 'tw': (963, 25, 1055, 47)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_GOLD_COINS.png'}) +PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK = Button(area={'cn': (968, 489, 1028, 539), 'en': (968, 489, 1028, 539), 'jp': (968, 489, 1028, 539), 'tw': (968, 489, 1028, 539)}, color={'cn': (131, 109, 120), 'en': (131, 109, 120), 'jp': (131, 109, 120), 'tw': (131, 109, 120)}, button={'cn': (968, 489, 1028, 539), 'en': (968, 489, 1028, 539), 'jp': (968, 489, 1028, 539), 'tw': (968, 489, 1028, 539)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK.png'}) +PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET = Button(area={'cn': (598, 335, 683, 420), 'en': (598, 335, 683, 420), 'jp': (598, 335, 683, 420), 'tw': (598, 335, 683, 420)}, color={'cn': (151, 130, 137), 'en': (151, 130, 137), 'jp': (151, 130, 137), 'tw': (151, 130, 137)}, button={'cn': (598, 335, 683, 420), 'en': (598, 335, 683, 420), 'jp': (598, 335, 683, 420), 'tw': (598, 335, 683, 420)}, file={'cn': './assets/cn/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png', 'en': './assets/en/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png', 'jp': './assets/jp/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png', 'tw': './assets/tw/private_quarters/PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET.png'}) diff --git a/module/private_quarters/private_quarters.py b/module/private_quarters/private_quarters.py new file mode 100644 index 000000000..b7ca00014 --- /dev/null +++ b/module/private_quarters/private_quarters.py @@ -0,0 +1,431 @@ +import module.config.server as server +from module.base.timer import Timer +from module.base.utils import random_rectangle_vector +from module.handler.assets import POPUP_CANCEL +from module.logger import logger +from module.ocr.ocr import Digit, DigitCounter +from module.private_quarters.assets import * +from module.ui.page import page_private_quarters +from module.ui.ui import UI + +if server.server in ['cn', 'jp']: + OCR_DAILY_COUNT = DigitCounter(PRIVATE_QUARTERS_DAILY_COUNT, letter=(218, 219, 221)) +else: + OCR_DAILY_COUNT = DigitCounter(PRIVATE_QUARTERS_DAILY_COUNT, letter=(255, 247, 247), threshold=64) + +if server.server != 'jp': + OCR_SHOP_GOLD_COINS = Digit(PRIVATE_QUARTERS_SHOP_GOLD_COINS, letter=(239, 239, 239), name='OCR_SHOP_GOLD_COINS') +else: + OCR_SHOP_GOLD_COINS = Digit(PRIVATE_QUARTERS_SHOP_GOLD_COINS, letter=(201, 201, 201), name='OCR_SHOP_GOLD_COINS') + + +class PrivateQuarters(UI): + # Key: str, target ship name + # Value: list[Button], button instances + # (Room_Entrance, Page_Locale) + available_targets = { + 'anchorage': (PRIVATE_QUARTERS_SHIP_ANCHORAGE, PRIVATE_QUARTERS_PAGE_LOCALE_BEACH), + 'noshiro': (PRIVATE_QUARTERS_SHIP_NOSHIRO, PRIVATE_QUARTERS_PAGE_LOCALE_BEACH), + 'sirius': (PRIVATE_QUARTERS_SHIP_SIRIUS, PRIVATE_QUARTERS_PAGE_LOCALE_BEACH), + 'new_jersey': (PRIVATE_QUARTERS_SHIP_NEW_JERSEY, PRIVATE_QUARTERS_PAGE_LOCALE_LOFT), + } + + def _pq_target_appear(self): + """ + Callable wrapper to validate target's appearance + offset=(100, 100) detectable for anchorage, noshiro, sirus, and new_jersey + When more ships added may need to adjust or capture specific bubble position per + ship, can use the available_targets to store similarly into tuples instead + """ + settle_timer = Timer(1.5, count=3).start() + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End, success + if self.appear(PRIVATE_QUARTERS_ROOM_TARGET_CHECK_1, offset=(100, 100)): + return True + if self.appear(PRIVATE_QUARTERS_ROOM_TARGET_CHECK_2, offset=(100, 100)): + return True + + # End, failed expired wait time + if settle_timer.reached(): + return False + + # Factor in couple drag up actions to + # counter odd default distance/zoom on target + p1, p2 = random_rectangle_vector( + (0, -30), box=PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA.area, random_range=(-10, -10, 10, 10), padding=5) + self.device.drag(p1, p2, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5)) + + def _pq_goto_room_seek(self, target_ship): + """ + Execute seek room routine + + Args: + target_ship (str): + + Returns: + bool + """ + target_title = target_ship.title().replace('_', ' ') + page_btn = self.available_targets[target_ship][1] + logger.hr(f'Seek {target_title}\'s Page', level=2) + + # Depending on current page position + # Search left then right or reverse order + directions = [PRIVATE_QUARTERS_PAGE_LEFT, PRIVATE_QUARTERS_PAGE_RIGHT] + if not self.appear(PRIVATE_QUARTERS_PAGE_LEFT, offset=(20, 20)): + directions.reverse() + + # Execute page seek + skip_first_screenshot = True + self.interval_clear(directions) + settle_timer = Timer(1.5, count=3).start() + for direction in directions: + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End, success + if self.appear(page_btn, offset=(20, 20)): + logger.info(f'Reached {target_title}\'s page') + return True + + # Enable interval delay to confirm page after click + if self.appear_then_click(direction, offset=(20, 20), interval=1): + settle_timer.reset() + continue + + # No more page clicks past interval 1 + # Thus can safely go the other direction + if settle_timer.reached(): + break + + logger.warning(f'{target_title}\'s page cannot be found') + return False + + def _pq_goto_room_check(self): + """ + Callable wrapper for whether is loading or blocked by download asset popup + """ + return self.appear(PRIVATE_QUARTERS_LOADING_CHECK, offset=(20, 20)) \ + or self.appear(POPUP_CANCEL, offset=(20, 20)) + + def _pq_goto_room_enter(self, target_ship): + """ + Execute enter room routine + + Args: + target_ship (str): + + Returns: + bool + """ + # Initiate goto into target's room + # Ensure either loading or popup + # prompt appears after click + target_title = target_ship.title().replace('_', ' ') + target_btn = self.available_targets[target_ship][0] + self.ui_click( + click_button=target_btn, + check_button=self._pq_goto_room_check, + appear_button=page_private_quarters.check_button, + offset=(20, 20), + skip_first_screenshot=True) + + # If was download asset popup + # Terminate the run + if self.handle_popup_cancel('PRIVATE_QUARTERS_DOWNLOAD_ASSET', offset=(20, 20)): + logger.error(f'Cannot enter {target_title}\'s room, please download the necessary assets first') + return False + + # Fully enter into target's room + # through click progression + click_timer = Timer(1.5, count=3).start() + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End + if self.appear(PRIVATE_QUARTERS_ROOM_CHECK, offset=(20, 20)): + break + + # Continue without clicking, mitigate too many click exception + if self.appear(PRIVATE_QUARTERS_LOADING_CHECK, offset=(20, 20)): + continue + + if click_timer.reached(): + self.device.click(PRIVATE_QUARTERS_ROOM_SAFE_CLICK_AREA) + click_timer.reset() + + # If target's intimacy is maxed + # Terminate the run + if self.appear(PRIVATE_QUARTERS_ROOM_TARGET_INTIMACY_MAX, offset=(20, 20)): + logger.warning( + f'{target_title}\'s intimacy is maxed, configure to new target or turn off subtask altogether') + return False + + return True + + def _pq_goto_room_exit(self): + """ + Execute room exit routine + """ + self.interval_clear(PRIVATE_QUARTERS_ROOM_BACK) + self.ui_click( + click_button=PRIVATE_QUARTERS_ROOM_BACK, + check_button=page_private_quarters.check_button, + offset=(20, 20), + retry_wait=1.5, + skip_first_screenshot=True + ) + self.handle_info_bar() + + def _pq_shop_exit(self): + """ + Execute shop exit routine + """ + self.ui_click( + click_button=PRIVATE_QUARTERS_SHOP_BACK, + check_button=page_private_quarters.check_button, + offset=(20, 20), + skip_first_screenshot=True + ) + + def pq_shop_weekly_roses(self): + """ + Execute purchase weekly roses from shop routine + Must have 24K+, try next day if low + """ + logger.hr(f'Get Weekly Roses', level=2) + # Enter shop + self.ui_click( + click_button=PRIVATE_QUARTERS_SHOP_ENTER, + check_button=PRIVATE_QUARTERS_SHOP_CHECK, + appear_button=page_private_quarters.check_button, + offset=(20, 20), + skip_first_screenshot=True + ) + + # Roses available for purchase? + # Exit shop if not + # Noticeable lag observed on appearance of roses + appear_timer = Timer(1.5, count=3).start() + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End, no roses + if appear_timer.reached(): + logger.info('No more weekly roses to purchase, exit subtask') + self._pq_shop_exit() + logger.hr(f'End Weekly Roses', level=2) + return + + # End, has roses + if self.appear(PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK, offset=(20, 20)): + break + + # Read coins, exit if < 24000 (total price for all roses) + # Try again next day if low + currency = OCR_SHOP_GOLD_COINS.ocr(self.device.image) + if currency < 24000: + logger.warning(f'Have: {currency}, Need: 24000. Try again next day') + self._pq_shop_exit() + logger.hr(f'End Weekly Roses', level=2) + return + logger.info('Purchasing all available weekly roses') + + # Execute purchase operation + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End + if self.appear(PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_GET, offset=(20, 20), interval=1): + self.device.click(PRIVATE_QUARTERS_SHOP_BACK) + break + + if self.appear_then_click(PRIVATE_QUARTERS_SHOP_WEEKLY_ROSES_CHECK, offset=(20, 20), interval=1): + continue + if self.appear_then_click(PRIVATE_QUARTERS_SHOP_AMOUNT_MAX, offset=(20, 20), interval=1): + continue + if self.appear_then_click(PRIVATE_QUARTERS_SHOP_CONFIRM_AMOUNT, offset=(20, 20), interval=1): + continue + + # Exit shop + self._pq_shop_exit() + logger.hr(f'End Weekly Roses', level=2) + + def pq_interact(self): + """ + Execute target interact routine + offset=(0, 60) to account for y-position of asset + Depending on intimacy level, the asset may shift + """ + # Click target ship girl for 1st stage sequence + logger.hr(f'Interact Start', level=2) + click_timer = Timer(1.5, count=3).start() + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End + if self.appear(PRIVATE_QUARTERS_INTERACT, offset=(0, 60)): + break + + if click_timer.reached(): + self.device.click(PRIVATE_QUARTERS_ROOM_TARGET_CLICK_AREA) + click_timer.reset() + + # Repeat 2nd and 3rd stage sequence 3 times + for i in range(1, 4): + logger.hr(f'Interact Loop {i}/3', level=3) + self.interval_clear([PRIVATE_QUARTERS_INTERACT_CHECK, + PRIVATE_QUARTERS_INTERACT]) + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End + if self.appear(PRIVATE_QUARTERS_INTERACT_CHECK, offset=(20, 20)): + break + + if self.appear_then_click(PRIVATE_QUARTERS_INTERACT, offset=(0, 60), interval=1): + continue + + skip_first_screenshot = True + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + # End + if self.appear(PRIVATE_QUARTERS_INTERACT, offset=(0, 60)): + break + + if self.appear(PRIVATE_QUARTERS_INTERACT_CHECK, offset=(20, 20), interval=1): + self.device.click(PRIVATE_QUARTERS_ROOM_BACK) + continue + + logger.hr(f'Interact End', level=2) + self._pq_goto_room_exit() + + def pq_goto_room(self, target_ship, retry=3): + """ + Execute goto target's room routine + Try again if target absent in initial load + Limit to at most configured 'retry' count + + Args: + target_ship (str): + retry (int): + + Returns: + bool + """ + success = False + target_title = target_ship.title().replace('_', ' ') + logger.hr(f'Enter {target_title}\'s Room', level=1) + + if not self._pq_goto_room_seek(target_ship): + return success + + for _ in range(retry): + if not self._pq_goto_room_enter(target_ship): + break + + if self._pq_target_appear(): + logger.info(f'{target_title} is waiting and excited for your arrival!') + success = True + break + logger.warning(f'{target_title} is not ready, exit and try again; retry={retry - (_ + 1)}') + + self._pq_goto_room_exit() + + return success + + def pq_run(self, buy_roses, target_interact, target_ship): + """ + Execute daily private quarters routine + - Purchase weekly roses from shop + - Interact with target ship girl + + Args: + buy_roses (bool): + target_interact (bool): + target_ship (str): + """ + logger.hr(f'Private Quarters Run', level=1) + target_title = target_ship.title().replace('_', ' ') + logger.info(f'Task configured for Buy_Roses={buy_roses}, ' + f'Interact_ShipGirl={target_interact}, ' + f'Target_ShipGirl={target_title}') + + # Enter shop and spend coin for weekly roses if enabled + if buy_roses: + self.pq_shop_weekly_roses() + + # Interact with target if enabled + if target_interact: + # Pull count here, exit run if = 0 + count, _, _ = OCR_DAILY_COUNT.ocr(self.device.image) + if count == 0: + logger.info('Daily intimacy count exhausted, exit subtask') + return + + # Verify target is a valid selectable + if target_ship not in self.available_targets: + logger.error(f'Unsupported target ship: {target_title}, cannot continue subtask') + return + + # Handle if target is not in initial load + # Limit to 3 tries + if not self.pq_goto_room(target_ship, retry=3): + return + + # Execute 'interact' routine + self.pq_interact() + + def run(self): + """ + Pages: + in: Any page + out: page_main, may have info_bar + """ + if server.server in ['cn', 'en', 'jp']: + self.ui_goto(page_private_quarters, get_ship=False) + self.handle_info_bar() + + self.pq_run( + buy_roses=self.config.PrivateQuarters_BuyRoses, + target_interact=self.config.PrivateQuarters_TargetInteract, + target_ship=self.config.PrivateQuarters_TargetShip + ) + else: + logger.info(f'Private Quarters task not presently supported for {server.server} server.') + logger.info('If want to address, review necessary assets, replace, update above condition, and test') + + self.config.task_delay(server_update=True) diff --git a/module/research/assets.py b/module/research/assets.py index bb5862dd7..c828bae42 100644 --- a/module/research/assets.py +++ b/module/research/assets.py @@ -69,4 +69,5 @@ TEMPLATE_S4_2 = Template(file={'cn': './assets/cn/research/TEMPLATE_S4_2.png', ' TEMPLATE_S5 = Template(file={'cn': './assets/cn/research/TEMPLATE_S5.png', 'en': './assets/en/research/TEMPLATE_S5.png', 'jp': './assets/jp/research/TEMPLATE_S5.png', 'tw': './assets/tw/research/TEMPLATE_S5.png'}) TEMPLATE_S6 = Template(file={'cn': './assets/cn/research/TEMPLATE_S6.png', 'en': './assets/en/research/TEMPLATE_S6.png', 'jp': './assets/jp/research/TEMPLATE_S6.png', 'tw': './assets/tw/research/TEMPLATE_S6.png'}) TEMPLATE_S7 = Template(file={'cn': './assets/cn/research/TEMPLATE_S7.png', 'en': './assets/en/research/TEMPLATE_S7.png', 'jp': './assets/jp/research/TEMPLATE_S7.png', 'tw': './assets/tw/research/TEMPLATE_S7.png'}) +TEMPLATE_S8 = Template(file={'cn': './assets/cn/research/TEMPLATE_S8.png', 'en': './assets/cn/research/TEMPLATE_S8.png', 'jp': './assets/cn/research/TEMPLATE_S8.png', 'tw': './assets/cn/research/TEMPLATE_S8.png'}) TEMPLATE_WAITING = Template(file={'cn': './assets/cn/research/TEMPLATE_WAITING.png', 'en': './assets/en/research/TEMPLATE_WAITING.png', 'jp': './assets/jp/research/TEMPLATE_WAITING.png', 'tw': './assets/tw/research/TEMPLATE_WAITING.png'}) diff --git a/module/research/preset.py b/module/research/preset.py index e1e97c9ed..0834b5b76 100644 --- a/module/research/preset.py +++ b/module/research/preset.py @@ -70,6 +70,72 @@ DICT_FILTER_PRESET = { # Goal: DR_blueprint=0, PRY_blueprint=0, tanrai_blueprint=150 # Average time cost: 153.41706666666678 # Average rewards: [238.69016631 238.37881965 529.71190834 528.92520834 528.39586667 150.07973333] + 'series_8_305_only_cube': """ + S8-Q0.5 > S8-DR0.5 > S8-PRY0.5 > Q0.5 > S8-Q4 > S8-Q2 > S8-Q1 > 0.5 + > S8-E-315 > S8-G1.5 > S8-G4 > Q1 > reset > S8-H1 > H1 > 1 > S8-E-031 + > S8-DR2.5 > S8-PRY2.5 > S8-G2.5 > G1.5 > 1.5 > Q2 > E2 > S8-H2 > H2 + > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-DR5 > S8-PRY5 > Q4 > G4 + > S8-H4 > H4 > 4 > S8-C6 > DR5 > PRY5 > 5 > S8-DR8 > S8-PRY8 > S8-C8 + > C6 > 6 > S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12 + """, + # Goal: DR_blurprint=0, PRY_blueprint=0, tanrai_blueprint=150 + # Average time cost: 161.37177965277806 + # Average rewards: [241.92774575 241.13046242 421.82134358 421.04494941 420.46893024 150.07799978] + 'series_8_305_only': """ + S8-Q0.5 > S8-PRY0.5 > S8-DR0.5 > Q0.5 > S8-Q4 > S8-Q2 > S8-Q1 > 0.5 + > S8-E-315 > S8-G4 > S8-G1.5 > Q1 > 1 > S8-E-031 > S8-DR2.5 > reset + > S8-G2.5 > S8-PRY2.5 > G1.5 > 1.5 > Q2 > E2 > 2 > DR2.5 > PRY2.5 + > G2.5 > 2.5 > S8-DR5 > S8-PRY5 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 + > 5 > S8-DR8 > S8-PRY8 > S8-C8 > C6 > 6 > DR8 > PRY8 > C8 > 8 + > S8-C12 > C12 > 12 + """, + # Goal: DR_blurprint=513, PRY_blueprint=343, tanrai_blueprint=100 + # Average time cost: 124.67622465277958 + # Average rewards: [531.93022864 529.81919864 510.27473326 510.18530159 510.11215826 100.8088164] + 'series_8_blueprint_305_cube': """ + S8-DR0.5 > S8-Q0.5 > S8-PRY0.5 > 0.5 > S8-DR2.5 > S8-Q1 > S8-Q2 + > S8-H1 > S8-E-315 > S8-G1.5 > reset > S8-Q4 > S8-G4 > S8-H2 > Q1 + > H1 > 1 > S8-G2.5 > S8-DR5 > S8-PRY2.5 > G1.5 > 1.5 > S8-E-031 + > S8-DR8 > Q2 > E2 > H2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-H4 + > S8-PRY5 > Q4 > G4 > H4 > 4 > S8-C6 > S8-PRY8 > DR5 > PRY5 > 5 > C6 + > 6 > S8-C8 > DR8 > PRY8 > C8 > 8 > S8-C12 > C12 > 12 + """, + # Goal: DR_blurprint=513, PRY_blueprint=343, tanrai_blueprint=100 + # Average time cost: 143.56399131945145 + # Average rewards: [520.06195858 519.19883191 392.86544828 392.64870495 392.49383995 102.2368499] + 'series_8_blueprint_305': """ + S8-DR0.5 > S8-PRY0.5 > S8-Q0.5 > S8-H0.5 > Q0.5 > S8-DR2.5 + > S8-G1.5 > S8-Q1 > S8-DR5 > 0.5 > S8-G4 > S8-Q2 > S8-PRY2.5 > reset + > S8-DR8 > Q1 > 1 > S8-E-315 > S8-G2.5 > G1.5 > 1.5 > S8-E-031 + > S8-Q4 > Q2 > E2 > 2 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-PRY5 + > S8-PRY8 > Q4 > G4 > 4 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8 + > S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12 + """, + # Goal: DR_blurprint=513, PRY_blueprint=343, tanrai_blueprint=0 + # Average time cost: 82.0121088194467 + # Average rewards: [519.0311752 514.64003687 653.77171198 653.72126532 653.66129615 26.97694791] + 'series_8_blueprint_only_cube': """ + S8-DR0.5 > S8-PRY0.5 > S8-H0.5 > S8-H1 > S8-H2 > S8-DR2.5 > S8-DR5 + > 0.5 > S8-DR8 > reset > S8-H4 > S8-Q1 > Q1 > H1 > 1 > S8-G1.5 > G1.5 + > 1.5 > S8-G2.5 > S8-Q2 > S8-E-315 > S8-E-031 > Q2 > E2 > H2 > 2 + > S8-PRY2.5 > S8-G4 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-Q4 > Q4 > G4 + > H4 > 4 > S8-PRY5 > S8-PRY8 > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 + > S8-C8 > S8-C12 > DR8 > PRY8 > C8 > 8 > C12 > 12 + """, + # Goal: DR_blurprint=513, PRY_blueprint=343, tanrai_blueprint=0 + # Average time cost: 124.71616166666873 + # Average rewards: [514.96354877 514.70099977 355.58865468 354.96831385 354.66888635 56.48432238] + 'series_8_blueprint_only': """ + S8-DR0.5 > S8-H0.5 > S8-PRY0.5 > S8-DR8 > S8-DR5 > S8-DR2.5 + > S8-G1.5 > S8-PRY2.5 > 0.5 > S8-G2.5 > S8-G4 > reset > S8-Q1 > Q1 + > 1 > S8-PRY5 > G1.5 > 1.5 > S8-Q2 > S8-E-031 > S8-E-315 > Q2 > E2 + > 2 > S8-PRY8 > DR2.5 > PRY2.5 > G2.5 > 2.5 > S8-Q4 > Q4 > G4 > 4 + > S8-C6 > DR5 > PRY5 > 5 > C6 > 6 > S8-C8 > DR8 > PRY8 > C8 > 8 + > S8-C12 > C12 > 12 + """, + # Goal: DR_blurprint=0, PRY_blueprint=0, tanrai_blueprint=150 + # Average time cost: 153.41706666666678 + # Average rewards: [238.69016631 238.37881965 529.71190834 528.92520834 528.39586667 150.07973333] 'series_7_la9_only_cube': """ S7-Q0.5 > S7-DR0.5 > S7-PRY0.5 > Q0.5 > S7-Q4 > S7-Q2 > S7-Q1 > 0.5 > S7-E-315 > S7-G1.5 > S7-G4 > Q1 > reset > S7-H1 > H1 > 1 > S7-E-031 diff --git a/module/research/preset_generator.py b/module/research/preset_generator.py index df9c3ee9e..616006254 100644 --- a/module/research/preset_generator.py +++ b/module/research/preset_generator.py @@ -80,6 +80,8 @@ def translate(string: str, target='series_4_tenrai_only_cube', for_simulate=Fals def convert_name(name, series): name = re.sub(r'series_\d', f'series_{series}', name) + if 'series_8' in name: + name = name.replace('tenrai', '305') if 'series_7' in name: name = name.replace('tenrai', 'la9') if 'series_6' in name: @@ -102,7 +104,7 @@ if __name__ == '__main__': Value( FILTER_STRING_CHEAPEST='Q1 > Q2 > T3 > T4 > Q4 > C6 > T6 > C8 > C12 > G1.5 > D2.5 > G2.5 > D5 > Q0.5 > G4 > D8 > H1 > H2 > H0.5 > D0.5 > H4') with Dict('DICT_FILTER_PRESET'): - for series in [7, 6, 5, 4, 3, 2]: + for series in [8, 7, 6, 5, 4, 3, 2]: def new_filter(**kwargs): for k, v in kwargs.items(): k = convert_name(k, series) diff --git a/module/research/project.py b/module/research/project.py index b77424c2f..5d211bdd6 100644 --- a/module/research/project.py +++ b/module/research/project.py @@ -400,13 +400,16 @@ def research_detect(image): class ResearchProject: REGEX_SHIP = re.compile( - '(neptune|monarch|ibuki|izumo|roon|saintlouis' + '(' + 'neptune|monarch|ibuki|izumo|roon|saintlouis' '|seattle|georgia|kitakaze|azuma|friedrich' '|gascogne|champagne|cheshire|drake|mainz|odin' '|anchorage|hakuryu|agir|august|marcopolo' '|plymouth|rupprecht|harbin|chkalov|brest' '|kearsarge|hindenburg|shimanto|schultz|flandre' - '|napoli|nakhimov|halford|bayard|daisen)') + '|napoli|nakhimov|halford|bayard|daisen' + '|goudenleeuw|mecklenburg|dmitri|kansas|vittorio' + ')') REGEX_INPUT = re.compile('(coin|cube|part)') REGEX_DR_SHIP = re.compile( 'azuma|friedrich' @@ -415,6 +418,7 @@ class ResearchProject: '|plymouth|brest' '|kearsarge|hindenburg' '|napoli|nakhimov' + '|goudenleeuw|mecklenburg' ) # Generate with: """ @@ -432,12 +436,13 @@ class ResearchProject: '779', '794', '305', '312', '346', '357', '379', '394', '721', '722', '772', '777', '795', '321', '322', '372', '377', '395', '708', '763', '775', '782', '768', '308', '363', '375', '382', '368', '719', '778', '786', '788', '793', '319', '378', '386', '388', '393', '783', '713', '739', '771', '796', '383', '313', '339', '371', '396', - '703', '758', '766', '790', '797', '303', '358', '366', '390', '397', '418', '431', '444', '459', '474', '492', - '018', '031', '044', '059', '074', '092', '405', '412', '446', '457', '479', '494', '005', '012', '046', '057', - '079', '094', '421', '422', '472', '477', '495', '021', '022', '072', '077', '095', '408', '463', '475', '482', - '468', '008', '063', '075', '082', '068', '419', '478', '486', '488', '493', '019', '078', '086', '088', '093', - '483', '413', '439', '471', '496', '083', '013', '039', '071', '096', '403', '458', '466', '490', '497', '003', - '058', '066', '090', '097'] + '703', '758', '766', '790', '797', '303', '358', '366', '390', '397', '780', '736', '787', '711', '764', '380', + '336', '387', '311', '364', '418', '431', '444', '459', '474', '492', '018', '031', '044', '059', '074', '092', + '405', '412', '446', '457', '479', '494', '005', '012', '046', '057', '079', '094', '421', '422', '472', '477', + '495', '021', '022', '072', '077', '095', '408', '463', '475', '482', '468', '008', '063', '075', '082', '068', + '419', '478', '486', '488', '493', '019', '078', '086', '088', '093', '483', '413', '439', '471', '496', '083', + '013', '039', '071', '096', '403', '458', '466', '490', '497', '003', '058', '066', '090', '097', '480', '436', + '487', '411', '464', '080', '036', '087', '011', '064'] def __init__(self, name, series): """ @@ -628,7 +633,8 @@ class ResearchProjectJp: SHIP_S5 = ['plymouth', 'rupprecht', 'harbin', 'chkalov', 'brest'] SHIP_S6 = ['kearsarge', 'hindenburg', 'shimanto', 'schultz', 'flandre'] SHIP_S7 = ['napoli', 'nakhimov', 'halford', 'bayard', 'daisen'] - SHIP_ALL = SHIP_S1 + SHIP_S2 + SHIP_S3 + SHIP_S4 + SHIP_S5 + SHIP_S6 + SHIP_S7 + SHIP_S8 = ['goudenleeuw', 'mecklenburg', 'dmitri', 'kansas', 'vittorio'] + SHIP_ALL = SHIP_S1 + SHIP_S2 + SHIP_S3 + SHIP_S4 + SHIP_S5 + SHIP_S6 + SHIP_S7 + SHIP_S8 DR_SHIP = [ 'azuma', 'friedrich', 'drake', @@ -636,6 +642,7 @@ class ResearchProjectJp: 'plymouth', 'brest', 'kearsarge', 'hindenburg', 'napoli', 'nakhimov', + 'goudenleeuw', 'mecklenburg', ] def __init__(self): diff --git a/module/research/project_data.py b/module/research/project_data.py index 6cf347614..9d7579029 100644 --- a/module/research/project_data.py +++ b/module/research/project_data.py @@ -19,7 +19,7 @@ LIST_RESEARCH_PROJECT = [ {'name': 'E-315-MI', 'series': 1, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-131-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Royal Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 381mm AA Gun Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-159-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 410mm Mounted Gun Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-174-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 203mm Main Gun (SK C) Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-174-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 203mm Main Gun (SK C) Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-192-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 203mm AA Gun Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-118-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Royal Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 Prototype Triple 152mm AA Gun Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-144-MI', 'series': 1, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'T0 100mm Mounted AA Gun Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, @@ -70,7 +70,7 @@ LIST_RESEARCH_PROJECT = [ {'name': 'T-249-MI', 'series': 2, 'time': 21600, 'task': 'Complete 6 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-031-MI', 'series': 2, 'time': 7200, 'task': 'Scrap 8 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-315-MI', 'series': 2, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, - {'name': 'E-179-MI', 'series': 2, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 406mm Main Gun (SK C/34) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-179-MI', 'series': 2, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 406mm Main Gun (SK C/34) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-105-MI', 'series': 2, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 152mm Main Gun (DP MK17) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-146-MI', 'series': 2, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype 40mm AA Gun (Type 5) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-157-MI', 'series': 2, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 310mm Main Gun (Type 0) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, @@ -125,7 +125,7 @@ LIST_RESEARCH_PROJECT = [ {'name': 'E-121-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Royal Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 234mm Main Gun (9.2" MK XII) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-123-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Royal Tech Pack', 'amount': 15}], 'output': [{'name': 'Twin 114mm DP (4.5" MK IV) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-124-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Royal Tech Pack', 'amount': 15}], 'output': [{'name': 'Sextuple Bofors 40mm AA Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-177-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 305mm Main Gun (SK C/39) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-177-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 305mm Main Gun (SK C/39) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-195-MI', 'series': 3, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 406mm/50 Main Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'G-412-MI', 'series': 3, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-236-MI', 'series': 3, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, @@ -172,10 +172,10 @@ LIST_RESEARCH_PROJECT = [ {'name': 'T-249-MI', 'series': 4, 'time': 21600, 'task': 'Complete 6 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-031-MI', 'series': 4, 'time': 7200, 'task': 'Scrap 8 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-315-MI', 'series': 4, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, - {'name': 'E-175-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 305mm SK C/39 Main Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-182-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype BF-109G T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-168-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 90mm Model 1939 High Angle Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-108-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 406mm Model 1940 Main Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-175-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 305mm SK C/39 Main Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-182-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype BF-109G T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-168-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 90mm Model 1939 High Angle Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-108-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 406mm Model 1940 Main Gun T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-163-MI', 'series': 4, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Saiun Kai T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'G-412-MI', 'series': 4, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-236-MI', 'series': 4, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, @@ -223,8 +223,8 @@ LIST_RESEARCH_PROJECT = [ {'name': 'E-031-MI', 'series': 5, 'time': 7200, 'task': 'Scrap 8 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-315-MI', 'series': 5, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-193-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Quadruple 330mm Mle 1931 (CB Only) Main Gun Mount Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-178-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Quadruple 30mm AA Gun Mount Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-186-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 130mm Model 1936 Main Gun Mount Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-178-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Quadruple 30mm AA Gun Mount Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-186-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 130mm Model 1936 Main Gun Mount Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-188-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Su-2 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-189-MI', 'series': 5, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype VIT-2 (VK-107) Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'G-412-MI', 'series': 5, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, @@ -274,9 +274,9 @@ LIST_RESEARCH_PROJECT = [ {'name': 'E-315-MI', 'series': 6, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-113-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 406mm Mk6 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-139-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 150mm Type 5 High-Angle Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-171-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 150mm TbtsK C42T Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-196-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 380mm Mle 1935 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, - {'name': 'E-184-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Ironblood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype 55mm Gerät 58 AA Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-171-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 150mm TbtsK C42T Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-196-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 380mm Mle 1935 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-184-MI', 'series': 6, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype 55mm Gerät 58 AA Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'G-412-MI', 'series': 6, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-236-MI', 'series': 6, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-531-MI', 'series': 6, 'time': 14400, 'task': '', 'input': [{'name': 'Coins', 'amount': 6000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, @@ -322,6 +322,11 @@ LIST_RESEARCH_PROJECT = [ {'name': 'T-249-MI', 'series': 7, 'time': 21600, 'task': 'Complete 6 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'E-031-MI', 'series': 7, 'time': 7200, 'task': 'Scrap 8 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, {'name': 'E-315-MI', 'series': 7, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'E-191-MI', 'series': 7, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype VIT-2 (Mode Change) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-166-MI', 'series': 7, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 254mm Model 1939 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-167-MI', 'series': 7, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Iron Blood Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Triple 152mm Model 1936 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-13-MI', 'series': 7, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Eagle Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype F8F Bearcat (Float) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-158-MI', 'series': 7, 'time': 21600, 'task': '', 'input': [{'name': 'T3 Sakura Tech Pack', 'amount': 15}], 'output': [{'name': 'Prototype Twin 410mm mod.A Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'G-412-MI', 'series': 7, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-236-MI', 'series': 7, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, {'name': 'G-531-MI', 'series': 7, 'time': 14400, 'task': '', 'input': [{'name': 'Coins', 'amount': 6000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, @@ -352,6 +357,51 @@ LIST_RESEARCH_PROJECT = [ {'name': 'Q-089-MI', 'series': 7, 'time': 14400, 'task': '', 'input': [{'name': 'T3 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'H-387-MI', 'series': 7, 'time': 3600, 'task': '', 'input': [{'name': 'Wisdom Cube', 'amount': 3}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T1 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, {'name': 'H-339-MI', 'series': 7, 'time': 7200, 'task': '', 'input': [{'name': 'Wisdom Cube', 'amount': 6}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T2 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, + {'name': 'C-153-MI', 'series': 8, 'time': 21600, 'task': '', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'C-185-MI', 'series': 8, 'time': 28800, 'task': '', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'B-622-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 3 or onward stages for 6 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'B-636-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 4 or onward stages for 6 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'B-654-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 5 or onward stages for 6 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'B-682-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 6 or onward stages for 6 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'B-235-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 7 or onward stages for 5 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'B-268-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 8 or onward stages for 5 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'B-128-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 9 or onward stages for 4 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'B-164-MI', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 10 or onward stages for 4 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'T-018-MI', 'series': 8, 'time': 10800, 'task': 'Complete 2 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'T-384-MI', 'series': 8, 'time': 14400, 'task': 'Complete 4 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'T-249-MI', 'series': 8, 'time': 21600, 'task': 'Complete 6 commissions.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-031-MI', 'series': 8, 'time': 7200, 'task': 'Scrap 8 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'E-315-MI', 'series': 8, 'time': 7200, 'task': 'Scrap 15 pieces of gear.', 'input': [], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'G-412-MI', 'series': 8, 'time': 5400, 'task': '', 'input': [{'name': 'Coins', 'amount': 1500}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'G-236-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'G-531-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'Coins', 'amount': 6000}], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-780-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Blueprint - Mecklenburg'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'D-736-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Blueprint - Gouden Leeuw'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'D-787-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Blueprint - Dmitri Donskoi'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'D-711-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Blueprint - Kansas'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'D-764-MI', 'series': 8, 'time': 9000, 'task': '', 'input': [{'name': 'Coins', 'amount': 3000}], 'output': [{'name': 'Blueprint - Vittorio Cuniberti'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}]}, + {'name': 'D-380-MI', 'series': 8, 'time': 18000, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}], 'output': [{'name': 'Blueprint - Mecklenburg'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-336-MI', 'series': 8, 'time': 18000, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}], 'output': [{'name': 'Blueprint - Gouden Leeuw'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-387-MI', 'series': 8, 'time': 18000, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}], 'output': [{'name': 'Blueprint - Dmitri Donskoi'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-311-MI', 'series': 8, 'time': 18000, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}], 'output': [{'name': 'Blueprint - Kansas'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-364-MI', 'series': 8, 'time': 18000, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}], 'output': [{'name': 'Blueprint - Vittorio Cuniberti'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-302-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'T1 General Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-310-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'T1 Main Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-351-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'T1 Torpedo Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-368-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'T1 Anti-Air Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-389-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'T1 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-202-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'T2 General Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-210-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'T2 Main Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-251-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'T2 Torpedo Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-268-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'T2 Anti-Air Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-289-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'T2 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T2'}, {'name': 'Coins'}]}, + {'name': 'Q-002-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'T3 General Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'Q-010-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'T3 Main Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'Q-051-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'T3 Torpedo Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'Q-068-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'T3 Anti-Air Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'Q-089-MI', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'T3 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'H-387-MI', 'series': 8, 'time': 3600, 'task': '', 'input': [{'name': 'Wisdom Cube', 'amount': 3}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T1 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, + {'name': 'H-339-MI', 'series': 8, 'time': 7200, 'task': '', 'input': [{'name': 'Wisdom Cube', 'amount': 6}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T2 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, {'name': 'C-038-RF', 'series': 1, 'time': 43200, 'task': '', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, {'name': 'B-351-RF', 'series': 1, 'time': 14400, 'task': 'Clear Chapter 11 or onward stages for 3 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, {'name': 'B-397-RF', 'series': 1, 'time': 14400, 'task': 'Clear Chapter 12 or onward stages for 3 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, @@ -525,4 +575,28 @@ LIST_RESEARCH_PROJECT = [ {'name': 'Q-068-UL', 'series': 7, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Anti-Air Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, {'name': 'Q-089-UL', 'series': 7, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, {'name': 'H-063-UL', 'series': 7, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}, {'name': 'Wisdom Cube', 'amount': 3}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T3 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, + {'name': 'E-866-MI', 'series': 7, 'time': 7200, 'task': '', 'input': [{'name': 'Twin 203mm Main Gun (M1927) T2 Design', 'amount': 45}], 'output': [{'name': 'Prototype Triple 254mm Model 1939 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-867-MI', 'series': 7, 'time': 7200, 'task': '', 'input': [{'name': 'Twin 120mm Main Gun (M1936) T3 Design', 'amount': 45}], 'output': [{'name': 'Prototype Triple 152mm Model 1936 Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-83-MI', 'series': 7, 'time': 7200, 'task': '', 'input': [{'name': 'T2 F6F Hellcat Design', 'amount': 45}], 'output': [{'name': 'Prototype F8F Bearcat (Float) T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'E-858-MI', 'series': 7, 'time': 7200, 'task': '', 'input': [{'name': 'T3 410mm Mounted Gun Design', 'amount': 45}], 'output': [{'name': 'Prototype Twin 410mm mod.A Main Gun Mount T0 Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'C-038-RF', 'series': 8, 'time': 43200, 'task': '', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}, {'name': 'Coins'}]}, + {'name': 'B-351-RF', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 11 or onward stages for 3 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'B-397-RF', 'series': 8, 'time': 14400, 'task': 'Clear Chapter 12 or onward stages for 3 times on Normal Mode ', 'input': [], 'output': [{'name': 'Random Blueprint'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-480-RF', 'series': 8, 'time': 28800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}], 'output': [{'name': 'Blueprint - Mecklenburg'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-436-RF', 'series': 8, 'time': 28800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}], 'output': [{'name': 'Blueprint - Gouden Leeuw'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-487-RF', 'series': 8, 'time': 28800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}], 'output': [{'name': 'Blueprint - Dmitri Donskoi'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-411-RF', 'series': 8, 'time': 28800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}], 'output': [{'name': 'Blueprint - Kansas'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-464-RF', 'series': 8, 'time': 28800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}], 'output': [{'name': 'Blueprint - Vittorio Cuniberti'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'H-207-RF', 'series': 8, 'time': 14400, 'task': '', 'input': [{'name': 'Wisdom Cube', 'amount': 10}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T3 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, + {'name': 'D-080-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'Wisdom Cube', 'amount': 5}], 'output': [{'name': 'Blueprint - Mecklenburg'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-036-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'Wisdom Cube', 'amount': 5}], 'output': [{'name': 'Blueprint - Gouden Leeuw'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-087-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'Wisdom Cube', 'amount': 5}], 'output': [{'name': 'Blueprint - Dmitri Donskoi'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-011-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'Wisdom Cube', 'amount': 5}], 'output': [{'name': 'Blueprint - Kansas'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'D-064-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'Wisdom Cube', 'amount': 5}], 'output': [{'name': 'Blueprint - Vittorio Cuniberti'}, {'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-002-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 General Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-010-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Main Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-051-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Torpedo Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-068-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Anti-Air Gun Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'Q-089-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 5000}, {'name': 'T3 Aircraft Part', 'amount': 20}], 'output': [{'name': 'Random Gear Design'}, {'name': 'Random Gear Design T3'}]}, + {'name': 'H-063-UL', 'series': 8, 'time': 1800, 'task': '', 'input': [{'name': 'Coins', 'amount': 8000}, {'name': 'Wisdom Cube', 'amount': 3}], 'output': [{'name': 'Random Blueprint'}, {'name': 'T3 Mystery Retrofit Blueprint'}, {'name': 'Cognitive Chips'}]}, ] diff --git a/module/research/selector.py b/module/research/selector.py index 2b24a834c..1aebedbd9 100644 --- a/module/research/selector.py +++ b/module/research/selector.py @@ -12,7 +12,7 @@ from module.research.project import research_detect, research_jp_detect from module.research.ui import ResearchUI RESEARCH_ENTRANCE = [ENTRANCE_1, ENTRANCE_2, ENTRANCE_3, ENTRANCE_4, ENTRANCE_5] -FILTER_REGEX = re.compile('(s[1234567])?' +FILTER_REGEX = re.compile('(s[12345678])?' '-?' '(neptune|monarch|ibuki|izumo|roon|saintlouis' '|seattle|georgia|kitakaze|azuma|friedrich' @@ -20,7 +20,8 @@ FILTER_REGEX = re.compile('(s[1234567])?' '|anchorage|hakuryu|agir|august|marcopolo' '|plymouth|rupprecht|harbin|chkalov|brest' '|kearsarge|hindenburg|shimanto|schultz|flandre' - '|nakhimov|napoli|halford|daisen|bayard)?' + '|napoli|nakhimov|halford|bayard|daisen' + '|goudenleeuw|mecklenburg|dmitri|kansas|vittorio)?' '(dr|pry)?' '([bcdeghqt])?' '-?' diff --git a/module/research/series.py b/module/research/series.py index c48a39eb1..479996d3d 100644 --- a/module/research/series.py +++ b/module/research/series.py @@ -14,6 +14,8 @@ RESEARCH_SCALING = [ def match_series(image, scaling): image = rgb2gray(image) + if TEMPLATE_S8.match(image, scaling=scaling): + return 8 if TEMPLATE_S7.match(image, scaling=scaling): return 7 if TEMPLATE_S6.match(image, scaling=scaling): diff --git a/module/retire/dock.py b/module/retire/dock.py index bbb8d3c35..198dcfe06 100644 --- a/module/retire/dock.py +++ b/module/retire/dock.py @@ -150,7 +150,7 @@ class DockNew(EquipmentNew): option_buttons=ButtonGrid( origin=(218, 268), delta=delta, button_shape=button_shape, grid_shape=(7, 2), name='FILTER_FACTION'), option_names=['all', 'eagle', 'royal', 'sakura', 'iron', 'dragon', 'sardegna', - 'northern', 'iris', 'vichya', 'other', 'not_available', 'not_available', 'not_available'], + 'northern', 'iris', 'vichya', 'tulipa', 'meta', 'tempesta', 'other'], option_default='all' ) setting.add_setting( @@ -165,7 +165,7 @@ class DockNew(EquipmentNew): option_buttons=ButtonGrid( origin=(218, 471), delta=delta, button_shape=button_shape, grid_shape=(7, 2), name='FILTER_EXTRA'), option_names=['no_limit', 'has_skin', 'can_retrofit', 'enhanceable', 'can_limit_break', 'not_level_max', 'can_awaken', - 'can_awaken_plus', 'special', 'oath_skin', 'unique_augment_module', 'not_available', 'not_available', 'not_available'], + 'can_awaken_plus', 'special', 'oath_skin', 'unique_augment_module', 'wear_skin', 'oathed', 'not_available'], option_default='no_limit' ) return setting diff --git a/module/reward/assets.py b/module/reward/assets.py index 75843e0ce..b55e14c33 100644 --- a/module/reward/assets.py +++ b/module/reward/assets.py @@ -6,7 +6,7 @@ from module.base.template import Template COIN = Button(area={'cn': (279, 48, 308, 73), 'en': (272, 53, 317, 73), 'jp': (279, 48, 308, 73), 'tw': (279, 48, 308, 73)}, color={'cn': (228, 175, 73), 'en': (221, 170, 75), 'jp': (228, 175, 73), 'tw': (228, 175, 73)}, button={'cn': (279, 48, 308, 73), 'en': (272, 53, 317, 73), 'jp': (279, 48, 308, 73), 'tw': (279, 48, 308, 73)}, file={'cn': './assets/cn/reward/COIN.png', 'en': './assets/en/reward/COIN.png', 'jp': './assets/jp/reward/COIN.png', 'tw': './assets/tw/reward/COIN.png'}) EXP = Button(area={'cn': (449, 31, 477, 49), 'en': (455, 51, 490, 71), 'jp': (449, 31, 477, 49), 'tw': (449, 31, 477, 49)}, color={'cn': (145, 158, 176), 'en': (133, 133, 145), 'jp': (145, 158, 176), 'tw': (145, 158, 176)}, button={'cn': (449, 31, 477, 49), 'en': (455, 51, 490, 71), 'jp': (449, 31, 477, 49), 'tw': (449, 31, 477, 49)}, file={'cn': './assets/cn/reward/EXP.png', 'en': './assets/en/reward/EXP.png', 'jp': './assets/jp/reward/EXP.png', 'tw': './assets/tw/reward/EXP.png'}) -MISSION_EMPTY = Button(area={'cn': (158, 347, 220, 378), 'en': (158, 348, 252, 373), 'jp': (158, 348, 221, 378), 'tw': (158, 347, 220, 378)}, color={'cn': (156, 160, 172), 'en': (167, 171, 182), 'jp': (155, 158, 170), 'tw': (156, 160, 172)}, button={'cn': (158, 347, 220, 378), 'en': (158, 348, 252, 373), 'jp': (158, 348, 221, 378), 'tw': (158, 347, 220, 378)}, file={'cn': './assets/cn/reward/MISSION_EMPTY.png', 'en': './assets/en/reward/MISSION_EMPTY.png', 'jp': './assets/jp/reward/MISSION_EMPTY.png', 'tw': './assets/cn/reward/MISSION_EMPTY.png'}) +MISSION_EMPTY = Button(area={'cn': (158, 347, 220, 378), 'en': (158, 348, 252, 373), 'jp': (158, 348, 221, 378), 'tw': (158, 347, 221, 378)}, color={'cn': (156, 160, 172), 'en': (167, 171, 182), 'jp': (155, 158, 170), 'tw': (154, 157, 169)}, button={'cn': (158, 347, 220, 378), 'en': (158, 348, 252, 373), 'jp': (158, 348, 221, 378), 'tw': (158, 347, 221, 378)}, file={'cn': './assets/cn/reward/MISSION_EMPTY.png', 'en': './assets/en/reward/MISSION_EMPTY.png', 'jp': './assets/jp/reward/MISSION_EMPTY.png', 'tw': './assets/tw/reward/MISSION_EMPTY.png'}) MISSION_MULTI = Button(area={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39), 'jp': (1041, 7, 1102, 36), 'tw': (1040, 6, 1102, 39)}, color={'cn': (226, 192, 142), 'en': (221, 179, 96), 'jp': (219, 178, 110), 'tw': (223, 184, 121)}, button={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39), 'jp': (1041, 7, 1102, 36), 'tw': (1040, 6, 1102, 39)}, file={'cn': './assets/cn/reward/MISSION_MULTI.png', 'en': './assets/en/reward/MISSION_MULTI.png', 'jp': './assets/jp/reward/MISSION_MULTI.png', 'tw': './assets/tw/reward/MISSION_MULTI.png'}) MISSION_NOTICE = Button(area={'cn': (940, 670, 945, 681), 'en': (940, 670, 945, 681), 'jp': (940, 670, 945, 681), 'tw': (940, 670, 945, 681)}, color={'cn': (183, 83, 66), 'en': (183, 83, 66), 'jp': (183, 83, 66), 'tw': (183, 83, 66)}, button={'cn': (940, 670, 945, 681), 'en': (940, 670, 945, 681), 'jp': (940, 670, 945, 681), 'tw': (940, 670, 945, 681)}, file={'cn': './assets/cn/reward/MISSION_NOTICE.png', 'en': './assets/en/reward/MISSION_NOTICE.png', 'jp': './assets/jp/reward/MISSION_NOTICE.png', 'tw': './assets/tw/reward/MISSION_NOTICE.png'}) MISSION_SINGLE = Button(area={'cn': (1096, 133, 1128, 163), 'en': (1130, 128, 1184, 150), 'jp': (1102, 120, 1166, 149), 'tw': (1090, 115, 1181, 166)}, color={'cn': (167, 200, 237), 'en': (170, 204, 239), 'jp': (136, 176, 226), 'tw': (108, 149, 216)}, button={'cn': (1096, 133, 1128, 163), 'en': (1130, 128, 1184, 150), 'jp': (1102, 120, 1166, 149), 'tw': (1090, 115, 1181, 166)}, file={'cn': './assets/cn/reward/MISSION_SINGLE.png', 'en': './assets/en/reward/MISSION_SINGLE.png', 'jp': './assets/jp/reward/MISSION_SINGLE.png', 'tw': './assets/tw/reward/MISSION_SINGLE.png'}) diff --git a/module/reward/reward.py b/module/reward/reward.py index 484f1c3eb..4b6b299d1 100644 --- a/module/reward/reward.py +++ b/module/reward/reward.py @@ -166,10 +166,6 @@ class Reward(UI): in: page_mission out: page_mission, MISSION_MULTI or MISSION_SINGLE or MISSION_UNFINISH """ - # MISSION_UNFINISH is available on CN only yet - if self.config.SERVER not in ['cn', 'en', 'jp']: - return - timeout = Timer(1, count=2).start() for _ in self.loop(): if timeout.reached(): diff --git a/module/shop/base.py b/module/shop/base.py index 10f20628b..00267dbf8 100644 --- a/module/shop/base.py +++ b/module/shop/base.py @@ -17,7 +17,7 @@ FILTER_REGEX = re.compile( '|chip|coin|cube|drill|food' '|plate|retrofit|pr|dr|specializedcore' '|logger|tuning' - '|hecombatplan|fragment' + '|hecombatplan|fragment|hiddenzonedatalogger' '|albacore|bataan|bearn|bluegill|carabiniere|casablanca|contedicavour|dukeofyork' '|echo|eldridge|gangut|glorious|grenville|hibiki|hunter|icarus' '|kawakaze|kinggeorgev|kinu|kuroshio|lagalissonniere|lemalinmuse|letemeraire|littorio' diff --git a/module/ui/assets.py b/module/ui/assets.py index b6f212b4d..c315576c2 100644 --- a/module/ui/assets.py +++ b/module/ui/assets.py @@ -31,6 +31,7 @@ DORMMENU_GOTO_ACADEMY = Button(area={'cn': (261, 487, 334, 587), 'en': (261, 487 DORMMENU_GOTO_DORM = Button(area={'cn': (408, 494, 541, 587), 'en': (408, 494, 541, 587), 'jp': (408, 494, 541, 587), 'tw': (408, 494, 541, 587)}, color={'cn': (167, 148, 137), 'en': (167, 148, 137), 'jp': (167, 148, 137), 'tw': (167, 148, 137)}, button={'cn': (408, 494, 541, 587), 'en': (408, 494, 541, 587), 'jp': (408, 494, 541, 587), 'tw': (408, 494, 541, 587)}, file={'cn': './assets/cn/ui/DORMMENU_GOTO_DORM.png', 'en': './assets/en/ui/DORMMENU_GOTO_DORM.png', 'jp': './assets/jp/ui/DORMMENU_GOTO_DORM.png', 'tw': './assets/tw/ui/DORMMENU_GOTO_DORM.png'}) DORMMENU_GOTO_MAIN = Button(area={'cn': (261, 487, 334, 587), 'en': (261, 487, 334, 587), 'jp': (261, 487, 334, 587), 'tw': (261, 487, 334, 587)}, color={'cn': (181, 172, 178), 'en': (181, 172, 178), 'jp': (181, 172, 178), 'tw': (181, 172, 178)}, button={'cn': (150, 153, 437, 279), 'en': (150, 153, 437, 279), 'jp': (150, 153, 437, 279), 'tw': (150, 153, 437, 279)}, file={'cn': './assets/cn/ui/DORMMENU_GOTO_MAIN.png', 'en': './assets/en/ui/DORMMENU_GOTO_MAIN.png', 'jp': './assets/jp/ui/DORMMENU_GOTO_MAIN.png', 'tw': './assets/tw/ui/DORMMENU_GOTO_MAIN.png'}) DORMMENU_GOTO_MEOWFFICER = Button(area={'cn': (634, 512, 749, 569), 'en': (634, 512, 749, 569), 'jp': (634, 512, 749, 569), 'tw': (634, 512, 749, 569)}, color={'cn': (144, 153, 176), 'en': (144, 153, 176), 'jp': (144, 153, 176), 'tw': (144, 153, 176)}, button={'cn': (634, 512, 749, 569), 'en': (634, 512, 749, 569), 'jp': (634, 512, 749, 569), 'tw': (634, 512, 749, 569)}, file={'cn': './assets/cn/ui/DORMMENU_GOTO_MEOWFFICER.png', 'en': './assets/en/ui/DORMMENU_GOTO_MEOWFFICER.png', 'jp': './assets/jp/ui/DORMMENU_GOTO_MEOWFFICER.png', 'tw': './assets/tw/ui/DORMMENU_GOTO_MEOWFFICER.png'}) +DORMMENU_GOTO_PRIVATE_QUARTERS = Button(area={'cn': (998, 581, 1148, 601), 'en': (998, 581, 1148, 601), 'jp': (998, 581, 1148, 601), 'tw': (998, 581, 1148, 601)}, color={'cn': (140, 140, 139), 'en': (140, 140, 139), 'jp': (140, 140, 139), 'tw': (140, 140, 139)}, button={'cn': (1010, 336, 1140, 596), 'en': (1010, 336, 1140, 596), 'jp': (1010, 336, 1140, 596), 'tw': (1010, 336, 1140, 596)}, file={'cn': './assets/cn/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png', 'en': './assets/en/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png', 'jp': './assets/jp/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png', 'tw': './assets/tw/ui/DORMMENU_GOTO_PRIVATE_QUARTERS.png'}) DORM_CHECK = Button(area={'cn': (949, 600, 1005, 654), 'en': (949, 600, 1005, 654), 'jp': (949, 600, 1005, 654), 'tw': (949, 600, 1005, 654)}, color={'cn': (255, 244, 209), 'en': (255, 244, 209), 'jp': (255, 244, 209), 'tw': (255, 244, 209)}, button={'cn': (949, 600, 1005, 654), 'en': (949, 600, 1005, 654), 'jp': (949, 600, 1005, 654), 'tw': (949, 600, 1005, 654)}, file={'cn': './assets/cn/ui/DORM_CHECK.png', 'en': './assets/en/ui/DORM_CHECK.png', 'jp': './assets/jp/ui/DORM_CHECK.png', 'tw': './assets/tw/ui/DORM_CHECK.png'}) DORM_FEED_CANCEL = Button(area={'cn': (494, 510, 547, 536), 'en': (445, 491, 594, 552), 'jp': (466, 510, 519, 536), 'tw': (484, 509, 557, 540)}, color={'cn': (196, 161, 109), 'en': (240, 200, 125), 'jp': (194, 160, 108), 'tw': (212, 174, 110)}, button={'cn': (494, 510, 547, 536), 'en': (445, 491, 594, 552), 'jp': (466, 510, 519, 536), 'tw': (484, 509, 557, 540)}, file={'cn': './assets/cn/ui/DORM_FEED_CANCEL.png', 'en': './assets/en/ui/DORM_FEED_CANCEL.png', 'jp': './assets/jp/ui/DORM_FEED_CANCEL.png', 'tw': './assets/tw/ui/DORM_FEED_CANCEL.png'}) DORM_GOTO_MAIN = Button(area={'cn': (40, 30, 62, 60), 'en': (40, 30, 62, 60), 'jp': (40, 30, 62, 60), 'tw': (40, 30, 62, 60)}, color={'cn': (255, 226, 133), 'en': (255, 226, 133), 'jp': (255, 226, 133), 'tw': (255, 226, 133)}, button={'cn': (40, 30, 62, 60), 'en': (40, 30, 62, 60), 'jp': (40, 30, 62, 60), 'tw': (40, 30, 62, 60)}, file={'cn': './assets/cn/ui/DORM_GOTO_MAIN.png', 'en': './assets/en/ui/DORM_GOTO_MAIN.png', 'jp': './assets/jp/ui/DORM_GOTO_MAIN.png', 'tw': './assets/tw/ui/DORM_GOTO_MAIN.png'}) @@ -71,6 +72,8 @@ OCR_PLAYER_EXP = Button(area={'cn': (1075, 162, 1266, 184), 'en': (1075, 162, 12 OCR_PLAYER_LEVEL = Button(area={'cn': (1158, 125, 1269, 156), 'en': (1158, 125, 1269, 156), 'jp': (1158, 125, 1269, 156), 'tw': (1158, 125, 1269, 156)}, color={'cn': (108, 105, 125), 'en': (108, 105, 125), 'jp': (108, 105, 125), 'tw': (108, 105, 125)}, button={'cn': (1158, 125, 1269, 156), 'en': (1158, 125, 1269, 156), 'jp': (1158, 125, 1269, 156), 'tw': (1158, 125, 1269, 156)}, file={'cn': './assets/cn/ui/OCR_PLAYER_LEVEL.png', 'en': './assets/cn/ui/OCR_PLAYER_LEVEL.png', 'jp': './assets/cn/ui/OCR_PLAYER_LEVEL.png', 'tw': './assets/cn/ui/OCR_PLAYER_LEVEL.png'}) OS_CHECK = Button(area={'cn': (613, 17, 627, 34), 'en': (613, 17, 627, 34), 'jp': (613, 17, 627, 34), 'tw': (613, 17, 627, 34)}, color={'cn': (58, 117, 146), 'en': (58, 117, 146), 'jp': (58, 117, 146), 'tw': (58, 117, 146)}, button={'cn': (613, 17, 627, 34), 'en': (613, 17, 627, 34), 'jp': (613, 17, 627, 34), 'tw': (613, 17, 627, 34)}, file={'cn': './assets/cn/ui/OS_CHECK.png', 'en': './assets/en/ui/OS_CHECK.png', 'jp': './assets/jp/ui/OS_CHECK.png', 'tw': './assets/tw/ui/OS_CHECK.png'}) PLAYER_CHECK = Button(area={'cn': (28, 668, 139, 688), 'en': (11, 649, 157, 705), 'jp': (26, 668, 139, 689), 'tw': (28, 668, 139, 688)}, color={'cn': (237, 204, 127), 'en': (197, 156, 97), 'jp': (237, 205, 128), 'tw': (237, 204, 127)}, button={'cn': (28, 668, 139, 688), 'en': (11, 649, 157, 705), 'jp': (26, 668, 139, 689), 'tw': (28, 668, 139, 688)}, file={'cn': './assets/cn/ui/PLAYER_CHECK.png', 'en': './assets/en/ui/PLAYER_CHECK.png', 'jp': './assets/jp/ui/PLAYER_CHECK.png', 'tw': './assets/tw/ui/PLAYER_CHECK.png'}) +PQ_GOTO_MAIN = Button(area={'cn': (1107, 19, 1143, 51), 'en': (1107, 19, 1143, 51), 'jp': (1107, 19, 1143, 51), 'tw': (1107, 19, 1143, 51)}, color={'cn': (199, 199, 199), 'en': (199, 199, 199), 'jp': (199, 199, 199), 'tw': (199, 199, 199)}, button={'cn': (1107, 19, 1143, 51), 'en': (1107, 19, 1143, 51), 'jp': (1107, 19, 1143, 51), 'tw': (1107, 19, 1143, 51)}, file={'cn': './assets/cn/ui/PQ_GOTO_MAIN.png', 'en': './assets/cn/ui/PQ_GOTO_MAIN.png', 'jp': './assets/cn/ui/PQ_GOTO_MAIN.png', 'tw': './assets/cn/ui/PQ_GOTO_MAIN.png'}) +PRIVATE_QUARTERS_CHECK = Button(area={'cn': (123, 18, 218, 47), 'en': (130, 25, 278, 41), 'jp': (130, 25, 278, 41), 'tw': (130, 25, 278, 41)}, color={'cn': (106, 109, 113), 'en': (149, 153, 159), 'jp': (149, 153, 159), 'tw': (149, 153, 159)}, button={'cn': (123, 18, 218, 47), 'en': (130, 25, 278, 41), 'jp': (130, 25, 278, 41), 'tw': (130, 25, 278, 41)}, file={'cn': './assets/cn/ui/PRIVATE_QUARTERS_CHECK.png', 'en': './assets/en/ui/PRIVATE_QUARTERS_CHECK.png', 'jp': './assets/jp/ui/PRIVATE_QUARTERS_CHECK.png', 'tw': './assets/tw/ui/PRIVATE_QUARTERS_CHECK.png'}) RAID_CHECK = Button(area={'cn': (107, 13, 216, 38), 'en': (116, 18, 174, 35), 'jp': (107, 13, 217, 40), 'tw': (111, 9, 228, 42)}, color={'cn': (129, 131, 129), 'en': (133, 118, 117), 'jp': (127, 129, 127), 'tw': (132, 154, 140)}, button={'cn': (107, 13, 216, 38), 'en': (116, 18, 174, 35), 'jp': (107, 13, 217, 40), 'tw': (111, 9, 228, 42)}, file={'cn': './assets/cn/ui/RAID_CHECK.png', 'en': './assets/en/ui/RAID_CHECK.png', 'jp': './assets/jp/ui/RAID_CHECK.png', 'tw': './assets/tw/ui/RAID_CHECK.png'}) RESEARCH_CHECK = Button(area={'cn': (118, 15, 170, 39), 'en': (119, 14, 259, 36), 'jp': (117, 14, 171, 40), 'tw': (117, 13, 172, 40)}, color={'cn': (165, 179, 215), 'en': (118, 133, 174), 'jp': (135, 154, 195), 'tw': (148, 165, 205)}, button={'cn': (118, 15, 170, 39), 'en': (119, 14, 259, 36), 'jp': (117, 14, 171, 40), 'tw': (117, 13, 172, 40)}, file={'cn': './assets/cn/ui/RESEARCH_CHECK.png', 'en': './assets/en/ui/RESEARCH_CHECK.png', 'jp': './assets/jp/ui/RESEARCH_CHECK.png', 'tw': './assets/tw/ui/RESEARCH_CHECK.png'}) RESHMENU_CHECK = Button(area={'cn': (121, 15, 174, 39), 'en': (118, 14, 279, 35), 'jp': (116, 13, 174, 42), 'tw': (121, 14, 175, 40)}, color={'cn': (156, 171, 209), 'en': (100, 113, 152), 'jp': (136, 149, 186), 'tw': (147, 162, 201)}, button={'cn': (121, 15, 174, 39), 'en': (118, 14, 279, 35), 'jp': (116, 13, 174, 42), 'tw': (121, 14, 175, 40)}, file={'cn': './assets/cn/ui/RESHMENU_CHECK.png', 'en': './assets/en/ui/RESHMENU_CHECK.png', 'jp': './assets/jp/ui/RESHMENU_CHECK.png', 'tw': './assets/tw/ui/RESHMENU_CHECK.png'}) diff --git a/module/ui/page.py b/module/ui/page.py index c79016c6a..b34c22a90 100644 --- a/module/ui/page.py +++ b/module/ui/page.py @@ -266,6 +266,11 @@ page_academy = Page(ACADEMY_CHECK) page_dormmenu.link(button=DORMMENU_GOTO_ACADEMY, destination=page_academy) page_academy.link(button=GOTO_MAIN, destination=page_main) +# Private Quarters +page_private_quarters = Page(PRIVATE_QUARTERS_CHECK) +page_dormmenu.link(button=DORMMENU_GOTO_PRIVATE_QUARTERS, destination=page_private_quarters) +page_private_quarters.link(button=PQ_GOTO_MAIN, destination=page_main) + # Game room & choose game page_game_room = Page(GAME_ROOM_CHECK) page_academy.link(button=ACADEMY_GOTO_GAME_ROOM, destination=page_game_room) diff --git a/module/ui/ui.py b/module/ui/ui.py index 7f14e0f68..a29d6d951 100644 --- a/module/ui/ui.py +++ b/module/ui/ui.py @@ -268,10 +268,11 @@ class UI(InfoHandler): self.ui_goto_old(destination, *args, **kwargs) - def ui_goto_old(self, destination, offset=(30, 30), skip_first_screenshot=True): + def ui_goto_old(self, destination, get_ship=True, offset=(30, 30), skip_first_screenshot=True): """ Args: destination (Page): + get_ship: offset: skip_first_screenshot: """ @@ -313,7 +314,7 @@ class UI(InfoHandler): continue # Additional - if self.ui_additional(): + if self.ui_additional(get_ship=get_ship): continue # Reset connection @@ -507,6 +508,9 @@ class UI(InfoHandler): def ui_additional(self, get_ship=True): """ Handle all annoying popups during UI switching. + + Args: + get_ship: """ # Popups appear at page_os # Has a popup_confirm variant diff --git a/module/war_archives/assets.py b/module/war_archives/assets.py index 79bd184cc..7d31f3f11 100644 --- a/module/war_archives/assets.py +++ b/module/war_archives/assets.py @@ -6,6 +6,7 @@ from module.base.template import Template OCR_DATA_KEY_CAMPAIGN = Button(area={'cn': (1188, 107, 1272, 131), 'en': (1188, 107, 1272, 131), 'jp': (1188, 107, 1272, 131), 'tw': (1188, 107, 1272, 131)}, color={'cn': (104, 101, 107), 'en': (104, 101, 107), 'jp': (104, 101, 107), 'tw': (104, 101, 107)}, button={'cn': (1188, 107, 1272, 131), 'en': (1188, 107, 1272, 131), 'jp': (1188, 107, 1272, 131), 'tw': (1188, 107, 1272, 131)}, file={'cn': './assets/cn/war_archives/OCR_DATA_KEY_CAMPAIGN.png', 'en': './assets/en/war_archives/OCR_DATA_KEY_CAMPAIGN.png', 'jp': './assets/jp/war_archives/OCR_DATA_KEY_CAMPAIGN.png', 'tw': './assets/tw/war_archives/OCR_DATA_KEY_CAMPAIGN.png'}) TEMPLATE_ABYSSAL_REFRAIN = Template(file={'cn': './assets/cn/war_archives/TEMPLATE_ABYSSAL_REFRAIN.png', 'en': './assets/cn/war_archives/TEMPLATE_ABYSSAL_REFRAIN.png', 'jp': './assets/cn/war_archives/TEMPLATE_ABYSSAL_REFRAIN.png', 'tw': './assets/cn/war_archives/TEMPLATE_ABYSSAL_REFRAIN.png'}) +TEMPLATE_AQUILIFERS_BALLADE = Template(file={'cn': './assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png', 'en': './assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png', 'jp': './assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png', 'tw': './assets/cn/war_archives/TEMPLATE_AQUILIFERS_BALLADE.png'}) TEMPLATE_ASHEN_SIMULACRUM = Template(file={'cn': './assets/cn/war_archives/TEMPLATE_ASHEN_SIMULACRUM.png', 'en': './assets/en/war_archives/TEMPLATE_ASHEN_SIMULACRUM.png', 'jp': './assets/cn/war_archives/TEMPLATE_ASHEN_SIMULACRUM.png', 'tw': './assets/cn/war_archives/TEMPLATE_ASHEN_SIMULACRUM.png'}) TEMPLATE_AURORA_NOCTIS = Template(file={'cn': './assets/cn/war_archives/TEMPLATE_AURORA_NOCTIS.png', 'en': './assets/en/war_archives/TEMPLATE_AURORA_NOCTIS.png', 'jp': './assets/cn/war_archives/TEMPLATE_AURORA_NOCTIS.png', 'tw': './assets/cn/war_archives/TEMPLATE_AURORA_NOCTIS.png'}) TEMPLATE_COUNTERATTACK_WITHIN_THE_FJORD = Template(file={'cn': './assets/cn/war_archives/TEMPLATE_COUNTERATTACK_WITHIN_THE_FJORD.png', 'en': './assets/cn/war_archives/TEMPLATE_COUNTERATTACK_WITHIN_THE_FJORD.png', 'jp': './assets/cn/war_archives/TEMPLATE_COUNTERATTACK_WITHIN_THE_FJORD.png', 'tw': './assets/cn/war_archives/TEMPLATE_COUNTERATTACK_WITHIN_THE_FJORD.png'}) diff --git a/module/war_archives/dictionary.py b/module/war_archives/dictionary.py index 13fbc3704..d9481a689 100644 --- a/module/war_archives/dictionary.py +++ b/module/war_archives/dictionary.py @@ -39,4 +39,5 @@ dic_archives_template = { 'war_archives_20220224_cn': TEMPLATE_ABYSSAL_REFRAIN, 'war_archives_20220324_cn': TEMPLATE_VIRTUAL_TOWER, 'war_archives_20220526_cn': TEMPLATE_PLEDGE_OF_THE_RADIANT_COURT, + 'war_archives_20220728_cn': TEMPLATE_AQUILIFERS_BALLADE, } diff --git a/module/webui/app.py b/module/webui/app.py index b43ed684a..22e5a8f40 100644 --- a/module/webui/app.py +++ b/module/webui/app.py @@ -64,7 +64,7 @@ from module.webui.base import Frame from module.webui.discord_presence import close_discord_rpc, init_discord_rpc from module.webui.fastapi import asgi_app from module.webui.lang import _t, t -from module.webui.patch import patch_executor +from module.webui.patch import patch_executor, patch_mimetype from module.webui.pin import put_input, put_select, pin_update from module.webui.process_manager import ProcessManager from module.webui.remote_access import RemoteAccess @@ -96,6 +96,7 @@ from module.webui.widgets import ( ) patch_executor() +patch_mimetype() task_handler = TaskHandler() diff --git a/module/webui/patch.py b/module/webui/patch.py index 09c0b0a71..d9d7609d2 100644 --- a/module/webui/patch.py +++ b/module/webui/patch.py @@ -39,3 +39,28 @@ def patch_executor(): loop = asyncio.get_event_loop() loop.set_default_executor(CachedThreadPoolExecutor.executor) + + +def patch_mimetype(): + """ + Patch mimetype db to use the builtin table instead of reading from environment. + + By default, mimetype reads user configured mimetype table from environment. It's good for server but bad on our + side, because we deploy on user's machine which may have polluted environment. To have a consistent behaviour on + all deployment, we use the builtin mimetype table only. + """ + import mimetypes + if mimetypes.inited: + # ohno mimetypes already inited + db = mimetypes.MimeTypes() + mimetypes._db = db + # override global variable + mimetypes.encodings_map = db.encodings_map + mimetypes.suffix_map = db.suffix_map + mimetypes.types_map = db.types_map[True] + mimetypes.common_types = db.types_map[False] + else: + # init db with the default table + db = mimetypes.MimeTypes() + mimetypes._db = db + mimetypes.inited = True