0
0
mirror of https://github.com/ok-oldking/ok-wuthering-waves.git synced 2025-06-07 09:25:34 +00:00
2024-06-22 23:13:59 +08:00

285 lines
10 KiB
Python

import time
from enum import IntEnum, StrEnum
from ok.color.Color import white_color, calculate_colorfulness
from ok.logging.Logger import get_logger
class Priority(IntEnum):
MIN = -999999999
SWITCH_CD = -1000
CURRENT_CHAR = -100
SKILL_AVAILABLE = 100
ALL_IN_CD = 0
NORMAL = 10
class Role(StrEnum):
DEFAULT = 'Default'
SUB_DPS = 'Sub DPS'
MAIN_DPS = 'Main DPS'
HEALER = 'Healer'
role_values = [role for role in Role]
char_lib_check_marks = ['char_1_lib_check_mark', 'char_2_lib_check_mark', 'char_3_lib_check_mark']
logger = get_logger(__name__)
class BaseChar:
def __init__(self, task, index, res_cd=0):
self.white_off_threshold = 0.01
self.task = task
self.sleep_adjust = 0.001
self.index = index
self.base_resonance_white_percentage = 0
self.base_echo_white_percentage = 0
self.base_liberation_white_percentage = 0
self.last_switch_time = -1
self.last_res = -1
self.has_intro = False
self.res_cd = res_cd
self.is_current_char = False
@property
def name(self):
return self.__class__.__name__
def __eq__(self, other):
if isinstance(other, BaseChar):
return self.name == other.name
return False
def perform(self):
# self.wait_down()
self.do_perform()
logger.debug(f'set current char false {self.index}')
def wait_down(self):
start = time.time()
while self.flying():
self.task.click()
self.sleep(0.05)
self.task.screenshot(
f'{self}_down_finish_{(time.time() - start):.2f}_f:{self.is_forte_full()}_e:{self.resonance_available()}_r:{self.echo_available()}_q:{self.liberation_available()}_i{self.has_intro}')
def do_perform(self):
self.click_liberation()
if self.resonance_available():
self.click_resonance()
self.sleep(0.1)
if self.echo_available():
self.click_echo()
self.sleep(0.1)
self.switch_next_char()
def __repr__(self):
return self.__class__.__name__ + ('_T' if self.is_current_char else '_F')
def switch_next_char(self, post_action=None):
self.last_switch_time = self.task.switch_next_char(self, post_action=post_action)
def sleep(self, sec):
self.task.sleep_check_combat(sec + self.sleep_adjust)
def click_resonance(self):
self.check_combat()
self.task.send_key(self.task.config.get('Resonance Key'))
while True:
curren_resonance = self.current_resonance()
if curren_resonance > 0 and abs(
curren_resonance - self.base_resonance_white_percentage) > self.white_off_threshold:
break
self.sleep(0.02)
self.task.click()
self.sleep(0.02)
self.task.send_key(self.task.config.get('Resonance Key'))
logger.info(f'{self} click resonance')
def update_res_cd(self):
current = time.time()
if current - self.last_res > self.res_cd: # count the first click only
self.last_res = time.time()
def click_echo(self):
self.check_combat()
self.task.send_key(self.get_echo_key())
while True:
current_echo = self.current_echo()
if current_echo > 0 and abs(
current_echo - self.base_echo_white_percentage) > self.white_off_threshold:
break
self.sleep(0.05)
self.task.send_key(self.get_echo_key())
logger.info(f'{self} click echo')
def check_combat(self):
self.task.check_combat()
def click_liberation(self, wait_end=True):
logger.info(f'click_liberation {self}')
self.check_combat()
self.task.in_liberation = True
self.task.send_key(self.get_liberation_key())
while self.liberation_available():
self.sleep(0.02)
self.task.send_key(self.get_liberation_key())
start = time.time()
while not self.task.in_team()[0]:
if start - time.time() > 5:
logger.info('too long a liberation, the boss was killed by the liberation')
self.task.reset_to_false()
from src.task.BaseCombatTask import NotInCombatException
raise NotInCombatException('not in combat')
self.sleep(0.02)
self.task.in_liberation = False
self.task.info[f'{self} liberation time'] = f'{(time.time() - start):.2f}'
def get_liberation_key(self):
return self.task.config['Liberation Key']
def get_echo_key(self):
return self.task.config['Echo Key']
def get_switch_priority(self, current_char, has_intro):
if time.time() - self.last_switch_time < 1:
return Priority.SWITCH_CD # switch cd
else:
return self.do_get_switch_priority(current_char, has_intro)
def do_get_switch_priority(self, current_char, has_intro=False):
priority = 0
if self.liberation_available():
priority += 1
if self.resonance_available():
priority += 1
if self.is_forte_full():
priority += 1
if priority > 0:
priority += Priority.SKILL_AVAILABLE
return priority
def resonance_available(self):
if self.is_current_char:
snap1 = self.current_resonance()
if snap1 == 0:
return False
if self.base_resonance_white_percentage != 0:
return abs(self.base_resonance_white_percentage - snap1) < self.white_off_threshold
cd_text = self.task.ocr(box=self.task.get_box_by_name('box_resonance'), target_height=540, threshold=0.95)
if len(cd_text) == 0 or not is_float(cd_text[0].name):
self.base_resonance_white_percentage = snap1
if self.task.debug:
self.task.screenshot(f'{self}_resonance_{snap1:.3f}')
logger.info(f'{self} set base resonance to {self.base_resonance_white_percentage:.3f}')
return True
if cd_text:
logger.info(f'{self} set base resonance to has text {cd_text}')
else:
if self.res_cd > 0:
return time.time() - self.last_res > self.res_cd
def echo_available(self):
snap1 = self.current_echo()
if snap1 == 0:
return False
if self.base_echo_white_percentage != 0:
return abs(self.base_echo_white_percentage - snap1) < self.white_off_threshold
cd_text = self.task.ocr(box=self.task.get_box_by_name('box_echo'), target_height=540, threshold=0.95)
if not cd_text or not is_float(cd_text[0].name):
self.base_echo_white_percentage = snap1
if self.task.debug:
self.task.screenshot(f'{self}_echo_{snap1:.3f}')
logger.info(f'set base resonance to {self.base_echo_white_percentage:.3f}')
return True
def is_con_full(self):
box = self.task.box_of_screen(1540 / 3840, 2007 / 2160, 1545 / 3840, 2010 / 2160, name='con_full')
colorfulness = calculate_colorfulness(self.task.frame, box)
box.confidence = colorfulness
self.task.draw_boxes('con_full', box)
if colorfulness > 0.1:
return True
def is_forte_full(self):
box = self.task.box_of_screen(2251 / 3840, 1993 / 2160, 2271 / 3840, 2016 / 2160, name='forte_full')
white_percent = self.task.calculate_color_percentage(forte_white_color, box)
box.confidence = white_percent
self.task.draw_boxes('forte_full', box)
if white_percent > 0.2:
return True
def liberation_available(self):
if self.is_current_char:
snap1_lib = self.current_liberation()
if snap1_lib == 0:
return False
if self.base_liberation_white_percentage != 0:
return abs(self.base_liberation_white_percentage - snap1_lib) < self.white_off_threshold
cd_text = self.task.ocr(box=self.task.get_box_by_name('box_liberation'), target_height=540, threshold=0.95)
if not cd_text or not is_float(cd_text[0].name):
self.base_liberation_white_percentage = snap1_lib
logger.info(f'{self} set base liberation to {self.base_liberation_white_percentage:.3f}')
if self.task.debug:
self.task.screenshot(f'{self}_liberation_{self.base_liberation_white_percentage:.3f}')
return True
else:
logger.debug(
f'{self} set base liberation {snap1_lib:.3f} has text {cd_text}')
else:
mark_to_check = char_lib_check_marks[self.index]
mark = self.task.find_one(mark_to_check, use_gray_scale=True)
if mark is not None:
logger.debug(f'{self.__repr__()} liberation ready by checking mark')
return True
def __str__(self):
return self.__repr__()
def normal_attack(self):
self.check_combat()
self.task.click()
def heavy_attack(self):
self.check_combat()
self.task.mouse_down()
self.sleep(0.6)
self.task.mouse_up()
def current_resonance(self):
return self.task.calculate_color_percentage(white_color,
self.task.get_box_by_name('box_resonance'))
def current_echo(self):
return self.task.calculate_color_percentage(white_color,
self.task.get_box_by_name('box_echo'))
def current_liberation(self):
return self.task.calculate_color_percentage(white_color, self.task.get_box_by_name('box_liberation'))
def flying(self):
return self.get_current_levitator() == 0
def get_current_levitator(self):
return self.task.calculate_color_percentage(white_color,
self.task.get_box_by_name('edge_levitator'))
forte_white_color = {
'r': (244, 255), # Red range
'g': (246, 255), # Green range
'b': (250, 255) # Blue range
}
def is_float(s):
try:
float(s)
return True
except ValueError:
return False