Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion module/campaign/gems_farming.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

class GemsCampaignOverride(CampaignBase):

def handle_combat_low_emotion(self):
def handle_combat_low_emotion(self, fleet_index=None):
"""
Overwrite info_handler.handle_combat_low_emotion()
If change vanguard is enabled, withdraw combat and change flagship and vanguard
Expand Down
118 changes: 118 additions & 0 deletions module/campaign/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@


class CampaignRun(CampaignEvent):
EMOTION_DOCK_CHECK_TASKS = {'Main', 'Main2', 'Main3', 'Event', 'Event2', 'WarArchives'}
EMOTION_POPUP_ONLY_STAGE_PREFIX = ('ht', 'c', 'd')

folder: str
name: str
stage: str
Expand Down Expand Up @@ -365,6 +368,112 @@ def handle_commission_notice(self):
self.config.task_call('Commission', force_call=True)
self.config.task_stop('Commission notice found')

@classmethod
def is_event_hard_stage(cls, name, folder):
if not str(folder).startswith('event_'):
return False
name = str(name).lower()
return name.startswith(cls.EMOTION_POPUP_ONLY_STAGE_PREFIX)

def emotion_popup_only_set(self, name, folder, log=True):
popup_only = self.is_event_hard_stage(name=name, folder=folder)
self.config.Emotion_PopupOnly = popup_only
if hasattr(self, 'campaign'):
self.campaign.config.Emotion_PopupOnly = popup_only
if popup_only and log:
logger.info('Event hard stage uses popup-only emotion control')

def emotion_dock_calibrate(self):
"""
Sync current task emotion ledger from normal fleet ships in dock.

Returns:
bool: If dock UI might have been entered and campaign UI should be restored.

Pages:
in: page_campaign
out: page_campaign or page_dock
"""
command = self.config.Scheduler_Command
if command not in self.EMOTION_DOCK_CHECK_TASKS:
return False
if self.campaign.emotion.is_popup_only:
return False
if not self.campaign.emotion.is_calculate:
return False

fleet_mapping = {}
for task_fleet in [1, 2]:
normal_fleet = getattr(self.config, f'Fleet_Fleet{task_fleet}', None)
try:
normal_fleet = int(normal_fleet)
except (TypeError, ValueError):
logger.warning(f'Invalid Fleet_Fleet{task_fleet}: {normal_fleet}')
continue
if 1 <= normal_fleet <= 6:
fleet_mapping[task_fleet] = normal_fleet
else:
logger.warning(f'Invalid Fleet_Fleet{task_fleet}: {normal_fleet}')

if not fleet_mapping:
logger.warning('No normal fleet configured for emotion dock calibration')
return False

logger.hr('Emotion dock calibration')
logger.info(f'Task `{command}` fleet mapping: {fleet_mapping}')

try:
from module.retire.dock import Dock
dock = Dock(config=self.config, device=self.device)
scanned = dock.scan_fleet_emotion(fleet_mapping.values())
except Exception as e:
logger.warning(f'Emotion dock calibration failed, keep current ledger: {e}')
return True

records = {}
for task_fleet, normal_fleet in fleet_mapping.items():
value = scanned.get(normal_fleet)
if value is None:
logger.warning(
f'No dock emotion result for task fleet {task_fleet} '
f'(normal fleet {normal_fleet}), keep current ledger'
)
continue
records[f'Emotion_Fleet{task_fleet}Value'] = value

if records:
logger.info(f'Sync emotion ledger from dock: {records}')
self.config.set_record(**records)
campaign_records = {}
for arg in records:
record = arg.replace('Value', 'Record')
campaign_records[arg] = getattr(self.config, arg)
campaign_records[record] = getattr(self.config, record)
self.campaign.config.override(**campaign_records)
self.campaign.emotion.update()
self.campaign.emotion.show()
else:
logger.warning('Emotion dock calibration produced no usable records')

return True

def emotion_preflight_check(self):
"""
Delay current task immediately if emotion is below threshold.

