Skip to content

Commit

Permalink
Merge pull request #93 from daredoes/feature/questing
Browse files Browse the repository at this point in the history
Feature: AFK Questing Loop
  • Loading branch information
daredoes authored Jan 29, 2023
2 parents 11d2896 + 385b575 commit 84e879b
Show file tree
Hide file tree
Showing 37 changed files with 721 additions and 128 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>bh.bot</groupId>
<artifactId>99bot</artifactId>
<version>3.5.1</version>
<version>3.6.0</version>

<dependencies>
<dependency>
Expand Down
24 changes: 24 additions & 0 deletions sample-scripts/MultiCharacter.AFK.web.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:: Do chaining tasks Quest, PVP, WB, GVG/Invasion/Expedition, TG, Raid and then exit after completed them all
:: https://github.com/9-9-9-9/Bit-Heroes-bot/wiki/Function-%22afk%22
:: Consider adding `--profile=YourProfileName` so you no longer needed to select profile manually
:: You can remove flag `--ear` to keep game online all day (but still gone if you got Disconnected)
:: With steam version of BH, refer to AFK.steam.bat file

:: Comment Out or Delete Unused Characters

:: Switch to Character #1
echo 'e' | call web.bot.bat change-character 1
echo 'e' | call web.bot.bat afk a --ear --profile=name1

:: Switch to Character #3
echo 'e' | call web.bot.bat change-character 2
echo 'e' | call web.bot.bat afk a --ear --profile=name2

:: Switch to Character #3
echo 'e' | call web.bot.bat change-character 3
echo 'e' | call web.bot.bat afk a --ear --profile=name3

:: Call itself to go in an infinite loop
call MultiCharacter.AFK.web.bat

