mirror of
https://github.com/ok-oldking/ok-wuthering-waves.git
synced 2025-06-03 09:25:19 +00:00
优化有时会提前跳出战斗的问题
This commit is contained in:
parent
c63210f119
commit
4bcb995306
@ -1,10 +1,6 @@
|
||||
import time
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from enum import IntEnum, StrEnum
|
||||
from ok.color.Color import color_range_to_bound
|
||||
from ok.config.Config import Config
|
||||
from ok.logging.Logger import get_logger
|
||||
from src import text_white_color
|
||||
@ -357,63 +353,11 @@ class BaseChar:
|
||||
return time.time() - self.last_echo > self.echo_cd
|
||||
|
||||
def is_con_full(self):
|
||||
return self.get_current_con() == 1
|
||||
return self.task.is_con_full()
|
||||
|
||||
def get_current_con(self):
|
||||
box = self.task.box_of_screen_scaled(3840, 2160, 1422, 1939, to_x=1566, to_y=2076, name='con_full',
|
||||
hcenter=True)
|
||||
box.confidence = 0
|
||||
|
||||
max_area = 0
|
||||
percent = 0
|
||||
max_is_full = False
|
||||
color_index = -1
|
||||
target_index = self.config.get('_ring_color_index', -1)
|
||||
cropped = box.crop_frame(self.task.frame)
|
||||
for i in range(len(con_colors)):
|
||||
if target_index != -1 and i != target_index:
|
||||
continue
|
||||
color_range = con_colors[i]
|
||||
area, is_full = self.count_rings(cropped, color_range,
|
||||
1500 / 3840 / 2160 * self.task.screen_width * self.task.screen_height)
|
||||
# self.logger.debug(f'is_con_full test color_range {color_range} {area, is_full}')
|
||||
if is_full:
|
||||
max_is_full = is_full
|
||||
color_index = i
|
||||
if area > max_area:
|
||||
max_area = int(area)
|
||||
if max_is_full:
|
||||
self.logger.info(
|
||||
f'is_con_full found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
|
||||
self.config['_full_ring_area'] = max_area
|
||||
self.config['_ring_color_index'] = color_index
|
||||
self.logger.info(
|
||||
f'is_con_full2 found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
|
||||
if self.config.get('_full_ring_area', 0) > 0:
|
||||
percent = max_area / self.config['_full_ring_area']
|
||||
if not max_is_full and percent >= 1:
|
||||
self.logger.warning(
|
||||
f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}')
|
||||
# self.task.screenshot(
|
||||
# f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}',
|
||||
# cropped)
|
||||
percent = 0.99
|
||||
if percent > 1:
|
||||
self.logger.error(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}')
|
||||
self.task.screenshot(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}', cropped)
|
||||
percent = 1
|
||||
# self.logger.info(
|
||||
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ')
|
||||
# if self.task.debug:
|
||||
# self.task.screenshot(
|
||||
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ',
|
||||
# cropped)
|
||||
box.confidence = percent
|
||||
self.current_con = percent
|
||||
self.task.draw_boxes(f'is_con_full_{self}', box)
|
||||
if percent > 1:
|
||||
percent = 1
|
||||
return percent
|
||||
self.current_con = self.task.get_current_con()
|
||||
return self.current_con
|
||||
|
||||
def is_forte_full(self):
|
||||
box = self.task.box_of_screen_scaled(3840, 2160, 2251, 1993, 2311, 2016, name='forte_full', hcenter=True)
|
||||
@ -443,17 +387,6 @@ class BaseChar:
|
||||
return False
|
||||
else:
|
||||
return self.is_available(snap, 'liberation')
|
||||
# else:
|
||||
# mark_to_check = char_lib_check_marks[self.index]
|
||||
# box = self.task.get_box_by_name(mark_to_check)
|
||||
# box = box.copy(x_offset=-box.width, y_offset=-box.height, width_offset=box.width * 2,
|
||||
# height_offset=box.height * 2)
|
||||
# for match in char_lib_check_marks:
|
||||
# mark = self.task.find_one(match, box=box, canny_lower=10, canny_higher=80, threshold=0.8)
|
||||
# if mark is not None:
|
||||
# self.logger.debug(f'{self.__repr__()} liberation ready by checking mark {mark}')
|
||||
# self.liberation_available_mark = True
|
||||
# return True
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
@ -495,77 +428,6 @@ class BaseChar:
|
||||
def flying(self):
|
||||
return self.current_resonance() == 0
|
||||
|
||||
def count_rings(self, image, color_range, min_area):
|
||||
# Define the color range
|
||||
lower_bound, upper_bound = color_range_to_bound(color_range)
|
||||
|
||||
image_with_contours = image.copy()
|
||||
|
||||
# Create a binary mask
|
||||
mask = cv2.inRange(image, lower_bound, upper_bound)
|
||||
|
||||
# Find connected components
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
|
||||
|
||||
colors = [
|
||||
(0, 255, 0), # Green
|
||||
(0, 0, 255), # Red
|
||||
(255, 0, 0), # Blue
|
||||
(0, 255, 255), # Yellow
|
||||
(255, 0, 255), # Magenta
|
||||
(255, 255, 0) # Cyan
|
||||
]
|
||||
|
||||
# Function to check if a component forms a ring
|
||||
def is_full_ring(component_mask):
|
||||
# Find contours
|
||||
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
if len(contours) != 1:
|
||||
return False
|
||||
contour = contours[0]
|
||||
|
||||
# Check if the contour is closed by checking if the start and end points are the same
|
||||
# if cv2.arcLength(contour, True) > 0:
|
||||
# return True
|
||||
# Approximate the contour with polygons.
|
||||
epsilon = 0.05 * cv2.arcLength(contour, True)
|
||||
approx = cv2.approxPolyDP(contour, epsilon, True)
|
||||
|
||||
# Check if the polygon is closed (has no gaps) and has a reasonable number of vertices for a ring.
|
||||
if not cv2.isContourConvex(approx) or len(approx) < 4:
|
||||
return False
|
||||
|
||||
# All conditions met, likely a close ring.
|
||||
return True
|
||||
|
||||
# Iterate over each component
|
||||
ring_count = 0
|
||||
is_full = False
|
||||
the_area = 0
|
||||
for label in range(1, num_labels):
|
||||
x, y, width, height, area = stats[label, :5]
|
||||
bounding_box_area = width * height
|
||||
component_mask = (labels == label).astype(np.uint8) * 255
|
||||
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
color = colors[label % len(colors)]
|
||||
cv2.drawContours(image_with_contours, contours, -1, color, 2)
|
||||
if bounding_box_area >= min_area:
|
||||
# Select a color from the list based on the label index
|
||||
if is_full_ring(component_mask):
|
||||
is_full = True
|
||||
the_area = area
|
||||
ring_count += 1
|
||||
|
||||
# if self.task.debug:
|
||||
# Save or display the image with contours
|
||||
# cv2.imwrite(f'test\\test_{self}_{is_full}_{the_area}_{lower_bound}.jpg', image_with_contours)
|
||||
if ring_count > 1:
|
||||
is_full = False
|
||||
the_area = 0
|
||||
self.logger.warning(f'is_con_full found multiple rings {ring_count}')
|
||||
|
||||
return the_area, is_full
|
||||
|
||||
|
||||
forte_white_color = {
|
||||
'r': (244, 255), # Red range
|
||||
@ -578,36 +440,3 @@ dot_color = {
|
||||
'g': (195, 255), # Green range
|
||||
'b': (195, 255) # Blue range
|
||||
}
|
||||
|
||||
con_colors = [
|
||||
{
|
||||
'r': (205, 235),
|
||||
'g': (190, 222), # for yellow spectro
|
||||
'b': (90, 130)
|
||||
},
|
||||
{
|
||||
'r': (150, 190), # Red range
|
||||
'g': (95, 140), # Green range for purple electric
|
||||
'b': (210, 249) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (200, 230), # Red range
|
||||
'g': (100, 130), # Green range for red fire
|
||||
'b': (75, 105) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (60, 95), # Red range
|
||||
'g': (150, 180), # Green range for blue ice
|
||||
'b': (210, 245) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (70, 110), # Red range
|
||||
'g': (215, 250), # Green range for green wind
|
||||
'b': (155, 190) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (190, 220), # Red range
|
||||
'g': (65, 105), # Green range for havoc
|
||||
'b': (145, 175) # Blue range
|
||||
}
|
||||
]
|
||||
|
@ -44,16 +44,15 @@ class CombatCheck:
|
||||
if is_pure_black(self.frame):
|
||||
logger.error('getting a pure black frame for unknown reason, reset_to_false return true')
|
||||
return True
|
||||
if recheck and time.time() - self.last_out_of_combat_time > 2.1:
|
||||
if recheck:
|
||||
logger.info('out of combat start double check')
|
||||
if self.debug:
|
||||
self.screenshot('out of combat start double check')
|
||||
self.last_out_of_combat_time = time.time()
|
||||
return True
|
||||
else:
|
||||
self.out_of_combat_reason = reason
|
||||
self.do_reset_to_false()
|
||||
return False
|
||||
if self.wait_until(self.check_health_bar, time_out=1.2, wait_until_before_delay=0):
|
||||
return True
|
||||
self.out_of_combat_reason = reason
|
||||
self.do_reset_to_false()
|
||||
return False
|
||||
|
||||
def do_reset_to_false(self):
|
||||
self._in_combat = False
|
||||
@ -102,6 +101,8 @@ class CombatCheck:
|
||||
if self.boss_lv_box is not None:
|
||||
current = self.boss_lv_box.crop_frame(self.frame)
|
||||
else:
|
||||
self.boss_lv_template = None
|
||||
self.boss_lv_box = None
|
||||
current = None
|
||||
max_val = 0
|
||||
if current is not None:
|
||||
@ -160,22 +161,21 @@ class CombatCheck:
|
||||
if now - self.last_combat_check > self.combat_check_interval:
|
||||
self.last_combat_check = now
|
||||
if check_team and not self.in_team()[0]:
|
||||
logger.info('not in team break out of combat')
|
||||
return self.reset_to_false(recheck=False, reason="not in team")
|
||||
if self.check_count_down():
|
||||
return True
|
||||
if self.boss_lv_template is not None:
|
||||
if self.wait_until(self.check_boss, time_out=2, wait_until_before_delay=0):
|
||||
if self.check_boss():
|
||||
return True
|
||||
else:
|
||||
return self.reset_to_false(recheck=False, reason="boss disappear")
|
||||
if self.check_health_bar():
|
||||
return True
|
||||
if self.ocr_lv_text():
|
||||
return True
|
||||
if self.target_enemy():
|
||||
return True
|
||||
logger.error('target_enemy failed, break out of combat')
|
||||
return self.reset_to_false(reason='target enemy failed')
|
||||
logger.error('target_enemy failed, try recheck break out of combat')
|
||||
return self.reset_to_false(recheck=True, reason='target enemy failed')
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
|
@ -1,10 +1,12 @@
|
||||
import math
|
||||
import time
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import win32api
|
||||
|
||||
import re
|
||||
from ok.color.Color import get_connected_area_by_color
|
||||
from ok.color.Color import get_connected_area_by_color, color_range_to_bound
|
||||
from ok.config.ConfigOption import ConfigOption
|
||||
from ok.feature.FindFeature import FindFeature
|
||||
from ok.logging.Logger import get_logger
|
||||
@ -347,6 +349,63 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
|
||||
def get_resonance_percentage(self):
|
||||
return self.calculate_color_percentage(white_color, self.get_box_by_name('box_resonance'))
|
||||
|
||||
def is_con_full(self):
|
||||
return self.get_current_con() == 1
|
||||
|
||||
def get_current_con(self):
|
||||
box = self.box_of_screen_scaled(3840, 2160, 1422, 1939, to_x=1566, to_y=2076, name='con_full',
|
||||
hcenter=True)
|
||||
box.confidence = 0
|
||||
|
||||
max_area = 0
|
||||
percent = 0
|
||||
max_is_full = False
|
||||
color_index = -1
|
||||
target_index = self.config.get('_ring_color_index', -1)
|
||||
cropped = box.crop_frame(self.frame)
|
||||
for i in range(len(con_colors)):
|
||||
if target_index != -1 and i != target_index:
|
||||
continue
|
||||
color_range = con_colors[i]
|
||||
area, is_full = self.count_rings(cropped, color_range,
|
||||
1500 / 3840 / 2160 * self.screen_width * self.screen_height)
|
||||
# self.logger.debug(f'is_con_full test color_range {color_range} {area, is_full}')
|
||||
if is_full:
|
||||
max_is_full = is_full
|
||||
color_index = i
|
||||
if area > max_area:
|
||||
max_area = int(area)
|
||||
if max_is_full:
|
||||
self.logger.info(
|
||||
f'is_con_full found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
|
||||
self.config['_full_ring_area'] = max_area
|
||||
self.config['_ring_color_index'] = color_index
|
||||
self.logger.info(
|
||||
f'is_con_full2 found a full ring {self.config.get("_full_ring_area", 0)} -> {max_area} {color_index}')
|
||||
if self.config.get('_full_ring_area', 0) > 0:
|
||||
percent = max_area / self.config['_full_ring_area']
|
||||
if not max_is_full and percent >= 1:
|
||||
self.logger.warning(
|
||||
f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}')
|
||||
# self.task.screenshot(
|
||||
# f'is_con_full not full but percent greater than 1, set to 0.99, {percent} {max_is_full}',
|
||||
# cropped)
|
||||
percent = 0.99
|
||||
if percent > 1:
|
||||
self.logger.error(f'is_con_full percent greater than 1, set to 1, {percent} {max_is_full}')
|
||||
percent = 1
|
||||
# self.logger.info(
|
||||
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ')
|
||||
# if self.task.debug:
|
||||
# self.task.screenshot(
|
||||
# f'is_con_full {self} {percent} {max_area}/{self.config.get("_full_ring_area", 0)} {color_index} ',
|
||||
# cropped)
|
||||
box.confidence = percent
|
||||
self.draw_boxes(f'is_con_full_{self}', box)
|
||||
if percent > 1:
|
||||
percent = 1
|
||||
return percent
|
||||
|
||||
def in_team(self):
|
||||
start = time.time()
|
||||
c1 = self.find_one('char_1_text',
|
||||
@ -370,6 +429,8 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
|
||||
else:
|
||||
return False, -1, exist_count + 1
|
||||
|
||||
# Function to check if a component forms a ring
|
||||
|
||||
def mouse_reset(self):
|
||||
# logger.debug("mouse_reset")
|
||||
try:
|
||||
@ -392,9 +453,112 @@ class BaseCombatTask(BaseWWTask, FindFeature, OCR, CombatCheck):
|
||||
except Exception as e:
|
||||
logger.error('mouse_reset exception', e)
|
||||
|
||||
def count_rings(self, image, color_range, min_area):
|
||||
# Define the color range
|
||||
lower_bound, upper_bound = color_range_to_bound(color_range)
|
||||
|
||||
image_with_contours = image.copy()
|
||||
|
||||
# Create a binary mask
|
||||
mask = cv2.inRange(image, lower_bound, upper_bound)
|
||||
|
||||
# Find connected components
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
|
||||
|
||||
colors = [
|
||||
(0, 255, 0), # Green
|
||||
(0, 0, 255), # Red
|
||||
(255, 0, 0), # Blue
|
||||
(0, 255, 255), # Yellow
|
||||
(255, 0, 255), # Magenta
|
||||
(255, 255, 0) # Cyan
|
||||
]
|
||||
|
||||
# Function to check if a component forms a ring
|
||||
def is_full_ring(component_mask):
|
||||
# Find contours
|
||||
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
if len(contours) != 1:
|
||||
return False
|
||||
contour = contours[0]
|
||||
|
||||
# Check if the contour is closed by checking if the start and end points are the same
|
||||
# if cv2.arcLength(contour, True) > 0:
|
||||
# return True
|
||||
# Approximate the contour with polygons.
|
||||
epsilon = 0.05 * cv2.arcLength(contour, True)
|
||||
approx = cv2.approxPolyDP(contour, epsilon, True)
|
||||
|
||||
# Check if the polygon is closed (has no gaps) and has a reasonable number of vertices for a ring.
|
||||
if not cv2.isContourConvex(approx) or len(approx) < 4:
|
||||
return False
|
||||
|
||||
# All conditions met, likely a close ring.
|
||||
return True
|
||||
|
||||
# Iterate over each component
|
||||
ring_count = 0
|
||||
is_full = False
|
||||
the_area = 0
|
||||
for label in range(1, num_labels):
|
||||
x, y, width, height, area = stats[label, :5]
|
||||
bounding_box_area = width * height
|
||||
component_mask = (labels == label).astype(np.uint8) * 255
|
||||
contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
color = colors[label % len(colors)]
|
||||
cv2.drawContours(image_with_contours, contours, -1, color, 2)
|
||||
if bounding_box_area >= min_area:
|
||||
# Select a color from the list based on the label index
|
||||
if is_full_ring(component_mask):
|
||||
is_full = True
|
||||
the_area = area
|
||||
ring_count += 1
|
||||
|
||||
# Save or display the image with contours
|
||||
# cv2.imwrite(f'test\\test_{self}_{is_full}_{the_area}_{lower_bound}.jpg', image_with_contours)
|
||||
if ring_count > 1:
|
||||
is_full = False
|
||||
the_area = 0
|
||||
self.logger.warning(f'is_con_full found multiple rings {ring_count}')
|
||||
|
||||
return the_area, is_full
|
||||
|
||||
|
||||
white_color = {
|
||||
'r': (253, 255), # Red range
|
||||
'g': (253, 255), # Green range
|
||||
'b': (253, 255) # Blue range
|
||||
}
|
||||
|
||||
con_colors = [
|
||||
{
|
||||
'r': (205, 235),
|
||||
'g': (190, 222), # for yellow spectro
|
||||
'b': (90, 130)
|
||||
},
|
||||
{
|
||||
'r': (150, 190), # Red range
|
||||
'g': (95, 140), # Green range for purple electric
|
||||
'b': (210, 249) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (200, 230), # Red range
|
||||
'g': (100, 130), # Green range for red fire
|
||||
'b': (75, 105) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (60, 95), # Red range
|
||||
'g': (150, 180), # Green range for blue ice
|
||||
'b': (210, 245) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (70, 110), # Red range
|
||||
'g': (215, 250), # Green range for green wind
|
||||
'b': (155, 190) # Blue range
|
||||
},
|
||||
{
|
||||
'r': (190, 220), # Red range
|
||||
'g': (65, 105), # Green range for havoc
|
||||
'b': (145, 175) # Blue range
|
||||
}
|
||||
]
|
||||
|
@ -35,13 +35,31 @@ class IllusiveRealmTask(BaseCombatTask):
|
||||
self.click()
|
||||
else:
|
||||
if self.available('liberation'):
|
||||
self.send_key(self.get_liberation_key())
|
||||
self.send_key_and_wait_animation(self.get_liberation_key())
|
||||
elif self.available('echo'):
|
||||
self.send_key(self.get_echo_key())
|
||||
elif self.available('resonance'):
|
||||
self.send_key(self.get_resonance_key())
|
||||
self.last_is_click = not self.last_is_click
|
||||
|
||||
def send_key_and_wait_animation(self, key, total_wait=10, animation_wait=5):
|
||||
start = time.time()
|
||||
animation_start = 0
|
||||
while time.time() - start < total_wait and (
|
||||
animation_start == 0 or time.time() - animation_start < animation_wait):
|
||||
if self.in_realm() or self.in_team()[0]:
|
||||
if animation_start > 0:
|
||||
self.in_liberation = False
|
||||
return
|
||||
else:
|
||||
self.send_key(key, interval=0.2)
|
||||
else:
|
||||
if animation_start == 0:
|
||||
animation_start = time.time()
|
||||
self.in_liberation = True
|
||||
self.next_frame()
|
||||
logger.info(f'send_key_and_wait_animation timed out {key}')
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
start = time.time()
|
||||
|
Loading…
x
Reference in New Issue
Block a user