Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
35 changes: 35 additions & 0 deletions module/base/emotion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""心情恢复的共享规则和纯计算函数。"""

SECONDS_PER_TICK = 6 * 60

DIC_RECOVER = {
'not_in_dormitory': 20,
'dormitory_floor_1': 40,
'dormitory_floor_2': 50,
}
DIC_RECOVER_MAX = {
'not_in_dormitory': 119,
'dormitory_floor_1': 150,
'dormitory_floor_2': 150,
}
OATH_RECOVER = 10
ONSEN_RECOVER = 10


def emotion_recovery_speed(recover, oath=False, onsen=False):
"""返回每个 6 分钟周期恢复的心情点数。"""
speed = DIC_RECOVER[recover]
if oath:
speed += OATH_RECOVER
if onsen:
speed += ONSEN_RECOVER
return speed // 10


def calculate_emotion_recovery(value, recover, elapsed, oath=False, onsen=False):
"""根据经过秒数返回当前心情值和未满一点的恢复余数。"""
speed = emotion_recovery_speed(recover, oath=oath, onsen=onsen)
recovery = speed * max(elapsed, 0) / SECONDS_PER_TICK
recovered_points = int(recovery)
current = min(max(int(value), 0) + recovered_points, DIC_RECOVER_MAX[recover])
return current, recovery - recovered_points
53 changes: 20 additions & 33 deletions module/combat/emotion.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@
游戏客户端存在已知 bug:长时间运行后情绪计算不准确,需要定期重启。
"""

from datetime import datetime, timedelta
from datetime import timedelta
from time import sleep

import numpy as np

from module.base.decorator import cached_property
from module.base.emotion import (
DIC_RECOVER_MAX,
SECONDS_PER_TICK,
calculate_emotion_recovery,
emotion_recovery_speed,
)
from module.base.utils import random_normal_distribution_int
from module.config.config import AzurLaneConfig
from module.config.time_source import now as current_time
from module.exception import ScriptEnd, ScriptError, RequestHumanTakeover
from module.logger import logger
Expand All @@ -36,22 +41,6 @@
'prevent_yellow_face': 30, # 防止黄脸
'prevent_red_face': 2, # 防止红脸
}
# 情绪恢复速度:每 6 分钟恢复的点数
DIC_RECOVER = {
'not_in_dormitory': 20, # 港区休息
'dormitory_floor_1': 40, # 后宅一楼
'dormitory_floor_2': 50, # 后宅二楼
}
# 情绪上限
DIC_RECOVER_MAX = {
'not_in_dormitory': 119,
'dormitory_floor_1': 150,
'dormitory_floor_2': 150,
}
OATH_RECOVER = 10 # 誓约额外恢复速度
ONSEN_RECOVER = 10 # 温泉额外恢复速度


class FleetEmotion:
"""单个舰队的情绪追踪器。

Expand Down Expand Up @@ -142,12 +131,7 @@ def speed(self):
Returns:
int: 每 6 分钟的恢复速度。
"""
speed = DIC_RECOVER[self.recover]
if self.oath:
speed += OATH_RECOVER
if self.onsen:
speed += ONSEN_RECOVER
return speed // 10
return emotion_recovery_speed(self.recover, self.oath, self.onsen)

@property
def limit(self):
Expand Down Expand Up @@ -176,12 +160,15 @@ def update(self):
符合情绪控制的安全方向(宁可低估也不高估)。
"""
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)
self.current, fractional = calculate_emotion_recovery(
self.value,
self.recover,
time_diff,
oath=self.oath,
onsen=self.onsen,
)
# 保留未满1点的恢复余数对应的秒数,用于 record() 回扣
self._fractional_seconds = recovery - int(recovery)
self._fractional_seconds = fractional

def get_recovered(self, expected_reduce=0):
"""计算情绪恢复到控制阈值的时间。
Expand All @@ -205,8 +192,8 @@ def get_recovered(self, expected_reduce=0):
emotion_needed = self.limit + expected_reduce - self.current
if emotion_needed <= 0:
return current_time()
# speed 为每360秒的恢复量,换算恢复所需秒数
seconds_needed = emotion_needed * 360 / self.speed
# speed 为每个恢复周期的恢复量,换算恢复所需秒数
seconds_needed = emotion_needed * SECONDS_PER_TICK / self.speed
return current_time() + timedelta(seconds=seconds_needed)

