Skip to content

Instantly share code, notes, and snippets.

@IgnatBeresnev
Created November 24, 2022 15:42
Show Gist options
  • Save IgnatBeresnev/1d8ae3e956761413cc320b157794fcd4 to your computer and use it in GitHub Desktop.
Save IgnatBeresnev/1d8ae3e956761413cc320b157794fcd4 to your computer and use it in GitHub Desktop.
package me.beresnev.bot.combat;
import me.beresnev.botapi.WowInstance;
import me.beresnev.botapi.navigation.Navigation;
import me.beresnev.botapi.spells.Spell;
import me.beresnev.botapi.units.ICharacter;
import me.beresnev.botapi.units.ICreature;
import me.beresnev.memoryapi.winapi.components.WinKey;
import static java.lang.System.currentTimeMillis;
import static me.beresnev.util.Util.sleep;
/**
* @author Cargeh
*/
public abstract class CombatProfile {
private static final long TIMEOUT = 5000;
private final WowInstance wowInstance;
private final ICharacter character;
private final Navigation navigation;
public CombatProfile(WowInstance wowInstance) {
this.wowInstance = wowInstance;
this.character = wowInstance.getCharacter();
this.navigation = wowInstance.getNavigation();
}
protected abstract Spell[] getRequiredSpells();
public boolean kill(ICreature creature) {
int creatureHealth = creature.getHealth();
long timestampOfHealthWrite = currentTimeMillis();
while (creatureHealth > 1) {
if (isMelee()) {
boolean attackingCreature = attackCreatureMelee(creature);
if (!attackingCreature)
return false;
} else {
// TODO: goto as ranged
}
rotationOn(creature);
sleep(getIterationInterval());
int currentCreatureHealth = creature.getHealth();
if (creatureHealth == currentCreatureHealth) {
if (isTimeoutReached(timestampOfHealthWrite))
return false;
} else {
timestampOfHealthWrite = currentTimeMillis();
}
creatureHealth = currentCreatureHealth;
}
return true;
}
private boolean attackCreatureMelee(ICreature creature) {
boolean isThere = navigation.goTo(creature);
if (!isThere)
return false;
faceAndTarget(creature);
navigation.attack(creature);
wowInstance.shortClick(WinKey.W);
wowInstance.shortClick(WinKey.S);
return true;
}
private void faceAndTarget(ICreature creature) {
character.target(creature);
navigation.face(creature);
}
protected abstract long getIterationInterval();
private boolean isTimeoutReached(long startedAttacking) {
return (currentTimeMillis() - startedAttacking) >= TIMEOUT;
}
protected abstract void rotationOn(ICreature creature);
protected abstract boolean isMelee();
protected abstract int getMinLevel();
protected abstract int getMaxLevel();
boolean isValidLevel(int level) {
return level > getMinLevel() && level <= getMaxLevel();
}
}
package me.beresnev.bot.combat.paladin;
import me.beresnev.bot.combat.CombatProfile;
import me.beresnev.botapi.WowInstance;
import me.beresnev.botapi.spells.Spell;
import me.beresnev.botapi.spells.Spellbook;
import me.beresnev.botapi.units.ICharacter;
import me.beresnev.botapi.units.ICreature;
import static me.beresnev.botapi.spells.Spell.PALADIN.HOLY_LIGHT;
import static me.beresnev.botapi.spells.Spell.PALADIN.SEAL_OF_RIGHTEOUSNESS;
/**
* @author Cargeh
*/
public class PaladinProfileLevel1 extends CombatProfile {
private static final int minLevel = 1;
private static final int maxLevel = 9;
private final ICharacter character;
private final Spellbook spellbook;
public PaladinProfileLevel1(WowInstance wowInstance) {
super(wowInstance);
this.character = wowInstance.getCharacter();
this.spellbook = wowInstance.getSpellbook();
}
public Spell[] getRequiredSpells() {
return new Spell[]{HOLY_LIGHT, SEAL_OF_RIGHTEOUSNESS};
}
@Override
protected long getIterationInterval() {
return 2000;
}
@Override
public void rotationOn(ICreature creature) {
if (sealIsNotUp())
reapplySeal();
if (needHeal())
heal();
}
@Override
public boolean isMelee() {
return true;
}
private boolean sealIsNotUp() {
return !character.hasAura(SEAL_OF_RIGHTEOUSNESS);
}
private void reapplySeal() {
spellbook.castSpell(SEAL_OF_RIGHTEOUSNESS);
}
private boolean needHeal() {
return character.getHealthPercentage() <= 30;
}
private void heal() {
spellbook.castSpell(HOLY_LIGHT);
}
}
package me.beresnev.bot.combat;
import me.beresnev.botapi.WowInstance;
import me.beresnev.botapi.units.ICreature;
import static java.lang.System.currentTimeMillis;
import static me.beresnev.bot.util.Util.numberIsInBound;
/**
* @author Cargeh
*/
public abstract class Rotation {
private static final long LEVEL_CHECK_PERIOD = 600000; // 10 minutes
protected final WowInstance wowInstance;
private volatile long timestampOfLastLevel = currentTimeMillis();
private volatile CombatProfile combatProfile;
public Rotation(WowInstance wowInstance) {
this.wowInstance = wowInstance;
this.combatProfile = getProfileFor(wowInstance.getCharacter().getLevel());
}
public boolean kill(ICreature creature) {
updateCombatProfileIfRequired();
return combatProfile.kill(creature);
}
private void updateCombatProfileIfRequired() {
long currentTime = currentTimeMillis();
if ((currentTime - timestampOfLastLevel) >= LEVEL_CHECK_PERIOD) {
int characterLevel = wowInstance.getCharacter().getLevel();
if (!combatProfile.isValidLevel(characterLevel)) {
combatProfile = getProfileFor(characterLevel);
}
timestampOfLastLevel = currentTime;
}
}
private CombatProfile getProfileFor(int level) {
if (numberIsInBound(level <= 9)) {
return getProfileWithValidatedSpellsLevel1();
} else {
throw new IllegalArgumentException("Cannot get a profile for level " + level);
}
}
private CombatProfile getProfileWithValidatedSpellsLevel1() {
CombatProfile profile = getProfileForLevel1();
checkRequiredSpells(profile);
return profile;
}
public void checkRequiredSpells(CombatProfile combatProfile) {
if (characterMissingSpells(combatProfile))
throw new IllegalStateException(
"Spells on your character are very outdated. Cannot proceed. Visit the trainer");
}
private boolean characterMissingSpells(CombatProfile combatProfile) {
return !wowInstance.getSpellbook().characterHasSpells(combatProfile.getRequiredSpells());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment