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.assets.assets_combat_team import COMBAT_TEAM_PREPARE, COMBAT_TEAM_SUPPORT
|
||||||
from tasks.combat.interact import CombatInteract
|
from tasks.combat.interact import CombatInteract
|
||||||
from tasks.combat.prepare import CombatPrepare
|
from tasks.combat.prepare import CombatPrepare
|
||||||
|
from tasks.combat.skill import CombatSkill
|
||||||
from tasks.combat.state import CombatState
|
from tasks.combat.state import CombatState
|
||||||
from tasks.combat.support import CombatSupport
|
from tasks.combat.support import CombatSupport
|
||||||
from tasks.combat.team import CombatTeam
|
from tasks.combat.team import CombatTeam
|
||||||
from tasks.map.control.joystick import MapControlJoystick
|
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):
|
def handle_combat_prepare(self):
|
||||||
"""
|
"""
|
||||||
Returns:
|
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
|