Add: Use skills in combat
BIN
assets/share/combat/skill/CHECK_A.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/share/combat/skill/CHECK_E.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/share/combat/skill/IN_SKILL.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/share/combat/skill/USE_A.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
assets/share/combat/skill/USE_E.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/share/combat/skill/USE_Q1.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
assets/share/combat/skill/USE_Q2.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
assets/share/combat/skill/USE_Q3.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/share/combat/skill/USE_Q4.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/share/combat/skill/USE_Q_AIM.png
Normal file
After Width: | Height: | Size: 25 KiB |
105
tasks/combat/assets/assets_combat_skill.py
Normal file
@ -0,0 +1,105 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
CHECK_A = ButtonWrapper(
|
||||
name='CHECK_A',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/CHECK_A.png',
|
||||
area=(967, 513, 1087, 623),
|
||||
search=(947, 493, 1107, 643),
|
||||
color=(91, 91, 97),
|
||||
button=(967, 513, 1087, 623),
|
||||
),
|
||||
)
|
||||
CHECK_E = ButtonWrapper(
|
||||
name='CHECK_E',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/CHECK_E.png',
|
||||
area=(1111, 429, 1261, 519),
|
||||
search=(1091, 409, 1280, 539),
|
||||
color=(80, 81, 89),
|
||||
button=(1111, 429, 1261, 519),
|
||||
),
|
||||
)
|
||||
IN_SKILL = ButtonWrapper(
|
||||
name='IN_SKILL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/IN_SKILL.png',
|
||||
area=(35, 619, 59, 635),
|
||||
search=(15, 599, 79, 655),
|
||||
color=(106, 107, 110),
|
||||
button=(35, 619, 59, 635),
|
||||
),
|
||||
)
|
||||
USE_A = ButtonWrapper(
|
||||
name='USE_A',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_A.png',
|
||||
area=(1037, 579, 1097, 639),
|
||||
search=(1017, 559, 1117, 659),
|
||||
color=(107, 108, 111),
|
||||
button=(1037, 579, 1097, 639),
|
||||
),
|
||||
)
|
||||
USE_E = ButtonWrapper(
|
||||
name='USE_E',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_E.png',
|
||||
area=(1154, 490, 1214, 550),
|
||||
search=(1134, 470, 1234, 570),
|
||||
color=(120, 123, 127),
|
||||
button=(1154, 490, 1214, 550),
|
||||
),
|
||||
)
|
||||
USE_Q1 = ButtonWrapper(
|
||||
name='USE_Q1',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_Q1.png',
|
||||
area=(217, 548, 253, 578),
|
||||
search=(197, 528, 273, 598),
|
||||
color=(145, 151, 225),
|
||||
button=(217, 548, 253, 578),
|
||||
),
|
||||
)
|
||||
USE_Q2 = ButtonWrapper(
|
||||
name='USE_Q2',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_Q2.png',
|
||||
area=(405, 546, 441, 576),
|
||||
search=(385, 526, 461, 596),
|
||||
color=(155, 131, 207),
|
||||
button=(405, 546, 441, 576),
|
||||
),
|
||||
)
|
||||
USE_Q3 = ButtonWrapper(
|
||||
name='USE_Q3',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_Q3.png',
|
||||
area=(593, 545, 629, 575),
|
||||
search=(573, 525, 649, 595),
|
||||
color=(208, 208, 202),
|
||||
button=(593, 545, 629, 575),
|
||||
),
|
||||
)
|
||||
USE_Q4 = ButtonWrapper(
|
||||
name='USE_Q4',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_Q4.png',
|
||||
area=(781, 545, 817, 575),
|
||||
search=(761, 525, 837, 595),
|
||||
color=(151, 113, 206),
|
||||
button=(781, 545, 817, 575),
|
||||
),
|
||||
)
|
||||
USE_Q_AIM = ButtonWrapper(
|
||||
name='USE_Q_AIM',
|
||||
share=Button(
|
||||
file='./assets/share/combat/skill/USE_Q_AIM.png',
|
||||
area=(1074, 521, 1174, 621),
|
||||
search=(1054, 501, 1194, 641),
|
||||
color=(82, 60, 64),
|
||||
button=(1074, 521, 1174, 621),
|
||||
),
|
||||
)
|
@ -6,13 +6,14 @@ from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
|
||||
from tasks.combat.assets.assets_combat_team import COMBAT_TEAM_PREPARE, COMBAT_TEAM_SUPPORT
|
||||
from tasks.combat.interact import CombatInteract
|
||||
from tasks.combat.prepare import CombatPrepare
|
||||
from tasks.combat.skill import CombatSkill
|
||||
from tasks.combat.state import CombatState
|
||||
from tasks.combat.support import CombatSupport
|
||||
from tasks.combat.team import CombatTeam
|
||||
from tasks.map.control.joystick import MapControlJoystick
|
||||
|
||||
|
||||
class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSupport, MapControlJoystick):
|
||||
class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSupport, CombatSkill, MapControlJoystick):
|
||||
def handle_combat_prepare(self):
|
||||
"""
|
||||
Returns:
|
||||
|
126
tasks/combat/skill.py
Normal file
@ -0,0 +1,126 @@
|
||||
from module.base.button import match_template
|
||||
from module.base.timer import Timer
|
||||
from module.logger import logger
|
||||
from tasks.base.ui import UI
|
||||
from tasks.combat.assets.assets_combat_skill import *
|
||||
|
||||
|
||||
class CombatSkill(UI):
|
||||
def is_in_skill(self) -> bool:
|
||||
"""
|
||||
Combat paused, require manual skill use
|
||||
"""
|
||||
if not self.appear(IN_SKILL):
|
||||
return False
|
||||
|
||||
if not self.image_color_count(IN_SKILL, color=(255, 255, 255), threshold=221, count=50):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _skill_click(self, button, skip_first_screenshot=True):
|
||||
"""
|
||||
Click a skill button.
|
||||
Not in skill page means skill has been used and skill animation is ongoing
|
||||
"""
|
||||
logger.info(f'Skill use: {button}')
|
||||
interval = Timer(1)
|
||||
clicked = False
|
||||
prev_image = None
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.is_in_skill():
|
||||
if interval.reached():
|
||||
prev_image = self.image_crop(button)
|
||||
self.device.click(button)
|
||||
interval.reset()
|
||||
clicked = True
|
||||
continue
|
||||
else:
|
||||
# Skill animation on going
|
||||
if clicked:
|
||||
logger.info(f'Skill used: {button}')
|
||||
break
|
||||
# New skill icon
|
||||
if prev_image is not None:
|
||||
if not match_template(self.image_crop(button), prev_image):
|
||||
logger.info(f'Skill used: {button}')
|
||||
break
|
||||
|
||||
def _skill_switch(self, check_button, click_button, skip_first_screenshot=True):
|
||||
"""
|
||||
Switch to A or E
|
||||
"""
|
||||
logger.info(f'Skill switch: {check_button}')
|
||||
interval = Timer(1)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
# Raw brown border
|
||||
if self.image_color_count(check_button, color=(220, 196, 145), threshold=221, count=50):
|
||||
logger.info(f'Skill switched: {check_button}')
|
||||
break
|
||||
|
||||
if self.is_in_skill():
|
||||
if interval.reached():
|
||||
self.device.click(click_button)
|
||||
interval.reset()
|
||||
continue
|
||||
|
||||
def wait_next_skill(self, expected_end=None, skip_first_screenshot=True):
|
||||
"""
|
||||
Args:
|
||||
expected_end: A function returns bool, True represents end.
|
||||
skip_first_screenshot:
|
||||
|
||||
Returns:
|
||||
bool: True if is_in_skill
|
||||
False if triggered expected_end
|
||||
"""
|
||||
logger.info('Wait next skill')
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.is_in_skill():
|
||||
return True
|
||||
if callable(expected_end) and expected_end():
|
||||
logger.info(f'Combat execute ended at {expected_end.__name__}')
|
||||
return False
|
||||
|
||||
def use_A(self) -> bool:
|
||||
logger.hr('Use A')
|
||||
self._skill_switch(check_button=CHECK_A, click_button=USE_A)
|
||||
self._skill_click(USE_A)
|
||||
return True
|
||||
|
||||
def use_E(self) -> bool:
|
||||
logger.hr('Use E')
|
||||
self._skill_switch(check_button=CHECK_E, click_button=USE_E)
|
||||
self._skill_click(USE_E)
|
||||
return True
|
||||
|
||||
def use_Q(self, position: int) -> bool:
|
||||
"""
|
||||
Args:
|
||||
position: 1 to 4
|
||||
"""
|
||||
logger.hr(f'Use Q {position}')
|
||||
try:
|
||||
button = [USE_Q1, USE_Q2, USE_Q3, USE_Q4][position - 1]
|
||||
except IndexError:
|
||||
logger.error(f'use_Q: position {position} does not exist')
|
||||
return False
|
||||
|
||||
self._skill_click(button)
|
||||
self._skill_click(USE_Q_AIM)
|
||||
return True
|