From d1e398bdb85295fbc9095102719e877ff913cda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=97?= <152146621+wess09@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:24:29 +0800 Subject: [PATCH 1/2] Dev (#232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(island): 适配商店新布局,拆分商店入口与购买返回检测,典雅之木翻译错误 (#230) * fix(island): 适配商店新布局,拆分商店入口与购买返回检测,典雅之木翻译错误 - 新增 ISLAND_SEED_SHOP_RETURN_CHECK 按钮,page_island_shop 入口改用新检测区域 (125,21,216,46) - ISLAND_SHOP_CHECK 保留原区域,用于 buy_seeds() 购买后返回检测 - 更新 ISLAND_FRY_SHOP_CHECK 检测区域为 (125,21,216,46) - 新增 dev_tools/button_region_editor.py 通用工具,支持按区域裁剪/置黑处理按钮图片 - 修复典雅之木翻译错误显示为优雅之木 * fix 调度器默认值 * fix:道中战斗失败撤退——修复了boss战失败时卡死的bug (#231) --------- Co-authored-by: quankong1551 <96553536+quankong1551@users.noreply.github.com> Co-authored-by: 鄜月 <73020805+moon-dim@users.noreply.github.com> --- .../island_fishery/ISLAND_FRY_SHOP_CHECK.png | Bin 6261 -> 7688 bytes assets/cn/map/FLEET_WITHDRAW_BOSS.png | Bin 0 -> 7895 bytes .../cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png | Bin 0 -> 7463 bytes assets/cn/ui/ISLAND_SHOP_CHECK.png | Bin 7710 -> 7594 bytes config/template.json | 12 +- dev_tools/button_region_editor.py | 139 +++ doc/island_feature_plan.md | 1035 +++++++++++++++++ module/combat/auto_search_combat.py | 5 +- module/config/argument/args.json | 53 +- module/config/argument/argument.yaml | 7 +- module/config/argument/task.yaml | 1 - module/config/config_generated.py | 2 +- module/config/i18n/zh-CN.json | 14 +- module/island_fishery/assets.py | 2 +- module/map/assets.py | 1 + module/ui/assets.py | 3 +- module/ui/page.py | 2 +- 17 files changed, 1198 insertions(+), 78 deletions(-) create mode 100644 assets/cn/map/FLEET_WITHDRAW_BOSS.png create mode 100644 assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png create mode 100644 dev_tools/button_region_editor.py create mode 100644 doc/island_feature_plan.md diff --git a/assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png b/assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png index ee876f3d197f14386906d46b75614c4f0a016498..8bd97d0b5b1a5e186ea55253c83bb7111cbde7eb 100644 GIT binary patch delta 5123 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 W^W1N$1&Uk&K`%R9D!q97@BasRrT4)A literal 6261 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 YyeO%keeZSYeOvH`t+P#&RY3ZG0UYR~WdHyG diff --git a/assets/cn/map/FLEET_WITHDRAW_BOSS.png b/assets/cn/map/FLEET_WITHDRAW_BOSS.png new file mode 100644 index 0000000000000000000000000000000000000000..243f3f38daaf5560e2aa0ba3b06736ee7f49547b GIT binary patch literal 7895 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 Q->(7m^gh$ze&z4~1r^#!fdBvi literal 0 HcmV?d00001 diff --git a/assets/cn/ui/ISLAND_SHOP_CHECK.png b/assets/cn/ui/ISLAND_SHOP_CHECK.png index 2e21cd4dc2ecfaf191c6f2ab6a2b476aec300297..3c6a9554abc20094b62d86b3535c41c84d8a4088 100644 GIT binary patch literal 7594 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 literal 7710 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

ucyc-JUrYc!(nuMJToor z?(W17e7>@RGH7v8p_NYx9Mlxj(;sgwXI{9_cX4KHYKn=EPq?$Yca~ph8nJhI!p%VD zM&-Ups(zx!`68Z0-QAjKl++FfHMvoN;D*UQtsJe;=9hp!NljEWWmV8%+D>{}S|X!C zSE8W2M|sbln6V?EW9nP%xWx#O-DG%4@qxd7kTB2;l;Ir=U2s?m=jX&ieV*DbbC(C& zv1T7*yyV-x4)Ruv*Quo^{vq^gTI6Pmou7Q>J@ikEQ~XbUI_koE2(a2 diff --git a/config/template.json b/config/template.json index bde3867e6..b49bcac26 100644 --- a/config/template.json +++ b/config/template.json @@ -169,7 +169,7 @@ "FleetOnsen": false }, "YukikazeTaskManager": { - "TaskPriorityAdjustment": "Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies > Island\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive \n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost" + "TaskPriorityAdjustment": "Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive\n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> IslandJuuEatery > IslandJuuCoffee > IslandGrill > IslandTeahouse > IslandRestaurant\n> IslandFarm > IslandRancher > IslandMineForest > IslandDailyGather > IslandManufacture\n> IslandAirDrop > IslandBusiness\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost" }, "Storage": { "Storage": {} @@ -2699,16 +2699,6 @@ } }, "IslandPlan": { - "Scheduler": { - "Enable": false, - "PushNotification": false, - "NextRun": "2020-01-01 00:00:00", - "Command": "IslandPlan", - "SuccessInterval": 0, - "FailureInterval": 120, - "ServerUpdate": "00:00", - "Sensitive": false - }, "IslandPlan": { "Season": "spring" }, diff --git a/dev_tools/button_region_editor.py b/dev_tools/button_region_editor.py new file mode 100644 index 000000000..cadfc2d33 --- /dev/null +++ b/dev_tools/button_region_editor.py @@ -0,0 +1,139 @@ +""" +按钮区域图像编辑器 —— button_extract.py 的逆向工具。 + +对指定的按钮图片按给定区域坐标进行处理,然后运行 button_extract.py 即可重新生成 +正确的 area/color/button 值。 + +处理规则: + - TEMPLATE_* 开头的图片:裁剪出区域内的像素,另存为小图(模板匹配用) + - 非 TEMPLATE 的普通 Button 图片:将区域外的像素全部置黑 (0,0,0), + 保留区域内像素不变。这样 button_extract.py 的 get_bbox() 会自动检测到正确的边界框。 + +使用方法: + 1. 在下面的 TASKS 列表中填写要处理的图片路径和区域坐标 + 2. 运行: python dev_tools/button_region_editor.py + 3. 处理完毕后,运行 button_extract.py 重新生成 assets.py: + uv run python -m dev_tools.button_extract +""" + +import os +import sys + +import numpy as np +from PIL import Image + +# ============================================================ +# 【在此处填写要处理的图片路径和目标区域坐标】 +# 格式: ("图片路径(相对项目根目录)", (x1, y1, x2, y2)) +# ============================================================ +TASKS = [ + ("./assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png", (125, 21, 216, 46)), + +] + + +def process_button_image(img_path, area): + """ + 处理普通 Button 图片: + - 将区域 (x1,y1,x2,y2) 之外的像素全部置黑 (0,0,0) + - 区域内像素保持不变 + - 图片尺寸保持 1280x720 不变 + """ + print(f" [Button] 处理: {os.path.basename(img_path)}, 区域={area}") + + img = Image.open(img_path).convert("RGB") + arr = np.array(img, dtype=np.uint8) + + if arr.shape[:2] != (720, 1280): + print(f" [WARN] 图片尺寸不是 1280x720,实际为 {arr.shape[1]}x{arr.shape[0]}") + + x1, y1, x2, y2 = area + # 创建全黑画布 + black = np.zeros_like(arr) + # 只复制区域内像素 + black[y1:y2, x1:x2] = arr[y1:y2, x1:x2] + + # 保存 + result = Image.fromarray(black, "RGB") + result.save(img_path) + print(f" [OK] 已保存(区域外已置黑): {img_path}") + return True + + +def process_template_image(img_path, area): + """ + 处理 TEMPLATE 图片: + - 从原图中裁剪出 area 区域 + - 另存为小图(只包含区域内像素) + """ + print(f" [Template] 处理: {os.path.basename(img_path)}, 区域={area}") + + img = Image.open(img_path).convert("RGB") + x1, y1, x2, y2 = area + # 裁剪区域 + cropped = img.crop((x1, y1, x2, y2)) + + cropped.save(img_path) + w, h = x2 - x1, y2 - y1 + print(f" [OK] 已保存(裁剪为 {w}x{h}): {img_path}") + return True + + +def run(): + print("=" * 60) + print("按钮区域图像编辑器 - button_extract 逆向工具") + print("=" * 60) + + if not TASKS: + print("[ERR] TASKS 列表为空,请先在脚本顶部填写要处理的图片路径和区域坐标。") + sys.exit(1) + + # 切换到项目根目录 + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(script_dir) + os.chdir(project_root) + print(f"项目根目录: {project_root}") + print() + + success_count = 0 + error_count = 0 + + for img_path, area in TASKS: + # 校验区域坐标 + x1, y1, x2, y2 = area + if x1 < 0 or y1 < 0 or x2 > 1280 or y2 > 720 or x1 >= x2 or y1 >= y2: + print(f" [ERR] 无效区域坐标 {area}(图片尺寸 1280x720): {img_path}") + error_count += 1 + continue + + # 检查图片是否存在 + abs_path = os.path.join(project_root, img_path) + if not os.path.exists(abs_path): + print(f" [ERR] 文件不存在: {img_path}") + error_count += 1 + continue + + # 根据文件名判断类型 + basename = os.path.basename(img_path) + if basename.startswith("TEMPLATE_"): + ok = process_template_image(abs_path, area) + else: + ok = process_button_image(abs_path, area) + + if ok: + success_count += 1 + else: + error_count += 1 + + print() + print("=" * 60) + print(f"处理完成:成功 {success_count} 个,失败 {error_count} 个") + if success_count > 0: + print() + print("下一步:运行 button_extract.py 重新生成 assets.py:") + print(" uv run python -m dev_tools.button_extract") + print("=" * 60) + + +if __name__ == "__main__": + run() diff --git a/doc/island_feature_plan.md b/doc/island_feature_plan.md new file mode 100644 index 000000000..7c9307ebf --- /dev/null +++ b/doc/island_feature_plan.md @@ -0,0 +1,1035 @@ +# 岛屿功能扩展设计文档 + +> 本文档记录岛屿模块新增功能的详细设计方案。 + +--- + +## 实现进度 TODO + +- [ ] **功能1**: 岛屿计划 TODO 列表 — 创建统一的任务计划管理器 +- [ ] **功能2**: 矿山/森林按库存阈值执行 — 检测仓库数量,低于阈值才安排生产 +- [ ] **功能3**: 每日订单功能 — 自动接取和完成每日订单 +- [ ] **功能4**: 货运委托功能 — 集成已有运输系统到 TODO 列表 +- [ ] **功能5**: 每周珍珠售卖 — 按配置日自动全量卖出珍珠 +- [ ] **功能6**: 经营模块智能分波 — 季节限定数量检测替换 + 加成商品检测替换 +- [ ] **功能7**: 自动采集角色体力检测 — 体力 < 100 自动换人 +- [ ] **功能8**: 摸猫/JUU速运任务 — 每日互动任务 +- [ ] **功能9**: 给三个小人打招呼 — NPC 互动 +- [ ] 配置系统:更新 [`argument.yaml`](module/config/argument/argument.yaml) 和 [`task.yaml`](module/config/argument/task.yaml) +- [ ] i18n:更新翻译文件 +- [ ] 运行配置生成器 + +--- + +## 目录 + +1. [功能1: 岛屿计划 TODO 列表](#功能1-岛屿计划-todo-列表) +2. [功能2: 矿山/森林按库存阈值执行](#功能2-矿山森林按库存阈值执行) +3. [功能3: 每日订单功能](#功能3-每日订单功能) +4. [功能4: 货运委托功能](#功能4-货运委托功能) +5. [功能5: 每周珍珠售卖](#功能5-每周珍珠售卖) +6. [功能6: 经营模块智能分波](#功能6-经营模块智能分波) +7. [功能7: 自动采集角色体力检测换人](#功能7-自动采集角色体力检测换人) +8. [功能8: 摸猫/JUU速运任务](#功能8-摸猫juu速运任务) +9. [功能9: 给三个小人打招呼](#功能9-给三个小人打招呼) +10. [配置变更总览](#配置变更总览) +11. [任务调度集成](#任务调度集成) + +--- + +## 功能1: 岛屿计划 TODO 列表 + +### 目标 + +创建一个统一的任务计划管理系统,让所有岛屿任务模块共享一个 `TODO` 列表。每次岛屿任务运行时,先生成 TODO 列表,按优先级排序执行。 + +### 设计方案 + +**新文件**: [`module/island/island_todo.py`](module/island/island_todo.py) + +#### 核心类: `IslandTodo` + +```python +class IslandTodo(Island): + """岛屿任务 TODO 列表管理器""" + + # 任务优先级 + PRIORITY_MAP = { + 'receive_transport': 10, # 收取货运委托 + 'daily_order': 20, # 每日订单 + 'pearl_selling': 30, # 每周珍珠(仅周一) + 'pet_cat': 35, # 摸猫 + 'juu_express': 36, # 啾啾速运 + 'greet': 37, # 打招呼 + 'farm': 40, # 农场 + 'mine_forest': 50, # 矿山/森林 + 'ranch': 60, # 牧场 + 'fishery': 61, # 渔场 + 'business_wave1': 70, # 经营第一波 + 'business_wave2': 71, # 经营第二波 + 'manufacture': 80, # 制造 + 'restaurant': 90, # 餐馆 + 'teahouse': 91, # 茶馆 + 'grill': 92, # 烤肉 + 'juu_eatery': 93, # 啾啾简餐 + 'juu_coffee': 94, # 啾咖啡 + 'daily_gather': 100, # 每日采集 + 'air_drop': 110, # 空投 + 'season_task': 120, # 季节任务 + 'transport_start': 130, # 开始货运委托 + } +``` + +#### TODO 条目结构 + +```python +class TodoItem: + task_id: str # 如 'farm', 'mine_forest' + priority: int # 优先级数字(越小越先执行) + enabled: bool # 用户配置是否启用 + description: str # 描述 + run_func: callable # 执行函数引用 +``` + +#### 执行流程 + +``` +IslandTodo.run() + ├── generate_todo_list() # 根据配置生成 TODO 列表 + │ ├── check_transport_receive() # 检查货运委托领取 + │ ├── check_daily_order() # 检查每日订单 + │ ├── check_pearl_selling() # 检查是否周一可卖珍珠 + │ ├── check_pet_cat() # 检查摸猫 + │ ├── check_juu_express() # 检查啾啾速运 + │ ├── check_greet() # 检查打招呼 + │ ├── check_farm_needs() # 检查农场需求 + │ ├── check_mine_forest_needs() # 检查矿山/森林需求 + │ ├── check_ranch_needs() # 检查牧场需求 + │ ├── check_business() # 检查经营(分两波) + │ └── ... # 其他模块 + │ + ├── sort_todo_list() # 按优先级排序 + │ + └── execute_todo_list() # 依次执行 + ├── run_single_task(item) + │ ├── if task_id == 'farm': IslandFarm(config, device).run() + │ ├── if task_id == 'mine_forest': IslandMineForest(config, device).run() + │ └── ... + └── handle_error() # 错误处理 +``` + +### 配置项 + +- [`IslandPlan.EnabledModules`](module/config/argument/argument.yaml:1112): 启用模块列表,多选 +- [`IslandPlan.TodoListOrder`](module/config/argument/argument.yaml:1112): TODO 顺序(按优先级默认) + +### 与现有任务调度的关系 + +当前的 [`task.yaml`](module/config/argument/task.yaml:362) 中 `Island` 组有多个独立任务(IslandFarm、IslandRancher 等)。 +新增 `IslandPlan` 任务后,用户可以选择使用统一的 `IslandPlan` 任务替代多个独立任务。 + +--- + +## 功能2: 矿山/森林按库存阈值执行 + +### 目标 + +当前 [`IslandMineForest.run()`](module/island/island_mine_forest.py:46) 根据固定槽位配置(Mining1~4、Felling1~4)决定哪些岗位运行,不考虑库存数量。 +改为先检查仓库库存,低于阈值才安排生产。 + +### 设计方案 + +修改文件: [`module/island/island_mine_forest.py`](module/island/island_mine_forest.py) + +#### 新增配置项 + +```yaml +IslandMine: + MinCopper: 0 # 铜矿最低库存 + MinAluminium: 0 # 铝矿最低库存 + MinIron: 0 # 铁矿最低库存 + MinSulphur: 0 # 硫磺最低库存 + MinSilver: 0 # 银矿最低库存 + # 当对应矿物库存 < MinXxx 时,才安排该岗位 +IslandForest: + MinElegant: 0 # 优雅木材最低库存 + MinPractical: 0 # 实用木材最低库存 + MinSelected: 0 # 精选木材最低库存 +``` + +#### 核心逻辑变更 + +```python +def check_inventory_and_prepare(self): + """检查仓库中矿山/森林产品数量,生成需要生产的列表""" + self.warehouse_filter('mine') + image = self.device.screenshot() + + needs = [] + # 矿山产品 + for product_name, (_, _, _) in self.PRODUCT_CONFIGS.items(): + if product_name in ['Elegant', 'Practical', 'Selected', 'Natural']: + continue # 跳过森林产品 + min_key = f'Min{product_name}' + threshold = getattr(self.config, f'IslandMine_{min_key}', 0) + count = self.ocr_item_quantity(image, TEMPLATE_MINE_PRODUCTS[product_name]) + if count < threshold: + needs.append(product_name) + + # 森林产品 + self.warehouse_filter('forest') + image = self.device.screenshot() + for product_name in ['Elegant', 'Practical', 'Selected', 'Natural']: + # ... 同理 +``` + +#### run() 方法修改 + +```python +def run(self): + # 1. 检查库存,生成需要生产的列表 + needs = self.check_inventory_and_prepare() + + # 2. 根据 needs 决定哪些岗位要运行 + # 优先匹配 Mining1~4 和 Felling1~4 中配置了对应产品的岗位 + # 如果产品已经足够,对应岗位直接跳过 + + # 3. 现有逻辑执行 + for post_id, product_config, time_var_name in all_configs: + if product_config is not None and product_config in needs: + self.run_single_post(post_id, product_config, time_var_name) +``` + +--- + +## 功能3: 每日订单功能 + +### 目标 + +岛屿系统中存在"每日订单"功能(在管理页面 → 采集页签旁的"订单"页签),玩家可以接取每日订单,完成后获得奖励。 + +### 设计方案 + +**新文件**: [`module/island/island_daily_order.py`](module/island/island_daily_order.py) + +#### 核心类: `IslandDailyOrder` + +```python +class IslandDailyOrder(Island): + """每日订单处理""" + + def run(self): + """ + 执行每日订单流程: + 1. 进入管理页面 → 订单页签 + 2. 领取已完成订单的奖励 + 3. 检查是否有可用订单可接 + 4. 自动接取符合条件(物品充足)的订单 + """ +``` + +#### 流程详解 + +``` +run() + ├── goto_management() + ├── switch_to_order_tab() # 切换到订单页签 + ├── claim_completed_orders() # 领取已完成的订单奖励 + ├── detect_available_orders() # 检测可用订单列表 + │ ├── OCR 订单名称和需求物品 + │ └── 匹配仓库库存 + ├── accept_best_orders() # 自动接取可完成的订单 + │ └── 确认接取 + └── set_next_run_time() # 设置下次运行时间 +``` + +#### 订单检测 + +- 订单区域有一个列表,可滑动查看 +- 每个订单显示:需求物品图标 + 数量、奖励预览 +- 有"接取"按钮(物品足够时亮起)或"已接取"状态 + +#### 配置项 + +```yaml +IslandDailyOrder: + Enabled: true # 启用每日订单 + AutoAccept: true # 自动接取可用订单 + MaxOrders: 3 # 最大同时接取订单数 + PriorityItems: [wheat, corn, ...] # 优先消耗的物品种类 +``` + +--- + +## 功能4: 货运委托功能 + +### 目标 + +货运委托(运输系统)已在 [`transport.py`](module/island/transport.py) 中有完整实现。 +需要将其集成到 IslandPlan TODO 列表中,并支持配置启用的委托槽位和黑名单物品。 + +### 现有功能分析 + +[`transport.py`](module/island/transport.py) 已实现: + +| 方法 | 功能 | +|------|------| +| [`IslandTransportRun.island_transport_run()`](module/island/transport.py:400) | 完整执行运输流程 | +| [`transport_receive()`](module/island/transport.py:280) | 领取已完成委托 | +| [`transport_detect()`](module/island/transport.py:249) | 检测委托状态 | +| [`transport_refresh()`](module/island/transport.py:334) | 刷新委托 | +| [`transport_start()`](module/island/transport.py:364) | 开始委托 | + +### 需要新增的功能 + +1. **集成到 IslandPlan TODO**: 在 [`island_todo.py`](module/island/island_todo.py) 中检查 transport 状态 +2. **配置支持**: + - 是否启用运输委托 + - 委托黑名单物品(已实现 via [`blacklist`](module/island/transport.py:222)) + - 自动刷新未满委托的开关 + +#### 配置项 + +```yaml +IslandTransport: + Enabled: true + AutoRefresh: true + SubmitCopper: true + SubmitAluminium: true + # ... 其他物品(已存在) +``` + +--- + +## 功能5: 每周珍珠售卖 + +### 目标 + +每周一(或配置的某天)自动进入珍珠商店,将库存中的珍珠全部卖出。 + +### 设计方案 + +**新文件**: [`module/island/island_pearl_sell.py`](module/island/island_pearl_sell.py) + +#### 核心类: `IslandPearlSell` + +```python +class IslandPearlSell(Island): + """每周珍珠售卖""" + + WEEKDAY_MAP = { + 'monday': 0, + 'tuesday': 1, + # ... + } + + def run(self): + """ + 流程: + 1. 检查今天是否是设定的售卖日 + 2. 导航到岛屿商店 + 3. 进入珍珠商店页签 + 4. 检测当前珍珠数量 + 5. 如果有珍珠,执行全量卖出 + 6. 设置下周同一时间运行 + """ +``` + +#### 流程详解 + +``` +run() + ├── if today != config.sell_day: skip + ├── navigate_to_island_shop() + ├── switch_to_pearl_tab() + ├── detect_pearl_count() # OCR 检测珍珠数量 + ├── if count > 0: + │ ├── click_sell_all() # 点击全部卖出 + │ └── confirm_sell() # 确认 + └── schedule_next_week() # 设置下周运行 +``` + +#### 珍珠售卖UI + +- 珍珠商店有专门页签 +- 显示当前珍珠数量 +- 有"全部卖出"按钮 +- 确认弹窗 + +#### 配置项 + +```yaml +IslandPearlSell: + Enabled: false # 默认关闭 + SellDay: monday # 售卖日(周一~周日) + SellTime: "09:00" # 售卖时间 +``` + +--- + +## 功能6: 经营模块智能分波 + +### 目标 + +对现有 [`IslandBusiness`](module/island/island_business.py:39) 经营模块进行三项增强: + +1. **分两波经营**:将 5 个商店分成两波执行,避免单次运行时间过长 +2. **季节限定检测替换**:检测季节限定餐品库存数量,如果 < 7 则替换为另一个可配置菜品 +3. **加成商品检测替换**:检测当天具有加成的商品,如果条件满足则替换,优先从下往上替换 + +### 设计方案 + +修改文件: [`module/island/island_business.py`](module/island/island_business.py) + +#### 6.1 分两波经营 + +将 5 个商店分成两个 Wave: + +```python +WAVE_CONFIG = { + 'wave1': { + 'shops': ['有鱼餐馆', '白熊饮品', '啾啾简餐'], # 前3个 + 'priority': 70, # TODO 优先级 + }, + 'wave2': { + 'shops': ['乌鱼烤肉', '啾咖啡'], # 后2个 + 'priority': 71, # TODO 优先级(稍低) + } +} +``` + +**配置项**: + +```yaml +IslandBusiness: + WaveEnabled: true # 启用分波 + Wave1Shops: [1, 2, 3] # 第一波商店索引 + Wave2Shops: [4, 5] # 第二波商店索引 + Wave1Time: "08:00" # 第一波执行时间 + Wave2Time: "14:00" # 第二波执行时间 +``` + +**执行流程**: + +```python +def should_run_wave1(self): + """判断第一波是否需要执行""" + now = datetime.now() + wave1_time = now.replace(hour=8, minute=0, second=0) + return now >= wave1_time + +def should_run_wave2(self): + """判断第二波是否需要执行""" + now = datetime.now() + wave2_time = now.replace(hour=14, minute=0, second=0) + return now >= wave2_time + +def run_wave(self, shop_list): + """执行指定商店列表的经营""" + for shop in shop_list: + self._process_single_shop(shop) +``` + +#### 6.2 季节限定餐品数量检测替换 + +核心逻辑:在经营前检查仓库中季节限定餐品的数量,如果 < 7 则替换为备用菜品。 + +```python +def check_seasonal_dish_quantity(self, shop_name): + """ + 检查指定商店的季节限定餐品库存数量。 + + Returns: + list: 需要替换的餐品列表 [(原餐品, 替换餐品), ...] + """ + replacement_plan = [] + + # 获取当前商店的季节限定餐品 + seasonal_items = self._get_seasonal_items_for_shop(shop_name) + if not seasonal_items: + return replacement_plan + + # 遍历当前激活的餐品配置,检查季节限定品 + for product in self.active_products.get(shop_name, []): + if product['name'] in seasonal_items: + # 通过仓库 OCR 检测该餐品数量 + count = self._check_product_quantity(product['name']) + if count < 7: + logger.info( + f"{shop_name}: 季节限定 {product['name']} 库存 {count} < 7," + f"需要替换" + ) + # 查找备用菜品配置 + fallback = self._get_fallback_product(shop_name, product['name']) + if fallback: + replacement_plan.append((product, fallback)) + + return replacement_plan +``` + +**备用菜品配置**: + +```yaml +IslandBusinessShop1: # 有鱼餐馆 + # ... 现有 Product1~5 配置 + SeasonalFallback1: hearty_meal # 季节限定餐品1的备用替换 + SeasonalFallback2: fo_tiao # 季节限定餐品2的备用替换 +``` + +#### 6.3 加成商品检测替换 + +核心逻辑:进入商店后,检测当天具有加成的商品(UI 上带有"推荐""流行"等标记),如果加成条件满足则替换当前商品,**优先从下往上替换**(即先替换最后一个槽位的商品)。 + +```python +def check_boosted_products(self, shop_name): + """ + 检测当天具有加成的商品,从下往上替换。 + + 加成判定: + - 游戏 UI 中商品可能有特殊标记(如"推荐"标签、高亮边框等) + - 通过模板匹配或颜色检测识别加成标记 + + 替换策略(从下往上): + - 假设有 5 个商品槽位:P1, P2, P3, P4, P5 + - 优先替换 P5 → P4 → P3 → P2 → P1 + """ + # 1. 截图商品区域 + self.device.screenshot() + + # 2. 检测所有商品的加成状态 + boosted_products = self._detect_boosted(shop_name) + if not boosted_products: + logger.info(f"{shop_name}: 没有检测到加成商品") + return + + # 3. 获取当前已选择的商品列表(从下往上遍历) + current_products = self.active_products.get(shop_name, []) + # 倒序,从最后一个槽位开始检查 + for product in reversed(current_products): + # 检查是否有加成商品可以替换这个槽位 + for boosted in boosted_products: + if boosted['name'] != product['name']: + # 检查加成条件是否满足 + if self._check_boost_condition(boosted): + logger.info( + f"{shop_name}: 加成商品 {boosted['name']} " + f"替换槽位商品 {product['name']}(从下往上)" + ) + # 执行替换 + self._replace_product(shop_name, product, boosted) + break +``` + +**加成商品检测方法**: + +```python +def _detect_boosted(self, shop_name): + """ + 检测加成商品。 + + 方法1: 模板匹配 — 检测商品图标上的"推荐"标签 + 方法2: 颜色检测 — 检测商品边框的特殊颜色 + 方法3: OCR — 读取商品名称旁边的特殊文本 + """ + products = self.shop_products.get(shop_name, []) + boosted = [] + + for p in products: + b = p.get('button') + if not b: + continue + + # 检测商品区域是否有"推荐"模板 + if hasattr(self, f'TEMPLATE_BOOSTED_{p["name"].upper()}'): + template = getattr(self, f'TEMPLATE_BOOSTED_{p["name"].upper()}') + if self.appear(template, offset=30): + boosted.append(p) + continue + + # 或者检测商品图标上叠加的加成标记 + TEMPLATE_BOOSTED_TAG = getattr(self, 'TEMPLATE_BOOSTED_TAG', None) + if TEMPLATE_BOOSTED_TAG: + area_img = crop(self.device.image, b.area) + if TEMPLATE_BOOSTED_TAG.match(area_img, similarity=0.8): + boosted.append(p) + + return boosted +``` + +**配置项**: + +```yaml +IslandBusiness: + BoostedReplace: true # 启用加成商品替换 + BoostThreshold: 1.2 # 加成倍率阈值(如 1.2 倍以上才替换) + BoostReplaceDirection: bottom_up # 替换方向:bottom_up(从下往上) +``` + +--- + +## 功能7: 自动采集角色体力检测换人 + +### 目标 + +在 [`IslandDailyGather`](module/island/island_daily_gather.py:14) 每日自动采集流程中,选择角色时检测其剩余体力(疲劳值),如果低于 100 则换人。 + +### 设计方案 + +修改文件: [`module/island/island_daily_gather.py`](module/island/island_daily_gather.py) + +#### 核心逻辑 + +```python +def select_collector_with_stamina(self): + """ + 选择采集角色时检测体力,低于 100 则换人。 + + 流程: + 1. 进入角色选择界面 + 2. 对角色列表按"生活等级"升序排序 + 3. 遍历角色列表,OCR 检测每个角色的体力值 + 4. 如果体力 >= 100,选择该角色 + 5. 如果所有角色体力都 < 100,选择体力最高的 + + OCR 区域说明: + - 体力值通常显示在角色头像旁边的数字 + - 格式如 "100/100" 或纯数字 "100" + - 使用 Digit 或 Duration 进行 OCR + """ +``` + +#### 体力检测区域 + +```python +# 每个角色卡片上体力值显示区域(相对角色卡片区域的偏移) +STAMINA_AREA_RELATIVE = (80, 5, 120, 25) # (x1, y1, x2, y2) 相对角色按钮 +``` + +#### 修改后的角色选择流程 + +```python +def _select_characters_with_stamina_check(self): + """ + 修改后的角色选择流程(替换原来的简单选择)。 + + 步骤: + 1. 打开角色选择界面 → 按生活等级排序 + 2. 对每个 "+" 按钮: + a. 遍历角色列表(从上到下) + b. 对每个角色截图体力区域 → OCR 读取数值 + c. 如果体力 >= 100 → 选中该角色 + d. 如果体力 < 100 → 跳过,继续找下一个 + e. 如果遍历完所有角色都 < 100 → 选体力最高的 + 3. 确认选择 + """ + for slot_idx in range(3): # 3 个采集槽位 + # 点击 "+" 按钮 + # 等待角色选择界面出现 + + best_char = None # (button, stamina) + for attempt in range(max_swipes): + self.device.screenshot() + + # 遍历当前页面的角色 + for char_button in self._get_visible_characters(): + stamina = self._ocr_stamina(char_button) + logger.info(f"角色体力: {stamina}") + + if stamina >= 100: + # 找到体力充足的,直接选中 + self.device.click(char_button) + self.device.sleep(0.5) + self.device.click(SELECT_UI_CONFIRM) + return + + # 记录体力最高的 + if best_char is None or stamina > best_char[1]: + best_char = (char_button, stamina) + + # 向下滑动查看更多角色 + self._swipe_down() + + # 没有体力 >= 100 的角色,选体力最高的 + if best_char: + logger.warning(f"没有体力>=100的角色,选择体力最高的: {best_char[1]}") + self.device.click(best_char[0]) + self.device.sleep(0.5) + self.device.click(SELECT_UI_CONFIRM) +``` + +#### OCR 体力值 + +```python +def _ocr_stamina(self, char_button): + """ + 对角色按钮区域的体力值进行 OCR。 + + Args: + char_button: 角色按钮 + + Returns: + int: 体力值,OCR 失败返回 0 + """ + # 体力区域:角色按钮右上方的小数字 + stamina_area = ( + char_button.area[0] + self.STAMINA_AREA_RELATIVE[0], + char_button.area[1] + self.STAMINA_AREA_RELATIVE[1], + char_button.area[0] + self.STAMINA_AREA_RELATIVE[2], + char_button.area[1] + self.STAMINA_AREA_RELATIVE[3], + ) + + ocr_btn = Button( + area=stamina_area, color=(), + button=stamina_area, + file={'cn': '', 'en': '', 'jp': '', 'tw': ''} + ) + + ocr = Digit(ocr_btn, letter=(255, 255, 255), threshold=200) + try: + value = ocr.ocr(self.device.image) + return int(value) if value else 0 + except: + return 0 +``` + +#### 配置项 + +```yaml +IslandDailyGather: + StaminaThreshold: 100 # 体力阈值,低于此值换人 + StaminaCheckEnabled: true # 启用体力检测 +``` + +--- + +## 功能8: 摸猫/JUU速运任务 + +### 目标 + +每日在岛屿上执行两个小互动: + +1. **摸猫**: 点击岛上出现的猫,获得好感度和随机奖励 +2. **JUU速运**: 在岛屿场景中找到并点击啾啾速运的NPC/建筑物,领取或提交速运任务 + +### 设计方案 + +**新文件**: [`module/island/island_daily_interact.py`](module/island/island_daily_interact.py) + +#### 核心类: `IslandDailyInteract` + +```python +class IslandDailyInteract(Island): + """每日互动任务:摸猫、JUU速运""" + + def run(self): + """执行每日互动""" + self.goto_island() + self.pet_cat() + self.juu_express() + + def pet_cat(self): + """ + 摸猫流程: + 1. 在岛屿主场景中寻找猫 + 2. 猫会随机出现在岛屿各个位置 + 3. 通过模板匹配检测猫 + 4. 点击猫 → 出现互动弹窗 + 5. 点击"抚摸"按钮 + 6. 关闭奖励弹窗 + """ + + def juu_express(self): + """ + JUU速运流程: + 1. 在岛屿场景中寻找JUU速运点 + 2. 通常在地图固定位置 + 3. 点击进入速运界面 + 4. 领取已完成速运的奖励 + 5. 如果有可用速运,接受 + """ +``` + +#### 摸猫检测 + +- 猫的图像模板存储在 [`assets/`](assets/) 中 +- 猫可能出现在多个位置,使用模板匹配扫描全屏 +- 如果没有检测到猫,说明已经被摸过了或不在场景中 + +#### JUU速运检测 + +- JUU速运在岛屿地图上有固定位置的建筑物/NPC +- 需要先进入岛屿场景,然后寻找速运入口 +- 速运界面有:领取奖励、查看速运列表 + +#### 配置项 + +```yaml +IslandDailyInteract: + PetCat: true # 启用摸猫 + JuuExpress: true # 启用JUU速运 +``` + +--- + +## 功能9: 给三个小人打招呼 + +### 目标 + +岛屿场景中会出现三个可互动的小人(NPC/游客),点击给他们打招呼可以获得友好度或小奖励。 + +### 设计方案 + +在 [`module/island/island_daily_interact.py`](module/island/island_daily_interact.py) 中扩展。 + +#### 核心逻辑 + +```python +def greet_npcs(self): + """ + 给三个小人打招呼流程: + 1. 进入岛屿主场景 + 2. 扫描场景中出现的 NPC 小人 + 3. 小人有三种类型/位置 + 4. 依次点击每个小人 + 5. 点击"打招呼"按钮 + 6. 关闭弹窗 + """ + + NPC_TEMPLATES = [ + TEMPLATE_NPC_1, # 小人1的模板 + TEMPLATE_NPC_2, # 小人2的模板 + TEMPLATE_NPC_3, # 小人3的模板 + ] +``` + +#### NPC 检测 + +- 三个小人在岛屿场景中的固定或半固定位置 +- 使用模板匹配检测 +- 可能出现在不同区域,需要扫描 +- 如果已被打过招呼,小人可能消失或变为不同状态 + +#### 挑战与注意事项 + +1. 小人可能不在当前屏幕视口中,需要滑动地图寻找 +2. 小人出现有随机性,不是每天都会出现 +3. 点击后的弹窗需要处理 + +#### 配置项 + +```yaml +IslandDailyInteract: + GreetNpcs: true # 启用打招呼 + GreetNpcCount: 3 # 打招呼数量 +``` + +--- + +## 配置变更总览 + +### [`argument.yaml`](module/config/argument/argument.yaml) 新增配置 + +```yaml +# ==================== Island 新增配置 ==================== + +IslandPlan: + Season: + value: spring + option: [spring, summer, autumn, winter] + # --- 新增 --- + EnabledModules: + value: [] + option: [Farm, Rancher, MineForest, Business, Restaurant, Teahouse, Grill, JuuEatery, JuuCoffee, DailyGather, AirDrop, Transport, DailyOrder, PearlSell, DailyInteract, SeasonTask, Manufacture] + +IslandMine: + # 现有 Mining1~4 + # --- 新增阈值 --- + MinCopper: 0 + MinAluminium: 0 + MinIron: 0 + MinSulphur: 0 + MinSilver: 0 + +IslandForest: + # 现有 Felling1~4 + # --- 新增阈值 --- + MinElegant: 0 + MinPractical: 0 + MinSelected: 0 + MinNatural: 0 + +IslandBusiness: + # --- 分波经营 --- + WaveEnabled: true + Wave1Shops: [1, 2, 3] + Wave2Shops: [4, 5] + Wave1Time: "08:00" + Wave2Time: "14:00" + # --- 季节限定替换 --- + SeasonalReplaceEnabled: true + SeasonalThreshold: 7 + # --- 加成商品替换 --- + BoostedReplace: true + BoostThreshold: 1.2 + BoostReplaceDirection: bottom_up + +IslandBusinessShop1: + SeasonalFallback1: hearty_meal + SeasonalFallback2: fo_tiao + +IslandDailyGather: + StaminaThreshold: 100 + StaminaCheckEnabled: true + +IslandDailyOrder: + Enabled: true + AutoAccept: true + MaxOrders: 3 + +IslandPearlSell: + Enabled: false + SellDay: + value: monday + option: [monday, tuesday, wednesday, thursday, friday, saturday, sunday] + SellTime: "09:00" + +IslandDailyInteract: + PetCat: true + JuuExpress: true + GreetNpcs: true + GreetNpcCount: 3 +``` + +### [`task.yaml`](module/config/argument/task.yaml) 修改 + +```yaml +Island: + tasks: + IslandPlan: + - Scheduler + - IslandPlan + - IslandDailyOrder # 新增 + - IslandPearlSell # 新增 + - IslandDailyInteract # 新增 + # ... 保留现有任务 +``` + +--- + +## 任务调度集成 + +### IslandPlan 作为统一入口 + +用户可通过 `IslandPlan` 任务一键执行所有岛屿任务。调度方式: + +1. **统一运行模式**: 启用 `IslandPlan` 后,自动生成 TODO 列表按优先级执行 +2. **独立运行模式**: 保留现有独立任务(IslandFarm、IslandRancher 等),用户可单独调度 + +### 优先级调度 + +``` +高优先级(立即执行): + 收取货运委托 → 10 + 每日订单 → 20 + 每周珍珠 → 30(仅周一) + 摸猫/速运/打招呼 → 35-37 + +中优先级(定期执行): + 农场/矿山/牧场 → 40-61 + 经营第一波 → 70 + 经营第二波 → 71 + 制造 → 80 + 餐饮类店铺 → 90-94 + +低优先级(确保每日执行): + 每日采集 → 100 + 空投 → 110 + 季节任务 → 120 + 货运开始 → 130 +``` + +### 与 alas.py 集成 + +在 [`alas.py`](alas.py) 中 `AzurLaneAutoScript` 类的任务循环中,`IslandPlan` 作为 `Island` 组下的一个任务,按照标准调度流程运行。 + +--- + +## 文件结构变化 + +``` +module/island/ +├── island.py # 已有 - 核心类 +├── island_todo.py # 新增 - TODO 列表管理器 +├── island_daily_order.py # 新增 - 每日订单 +├── island_pearl_sell.py # 新增 - 珍珠售卖 +├── island_daily_interact.py # 新增 - 摸猫/速运/打招呼 +├── island_mine_forest.py # 修改 - 增加库存检测 +├── island_business.py # 修改 - 分波 + 季节检测 + 加成检测 +├── island_daily_gather.py # 修改 - 体力检测换人 +├── transport.py # 已有 - 货运委托 +├── assets.py # 已有 - 通用按钮资源 +├── ... +``` + +--- + +## i18n 新增 Key + +在 [`zh-CN.json`](module/config/i18n/zh-CN.json) 等翻译文件中新增: + +```json +{ + "Island.IslandPlan.EnabledModules": "启用模块", + "Island.IslandPlan.EnabledModules.description": "选择需要在岛屿计划中自动管理的模块", + "Island.IslandMine.MinCopper": "铜矿最低库存", + "Island.IslandMine.MinAluminium": "铝矿最低库存", + "Island.IslandMine.MinIron": "铁矿最低库存", + "Island.IslandMine.MinSulphur": "硫磺最低库存", + "Island.IslandMine.MinSilver": "银矿最低库存", + "Island.IslandForest.MinElegant": "优雅木材最低库存", + "Island.IslandForest.MinPractical": "实用木材最低库存", + "Island.IslandForest.MinSelected": "精选木材最低库存", + "Island.IslandForest.MinNatural": "自然木材最低库存", + + "Island.IslandBusiness.WaveEnabled": "启用分波经营", + "Island.IslandBusiness.WaveEnabled.description": "将5个商店分成两波执行", + "Island.IslandBusiness.SeasonalReplaceEnabled": "季节限定替换", + "Island.IslandBusiness.SeasonalReplaceEnabled.description": "季节限定菜品库存不足时自动替换", + "Island.IslandBusiness.SeasonalThreshold": "季节限定替换阈值", + "Island.IslandBusiness.BoostedReplace": "加成商品替换", + "Island.IslandBusiness.BoostedReplace.description": "检测当天加成商品自动替换(从下往上)", + "Island.IslandBusiness.BoostThreshold": "加成倍率阈值", + "Island.IslandBusinessShop1.SeasonalFallback1": "季节限定备用菜品1", + + "Island.IslandDailyGather.StaminaThreshold": "体力阈值", + "Island.IslandDailyGather.StaminaThreshold.description": "角色体力低于此值则换人", + "Island.IslandDailyGather.StaminaCheckEnabled": "启用体力检测", + + "Island.IslandDailyOrder.Enabled": "启用每日订单", + "Island.IslandPearlSell.Enabled": "启用珍珠售卖", + "Island.IslandPearlSell.SellDay": "售卖日", + "Island.IslandDailyInteract.PetCat": "摸猫", + "Island.IslandDailyInteract.JuuExpress": "JUU速运", + "Island.IslandDailyInteract.GreetNpcs": "打招呼" +} +``` + +--- + +## 实现优先级 + +| 优先级 | 功能 | 预计工作量 | +|--------|------|-----------| +| P0 | 矿山/森林库存阈值 | 小(改现有代码) | +| P0 | TODO 列表框架 | 中(新文件) | +| P0 | 经营模块智能分波 | 中(改现有代码) | +| P0 | 经营模块季节限定替换 | 中(新增逻辑) | +| P1 | 经营模块加成商品替换 | 中(需截图资源) | +| P1 | 货运委托集成 | 小(集成已有代码) | +| P1 | 每日订单 | 中(新功能) | +| P1 | 自动采集体力检测换人 | 小(改现有代码) | +| P2 | 珍珠售卖 | 小(新功能) | +| P2 | 摸猫/JUU速运 | 中(需截图资源) | +| P3 | 打招呼 | 中(需截图资源) | + +> **注意**: 摸猫、JUU速运、给小人打招呼、加成商品检测等功能需要游戏内截图资源(Button/Template),需先通过 `dev_tools/button_extract.py` 从截图中提取按钮定义才能实现。 diff --git a/module/combat/auto_search_combat.py b/module/combat/auto_search_combat.py index 9ca775489..c9e260ef2 100644 --- a/module/combat/auto_search_combat.py +++ b/module/combat/auto_search_combat.py @@ -5,7 +5,7 @@ from module.exception import CampaignEnd from module.handler.assets import AUTO_SEARCH_MAP_OPTION_ON, GET_MISSION from module.logger import logger -from module.map.assets import WITHDRAW, SWITCH_OVER, FLEET_WITHDRAW, FLEET_SWITCH_CONFIRM +from module.map.assets import WITHDRAW, SWITCH_OVER, FLEET_WITHDRAW, FLEET_SWITCH_CONFIRM, FLEET_WITHDRAW_BOSS from module.map.map_operation import MapOperation @@ -355,6 +355,9 @@ def auto_search_combat_status(self): self.device.screenshot() if self.appear_then_click(FLEET_WITHDRAW, offset=(30, 30)): break + if self.appear(FLEET_WITHDRAW_BOSS, offset=(30, 30)): + self.withdraw() + break if self.appear_then_click(SWITCH_OVER, interval=2): continue self.fleet_alive_multiple = False diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 25cec3b00..0ac5b5534 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -782,7 +782,7 @@ "YukikazeTaskManager": { "TaskPriorityAdjustment": { "type": "textarea", - "value": "Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies > Island\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive \n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost" + "value": "Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive\n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> IslandJuuEatery > IslandJuuCoffee > IslandGrill > IslandTeahouse > IslandRestaurant\n> IslandFarm > IslandRancher > IslandMineForest > IslandDailyGather > IslandManufacture\n> IslandAirDrop > IslandBusiness\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost" } }, "Storage": { @@ -13532,57 +13532,6 @@ } }, "IslandPlan": { - "Scheduler": { - "Enable": { - "type": "checkbox", - "value": false, - "option": [ - true, - false - ] - }, - "PushNotification": { - "type": "checkbox", - "value": false, - "option": [ - true, - false - ] - }, - "NextRun": { - "type": "datetime", - "value": "2020-01-01 00:00:00", - "validate": "datetime" - }, - "Command": { - "type": "input", - "value": "IslandPlan", - "display": "hide" - }, - "SuccessInterval": { - "type": "input", - "value": 0, - "display": "hide" - }, - "FailureInterval": { - "type": "input", - "value": 120, - "display": "hide" - }, - "ServerUpdate": { - "type": "input", - "value": "00:00", - "display": "hide" - }, - "Sensitive": { - "type": "checkbox", - "value": false, - "option": [ - true, - false - ] - } - }, "IslandPlan": { "Season": { "type": "select", diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 0730f02f6..0acdddef1 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -272,16 +272,19 @@ YukikazeTaskManager: > Exercise > Dorm > Meowfficer > Guild > Gacha > Reward - > ShopFrequent > ShopOnce > Shipyard > Freebies > Island + > ShopFrequent > ShopOnce > Shipyard > Freebies > PrivateQuarters > OpsiExplore > Minigame > Awaken > OpsiAshBeacon > OpsiDaily > OpsiShop > OpsiVoucher > EventShop - > OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive + > OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive > Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss > Sos > EventSp > EventA > EventB > EventC > EventD > RaidDaily > CoalitionSp > WarArchives > MaritimeEscort + > IslandJuuEatery > IslandJuuCoffee > IslandGrill > IslandTeahouse > IslandRestaurant + > IslandFarm > IslandRancher > IslandMineForest > IslandDailyGather > IslandManufacture + > IslandAirDrop > IslandBusiness > Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3 > OpsiMeowfficerFarming > GemsFarming diff --git a/module/config/argument/task.yaml b/module/config/argument/task.yaml index bce8cacf4..80a231cb9 100644 --- a/module/config/argument/task.yaml +++ b/module/config/argument/task.yaml @@ -364,7 +364,6 @@ Island: page: 'setting' tasks: IslandPlan: - - Scheduler - IslandPlan IslandBusiness: - Scheduler diff --git a/module/config/config_generated.py b/module/config/config_generated.py index b49d33b1e..07cb0ef1b 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -161,7 +161,7 @@ class GeneratedConfig: PublicEmotion_FleetOnsen = False # 配置组 `YukikazeTaskManager` - YukikazeTaskManager_TaskPriorityAdjustment = 'Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies > Island\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive \n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost' + YukikazeTaskManager_TaskPriorityAdjustment = 'Restart\n> OpsiCrossMonth\n> Commission > Tactical > Research\n> Exercise\n> Dorm > Meowfficer > Guild > Gacha\n> Reward\n> ShopFrequent > ShopOnce > Shipyard > Freebies\n> PrivateQuarters\n> OpsiExplore\n> Minigame > Awaken\n> OpsiAshBeacon\n> OpsiDaily > OpsiShop > OpsiVoucher > EventShop\n> OpsiAbyssal > OpsiStronghold > OpsiObscure > OpsiArchive\n> Daily > Hard > OpsiAshBeacon > OpsiAshAssist > OpsiMonthBoss\n> Sos > EventSp > EventA > EventB > EventC > EventD\n> RaidDaily > CoalitionSp > WarArchives > MaritimeEscort\n> IslandJuuEatery > IslandJuuCoffee > IslandGrill > IslandTeahouse > IslandRestaurant\n> IslandFarm > IslandRancher > IslandMineForest > IslandDailyGather > IslandManufacture\n> IslandAirDrop > IslandBusiness\n> Event > Event2 > Event3 > Raid > Hospital > HospitalEvent > Coalition > RaidScuttle > Main > Main2 > Main3\n> OpsiMeowfficerFarming\n> GemsFarming\n> Ambush11\n> OpsiHazard1Leveling\n> ThreeOilLowCost' # 配置组 `OneClickRetire` OneClickRetire_KeepLimitBreak = 'keep_limit_break' # keep_limit_break, do_not_keep diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 3a22eaae3..db7bc4fbd 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -287,7 +287,7 @@ "help": "使用蒙特卡洛算法估算在当前状态下持续进行侵蚀循环一段时间后的结果,该功能不会影响AzurPilot正常运行\n模型所用参数均取自AzurPilot配置和统计,请确保正确配置了智能调度等大世界设置\n目前为测试版本,结果不具备太多参考价值\n关于奸商售卖行动力的模型无足够充分的证据支撑。具体来讲,这里认为奸商卖6种行动力箱子满足超几何分布X~H(6,6,24)\n关于坠机:这里坠机是指整个模拟流程中行动力低于智能调度中设置的行动力保留阈值至少一次。若低于该阈值,模拟器将停止侵蚀循环等待行动力自然回复" }, "IslandPlan": { - "name": "岛屿计划全局配置", + "name": "全局配置", "help": "岛屿计划的全局配置,包括季节设定" }, "IslandBusiness": { @@ -3425,7 +3425,7 @@ }, "RancherFilter": { "name": "使用角色", - "help": "以>连接,例如肇和 新泽西 小天城:ChaoHo > NewJersey > Amagi_chan\n小加加:Saratoga > 明石:Akashi > 塔什干:Tashkent > 应瑞:YingSwei\n恶毒:LeMalin > 独角兽:Unicorn > 岛风:Shimakaze > 柴郡:Cheshire\n镇海:ChenHai > 威廉D波特:WilliamDPorter\n海伦娜:Helena > 大帝:Friedrich > 愛宕:Atago" + "help": "以>连接,例如肇和 新泽西 小天城:ChaoHo > NewJersey > Amagi_chan\n小加加:Saratoga > 明石:Akashi > 塔什干:Tashkent > 应瑞:YingSwei\n恶毒:LeMalin > 独角兽:Unicorn > 岛风:Shimakaze > 柴郡:Cheshire\n镇海:ChenHai > 威廉D波特:WilliamDPorter\n海伦娜:Helena > 大帝:Friedrich > 愛宕:Atago\n逸仙:Yixian > 奥古斯特:August > 欧根亲王:Eugen > 胡德:Hood > 标枪:Javelin > 拉菲:Laffey > 探索者:Explorer > 领航员:Navigator > 领洋者:OceanCrosser > 飞云:FeiYun > 高雄:Takao" }, "Wool": { "name": "养羊", @@ -3482,7 +3482,7 @@ }, "RancherFilter": { "name": "使用角色", - "help": "以>连接,例如肇和 新泽西 小天城:ChaoHo > NewJersey > Amagi_chan\n小加加:Saratoga > 明石:Akashi > 塔什干:Tashkent > 应瑞:YingSwei\n恶毒:LeMalin > 独角兽:Unicorn > 岛风:Shimakaze > 柴郡:Cheshire\n镇海:ChenHai > 威廉D波特:WilliamDPorter\n海伦娜:Helena > 大帝:Friedrich > 愛宕:Atago" + "help": "以>连接,例如肇和 新泽西 小天城:ChaoHo > NewJersey > Amagi_chan\n小加加:Saratoga > 明石:Akashi > 塔什干:Tashkent > 应瑞:YingSwei\n恶毒:LeMalin > 独角兽:Unicorn > 岛风:Shimakaze > 柴郡:Cheshire\n镇海:ChenHai > 威廉D波特:WilliamDPorter\n海伦娜:Helena > 大帝:Friedrich > 愛宕:Atago\n逸仙:Yixian > 奥古斯特:August > 欧根亲王:Eugen > 胡德:Hood > 标枪:Javelin > 拉菲:Laffey > 探索者:Explorer > 领航员:Navigator > 领洋者:OceanCrosser > 飞云:FeiYun > 高雄:Takao" } }, "IslandMine": { @@ -3542,7 +3542,7 @@ "None": "None", "Practical": "实用之木", "Selected": "精选之木", - "Elegant": "优雅之木" + "Elegant": "典雅之木" }, "Felling2": { "name": "伐木2", @@ -3550,7 +3550,7 @@ "None": "None", "Practical": "实用之木", "Selected": "精选之木", - "Elegant": "优雅之木" + "Elegant": "典雅之木" }, "Felling3": { "name": "伐木3", @@ -3558,7 +3558,7 @@ "None": "None", "Practical": "实用之木", "Selected": "精选之木", - "Elegant": "优雅之木" + "Elegant": "典雅之木" }, "Felling4": { "name": "伐木4", @@ -3566,7 +3566,7 @@ "None": "None", "Practical": "实用之木", "Selected": "精选之木", - "Elegant": "优雅之木" + "Elegant": "典雅之木" } }, "IslandRestaurant": { diff --git a/module/island_fishery/assets.py b/module/island_fishery/assets.py index 00e8bcd51..0e6bd8ace 100644 --- a/module/island_fishery/assets.py +++ b/module/island_fishery/assets.py @@ -11,7 +11,7 @@ ISLAND_FISH_FRY_SHOP_OTHER_CHECK = Button(area={'cn': (581, 89, 659, 117), 'en': (581, 89, 659, 117), 'jp': (581, 89, 659, 117), 'tw': (581, 89, 659, 117)}, color={'cn': (252, 197, 119), 'en': (252, 197, 119), 'jp': (252, 197, 119), 'tw': (252, 197, 119)}, button={'cn': (581, 89, 659, 117), 'en': (581, 89, 659, 117), 'jp': (581, 89, 659, 117), 'tw': (581, 89, 659, 117)}, file={'cn': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_OTHER_CHECK.png', 'en': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_OTHER_CHECK.png', 'jp': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_OTHER_CHECK.png', 'tw': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_OTHER_CHECK.png'}) ISLAND_FISH_FRY_SHOP_SEAWATER = Button(area={'cn': (412, 94, 480, 111), 'en': (412, 94, 480, 111), 'jp': (412, 94, 480, 111), 'tw': (412, 94, 480, 111)}, color={'cn': (170, 170, 169), 'en': (170, 170, 169), 'jp': (170, 170, 169), 'tw': (170, 170, 169)}, button={'cn': (412, 94, 480, 111), 'en': (412, 94, 480, 111), 'jp': (412, 94, 480, 111), 'tw': (412, 94, 480, 111)}, file={'cn': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER.png', 'en': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER.png', 'jp': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER.png', 'tw': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER.png'}) ISLAND_FISH_FRY_SHOP_SEAWATER_CHECK = Button(area={'cn': (412, 94, 480, 111), 'en': (412, 94, 480, 111), 'jp': (412, 94, 480, 111), 'tw': (412, 94, 480, 111)}, color={'cn': (251, 209, 149), 'en': (251, 209, 149), 'jp': (251, 209, 149), 'tw': (251, 209, 149)}, button={'cn': (412, 94, 480, 111), 'en': (412, 94, 480, 111), 'jp': (412, 94, 480, 111), 'tw': (412, 94, 480, 111)}, file={'cn': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER_CHECK.png', 'en': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER_CHECK.png', 'jp': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER_CHECK.png', 'tw': './assets/cn/island_fishery/ISLAND_FISH_FRY_SHOP_SEAWATER_CHECK.png'}) -ISLAND_FRY_SHOP_CHECK = Button(area={'cn': (28, 569, 93, 623), 'en': (28, 569, 93, 623), 'jp': (28, 569, 93, 623), 'tw': (28, 569, 93, 623)}, color={'cn': (68, 69, 70), 'en': (68, 69, 70), 'jp': (68, 69, 70), 'tw': (68, 69, 70)}, button={'cn': (28, 569, 93, 623), 'en': (28, 569, 93, 623), 'jp': (28, 569, 93, 623), 'tw': (28, 569, 93, 623)}, file={'cn': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'en': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'jp': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'tw': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png'}) +ISLAND_FRY_SHOP_CHECK = Button(area={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, color={'cn': (94, 98, 110), 'en': (94, 98, 110), 'jp': (94, 98, 110), 'tw': (94, 98, 110)}, button={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, file={'cn': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'en': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'jp': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png', 'tw': './assets/cn/island_fishery/ISLAND_FRY_SHOP_CHECK.png'}) ISLAND_SHOP_GOTO_FISHERY_GEAR = Button(area={'cn': (27, 457, 74, 487), 'en': (27, 457, 74, 487), 'jp': (27, 457, 74, 487), 'tw': (27, 457, 74, 487)}, color={'cn': (78, 79, 80), 'en': (78, 79, 80), 'jp': (78, 79, 80), 'tw': (78, 79, 80)}, button={'cn': (27, 457, 74, 487), 'en': (27, 457, 74, 487), 'jp': (27, 457, 74, 487), 'tw': (27, 457, 74, 487)}, file={'cn': './assets/cn/island_fishery/ISLAND_SHOP_GOTO_FISHERY_GEAR.png', 'en': './assets/cn/island_fishery/ISLAND_SHOP_GOTO_FISHERY_GEAR.png', 'jp': './assets/cn/island_fishery/ISLAND_SHOP_GOTO_FISHERY_GEAR.png', 'tw': './assets/cn/island_fishery/ISLAND_SHOP_GOTO_FISHERY_GEAR.png'}) POST_BASS = Button(area={'cn': (450, 320, 521, 389), 'en': (450, 320, 521, 389), 'jp': (450, 320, 521, 389), 'tw': (450, 320, 521, 389)}, color={'cn': (175, 178, 174), 'en': (175, 178, 174), 'jp': (175, 178, 174), 'tw': (175, 178, 174)}, button={'cn': (450, 320, 521, 389), 'en': (450, 320, 521, 389), 'jp': (450, 320, 521, 389), 'tw': (450, 320, 521, 389)}, file={'cn': './assets/cn/island_fishery/POST_BASS.png', 'en': './assets/cn/island_fishery/POST_BASS.png', 'jp': './assets/cn/island_fishery/POST_BASS.png', 'tw': './assets/cn/island_fishery/POST_BASS.png'}) POST_CRAB = Button(area={'cn': (450, 320, 521, 389), 'en': (450, 320, 521, 389), 'jp': (450, 320, 521, 389), 'tw': (450, 320, 521, 389)}, color={'cn': (148, 143, 150), 'en': (148, 143, 150), 'jp': (148, 143, 150), 'tw': (148, 143, 150)}, button={'cn': (450, 320, 521, 389), 'en': (450, 320, 521, 389), 'jp': (450, 320, 521, 389), 'tw': (450, 320, 521, 389)}, file={'cn': './assets/cn/island_fishery/POST_CRAB.png', 'en': './assets/cn/island_fishery/POST_CRAB.png', 'jp': './assets/cn/island_fishery/POST_CRAB.png', 'tw': './assets/cn/island_fishery/POST_CRAB.png'}) diff --git a/module/map/assets.py b/module/map/assets.py index f68a27dfc..81f2e01e0 100644 --- a/module/map/assets.py +++ b/module/map/assets.py @@ -24,6 +24,7 @@ FLEET_SUPPORT_EMPTY = Button(area={'cn': (454, 470, 538, 540), 'en': (454, 470, 538, 540), 'jp': (454, 470, 538, 540), 'tw': (454, 470, 538, 540)}, color={'cn': (47, 54, 77), 'en': (47, 54, 77), 'jp': (47, 54, 77), 'tw': (47, 54, 77)}, button={'cn': (454, 470, 538, 540), 'en': (454, 470, 538, 540), 'jp': (454, 470, 538, 540), 'tw': (454, 470, 538, 540)}, file={'cn': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'en': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'jp': './assets/cn/map/FLEET_SUPPORT_EMPTY.png', 'tw': './assets/cn/map/FLEET_SUPPORT_EMPTY.png'}) FLEET_SWITCH_CONFIRM = Button(area={'cn': (553, 481, 728, 541), 'en': (553, 481, 728, 541), 'jp': (553, 481, 728, 541), 'tw': (553, 481, 728, 541)}, color={'cn': (98, 144, 201), 'en': (98, 144, 201), 'jp': (98, 144, 201), 'tw': (98, 144, 201)}, button={'cn': (553, 481, 728, 541), 'en': (553, 481, 728, 541), 'jp': (553, 481, 728, 541), 'tw': (553, 481, 728, 541)}, file={'cn': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'en': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'jp': './assets/cn/map/FLEET_SWITCH_CONFIRM.png', 'tw': './assets/cn/map/FLEET_SWITCH_CONFIRM.png'}) FLEET_WITHDRAW = Button(area={'cn': (714, 356, 773, 380), 'en': (714, 356, 773, 380), 'jp': (714, 356, 773, 380), 'tw': (714, 356, 773, 380)}, color={'cn': (175, 188, 201), 'en': (175, 188, 201), 'jp': (175, 188, 201), 'tw': (175, 188, 201)}, button={'cn': (714, 356, 773, 380), 'en': (714, 356, 773, 380), 'jp': (714, 356, 773, 380), 'tw': (714, 356, 773, 380)}, file={'cn': './assets/cn/map/FLEET_WITHDRAW.png', 'en': './assets/cn/map/FLEET_WITHDRAW.png', 'jp': './assets/cn/map/FLEET_WITHDRAW.png', 'tw': './assets/cn/map/FLEET_WITHDRAW.png'}) +FLEET_WITHDRAW_BOSS = Button(area={'cn': (713, 355, 774, 381), 'en': (713, 355, 774, 381), 'jp': (713, 355, 774, 381), 'tw': (713, 355, 774, 381)}, color={'cn': (163, 171, 178), 'en': (163, 171, 178), 'jp': (163, 171, 178), 'tw': (163, 171, 178)}, button={'cn': (713, 355, 774, 381), 'en': (713, 355, 774, 381), 'jp': (713, 355, 774, 381), 'tw': (713, 355, 774, 381)}, file={'cn': './assets/cn/map/FLEET_WITHDRAW_BOSS.png', 'en': './assets/cn/map/FLEET_WITHDRAW_BOSS.png', 'jp': './assets/cn/map/FLEET_WITHDRAW_BOSS.png', 'tw': './assets/cn/map/FLEET_WITHDRAW_BOSS.png'}) MAP_CAT_ATTACK = Button(area={'cn': (1237, 103, 1252, 153), 'en': (1237, 103, 1252, 153), 'jp': (1237, 103, 1252, 153), 'tw': (1237, 103, 1252, 153)}, color={'cn': (43, 45, 52), 'en': (43, 45, 52), 'jp': (43, 45, 52), 'tw': (43, 45, 52)}, button={'cn': (1148, 653, 1262, 705), 'en': (1147, 651, 1263, 701), 'jp': (1149, 653, 1261, 704), 'tw': (1148, 653, 1262, 705)}, file={'cn': './assets/cn/map/MAP_CAT_ATTACK.png', 'en': './assets/en/map/MAP_CAT_ATTACK.png', 'jp': './assets/jp/map/MAP_CAT_ATTACK.png', 'tw': './assets/tw/map/MAP_CAT_ATTACK.png'}) MAP_CAT_ATTACK_MIRROR = Button(area={'cn': (147, 145, 187, 157), 'en': (147, 145, 187, 157), 'jp': (147, 145, 187, 157), 'tw': (147, 145, 187, 157)}, color={'cn': (214, 191, 99), 'en': (214, 191, 99), 'jp': (214, 191, 99), 'tw': (214, 191, 99)}, button={'cn': (147, 145, 187, 157), 'en': (147, 145, 187, 157), 'jp': (147, 145, 187, 157), 'tw': (147, 145, 187, 157)}, file={'cn': './assets/cn/map/MAP_CAT_ATTACK_MIRROR.png', 'en': './assets/en/map/MAP_CAT_ATTACK_MIRROR.png', 'jp': './assets/jp/map/MAP_CAT_ATTACK_MIRROR.png', 'tw': './assets/tw/map/MAP_CAT_ATTACK_MIRROR.png'}) MAP_MODE_SWITCH_HARD = Button(area={'cn': (341, 580, 374, 617), 'en': (341, 580, 374, 617), 'jp': (341, 580, 374, 617), 'tw': (341, 580, 374, 617)}, color={'cn': (234, 179, 179), 'en': (234, 179, 179), 'jp': (234, 179, 179), 'tw': (234, 179, 179)}, button={'cn': (341, 580, 374, 617), 'en': (341, 580, 374, 617), 'jp': (341, 580, 374, 617), 'tw': (341, 580, 374, 617)}, file={'cn': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'en': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'jp': './assets/cn/map/MAP_MODE_SWITCH_HARD.png', 'tw': './assets/cn/map/MAP_MODE_SWITCH_HARD.png'}) diff --git a/module/ui/assets.py b/module/ui/assets.py index aab307853..dd01595d2 100644 --- a/module/ui/assets.py +++ b/module/ui/assets.py @@ -85,9 +85,10 @@ ISLAND_POSTMANAGE_GOTO_MANAGEMENT = Button(area={'cn': (0, 16, 108, 71), 'en': (0, 16, 108, 71), 'jp': (0, 16, 108, 71), 'tw': (0, 16, 108, 71)}, color={'cn': (239, 239, 240), 'en': (239, 239, 240), 'jp': (239, 239, 240), 'tw': (239, 239, 240)}, button={'cn': (0, 16, 108, 71), 'en': (0, 16, 108, 71), 'jp': (0, 16, 108, 71), 'tw': (0, 16, 108, 71)}, file={'cn': './assets/cn/ui/ISLAND_POSTMANAGE_GOTO_MANAGEMENT.png', 'en': './assets/cn/ui/ISLAND_POSTMANAGE_GOTO_MANAGEMENT.png', 'jp': './assets/cn/ui/ISLAND_POSTMANAGE_GOTO_MANAGEMENT.png', 'tw': './assets/cn/ui/ISLAND_POSTMANAGE_GOTO_MANAGEMENT.png'}) ISLAND_SEASON_CHECK = Button(area={'cn': (124, 18, 244, 47), 'en': (124, 18, 244, 47), 'jp': (125, 21, 218, 46), 'tw': (124, 18, 244, 47)}, color={'cn': (99, 106, 117), 'en': (99, 106, 117), 'jp': (60, 68, 81), 'tw': (99, 106, 117)}, button={'cn': (124, 18, 244, 47), 'en': (124, 18, 244, 47), 'jp': (125, 21, 218, 46), 'tw': (124, 18, 244, 47)}, file={'cn': './assets/cn/ui/ISLAND_SEASON_CHECK.png', 'en': './assets/cn/ui/ISLAND_SEASON_CHECK.png', 'jp': './assets/jp/ui/ISLAND_SEASON_CHECK.png', 'tw': './assets/cn/ui/ISLAND_SEASON_CHECK.png'}) ISLAND_SEASON_GOTO_ISLAND = Button(area={'cn': (34, 30, 68, 64), 'en': (34, 30, 68, 64), 'jp': (34, 30, 68, 64), 'tw': (34, 30, 68, 64)}, color={'cn': (238, 238, 238), 'en': (238, 238, 238), 'jp': (238, 238, 238), 'tw': (238, 238, 238)}, button={'cn': (34, 30, 68, 64), 'en': (34, 30, 68, 64), 'jp': (34, 30, 68, 64), 'tw': (34, 30, 68, 64)}, file={'cn': './assets/cn/ui/ISLAND_SEASON_GOTO_ISLAND.png', 'en': './assets/cn/ui/ISLAND_SEASON_GOTO_ISLAND.png', 'jp': './assets/cn/ui/ISLAND_SEASON_GOTO_ISLAND.png', 'tw': './assets/cn/ui/ISLAND_SEASON_GOTO_ISLAND.png'}) +ISLAND_SEED_SHOP_RETURN_CHECK = Button(area={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, color={'cn': (70, 75, 89), 'en': (70, 75, 89), 'jp': (70, 75, 89), 'tw': (70, 75, 89)}, button={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, file={'cn': './assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png', 'en': './assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png', 'jp': './assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png', 'tw': './assets/cn/ui/ISLAND_SEED_SHOP_RETURN_CHECK.png'}) ISLAND_SHOPPING_CHECK = Button(area={'cn': (479, 579, 586, 608), 'en': (479, 579, 586, 608), 'jp': (479, 579, 586, 608), 'tw': (479, 579, 586, 608)}, color={'cn': (247, 244, 243), 'en': (247, 244, 243), 'jp': (247, 244, 243), 'tw': (247, 244, 243)}, button={'cn': (479, 579, 586, 608), 'en': (479, 579, 586, 608), 'jp': (479, 579, 586, 608), 'tw': (479, 579, 586, 608)}, file={'cn': './assets/cn/ui/ISLAND_SHOPPING_CHECK.png', 'en': './assets/cn/ui/ISLAND_SHOPPING_CHECK.png', 'jp': './assets/cn/ui/ISLAND_SHOPPING_CHECK.png', 'tw': './assets/cn/ui/ISLAND_SHOPPING_CHECK.png'}) ISLAND_SHOPPING_GOTO_SHOP = Button(area={'cn': (963, 104, 1015, 161), 'en': (963, 104, 1015, 161), 'jp': (963, 104, 1015, 161), 'tw': (963, 104, 1015, 161)}, color={'cn': (61, 61, 61), 'en': (61, 61, 61), 'jp': (61, 61, 61), 'tw': (61, 61, 61)}, button={'cn': (963, 104, 1015, 161), 'en': (963, 104, 1015, 161), 'jp': (963, 104, 1015, 161), 'tw': (963, 104, 1015, 161)}, file={'cn': './assets/cn/ui/ISLAND_SHOPPING_GOTO_SHOP.png', 'en': './assets/cn/ui/ISLAND_SHOPPING_GOTO_SHOP.png', 'jp': './assets/cn/ui/ISLAND_SHOPPING_GOTO_SHOP.png', 'tw': './assets/cn/ui/ISLAND_SHOPPING_GOTO_SHOP.png'}) -ISLAND_SHOP_CHECK = Button(area={'cn': (28, 523, 93, 556), 'en': (28, 523, 93, 556), 'jp': (28, 523, 93, 556), 'tw': (28, 523, 93, 556)}, color={'cn': (88, 89, 90), 'en': (88, 89, 90), 'jp': (88, 89, 90), 'tw': (88, 89, 90)}, button={'cn': (28, 523, 93, 556), 'en': (28, 523, 93, 556), 'jp': (28, 523, 93, 556), 'tw': (28, 523, 93, 556)}, file={'cn': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'en': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'jp': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'tw': './assets/cn/ui/ISLAND_SHOP_CHECK.png'}) +ISLAND_SHOP_CHECK = Button(area={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, color={'cn': (88, 93, 104), 'en': (88, 93, 104), 'jp': (88, 93, 104), 'tw': (88, 93, 104)}, button={'cn': (125, 21, 216, 46), 'en': (125, 21, 216, 46), 'jp': (125, 21, 216, 46), 'tw': (125, 21, 216, 46)}, file={'cn': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'en': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'jp': './assets/cn/ui/ISLAND_SHOP_CHECK.png', 'tw': './assets/cn/ui/ISLAND_SHOP_CHECK.png'}) ISLAND_SHOP_GOTO_ISLAND = Button(area={'cn': (0, 18, 111, 72), 'en': (0, 18, 111, 72), 'jp': (0, 18, 111, 72), 'tw': (0, 18, 111, 72)}, color={'cn': (246, 246, 247), 'en': (246, 246, 247), 'jp': (246, 246, 247), 'tw': (246, 246, 247)}, button={'cn': (0, 18, 111, 72), 'en': (0, 18, 111, 72), 'jp': (0, 18, 111, 72), 'tw': (0, 18, 111, 72)}, file={'cn': './assets/cn/ui/ISLAND_SHOP_GOTO_ISLAND.png', 'en': './assets/cn/ui/ISLAND_SHOP_GOTO_ISLAND.png', 'jp': './assets/cn/ui/ISLAND_SHOP_GOTO_ISLAND.png', 'tw': './assets/cn/ui/ISLAND_SHOP_GOTO_ISLAND.png'}) ISLAND_STORAGE_CHECK = Button(area={'cn': (159, 99, 195, 117), 'en': (159, 99, 195, 117), 'jp': (159, 99, 195, 117), 'tw': (159, 99, 195, 117)}, color={'cn': (104, 105, 108), 'en': (104, 105, 108), 'jp': (104, 105, 108), 'tw': (104, 105, 108)}, button={'cn': (159, 99, 195, 117), 'en': (159, 99, 195, 117), 'jp': (159, 99, 195, 117), 'tw': (159, 99, 195, 117)}, file={'cn': './assets/cn/ui/ISLAND_STORAGE_CHECK.png', 'en': './assets/cn/ui/ISLAND_STORAGE_CHECK.png', 'jp': './assets/jp/ui/ISLAND_STORAGE_CHECK.png', 'tw': './assets/cn/ui/ISLAND_STORAGE_CHECK.png'}) ISLAND_STORAGE_EXIT = Button(area={'cn': (1124, 86, 1163, 123), 'en': (1124, 86, 1163, 123), 'jp': (1124, 86, 1163, 123), 'tw': (1124, 86, 1163, 123)}, color={'cn': (228, 228, 228), 'en': (228, 228, 228), 'jp': (228, 228, 228), 'tw': (228, 228, 228)}, button={'cn': (1124, 86, 1163, 123), 'en': (1124, 86, 1163, 123), 'jp': (1124, 86, 1163, 123), 'tw': (1124, 86, 1163, 123)}, file={'cn': './assets/cn/ui/ISLAND_STORAGE_EXIT.png', 'en': './assets/cn/ui/ISLAND_STORAGE_EXIT.png', 'jp': './assets/cn/ui/ISLAND_STORAGE_EXIT.png', 'tw': './assets/cn/ui/ISLAND_STORAGE_EXIT.png'}) diff --git a/module/ui/page.py b/module/ui/page.py index 8941c6b2c..e5a3f64ce 100644 --- a/module/ui/page.py +++ b/module/ui/page.py @@ -362,7 +362,7 @@ def link(self, button, destination): page_island_message = Page(DORMMENU_GOTO_ISLAND_MESSAGE) page_island_management = Page(ISLAND_MANAGEMENT_CHECK) page_island_postmanage = Page(ISLAND_POSTMANAGE_CHECK) -page_island_shop = Page(ISLAND_SHOP_CHECK) +page_island_shop = Page(ISLAND_SEED_SHOP_RETURN_CHECK) page_island_shopping = Page(ISLAND_SHOPPING_CHECK) page_island_warehouse = Page(ISLAND_WAREHOUSE_CHECK) page_island_warehouse_filter = Page(ISLAND_WAREHOUSE_FILTER_CHECK) From 0f7f76200c48be4f6251daf344403b6fccfb26e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=89=91=E9=B8=A3?= Date: Sun, 7 Jun 2026 13:04:59 +0800 Subject: [PATCH 2/2] fix MuMu Pro detection for generic ADB serials --- module/device/connection_attr.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/module/device/connection_attr.py b/module/device/connection_attr.py index bde6df59e..32db6c469 100644 --- a/module/device/connection_attr.py +++ b/module/device/connection_attr.py @@ -169,7 +169,12 @@ def is_mumu12_family(self): def is_mumu_family(self): # 127.0.0.1:7555 # 127.0.0.1:16384 + 32*n - return self.serial == '127.0.0.1:7555' or self.is_mumu12_family + # MuMu Pro on macOS may expose a generic emulator-* serial instead. + return ( + self.serial == '127.0.0.1:7555' + or self.is_mumu12_family + or self.config.EmulatorInfo_Emulator == 'MuMuPro' + ) @cached_property def is_ldplayer_bluestacks_family(self):