Returns:
bool: If current task was delayed and should leave the run loop.
"""
if self.campaign.emotion.is_popup_only:
return False
try:
self.campaign.emotion.check_reduce(self.campaign._map_battle)
except ScriptEnd as e:
logger.hr('Script end')
logger.info(str(e))
return True
return False

def run(self, name, folder='campaign_main', mode='normal', total=0):
"""
Args:
Expand All @@ -375,9 +484,12 @@ def run(self, name, folder='campaign_main', mode='normal', total=0):
"""
name, folder = self.handle_stage_name(name, folder, mode=mode)
self.config.override(Campaign_Name=name, Campaign_Event=folder)
self.emotion_popup_only_set(name=name, folder=folder, log=False)
self.load_campaign(name, folder=folder)
self.emotion_popup_only_set(name=name, folder=folder)
self.run_count = 0
self.run_limit = self.config.StopCondition_RunCount
emotion_dock_calibration_checked = False
while 1:
# End
if total and self.run_count >= total:
Expand Down Expand Up @@ -416,6 +528,12 @@ def run(self, name, folder='campaign_main', mode='normal', total=0):
self.campaign.ensure_campaign_ui(name=self.stage, mode=mode)
self.disable_raid_on_event()
self.handle_commission_notice()
if not emotion_dock_calibration_checked:
emotion_dock_calibration_checked = True
if self.emotion_dock_calibrate():
self.campaign.ensure_campaign_ui(name=self.stage, mode=mode)
if self.emotion_preflight_check():
break

# if in hard mode, check remain times
if self.ui_page_appear(page_campaign) and MODE_SWITCH_1.get(main=self) == 'normal':
Expand Down
2 changes: 1 addition & 1 deletion module/combat/auto_search_combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def auto_search_combat(self, emotion_reduce=None, fleet_index=1):
Note that fleet index == 1 is mob fleet, 2 is boss fleet.
It's not the fleet index in fleet preparation or auto search setting.
"""
emotion_reduce = emotion_reduce if emotion_reduce is not None else self.emotion.is_calculate
emotion_reduce = emotion_reduce if emotion_reduce is not None else self.emotion.should_track

