From 7b8ba1622d910c208f34104efb6acee74e55df4a Mon Sep 17 00:00:00 2001 From: Beatrice-betty Date: Mon, 27 Jul 2026 13:13:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(emotion,coalition):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=83=85=E7=BB=AA=E8=AE=A1=E7=AE=97=E5=92=8C=E8=81=94=E7=9B=9F?= =?UTF-8?q?=E6=B2=89=E8=88=B9=E5=BF=83=E6=83=85=E6=89=A3=E5=87=8F=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 重构情绪恢复计算逻辑,使用浮点值保留恢复余数,跨record调用累积 2. 调整联盟沉船心情扣减规则,仅关卡进入时扣减一次,不再按战斗次数额外扣减 3. 优化record方法,仅在情绪整数变化时更新时间戳并回扣余数秒数 4. 修复情绪显示逻辑,显示实时恢复值而非缓存值 --- module/coalition/coalition_scuttle.py | 76 +++++++++++++++++++++------ module/combat/emotion.py | 59 +++++++++++++++------ 2 files changed, 102 insertions(+), 33 deletions(-) diff --git a/module/coalition/coalition_scuttle.py b/module/coalition/coalition_scuttle.py index 140fa7762..f25495c1e 100644 --- a/module/coalition/coalition_scuttle.py +++ b/module/coalition/coalition_scuttle.py @@ -24,12 +24,14 @@ class CoalitionScuttleCombat(CoalitionCombat): def auto_search_combat_execute(self, emotion_reduce=True, fleet_index=1, expected_end=None): """ - 重写自动搜索战斗执行,D评价沉船时不额外扣减10心情。 + 重写自动搜索战斗执行,联盟沉船不额外扣减心情。 - 进入战斗扣减2心情(正常出击代价),D评价不执行 shipwreck=True 的额外扣减。 + 联盟沉船中一个关卡包含多次战斗(1/2/3/4队), + 但游戏只在整个关卡进入时扣1次2点心情,不按内部战斗次数扣减。 + D评价也不执行 shipwreck=True 的额外扣减。 Args: - emotion_reduce (bool): 是否扣减心情。 + emotion_reduce (bool): 是否扣减心情(仅在第一场战斗时为True)。 fleet_index (int): 舰队编号。 expected_end (callable): 自定义结束条件。 """ @@ -41,7 +43,8 @@ def auto_search_combat_execute(self, emotion_reduce=True, fleet_index=1, expecte self.device.stuck_record_clear() self.device.click_record_clear() - # 进入战斗扣减2心情(正常出击代价) + # 联盟沉船仅在第一场战斗时扣减2心情(关卡进入代价) + # 后续战斗(2/3/4队)不再扣减,与游戏服务端行为一致 if emotion_reduce: self.emotion.reduce(fleet_index) @@ -81,7 +84,7 @@ def auto_search_combat_execute(self, emotion_reduce=True, fleet_index=1, expecte if self.handle_get_ship(): continue - # D评价沉船:不执行 emotion.reduce(shipwreck=True) + # D评价沉船:不额外扣减心情 if self.appear_then_click(OPTS_INFO_D, offset=(30, 30), interval=2): self._withdraw = True self._is_shipwreck = True @@ -97,11 +100,10 @@ def auto_search_combat_execute(self, emotion_reduce=True, fleet_index=1, expecte confirm_timer.reset() break - # A/B评价正常扣减心情 + # A/B/S评价:联盟沉船中不额外扣减心情 + # 游戏服务端只在整个关卡进入时扣1次2点,不按战斗结算类型扣减 if self.appear(BATTLE_STATUS_A) or self.appear(BATTLE_STATUS_B) \ or self.appear(EXP_INFO_A) or self.appear(EXP_INFO_B): - if emotion_reduce: - self.emotion.reduce(fleet_index, shipwreck=True) break # S评价或自动搜索运行中 @@ -117,21 +119,23 @@ def auto_search_combat_execute(self, emotion_reduce=True, fleet_index=1, expecte def coalition_combat(self): """ - 联盟沉船战斗执行,进入战斗扣减2心情,D评价不额外扣减。 + 联盟沉船战斗执行,仅在第一场战斗扣减2心情。 - 原因:沉船任务中舰船被击沉后需要换新船,不应扣减额外心情。 + 联盟沉船一个关卡包含多次战斗(1/2/3/4队), + 但游戏只在整个关卡进入时扣1次2点心情,后续战斗不再扣减。 """ from module.exception import CampaignEnd self.battle_count = 0 - self.combat_preparation(emotion_reduce=False) # 不在此扣减,由 auto_search_combat_execute 统一扣减 + self.combat_preparation(emotion_reduce=False) try: while 1: logger.hr(f'{self.FUNCTION_NAME_BASE}{self.battle_count}', level=2) - self._is_shipwreck = False # 重置沉船标记 + self._is_shipwreck = False + # 仅第一场战斗扣减2心情(关卡进入代价),后续战斗不再扣减 self.auto_search_combat_execute( - emotion_reduce=True, # 进入战斗扣减2心情 + emotion_reduce=self.battle_count == 0, fleet_index=1, expected_end=self.auto_search_combat_end ) @@ -247,7 +251,7 @@ def coalition_combat_re_enter(self, skip_first_screenshot=True): class CoalitionScuttleRun(Coalition, CoalitionScuttleCombat): - """联盟沉船主循环,沉船任务不扣减心情。""" + """联盟沉船主循环,沉船任务进入关卡只扣1次2点心情。""" def handle_combat_low_emotion(self): """ @@ -257,15 +261,53 @@ def handle_combat_low_emotion(self): """ return self.handle_popup_confirm('IGNORE_LOW_EMOTION') + def coalition_execute_once(self, event, stage, fleet): + """执行一次联盟沉船战斗。 + + 覆盖父类方法,将心情预估从多场战斗改为1场(整个关卡只扣1次2点)。 + 联盟沉船虽然内部有多次战斗(1/2/3/4队),但游戏只在整个关卡进入时扣1次心情。 + + Args: + event: 活动名称。 + stage: 关卡名称。 + fleet: 舰队模式。 + """ + self.config.override( + Campaign_Name=f'{event}_{stage}', + Campaign_UseAutoSearch=False, + Fleet_FleetOrder='fleet1_all_fleet2_standby', + ) + if self.config.Coalition_Fleet == 'single' and self.config.Emotion_Fleet1Control == 'prevent_red_face': + logger.warning('AL does not allow single coalition with emotion < 30, ' + 'emotion control is forced to prevent_yellow_face') + self.config.override(Emotion_Fleet1Control='prevent_yellow_face') + if stage == 'sp': + self.config.override(Coalition_Fleet='multi') + + # 联盟沉船:整个关卡只扣1次2点心情,不按内部战斗次数预估 + try: + self.emotion.check_reduce(battle=1) + except ScriptEnd: + self.coalition_map_exit(event) + raise + + if self._coalition_has_oil_icon and self.triggered_stop_condition(oil_check=True, coin_check=True): + self.coalition_map_exit(event) + raise ScriptEnd + + self.enter_map(event=event, stage=stage, mode=fleet) + self.coalition_combat() + def triggered_stop_condition(self, oil_check=False, pt_check=False, coin_check=False): """ - 检查是否触发了停止条件,在父类基础上增加沉船正常结束检测。 + 检查是否触发了停止条件。 + + 联盟沉船不因 triggered_normal_end(舰船被击沉)而停止任务, + 由 RunCount 控制何时停止。D评价和非D评价都算1次有效战斗。 Returns: bool: 是否触发了停止条件。 """ - if self.triggered_normal_end: - return True if super().triggered_stop_condition(oil_check=oil_check, pt_check=pt_check, coin_check=coin_check): return True diff --git a/module/combat/emotion.py b/module/combat/emotion.py index cb1e73959..0685804cb 100644 --- a/module/combat/emotion.py +++ b/module/combat/emotion.py @@ -168,16 +168,20 @@ def max(self): def update(self): """根据实际经过时间计算情绪恢复。 - 使用连续时间恢复计算,而非离散6分钟区间。 - 原方法使用 // 360 计算恢复次数,当 record() 频繁重置时间戳时 - (如联盟沉船每2分钟调用一次),恢复永远无法累积。 - 改为按实际秒数计算恢复量,与游戏服务端行为一致。 - """ - time_diff = int(current_time().timestamp()) - int(self.record.timestamp()) + 使用连续时间恢复计算,保留浮点恢复量以累积分数部分。 + 游戏服务端按实际经过时间精确计算恢复,每6分钟恢复speed点。 + 旧方法用 int() 截断恢复量,每次 record() 重置时间戳后, + 未满1点的恢复余数被丢弃,长时间运行导致严重低估。 + 现改为 floor() 取整保留整数部分,同时 record() 仅在整数变化时 + 重置时间戳并回扣分数秒,确保余数可跨次累积。 + """ + time_diff = current_time().timestamp() - self.record.timestamp() time_diff = max(time_diff, 0) # speed 为每360秒的恢复量,换算为每秒恢复 speed/360 点 recovery = self.speed * time_diff / 360 self.current = min(max(self.value, 0) + int(recovery), self.max) + # 保留未满1点的恢复余数对应的秒数,用于 record() 回扣 + self._fractional_seconds = recovery - int(recovery) def get_recovered(self, expected_reduce=0): """计算情绪恢复到控制阈值的时间。 @@ -268,25 +272,48 @@ def update(self): fleet.update() def record(self): - """将当前情绪值保存到配置中。""" + """将当前情绪值保存到配置中。 + + 仅在心情整数值发生变化时更新 Record 时间戳, + 并将 Record 回扣 fractional_seconds 对应的等效秒数, + 使未满1点的恢复余数可在下次 update() 时继续累积。 + """ if self.using_public: - value = {self.public_fleet.value_name: self.public_fleet.current} - self.config.set_record(**value) + fleet = self.public_fleet + old_value = fleet.value + new_value = fleet.current + # 仅在整数变化时重置时间戳,回扣分数秒 + if new_value != old_value: + record_time = current_time().replace(microsecond=0) + fractional = getattr(fleet, '_fractional_seconds', 0) + if fractional > 0: + # 回扣 fractional_seconds 对应的秒数 + record_time = record_time - timedelta(seconds=fractional * 360 / fleet.speed) + with self.config.multi_set(): + setattr(self.config, fleet.value_name, new_value) + setattr(self.config, fleet.value_name.replace('Value', 'Record'), record_time) return - - value = {} - for fleet in self.fleets: - value[fleet.value_name] = fleet.current - self.config.set_record(**value) + with self.config.multi_set(): + for fleet in self.fleets: + old_value = fleet.value + new_value = fleet.current + if new_value != old_value: + record_time = current_time().replace(microsecond=0) + fractional = getattr(fleet, '_fractional_seconds', 0) + if fractional > 0: + record_time = record_time - timedelta(seconds=fractional * 360 / fleet.speed) + setattr(self.config, fleet.value_name, new_value) + setattr(self.config, fleet.value_name.replace('Value', 'Record'), record_time) def show(self): + """显示当前计算的心情值(含时间恢复),而非上次保存值。""" if self.using_public: - logger.attr(f'情绪公海舰队', self.public_fleet.value) + logger.attr(f'情绪公海舰队', self.public_fleet.current) return for fleet in self.fleets: - logger.attr(f'情绪舰队_{fleet.fleet}', fleet.value) + logger.attr(f'情绪舰队_{fleet.fleet}', fleet.current) @property def reduce_per_battle(self):