diff --git a/scripts/src/main/java/io/github/fate_grand_automata/scripts/locations/BattleScreenLocations.kt b/scripts/src/main/java/io/github/fate_grand_automata/scripts/locations/BattleScreenLocations.kt index 350150b3c..9177ebc6f 100644 --- a/scripts/src/main/java/io/github/fate_grand_automata/scripts/locations/BattleScreenLocations.kt +++ b/scripts/src/main/java/io/github/fate_grand_automata/scripts/locations/BattleScreenLocations.kt @@ -116,6 +116,9 @@ class BattleScreenLocations @Inject constructor( fun imageRegion(skill: Skill.Servant) = Region(22, 28, 30, 30) + locate(skill) + fun cooldownTextRegion(skill: Skill.Servant) = + Region(-5, 40, 100, 55) + locate(skill) + val servantDetailsInfoClick = Location(-660, 110).xFromCenter() val servantDetailsFaceCardRegion = when (gameServer) { diff --git a/scripts/src/main/java/io/github/fate_grand_automata/scripts/modules/SkillSpam.kt b/scripts/src/main/java/io/github/fate_grand_automata/scripts/modules/SkillSpam.kt index d44fdde7b..9fb0c3866 100644 --- a/scripts/src/main/java/io/github/fate_grand_automata/scripts/modules/SkillSpam.kt +++ b/scripts/src/main/java/io/github/fate_grand_automata/scripts/modules/SkillSpam.kt @@ -6,8 +6,10 @@ import io.github.fate_grand_automata.scripts.models.ServantTarget import io.github.fate_grand_automata.scripts.models.SkillSpamConfig import io.github.fate_grand_automata.scripts.models.SkillSpamTarget import io.github.fate_grand_automata.scripts.models.SpamConfigPerTeamSlot +import io.github.fate_grand_automata.scripts.models.Skill import io.github.fate_grand_automata.scripts.models.battle.BattleState import io.github.fate_grand_automata.scripts.models.skills +import io.github.lib_automata.Pattern import io.github.lib_automata.dagger.ScriptScope import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -22,6 +24,8 @@ class SkillSpam @Inject constructor( ) : IFgoAutomataApi by api { companion object { val skillSpamDelay = 0.25.seconds + val skillReadyRecheckDelay = 0.1.seconds + val cooldownRegex = Regex("""\d+""") } fun spamSkills() { @@ -42,7 +46,7 @@ class SkillSpam @Inject constructor( // Some delay for skill icon to be loaded skillSpamDelay.wait() - if (skillImage in locations.battle.imageRegion(skill)) { + if (isReadyForSpam(skill, skillImage)) { val target = skillSpamConfig.determineTarget(servantSlot) caster.castServantSkill(skill, target) @@ -68,4 +72,32 @@ class SkillSpam @Inject constructor( SkillSpamTarget.Left -> ServantTarget.Left SkillSpamTarget.Right -> ServantTarget.Right } -} \ No newline at end of file + + private fun isReadyForSpam(skill: Skill.Servant, skillImage: Pattern): Boolean { + fun checkReady() = skillImage in locations.battle.imageRegion(skill) && !hasCooldownText(skill) + + if (!useSameSnapIn { checkReady() }) { + return false + } + + skillReadyRecheckDelay.wait() + + return useSameSnapIn { checkReady() } + } + + private fun hasCooldownText(skill: Skill.Servant): Boolean { + val text = locations.battle.cooldownTextRegion(skill) + .detectText(outlinedText = true) + .replace('O', '0') + .replace('o', '0') + .replace('I', '1') + .replace('l', '1') + + val cooldown = cooldownRegex + .find(text) + ?.value + ?.toIntOrNull() + + return cooldown != null && cooldown > 0 + } +}