diff --git a/assets/game_data/screen_info/notorious_hunt.yml b/assets/game_data/screen_info/notorious_hunt.yml index 0e5d02ba..aeec2628 100644 --- a/assets/game_data/screen_info/notorious_hunt.yml +++ b/assets/game_data/screen_info/notorious_hunt.yml @@ -226,3 +226,79 @@ area_list: template_match_threshold: 0.7 color_range: null goto_list: [] +- area_name: 按钮-深度追猎-ON + id_mark: false + pc_rect: + - 0 + - 0 + - 0 + - 0 + text: 'ON' + lcs_percent: 0.5 + template_sub_dir: '' + template_id: '' + template_match_threshold: 0.7 + color_range: + - - 70 + - 80 + - 0 + - - 255 + - 255 + - 255 + goto_list: [] +- area_name: 按钮-深度追猎-确认 + id_mark: false + pc_rect: + - 0 + - 0 + - 0 + - 0 + text: 确认 + lcs_percent: 0.5 + template_sub_dir: '' + template_id: '' + template_match_threshold: 0.7 + color_range: null + goto_list: [] +- area_name: 文本-剩余电量 + id_mark: false + pc_rect: + - 0 + - 0 + - 0 + - 0 + text: '' + lcs_percent: 0.5 + template_sub_dir: '' + template_id: '' + template_match_threshold: 0.7 + color_range: null + goto_list: [] +- area_name: 文本-需要电量 + id_mark: false + pc_rect: + - 0 + - 0 + - 0 + - 0 + text: '' + lcs_percent: 0.5 + template_sub_dir: '' + template_id: '' + template_match_threshold: 0.7 + color_range: null + goto_list: [] +- area_name: 按钮-无报酬模式 + id_mark: false + pc_rect: + - 0 + - 0 + - 0 + - 0 + text: 无报酬模式 + lcs_percent: 0.5 + template_sub_dir: '' + template_id: '' + template_match_threshold: 0.7 + color_range: null + goto_list: [] diff --git a/src/zzz_od/application/charge_plan/charge_plan_app.py b/src/zzz_od/application/charge_plan/charge_plan_app.py index 7dcee293..19685892 100644 --- a/src/zzz_od/application/charge_plan/charge_plan_app.py +++ b/src/zzz_od/application/charge_plan/charge_plan_app.py @@ -11,6 +11,7 @@ from zzz_od.operation.back_to_normal_world import BackToNormalWorld from zzz_od.operation.compendium.combat_simulation import CombatSimulation from zzz_od.operation.compendium.expert_challenge import ExpertChallenge +from zzz_od.operation.compendium.notorious_hunt import NotoriousHunt from zzz_od.operation.compendium.routine_cleanup import RoutineCleanup from zzz_od.operation.compendium.tp_by_compendium import TransportByCompendium from zzz_od.operation.goto.goto_menu import GotoMenu @@ -37,6 +38,7 @@ def __init__(self, ctx: ZContext): @node_from(from_name='实战模拟室') @node_from(from_name='定期清剿') @node_from(from_name='专业挑战室') + @node_from(from_name='恶名狩猎') @operation_node(name='打开菜单', is_start_node=True) def goto_menu(self) -> OperationRoundResult: op = GotoMenu(self.ctx) @@ -79,6 +81,8 @@ def transport(self) -> OperationRoundResult: need_charge_power = 60 elif self.next_plan.category_name == '专业挑战室': need_charge_power = 40 + elif self.next_plan.category_name == '恶名狩猎': + need_charge_power = 60 else: self.need_to_check_power_in_mission = True @@ -126,11 +130,21 @@ def expert_challenge(self) -> OperationRoundResult: can_run_times=None if self.need_to_check_power_in_mission else self.next_can_run_times) return self.round_by_op_result(op.execute()) + @node_from(from_name='识别副本分类', status='恶名狩猎') + @operation_node(name='专业挑战室') + def notorious_hunt(self) -> OperationRoundResult: + op = NotoriousHunt(self.ctx, self.next_plan, + use_charge_power=True, + need_check_power=self.need_to_check_power_in_mission, + can_run_times=None if self.need_to_check_power_in_mission else self.next_can_run_times) + return self.round_by_op_result(op.execute()) + @node_from(from_name='传送', status=STATUS_ROUND_FINISHED) @node_from(from_name='传送', success=False) @node_from(from_name='实战模拟室', status=CombatSimulation.STATUS_CHARGE_NOT_ENOUGH) @node_from(from_name='定期清剿', status=RoutineCleanup.STATUS_CHARGE_NOT_ENOUGH) @node_from(from_name='专业挑战室', status=ExpertChallenge.STATUS_CHARGE_NOT_ENOUGH) + @node_from(from_name='恶名狩猎', status=ExpertChallenge.STATUS_CHARGE_NOT_ENOUGH) @operation_node(name='返回大世界', is_start_node=True) def back_to_world(self) -> OperationRoundResult: op = BackToNormalWorld(self.ctx) diff --git a/src/zzz_od/application/charge_plan/charge_plan_config.py b/src/zzz_od/application/charge_plan/charge_plan_config.py index 1842893f..b9d18003 100644 --- a/src/zzz_od/application/charge_plan/charge_plan_config.py +++ b/src/zzz_od/application/charge_plan/charge_plan_config.py @@ -8,11 +8,11 @@ class CardNumEnum(Enum): DEFAULT = ConfigItem('默认数量') - NUM_1 = ConfigItem('1') - NUM_2 = ConfigItem('2') - NUM_3 = ConfigItem('3') - NUM_4 = ConfigItem('4') - NUM_5 = ConfigItem('5') + NUM_1 = ConfigItem('1张卡片', '1') + NUM_2 = ConfigItem('2张卡片', '2') + NUM_3 = ConfigItem('3张卡片', '3') + NUM_4 = ConfigItem('4张卡片', '4') + NUM_5 = ConfigItem('5张卡片', '5') class ChargePlanItem: @@ -29,7 +29,7 @@ def __init__( plan_times: int = 1, card_num: str = CardNumEnum.DEFAULT.value.value, predefined_team_idx: int = -1, - notorious_hunt_buff_num: int = 1 + notorious_hunt_buff_num: int = 1, ): self.tab_name: str = tab_name self.category_name: str = category_name @@ -86,7 +86,7 @@ def save(self): 'plan_times': plan_item.plan_times, 'card_num': plan_item.card_num, 'predefined_team_idx': plan_item.predefined_team_idx, - 'notorious_hunt_buff_num': plan_item.notorious_hunt_buff_num + 'notorious_hunt_buff_num': plan_item.notorious_hunt_buff_num, } new_history_list.append(plan_data.copy()) diff --git a/src/zzz_od/application/notorious_hunt/notorious_hunt_app.py b/src/zzz_od/application/notorious_hunt/notorious_hunt_app.py index e63ebccd..28dcc415 100644 --- a/src/zzz_od/application/notorious_hunt/notorious_hunt_app.py +++ b/src/zzz_od/application/notorious_hunt/notorious_hunt_app.py @@ -55,7 +55,7 @@ def transport(self) -> OperationRoundResult: @node_from(from_name='判断剩余次数') @operation_node(name='恶名狩猎') def notorious_hunt(self) -> OperationRoundResult: - op = NotoriousHunt(self.ctx, self.next_plan) + op = NotoriousHunt(self.ctx, self.next_plan, use_charge_power=False) return self.round_by_op_result(op.execute()) @node_from(from_name='恶名狩猎') diff --git a/src/zzz_od/application/notorious_hunt/notorious_hunt_config.py b/src/zzz_od/application/notorious_hunt/notorious_hunt_config.py index b169852f..3eda36d5 100644 --- a/src/zzz_od/application/notorious_hunt/notorious_hunt_config.py +++ b/src/zzz_od/application/notorious_hunt/notorious_hunt_config.py @@ -77,7 +77,7 @@ def save(self): 'auto_battle_config': plan_item.auto_battle_config, 'run_times': plan_item.run_times, 'plan_times': plan_item.plan_times, - 'notorious_hunt_buff_num': plan_item.notorious_hunt_buff_num + 'notorious_hunt_buff_num': plan_item.notorious_hunt_buff_num, }) YamlConfig.save(self) diff --git a/src/zzz_od/game_data/compendium.py b/src/zzz_od/game_data/compendium.py index 80c318b2..d6553b30 100644 --- a/src/zzz_od/game_data/compendium.py +++ b/src/zzz_od/game_data/compendium.py @@ -211,12 +211,22 @@ def get_charge_plan_category_list(self) -> List[ConfigItem]: value=category_item.category_name )) + category_list = self.get_category_list_data('作战') + for category_item in category_list: + if category_item.category_name not in ['恶名狩猎']: + continue + category_config_list.append(ConfigItem( + label=category_item.category_name, + value=category_item.category_name + )) + return category_config_list def get_charge_plan_mission_type_list(self, category_name: str) -> List[ConfigItem]: config_list: List[ConfigItem] = [] - mission_type_list = self.get_mission_type_list_data('训练', category_name) + tab_name = '作战' if category_name == '恶名狩猎' else '训练' + mission_type_list = self.get_mission_type_list_data(tab_name, category_name) for mission_type_item in mission_type_list: config_list.append(ConfigItem( label=mission_type_item.mission_type_name_display, @@ -228,7 +238,8 @@ def get_charge_plan_mission_type_list(self, category_name: str) -> List[ConfigIt def get_charge_plan_mission_list(self, category_name: str, mission_type: str) -> List[ConfigItem]: config_list: List[ConfigItem] = [] - mission_list = self.get_mission_list_data('训练', category_name, mission_type) + tab_name = '作战' if category_name == '恶名狩猎' else '训练' + mission_list = self.get_mission_list_data(tab_name, category_name, mission_type) for mission_item in mission_list: config_list.append(ConfigItem( label=mission_item.mission_name_display, diff --git a/src/zzz_od/gui/view/one_dragon/charge_plan_interface.py b/src/zzz_od/gui/view/one_dragon/charge_plan_interface.py index 0385a109..f8a80042 100644 --- a/src/zzz_od/gui/view/one_dragon/charge_plan_interface.py +++ b/src/zzz_od/gui/view/one_dragon/charge_plan_interface.py @@ -9,6 +9,7 @@ from one_dragon.gui.widgets.setting_card.switch_setting_card import SwitchSettingCard from zzz_od.application.battle_assistant.auto_battle_config import get_auto_battle_op_config_list from zzz_od.application.charge_plan.charge_plan_config import ChargePlanItem, CardNumEnum +from zzz_od.application.notorious_hunt.notorious_hunt_config import NotoriousHuntBuffEnum from zzz_od.context.zzz_context import ZContext from phosdeiz.gui.widgets import Column,ComboBox @@ -37,6 +38,9 @@ def __init__(self, ctx: ZContext, self.card_num_box = ComboBox() self.card_num_box.currentIndexChanged.connect(self._on_card_num_changed) + self.notorious_hunt_buff_num_opt = ComboBox() + self.notorious_hunt_buff_num_opt.currentIndexChanged.connect(self.on_notorious_hunt_buff_num_changed) + self.predefined_team_opt = ComboBox() self.predefined_team_opt.currentIndexChanged.connect(self.on_predefined_team_changed) @@ -66,6 +70,7 @@ def __init__(self, ctx: ZContext, self.mission_type_combo_box, self.mission_combo_box, self.card_num_box, + self.notorious_hunt_buff_num_opt, self.predefined_team_opt, self.auto_battle_combo_box, ], @@ -100,6 +105,14 @@ def init_card_num_box(self) -> None: self.card_num_box.set_items(config_list, self.plan.card_num) self.card_num_box.setVisible(self.plan.category_name == '实战模拟室') + def init_notorious_hunt_buff_num_opt(self) -> None: + """ + 初始化不透明度下拉框 + """ + config_list = [config_enum.value for config_enum in NotoriousHuntBuffEnum] + self.notorious_hunt_buff_num_opt.set_items(config_list, self.plan.notorious_hunt_buff_num) + self.notorious_hunt_buff_num_opt.setVisible(self.plan.category_name == '恶名狩猎') + def init_predefined_team_opt(self) -> None: """ 初始化预备编队的下拉框 @@ -134,6 +147,7 @@ def init_with_plan(self, plan: ChargePlanItem) -> None: self.init_mission_combo_box() self.init_card_num_box() + self.init_notorious_hunt_buff_num_opt() self.init_predefined_team_opt() self.init_auto_battle_box() @@ -146,6 +160,7 @@ def _on_category_changed(self, idx: int) -> None: self.init_mission_type_combo_box() self.init_mission_combo_box() + self.init_notorious_hunt_buff_num_opt() self.update_by_history() @@ -171,6 +186,10 @@ def _on_card_num_changed(self, idx: int) -> None: self.plan.card_num = self.card_num_box.itemData(idx) self._emit_value() + def on_notorious_hunt_buff_num_changed(self, idx: int) -> None: + self.plan.notorious_hunt_buff_num = self.notorious_hunt_buff_num_opt.currentData() + self._emit_value() + def on_predefined_team_changed(self, idx: int) -> None: self.plan.predefined_team_idx = self.predefined_team_opt.currentData() self.init_auto_battle_box() @@ -208,11 +227,13 @@ def update_by_history(self) -> None: return self.plan.card_num = history.card_num + self.plan.notorious_hunt_buff_num = history.notorious_hunt_buff_num self.plan.predefined_team_idx = history.predefined_team_idx self.plan.auto_battle_config = history.auto_battle_config self.plan.plan_times = history.plan_times self.init_card_num_box() + self.init_notorious_hunt_buff_num_opt() self.init_predefined_team_opt() self.init_auto_battle_box() self.init_plan_times_input() diff --git a/src/zzz_od/operation/compendium/notorious_hunt.py b/src/zzz_od/operation/compendium/notorious_hunt.py index 00194f68..3206ad24 100644 --- a/src/zzz_od/operation/compendium/notorious_hunt.py +++ b/src/zzz_od/operation/compendium/notorious_hunt.py @@ -26,8 +26,14 @@ class NotoriousHunt(ZOperation): STATUS_NO_LEFT_TIMES: ClassVar[str] = '没有剩余次数' - - def __init__(self, ctx: ZContext, plan: ChargePlanItem): + STATUS_WITH_LEFT_TIMES: ClassVar[str] = '有剩余次数' + STATUS_CHARGE_NOT_ENOUGH: ClassVar[str] = '电量不足' + STATUS_CHARGE_ENOUGH: ClassVar[str] = '电量充足' + + def __init__(self, ctx: ZContext, plan: ChargePlanItem, + use_charge_power: bool = False, + can_run_times: Optional[int] = None, + need_check_power: bool = False): """ 使用快捷手册传送后 用这个进行挑战 @@ -42,6 +48,10 @@ def __init__(self, ctx: ZContext, plan: ChargePlanItem): ) self.plan: ChargePlanItem = plan + self.use_charge_power: bool = use_charge_power # 是否使用电量 深度追猎 + self.need_check_power: bool = need_check_power + self.can_run_times: int = can_run_times + self.auto_op: Optional[AutoBattleOperator] = None self.charge_left: Optional[int] = None self.charge_need: Optional[int] = None @@ -62,26 +72,6 @@ def wait_entry_load(self) -> OperationRoundResult: return self.round_retry(r1.status, wait=1) @node_from(from_name='等待入口加载') - @operation_node(name='识别剩余次数') - def check_left_times(self) -> OperationRoundResult: - screen = self.screenshot() - area = self.ctx.screen_loader.get_area('恶名狩猎', '剩余次数') - part = cv2_utils.crop_image_only(screen, area.rect) - - ocr_result = self.ctx.ocr.run_ocr_single_line(part) - left_times = str_utils.get_positive_digits(ocr_result, None) - - if left_times is None: - return self.round_retry('未能识别剩余次数', wait_round_time=1) - elif left_times == 0: - self.ctx.notorious_hunt_record.left_times = 0 - return self.round_success(NotoriousHunt.STATUS_NO_LEFT_TIMES) - else: - self.ctx.notorious_hunt_record.left_times = left_times - self.can_run_times = min(left_times, self.plan.plan_times - self.plan.run_times) - return self.round_success() - - @node_from(from_name='识别剩余次数') @operation_node(name='选择副本') def choose_mission(self) -> OperationRoundResult: screen = self.screenshot() @@ -121,6 +111,84 @@ def choose_mission(self) -> OperationRoundResult: return self.round_retry(f'未能识别{self.plan.mission_type_name}', wait_round_time=2) @node_from(from_name='选择副本') + @operation_node(name='选择深度追猎') + def choose_by_use_power(self): + screen = self.screenshot() + + result = self.round_by_find_area(screen, '恶名狩猎', '按钮-深度追猎-ON') + current_use_power = result.is_success # 当前在深度追猎模式 + + if self.use_charge_power == current_use_power: + return self.round_success() + + # 选择深度追猎之后的对话框 + result = self.round_by_find_and_click_area(screen, '恶名狩猎', '按钮-深度追猎-确认') + if result.is_success: + return self.round_wait(result.status, wait=1) + + self.round_by_click_area('恶名狩猎', '按钮-深度追猎-ON') + return self.round_retry(wait=1) + + @node_from(from_name='选择深度追猎') + @operation_node(name='识别可运行次数') + def check_can_run_times(self) -> OperationRoundResult: + screen = self.screenshot() + + if self.use_charge_power: # 深度追猎 + if self.need_check_power: + area = self.ctx.screen_loader.get_area('恶名狩猎', '文本-剩余电量') + part = cv2_utils.crop_image_only(screen, area.rect) + ocr_result = self.ctx.ocr.run_ocr_single_line(part) + self.charge_left = str_utils.get_positive_digits(ocr_result, None) + if self.charge_left is None: + return self.round_retry(status='识别 %s 失败' % '剩余电量', wait=1) + + area = self.ctx.screen_loader.get_area('恶名狩猎', '文本-需要电量') + part = cv2_utils.crop_image_only(screen, area.rect) + ocr_result = self.ctx.ocr.run_ocr_single_line(part) + self.charge_need = str_utils.get_positive_digits(ocr_result, None) + if self.charge_need is None: + return self.round_retry(status='识别 %s 失败' % '需要电量', wait=1) + + log.info('所需电量 %d 剩余电量 %d', self.charge_need, self.charge_left) + if self.charge_need > self.charge_left: + return self.round_success(NotoriousHunt.STATUS_CHARGE_NOT_ENOUGH) + + self.can_run_times = self.charge_left // self.charge_need + max_need_run_times = self.plan.plan_times - self.plan.run_times + + if self.can_run_times > max_need_run_times: + self.can_run_times = max_need_run_times + + return self.round_success(NotoriousHunt.STATUS_CHARGE_ENOUGH) + else: + if self.can_run_times == 0: + return self.round_success(NotoriousHunt.STATUS_CHARGE_NOT_ENOUGH) + else: + return self.round_success(NotoriousHunt.STATUS_CHARGE_ENOUGH) + else: + result = self.round_by_find_area(screen, '恶名狩猎', '按钮-无报酬模式') + if result.is_success: # 可能是其他设备挑战了 没有剩余次数了 + self.ctx.notorious_hunt_record.left_times = 0 + return self.round_success(NotoriousHunt.STATUS_NO_LEFT_TIMES) + + area = self.ctx.screen_loader.get_area('恶名狩猎', '剩余次数') + part = cv2_utils.crop_image_only(screen, area.rect) + + ocr_result = self.ctx.ocr.run_ocr_single_line(part) + left_times = str_utils.get_positive_digits(ocr_result, None) + if left_times is None: # 识别不到时 使用记录中的数量 + self.can_run_times = self.ctx.notorious_hunt_record.left_times + + # 运行次数上限是计划剩余次数 + need_run_times = self.plan.plan_times - self.plan.run_times + if self.can_run_times > need_run_times: + self.can_run_times = need_run_times + + return self.round_success(NotoriousHunt.STATUS_WITH_LEFT_TIMES) + + @node_from(from_name='识别可运行次数', status=STATUS_CHARGE_ENOUGH) + @node_from(from_name='识别可运行次数', status=STATUS_WITH_LEFT_TIMES) @operation_node(name='选择难度') def choose_level(self) -> OperationRoundResult: if self.plan.level == NotoriousHuntLevelEnum.DEFAULT.value.value: @@ -352,8 +420,11 @@ def battle_fail_exit(self) -> OperationRoundResult: @operation_node(name='战斗结束') def after_battle(self) -> OperationRoundResult: self.can_run_times -= 1 - self.ctx.notorious_hunt_record.left_times = self.ctx.notorious_hunt_record.left_times - 1 - self.ctx.notorious_hunt_config.add_plan_run_times(self.plan) + if self.use_charge_power: + self.ctx.charge_plan_config.add_plan_run_times(self.plan) + else: + self.ctx.notorious_hunt_record.left_times = self.ctx.notorious_hunt_record.left_times - 1 + self.ctx.notorious_hunt_config.add_plan_run_times(self.plan) return self.round_success() @node_from(from_name='战斗结束') @@ -372,7 +443,10 @@ def check_next(self) -> OperationRoundResult: def no_left_times(self) -> OperationRoundResult: # 本地记录的剩余次数错误 找不到再来一次 # 可能在其它设备上完成了挑战 也可能是上面识别错了 - self.ctx.notorious_hunt_record.left_times = 0 + if self.use_charge_power: + pass + else: + self.ctx.notorious_hunt_record.left_times = 0 screen = self.screenshot() return self.round_by_find_and_click_area(screen, '战斗画面', '战斗结果-完成', success_wait=5, retry_wait_round=1)