mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-26 18:20:42 +00:00
239590b2de
- 修复12-4打大型练级不挑敌人时, 会开局撤退的问题
151 lines
4.5 KiB
Python
151 lines
4.5 KiB
Python
import numpy as np
|
|
|
|
from module.base.base import ModuleBase
|
|
from module.base.button import color_similar
|
|
from module.logger import logger
|
|
|
|
# Location of six HP bar.
|
|
LOCATION = [
|
|
(36, 195),
|
|
(36, 295),
|
|
(36, 395),
|
|
(36, 497),
|
|
(36, 597),
|
|
(36, 697)
|
|
]
|
|
# HP bar size.
|
|
SIZE = (67, 4)
|
|
# Color that shows on HP bar.
|
|
COLOR_HP_GREEN = (156, 235, 57)
|
|
COLOR_HP_RED = (99, 44, 24)
|
|
SCOUT_POSITION = [
|
|
(403, 421),
|
|
(625, 369),
|
|
(821, 326)
|
|
]
|
|
|
|
|
|
class HPBalancer(ModuleBase):
|
|
hp = []
|
|
hp_record = []
|
|
_scout_order = (0, 1, 2)
|
|
|
|
def _calculate_hp(self, location, size):
|
|
"""Calculate hp according to color.
|
|
|
|
Args:
|
|
location (tuple): Upper right of HP bar. (x, y)
|
|
size (tuple): Size of HP bar. (x, y)
|
|
|
|
Returns:
|
|
float: HP.
|
|
"""
|
|
area = np.append(np.array(location), np.array(location) + np.array(size))
|
|
data = self.device.image.crop(area).resize((size[0], 1))
|
|
data = [
|
|
color_similar(pixel, COLOR_HP_GREEN) or color_similar(pixel, COLOR_HP_RED)
|
|
for pixel in np.array(data)[0]
|
|
]
|
|
data = np.sum(data) / size[0]
|
|
return data
|
|
|
|
def hp_get(self):
|
|
"""Get current HP from screenshot.
|
|
|
|
Returns:
|
|
list: HP(float) of 6 ship.
|
|
"""
|
|
hp = [self._calculate_hp(loca, SIZE) for loca in LOCATION]
|
|
scout = np.array(hp[3:]) * np.array(self.config.SCOUT_HP_WEIGHTS) / np.max(self.config.SCOUT_HP_WEIGHTS)
|
|
self.hp = hp[:3] + scout.tolist()
|
|
logger.attr('HP', ' '.join([str(int(data * 100)).rjust(3) + '%' for data in hp]))
|
|
if np.sum(np.abs(np.diff(self.config.SCOUT_HP_WEIGHTS))) > 0:
|
|
logger.attr('HP_weight', ' '.join([str(int(data * 100)).rjust(3) + '%' for data in self.hp]))
|
|
return self.hp
|
|
|
|
def hp_init(self):
|
|
self.hp_get()
|
|
self.hp_record = self.hp
|
|
return self.hp
|
|
|
|
def _scout_position_change(self, p1, p2):
|
|
"""Exchange KAN-SEN's position.
|
|
It need to move up and down a little, even though it moves to the right location.
|
|
|
|
Args:
|
|
p1 (int): Origin position [0, 2].
|
|
p2 (int): Target position [0, 2].
|
|
"""
|
|
logger.info('scout_position_change (%s, %s)' % (p1, p2))
|
|
self.device.drag(p1=SCOUT_POSITION[p1], p2=SCOUT_POSITION[p2], segments=3)
|
|
|
|
def _expected_scout_order(self, hp):
|
|
count = np.count_nonzero(hp)
|
|
threshold = self.config.SCOUT_HP_DIFFERENCE_THRESHOLD
|
|
|
|
if count == 3:
|
|
descending = np.sort(hp)[::-1]
|
|
sort = np.argsort(hp)[::-1]
|
|
if descending[0] - descending[2] > threshold:
|
|
if descending[1] - descending[2] > threshold:
|
|
# 100% 70% 40%
|
|
order = [sort[0], sort[2], sort[1]]
|
|
else:
|
|
# 100% 70% 60%
|
|
order = [sort[0], 1, 2]
|
|
order[sort[0]] = 0
|
|
else:
|
|
# 80% 80% 80%
|
|
order = [0, 1, 2]
|
|
elif count == 2:
|
|
if hp[1] - hp[0] > threshold:
|
|
# 70% 100% 0%
|
|
order = [1, 0, 2]
|
|
else:
|
|
# 100% 70% 0%
|
|
order = [0, 1, 2]
|
|
elif count == 1:
|
|
# 80% 0% 0%
|
|
order = [0, 1, 2]
|
|
else:
|
|
logger.warning(f'HP invalid: {hp}')
|
|
order = [0, 1, 2]
|
|
|
|
return order
|
|
|
|
@staticmethod
|
|
def _gen_exchange_step(origin, target):
|
|
diff = np.array(target) - np.array(origin)
|
|
count = np.count_nonzero(diff)
|
|
if count == 3:
|
|
yield (2, 0)
|
|
if np.argsort(target)[0] - np.argsort(origin)[0] == 1:
|
|
yield (2, 1)
|
|
else:
|
|
yield (1, 0)
|
|
elif count == 2:
|
|
yield tuple(np.nonzero(diff)[0])
|
|
elif count == 0:
|
|
# Target is the same as origin. Do nothing
|
|
pass
|
|
|
|
def hp_balance(self):
|
|
if self.config.ENABLE_MAP_FLEET_LOCK:
|
|
return False
|
|
|
|
target = self._expected_scout_order(self.hp[3:])
|
|
for step in self._gen_exchange_step(self._scout_order, target):
|
|
self._scout_position_change(*step)
|
|
self.device.sleep(0.5)
|
|
|
|
return True
|
|
|
|
def hp_withdraw_triggered(self):
|
|
if self.config.ENABLE_LOW_HP_WITHDRAW:
|
|
hp = np.array(self.hp)[np.array(self.hp_record) > 0.3]
|
|
if np.any(hp < self.config.LOW_HP_WITHDRAW_THRESHOLD):
|
|
logger.info('Low HP withdraw triggered.')
|
|
return True
|
|
|
|
return False
|