:: Move this file to bot's folder in order to use (this file was distributed within `sample-script` folder so it unable to run)
1 change: 1 addition & 0 deletions src/main/java/bh/bot/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static void main(String[] args) {
WorldBossTeamApp.class, //
RaidApp.class, //
PvpApp.class, //
QuestApp.class, //
InvasionApp.class, //
ExpeditionApp.class, //
TrialsApp.class, //
Expand Down
314 changes: 227 additions & 87 deletions src/main/java/bh/bot/app/AbstractApplication.java

Large diffs are not rendered by default.

40 changes: 38 additions & 2 deletions src/main/java/bh/bot/app/AfkApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class AfkApp extends AbstractApplication {
private final AtomicLong blockPvpUntil = new AtomicLong(0);
private final AtomicLong blockWorldBossUntil = new AtomicLong(0);
private final AtomicLong blockRaidUntil = new AtomicLong(0);
private final AtomicLong blockQuestUntil = new AtomicLong(0);
private final AtomicLong blockGvgAndInvasionAndExpeditionUntil = new AtomicLong(0);
private final AtomicLong blockTrialsAndGauntletUntil = new AtomicLong(0);
private final AtomicBoolean isOnPvp = new AtomicBoolean(false);
Expand All @@ -63,10 +64,11 @@ protected void internalRun(String[] args) {
eventList = getAttendablePlaces(getEventListFromArg(args));

boolean doRaid = eventList.contains(AttendablePlaces.raid);
boolean doQuest = eventList.contains(AttendablePlaces.quest);
boolean doWorldBoss = eventList.contains(AttendablePlaces.worldBoss);
boolean doExpedition = eventList.contains(AttendablePlaces.expedition);
boolean doPVP = eventList.contains(AttendablePlaces.pvp);
if (doRaid || doWorldBoss || doExpedition || doPVP) {
if (doRaid || doWorldBoss || doExpedition || doPVP || doQuest) {
userConfig = getPredefinedUserConfigFromProfileName("You want to do Raid/World Boss (Solo)/Expedition/PVP so you have to specific profile name first!\nSelect an existing profile:");

try {
Expand All @@ -75,6 +77,10 @@ protected void internalRun(String[] args) {
userConfig.getRaidLevelDesc());
}

if (doQuest) {
info(ColorizeUtil.formatInfo, "You have selected %s mode", userConfig.getQuestModeDesc());
}

if (doWorldBoss) {
info(ColorizeUtil.formatInfo, "You have selected world boss %s", userConfig.getWorldBossLevelDesc());
warn("World Boss is solo only and does not support select mode of World Boss (Normal/Hard/Heroic), only select by default So which boss do you want to hit? Choose it before turn this on");
Expand Down Expand Up @@ -113,6 +119,7 @@ protected void internalRun(String[] args) {
eventList.contains(AttendablePlaces.pvp), //
eventList.contains(AttendablePlaces.worldBoss), //
eventList.contains(AttendablePlaces.raid), //
eventList.contains(AttendablePlaces.quest), //
eventList.contains(AttendablePlaces.gvg), //
eventList.contains(AttendablePlaces.invasion), //
eventList.contains(AttendablePlaces.expedition), //
Expand All @@ -130,6 +137,7 @@ protected void internalRun(String[] args) {
.closeEnterGameNewsDialog() //
.persuade() //
.detectChatboxDirectMessage() //
.preventLeaveDungeon() //
.build() //
), //
() -> doCheckGameScreenOffset(masterSwitch) //
Expand All @@ -142,20 +150,26 @@ private void doLoop(//
boolean doPvp, //
boolean doWorldBoss, //
boolean doRaid, //
boolean doQuest, //
boolean doGvg, //
boolean doInvasion, //
boolean doExpedition, //
boolean doTrials, //
boolean doGauntlet //
) {
try {

info(ColorizeUtil.formatInfo, "\n\nStarting AFK");
boolean isUnknownGvgOrInvasionOrExpedition = (doGvg && doInvasion) || (doGvg && doExpedition)
|| (doInvasion && doExpedition);
boolean isUnknownTrialsOrGauntlet = doTrials && doGauntlet;
int continuousNotFound = 0;
final Point coordinateHideMouse = new Point(0, 0);
final ArrayList<Tuple3<AttendablePlace, AtomicLong, List<AbstractDoFarmingApp.NextAction>>> taskList = new ArrayList<>();
// Add Questing as first task
if (doQuest)
taskList.add(new Tuple3<>(AttendablePlaces.quest, blockQuestUntil, QuestApp.getPredefinedImageActions()));

NextAction naBtnFightPvp = null;
if (doPvp) {
List<AbstractDoFarmingApp.NextAction> pvpPia = PvpApp.getPredefinedImageActions();
Expand Down Expand Up @@ -206,6 +220,7 @@ private void doLoop(//
}

ArrayList<AbstractDoFarmingApp.NextAction> outOfTurnNextActionList = new ArrayList<>();
addOutOfTurnActionsToList(outOfTurnNextActionList, QuestApp.getPredefinedImageActions());
addOutOfTurnActionsToList(outOfTurnNextActionList, PvpApp.getPredefinedImageActions());
addOutOfTurnActionsToList(outOfTurnNextActionList, WorldBossApp.getPredefinedImageActions());
addOutOfTurnActionsToList(outOfTurnNextActionList, RaidApp.getPredefinedImageActions());
Expand All @@ -226,11 +241,14 @@ private void doLoop(//

final Supplier<Boolean> isWorldBossBlocked = () -> !isNotBlocked(blockWorldBossUntil);
final Supplier<Boolean> isRaidBlocked = () -> !isNotBlocked(blockRaidUntil);
final Supplier<Boolean> isQuestBlocked = () -> !isNotBlocked(blockQuestUntil);

Main.warningSupport();

if (doRaid)
info(ColorizeUtil.formatInfo, "Raid: %s of %s", userConfig.getRaidModeDesc(), userConfig.getRaidLevelDesc());
if (doQuest)
info(ColorizeUtil.formatInfo, "Quest: %s", userConfig.getQuestModeDesc());
if (doWorldBoss)
info(ColorizeUtil.formatInfo, "World Boss: %s", userConfig.getWorldBossLevelDesc());
if (doExpedition)
Expand Down Expand Up @@ -325,6 +343,13 @@ private void doLoop(//
continue ML;
}

if (tryEnterQuest(doQuest, userConfig, isQuestBlocked, this.gameScreenInteractor)) {
debug("tryEnterQuest");
continuousNotFound = 0;
moveCursor(coordinateHideMouse);
continue ML;
}

if (tryEnterWorldBoss(doWorldBoss, userConfig, isWorldBossBlocked)) {
debug("tryEnterWorldBoss");
continuousNotFound = 0;
Expand Down Expand Up @@ -461,6 +486,8 @@ else if (attendablePlace == AttendablePlaces.worldBoss)
x = blockWorldBossUntil;
else if (attendablePlace == AttendablePlaces.raid)
x = blockRaidUntil;
else if (attendablePlace == AttendablePlaces.quest)
x = blockQuestUntil;
else if (attendablePlace == AttendablePlaces.gvg || attendablePlace == AttendablePlaces.invasion
|| attendablePlace == AttendablePlaces.expedition)
x = blockGvgAndInvasionAndExpeditionUntil;
Expand All @@ -480,6 +507,7 @@ private ArrayList<AttendablePlace> getAttendablePlaces(AfkBatch afkBatch) {
AttendablePlaces.gvg, //
AttendablePlaces.gauntlet, //

AttendablePlaces.quest, //
AttendablePlaces.pvp, //
AttendablePlaces.worldBoss, //
AttendablePlaces.raid //
Expand All @@ -502,12 +530,15 @@ private ArrayList<AttendablePlace> getAttendablePlaces(AfkBatch afkBatch) {
eventList.add(AttendablePlaces.worldBoss);
if (argumentInfo.eRaid || afkBatch.doRaid)
eventList.add(AttendablePlaces.raid);
if (argumentInfo.eQuest || afkBatch.doQuest)
eventList.add(AttendablePlaces.quest);
//
if (eventList.size() == 0) {
final List<MenuItem> menuItems = Stream.of(
MenuItem.from(AttendablePlaces.pvp),
MenuItem.from(AttendablePlaces.worldBoss),
MenuItem.from(AttendablePlaces.raid),
MenuItem.from(AttendablePlaces.quest),
MenuItem.from("GVG/Expedition/Invasion", AttendablePlaces.gvg, AttendablePlaces.expedition, AttendablePlaces.invasion),
MenuItem.from("Trials/Gauntlet", AttendablePlaces.trials, AttendablePlaces.gauntlet),
MenuItem.from(AttendablePlaces.pvp, AttendablePlaces.worldBoss, AttendablePlaces.raid),
Expand Down Expand Up @@ -590,6 +621,7 @@ protected String getLimitationExplain() {
private static final char codeWorldBoss1 = 'B';
private static final char codeWorldBoss2 = 'W';
private static final char codeRaid = 'R';
private static final char codeQuest = 'Q';
private static final char codeInvasion = 'I';
private static final char codeExpedition = 'E';
private static final char codeGVG = 'V';
Expand All @@ -600,12 +632,13 @@ protected String getLimitationExplain() {
private static final char codeComboTrialsGauntlet = '3';
private static final char codeComboAll = 'A';

private static final String shortDescArg = String.format("%s (PVP), %s (World Boss), %s (Raid), %s (Invasion), %s (Expedition), %s (GVG), %s (Gauntlet), %s (Trials), %s (PVP/World Boss/Raid), %s (Invasion/GVG/Expedition), %s (Trials/Gauntlet), %s (All)", codePvp, codeWorldBoss1, codeRaid, codeInvasion, codeExpedition, codeGVG, codeGauntlet, codeTrials, codeComboPvpWorldBossRaid, codeComboInvasionGvgExpedition, codeComboTrialsGauntlet, codeComboAll);
private static final String shortDescArg = String.format("%s (PVP), %s (World Boss), %s (Raid), %s (Quest), %s (Invasion), %s (Expedition), %s (GVG), %s (Gauntlet), %s (Trials), %s (PVP/World Boss/Raid), %s (Invasion/GVG/Expedition), %s (Trials/Gauntlet), %s (All)", codePvp, codeWorldBoss1, codeRaid, codeQuest, codeInvasion, codeExpedition, codeGVG, codeGauntlet, codeTrials, codeComboPvpWorldBossRaid, codeComboInvasionGvgExpedition, codeComboTrialsGauntlet, codeComboAll);

private static class AfkBatch {
public boolean doPvp;
public boolean doWorldBoss;
public boolean doRaid;
public boolean doQuest;
public boolean doInvasion;
public boolean doExpedition;
public boolean doGvg;
Expand All @@ -622,6 +655,7 @@ private static AfkBatch getEventListFromArg(String[] args) {
result.doPvp = true;
result.doWorldBoss = true;
result.doRaid = true;
result.doQuest = true;
result.doInvasion = true;
result.doExpedition = true;
result.doGvg = true;
Expand All @@ -644,6 +678,8 @@ private static AfkBatch getEventListFromArg(String[] args) {
result.doWorldBoss = true;
} else if (c == codeRaid) {
result.doRaid = true;
} else if (c == codeQuest) {
result.doQuest = true;
} else if (c == codeInvasion) {
result.doInvasion = true;
} else if (c == codeGVG) {
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/bh/bot/app/SettingApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ protected void internalRun(String[] args) {
if (file.exists() && file.isDirectory())
throw new InvalidDataException("%s is a directory", fileName);
Tuple2<Boolean, UserConfig> resultLoadUserConfig = Configuration.loadUserConfig(cfgProfileName);
int raidLevel, raidMode, worldBossLevel, expeditionPlace, pvpTarget;
int raidLevel, raidMode, worldBossLevel, expeditionPlace, pvpTarget, questMode;
if (resultLoadUserConfig._1) {
raidLevel = resultLoadUserConfig._2.raidLevel;
raidMode = resultLoadUserConfig._2.raidMode;
questMode = resultLoadUserConfig._2.questMode;
worldBossLevel = resultLoadUserConfig._2.worldBossLevel;
expeditionPlace = resultLoadUserConfig._2.expeditionPlace;
pvpTarget = resultLoadUserConfig._2.pvpTarget;
Expand All @@ -47,6 +48,11 @@ protected void internalRun(String[] args) {
else
info(ColorizeUtil.formatInfo, "You haven't specified Raid mode (Normal/Hard/Heroic)");

if (UserConfig.isValidDifficultyMode(resultLoadUserConfig._2.questMode))
info(ColorizeUtil.formatInfo, "Selected Quest mode %s", resultLoadUserConfig._2.getQuestModeDesc());
else
info(ColorizeUtil.formatInfo, "You haven't specified Quest mode (Normal/Hard/Heroic)");

if (resultLoadUserConfig._2.isValidWorldBossLevel())
info(ColorizeUtil.formatInfo, "Selected World Boss (Solo) %s", resultLoadUserConfig._2.getWorldBossLevelDesc());
else
Expand All @@ -67,6 +73,7 @@ protected void internalRun(String[] args) {
} else {
raidLevel = 0;
raidMode = 0;
questMode = 0;
worldBossLevel = 0;
expeditionPlace = 0;
pvpTarget = 0;
Expand All @@ -90,6 +97,13 @@ protected void internalRun(String[] args) {
tmp = readIntInput(sb.toString(), modeRange._1, modeRange._2);
raidMode = tmp == null ? raidMode : tmp;
//
sb = new StringBuilder("All Quest's difficulty mode:\n");
for (byte rl = modeRange._1; rl <= modeRange._2; rl++)
sb.append(String.format(" %2d. %s\n", rl, UserConfig.getDifficultyModeDesc(rl, "Quest")));
sb.append("Specific Quest mode? This will be used when a level with difficulties happens to be selected");
tmp = readIntInput(sb.toString(), modeRange._1, modeRange._2);
questMode = tmp == null ? questMode : tmp;
//
final Tuple2<Byte, Byte> woldBossLevelRange = UserConfig.getWorldBossLevelRange();
sb = new StringBuilder("All World Boss levels:\n");
for (int rl = woldBossLevelRange._1; rl <= woldBossLevelRange._2; rl++)
Expand All @@ -115,14 +129,19 @@ protected void internalRun(String[] args) {
tmp = readIntInput(sb.toString(), pvpTargetRange._1, pvpTargetRange._2);
pvpTarget = tmp == null ? pvpTarget : tmp;
//
UserConfig newCfg = new UserConfig(cfgProfileName, (byte) raidLevel, (byte) raidMode, (byte) worldBossLevel, (byte) expeditionPlace, (byte) pvpTarget);
UserConfig newCfg = new UserConfig(cfgProfileName, (byte) raidLevel, (byte) raidMode, (byte) worldBossLevel, (byte) expeditionPlace, (byte) pvpTarget, (byte) questMode);

sb = new StringBuilder("Your setting:\n");
if (newCfg.isValidRaidLevel() && UserConfig.isValidDifficultyMode(newCfg.raidMode))
sb.append(String.format(" %s mode of raid %s", UserConfig.getDifficultyModeDesc((byte) raidMode, "Raid"), UserConfig.getRaidLevelDesc((byte) raidLevel)));
else
sb.append(" raid has not been set");
sb.append('\n');
if (UserConfig.isValidDifficultyMode(newCfg.questMode))
sb.append(String.format(" %s mode of quest", UserConfig.getDifficultyModeDesc((byte) questMode, "Quest")));
else
sb.append(" quest has not been set");
sb.append('\n');
if (newCfg.isValidWorldBossLevel())
sb.append(String.format(" world boss (solo) %s", UserConfig.getWorldBossLevelDesc((byte) worldBossLevel)));
else
Expand Down Expand Up @@ -151,6 +170,7 @@ protected void internalRun(String[] args) {
if (save) {
sb = new StringBuilder();
sb.append(String.format("%s=%d\n", UserConfig.raidLevelKey, raidLevel));
sb.append(String.format("%s=%d\n", UserConfig.questModeKey, questMode));
sb.append(String.format("%s=%d\n", UserConfig.raidModeKey, raidMode));
sb.append(String.format("%s=%d\n", UserConfig.worldBossLevelKey, worldBossLevel));
sb.append(String.format("%s=%d\n", UserConfig.expeditionPlaceKey, expeditionPlace));
Expand Down
Loading

0 comments on commit 84e879b

Please sign in to comment.