class Emotion:
Expand Down Expand Up @@ -291,7 +278,7 @@ def record(self):
fractional = getattr(fleet, '_fractional_seconds', 0)
if fractional > 0:
# 回扣 fractional_seconds 对应的秒数
record_time = record_time - timedelta(seconds=fractional * 360 / fleet.speed)
record_time = record_time - timedelta(seconds=fractional * SECONDS_PER_TICK / 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)
Expand All @@ -303,7 +290,7 @@ def record(self):
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)
record_time = record_time - timedelta(seconds=fractional * SECONDS_PER_TICK / fleet.speed)
setattr(self.config, fleet.value_name, new_value)
setattr(self.config, fleet.value_name.replace('Value', 'Record'), record_time)

Expand Down
7 changes: 6 additions & 1 deletion module/config/config_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@
from deploy.utils import DEPLOY_TEMPLATE, poor_yaml_read, poor_yaml_write
from module.base.timer import timer
from module.config.deep import deep_default, deep_get, deep_iter, deep_set
from module.config.emotion_recovery import recover_emotion_config
from module.config.env import IS_ON_PHONE_CLOUD
from module.config.server import VALID_CHANNEL_PACKAGE, VALID_PACKAGE, VALID_SERVER_LIST, to_package, to_server
from module.config.task_priority import get_scheduler_tasks, merge_task_priority
from module.config.time_source import now as current_time
from module.config.utils import *
from module.config.redirect_utils.utils import *

Expand Down Expand Up @@ -706,11 +708,12 @@ class ConfigUpdater:
def args(self):
return read_file(filepath_args())

def config_update(self, old, is_template=False):
def config_update(self, old, is_template=False, now=None):
"""
Args:
old: 旧配置字典。
is_template: 是否为模板配置。
now: 用于刷新心情值的当前时间;测试可传入固定时间。

Returns:
更新后的配置字典。
Expand Down Expand Up @@ -804,6 +807,8 @@ def default_stage(t, stage):
merge_task_priority(new_priority, template_priority, get_scheduler_tasks(self.args)),
)
new = self._override(new)
if not is_template:
recover_emotion_config(new, now or current_time())

return new

Expand Down
71 changes: 71 additions & 0 deletions module/config/emotion_recovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""配置加载阶段的心情恢复计算。"""

from datetime import datetime, timedelta

from module.base.emotion import (
DIC_RECOVER,
DIC_RECOVER_MAX,
SECONDS_PER_TICK,
calculate_emotion_recovery,
emotion_recovery_speed,
)


def _recover_fleet(group, prefix, now):
value_key = f'{prefix}Value'
record_key = f'{prefix}Record'
recover_key = f'{prefix}Recover'
if value_key not in group or record_key not in group or recover_key not in group:
return

value = group[value_key]
record = group[record_key]
recover = group[recover_key]
if not isinstance(value, (int, float)) or not isinstance(record, datetime):
return
if recover not in DIC_RECOVER:
return

elapsed = now.timestamp() - record.timestamp()
if elapsed <= 0:
return

oath = bool(group.get(f'{prefix}Oath', False))
onsen = bool(group.get(f'{prefix}Onsen', False))
speed = emotion_recovery_speed(recover, oath=oath, onsen=onsen)
maximum = DIC_RECOVER_MAX[recover]
new_value, fractional = calculate_emotion_recovery(
value,
recover,
elapsed,
oath=oath,
onsen=onsen,
)

group[value_key] = new_value
if new_value >= maximum:
group[record_key] = now.replace(microsecond=0)
return

record_time = now.replace(microsecond=0)
if fractional > 0:
record_time -= timedelta(seconds=fractional * SECONDS_PER_TICK / speed)
group[record_key] = record_time


def recover_emotion_config(data, now):
"""把任务配置中的持久化心情更新到 ``now`` 对应的当前值。"""
for task in data.values():
if not isinstance(task, dict):
continue

emotion = task.get('Emotion')
if isinstance(emotion, dict):
_recover_fleet(emotion, 'Fleet1', now)
_recover_fleet(emotion, 'Fleet2', now)

public_emotion = task.get('PublicEmotion')
if isinstance(public_emotion, dict):
_recover_fleet(public_emotion, 'Fleet', now)

return data
Loading
Loading