self.auto_search_combat_execute(emotion_reduce=emotion_reduce, fleet_index=fleet_index)
self.auto_search_combat_status()
Expand Down
4 changes: 2 additions & 2 deletions module/combat/combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def combat_preparation(self, balance_hp=False, emotion_reduce=False, auto='comba
continue
if self.handle_retirement():
continue
if self.handle_combat_low_emotion():
if self.handle_combat_low_emotion(fleet_index=fleet_index):
continue
if balance_hp and self.handle_emergency_repair_use():
continue
Expand Down Expand Up @@ -636,7 +636,7 @@ def combat(self, balance_hp=None, emotion_reduce=None, auto_mode=None, submarine
fleet_index (int): 1 or 2
"""
balance_hp = balance_hp if balance_hp is not None else self.config.HpControl_UseHpBalance
emotion_reduce = emotion_reduce if emotion_reduce is not None else self.emotion.is_calculate
emotion_reduce = emotion_reduce if emotion_reduce is not None else self.emotion.should_track
if auto_mode is None:
auto_mode = self.config.Fleet_Fleet1Mode if fleet_index == 1 else self.config.Fleet_Fleet2Mode
if submarine_mode is None:
Expand Down
64 changes: 63 additions & 1 deletion module/combat/emotion.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ def is_calculate(self):
def is_ignore(self):
return 'ignore' in self.config.Emotion_Mode

@property
def is_popup_only(self):
return getattr(self.config, 'Emotion_PopupOnly', False)

@property
def should_track(self):
return self.is_calculate and not self.is_popup_only

def update(self):
"""
Update emotion value. This should be called before doing anything.
Expand Down Expand Up @@ -204,6 +212,54 @@ def reduce_per_battle_before_entering(self):
else:
return 2

def _fleet_indexes(self, fleet_index=None):
try:
fleet_index = int(fleet_index)
except (TypeError, ValueError):
return [1, 2]

if fleet_index in [1, 2]:
return [fleet_index]
return [1, 2]

def reset_low_emotion(self, fleet_index=None):
"""
Reset emotion ledger after the game client reports low emotion.

Args:
fleet_index (int, None): 1 or 2. Unknown fleets reset both ledgers.

Returns:
list[FleetEmotion]: Fleets whose values were reset.
"""
indexes = self._fleet_indexes(fleet_index=fleet_index)
if len(indexes) > 1:
logger.warning('Unable to identify low-emotion fleet, reset both fleet ledgers')

logger.hr('Emotion control')
self.update()
fleets = [self.fleets[index - 1] for index in indexes]
for fleet in fleets:
fleet.current = max(fleet.limit - 1, 0)
logger.info(f'Reset emotion fleet {fleet.fleet} to {fleet.current}')

self.record()
self.show()
return fleets
Comment on lines +329 to +342

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不是,ai写的代码自己审一下啊,弹低心情就把心情设置为最大,那计算心情的意义是什么呢

设置为0,然后让 Emotion.wait() 在图内等待,然后等到下一场战斗的心情再继续,结束关卡之后等待下一把的预期心情消耗再进图

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

抱歉这个是我记错了,我记成心情40点以下就出现弹窗,所以max(fleet.limit - 1, 0)这设成出现弹窗就默认心情到了39点


def delay_after_low_emotion(self, fleet_index=None):
"""
Delay current task after backing out of the low-emotion sortie popup.

Raise:
ScriptEnd: Stop current task normally so scheduler can continue.
"""
fleets = self.reset_low_emotion(fleet_index=fleet_index)
recovered = max([fleet.get_recovered(expected_reduce=self.reduce_per_battle) for fleet in fleets])
logger.info(f'Delay current task until emotion recovers at {recovered}')
self.config.task_delay(target=recovered)
raise ScriptEnd('Emotion control')

def check_reduce(self, battle):
"""
Check emotion before entering a campaign.
Expand All @@ -214,7 +270,7 @@ def check_reduce(self, battle):
Raise:
ScriptEnd: Delay current task to prevent emotion control in the future.
"""
if not self.is_calculate:
if not self.should_track:
return

method = self.config.Fleet_FleetOrder
Expand Down Expand Up @@ -250,6 +306,9 @@ def wait(self, fleet_index):
Args:
fleet_index (int): 1 or 2.
"""
if not self.should_track:
return

self.update()
self.record()
self.show()
Expand All @@ -275,6 +334,9 @@ def reduce(self, fleet_index):
Args:
fleet_index (int): 1 or 2.
"""
if not self.should_track:
return

logger.hr('Emotion reduce')
self.update()

Expand Down
2 changes: 1 addition & 1 deletion module/event_hospital/combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def check_coin():
check_coin()
if self.handle_retirement():
continue
if self.handle_combat_low_emotion():
if self.handle_combat_low_emotion(fleet_index=fleet_index):
continue
if self.appear_then_click(BATTLE_PREPARATION, offset=(30, 20), interval=2):
continue
Expand Down
16 changes: 12 additions & 4 deletions module/handler/info_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def handle_popup_cancel(self, name='', offset=None, interval=2):
return True
if self.appear(POPUP_CANCEL_WHITE, offset=offset, interval=interval):
POPUP_CANCEL_WHITE.name = POPUP_CANCEL_WHITE.name + '_' + name
self.device.click(POPUP_CONFIRM_WHITE)
self.device.click(POPUP_CANCEL_WHITE)
POPUP_CANCEL_WHITE.name = POPUP_CANCEL_WHITE.name[:-len(name) - 1]
return True
return False
Expand Down Expand Up @@ -184,14 +184,22 @@ def handle_urgent_commission(self, drop=None):

return appear

def handle_combat_low_emotion(self):
if not self.emotion.is_ignore:
def handle_combat_low_emotion(self, fleet_index=None):
if self.emotion.is_ignore:
result = self.handle_popup_confirm('IGNORE_LOW_EMOTION')
if result:
# Avoid clicking AUTO_SEARCH_MAP_OPTION_OFF
self.interval_reset(AUTO_SEARCH_MAP_OPTION_OFF)
return result

if not self.emotion.is_calculate:
return False

result = self.handle_popup_confirm('IGNORE_LOW_EMOTION')
result = self.handle_popup_cancel('LOW_EMOTION_CONTROL')
if result:
# Avoid clicking AUTO_SEARCH_MAP_OPTION_OFF
self.interval_reset(AUTO_SEARCH_MAP_OPTION_OFF)
self.emotion.delay_after_low_emotion(fleet_index=fleet_index)
return result

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle 系方法不应该有修改配置文件的行为


def handle_use_data_key(self):
Expand Down
4 changes: 2 additions & 2 deletions module/map/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def clear_chosen_enemy(self, grid, expected=''):
expected = f'combat_{expected}' if expected else 'combat'
battle_count = self.battle_count
self.show_fleet()
if self.emotion.is_calculate and self.config.Campaign_UseFleetLock:
if self.emotion.should_track and self.config.Campaign_UseFleetLock:
self.emotion.wait(fleet_index=self.fleet_current_index)
self.goto(grid, expected=expected)

Expand Down Expand Up @@ -728,7 +728,7 @@ def clear_bouncing_enemy(self):
self.show_fleet()
prev = self.battle_count
for n, grid in enumerate(itertools.cycle(route)):
if self.emotion.is_calculate and self.config.Campaign_UseFleetLock:
if self.emotion.should_track and self.config.Campaign_UseFleetLock:
self.emotion.wait(fleet_index=self.fleet_current_index)
self.goto(grid, expected='combat_nothing')

Expand Down
Loading