0
0
mirror of https://github.com/ok-oldking/ok-wuthering-waves.git synced 2025-04-24 08:25:16 +00:00

修复95版本自动战斗报错

This commit is contained in:
firedcto@gmail.com 2025-04-16 13:42:56 +08:00
parent b27e0de3e4
commit 2c23e3a268
2 changed files with 90 additions and 234 deletions

View File

@ -1,234 +0,0 @@
import math
import re
import time
import cv2
import numpy as np
from qfluentwidgets import FluentIcon
from ok import Logger
from src.task.BaseCombatTask import BaseCombatTask
from src.task.WWOneTimeTask import WWOneTimeTask
logger = Logger.get_logger(__name__)
class Farm13CTask(WWOneTimeTask, BaseCombatTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.icon = FluentIcon.FLAG
self.description = "Farm selected Tacet Suppression until out of stamina, will use the backup stamina, you need to be able to teleport from the menu(F2)"
self.name = "Tacet Suppression (Must explore first to be able to teleport)"
default_config = {
'Which Tacet Suppression to Farm': 1 # starts with 1
}
self.row_per_page = 5
self.total_number = 11
default_config.update(self.default_config)
self.config_description = {
'Which Tacet Suppression to Farm': 'the Nth number in the Tacet Suppression list (F2)',
}
self.default_config = default_config
self.max_star_distance = 1000
self.last_star = None
self.last_angle = None
self.stuck_keys = [['space', 0.2], ['a',2], ['d',2]]
self.stuck_index = 0
self.last_cords = None
self.cords_re = re.compile('^\d+,\d+,\d+$')
@property
def star_move_distance_threshold(self):
return self.height_of_screen(0.005)
def run(self):
self.last_star = None
self.last_angle = None
while True:
echos = self.yolo_find_all()
self.draw_boxes("yolo", echos)
self.sleep(0.1)
def get_cords(self):
cords = self.ocr(0.01, 0.95, 0.21, 1, match=self.cords_re, log=True)
if cords:
return cords[0].name
def get_angle(self):
arrow_template = self.get_feature_by_name('arrow')
original_mat = arrow_template.mat
max_conf = 0
max_angle = 0
max_target = None
max_mat = None
(h, w) = arrow_template.mat.shape[:2]
# self.log_debug(f'turn_east h:{h} w:{w}')
center = (w // 2, h // 2)
target_box = self.get_box_by_name('box_arrow')
# if self.debug:
# self.screenshot('arrow_original', original_ mat)
for angle in range(0, 360):
# Rotate the template image
rotation_matrix = cv2.getRotationMatrix2D(center, -angle, 1.0)
arrow_template.mat = cv2.warpAffine(original_mat, rotation_matrix, (w, h))
arrow_template.mask = np.where(np.all(arrow_template.mat == [0, 0, 0], axis=2), 0, 255).astype(np.uint8)
target = self.find_one(f'arrow_{angle}', box=target_box,
template=arrow_template, threshold=0.01)
# if self.debug and angle % 90 == 0:
# self.screenshot(f'arrow_rotated_{angle}', arrow_template.mat)
if target and target.confidence > max_conf:
max_conf = target.confidence
max_angle = angle
max_target = target
max_mat = arrow_template.mat
arrow_template.mat = original_mat
# arrow_template.mask = None
# if self.debug and max_mat is not None:
# self.screenshot('max_mat',frame=max_mat)
# self.log_debug(f'turn_east max_conf: {max_conf} {max_angle}')
return max_angle , max_target
def find_next_star(self):
stars = self.find_stars()
min_distance = self.max_star_distance
nearest_star = None
x2, y2 = self.get_box_by_name('box_minimap').center()
for star in stars:
if not self.last_star:
x1, y1 = star.center()
angle = calculate_angle_clockwise(x1, y1, x2, y2)
if self.last_angle is not None and abs(angle - self.last_angle) < 90:
self.log_debug(f'old path continue {abs(angle - self.last_angle)} {star}')
continue
self.last_star = star
self.log_debug(f'no last star return nearest {self.last_star} {self.last_angle}')
return -1, star
distance = star.center_distance(self.last_star)
if distance < min_distance:
min_distance = distance
nearest_star = star
if nearest_star:
self.last_star = nearest_star
self.log_debug(f'nearest_star: {min_distance} {nearest_star}')
return min_distance, nearest_star
def go_to_star(self):
current_direction = None
self.center_camera()
while True:
self.sleep(0.01)
if self.in_combat():
if current_direction is not None:
self.mouse_up(key='right')
self.send_key_up(current_direction)
current_direction = None
self.combat_once()
while self.yolo_find_echo(use_color=False, walk=False)[1]:
self.sleep(0.5)
cords = self.get_cords()
if cords and cords == self.last_cords:
logger.info(f'might be stuck, try jump')
self.send_key(self.stuck_keys[self.stuck_index % 3][0], down_time=self.stuck_keys[self.stuck_index % 3][1], after_sleep=0.5)
self.stuck_index += 1
continue
self.last_cords = cords
stars = self.find_stars()
if not stars:
self.log_info('cannot find any stars, stop farming', notify=True)
break
star = stars[0]
angle = self.get_angle_to_star(star)
if current_direction == 'w':
if 4 <= angle <= 90:
minor_adjust = 'd'
elif -90 <= angle <= -4:
minor_adjust = 'a'
else:
minor_adjust = None
if minor_adjust:
# if self.debug:
# self.screenshot(f'minor_adjust_{minor_adjust}_{angle}')
self.log_info(f'minor_adjust to {minor_adjust}_{angle}')
self.send_key_down(minor_adjust)
# self.center_camera()
self.sleep(0.3)
self.send_key_up(minor_adjust)
continue
if -45 <= angle <= 45:
new_direction = 'w'
elif 45 < angle <= 135:
new_direction = 'd'
elif -135 < angle <= -45:
new_direction = 'a'
else:
new_direction = 's'
if current_direction != new_direction:
self.log_info(f'changed direction {angle} {current_direction} -> {new_direction}')
if self.debug:
self.screenshot(f'{current_direction}_{new_direction}_{angle}')
if current_direction:
self.send_key_up(current_direction)
self.sleep(0.2)
self.turn_direction(new_direction)
self.send_key_down('w')
self.sleep(0.2)
self.mouse_down(key='right')
current_direction = 'w'
self.sleep(1)
if current_direction is not None:
self.mouse_up(key='right')
self.send_key_up(current_direction)
def get_angle_to_star(self, star):
x1, y1 = self.get_box_by_name('box_minimap').center()
x2, y2 = star.center()
target_angle = calculate_angle_clockwise(x1, y1, x2, y2)
my_angle = self.get_angle()[0]
if my_angle >= target_angle:
turn_angle = -(my_angle - target_angle)
else:
turn_angle = target_angle - my_angle
if turn_angle > 180:
turn_angle = 360 - turn_angle
if turn_angle < -180:
turn_angle = 360 + turn_angle
logger.debug(f'go to turn_angle {my_angle} {target_angle} {turn_angle}')
return turn_angle
def find_stars(self):
box_minimap = self.get_box_by_name('box_minimap')
stars = self.find_feature('star', threshold=0.5, box=box_minimap)
sorted_stars = sorted(stars, key=lambda star: - box_minimap.center_distance(star))
# if self.debug:
# self.screenshot('starts', show_box=True)
# self.screenshot('stars_mask', frame=mask_star(self.frame), show_box=True)
return sorted_stars
def calculate_angle_clockwise(x1, y1, x2, y2):
"""
Calculates angle (radians) from horizontal right to line (x1,y1)->(x2,y2).
Positive clockwise, negative counter-clockwise.
"""
dx = x2 - x1
dy = y2 - y1
# math.atan2(dy, dx) gives angle from positive x-axis, positive CCW.
# Negate for positive CW convention.
return math.degrees(math.atan2(dy, dx))
star_color = {
'r': (190, 220), # Red range
'g': (190, 220), # Green range
'b': (190, 220) # Blue range
}
def mask_star(image):
# return image
return create_color_mask(image, star_color)
def create_color_mask(image, color_ranges):
mask = cv2.inRange(image, (color_ranges['b'][0], color_ranges['g'][0], color_ranges['r'][0]), (color_ranges['b'][1], color_ranges['g'][1], color_ranges['r'][1]))
return mask

90
src/task/FarmEchoTask.py Normal file
View File

@ -0,0 +1,90 @@
import time
from qfluentwidgets import FluentIcon
from ok import Logger
from src.task.BaseCombatTask import BaseCombatTask
from src.task.WWOneTimeTask import WWOneTimeTask
logger = Logger.get_logger(__name__)
class FarmEchoTask(WWOneTimeTask, BaseCombatTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.description = "Click Start in Game World"
self.name = "Farm Echo in Dungeon"
self.default_config.update({
'Level': 1,
'Repeat Farm Count': 100,
'Boss': 'Dreamless'
})
self.config_description = {
'Level': '(1-6) Important, Choose which level to farm, lower levels might not produce a echo'
}
self.config_type["Boss"] = {'type': "drop_down", 'options': ['Hecate', 'Dreamless', 'Jue', 'Fleurdelys']}
self.icon = FluentIcon.ALBUM
self.add_exit_after_config()
def run(self):
WWOneTimeTask.run(self)
self.set_check_monthly_card()
self.ensure_main(time_out=180)
if not self.in_team()[0]:
self.log_error('must be in game world and in teams, please check you game resolution is 16:9', notify=True)
return
# loop here
count = 0
self.teleport_to_boss(self.config.get('Boss'))
self.sleep(1)
self.walk_until_f(time_out=10,
raise_if_not_found=True)
logger.info(f'enter success')
challenge = self.wait_feature('gray_button_challenge', raise_if_not_found=True)
logger.info(f'found challenge {challenge}')
self.sleep(1)
self.choose_level(self.config.get("Level"))
while count < self.config.get("Repeat Farm Count", 0):
count += 1
self.wait_in_team_and_world(time_out=20)
self.sleep(1)
self.combat_once()
logger.info(f'farm echo move {self.config.get("Boss")} yolo_find_echo')
dropped = self.yolo_find_echo()[0]
self.incr_drop(dropped)
self.sleep(0.5)
self.send_key('esc', after_sleep=0.5)
self.wait_click_feature('confirm_btn_hcenter_vcenter', relative_x=-1, raise_if_not_found=True,
post_action=lambda: self.send_key('esc', after_sleep=1),
settle_time=2)
self.wait_in_team_and_world(time_out=120)
self.sleep(2)
def choose_level(self, start):
y = 0.17
x = 0.15
distance = 0.08
logger.info(f'choose level {start}')
self.click_relative(x, y + (start - 1) * distance)
self.sleep(0.5)
self.wait_click_feature('gray_button_challenge', raise_if_not_found=True,
click_after_delay=0.5)
self.wait_click_feature('gray_confirm_exit_button', relative_x=-1, raise_if_not_found=False,
time_out=3, click_after_delay=0.5, threshold=0.8)
self.wait_click_feature('gray_start_battle', relative_x=-1, raise_if_not_found=True,
click_after_delay=0.5, threshold=0.8)
echo_color = {
'r': (200, 255), # Red range
'g': (150, 220), # Green range
'b': (130, 170) # Blue range
}