From 444f06e852f58a00f714b0f28a4bf2acd50bcfac Mon Sep 17 00:00:00 2001 From: infuse21 Date: Sat, 18 Jul 2026 12:39:16 +0100 Subject: [PATCH 1/5] ## Summary - Defers off-path recalculation while the player is still moving, animating, interacting, settling after doors/transports, or making recent route/interim progress. - Reworks route minimap clicks and unreachable-tile recovery to stay anchored to the planned raw path, use Euclidean minimap reach, and avoid backtracking to earlier nearby path branches. - Adds sticky interim checkpoint tracking so recovery/continuation clicks are not spammed while valid movement is already in flight. - Tightens door handling by deferring door probes while moving and only blacklisting wrong-traversal doors when the player started near the attempted door edge. - Improves charter ship destination widget lookup/clicking and optional confirmation handling. --- docs/entity-guides/movement.md | 32 +- .../shortestpath/ShortestPathPlugin.java | 2 +- .../pathfinder/PathfinderConfig.java | 2 +- .../microbot/util/walker/Rs2Walker.java | 1337 ++++++++++++++--- .../microbot/util/walker/WebWalkLog.java | 21 +- .../util/walker/Rs2WalkerUnitTest.java | 284 +++- 6 files changed, 1457 insertions(+), 221 deletions(-) diff --git a/docs/entity-guides/movement.md b/docs/entity-guides/movement.md index 4a658235f4..2ed25f0c5d 100644 --- a/docs/entity-guides/movement.md +++ b/docs/entity-guides/movement.md @@ -77,6 +77,8 @@ waitForDoorInteractionProgress(fromWp, toWp); **Defensive check:** In live testing, a door should produce one interaction followed by movement/path progress, not repeated `Raw path door handler resolved obstacle` messages every tick while the player is moving. +If a previous minimap click is still moving the player, do not attribute that movement to a new gate interaction. A valid gate can be blacklisted when the walker clicks an interim waypoint, notices the gate while movement is still in flight, then compares the pre/post positions from the old minimap movement against the gate edge. Wrong-traversal blacklisting should only run when the player started near the attempted door edge. + ## 5. Suppress the inverse adjacent transport after crossing a same-plane door Some doors are represented in `transports.tsv` as two adjacent same-plane transports, one for each direction. After the walker clicks one side and arrives on the other, immediately accepting the inverse transport can bounce the player back through the same door instead of letting the next minimap step continue away from it. Mark both tiles of a successful adjacent same-plane transport as recently handled for a short window. @@ -286,12 +288,38 @@ if (isStuckTooLong()) { After a handled transport, avoid expensive path-adjacent or raw transport scans on ordinary open-ground segments unless a nearby planned transport or recent door attempt exists. Those scans are recovery tools, and on long outdoor routes a no-op scan can add several seconds before the next minimap click. -For long-route minimap walking, let the next checkpoint selection happen before the current minimap target is fully consumed. Waiting until the player is only a few tiles from the interim makes the walker visibly stop before issuing the next click; handing off at a moderate remaining distance keeps movement continuous without rapid re-clicking. If an interim clears as close and no nearby route door/transport is pending, issue the next route-aligned continuation click immediately instead of waiting for idle-nudge recovery. +For long-route minimap walking, let the next checkpoint selection happen before the current minimap target is fully consumed. Waiting until the player is only a few tiles from the interim makes the walker visibly stop before issuing the next click; handing off at a moderate remaining distance keeps movement continuous without rapid re-clicking. If an interim clears as close and no nearby route door/transport is pending, issue the next route-aligned continuation click immediately instead of waiting for idle-nudge recovery. Stale-progress checks must also count distance progress toward the actual interim checkpoint, not only smoothed path index progress; sparse smoothed paths can otherwise clear valid raw-path checkpoints as stale while the player is still walking toward them. + +Before the first movement click, only scan a small number of immediate route edges for doors or blockers. A door several segments ahead can be handled after the first minimap click moves the player toward it; spending startup time scanning every nearby raw segment creates a visible cold start. Continuation clicks that keep an active route moving should be tail-exempt like `interim-in-flight`; otherwise very long routes can exhaust `MAX_PROCESS_WALK_TAIL_ITERATIONS` while still making progress and trigger an unnecessary auto-retry. Sticky interim targets should also clear when route-index progress goes stale. If the player keeps moving but the closest path index does not advance for `INTERIM_PROGRESS_TIMEOUT_MS`, treat the checkpoint as stale and select a fresh route-aligned target instead of waiting for max-age expiry. -When a route-following minimap click is outside the minimap clip, fallback clicks must stay on the raw path. A generic "reachable tile closer to target" fallback can select a tile far away from the route in open areas, especially near the final destination. +When a route-following minimap click is outside the minimap clip, fallback clicks must stay on the raw path. This includes the "clicked but no movement yet" retry after a route click and route-backed direct short-walks near the final destination. A generic "reachable tile closer to target" fallback can select a tile far away from the route in open areas, especially near fences and the final destination. Raw fallback must be anchored from the stabilized route index, not a fresh nearest-raw-tile lookup, or the walker can snap backward to an already-travelled branch. For adjacent same-plane shortcuts, do not treat any movement away from the origin as success. Some shortcuts, such as stepping stones, can fail and place the player on a fallback tile; once the player is settled away from the expected destination, stop the landing wait and replan from the actual tile. + +## 14. Keep optimistic recovery clicks route-backed and paced + +Unreachable-tile recovery is a fallback for bounded reachability false negatives, not a license to pick an arbitrary minimap point. Recovery clicks should use the same route-backed raw-path fallback as normal route movement, then store the actual clicked target as the sticky interim checkpoint. After issuing the click, wait only for movement to start or the checkpoint/goal to be reached; do not wait for a full idle cycle before returning to the walk loop. + +**Why this matters:** Bounded local reachability can report a valid route tile as unreachable even though the server pathfinder can still walk toward it. Arbitrary or repeated recovery clicks can pull the player away from the planned route and create visible stop-start movement. + +**Pattern to follow:** + +```java +int reach = STALL_RECOVERY_MINIMAP_REACH_EUCLIDEAN; +WorldPoint clickTarget = clampToEuclideanRadius(playerLoc, recoverTarget, reach - 1); +WorldPoint clickedTarget = clickMiniMapOrFallback(rawPath, clickTarget, playerLoc, reach - 1, false, rawAnchorIndex); +if (clickedTarget != null) { + interimTargetWp = clickedTarget; + waitForMovementStartAfterRecovery(target, playerLoc, clickedTarget, target, finishThreshold); +} +``` + +**Where this applies:** `Rs2Walker.processWalk` unreachable-smoothed-tile recovery, route-backed direct short-walks, and any fallback that runs after local reachability says a route tile is not currently reachable. + +**Defensive check:** Exercise a long outdoor route and a route with gates or transports. Recovery logs should select route-backed points, and there should be no long idle pause between `unreachable optimistic recovery` and the next route-aligned movement. + +After recovery sets a sticky interim target, do not issue another optimistic recovery while that interim is still active and movement/progress is fresh. Yield as `interim-in-flight` or another tail-exempt movement state until the checkpoint is close, stale, or expired. Otherwise the walker can loop through several recovery clicks while the player is already moving, especially when local reachability reports the next smoothed tile as unreachable. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java index 6a62b53d07..3f4c1437d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathPlugin.java @@ -308,7 +308,7 @@ protected void shutDown() { //Method from microbot public static void exit() { if (pathfindingExecutor != null) { - Rs2Walker.setTarget(null); + Rs2Walker.clearWalkingRoute("shortest-path-plugin:exit"); pathfindingExecutor.shutdownNow(); pathfindingExecutor = null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/pathfinder/PathfinderConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/pathfinder/PathfinderConfig.java index 211e1fdeef..92855da1cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/pathfinder/PathfinderConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/pathfinder/PathfinderConfig.java @@ -879,7 +879,7 @@ private boolean useTransport(Transport transport) { if (transport.getCurrencyAmount() > 0) { if (refreshCurrencyCache != null) { int[] cached = refreshCurrencyCache.computeIfAbsent(transport.getCurrencyName(), name -> { - int invCount = Rs2Inventory.count(name); + int invCount = Rs2Inventory.itemQuantity(name); int bankCount = useBankItems ? Rs2Bank.count(name) : 0; return new int[]{invCount, bankCount}; }); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java index 2c760efe15..68df3dceea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java @@ -126,29 +126,38 @@ public static WorldPoint getCurrentTarget() { private static volatile long interimSetAtMs = 0L; private static volatile long interimLastProgressAtMs = 0L; private static volatile int interimLastBestPathIdx = -1; + private static volatile int interimLastDistanceToTarget = Integer.MAX_VALUE; private static volatile long interimLastRetargetAtMs = 0L; /** Cooldown so partial-segment in-transit {@link #recalculatePath()} does not spam. */ private static volatile long lastPartialTransRecalcMs = 0L; private static final long PARTIAL_TRANS_RECAL_COOLDOWN_MS = 3500L; - private static final int INTERIM_CLOSE_TILES = 4; + private static final int INTERIM_CLOSE_TILES = 5; private static final int INTERIM_PRECLICK_TILES = 6; - private static final int INTERIM_RUN_PRECLICK_TILES = 11; + private static final int INTERIM_RUN_PRECLICK_TILES = 8; private static final int INTERIM_MOVING_POLL_MS = 450; private static final long INTERIM_PROGRESS_TIMEOUT_MS = 2500L; private static final long INTERIM_MAX_AGE_MS = 10_000L; private static final long INTERIM_RETARGET_COOLDOWN_MS = 900L; + private static final long ROUTE_PROGRESS_STALL_GRACE_MS = 4_000L; + private static final long OFF_PATH_RECALC_RECENT_MOVEMENT_MS = 2_000L; + private static final long OFF_PATH_RECALC_ROUTE_PROGRESS_GRACE_MS = 3_500L; + private static final long OFF_PATH_RECALC_MINIMAP_CLICK_GRACE_MS = 2_500L; + private static final int OFF_PATH_RECALC_DEFER_WAIT_MIN_MS = 250; + private static final int OFF_PATH_RECALC_DEFER_WAIT_MAX_MS = 1_200; private static final long RAW_SCAN_DOOR_FOCUS_MAX_MS = 2200L; private static final int RAW_SCAN_DOOR_FOCUS_MAX_ATTEMPTS = 3; private static final long DOOR_POST_INTERACT_SETTLE_MS = 900L; private static final long DOOR_EDGE_SKIP_COOLDOWN_MS = 700L; - private static final long RECOVERY_MOVEMENT_IN_FLIGHT_MS = 1400L; + private static final long RECOVERY_MOVEMENT_IN_FLIGHT_MS = 3_500L; private static final long DOOR_TRAVERSAL_RECOVERY_BLOCK_MS = 2_200L; + private static final long POST_DOOR_NUDGE_RECENT_ATTEMPT_MS = 6_000L; private static final int PATHFINDER_DONE_POLL_WAIT_MS = 1200; private static final int PATHFINDER_DONE_RETRY_SLEEP_MIN_MS = 120; private static final int PATHFINDER_DONE_RETRY_SLEEP_MAX_MS = 220; private static final long STARTUP_FIRST_CLICK_BUDGET_MS = 2200L; + private static final int STARTUP_PRECLICK_DOOR_SCAN_LOOKAHEAD_EDGES = 2; private static final int POST_DOOR_FAST_CLICK_MAX_EUCLIDEAN = 13; private static final int POST_DOOR_EDGE_NUDGE_MAX_FROM_PLAYER = 3; private static final int POST_DOOR_EDGE_NUDGE_WAIT_MS = 1200; @@ -162,7 +171,7 @@ public static WorldPoint getCurrentTarget() { private static final int UNREACHABLE_DOOR_RECOVERY_BACKTRACK_EDGES = 2; private static final int UNREACHABLE_DOOR_RECOVERY_LOOKAHEAD_EDGES = 10; private static final int STALL_RECOVERY_MINIMAP_REACH_EUCLIDEAN = 10; - private static final int NORMAL_MINIMAP_REACH_EUCLIDEAN = 12; + private static final int NORMAL_MINIMAP_REACH_EUCLIDEAN = 11; private static final int UNREACHABLE_RECOVERY_FORWARD_SCAN_TILES = 24; private static final long ACTIVE_ROUTE_IDLE_NUDGE_MS = 2_500L; private static final long ACTIVE_ROUTE_IDLE_NUDGE_COOLDOWN_MS = 2_000L; @@ -196,6 +205,7 @@ public static WorldPoint getCurrentTarget() { private static volatile WorldPoint routeProgressPathStart = null; private static volatile WorldPoint routeProgressPathEnd = null; private static volatile int routeProgressPathSize = -1; + private static volatile long routeProgressAdvancedAtMs = 0L; private static final java.util.Deque expectedTransportDestinations = new ArrayDeque<>(); private static final Set startupPhasesLogged = ConcurrentHashMap.newKeySet(); @@ -314,6 +324,24 @@ private enum WalkerPhase { STEADY } + private static final class WalkLoopSnapshot { + private final WorldPoint playerLoc; + private final HashMap closestReachableTiles; + + private WalkLoopSnapshot(WorldPoint playerLoc) { + this.playerLoc = playerLoc; + this.closestReachableTiles = getClosestIndexReachableTiles(playerLoc); + } + + private static WalkLoopSnapshot capture() { + return new WalkLoopSnapshot(Rs2Player.getWorldLocation()); + } + + private int closestTileIndex(List path) { + return getClosestTileIndex(path, playerLoc, closestReachableTiles); + } + } + private interface ObstaclePolicy { long segmentDoorTimeoutMs(); long unreachableDoorTimeoutMs(); @@ -420,6 +448,21 @@ private static ObstaclePolicy obstaclePolicyForCurrentPhase() { : STEADY_OBSTACLE_POLICY; } + static boolean shouldSkipStartupPreclickSegmentHandlers(boolean startupBeforeFirstClick, + int segmentIdx, + int routeStartIdx, + boolean recentDoorAttemptNearSegment, + boolean doorSettling, + boolean recoveryInFlight) { + if (!startupBeforeFirstClick || routeStartIdx < 0 || segmentIdx < routeStartIdx) { + return false; + } + if (recentDoorAttemptNearSegment || doorSettling || recoveryInFlight) { + return false; + } + return segmentIdx > routeStartIdx + STARTUP_PRECLICK_DOOR_SCAN_LOOKAHEAD_EDGES; + } + /** * Same-plane Chebyshev distance from player to {@code dest} strictly less than {@code maxChebyshevExclusive}. * Requires matching {@link WorldPoint#getPlane()} before using {@link WorldPoint#distanceTo2D} — that method only @@ -491,6 +534,7 @@ private static int tightFinishThreshold(WorldPoint goal, WorldPoint pathLastWalk /** If phase 1 exits on arrival distance while still moving, wait briefly for idle-only (reduces tail churn). */ private static final int POST_SCENE_WALK_IDLE_SECOND_PHASE_MS_MAX = 4_000; + private static final int POST_RECOVERY_MOVEMENT_START_WAIT_MS = 1_200; private static void waitUntilIdleAfterSceneWalk(WorldPoint cancelGoal, int timeoutMs) { waitUntilIdleAfterSceneWalk(cancelGoal, timeoutMs, null, 0); @@ -749,6 +793,7 @@ public static List getSeasonalTransportHandlers() */ public static final class Telemetry { public static final AtomicInteger offPathRecalcCount = new AtomicInteger(); + public static final AtomicInteger offPathRecalcDeferredCount = new AtomicInteger(); public static final AtomicInteger stallRecalcCount = new AtomicInteger(); public static final AtomicInteger partialRetryCount = new AtomicInteger(); public static final AtomicInteger unreachableCount = new AtomicInteger(); @@ -766,6 +811,9 @@ public static final class Telemetry { private static final ConcurrentHashMap doorRejectByCause = new ConcurrentHashMap<>(); private static final AtomicInteger doorRejectSummaryLogSeq = new AtomicInteger(0); private static final int DOOR_REJECT_SUMMARY_LOG_INTERVAL = 40; + private static final ConcurrentHashMap offPathDeferredByReason = new ConcurrentHashMap<>(); + private static final AtomicInteger offPathDeferredSummaryLogSeq = new AtomicInteger(0); + private static final int OFF_PATH_DEFERRED_SUMMARY_LOG_INTERVAL = 20; /** * Rate-limited debug summary of {@link #doorRejectByCause} tallies (noise control on tight door clusters). @@ -805,6 +853,22 @@ public static void recordOffPathRecalc(WorldPoint playerPos, int pathSize) { playerPos, pathSize, offPathRecalcCount.get(), stallRecalcCount.get()); } + public static void recordOffPathRecalcDeferred(String reason, WorldPoint playerPos, + WorldPoint target, int pathSize) { + if (reason == null || reason.isEmpty()) { + reason = "unknown"; + } + offPathRecalcDeferredCount.incrementAndGet(); + offPathDeferredByReason.computeIfAbsent(reason, k -> new AtomicInteger()).incrementAndGet(); + lastReason = "off-path-deferred:" + reason; + lastEventAtMs.set(System.currentTimeMillis()); + if (Rs2LogRateLimit.everyN(offPathDeferredSummaryLogSeq, OFF_PATH_DEFERRED_SUMMARY_LOG_INTERVAL) + && log.isDebugEnabled()) { + log.debug("[WalkerTelemetry] OFFPATH_RECALC_DEFERRED player={} target={} pathSize={} summary={}", + playerPos, target, pathSize, offPathDeferredByReason); + } + } + public static void recordStallRecalc(long sinceMovedMs, WorldPoint playerPos) { stallRecalcCount.incrementAndGet(); lastReason = "stall"; @@ -836,6 +900,7 @@ public static void recordUnreachable(String cause, WorldPoint player, WorldPoint public static void reset() { offPathRecalcCount.set(0); + offPathRecalcDeferredCount.set(0); stallRecalcCount.set(0); partialRetryCount.set(0); unreachableCount.set(0); @@ -845,6 +910,8 @@ public static void reset() { seasonalHandlerMissCount.set(0); doorRejectByCause.clear(); doorRejectSummaryLogSeq.set(0); + offPathDeferredByReason.clear(); + offPathDeferredSummaryLogSeq.set(0); lastEventAtMs.set(0); lastReason = ""; log.info("[WalkerTelemetry] counters reset"); @@ -1054,6 +1121,7 @@ private static WalkerState walkWithStateInternal(WorldPoint target, int distance interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; lastPartialTransRecalcMs = 0L; idleNudgeLastObservedLocation = playerLocWalk; @@ -1191,9 +1259,10 @@ private static WalkerState processWalk(WorldPoint target, int distance, int part int rawSize = rawPath == null ? -1 : rawPath.size(); int walkSize = path == null ? -1 : path.size(); markStartupPhase("path_snapshot", target, "raw=" + rawSize + " walk=" + walkSize); + final WalkLoopSnapshot walkLoop = WalkLoopSnapshot.capture(); final WorldPoint dst; if (path == null || path.isEmpty()) { - dst = Rs2Player.getWorldLocation(); + dst = walkLoop.playerLoc; } else { dst = path.get(path.size()-1); } @@ -1204,7 +1273,7 @@ private static WalkerState processWalk(WorldPoint target, int distance, int part WebWalkLog.partialSegment(dst, dst.distanceTo(target), target, path.size()); partialPath = true; } else { - Telemetry.recordUnreachable("no-walkable-path", Rs2Player.getWorldLocation(), + Telemetry.recordUnreachable("no-walkable-path", walkLoop.playerLoc, target, dst, path == null ? 0 : path.size(), distance, pathfinder); setTarget(null, "rs2walker:processWalk:no-walkable-path"); return WalkerState.UNREACHABLE; @@ -1218,11 +1287,11 @@ private static WalkerState processWalk(WorldPoint target, int distance, int part // Partial segment: before standing on the segment endpoint, refresh routing from current // position so the continuation is ready (smooth handoff vs dead stop at segment end). if (partialPath) { - WorldPoint playerPt = Rs2Player.getWorldLocation(); + WorldPoint playerPt = walkLoop.playerLoc; if (playerPt != null && dst != null) { int distToDstSeg = playerPt.distanceTo2D(dst); int distToGoal = playerPt.distanceTo2D(target); - int closestEarly = getClosestTileIndex(path); + int closestEarly = walkLoop.closestTileIndex(path); int remainingSteps = closestEarly >= 0 ? (path.size() - 1 - closestEarly) : Integer.MAX_VALUE; final int nearSegmentEndTiles = 12; final int nearSegmentEndSteps = 10; @@ -1316,13 +1385,13 @@ && tryIssueRouteRecoveryClick(rawPath, path, target, "active route idle nudge")) } } - WorldPoint playerLocForIndex = Rs2Player.getWorldLocation(); - int indexOfStartPoint = stabilizeRouteProgressIndex(path, getClosestTileIndex(path), target, playerLocForIndex); + WorldPoint playerLocForIndex = walkLoop.playerLoc; + int indexOfStartPoint = stabilizeRouteProgressIndex(path, walkLoop.closestTileIndex(path), target, playerLocForIndex); indexOfStartPoint = advanceIndexPastRecentTransportEdge(path, indexOfStartPoint, playerLocForIndex); if (indexOfStartPoint == -1) { walkerDiag("getClosestTileIndex=-1 pathSize=%d player=%s pathFirst=%s pathLast=%s", path.size(), - Rs2Player.getWorldLocation(), + playerLocForIndex, path.isEmpty() ? null : path.get(0), path.isEmpty() ? null : path.get(path.size() - 1)); traceProcessWalkExit("closest-index-none", target, processWalkTail); @@ -1331,7 +1400,7 @@ && tryIssueRouteRecoveryClick(rawPath, path, target, "active route idle nudge")) } primeExpectedTransportDestinations(path, indexOfStartPoint); - lastPosition = Rs2Player.getWorldLocation(); + lastPosition = playerLocForIndex; boolean clearedInterimTarget = clearInterimTargetIfReachedOrExpired(lastPosition, path, System.currentTimeMillis()); WorldPoint plImmediate = lastPosition; @@ -1489,21 +1558,21 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { "nearPath=false variance=" + nearPathByVariance); } if (!nearPath && !recentTransportWindow && !nearPathByVariance) { - // Avoid mid-walk recalculation while the player is still moving. recalculatePath() - // cancels the pathfinder and waits up to 10s for a new one — a visible stall. - // isStuckTooLong() will trigger a real recalculation if progress actually halts. - boolean movingOrRecentlyMoved = Rs2Player.isMoving() - || (lastMovedTimeMs > 0 && System.currentTimeMillis() - lastMovedTimeMs < 2000); - if (movingOrRecentlyMoved) { + // Avoid mid-walk recalculation while recent clicks, route progress, or busy state + // indicate the player may still be advancing. isStuckTooLong() will trigger a + // real recovery path once progress actually halts. + String deferReason = currentOffPathRecalcDeferralReason(lastAttemptedMinimapClickAtMs); + if (deferReason != null) { + Telemetry.recordOffPathRecalcDeferred(deferReason, playerForPathCheck, target, path.size()); if (lastTransportHandledAtMs > 0 && System.currentTimeMillis() - lastTransportHandledAtMs <= POST_TRANSPORT_PATH_TMARK_WINDOW_MS) { WebWalkLog.tmark("post_transport_offpath_moving_yield", System.currentTimeMillis() - lastTransportHandledAtMs, target, playerForPathCheck, - "movingRecent=true"); + "defer=" + deferReason); } - exitReason = "off-path-but-moving"; + exitReason = "off-path-deferred:" + deferReason; break; } Telemetry.recordOffPathRecalc(Rs2Player.getWorldLocation(), path.size()); @@ -1543,15 +1612,28 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { && !isDoorInteractionSettling() && !isRecoveryMovementInFlight() && reachableTilesCache.containsKey(currentWorldPoint); - if (skipPostTransportSegmentHandlers) { + boolean skipStartupPreclickSegmentHandlers = shouldSkipStartupPreclickSegmentHandlers( + currentWalkerPhase() == WalkerPhase.STARTUP, + i, + indexOfStartPoint, + recentDoorAttemptNearSegment, + isDoorInteractionSettling(), + isRecoveryMovementInFlight()); + if (skipPostTransportSegmentHandlers || skipStartupPreclickSegmentHandlers) { + if (skipStartupPreclickSegmentHandlers) { + markStartupPhase("preclick_segment_handler_skip", target, + "i=" + i + " reason=startup_preclick_budget"); + } tmarkPostTransport("post_transport_segment_handler_skip", target, - "i=" + i + " reason=no_nearby_planned_transport"); + "i=" + i + " reason=" + (skipPostTransportSegmentHandlers + ? "no_nearby_planned_transport" + : "startup_preclick_budget")); } else { long segmentHandlerStartAt = System.currentTimeMillis(); int rawI = (i < smoothedToRaw.length) ? smoothedToRaw[i] : 0; int rawEnd = rawEndForSmoothedIndex(i, smoothedToRaw, rawPath, path); - if (!isDoorInteractionSettling() && !isRecoveryMovementInFlight()) { + if (!Rs2Player.isMoving() && !isDoorInteractionSettling() && !isRecoveryMovementInFlight()) { doorOrTransportResult = handleDoorsInRawSegment(rawPath, rawI, rawEnd, obstaclePolicy.segmentDoorTimeoutMs(), doorEdgesAttemptedThisTail, reachableTilesCache); @@ -1677,6 +1759,14 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { exitReason = "door-traversal-pending-yield"; break; } + if (shouldYieldForActiveRecoveryInterim(playerLoc, path, System.currentTimeMillis())) { + exitReason = "interim-in-flight"; + break; + } + if (tryRecentDoorAttemptEdgeNudge(playerLoc, target)) { + exitReason = "recent-door-edge-nudge"; + break; + } if (handlePendingDoorNearRawPath(rawPath, obstaclePolicy.unreachableDoorTimeoutMs(), doorEdgesAttemptedThisTail, playerLoc, 2, 14)) { exitReason = "door-handled-unreachable-raw-scan"; @@ -1697,6 +1787,17 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { UNREACHABLE_DOOR_RECOVERY_BACKTRACK_EDGES, UNREACHABLE_DOOR_RECOVERY_LOOKAHEAD_EDGES, HANDLER_RANGE); + if (!gateDoorInteraction + && unresolvedDoorNearRawPath + && handleUnresolvedDoorNearRawPath(rawPath, rawEdgeStart, + obstaclePolicy.unreachableDoorTimeoutMs(), doorEdgesAttemptedThisTail, + playerLoc, + UNREACHABLE_DOOR_RECOVERY_BACKTRACK_EDGES, + UNREACHABLE_DOOR_RECOVERY_LOOKAHEAD_EDGES, + HANDLER_RANGE)) { + exitReason = "door-handled-nearby-route-door"; + break; + } // Fallback: only interact with objects on/adjacent to blocked path edges // within ~15 tiles. Prevents clicking already-open / unrelated doors. final long nowMs = System.currentTimeMillis(); @@ -1726,27 +1827,27 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { // like a human clicking the furthest visible tile. We trust the server path // (no reachability gate on the click); isKnownWalkableOrUnloaded only keeps // us from clicking into a known wall, it is NOT the bounded BFS check. - final int RECOVERY_MINIMAP_REACH_EUCLIDEAN = 13; + final int recoveryMinimapReach = STALL_RECOVERY_MINIMAP_REACH_EUCLIDEAN; int recoverIdx = findForwardReachableRecoveryIndex(path, i, playerLoc, - RECOVERY_MINIMAP_REACH_EUCLIDEAN); + recoveryMinimapReach); if (recoverIdx < 0) { recoverIdx = findFurthestClickableIndex(path, i, playerLoc, wp -> { Set ts = ShortestPathPlugin.getTransports().get(wp); return ts != null && !ts.isEmpty(); }, - RECOVERY_MINIMAP_REACH_EUCLIDEAN); + recoveryMinimapReach); } int minRecoveryIdx = Math.max(indexOfStartPoint, i); recoverIdx = Math.min(Math.max(recoverIdx, minRecoveryIdx), path.size() - 1); WorldPoint recoverTarget = path.get(recoverIdx); if (euclideanSq(recoverTarget, playerLoc) - > RECOVERY_MINIMAP_REACH_EUCLIDEAN * RECOVERY_MINIMAP_REACH_EUCLIDEAN) { + > recoveryMinimapReach * recoveryMinimapReach) { // Furthest in-range path tile still beyond the minimap clip (e.g. a // diagonal segment). Interpolate a point near the minimap edge toward // path[i]; the server routes through whatever blocks line-of-sight. recoverTarget = interpolateClickableTarget(path, i, playerLoc, - path.get(i), RECOVERY_MINIMAP_REACH_EUCLIDEAN - 1, + path.get(i), recoveryMinimapReach - 1, wp -> inInstance || isKnownWalkableOrUnloaded(wp)); } // Don't let recovery park the player on a tile next to an aggressive NPC @@ -1764,9 +1865,24 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { recoverIdx = safeIdx; recoverTarget = path.get(safeIdx); } - boolean clicked = recoverTarget != null - && !recoverTarget.equals(playerLoc) - && Rs2Walker.walkMiniMap(recoverTarget); + int rawAnchorIndex = rawIndexForSmoothedIndex(recoverIdx, smoothedToRaw, rawPath); + WorldPoint rawRecoveryTarget = findFurthestReachableRawPathPoint(rawPath, playerLoc, + recoveryMinimapReach - 1, rawAnchorIndex); + if (rawRecoveryTarget != null + && !rawRecoveryTarget.equals(playerLoc) + && (dangerCfg == null + || !dangerCfg.isAvoidDangerousNpcs() + || !dangerCfg.isDangerousAdjacentTile(WorldPointUtil.packWorldPoint(rawRecoveryTarget)))) { + recoverTarget = rawRecoveryTarget; + } + WorldPoint clickedRecoveryTarget = null; + if (recoverTarget != null && !recoverTarget.equals(playerLoc)) { + recoverTarget = clampToEuclideanRadius(playerLoc, recoverTarget, + recoveryMinimapReach - 1); + clickedRecoveryTarget = clickMiniMapOrFallback(rawPath, recoverTarget, playerLoc, + recoveryMinimapReach - 1, rawPath == null || rawPath.isEmpty(), rawAnchorIndex); + } + boolean clicked = clickedRecoveryTarget != null; // Scene-click fallback only on final-adjacent approach (minimap click may // miss the clip when very close); kept gated on reachability since it is a // last resort, not the primary recovery path. @@ -1777,23 +1893,28 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { && Rs2Tile.isTileReachable(recoverTarget) && walkFastCanvas(recoverTarget)) { clicked = true; + clickedRecoveryTarget = recoverTarget; log.debug("[Walker] unreachable recovery: scene click -> {}", recoverTarget); } log.info("[Walker] unreachable optimistic recovery: clicked={} to={} pathTile={} idx={}", - clicked, recoverTarget, currentWorldPoint, recoverIdx); + clicked, clicked ? clickedRecoveryTarget : recoverTarget, currentWorldPoint, recoverIdx); if (clicked) { markFirstMovementClick("first_recovery_click", target, playerLoc, - "to=" + compactWorldPoint(recoverTarget)); + "to=" + compactWorldPoint(clickedRecoveryTarget)); lastUnreachableRecoveryClickAtMs = System.currentTimeMillis(); // Sticky interim: subsequent iterations travel toward this point via the // interim-in-flight path instead of re-running the (false-negative) // reachability check and re-clicking every tick. - interimTargetWp = recoverTarget; + interimTargetWp = clickedRecoveryTarget; interimTargetIdx = recoverIdx; interimSetAtMs = System.currentTimeMillis(); + interimLastProgressAtMs = interimSetAtMs; + interimLastBestPathIdx = getClosestTileIndex(path, playerLoc); + interimLastDistanceToTarget = distanceToInterimOrMax(clickedRecoveryTarget, playerLoc); + interimLastRetargetAtMs = interimSetAtMs; WorldPoint pathLastRecovery = path.get(path.size() - 1); int finishThRecovery = tightFinishThreshold(target, pathLastRecovery, distance); - waitUntilIdleAfterSceneWalk(target, POST_SCENE_WALK_IDLE_WAIT_MS_MAX, target, + waitForMovementStartAfterRecovery(target, playerLoc, clickedRecoveryTarget, target, finishThRecovery); // Next outer iteration runs checkIfStuck/isStuckTooLong before tile delta — avoid // spurious stall-recalc right after issuing recovery movement. @@ -1826,8 +1947,8 @@ && walkFastCanvas(recoverTarget)) { // Minimap clickable area is a circle, so reach is a Euclidean radius — // cardinal tiles reach ~13, diagonals ~9. Empirically 14 was too // optimistic (clicks at 13.5–13.9 Euclidean missed the clip). - final int MINIMAP_REACH_EUCLIDEAN = NORMAL_MINIMAP_REACH_EUCLIDEAN; WorldPoint playerLoc = Rs2Player.getWorldLocation(); + final int MINIMAP_REACH_EUCLIDEAN = NORMAL_MINIMAP_REACH_EUCLIDEAN; // Checkpoint-style walking: once we set a minimap flag, let the player actually // travel toward it. Do not keep recalculating/clicking new targets mid-run. @@ -1848,6 +1969,7 @@ && walkFastCanvas(recoverTarget)) { interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; doorOrTransportResult = true; exitReason = "door-handled-during-interim"; @@ -1859,17 +1981,20 @@ && walkFastCanvas(recoverTarget)) { || !Rs2Player.isMoving(), INTERIM_MOVING_POLL_MS); WorldPoint posAfterWait = Rs2Player.getWorldLocation(); + recordInterimDistanceProgress(interimFinal, posAfterWait, System.currentTimeMillis()); if ((posAfterWait != null && posBeforeWait.distanceTo2D(posAfterWait) > 0) || Rs2Player.isMoving()) { lastMovedTimeMs = System.currentTimeMillis(); stuckCount = 0; } - boolean readyForNextClick = posAfterWait != null - && interimFinal.distanceTo2D(posAfterWait) <= interimPreclickTiles(); - if (!readyForNextClick && Rs2Player.isMoving()) { + boolean closeEnoughForNextClick = posAfterWait != null + && interimFinal.distanceTo2D(posAfterWait) <= INTERIM_CLOSE_TILES; + if (!closeEnoughForNextClick && Rs2Player.isMoving()) { exitReason = "interim-in-flight"; walkerDiag("interim-in-flight interim=%s interimDist=%d player=%s moving=true", - interimFinal, interimDist, playerLoc); + interimFinal, + posAfterWait == null ? interimDist : interimFinal.distanceTo2D(posAfterWait), + posAfterWait == null ? playerLoc : posAfterWait); break; } } else { @@ -1881,6 +2006,7 @@ && walkFastCanvas(recoverTarget)) { interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; } } @@ -1890,34 +2016,21 @@ && walkFastCanvas(recoverTarget)) { interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; } - int targetIdx = findFurthestClickableIndex(path, i, playerLoc, + int targetIdx = findFurthestForwardClickableIndex(path, i, playerLoc, wp -> { Set ts = ShortestPathPlugin.getTransports().get(wp); return ts != null && !ts.isEmpty(); }, MINIMAP_REACH_EUCLIDEAN); WorldPoint targetWp = path.get(targetIdx); - // Forward waypoint out of minimap reach (e.g., diagonal PathSmoother - // segment at Chebyshev 10 = Euclidean 14.1). Backward-scan returns - // the previous in-reach waypoint, but clicking it walks backward or - // barely advances. Instead, interpolate a point close to the minimap - // edge toward the forward waypoint — the server's walk-here - // pathfinder routes through whatever is blocking line-of-sight - // (door, gate, diagonal offset). Each interpolated click covers - // ~12 tiles, matching a human clicking the furthest visible tile. - if (targetIdx < i) { - targetWp = interpolateClickableTarget( - path, - i, - playerLoc, - targetWp, - MINIMAP_REACH_EUCLIDEAN - 1, - wp -> inInstance || isKnownWalkableOrUnloaded(wp)); - targetIdx = Math.max(indexOfStartPoint, i - 1); - } else if (euclideanSq(targetWp, playerLoc) > MINIMAP_REACH_EUCLIDEAN * MINIMAP_REACH_EUCLIDEAN) { + // If the forward waypoint is outside minimap reach, interpolate a + // visible point in that direction instead of falling back to an + // earlier path tile. + if (euclideanSq(targetWp, playerLoc) > MINIMAP_REACH_EUCLIDEAN * MINIMAP_REACH_EUCLIDEAN) { targetWp = interpolateClickableTarget( path, i, @@ -1934,17 +2047,19 @@ && walkFastCanvas(recoverTarget)) { WorldPoint sticky = interimTargetWp; if (sticky != null && sticky.getPlane() == playerLoc.getPlane()) { int stickyDist = sticky.distanceTo2D(playerLoc); + recordInterimDistanceProgress(sticky, playerLoc, nowMs); if (stickyDist <= INTERIM_CLOSE_TILES || nowMs - interimSetAtMs > INTERIM_MAX_AGE_MS) { interimTargetWp = null; interimTargetIdx = -1; interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; } else { // U-turn safe progress: track progress along the path index, not Euclidean // distance-to-target (which can increase on U-shaped routes). - int bestIdxNow = getClosestTileIndex(path); + int bestIdxNow = getClosestTileIndex(path, playerLoc); if (bestIdxNow > interimLastBestPathIdx) { interimLastBestPathIdx = bestIdxNow; interimLastProgressAtMs = nowMs; @@ -1969,10 +2084,11 @@ && walkFastCanvas(recoverTarget)) { WorldPoint posBefore = playerLoc; WorldPoint clickTarget = inInstance ? targetWp : getPointWithWallDistance(targetWp); - if (!inInstance && !Rs2Tile.isTileReachable(clickTarget)) { + if (!inInstance) { + int rawAnchorIndex = rawIndexForSmoothedIndex(i, smoothedToRaw, rawPath); WorldPoint rawReachableTarget = findFurthestReachableRawPathPoint(rawPath, playerLoc, - MINIMAP_REACH_EUCLIDEAN - 1); - if (rawReachableTarget != null) { + MINIMAP_REACH_EUCLIDEAN - 1, rawAnchorIndex); + if (!Rs2Tile.isTileReachable(clickTarget) && rawReachableTarget != null) { targetWp = rawReachableTarget; clickTarget = rawReachableTarget; } @@ -1984,6 +2100,7 @@ && walkFastCanvas(recoverTarget)) { exitReason = "door-handled-before-minimap-click"; break; } + clickTarget = clampToEuclideanRadius(playerLoc, clickTarget, MINIMAP_REACH_EUCLIDEAN - 1); long nowBeforeClick = System.currentTimeMillis(); if (lastTransportHandledAtMs > 0 && nowBeforeClick - lastTransportHandledAtMs <= POST_TRANSPORT_PATH_TMARK_WINDOW_MS) { @@ -1994,27 +2111,25 @@ && walkFastCanvas(recoverTarget)) { "to=" + compactWorldPoint(clickTarget)); } markStartupPhase("click_candidate_found", target, "to=" + compactWorldPoint(clickTarget)); - boolean clicked = Rs2Walker.walkMiniMap(clickTarget); - if (!clicked) { - clicked = walkRawPathMiniMapToward(rawPath, clickTarget, playerLoc, MINIMAP_REACH_EUCLIDEAN - 1); - if (!clicked && (rawPath == null || rawPath.isEmpty())) { - clicked = walkMiniMapToward(clickTarget, playerLoc, MINIMAP_REACH_EUCLIDEAN - 1); - } - } + int rawAnchorIndex = rawIndexForSmoothedIndex(i, smoothedToRaw, rawPath); + WorldPoint clickedTarget = clickMiniMapOrFallback(rawPath, clickTarget, playerLoc, + MINIMAP_REACH_EUCLIDEAN - 1, rawPath == null || rawPath.isEmpty(), rawAnchorIndex); + boolean clicked = clickedTarget != null; if (walkCancelledDiag(target, "processWalk:after-minimap-click", processWalkTail)) { return WalkerState.EXIT; } - lastAttemptedMinimapClick = targetWp; + lastAttemptedMinimapClick = clicked ? clickedTarget : clickTarget; lastAttemptedMinimapClickOk = clicked; lastAttemptedMinimapClickAtMs = nowMs; if (clicked) { markFirstMovementClick("first_minimap_click", target, posBefore, - "to=" + compactWorldPoint(clickTarget)); - interimTargetWp = targetWp; + "to=" + compactWorldPoint(clickedTarget)); + interimTargetWp = clickedTarget; interimTargetIdx = targetIdx; interimSetAtMs = nowMs; interimLastProgressAtMs = nowMs; - interimLastBestPathIdx = getClosestTileIndex(path); + interimLastBestPathIdx = getClosestTileIndex(path, posBefore); + interimLastDistanceToTarget = distanceToInterimOrMax(clickedTarget, posBefore); interimLastRetargetAtMs = nowMs; final WorldPoint b = targetWp; @@ -2037,8 +2152,23 @@ && walkFastCanvas(recoverTarget)) { return before.distanceTo2D(now) >= progressCap; }, 1200); WorldPoint afterClickWait = Rs2Player.getWorldLocation(); + boolean routeRetryClicked = false; + if (afterClickWait != null && afterClickWait.equals(before) && !Rs2Player.isMoving()) { + WorldPoint routeRetryTarget = clickMiniMapOrFallback(rawPath, b, before, + MINIMAP_REACH_EUCLIDEAN - 1, false, rawAnchorIndex); + if (routeRetryTarget != null) { + routeRetryClicked = true; + lastAttemptedMinimapClick = routeRetryTarget; + lastAttemptedMinimapClickOk = true; + lastAttemptedMinimapClickAtMs = System.currentTimeMillis(); + interimTargetWp = routeRetryTarget; + interimLastProgressAtMs = lastAttemptedMinimapClickAtMs; + interimLastDistanceToTarget = distanceToInterimOrMax(routeRetryTarget, before); + interimLastRetargetAtMs = lastAttemptedMinimapClickAtMs; + } + } if (afterClickWait != null && afterClickWait.equals(before) && !Rs2Player.isMoving() - && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { + && routeRetryClicked) { sleepUntil(() -> { if (isWalkCancelled(target)) return true; WorldPoint now = Rs2Player.getWorldLocation(); @@ -2079,6 +2209,7 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; sleepUntil(() -> isWalkCancelled(target) || !Rs2Player.isMoving(), 1200); if (walkCancelledDiag(target, "processWalk:after-click-failed-wait", processWalkTail)) { @@ -2124,8 +2255,8 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { } // Only do the final-tile canvas click if we iterated the whole path cleanly. - // Exiting because the player left the path ("off-path-but-moving"/"not-near-path") - // means the player is still walking somewhere else — don't clobber that destination. + // Exiting because the player left the path may still mean movement is active. + // so don't clobber that destination. if (!doorOrTransportResult && "end-of-path".equals(exitReason)) { if (walkCancelledDiag(target, "processWalk:before-final-canvas", processWalkTail)) { return WalkerState.EXIT; @@ -2148,7 +2279,16 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { if (Rs2Tile.isTileReachable(finalTile) && Rs2Player.getWorldLocation().distanceTo(finalTile) >= finishTh) { final WorldPoint canvasClickWp = finalTile; - if (Rs2Walker.walkFastCanvas(canvasClickWp)) { + WorldPoint finalPlayerLoc = Rs2Player.getWorldLocation(); + boolean finalClick; + if (rawPath != null && !rawPath.isEmpty() && finalPlayerLoc != null) { + int rawAnchorIndex = rawAnchorIndexForPathPosition(rawPath, path, finalPlayerLoc); + finalClick = clickRouteBackedShortWalk(rawPath, canvasClickWp, finalPlayerLoc, + NORMAL_MINIMAP_REACH_EUCLIDEAN - 1, rawAnchorIndex); + } else { + finalClick = Rs2Walker.walkFastCanvas(canvasClickWp); + } + if (finalClick) { waitUntilIdleAfterSceneWalk(target, POST_SCENE_WALK_IDLE_WAIT_MS_MAX, target, finishTh); if (walkCancelledDiag(target, "processWalk:after-final-canvas-wait", processWalkTail)) { return WalkerState.EXIT; @@ -2180,10 +2320,16 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { setTarget(null, "rs2walker:processWalk:partial-retries-exhausted"); return WalkerState.UNREACHABLE; } else { - if ("off-path-but-moving".equals(exitReason)) { - // Wait for the player to re-enter the path or to stop moving. Prevents a tight - // recursion loop that would spin on isNearPath() while the player is walking. - long offPathWaitMs = 2000L; + if (isOffPathRecalcDeferredExit(exitReason)) { + // Wait briefly for the player to re-enter the path or for the progress signal + // that deferred the recalc to expire. Prevents a tight loop around isNearPath(). + String deferReason = offPathDeferredReasonFromExit(exitReason); + long offPathWaitMs = offPathRecalcDeferredWaitMs(deferReason, + System.currentTimeMillis(), + lastMovedTimeMs, + routeProgressAdvancedAtMs, + lastAttemptedMinimapClickAtMs, + interimLastProgressAtMs); long now = System.currentTimeMillis(); if (lastTransportHandledAtMs > 0 && now - lastTransportHandledAtMs <= POST_TRANSPORT_PATH_TMARK_WINDOW_MS) { @@ -2196,6 +2342,7 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { } } if (offPathWaitMs > 0) { + final long deferredLastClickAtMs = lastAttemptedMinimapClickAtMs; if (lastTransportHandledAtMs > 0 && System.currentTimeMillis() - lastTransportHandledAtMs <= POST_TRANSPORT_PATH_TMARK_WINDOW_MS) { WebWalkLog.tmark("post_transport_offpath_sleep", @@ -2204,7 +2351,9 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { Rs2Player.getWorldLocation(), "ms=" + offPathWaitMs); } - sleepUntil(() -> isWalkCancelled(target) || isNearPath() || !Rs2Player.isMoving(), + sleepUntil(() -> isWalkCancelled(target) + || isNearPath() + || currentOffPathRecalcDeferralReason(deferredLastClickAtMs) == null, (int) offPathWaitMs); } if (walkCancelledDiag(target, "processWalk:after-off-path-wait", processWalkTail)) { @@ -2213,7 +2362,9 @@ && walkReachableMiniMapToward(b, before, MINIMAP_REACH_EUCLIDEAN - 1)) { } // Benign yields: outer for-loop increments processWalkTail each iteration; exempt so // long minimap interim waits cannot exhaust MAX_PROCESS_WALK_TAIL_ITERATIONS and EXIT. - if ("interim-in-flight".equals(exitReason) || "off-path-but-moving".equals(exitReason)) { + if ("interim-in-flight".equals(exitReason) + || "recovery-move-in-flight".equals(exitReason) + || isOffPathRecalcDeferredExit(exitReason)) { walkerDiag("tail exempt exitReason=%s tailBefore=%d", exitReason, processWalkTail); processWalkTail--; } @@ -2488,15 +2639,55 @@ private static boolean walkRawPathMiniMapToward(List rawPath, WorldPoint target, WorldPoint playerLoc, int maxEuclidean) { - WorldPoint fallback = findFurthestVisibleReachableRawPathPoint(rawPath, playerLoc, maxEuclidean); + return walkRawPathMiniMapTargetToward(rawPath, target, playerLoc, maxEuclidean, -1) != null; + } + + private static WorldPoint clickMiniMapOrFallback(List rawPath, + WorldPoint target, + WorldPoint playerLoc, + int maxEuclidean, + boolean allowDirectionalFallback) { + return clickMiniMapOrFallback(rawPath, target, playerLoc, maxEuclidean, allowDirectionalFallback, -1); + } + + private static WorldPoint clickMiniMapOrFallback(List rawPath, + WorldPoint target, + WorldPoint playerLoc, + int maxEuclidean, + boolean allowDirectionalFallback, + int rawAnchorIndex) { + if (target == null || playerLoc == null || target.equals(playerLoc)) { + return null; + } + if (walkMiniMap(target)) { + return target; + } + WorldPoint rawFallback = walkRawPathMiniMapTargetToward(rawPath, target, playerLoc, + maxEuclidean, rawAnchorIndex); + if (rawFallback != null) { + return rawFallback; + } + if (allowDirectionalFallback && walkMiniMapToward(target, playerLoc, maxEuclidean)) { + return target; + } + return null; + } + + private static WorldPoint walkRawPathMiniMapTargetToward(List rawPath, + WorldPoint target, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex) { + WorldPoint fallback = findFurthestVisibleReachableRawPathPoint(rawPath, playerLoc, + maxEuclidean, rawAnchorIndex); if (fallback == null || fallback.equals(playerLoc) || fallback.equals(target)) { - return false; + return null; } if (walkMiniMap(fallback)) { log.info("[Walker] Minimap click target {} was outside clip; used route fallback {}", target, fallback); - return true; + return fallback; } - return false; + return null; } static boolean walkMiniMapToward(WorldPoint target, WorldPoint playerLoc, int maxEuclidean) { @@ -2559,18 +2750,27 @@ && euclideanSq(tile, target) < currentDistance) .orElse(false); } - private static WorldPoint findFurthestReachableRawPathPoint(List rawPath, - WorldPoint playerLoc, - int maxEuclidean) { + static WorldPoint findFurthestReachableRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean) { + return findFurthestReachableRawPathPoint(rawPath, playerLoc, maxEuclidean, -1); + } + + static WorldPoint findFurthestReachableRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex) { if (rawPath == null || rawPath.isEmpty() || playerLoc == null) { return null; } - int closestRawIndex = getClosestTileIndex(rawPath); + int closestRawIndex = rawPathForwardAnchorIndex(rawPath, playerLoc, rawAnchorIndex); if (closestRawIndex < 0) { return null; } int maxSq = maxEuclidean * maxEuclidean; + int maxRouteSteps = maxEuclidean + 2; + int routeSteps = 0; Set reachable = Rs2Tile.getReachableTilesFromTile(playerLoc, Math.max(2, maxEuclidean)).keySet(); WorldPoint best = null; for (int rawIndex = closestRawIndex; rawIndex < rawPath.size(); rawIndex++) { @@ -2578,6 +2778,13 @@ private static WorldPoint findFurthestReachableRawPathPoint(List raw if (candidate == null || candidate.getPlane() != playerLoc.getPlane()) { break; } + if (rawIndex > closestRawIndex) { + WorldPoint previous = rawPath.get(rawIndex - 1); + routeSteps += rawPathStepDistance(previous, candidate); + if (routeSteps > maxRouteSteps) { + break; + } + } if (euclideanSq(candidate, playerLoc) > maxSq) { break; } @@ -2588,18 +2795,27 @@ private static WorldPoint findFurthestReachableRawPathPoint(List raw return best; } - private static WorldPoint findFurthestVisibleReachableRawPathPoint(List rawPath, - WorldPoint playerLoc, - int maxEuclidean) { + static WorldPoint findFurthestVisibleReachableRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean) { + return findFurthestVisibleReachableRawPathPoint(rawPath, playerLoc, maxEuclidean, -1); + } + + static WorldPoint findFurthestVisibleReachableRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex) { if (rawPath == null || rawPath.isEmpty() || playerLoc == null) { return null; } - int closestRawIndex = getClosestTileIndex(rawPath); + int closestRawIndex = rawPathForwardAnchorIndex(rawPath, playerLoc, rawAnchorIndex); if (closestRawIndex < 0) { return null; } int maxSq = maxEuclidean * maxEuclidean; + int maxRouteSteps = maxEuclidean + 2; + int routeSteps = 0; Set reachable = Rs2Tile.getReachableTilesFromTile(playerLoc, Math.max(2, maxEuclidean)).keySet(); WorldPoint best = null; for (int rawIndex = closestRawIndex; rawIndex < rawPath.size(); rawIndex++) { @@ -2607,6 +2823,13 @@ private static WorldPoint findFurthestVisibleReachableRawPathPoint(List closestRawIndex) { + WorldPoint previous = rawPath.get(rawIndex - 1); + routeSteps += rawPathStepDistance(previous, candidate); + if (routeSteps > maxRouteSteps) { + break; + } + } if (euclideanSq(candidate, playerLoc) > maxSq) { break; } @@ -2619,6 +2842,45 @@ && isMiniMapClickable(candidate, 5)) { return best; } + private static int rawPathStepDistance(WorldPoint previous, WorldPoint current) { + if (previous == null || current == null || previous.getPlane() != current.getPlane()) { + return Integer.MAX_VALUE / 4; + } + return Math.max(1, previous.distanceTo2D(current)); + } + + static int rawPathForwardAnchorIndex(List rawPath, WorldPoint playerLoc, int rawAnchorIndex) { + if (rawPath == null || rawPath.isEmpty() || playerLoc == null) { + return -1; + } + if (rawAnchorIndex < 0) { + return getClosestTileIndex(rawPath, playerLoc); + } + + int start = Math.max(0, Math.min(rawAnchorIndex, rawPath.size() - 1)); + int endExclusive = Math.min(rawPath.size(), start + ROUTE_PROGRESS_FORWARD_SEARCH_TILES + 1); + int bestIdx = -1; + int bestDist = Integer.MAX_VALUE; + for (int i = start; i < endExclusive; i++) { + WorldPoint point = rawPath.get(i); + if (point == null) { + continue; + } + if (point.getPlane() != playerLoc.getPlane()) { + break; + } + int dist = point.distanceTo2D(playerLoc); + if (dist < bestDist) { + bestIdx = i; + bestDist = dist; + if (dist == 0) { + break; + } + } + } + return bestIdx >= 0 ? bestIdx : start; + } + private static boolean shouldIssueActiveRouteIdleNudge() { WorldPoint playerLoc = Rs2Player.getWorldLocation(); long now = System.currentTimeMillis(); @@ -2658,7 +2920,7 @@ private static boolean tryIssueRouteContinuationClick(List rawPath, return false; } if (rawPath != null && !rawPath.isEmpty()) { - int rawIdx = getClosestTileIndex(rawPath); + int rawIdx = getClosestTileIndex(rawPath, playerLoc); if (rawIdx >= 0 && hasUnresolvedDoorLikeObjectNearRawPath(rawPath, rawIdx, playerLoc, @@ -2668,7 +2930,7 @@ private static boolean tryIssueRouteContinuationClick(List rawPath, return false; } } - int pathIdx = Math.max(0, getClosestTileIndex(path)); + int pathIdx = Math.max(0, getClosestTileIndex(path, playerLoc)); if (hasUpcomingNearbyTransportStep(path, pathIdx, playerLoc, POST_TRANSPORT_RAW_SCAN_TRANSPORT_LOOKAHEAD_EDGES, POST_TRANSPORT_RAW_SCAN_TRANSPORT_MAX_DIST)) { @@ -2688,15 +2950,18 @@ private static boolean tryIssueRouteMovementClick(List rawPath, if (playerLoc == null || path == null || path.isEmpty()) { return false; } + int targetIdx = stabilizeRouteProgressIndex(path, getClosestTileIndex(path, playerLoc), target, playerLoc); + int[] routeSmoothedToRaw = mapSmoothedToRaw(path, rawPath); + int rawAnchorIndex = rawIndexForSmoothedIndex(targetIdx, routeSmoothedToRaw, rawPath); WorldPoint clickTarget = findFurthestReachableRawPathPoint( rawPath, playerLoc, - maxEuclidean); - int targetIdx = getClosestTileIndex(path); + maxEuclidean, + rawAnchorIndex); if (clickTarget == null) { int startIdx = Math.max(0, targetIdx); - int clickableIdx = findFurthestClickableIndex(path, startIdx, playerLoc, + int clickableIdx = findFurthestForwardClickableIndex(path, startIdx, playerLoc, wp -> { Set ts = ShortestPathPlugin.getTransports().get(wp); return ts != null && !ts.isEmpty(); @@ -2718,28 +2983,34 @@ private static boolean tryIssueRouteMovementClick(List rawPath, } boolean clicked = false; + WorldPoint clickedTarget = null; if (clickTarget != null && !clickTarget.equals(playerLoc)) { - clicked = walkMiniMap(clickTarget) - || walkRawPathMiniMapToward(rawPath, clickTarget, playerLoc, maxEuclidean - 1); - if (!clicked && (rawPath == null || rawPath.isEmpty())) { - clicked = walkMiniMapToward(clickTarget, playerLoc, maxEuclidean - 1); - } + clickTarget = clampToEuclideanRadius(playerLoc, clickTarget, maxEuclidean - 1); + clickedTarget = clickMiniMapOrFallback(rawPath, clickTarget, playerLoc, + maxEuclidean - 1, rawPath == null || rawPath.isEmpty(), rawAnchorIndex); + clicked = clickedTarget != null; + } + if (clicked && "interim close route click".equals(logLabel)) { + log.debug("[Walker] {}: clicked={} to={} player={} idx={}", + logLabel, true, clickedTarget, playerLoc, targetIdx); + } else { + log.info("[Walker] {}: clicked={} to={} player={} idx={}", + logLabel, clicked, clicked ? clickedTarget : clickTarget, playerLoc, targetIdx); } - log.info("[Walker] {}: clicked={} to={} player={} idx={}", - logLabel, clicked, clickTarget, playerLoc, targetIdx); if (!clicked) { return false; } - markFirstMovementClick("stall recovery click".equals(logLabel) ? "stall_recovery_click" : "active_route_idle_nudge", + markFirstMovementClick(routeMovementClickPhase(logLabel), target, playerLoc, - "to=" + compactWorldPoint(clickTarget)); - interimTargetWp = clickTarget; + "to=" + compactWorldPoint(clickedTarget)); + interimTargetWp = clickedTarget; interimTargetIdx = targetIdx; interimSetAtMs = System.currentTimeMillis(); interimLastProgressAtMs = interimSetAtMs; - interimLastBestPathIdx = getClosestTileIndex(path); + interimLastBestPathIdx = getClosestTileIndex(path, playerLoc); + interimLastDistanceToTarget = distanceToInterimOrMax(clickedTarget, playerLoc); interimLastRetargetAtMs = interimSetAtMs; if (markRecoveryCooldown) { lastUnreachableRecoveryClickAtMs = interimSetAtMs; @@ -2755,6 +3026,19 @@ private static boolean tryIssueRouteMovementClick(List rawPath, return true; } + static String routeMovementClickPhase(String logLabel) { + if ("stall recovery click".equals(logLabel)) { + return "stall_recovery_click"; + } + if ("active route idle nudge".equals(logLabel)) { + return "active_route_idle_nudge"; + } + if ("interim close route click".equals(logLabel)) { + return "interim_close_route_click"; + } + return "route_movement_click"; + } + /** * Used in instances like vorkath, jad, nmz * @@ -2782,6 +3066,46 @@ public static boolean walkFastCanvas(WorldPoint worldPoint) { return walkFastCanvas(worldPoint, true); } + private static boolean walkFastCanvasOnScreenOnly(WorldPoint worldPoint, boolean toggleRun) { + LocalPoint localPoint = localPointForWorld(worldPoint); + if (localPoint == null || !Rs2Camera.isTileOnScreen(localPoint)) { + return false; + } + Point canvasPoint = Perspective.localToCanvas( + Microbot.getClient(), + localPoint, + Microbot.getClient().getTopLevelWorldView().getPlane()); + int canvasX = canvasPoint != null ? canvasPoint.getX() : -1; + int canvasY = canvasPoint != null ? canvasPoint.getY() : -1; + if (canvasX < 0 || canvasY < 0) { + return false; + } + + Rs2Player.toggleRunEnergy(toggleRun); + NewMenuEntry entry = new NewMenuEntry() + .param0(canvasX) + .param1(canvasY) + .type(MenuAction.WALK) + .identifier(0) + .itemId(0) + .option("Walk here"); + + Microbot.doInvoke(entry, + new Rectangle(canvasX, canvasY, Microbot.getClient().getCanvasWidth(), Microbot.getClient().getCanvasHeight())); + return true; + } + + private static LocalPoint localPointForWorld(WorldPoint worldPoint) { + if (worldPoint == null) { + return null; + } + LocalPoint localPoint = LocalPoint.fromWorld(Microbot.getClient().getTopLevelWorldView(), worldPoint); + if (Microbot.getClient().getTopLevelWorldView().isInstance() && localPoint == null) { + localPoint = Rs2LocalPoint.fromWorldInstance(worldPoint); + } + return localPoint; + } + public static boolean walkFastCanvas(WorldPoint worldPoint, boolean toggleRun) { if (worldPoint == null) { log.debug("[Walker] walkFastCanvas rejected: null worldPoint"); @@ -3086,32 +3410,38 @@ public static List getTransportsForPath(List path, int in */ public static List getTransportsForPath(List path, int indexOfStartPoint, TransportType prefTransportType, boolean applyFiltering) { List transportList = new ArrayList<>(); + if (path == null || path.isEmpty() || indexOfStartPoint < 0 || indexOfStartPoint >= path.size()) { + return transportList; + } + Map pathFirstIndex = buildPathFirstIndex(path); + WorldPoint playerLoc = Rs2Player.getWorldLocation(); int currentIndex = indexOfStartPoint; // Loop through the path until the end while (currentIndex < path.size()) { WorldPoint currentPoint = path.get(currentIndex); // Get any transports that start at this point (or keyed by this point) - Set transportsAtPoint = ShortestPathPlugin.getTransports() - .getOrDefault(currentPoint, new HashSet<>()); + Set transportsAtPoint = ShortestPathPlugin.getTransports().get(currentPoint); + if (transportsAtPoint == null || transportsAtPoint.isEmpty()) { + currentIndex++; + continue; + } boolean foundTransport = false; // sort by type to prioritize teleportation items first, then other types - transportsAtPoint = transportsAtPoint.stream() - .sorted(Comparator.comparing(Transport::getType, (type1, type2) -> { - // sort teleportation items by preference transport type for the current path point. - - if (type1 == prefTransportType && type2 != prefTransportType) { - return -1; - } - if (type2 == prefTransportType && type1 != prefTransportType) { - return 1; - } - // For all other types, use natural enum ordering - return type1.compareTo(type2); - })) - .collect(Collectors.toCollection(LinkedHashSet::new)); + List orderedTransports = new ArrayList<>(transportsAtPoint); + orderedTransports.sort(Comparator.comparing(Transport::getType, (type1, type2) -> { + // sort teleportation items by preference transport type for the current path point. + if (type1 == prefTransportType && type2 != prefTransportType) { + return -1; + } + if (type2 == prefTransportType && type1 != prefTransportType) { + return 1; + } + // For all other types, use natural enum ordering + return type1.compareTo(type2); + })); // Iterate over each available transport - for (Transport transport : transportsAtPoint) { + for (Transport transport : orderedTransports) { // Special handling for teleportation-like transports (originless) // NOTE: Leagues "Area" teleports are injected as SEASONAL_TRANSPORT with null origin. @@ -3125,8 +3455,8 @@ public static List getTransportsForPath(List path, int in || isLeaguesAreaTeleport) { // For teleportation, we assume origin is null and simply check if the destination exists in the path. - int destIndex = path.indexOf(transport.getDestination()); - if (destIndex != -1) { + Integer destIndex = pathFirstIndex.get(transport.getDestination()); + if (destIndex != null) { transportList.add(transport); // Advance the current index to the destination tile (or at least one forward) currentIndex = destIndex > currentIndex ? destIndex : currentIndex + 1; @@ -3146,19 +3476,20 @@ public static List getTransportsForPath(List path, int in for (WorldPoint origin : originPoints) { // If an origin is defined but the player's plane doesn't match, skip it. - WorldPoint plTransportFilter = Rs2Player.getWorldLocation(); - if (transport.getOrigin() != null && plTransportFilter != null - && plTransportFilter.getPlane() != transport.getOrigin().getPlane()) { + if (transport.getOrigin() != null && playerLoc != null + && playerLoc.getPlane() != transport.getOrigin().getPlane()) { continue; } // For non-teleportation transports, ensure both origin and destination exist in the path // and that the destination comes after the origin. - int indexOfDestination = path.indexOf(transport.getDestination()); + Integer indexOfDestinationValue = pathFirstIndex.get(transport.getDestination()); + int indexOfDestination = indexOfDestinationValue != null ? indexOfDestinationValue : -1; if (transport.getType() != TransportType.TELEPORTATION_ITEM && transport.getType() != TransportType.TELEPORTATION_SPELL && !isLeaguesAreaTeleport) { - int indexOfOrigin = path.indexOf(transport.getOrigin()); + Integer indexOfOriginValue = pathFirstIndex.get(transport.getOrigin()); + int indexOfOrigin = indexOfOriginValue != null ? indexOfOriginValue : -1; if (indexOfOrigin == -1 || indexOfDestination == -1 || indexOfDestination < indexOfOrigin) { continue; } @@ -3192,6 +3523,14 @@ public static List getTransportsForPath(List path, int in return transportList; } + private static Map buildPathFirstIndex(List path) { + Map pathFirstIndex = new HashMap<>(path.size()); + for (int i = 0; i < path.size(); i++) { + pathFirstIndex.putIfAbsent(path.get(i), i); + } + return pathFirstIndex; + } + /** * Applies transport filtering and requirement setup for transport items. * This method filters transports to only include those that require items and @@ -3347,7 +3686,6 @@ private static WalkerState tryDirectShortWalk(WorldPoint target, if (!inInstance && localRouteDetoursFromComputedRoute(rawPath, end, directClickMaxDistance)) { return WalkerState.MOVING; } - long suppressUntil = suppressTryDirectShortWalkUntilMs; if (suppressUntil != 0L && System.currentTimeMillis() < suppressUntil) { log.debug("[Walker] defer tryDirectShortWalk minimap (post door canvas nudge, {}ms window)", @@ -3355,12 +3693,20 @@ private static WalkerState tryDirectShortWalk(WorldPoint target, return WalkerState.MOVING; } - boolean clicked = walkMiniMap(end); - if (!clicked) { - clicked = walkMiniMapToward(end, playerLoc, directClickMaxDistance - 1); - } - if (!clicked) { - clicked = walkFastCanvas(end); + boolean routeBacked = rawPath != null && !rawPath.isEmpty(); + int rawAnchorIndex = routeBacked ? rawAnchorIndexForPathPosition(rawPath, path, playerLoc) : -1; + boolean clicked; + if (routeBacked) { + clicked = clickRouteBackedShortWalk(rawPath, end, playerLoc, + directClickMaxDistance - 1, rawAnchorIndex); + } else { + clicked = walkMiniMap(end); + if (!clicked) { + clicked = walkMiniMapToward(end, playerLoc, directClickMaxDistance - 1); + } + if (!clicked) { + clicked = walkFastCanvas(end); + } } if (!clicked) { return WalkerState.MOVING; @@ -3373,7 +3719,14 @@ private static WalkerState tryDirectShortWalk(WorldPoint target, }, 800); if (!moved) { - clicked = walkFastCanvas(end); + WorldPoint retryPlayerLoc = Rs2Player.getWorldLocation(); + if (routeBacked && retryPlayerLoc != null) { + int retryRawAnchorIndex = rawPathForwardAnchorIndex(rawPath, retryPlayerLoc, rawAnchorIndex); + clicked = clickRouteBackedShortWalk(rawPath, end, retryPlayerLoc, + directClickMaxDistance - 1, retryRawAnchorIndex); + } else { + clicked = walkFastCanvas(end); + } if (!clicked) { return WalkerState.MOVING; } @@ -3403,6 +3756,28 @@ private static WalkerState tryDirectShortWalk(WorldPoint target, return WalkerState.MOVING; } + private static int rawAnchorIndexForPathPosition(List rawPath, + List path, + WorldPoint playerLoc) { + int closestPathIdx = getClosestTileIndex(path, playerLoc); + int[] smoothedToRaw = mapSmoothedToRaw(path, rawPath); + int rawAnchorIndex = rawIndexForSmoothedIndex(closestPathIdx, smoothedToRaw, rawPath); + return rawPathForwardAnchorIndex(rawPath, playerLoc, rawAnchorIndex); + } + + private static boolean clickRouteBackedShortWalk(List rawPath, + WorldPoint end, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex) { + WorldPoint clickedTarget = clickMiniMapOrFallback(rawPath, end, playerLoc, + maxEuclidean, false, rawAnchorIndex); + if (clickedTarget != null) { + return true; + } + return walkFastCanvasOnScreenOnly(end, true); + } + private static boolean hasPendingExplicitTransportStepBeforeArrival(List path, WorldPoint target, int distance) { @@ -3441,7 +3816,7 @@ private static boolean localRouteDetoursFromComputedRoute(List rawPa return false; } - int rawStart = getClosestTileIndex(rawPath); + int rawStart = getClosestTileIndex(rawPath, playerLoc); if (rawStart < 0 || rawStart >= rawPath.size() - 1) { return false; } @@ -3481,7 +3856,7 @@ private static boolean hasPendingDoorLikeSceneObjectBeforeDirectClick(List= route.size()) { return false; } @@ -3524,6 +3899,9 @@ private static boolean handlePendingDoorBeforeRouteClick(List rawPat || playerLoc == null || targetPathIdx < fromPathIdx) { return false; } + if (Rs2Player.isMoving()) { + return false; + } int rawStart = rawIndexForSmoothedIndex(fromPathIdx, smoothedToRaw, rawPath); int rawTarget = rawIndexForSmoothedIndex(targetPathIdx, smoothedToRaw, rawPath); @@ -3564,7 +3942,7 @@ private static boolean handlePendingDoorDuringInterim(List rawPath, WorldPoint playerLoc) { if (rawPath == null || rawPath.size() < 2 || playerLoc == null || isDoorInteractionSettling() || isDoorEdgePassSkipCoolingDown() - || isRecoveryMovementInFlight()) { + || isRecoveryMovementInFlight() || Rs2Player.isMoving()) { return false; } @@ -3580,8 +3958,11 @@ private static boolean handlePendingDoorNearRawPath(List rawPath, if (rawPath == null || rawPath.size() < 2 || playerLoc == null) { return false; } + if (Rs2Player.isMoving()) { + return false; + } - int rawStart = getClosestTileIndex(rawPath); + int rawStart = getClosestTileIndex(rawPath, playerLoc); if (rawStart < 0) { return false; } @@ -3613,6 +3994,45 @@ private static boolean handlePendingDoorNearRawPath(List rawPath, return false; } + private static boolean handleUnresolvedDoorNearRawPath(List rawPath, + int rawEdgeStart, + long timeoutMs, + Map attempted, + WorldPoint playerLoc, + int backtrackEdges, + int lookaheadEdges, + int radiusTiles) { + if (rawPath == null || rawPath.size() < 2 || rawEdgeStart < 0 || playerLoc == null || Rs2Player.isMoving()) { + return false; + } + + int start = Math.max(0, rawEdgeStart - Math.max(0, backtrackEdges)); + int endExclusive = Math.min(rawPath.size() - 1, rawEdgeStart + Math.max(1, lookaheadEdges)); + for (int ri = start; ri < endExclusive && ri < rawPath.size() - 1; ri++) { + WorldPoint from = rawPath.get(ri); + WorldPoint to = rawPath.get(ri + 1); + if (from == null || to == null) { + continue; + } + if (from.getPlane() != playerLoc.getPlane() || to.getPlane() != playerLoc.getPlane()) { + break; + } + if (from.distanceTo2D(playerLoc) > radiusTiles && to.distanceTo2D(playerLoc) > radiusTiles) { + continue; + } + if (isCatalogBackedTransportSegment(rawPath, ri) && !isDoorLikeCatalogTransportSegment(rawPath, ri)) { + continue; + } + if (!hasUnresolvedDoorLikeSceneObjectOnSegment(from, to, playerLoc, radiusTiles)) { + continue; + } + if (handleDoorsWithTimeout(rawPath, ri, timeoutMs, attempted, true)) { + return true; + } + } + return false; + } + private static int rawIndexForSmoothedIndex(int smoothedIdx, int[] smoothedToRaw, List rawPath) { if (rawPath == null || rawPath.isEmpty()) { return -1; @@ -3654,7 +4074,7 @@ private static boolean handleNearbyRawPathSceneObjects(List rawPath, return false; } - int rawStart = getClosestTileIndex(rawPath); + int rawStart = getClosestTileIndex(rawPath, playerLoc); if (rawStart < 0) { clearRawScanDoorFocus("raw-start-missing"); return false; @@ -3878,10 +4298,19 @@ private static void addForwardPathIndices(Map forwardIndex, return; } - int closestIndex = IntStream.range(0, path.size()) - .boxed() - .min(Comparator.comparingInt(i -> playerLoc.distanceTo(path.get(i)))) - .orElse(0); + int closestIndex = 0; + int closestDistance = Integer.MAX_VALUE; + for (int i = 0; i < path.size(); i++) { + WorldPoint point = path.get(i); + if (point == null) { + continue; + } + int distance = playerLoc.distanceTo(point); + if (distance < closestDistance) { + closestDistance = distance; + closestIndex = i; + } + } for (int i = closestIndex; i < path.size(); i++) { forwardIndex.putIfAbsent(path.get(i), i); } @@ -3895,6 +4324,9 @@ private static void addForwardPathIndices(Map forwardIndex, private static final long STATIONARY_DOOR_SUPPRESS_MS = 10_000; private static final Map recentDoorAttemptByEdge = new ConcurrentHashMap<>(); private static final long DOOR_ATTEMPT_EDGE_COOLDOWN_MS = 2_500; + private static volatile WorldPoint lastDoorAttemptFrom = null; + private static volatile WorldPoint lastDoorAttemptTo = null; + private static volatile long lastDoorAttemptAtMs = 0L; private static final Map recentCurrentTileTransportByEdge = new ConcurrentHashMap<>(); private static final long CURRENT_TILE_TRANSPORT_EDGE_COOLDOWN_MS = 2_200; private static final long DOOR_INTERACTION_GLOBAL_COOLDOWN_MS = 1_800; @@ -3971,6 +4403,25 @@ static int findFurthestClickableIndex(List path, int startIdx, World return bestIdx; } + static int findFurthestForwardClickableIndex(List path, int startIdx, WorldPoint playerLoc, + java.util.function.Predicate isTransportOrigin, + int maxEuclidean) { + if (path == null || startIdx < 0 || startIdx >= path.size()) return startIdx; + WorldPoint startWp = path.get(startIdx); + if (startWp == null) return startIdx; + final int maxSq = maxEuclidean * maxEuclidean; + + int bestIdx = startIdx; + for (int j = startIdx; j < path.size(); j++) { + WorldPoint candidate = path.get(j); + if (candidate == null || candidate.getPlane() != startWp.getPlane()) break; + if (j > startIdx && isTransportOrigin != null && isTransportOrigin.test(candidate)) break; + if (playerLoc != null && euclideanSq(candidate, playerLoc) > maxSq) break; + bestIdx = j; + } + return bestIdx; + } + private static int findForwardReachableRecoveryIndex(List path, int startIdx, WorldPoint playerLoc, @@ -4064,6 +4515,47 @@ static WorldPoint interpolateClickableTarget(List path, return fallbackWp; } + static WorldPoint clampToEuclideanRadius(WorldPoint playerLoc, WorldPoint target, int maxEuclidean) { + if (playerLoc == null || target == null || target.getPlane() != playerLoc.getPlane() || maxEuclidean <= 0) { + return target; + } + int maxSq = maxEuclidean * maxEuclidean; + if (euclideanSq(playerLoc, target) <= maxSq) { + return target; + } + + int dx = target.getX() - playerLoc.getX(); + int dy = target.getY() - playerLoc.getY(); + double distance = Math.sqrt(dx * dx + dy * dy); + if (distance <= 1) { + return target; + } + + double scale = maxEuclidean / distance; + int stepX = (int) Math.round(dx * scale); + int stepY = (int) Math.round(dy * scale); + if (stepX == 0 && stepY == 0) { + if (Math.abs(dx) >= Math.abs(dy)) { + stepX = Integer.signum(dx); + } else { + stepY = Integer.signum(dy); + } + } + + WorldPoint clamped = new WorldPoint(playerLoc.getX() + stepX, playerLoc.getY() + stepY, playerLoc.getPlane()); + while (!clamped.equals(playerLoc) && euclideanSq(playerLoc, clamped) > maxSq) { + if (Math.abs(stepX) >= Math.abs(stepY) && stepX != 0) { + stepX -= Integer.signum(stepX); + } else if (stepY != 0) { + stepY -= Integer.signum(stepY); + } else { + break; + } + clamped = new WorldPoint(playerLoc.getX() + stepX, playerLoc.getY() + stepY, playerLoc.getPlane()); + } + return clamped.equals(playerLoc) ? target : clamped; + } + private static int euclideanSq(WorldPoint a, WorldPoint b) { int dx = a.getX() - b.getX(); int dy = a.getY() - b.getY(); @@ -4333,6 +4825,11 @@ && isNullOrPlaceholderObjectName(comp.getName())) { compactWorldPoint(probe), compactWorldPoint(fromWp), compactWorldPoint(toWp)); return false; } + if (Rs2Player.isMoving()) { + WebWalkLog.spInfo("door_interact_deferred | reason=moving mode=segment-door probe={} from={} to={}", + compactWorldPoint(probe), compactWorldPoint(fromWp), compactWorldPoint(toWp)); + return false; + } markDoorAttempt(probe, fromWp, toWp); markGlobalDoorInteractionCooldown(); WorldPoint posBefore = Rs2Player.getWorldLocation(); @@ -4477,6 +4974,11 @@ private static boolean tryHandleDoorObject(TileObject object, WorldPoint probe, compactWorldPoint(probe), compactWorldPoint(fromWp), compactWorldPoint(toWp)); return false; } + if (Rs2Player.isMoving()) { + WebWalkLog.spInfo("door_interact_deferred | reason=moving mode=segment-probe probe={} from={} to={}", + compactWorldPoint(probe), compactWorldPoint(fromWp), compactWorldPoint(toWp)); + return false; + } markDoorAttempt(probe, fromWp, toWp); markGlobalDoorInteractionCooldown(); WorldPoint posBefore = Rs2Player.getWorldLocation(); @@ -4760,6 +5262,31 @@ private static boolean tryDoorEdgeCrossNudge(WorldPoint fromWp, WorldPoint toWp, return progressed; } + private static boolean tryRecentDoorAttemptEdgeNudge(WorldPoint playerLoc, WorldPoint target) { + WorldPoint from = lastDoorAttemptFrom; + WorldPoint to = lastDoorAttemptTo; + long attemptedAt = lastDoorAttemptAtMs; + if (playerLoc == null || from == null || to == null || attemptedAt <= 0L) { + return false; + } + long ageMs = System.currentTimeMillis() - attemptedAt; + if (ageMs < 0L || ageMs > POST_DOOR_NUDGE_RECENT_ATTEMPT_MS) { + return false; + } + if (playerLoc.getPlane() != to.getPlane() || playerLoc.distanceTo2D(to) > POST_DOOR_EDGE_NUDGE_MAX_FROM_PLAYER) { + return false; + } + if (Rs2Player.isMoving() || Rs2Player.isAnimating()) { + return false; + } + boolean nudged = tryDoorEdgeCrossNudge(from, to, target); + if (nudged) { + WebWalkLog.tmark("recent_door_edge_nudge", System.currentTimeMillis() - walkSessionStartedAtMs, + target, playerLoc, "from=" + compactWorldPoint(from) + " to=" + compactWorldPoint(to)); + } + return nudged; + } + static boolean isDoorEdgeNudgeResolved(WorldPoint before, WorldPoint after, WorldPoint fromWp, WorldPoint toWp) { if (before == null || after == null || fromWp == null || toWp == null) { return false; @@ -4803,8 +5330,7 @@ static boolean shouldClearInterimTarget(WorldPoint interim, if (playerLoc == null || playerLoc.getPlane() != interim.getPlane()) { return true; } - int preclickTiles = interimPreclickTiles(); - if (playerLoc.distanceTo2D(interim) <= preclickTiles) { + if (playerLoc.distanceTo2D(interim) <= INTERIM_CLOSE_TILES) { return true; } if (lastProgressAtMs > 0L && nowMs - lastProgressAtMs > INTERIM_PROGRESS_TIMEOUT_MS) { @@ -4813,12 +5339,59 @@ static boolean shouldClearInterimTarget(WorldPoint interim, return setAtMs > 0L && nowMs - setAtMs > INTERIM_MAX_AGE_MS; } + static int distanceToInterimOrMax(WorldPoint interim, WorldPoint playerLoc) { + if (interim == null || playerLoc == null || interim.getPlane() != playerLoc.getPlane()) { + return Integer.MAX_VALUE; + } + return playerLoc.distanceTo2D(interim); + } + + private static void recordInterimDistanceProgress(WorldPoint interim, WorldPoint playerLoc, long nowMs) { + int distance = distanceToInterimOrMax(interim, playerLoc); + if (distance < interimLastDistanceToTarget) { + interimLastDistanceToTarget = distance; + interimLastProgressAtMs = nowMs; + } + } + + private static void waitForMovementStartAfterRecovery(WorldPoint cancelGoal, + WorldPoint playerBefore, + WorldPoint interimGoal, + WorldPoint arrivalGoal, + int arrivalMaxChebyshev) { + if (cancelGoal == null || playerBefore == null) { + return; + } + sleepUntil(() -> { + if (isWalkCancelled(cancelGoal)) { + return true; + } + WorldPoint playerNow = Rs2Player.getWorldLocation(); + if (playerNow == null) { + return false; + } + if (!playerNow.equals(playerBefore) || Rs2Player.isMoving()) { + return true; + } + if (interimGoal != null + && interimGoal.getPlane() == playerNow.getPlane() + && playerNow.distanceTo2D(interimGoal) <= INTERIM_CLOSE_TILES) { + return true; + } + return arrivalGoal != null + && arrivalMaxChebyshev >= 0 + && arrivalGoal.getPlane() == playerNow.getPlane() + && playerNow.distanceTo2D(arrivalGoal) <= arrivalMaxChebyshev; + }, POST_RECOVERY_MOVEMENT_START_WAIT_MS); + } + private static boolean clearInterimTargetIfReachedOrExpired(WorldPoint playerLoc, List path, long nowMs) { WorldPoint interim = interimTargetWp; + recordInterimDistanceProgress(interim, playerLoc, nowMs); if (interim != null && path != null && !path.isEmpty()) { - int bestIdxNow = getClosestTileIndex(path); + int bestIdxNow = getClosestTileIndex(path, playerLoc); if (bestIdxNow > interimLastBestPathIdx) { interimLastBestPathIdx = bestIdxNow; interimLastProgressAtMs = nowMs; @@ -4830,7 +5403,7 @@ private static boolean clearInterimTargetIfReachedOrExpired(WorldPoint playerLoc String reason; if (playerLoc == null || interim == null || playerLoc.getPlane() != interim.getPlane()) { reason = "invalid"; - } else if (playerLoc.distanceTo2D(interim) <= interimPreclickTiles()) { + } else if (playerLoc.distanceTo2D(interim) <= INTERIM_CLOSE_TILES) { reason = "close"; } else if (interimLastProgressAtMs > 0L && nowMs - interimLastProgressAtMs > INTERIM_PROGRESS_TIMEOUT_MS) { reason = "stale-progress"; @@ -4841,16 +5414,72 @@ private static boolean clearInterimTargetIfReachedOrExpired(WorldPoint playerLoc return true; } + private static boolean shouldYieldForActiveRecoveryInterim(WorldPoint playerLoc, + List path, + long nowMs) { + WorldPoint interim = interimTargetWp; + if (interim == null) { + return false; + } + recordInterimDistanceProgress(interim, playerLoc, nowMs); + if (playerLoc != null && path != null && !path.isEmpty()) { + int bestIdxNow = getClosestTileIndex(path, playerLoc); + if (bestIdxNow > interimLastBestPathIdx) { + interimLastBestPathIdx = bestIdxNow; + interimLastProgressAtMs = nowMs; + } + } + return shouldYieldForActiveRecoveryInterim(interim, + playerLoc, + interimSetAtMs, + interimLastProgressAtMs, + nowMs, + lastMovedTimeMs, + lastUnreachableRecoveryClickAtMs, + Rs2Player.isMoving()); + } + + static boolean shouldYieldForActiveRecoveryInterim(WorldPoint interim, + WorldPoint playerLoc, + long setAtMs, + long lastProgressAtMs, + long nowMs, + long lastMovedAtMs, + long lastRecoveryClickAtMs, + boolean playerMoving) { + if (interim == null) { + return false; + } + if (shouldClearInterimTarget(interim, playerLoc, setAtMs, lastProgressAtMs, nowMs)) { + return false; + } + if (playerMoving) { + return true; + } + if (isRecentEvent(nowMs, lastProgressAtMs, INTERIM_PROGRESS_TIMEOUT_MS)) { + return true; + } + if (isRecentEvent(nowMs, lastMovedAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS)) { + return true; + } + return isRecentEvent(nowMs, lastRecoveryClickAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS); + } + private static void clearInterimTarget(String reason) { WorldPoint old = interimTargetWp; if (old != null) { - WebWalkLog.spInfo("interim_clear | reason={} interim={}", reason, compactWorldPoint(old)); + if ("close".equals(reason)) { + WebWalkLog.spDebug("interim_clear | reason={} interim={}", reason, compactWorldPoint(old)); + } else { + WebWalkLog.spInfo("interim_clear | reason={} interim={}", reason, compactWorldPoint(old)); + } } interimTargetWp = null; interimTargetIdx = -1; interimSetAtMs = 0L; interimLastProgressAtMs = 0L; interimLastBestPathIdx = -1; + interimLastDistanceToTarget = Integer.MAX_VALUE; interimLastRetargetAtMs = 0L; } @@ -4899,6 +5528,11 @@ private static void markGlobalDoorInteractionCooldown() { private static void markDoorAttempt(WorldPoint doorTile, WorldPoint fromWp, WorldPoint toWp) { Rs2DoorHandler.markDoorAttempt(recentDoorAttemptByEdge, doorTile, fromWp, toWp); + if (fromWp != null && toWp != null) { + lastDoorAttemptFrom = fromWp; + lastDoorAttemptTo = toWp; + lastDoorAttemptAtMs = System.currentTimeMillis(); + } } private static boolean shouldThrottleCurrentTileTransportAttempt(WorldPoint fromWp, WorldPoint toWp) { @@ -5190,6 +5824,9 @@ static boolean shouldBlacklistDoorAfterWrongTraversal(WorldPoint start, WorldPoi if (start.getPlane() != end.getPlane()) { return true; } + if (!startedNearDoorEdge(start, fromWp, toWp)) { + return false; + } int moved = start.distanceTo2D(end); if (moved < 3) { return false; @@ -5207,6 +5844,20 @@ static boolean shouldBlacklistDoorAfterWrongTraversal(WorldPoint start, WorldPoi return endFrom >= startFrom + 2; } + private static boolean startedNearDoorEdge(WorldPoint start, WorldPoint fromWp, WorldPoint toWp) { + if (start == null) { + return false; + } + final int maxDoorStartDistance = 3; + boolean nearFrom = fromWp != null + && fromWp.getPlane() == start.getPlane() + && start.distanceTo2D(fromWp) <= maxDoorStartDistance; + boolean nearTo = toWp != null + && toWp.getPlane() == start.getPlane() + && start.distanceTo2D(toWp) <= maxDoorStartDistance; + return nearFrom || nearTo; + } + private static boolean movedAcrossInteractedObject(WorldPoint start, WorldPoint end, WorldPoint objectLoc) { int startRelX = Integer.compare(start.getX(), objectLoc.getX()); int endRelX = Integer.compare(end.getX(), objectLoc.getX()); @@ -6474,40 +7125,72 @@ private static boolean searchNeighborPoint(int orientation, WorldPoint point, Wo * @return closest tile index */ public static int getClosestTileIndex(List path) { + WorldPoint playerLoc = Rs2Player.getWorldLocation(); + return getClosestTileIndex(path, playerLoc, getClosestIndexReachableTiles(playerLoc)); + } - var tiles = Rs2Tile.getReachableTilesFromTile(Rs2Player.getWorldLocation(), 20); + static int getClosestTileIndex(List path, WorldPoint playerLoc) { + return getClosestTileIndex(path, playerLoc, getClosestIndexReachableTiles(playerLoc)); + } - /** - * Exception to handle objects that handle long animations or walk - * ignore colission if we did not find a valid tile to walk on - * this is to ensure we stay on the path even if we are on a agility obstacle - */ - if (tiles.keySet().isEmpty()) { - tiles = Rs2Tile.getReachableTilesFromTileIgnoreCollision(Rs2Player.getWorldLocation(), 20); + static int getClosestTileIndex(List path, + WorldPoint playerLoc, + Map reachableTiles) { + if (path == null || path.isEmpty() || playerLoc == null) { + return -1; } - final HashMap _tiles = tiles; - WorldPoint startPoint = path.stream() - .min(Comparator.comparingInt(a -> _tiles.getOrDefault(a, Integer.MAX_VALUE))) - .orElse(null); + int bestReachableIndex = -1; + int bestReachableDistance = Integer.MAX_VALUE; + if (reachableTiles != null && !reachableTiles.isEmpty()) { + for (int i = 0; i < path.size(); i++) { + WorldPoint point = path.get(i); + if (point == null) { + continue; + } + int reachableDistance = reachableTiles.getOrDefault(point, Integer.MAX_VALUE); + if (reachableDistance < bestReachableDistance) { + bestReachableDistance = reachableDistance; + bestReachableIndex = i; + if (reachableDistance == 0) { + break; + } + } + } + } - /** - * Check if the startPoint is null or no matching tile is found - * If either condition is true, proceed to find the closest index in the path list. - */ - if (startPoint == null || _tiles.getOrDefault(startPoint, Integer.MAX_VALUE) == Integer.MAX_VALUE) { - Optional closestIndexOptional = IntStream.range(0, path.size()) - .boxed() - .min(Comparator.comparingInt(i -> Rs2Player.getWorldLocation().distanceTo(path.get(i)))); - if (closestIndexOptional.isPresent()) { - return closestIndexOptional.get(); + if (bestReachableIndex >= 0 && bestReachableDistance != Integer.MAX_VALUE) { + return bestReachableIndex; + } + + int closestIndex = -1; + int closestDistance = Integer.MAX_VALUE; + for (int i = 0; i < path.size(); i++) { + WorldPoint point = path.get(i); + if (point == null) { + continue; + } + int distance = playerLoc.distanceTo(point); + if (distance < closestDistance) { + closestDistance = distance; + closestIndex = i; } } + return closestIndex; + } - return IntStream.range(0, path.size()) - .filter(i -> path.get(i).equals(startPoint)) - .findFirst() - .orElse(-1); + private static HashMap getClosestIndexReachableTiles(WorldPoint playerLoc) { + if (playerLoc == null) { + return new HashMap<>(); + } + HashMap tiles = Rs2Tile.getReachableTilesFromTile(playerLoc, 20); + + // If an animation/shortcut puts the player on a collision-odd tile, keep route progress + // anchored by distance instead of repeatedly recalculating an empty reachable set. + if (tiles.isEmpty()) { + tiles = Rs2Tile.getReachableTilesFromTileIgnoreCollision(playerLoc, 20); + } + return tiles; } static int stabilizeRouteProgressIndex(List path, int closestIdx, WorldPoint target, WorldPoint playerLoc) { @@ -6529,10 +7212,14 @@ static int stabilizeRouteProgressIndex(List path, int closestIdx, Wo routeProgressPathEnd = pathEnd; routeProgressPathSize = path.size(); routeProgressIdx = closestIdx; + routeProgressAdvancedAtMs = System.currentTimeMillis(); return closestIdx; } if (routeProgressIdx < 0 || closestIdx >= routeProgressIdx) { + if (closestIdx > routeProgressIdx) { + recordRouteProgressAdvanced(); + } routeProgressIdx = closestIdx; return closestIdx; } @@ -6541,6 +7228,7 @@ static int stabilizeRouteProgressIndex(List path, int closestIdx, Wo if (forwardIdx >= routeProgressIdx) { if (forwardIdx > routeProgressIdx) { routeProgressIdx = forwardIdx; + recordRouteProgressAdvanced(); } return routeProgressIdx; } @@ -6601,6 +7289,14 @@ private static void resetRouteProgress() { routeProgressPathStart = null; routeProgressPathEnd = null; routeProgressPathSize = -1; + routeProgressAdvancedAtMs = 0L; + } + + private static void recordRouteProgressAdvanced() { + long now = System.currentTimeMillis(); + routeProgressAdvancedAtMs = now; + lastMovedTimeMs = now; + stuckCount = 0; } private static boolean isRecentTransportEdgeWindow() { @@ -7618,7 +8314,8 @@ private static boolean hasPrecomputedContinuationFromTransport(Transport transpo if (walkPath == null || walkPath.size() < 2) { return false; } - int closest = getClosestTileIndex(walkPath); + WorldPoint playerLoc = Rs2Player.getWorldLocation(); + int closest = getClosestTileIndex(walkPath, playerLoc); if (closest < 0) { return false; } @@ -8150,7 +8847,7 @@ private static boolean isNearPathByVariance(List path, WorldPoint pl if (path == null || path.isEmpty() || playerLoc == null) { return false; } - int closestIdx = getClosestTileIndex(path); + int closestIdx = getClosestTileIndex(path, playerLoc); if (closestIdx < 0 || closestIdx >= path.size()) { return false; } @@ -8160,6 +8857,104 @@ private static boolean isNearPathByVariance(List path, WorldPoint pl && closest.distanceTo2D(playerLoc) <= PATH_VARIANCE_TOLERANCE_CHEBYSHEV; } + static String offPathRecalcDeferralReason(boolean playerMoving, + boolean playerAnimating, + boolean playerInteracting, + boolean doorSettling, + boolean transportSettling, + boolean interimActive, + long nowMs, + long lastMovedAtMs, + long routeProgressAtMs, + long minimapClickAtMs, + long interimProgressAtMs) { + if (doorSettling) { + return "door-settling"; + } + if (transportSettling) { + return "transport-settling"; + } + if (playerMoving) { + return "moving"; + } + if (playerAnimating) { + return "animating"; + } + if (playerInteracting) { + return "interacting"; + } + if (isRecentEvent(nowMs, routeProgressAtMs, OFF_PATH_RECALC_ROUTE_PROGRESS_GRACE_MS)) { + return "route-progress"; + } + if (isRecentEvent(nowMs, minimapClickAtMs, OFF_PATH_RECALC_MINIMAP_CLICK_GRACE_MS)) { + return "recent-click"; + } + if (interimActive && isRecentEvent(nowMs, interimProgressAtMs, INTERIM_PROGRESS_TIMEOUT_MS)) { + return "interim-progress"; + } + if (isRecentEvent(nowMs, lastMovedAtMs, OFF_PATH_RECALC_RECENT_MOVEMENT_MS)) { + return "recent-movement"; + } + return null; + } + + private static String currentOffPathRecalcDeferralReason(long minimapClickAtMs) { + return offPathRecalcDeferralReason( + Rs2Player.isMoving(), + Rs2Player.isAnimating(), + Rs2Player.isInteracting(), + isDoorInteractionSettling(), + isTransportInteractionSettling(), + interimTargetWp != null, + System.currentTimeMillis(), + lastMovedTimeMs, + routeProgressAdvancedAtMs, + minimapClickAtMs, + interimLastProgressAtMs); + } + + static int offPathRecalcDeferredWaitMs(String reason, + long nowMs, + long lastMovedAtMs, + long routeProgressAtMs, + long minimapClickAtMs, + long interimProgressAtMs) { + long remainingMs = OFF_PATH_RECALC_DEFER_WAIT_MAX_MS; + if ("route-progress".equals(reason)) { + remainingMs = remainingRecentEventMs(nowMs, routeProgressAtMs, OFF_PATH_RECALC_ROUTE_PROGRESS_GRACE_MS); + } else if ("recent-click".equals(reason)) { + remainingMs = remainingRecentEventMs(nowMs, minimapClickAtMs, OFF_PATH_RECALC_MINIMAP_CLICK_GRACE_MS); + } else if ("interim-progress".equals(reason)) { + remainingMs = remainingRecentEventMs(nowMs, interimProgressAtMs, INTERIM_PROGRESS_TIMEOUT_MS); + } else if ("recent-movement".equals(reason)) { + remainingMs = remainingRecentEventMs(nowMs, lastMovedAtMs, OFF_PATH_RECALC_RECENT_MOVEMENT_MS); + } + return (int) Math.max(OFF_PATH_RECALC_DEFER_WAIT_MIN_MS, + Math.min(OFF_PATH_RECALC_DEFER_WAIT_MAX_MS, remainingMs)); + } + + private static boolean isOffPathRecalcDeferredExit(String exitReason) { + return exitReason != null && exitReason.startsWith("off-path-deferred:"); + } + + private static String offPathDeferredReasonFromExit(String exitReason) { + if (!isOffPathRecalcDeferredExit(exitReason)) { + return ""; + } + return exitReason.substring("off-path-deferred:".length()); + } + + private static boolean isRecentEvent(long nowMs, long eventAtMs, long graceMs) { + return eventAtMs > 0L && nowMs >= eventAtMs && nowMs - eventAtMs < graceMs; + } + + private static long remainingRecentEventMs(long nowMs, long eventAtMs, long graceMs) { + if (!isRecentEvent(nowMs, eventAtMs, graceMs)) { + return OFF_PATH_RECALC_DEFER_WAIT_MIN_MS; + } + return graceMs - (nowMs - eventAtMs); + } + private static boolean hasUpcomingNearbyTransportStep(List path, int startIdx, WorldPoint playerLoc, @@ -8279,6 +9074,11 @@ private static boolean isStuckTooLong() { return false; } + long routeProgressAt = routeProgressAdvancedAtMs; + if (routeProgressAt > 0L && System.currentTimeMillis() - routeProgressAt < ROUTE_PROGRESS_STALL_GRACE_MS) { + return false; + } + return lastMovedTimeMs > 0 && System.currentTimeMillis() - lastMovedTimeMs > stallThresholdMs(); } @@ -8959,33 +9759,160 @@ private static boolean handleCharterShip(Transport transport) { log.info("Charter Ship NPC: " + npcName + " - " + (npc != null ? npc.getId() : "not found")); if (Rs2Npc.canWalkTo(npc, 20) && Rs2Npc.interact(npc, transport.getAction())) { Rs2Player.waitForWalking(); - sleepUntil(() -> Rs2Widget.isWidgetVisible(885, 4)); - List destinationWidgets = Arrays.stream(Rs2Widget.getWidget(885, 4).getDynamicChildren()) - .filter(w -> w.getActions() != null) - .collect(Collectors.toList()); + if (!sleepUntil(() -> Rs2Widget.isWidgetVisible(885, 4), 5000)) { + return false; + } - if (destinationWidgets.isEmpty()) return false; + Widget destinationWidget = findCharterDestinationWidget(transport.getDisplayInfo()); + if (!invokeCharterDestinationWidget(destinationWidget, transport.getDisplayInfo())) { + return false; + } + confirmCharterTravelIfPrompted(); + return true; + } + return false; + } - String destinationText = transport.getDisplayInfo(); + private static Widget findCharterDestinationWidget(String destinationText) { + return Microbot.getClientThread().runOnClientThreadOptional(() -> { + Widget root = Microbot.getClient().getWidget(885, 4); + if (root == null || root.isHidden()) { + return null; + } - Widget destinationWidget = Rs2Widget.findWidget(destinationText, destinationWidgets); - if (destinationWidget == null) return false; + Widget textMatch = findCharterDestinationTextWidget(root, destinationText); + if (textMatch == null) { + return null; + } - boolean isWidgetVisible = Microbot.getClientThread().runOnClientThreadOptional(() -> !destinationWidget.isHidden()).orElse(false); + Widget clickable = findClickableCharterWidget(textMatch, root); + return clickable != null ? clickable : textMatch; + }).orElse(null); + } - NewMenuEntry destinationMenuEntry = new NewMenuEntry() - .option(destinationText) - .target("") - .identifier(1) - .type(MenuAction.CC_OP) - .param0(destinationWidget.getIndex()) - .param1(destinationWidget.getId()) - .forceLeftClick(false); + private static Widget findCharterDestinationTextWidget(Widget widget, String destinationText) { + if (widget == null || widget.isHidden()) { + return null; + } + if (charterWidgetMatchesDestination(widget, destinationText)) { + return widget; + } - Microbot.doInvoke(destinationMenuEntry, new Rectangle(1, 1)); + Widget[] staticChildren = widget.getStaticChildren(); + Widget found = findCharterDestinationTextWidget(staticChildren, destinationText); + if (found != null) { + return found; + } + + Widget[] dynamicChildren = widget.getDynamicChildren(); + found = findCharterDestinationTextWidget(dynamicChildren, destinationText); + if (found != null) { + return found; + } + + return findCharterDestinationTextWidget(widget.getNestedChildren(), destinationText); + } + + private static Widget findCharterDestinationTextWidget(Widget[] widgets, String destinationText) { + if (widgets == null) { + return null; + } + for (Widget widget : widgets) { + Widget found = findCharterDestinationTextWidget(widget, destinationText); + if (found != null) { + return found; + } + } + return null; + } + + private static boolean charterWidgetMatchesDestination(Widget widget, String destinationText) { + String needle = normalizeCharterWidgetText(destinationText); + if (needle.isEmpty()) { + return false; + } + if (normalizeCharterWidgetText(widget.getText()).contains(needle) + || normalizeCharterWidgetText(widget.getName()).contains(needle)) { return true; } - return false; + String[] actions = widget.getActions(); + if (actions == null) { + return false; + } + return Arrays.stream(actions) + .filter(Objects::nonNull) + .map(Rs2Walker::normalizeCharterWidgetText) + .anyMatch(action -> action.contains(needle)); + } + + private static String normalizeCharterWidgetText(String text) { + if (text == null || text.isEmpty()) { + return ""; + } + return Rs2UiHelper.stripTagsToSpace(text) + .trim() + .toLowerCase(Locale.ROOT) + .replaceAll("\\s+", " "); + } + + private static Widget findClickableCharterWidget(Widget widget, Widget root) { + Widget current = widget; + while (current != null) { + if (hasWidgetActions(current)) { + return current; + } + if (current == root) { + return null; + } + current = current.getParent(); + } + return null; + } + + private static boolean hasWidgetActions(Widget widget) { + String[] actions = widget.getActions(); + return actions != null && Arrays.stream(actions).anyMatch(action -> action != null && !action.isEmpty()); + } + + private static boolean invokeCharterDestinationWidget(Widget widget, String destinationText) { + if (widget == null) { + return false; + } + + String option = getFirstWidgetAction(widget); + if (option == null || option.isBlank()) { + option = destinationText; + } + + NewMenuEntry destinationMenuEntry = new NewMenuEntry() + .option(option) + .target("") + .identifier(1) + .type(MenuAction.CC_OP) + .param0(widget.getIndex()) + .param1(widget.getId()) + .forceLeftClick(false); + + Rectangle bounds = widget.getBounds(); + Microbot.doInvoke(destinationMenuEntry, bounds != null ? bounds : Rs2UiHelper.getDefaultRectangle()); + return true; + } + + private static String getFirstWidgetAction(Widget widget) { + String[] actions = widget.getActions(); + if (actions == null) { + return null; + } + return Arrays.stream(actions) + .filter(action -> action != null && !action.isEmpty()) + .findFirst() + .orElse(null); + } + + private static void confirmCharterTravelIfPrompted() { + if (sleepUntil(Rs2Dialogue::hasSelectAnOption, 2000)) { + Rs2Dialogue.clickOption("Yes", true); + } } /** * interact with interfaces like spirit tree etc... diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/WebWalkLog.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/WebWalkLog.java index cec154d812..63d7d7c4d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/WebWalkLog.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/WebWalkLog.java @@ -22,7 +22,7 @@ public static void routeClearMissingReason(String threadName) { LOG.warn("[WebWalk] clear | reason= thread={}", threadName); } - /** Cancel / EXIT / traceProcessWalkExit — compact WARN for production diagnosis. */ + /** Cancel / EXIT / traceProcessWalkExit - compact WARN for production diagnosis. */ public static void exitWarn(String reason, boolean nullCurrent, boolean targetMismatch, boolean interrupted, WorldPoint goal, WorldPoint current, int tailIdx, int tailMax, WorldPoint player) { LOG.warn("[WebWalk] exit | r={} nullCur={} mismatch={} intr={} goal={} cur={} tail={}/{} at={}", @@ -33,18 +33,23 @@ public static void exitDetailDebug(String fmt, Object... args) { LOG.debug("[WebWalk] exit_dbg | " + fmt, args); } - /** interim-in-flight and similar yields — DEBUG to avoid tick spam. */ + /** interim-in-flight and similar yields - DEBUG to avoid tick spam. */ public static void yieldDebug(String reason, WorldPoint player, WorldPoint goal, WorldPoint pathEnd, int idxStart, int pathLen) { LOG.debug("[WebWalk] yield | r={} player={} goal={} end={} idx={}/{}", reason, player, goal, pathEnd, idxStart, pathLen); } public static void earlyExit(String reason, WorldPoint player, WorldPoint goal, WorldPoint pathEnd, int idxStart, int pathLen) { + if ("interim-in-flight".equals(reason)) { + LOG.debug("[WebWalk] early_exit | r={} at={} goal={} end={} idx={}/{}", + reason, player, goal, pathEnd, idxStart, pathLen); + return; + } LOG.info("[WebWalk] early_exit | r={} at={} goal={} end={} idx={}/{}", reason, player, goal, pathEnd, idxStart, pathLen); } - /** Path ends far from goal — walking multi-hop segment. */ + /** Path ends far from goal - walking multi-hop segment. */ public static void partialSegment(WorldPoint pathEnd, int distToGoal, WorldPoint goal, int waypointCount) { LOG.info("[WebWalk] partial_seg | end={} dGoal={} goal={} nWp={}", pathEnd, distToGoal, goal, waypointCount); } @@ -65,7 +70,7 @@ public static void stallContextDebug(WorldPoint lastClick, boolean clickOk, long LOG.debug("[WebWalk] stall_ctx | lastClick={} ok={} ageMs={} interim={}", lastClick, clickOk, clickAgeMs, interim); } - /** Off-path / unreachable recovery / generic replan — single INFO line. */ + /** Off-path / unreachable recovery / generic replan - single INFO line. */ public static void recalc(String reason) { LOG.info("[WebWalk] recalc | {}", reason); } @@ -86,12 +91,12 @@ public static void tailExceeded(int maxTail, WorldPoint target, WorldPoint curre maxTail, target, current, interim, stuck, player); } - /** Pathfinder {@link net.runelite.client.plugins.microbot.shortestpath.pathfinder.Pathfinder} — DEBUG volume. */ + /** Pathfinder {@link net.runelite.client.plugins.microbot.shortestpath.pathfinder.Pathfinder} - DEBUG volume. */ public static void pf(String fmt, Object... args) { LOG.debug("[WebWalk] pf | " + fmt, args); } - /** {@link net.runelite.client.plugins.microbot.shortestpath.pathfinder.PathfinderConfig} refresh — DEBUG volume. */ + /** {@link net.runelite.client.plugins.microbot.shortestpath.pathfinder.PathfinderConfig} refresh - DEBUG volume. */ public static void cfg(String fmt, Object... args) { LOG.debug("[WebWalk] cfg | " + fmt, args); } @@ -100,7 +105,7 @@ public static void leagues(String fmt, Object... args) { LOG.debug("[WebWalk] leagues | " + fmt, args); } - /** Leagues calibration, region unlock, explicit no-op — INFO (not tick-spam paths). */ + /** Leagues calibration, region unlock, explicit no-op - INFO (not tick-spam paths). */ public static void leaguesInfo(String fmt, Object... args) { LOG.info("[WebWalk] leagues | " + fmt, args); } @@ -131,7 +136,7 @@ public static void compareError(double totalMs, WorldPoint target, String err) { LOG.warn("[WebWalk] compare_err | {}ms target={} err={}", String.format("%.1f", totalMs), target, err); } - /** Banked-route helper: per-path transport scan — DEBUG volume. */ + /** Banked-route helper: per-path transport scan - DEBUG volume. */ public static void bankPathTransportsDebug(int count, WorldPoint from, WorldPoint to) { LOG.debug("[WebWalk] bank_path | transports={} {} -> {}", count, from, to); } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java index 31c84b2018..b0f01f0ac5 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java @@ -11,8 +11,10 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; @@ -238,6 +240,30 @@ public void rankSidestep_preservesAllTilesIncludingEquidistant() { assertTrue(ranked.contains(north)); } + @Test + public void getClosestTileIndex_usesReachableDistanceWhenAvailable() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + WorldPoint farByWorldDistance = new WorldPoint(3210, 3200, 0); + WorldPoint nearReachable = new WorldPoint(3220, 3200, 0); + List path = Arrays.asList(farByWorldDistance, nearReachable); + Map reachable = new HashMap<>(); + reachable.put(farByWorldDistance, 8); + reachable.put(nearReachable, 3); + + assertEquals(1, Rs2Walker.getClosestTileIndex(path, player, reachable)); + } + + @Test + public void getClosestTileIndex_fallsBackToWorldDistanceWhenNoReachablePathTile() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + List path = Arrays.asList( + new WorldPoint(3210, 3200, 0), + new WorldPoint(3202, 3200, 0), + new WorldPoint(3220, 3200, 0)); + + assertEquals(1, Rs2Walker.getClosestTileIndex(path, player, Collections.emptyMap())); + } + // --------------------------------------------------------------------------- // #21 — Minimap forward-scan // --------------------------------------------------------------------------- @@ -356,7 +382,7 @@ public void findFurthest_nullPredicate_treatsAsNoTransport() { } @Test - public void stabilizeRouteProgressIndex_doesNotJumpBackToEarlierSwitchbackBranch() { + public void stabilizeRouteProgressIndex_doesNotJumpBackToEarlierNearbyBranch() { WorldPoint target = new WorldPoint(3200, 3201, 0); List path = Arrays.asList( new WorldPoint(3200, 3200, 0), @@ -376,7 +402,7 @@ public void stabilizeRouteProgressIndex_doesNotJumpBackToEarlierSwitchbackBranch } @Test - public void findForwardRecoveryIndex_prefersLaterReachableSwitchbackBranch() { + public void findForwardRecoveryIndex_prefersLaterReachableBranch() { WorldPoint player = new WorldPoint(1000, 1000, 0); List path = Arrays.asList( new WorldPoint(998, 1000, 0), @@ -396,7 +422,7 @@ public void findForwardRecoveryIndex_prefersLaterReachableSwitchbackBranch() { } @Test - public void findFurthestClickableIndex_canReturnEarlierSwitchbackBranch() { + public void findFurthestClickableIndex_canReturnEarlierNearbyBranch() { WorldPoint player = new WorldPoint(1000, 1000, 0); List path = Arrays.asList( new WorldPoint(998, 1000, 0), @@ -410,6 +436,83 @@ public void findFurthestClickableIndex_canReturnEarlierSwitchbackBranch() { assertEquals("generic fallback is allowed to backtrack; recovery clamps this at the call site", 2, idx); } + @Test + public void findFurthestForwardClickableIndex_doesNotBacktrackToEarlierNearbyBranch() { + WorldPoint player = new WorldPoint(1000, 1000, 0); + List path = Arrays.asList( + new WorldPoint(998, 1000, 0), + new WorldPoint(999, 1000, 0), + new WorldPoint(1000, 1001, 0), + new WorldPoint(1015, 1000, 0), + new WorldPoint(1016, 1001, 0)); + + int idx = Rs2Walker.findFurthestForwardClickableIndex(path, 3, player, wp -> false, 13); + + assertEquals("normal route following should interpolate toward the forward tile, not backtrack", 3, idx); + } + + @Test + public void findFurthestForwardClickableIndex_stopsBeforeTransportOrigin() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + WorldPoint transportOrigin = new WorldPoint(3203, 3200, 0); + List path = Arrays.asList( + new WorldPoint(3201, 3200, 0), + new WorldPoint(3202, 3200, 0), + transportOrigin, + new WorldPoint(3204, 3200, 0)); + + int idx = Rs2Walker.findFurthestForwardClickableIndex(path, 0, player, transportOrigin::equals, 13); + + assertEquals("route clicks must not skip a planned transport origin", 1, idx); + } + + @Test + public void offPathRecalcDeferralReason_prefersSettlingAndBusyState() { + long now = 10_000L; + + assertEquals("door-settling", Rs2Walker.offPathRecalcDeferralReason( + true, false, false, true, false, false, + now, 0L, 0L, 0L, 0L)); + assertEquals("transport-settling", Rs2Walker.offPathRecalcDeferralReason( + true, false, false, false, true, false, + now, 0L, 0L, 0L, 0L)); + assertEquals("moving", Rs2Walker.offPathRecalcDeferralReason( + true, false, false, false, false, false, + now, 0L, 0L, 0L, 0L)); + } + + @Test + public void offPathRecalcDeferralReason_recentProgressDefersAfterMovementStops() { + long now = 10_000L; + + assertEquals("route-progress", Rs2Walker.offPathRecalcDeferralReason( + false, false, false, false, false, false, + now, 0L, 8_000L, 0L, 0L)); + assertEquals("recent-click", Rs2Walker.offPathRecalcDeferralReason( + false, false, false, false, false, false, + now, 0L, 0L, 8_000L, 0L)); + assertEquals("interim-progress", Rs2Walker.offPathRecalcDeferralReason( + false, false, false, false, false, true, + now, 0L, 0L, 0L, 8_000L)); + } + + @Test + public void offPathRecalcDeferralReason_allowsRecalcWhenSignalsExpired() { + long now = 10_000L; + + assertEquals(null, Rs2Walker.offPathRecalcDeferralReason( + false, false, false, false, false, false, + now, 7_000L, 6_000L, 7_000L, 7_000L)); + } + + @Test + public void offPathRecalcDeferredWaitMs_isBounded() { + assertEquals(1200, Rs2Walker.offPathRecalcDeferredWaitMs( + "route-progress", 10_000L, 0L, 9_700L, 0L, 0L)); + assertEquals(250, Rs2Walker.offPathRecalcDeferredWaitMs( + "route-progress", 10_000L, 0L, 6_600L, 0L, 0L)); + } + @Test public void interpolateClickableTarget_usesInterpolatedPointWhenUsable() { WorldPoint player = new WorldPoint(3200, 3200, 0); @@ -453,6 +556,26 @@ public void interpolateClickableTarget_shortensOutOfReachForwardWaypoint() { new WorldPoint(3212, 3200, 0), target); } + @Test + public void clampToEuclideanRadius_shortensDiagonalTargetInsideCircle() { + WorldPoint player = new WorldPoint(2875, 3418, 0); + WorldPoint target = new WorldPoint(2886, 3428, 0); + + WorldPoint clamped = Rs2Walker.clampToEuclideanRadius(player, target, 10); + + assertTrue(clamped.distanceTo2D(player) <= 10); + assertTrue(clamped.getX() > player.getX()); + assertTrue(clamped.getY() > player.getY()); + } + + @Test + public void clampToEuclideanRadius_keepsInRangeTarget() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + WorldPoint target = new WorldPoint(3206, 3203, 0); + + assertEquals(target, Rs2Walker.clampToEuclideanRadius(player, target, 10)); + } + // --------------------------------------------------------------------------- // Raw-path wall-door segment probing // --------------------------------------------------------------------------- @@ -525,6 +648,23 @@ public void shouldClearInterimTarget_closeToCheckpoint_returnsTrue() { 2_000L)); } + @Test + public void shouldClearInterimTarget_preclickDistanceStillKeepsCheckpoint() { + assertFalse(Rs2Walker.shouldClearInterimTarget( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2884, 3396, 0), + 1_000L, + 1_500L, + 2_000L)); + } + + @Test + public void distanceToInterimOrMax_samePlaneReturnsDistance() { + assertEquals(8, Rs2Walker.distanceToInterimOrMax( + new WorldPoint(2850, 3506, 0), + new WorldPoint(2849, 3498, 0))); + } + @Test public void shouldClearInterimTarget_expiredCheckpoint_returnsTrue() { assertTrue(Rs2Walker.shouldClearInterimTarget( @@ -555,10 +695,124 @@ public void shouldClearInterimTarget_activeFarCheckpoint_returnsFalse() { 5_000L)); } + @Test + public void shouldYieldForActiveRecoveryInterim_recentProgress_returnsTrue() { + assertTrue(Rs2Walker.shouldYieldForActiveRecoveryInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2884, 3396, 0), + 1_000L, + 2_500L, + 3_000L, + 0L, + 0L, + false)); + } + + @Test + public void shouldYieldForActiveRecoveryInterim_staleProgress_returnsFalse() { + assertFalse(Rs2Walker.shouldYieldForActiveRecoveryInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2880, 3396, 0), + 1_000L, + 1_500L, + 5_000L, + 0L, + 0L, + false)); + } + + @Test + public void shouldYieldForActiveRecoveryInterim_recentRecoveryClick_returnsTrue() { + assertTrue(Rs2Walker.shouldYieldForActiveRecoveryInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2880, 3396, 0), + 1_000L, + 0L, + 3_000L, + 0L, + 2_000L, + false)); + } + @Test public void interimPreclickTiles_runHandsOffEarlierThanWalk() { assertEquals(6, Rs2Walker.interimPreclickTiles(false)); - assertEquals(11, Rs2Walker.interimPreclickTiles(true)); + assertEquals(8, Rs2Walker.interimPreclickTiles(true)); + } + + @Test + public void routeMovementClickPhase_labelsContinuationSeparatelyFromRecovery() { + assertEquals("stall_recovery_click", Rs2Walker.routeMovementClickPhase("stall recovery click")); + assertEquals("active_route_idle_nudge", Rs2Walker.routeMovementClickPhase("active route idle nudge")); + assertEquals("interim_close_route_click", Rs2Walker.routeMovementClickPhase("interim close route click")); + assertEquals("route_movement_click", Rs2Walker.routeMovementClickPhase("other")); + } + + @Test + public void shouldSkipStartupPreclickSegmentHandlers_skipsBeyondStartupLookahead() { + assertTrue(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( + true, + 8, + 5, + false, + false, + false)); + } + + @Test + public void shouldSkipStartupPreclickSegmentHandlers_keepsImmediateAndDoorRecoveryEdges() { + assertFalse(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( + true, + 7, + 5, + false, + false, + false)); + assertFalse(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( + true, + 8, + 5, + true, + false, + false)); + assertFalse(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( + false, + 8, + 5, + false, + false, + false)); + } + + @Test + public void rawPathForwardAnchorIndex_keepsFallbackAheadOfAnchor() { + List rawPath = Arrays.asList( + new WorldPoint(3200, 3200, 0), + new WorldPoint(3201, 3200, 0), + new WorldPoint(3202, 3200, 0), + new WorldPoint(3203, 3200, 0), + new WorldPoint(3204, 3200, 0), + new WorldPoint(3205, 3200, 0), + new WorldPoint(3206, 3200, 0), + new WorldPoint(3207, 3200, 0), + new WorldPoint(3208, 3200, 0), + new WorldPoint(3209, 3200, 0), + new WorldPoint(3210, 3200, 0), + new WorldPoint(3210, 3201, 0), + new WorldPoint(3210, 3202, 0), + new WorldPoint(3210, 3203, 0), + new WorldPoint(3210, 3204, 0), + new WorldPoint(3209, 3204, 0), + new WorldPoint(3208, 3204, 0), + new WorldPoint(3207, 3204, 0), + new WorldPoint(3206, 3204, 0), + new WorldPoint(3205, 3204, 0), + new WorldPoint(3204, 3204, 0)); + WorldPoint playerOnReturnBranch = rawPath.get(20); + + assertEquals("forward anchor must keep raw fallback on the current return branch", + 20, + Rs2Walker.rawPathForwardAnchorIndex(rawPath, playerOnReturnBranch, 14)); } @Test @@ -600,6 +854,16 @@ public void shouldBlacklistDoorAfterWrongTraversal_teleportAway_returnsTrue() { new WorldPoint(1988, 5569, 0))); } + @Test + public void shouldBlacklistDoorAfterWrongTraversal_startedFarFromDoor_returnsFalse() { + assertFalse("movement from an earlier minimap click must not blacklist a valid gate", + Rs2Walker.shouldBlacklistDoorAfterWrongTraversal( + new WorldPoint(3270, 3320, 0), + new WorldPoint(3275, 3325, 0), + new WorldPoint(3262, 3322, 0), + new WorldPoint(3261, 3321, 0))); + } + @Test public void shouldBlacklistDoorAfterWrongTraversal_progressTowardEdge_returnsFalse() { assertFalse(Rs2Walker.shouldBlacklistDoorAfterWrongTraversal( @@ -768,6 +1032,18 @@ public void telemetry_counterIsIndependentOfOtherReasons() { assertEquals(1, Rs2Walker.Telemetry.partialRetryCount.get()); } + @Test + public void telemetry_recordOffPathRecalcDeferred_setsReasonButDoesNotCountAsRecalc() { + Rs2Walker.Telemetry.recordOffPathRecalcDeferred("route-progress", + new WorldPoint(3200, 3200, 0), + new WorldPoint(3210, 3210, 0), + 20); + + assertEquals(1, Rs2Walker.Telemetry.offPathRecalcDeferredCount.get()); + assertEquals("off-path-deferred:route-progress", Rs2Walker.Telemetry.lastReason); + assertEquals(0, Rs2Walker.Telemetry.totalRecalcs()); + } + @Test public void telemetry_reset_clearsUnreachable() { Rs2Walker.Telemetry.recordUnreachable("no-walkable-path", From 51af3342a22275218604fbfd035eede7e3583d77 Mon Sep 17 00:00:00 2001 From: infuse21 Date: Sat, 18 Jul 2026 14:14:48 +0100 Subject: [PATCH 2/5] changed client-thread-guardrail-baseline.txt cold start - hopefuly fixed Mid-route Stalling rs2 walker now accepts adjacent same-plane transport/objct landing --- docs/entity-guides/movement.md | 4 +- .../microbot/util/walker/Rs2Walker.java | 45 ++++++++---- .../util/walker/Rs2WalkerUnitTest.java | 70 ++++++++++++++++--- .../client-thread-guardrail-baseline.txt | 69 ++++++++++-------- 4 files changed, 136 insertions(+), 52 deletions(-) diff --git a/docs/entity-guides/movement.md b/docs/entity-guides/movement.md index 2ed25f0c5d..123d6eadef 100644 --- a/docs/entity-guides/movement.md +++ b/docs/entity-guides/movement.md @@ -290,7 +290,7 @@ After a handled transport, avoid expensive path-adjacent or raw transport scans For long-route minimap walking, let the next checkpoint selection happen before the current minimap target is fully consumed. Waiting until the player is only a few tiles from the interim makes the walker visibly stop before issuing the next click; handing off at a moderate remaining distance keeps movement continuous without rapid re-clicking. If an interim clears as close and no nearby route door/transport is pending, issue the next route-aligned continuation click immediately instead of waiting for idle-nudge recovery. Stale-progress checks must also count distance progress toward the actual interim checkpoint, not only smoothed path index progress; sparse smoothed paths can otherwise clear valid raw-path checkpoints as stale while the player is still walking toward them. -Before the first movement click, only scan a small number of immediate route edges for doors or blockers. A door several segments ahead can be handled after the first minimap click moves the player toward it; spending startup time scanning every nearby raw segment creates a visible cold start. +Before the first movement click, avoid timeout-backed speculative segment scans for doors, blockers, rockfalls, or transports. Let the first minimap click move the player toward the route; actual visible doors can still be handled by the dedicated pre-click route-door guard, and steady-state handling can resolve later obstacles once movement has started. Spending startup time scanning every nearby raw segment creates a visible cold start. Continuation clicks that keep an active route moving should be tail-exempt like `interim-in-flight`; otherwise very long routes can exhaust `MAX_PROCESS_WALK_TAIL_ITERATIONS` while still making progress and trigger an unnecessary auto-retry. @@ -298,7 +298,7 @@ Sticky interim targets should also clear when route-index progress goes stale. I When a route-following minimap click is outside the minimap clip, fallback clicks must stay on the raw path. This includes the "clicked but no movement yet" retry after a route click and route-backed direct short-walks near the final destination. A generic "reachable tile closer to target" fallback can select a tile far away from the route in open areas, especially near fences and the final destination. Raw fallback must be anchored from the stabilized route index, not a fresh nearest-raw-tile lookup, or the walker can snap backward to an already-travelled branch. -For adjacent same-plane shortcuts, do not treat any movement away from the origin as success. Some shortcuts, such as stepping stones, can fail and place the player on a fallback tile; once the player is settled away from the expected destination, stop the landing wait and replan from the actual tile. +For adjacent same-plane shortcuts, do not treat any movement away from the origin as success. Some shortcuts, such as stepping stones, can fail and place the player on a fallback tile; once the player is settled away from the expected destination, stop the landing wait and replan from the actual tile. If the player is settled within one tile of the expected destination and is no longer on the origin, accept the landing instead of waiting for an exact tile that server pathing may not choose. ## 14. Keep optimistic recovery clicks route-backed and paced diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java index 68df3dceea..9de5153b3a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java @@ -156,8 +156,6 @@ public static WorldPoint getCurrentTarget() { private static final int PATHFINDER_DONE_POLL_WAIT_MS = 1200; private static final int PATHFINDER_DONE_RETRY_SLEEP_MIN_MS = 120; private static final int PATHFINDER_DONE_RETRY_SLEEP_MAX_MS = 220; - private static final long STARTUP_FIRST_CLICK_BUDGET_MS = 2200L; - private static final int STARTUP_PRECLICK_DOOR_SCAN_LOOKAHEAD_EDGES = 2; private static final int POST_DOOR_FAST_CLICK_MAX_EUCLIDEAN = 13; private static final int POST_DOOR_EDGE_NUDGE_MAX_FROM_PLAYER = 3; private static final int POST_DOOR_EDGE_NUDGE_WAIT_MS = 1200; @@ -433,13 +431,7 @@ private static WalkerPhase currentWalkerPhase() { if (firstMovementClickMarked) { return WalkerPhase.STEADY; } - long startedAt = walkSessionStartedAtMs; - if (startedAt <= 0) { - return WalkerPhase.STEADY; - } - return (System.currentTimeMillis() - startedAt) <= STARTUP_FIRST_CLICK_BUDGET_MS - ? WalkerPhase.STARTUP - : WalkerPhase.STEADY; + return WalkerPhase.STARTUP; } private static ObstaclePolicy obstaclePolicyForCurrentPhase() { @@ -460,7 +452,7 @@ static boolean shouldSkipStartupPreclickSegmentHandlers(boolean startupBeforeFir if (recentDoorAttemptNearSegment || doorSettling || recoveryInFlight) { return false; } - return segmentIdx > routeStartIdx + STARTUP_PRECLICK_DOOR_SCAN_LOOKAHEAD_EDGES; + return true; } /** @@ -1622,13 +1614,13 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { if (skipPostTransportSegmentHandlers || skipStartupPreclickSegmentHandlers) { if (skipStartupPreclickSegmentHandlers) { markStartupPhase("preclick_segment_handler_skip", target, - "i=" + i + " reason=startup_preclick_budget"); + "i=" + i + " reason=startup_before_first_click"); } tmarkPostTransport("post_transport_segment_handler_skip", target, "i=" + i + " reason=" + (skipPostTransportSegmentHandlers ? "no_nearby_planned_transport" - : "startup_preclick_budget")); + : "startup_before_first_click")); } else { long segmentHandlerStartAt = System.currentTimeMillis(); int rawI = (i < smoothedToRaw.length) ? smoothedToRaw[i] : 0; @@ -7932,6 +7924,7 @@ private static boolean waitForPostHandleObjectLanding(Transport transport, int maxInclusive) { long waitStartedAt = System.currentTimeMillis(); AtomicBoolean settledAwayFromAdjacentDestination = new AtomicBoolean(false); + AtomicBoolean settledNearAdjacentDestination = new AtomicBoolean(false); boolean completed = sleepUntil(() -> { if (isPlayerWithinChebyshevInclusive(destWait, maxInclusive)) { return true; @@ -7945,6 +7938,10 @@ private static boolean waitForPostHandleObjectLanding(Transport transport, || Rs2Player.isMoving() || Rs2Player.isAnimating()) { return false; } + if (isSettledNearAdjacentSamePlaneLanding(transport, playerLoc, destWait, maxInclusive)) { + settledNearAdjacentDestination.set(true); + return true; + } WorldPoint origin = transport == null ? null : transport.getOrigin(); boolean settledAwayFromOrigin = origin != null && playerLoc.distanceTo2D(origin) > 1; if (playerLoc.distanceTo2D(destWait) > Math.max(1, maxInclusive) @@ -7955,6 +7952,11 @@ private static boolean waitForPostHandleObjectLanding(Transport transport, return false; }, POST_HANDLE_OBJECT_LANDING_WAIT_MS); + if (settledNearAdjacentDestination.get()) { + WebWalkLog.spInfo("post-handleObject adjacent landing accepted | dest={} at={}", + compactWorldPoint(destWait), compactWorldPoint(Rs2Player.getWorldLocation())); + return true; + } if (settledAwayFromAdjacentDestination.get()) { WebWalkLog.spInfo("post-handleObject adjacent landing failed | dest={} at={}", compactWorldPoint(destWait), compactWorldPoint(Rs2Player.getWorldLocation())); @@ -7963,6 +7965,25 @@ private static boolean waitForPostHandleObjectLanding(Transport transport, return completed; } + static boolean isSettledNearAdjacentSamePlaneLanding(Transport transport, + WorldPoint playerLoc, + WorldPoint destWait, + int maxInclusive) { + if (!isAdjacentSamePlaneTransport(transport) + || playerLoc == null + || destWait == null + || playerLoc.getPlane() != destWait.getPlane()) { + return false; + } + WorldPoint origin = transport.getOrigin(); + if (origin == null || playerLoc.equals(origin)) { + return false; + } + int destinationDistance = playerLoc.distanceTo2D(destWait); + return destinationDistance <= Math.max(1, maxInclusive) + && playerLoc.distanceTo2D(origin) > 0; + } + /** * Handles the transportation process specifically for instances of PohTransport. * Any Transport param that reaches this is assumed to be a PohTransport. diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java index b0f01f0ac5..5de440bd1e 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java @@ -116,6 +116,63 @@ public void shouldRecalculatePathAfterTransport_skipsAdjacentSamePlaneTransport( assertFalse(Rs2Walker.shouldRecalculatePathAfterTransport(door)); } + @Test + public void isSettledNearAdjacentSamePlaneLanding_acceptsNearDestinationOffOrigin() { + Transport door = new Transport( + new WorldPoint(3152, 3363, 0), + new WorldPoint(3153, 3363, 0), + "Door", + TransportType.TRANSPORT, + false, + "Open", + "Door", + 136); + + assertTrue(Rs2Walker.isSettledNearAdjacentSamePlaneLanding( + door, + new WorldPoint(3154, 3363, 0), + new WorldPoint(3153, 3363, 0), + 0)); + } + + @Test + public void isSettledNearAdjacentSamePlaneLanding_rejectsOriginTile() { + Transport door = new Transport( + new WorldPoint(3152, 3363, 0), + new WorldPoint(3153, 3363, 0), + "Door", + TransportType.TRANSPORT, + false, + "Open", + "Door", + 136); + + assertFalse(Rs2Walker.isSettledNearAdjacentSamePlaneLanding( + door, + new WorldPoint(3152, 3363, 0), + new WorldPoint(3153, 3363, 0), + 0)); + } + + @Test + public void isSettledNearAdjacentSamePlaneLanding_rejectsTilesTooFarFromDestination() { + Transport door = new Transport( + new WorldPoint(3152, 3363, 0), + new WorldPoint(3153, 3363, 0), + "Door", + TransportType.TRANSPORT, + false, + "Open", + "Door", + 136); + + assertFalse(Rs2Walker.isSettledNearAdjacentSamePlaneLanding( + door, + new WorldPoint(3155, 3363, 0), + new WorldPoint(3153, 3363, 0), + 0)); + } + @Test public void shouldRecalculatePathAfterTransport_includesLongDistanceTransport() { Transport ship = new Transport( @@ -749,10 +806,10 @@ public void routeMovementClickPhase_labelsContinuationSeparatelyFromRecovery() { } @Test - public void shouldSkipStartupPreclickSegmentHandlers_skipsBeyondStartupLookahead() { + public void shouldSkipStartupPreclickSegmentHandlers_skipsBeforeFirstMovementClick() { assertTrue(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( true, - 8, + 5, 5, false, false, @@ -760,14 +817,7 @@ public void shouldSkipStartupPreclickSegmentHandlers_skipsBeyondStartupLookahead } @Test - public void shouldSkipStartupPreclickSegmentHandlers_keepsImmediateAndDoorRecoveryEdges() { - assertFalse(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( - true, - 7, - 5, - false, - false, - false)); + public void shouldSkipStartupPreclickSegmentHandlers_keepsDoorRecoveryAndSteadyEdges() { assertFalse(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( true, 8, diff --git a/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt b/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt index 3395d9f6e9..a2605ab88d 100644 --- a/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt +++ b/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt @@ -720,10 +720,18 @@ net.runelite.client.plugins.microbot.util.walker.Rs2MiniMap#worldToMinimap(World net.runelite.client.plugins.microbot.util.walker.Rs2MiniMap#worldToMinimap(WorldPoint): Point -> net.runelite.api.WorldView#isInstance(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2MiniMap#worldToMinimap(WorldPoint): Point -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#adjacentSamePlaneTransportSuppressionPoints(Transport, TileObject): Set -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#charterWidgetMatchesDestination(Widget, String): boolean -> net.runelite.api.widgets.Widget#getActions(): String[] +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#charterWidgetMatchesDestination(Widget, String): boolean -> net.runelite.api.widgets.Widget#getName(): String +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#charterWidgetMatchesDestination(Widget, String): boolean -> net.runelite.api.widgets.Widget#getText(): String net.runelite.client.plugins.microbot.util.walker.Rs2Walker#closeWorldMap(): boolean -> net.runelite.api.widgets.Widget#getBounds(): Rectangle net.runelite.client.plugins.microbot.util.walker.Rs2Walker#distanceToRegion(int, int): int -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#distanceToRegion(int, int): int -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#doorObjectStillHasAction(TileObject, WorldPoint, WorldPoint, WorldPoint, List, String): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#findCharterDestinationTextWidget(Widget, String): Widget -> net.runelite.api.widgets.Widget#getDynamicChildren(): Widget[] +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#findCharterDestinationTextWidget(Widget, String): Widget -> net.runelite.api.widgets.Widget#getStaticChildren(): Widget[] +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#findCharterDestinationTextWidget(Widget, String): Widget -> net.runelite.api.widgets.Widget#isHidden(): boolean +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#findClickableCharterWidget(Widget, Widget): Widget -> net.runelite.api.widgets.Widget#getParent(): Widget +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getFirstWidgetAction(Widget): String -> net.runelite.api.widgets.Widget#getActions(): String[] net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getPointWithWallDistance(WorldPoint): WorldPoint -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getPointWithWallDistance(WorldPoint): WorldPoint -> net.runelite.api.CollisionData#getFlags(): int[][] net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getPointWithWallDistance(WorldPoint): WorldPoint -> net.runelite.api.WorldView#getCollisionMaps(): CollisionData[] @@ -735,9 +743,6 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getTile(WorldPoint): net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getTile(WorldPoint): Tile -> net.runelite.api.WorldView#isInstance(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getTile(WorldPoint): Tile -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#getTransportsForPath(List, int, TransportType, boolean): List -> net.runelite.api.Client#getTopLevelWorldView(): WorldView -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleCharterShip(Transport): boolean -> net.runelite.api.widgets.Widget#getDynamicChildren(): Widget[] -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleCharterShip(Transport): boolean -> net.runelite.api.widgets.Widget#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleCharterShip(Transport): boolean -> net.runelite.api.widgets.Widget#getIndex(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleDoors(List, int, boolean): boolean -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleDoors(List, int, boolean): boolean -> net.runelite.api.ObjectComposition#getImpostorIds(): int[] net.runelite.client.plugins.microbot.util.walker.Rs2Walker#handleDoors(List, int, boolean): boolean -> net.runelite.api.ObjectComposition#getName(): String @@ -771,7 +776,11 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#hasDoorCandidateOnRaw net.runelite.client.plugins.microbot.util.walker.Rs2Walker#hasDoorCandidateOnRawSegment(List, int): boolean -> net.runelite.api.WorldView#getScene(): Scene net.runelite.client.plugins.microbot.util.walker.Rs2Walker#hasLineOfSightBetween(WorldPoint, WorldPoint): boolean -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#hasLineOfSightBetween(WorldPoint, WorldPoint): boolean -> net.runelite.api.coords.WorldArea#hasLineOfSightTo(WorldView, WorldArea): boolean +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#hasWidgetActions(Widget): boolean -> net.runelite.api.widgets.Widget#getActions(): String[] net.runelite.client.plugins.microbot.util.walker.Rs2Walker#interactingActorNearWalkablePath(): boolean -> net.runelite.api.Actor#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#invokeCharterDestinationWidget(Widget, String): boolean -> net.runelite.api.widgets.Widget#getBounds(): Rectangle +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#invokeCharterDestinationWidget(Widget, String): boolean -> net.runelite.api.widgets.Widget#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#invokeCharterDestinationWidget(Widget, String): boolean -> net.runelite.api.widgets.Widget#getIndex(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCatalogTransportObject(TileObject): boolean -> net.runelite.api.TileObject#getId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCatalogTransportObject(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCloseToRegion(int, int, int): boolean -> net.runelite.api.Client#getTopLevelWorldView(): WorldView @@ -788,33 +797,35 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isPendingRouteDoorObj net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isPendingRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isUnresolvedRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.ObjectComposition#getName(): String net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isUnresolvedRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$42(WorldPoint, WorldPoint, WorldPoint, List, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$43(WorldPoint, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleCharterShip$181(Widget): boolean -> net.runelite.api.widgets.Widget#getActions(): String[] -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$40(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$41(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleFairyRing$187(Transport, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$158(Widget, Object[]): boolean -> net.runelite.api.widgets.Widget#getOnOpListener(): Object[] -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$160(String): boolean -> net.runelite.api.widgets.Widget#getText(): String -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$136(int, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$142(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$142(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$143(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$143(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleRockfall$22(WorldPoint, Tile): boolean -> net.runelite.api.Tile#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$116(int, boolean, TileObject): boolean -> net.runelite.api.ObjectComposition#getName(): String -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$116(int, boolean, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$118(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$119(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$120(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$121(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$123(int, List, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$124(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$150(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$151(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$40(WorldPoint, WorldPoint, WorldPoint, List, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$41(WorldPoint, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$38(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$39(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleFairyRing$185(Transport, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$154(Widget, Object[]): boolean -> net.runelite.api.widgets.Widget#getOnOpListener(): Object[] +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$156(String): boolean -> net.runelite.api.widgets.Widget#getText(): String +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$132(int, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$138(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$138(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$139(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$139(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleRockfall$21(WorldPoint, Tile): boolean -> net.runelite.api.Tile#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$112(int, boolean, TileObject): boolean -> net.runelite.api.ObjectComposition#getName(): String +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$112(int, boolean, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$114(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$115(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$116(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$117(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$119(int, List, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$120(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$146(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$147(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$processWalk$2(): boolean -> net.runelite.api.widgets.Widget#getSpriteId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$processWalk$3(): boolean -> net.runelite.api.widgets.Widget#getSpriteId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$tryHandleBlockingPathObjectsWithTimeout$69(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$tryHandleBlockingPathObjectsWithTimeout$68(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.Client#getTopLevelWorldView(): WorldView +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.WorldView#isInstance(): boolean +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#markNearbyDoorFamilyOpened(TileObject, WorldPoint, String, int): void -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#maybeCanvasNudgeAfterDoor(WorldPoint, int, List): void -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#maybeCanvasNudgeAfterDoor(WorldPoint, int, List): void -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint @@ -848,6 +859,8 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvas(WorldP net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvas(WorldPoint, boolean): boolean -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvas(WorldPoint, boolean): boolean -> net.runelite.api.WorldView#isInstance(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvas(WorldPoint, boolean): boolean -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvasOnScreenOnly(WorldPoint, boolean): boolean -> net.runelite.api.Client#getTopLevelWorldView(): WorldView +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastCanvasOnScreenOnly(WorldPoint, boolean): boolean -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastLocal(LocalPoint): void -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastLocal(LocalPoint): void -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkNextToInstance(GameObject): void -> net.runelite.api.Client#getTopLevelWorldView(): WorldView From 82b537720efb5e5e7ed1314df8e977e617c02d76 Mon Sep 17 00:00:00 2001 From: infuse21 Date: Sun, 19 Jul 2026 15:28:45 +0100 Subject: [PATCH 3/5] summary for all current new commits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adds a per-loop `WalkLoopSnapshot` so route progress decisions reuse a stable player location and reachable-tile snapshot during each walker loop. - Reworks closest-path-index and route-progress tracking to prefer reachable distance when available, fall back safely when reachability is empty, and preserve forward progress on routes that double back near earlier branches. - Keeps primary minimap clicks, direct short-walk fallback, and unreachable recovery anchored to the raw shortest-path route before using smoothed waypoint nudges or generic fallbacks. - Adds raw-route target selection helpers with candidate predicates so recovery and continuation clicks stay on known walkable/unloaded route tiles. - Defers off-path recalculation while movement, interaction, animation, door/transport settling, recent clicks, route progress, or interim checkpoint progress indicate the player is still advancing. - Adds sticky interim checkpoint tracking and early `interim-in-flight` yields before broad scans, current-tile transport checks, direct short-walk attempts, and path segment scans. - Hints route progress after clicked-ahead checkpoints so later route anchoring does not snap back to nearby already-travelled branches. - Improves startup behavior by skipping speculative timeout-backed obstacle scans before the first movement click, while still allowing immediate planned transport steps to dispatch. - Suppresses active route idle nudges and stall recovery clicks when the current route segment is an explicit transport edge. - Tightens door/gate handling so wrong-traversal blacklisting only happens when the player started near the attempted door edge. - Accepts adjacent same-plane transport/object landings when the player settles near the expected destination instead of requiring the exact destination tile. - Improves charter ship handling by recursively resolving destination widgets, invoking the clickable widget/action, and confirming travel prompts when needed. - Updates `ShortestPathPlugin` route cleanup, pathfinder inventory quantity checks, WebWalk logging volume, movement docs, unit coverage, and the client-thread guardrail baseline. • Rs2Walker.java: immediate planned transports now suppress idle/stall recovery, so first-step teleports like Home Teleport should fire before pointless movement clicks. • Rs2Walker.java: active interim route clicks now yield before broad scans, reducing stop-start spam. • Rs2Walker.java: normal route clicks prefer raw shortest-path tiles instead of side/fallback tiles. • Rs2Walker.java: public walker entrypoints now reject client-thread calls before lock waits or player/tile reads. • Rs2WalkerUnitTest.java: added focused tests for route anchoring, raw-route click selection, interim yielding, and immediate-transport idle nudge suppression. • movement.md: documented the new walker gotchas Implemented the Al Kharid toll gate fix. What changed: • Added Pay-toll(10gp) transports for all four gate tiles in transports.tsv. • Added quest-free Open gate transports for Prince Ali Rescue completion. • Replaced the old quest-only tile restriction with blocked edge rules, so non-quest accounts can route through if they have 10 coins. • Walker now treats paid TRANSPORT rows as currency transports for item/banking checks. • Added special handling for Al Kharid toll gate confirmation: it uses Pay-toll(10gp) and clicks Yes, okay / Yes if prompted. I did not add the “talk to guard” fallback yet; this handles the cleaner object interaction path first. --- docs/entity-guides/movement.md | 91 +++- .../microbot/util/walker/Rs2Walker.java | 446 ++++++++++++++---- .../banking/Rs2WalkerBankingPlanner.java | 6 +- .../microbot/shortestpath/blocked_edges.tsv | 2 + .../microbot/shortestpath/restrictions.tsv | 8 +- .../microbot/shortestpath/transports.tsv | 8 + .../shortestpath/ShortestPathCoreTest.java | 72 +++ .../util/walker/Rs2WalkerUnitTest.java | 161 +++++++ 8 files changed, 684 insertions(+), 110 deletions(-) diff --git a/docs/entity-guides/movement.md b/docs/entity-guides/movement.md index 123d6eadef..235384a743 100644 --- a/docs/entity-guides/movement.md +++ b/docs/entity-guides/movement.md @@ -237,9 +237,9 @@ if (isStuckTooLong()) { For long open routes, retarget before the player fully stops when they are already close to the interim checkpoint, and keep normal minimap clicks slightly inside the observed minimap edge. This reduces visible stop/start pauses and outside-clip fallback clicks without reintroducing rapid click thrash. -## 12. Do not let optimistic recovery override unresolved door blockers +## 12. Do not let local recovery override unresolved door blockers -Unreachable-tile recovery is useful for outdoor false negatives, but in tight rooms it can fight the door resolver. If a route edge still has a door-like scene object on or adjacent to the raw path, suppress broad minimap recovery and let the door scanners retry after their normal cooldowns. Do not permanently blacklist a path-adjacent fallback door just because one attempt traversed the wrong way; in small door clusters the same object may be the correct blocker again once the player has moved to the other side. +Local-reachability recovery is useful for outdoor false negatives, but in tight rooms it can fight the door resolver. If a route edge still has a door-like scene object on or adjacent to the raw path, suppress broad minimap recovery and let the door scanners retry after their normal cooldowns. Do not permanently blacklist a path-adjacent fallback door just because one attempt traversed the wrong way; in small door clusters the same object may be the correct blocker again once the player has moved to the other side. **Why this matters:** In POH-style tight rooms with several doors close together, a fallback door click can move the player away from the intended route. If that door tile is session-blacklisted and optimistic recovery keeps clicking route tiles beyond the blocker, the walker loops around the room until a user manually opens the final door. @@ -257,7 +257,7 @@ clickOptimisticRecoveryTarget(); **Where this applies:** `Rs2Walker.processWalk` unreachable-tile handling, `tryResolvePathAdjacentBlocker`, and any fallback that issues minimap recovery clicks after door/path-adjacent scans fail. -**Defensive check:** Reproduce a route through a small room with three nearby doors and a POH portal. The walker should retry the route-door blocker and avoid repeated `unreachable optimistic recovery` loops around the room; it should not need the user to manually open the final door. +**Defensive check:** Reproduce a route through a small room with three nearby doors and a POH portal. The walker should retry the route-door blocker and avoid repeated `route-backed local recovery click` loops around the room; it should not need the user to manually open the final door. ## 13. Stall recalculation must also issue fresh movement @@ -300,9 +300,9 @@ When a route-following minimap click is outside the minimap clip, fallback click For adjacent same-plane shortcuts, do not treat any movement away from the origin as success. Some shortcuts, such as stepping stones, can fail and place the player on a fallback tile; once the player is settled away from the expected destination, stop the landing wait and replan from the actual tile. If the player is settled within one tile of the expected destination and is no longer on the origin, accept the landing instead of waiting for an exact tile that server pathing may not choose. -## 14. Keep optimistic recovery clicks route-backed and paced +## 14. Keep local recovery clicks route-backed and paced -Unreachable-tile recovery is a fallback for bounded reachability false negatives, not a license to pick an arbitrary minimap point. Recovery clicks should use the same route-backed raw-path fallback as normal route movement, then store the actual clicked target as the sticky interim checkpoint. After issuing the click, wait only for movement to start or the checkpoint/goal to be reached; do not wait for a full idle cycle before returning to the walk loop. +Local-reachability recovery is a fallback for bounded reachability false negatives, not a license to pick an arbitrary minimap point. Recovery clicks should use the same route-backed raw-path fallback as normal route movement, then store the actual clicked target as the sticky interim checkpoint. After issuing the click, wait only for movement to start or the checkpoint/goal to be reached; do not wait for a full idle cycle before returning to the walk loop. **Why this matters:** Bounded local reachability can report a valid route tile as unreachable even though the server pathfinder can still walk toward it. Arbitrary or repeated recovery clicks can pull the player away from the planned route and create visible stop-start movement. @@ -318,8 +318,85 @@ if (clickedTarget != null) { } ``` -**Where this applies:** `Rs2Walker.processWalk` unreachable-smoothed-tile recovery, route-backed direct short-walks, and any fallback that runs after local reachability says a route tile is not currently reachable. +**Where this applies:** `Rs2Walker.processWalk` local-reachability recovery, route-backed direct short-walks, and any fallback that runs after local reachability says a route tile is not currently reachable. -**Defensive check:** Exercise a long outdoor route and a route with gates or transports. Recovery logs should select route-backed points, and there should be no long idle pause between `unreachable optimistic recovery` and the next route-aligned movement. +**Defensive check:** Exercise a long outdoor route and a route with gates or transports. Recovery logs should select route-backed points, and there should be no long idle pause between `route-backed local recovery click` and the next route-aligned movement. After recovery sets a sticky interim target, do not issue another optimistic recovery while that interim is still active and movement/progress is fresh. Yield as `interim-in-flight` or another tail-exempt movement state until the checkpoint is close, stale, or expired. Otherwise the walker can loop through several recovery clicks while the player is already moving, especially when local reachability reports the next smoothed tile as unreachable. + +## 15. Keep primary route clicks on the raw route + +When a shortest-path raw route exists, choose the next minimap target from that raw route before applying smoothed-waypoint wall-distance nudges, bounded reachability shortcuts, or generic directional fallbacks. Sideways reachable tiles can be valid server walk targets while still being the wrong side of a fence, gate, or corridor corner. Generic fallback is only appropriate when no route-backed raw point is available. + +**Why this matters:** Tight routes near gates and fences can fail when the walker clicks a tile left or right of the drawn route line. The game then chooses its own path around the obstacle, which fights the planned door/transport handlers and produces stop-start recovery. + +**Pattern to follow:** + +```java +WorldPoint rawTarget = findFurthestRawPathPointMatching(rawPath, playerLoc, reach, rawAnchor, + Rs2Walker::isKnownWalkableOrUnloaded); +WorldPoint clickTarget = rawTarget != null ? rawTarget : getPointWithWallDistance(smoothedTarget); +``` + +**Where this applies:** `Rs2Walker.processWalk`, recovery clicks after false unreachable reports, route continuation clicks, direct short-walk fallbacks, and any minimap click helper used while a shortest-path raw route exists. + +**Defensive check:** Unit-test raw-route target selection with a route that doubles back near an earlier branch; the selected tile must stay at or ahead of the anchored raw route index. + +## 16. Yield before scans while an interim route click is in flight + +Sticky interim targets only reduce click thrash if they are checked before broad route scans. When a fresh interim checkpoint is still far away and the player is moving or has very recent checkpoint progress, yield before raw-scene scans, current-tile transport scans, direct short-walk attempts, and path segment scans. Resume normal route work once the checkpoint is close, stale, expired, on another plane, or movement has genuinely stopped. + +**Why this matters:** Long post-transport routes can otherwise run several no-op scans and select several small follow-up clicks while the previous minimap flag is still carrying the player. That looks like stop-start walking and burns tail iterations even though the route is making progress. + +**Pattern to follow:** + +```java +if (shouldYieldForActiveRouteInterim(playerLoc, path, nowMs)) { + exitReason = "interim-in-flight"; + continue; +} +``` + +**Where this applies:** `Rs2Walker.processWalk` before broad raw-scene handling, current-tile transport handling, direct short-walk handling, and the main path loop. + +**Defensive check:** Start a long route immediately after a transport. While the player is still moving toward the active minimap checkpoint, the walker should log a tail-exempt `interim-in-flight` yield instead of repeated `post_transport_path_selected` clicks for nearby path indices. + +## 17. Dispatch immediate planned transports before idle nudges + +When the current route index is an explicit shortest-path transport edge, let the segment transport handler run even during startup, before route idle nudges or stall recovery clicks. Keep startup door/rockfall probes skipped, but do not postpone teleports, ships, ladders, or other catalog-backed route transports that start at the player's current segment. + +**Why this matters:** Originless spell/item teleports can be the first edge in a route. If startup logic suppresses the segment handler and idle recovery runs first, the walker can sit on the origin, spam no-op route nudges, trigger stall recovery, and only then cast the teleport. + +**Pattern to follow:** + +```java +boolean immediateTransport = hasImmediatePlannedTransportStep(path, routeStartIdx, playerLoc); +if (shouldRunActiveRouteIdleNudge(idleNudgeDue, immediateTransport)) { + tryIssueRouteRecoveryClick(rawPath, path, target, "active route idle nudge"); +} +``` + +**Where this applies:** `Rs2Walker.processWalk` startup handling, active route idle nudges, stall recovery clicks, and segment transport dispatch. + +**Defensive check:** Start a route whose first planned edge is Home Teleport. Logs should show `transport_handoff_enter` for `TELEPORTATION_SPELL` without several `active route idle nudge: clicked=false` entries first. + +## 18. Model conditional paid gates as transports plus blocked edges + +When a gate can be crossed by either a quest unlock or a currency payment, do not model the gate tiles as quest-only restrictions. A tile restriction cannot express "quest complete OR pay coins", and it can prevent the walker from reaching the paid transport origin. Model each crossing as explicit paid/free transports and add a blocked edge override so normal walking cannot bypass the unavailable transport. + +**Why this matters:** The Lumbridge-to-Al Kharid toll gate can be opened freely after Prince Ali Rescue or paid through with 10 coins. A quest-only restriction blocks the paid route for accounts without the quest, while no edge block can let the pathfinder walk through the gate without paying. + +**Pattern to follow:** + +```java +// Wrong: restrict both sides of the gate to one quest state. +3267 3227 0 Prince Ali Rescue + +// Right: transport data decides availability; blocked_edges prevents free walking. +3267 3227 0 3268 3227 0 Pay-toll(10gp);Gate;2786 ... 10 Coins +3267 3227 0 3268 3227 0 Open;Gate;2786 ... Prince Ali Rescue +``` + +**Where this applies:** `transports.tsv`, `blocked_edges.tsv`, `restrictions.tsv`, `PathfinderConfig`, and `Rs2Walker.handleTransports`. + +**Defensive check:** Add resource tests that assert both paid and quest-free transports load, the gate tiles are not quest-only restricted, and the gate edge is blocked without a usable transport. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java index 9de5153b3a..9afa31c64c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java @@ -48,6 +48,7 @@ import net.runelite.client.plugins.microbot.util.leaguetransport.SeasonalTransportHandlers; import net.runelite.client.plugins.microbot.util.logging.Rs2LogRateLimit; import java.util.function.BooleanSupplier; +import java.util.function.Predicate; import org.slf4j.event.Level; import net.runelite.client.plugins.microbot.util.poh.PohTeleports; import net.runelite.client.plugins.microbot.util.poh.PohTransport; @@ -206,6 +207,16 @@ public static WorldPoint getCurrentTarget() { private static volatile long routeProgressAdvancedAtMs = 0L; private static final java.util.Deque expectedTransportDestinations = new ArrayDeque<>(); private static final Set startupPhasesLogged = ConcurrentHashMap.newKeySet(); + private static final Set AL_KHARID_TOLL_GATE_OBJECT_IDS = Set.of( + net.runelite.api.ObjectID.CITY_GATE_2786, + net.runelite.api.ObjectID.CITY_GATE_2787, + net.runelite.api.ObjectID.CITY_GATE_2788, + net.runelite.api.ObjectID.CITY_GATE_2789); + private static final Set AL_KHARID_TOLL_GATE_POINTS = Set.of( + new WorldPoint(3267, 3227, 0), + new WorldPoint(3267, 3228, 0), + new WorldPoint(3268, 3227, 0), + new WorldPoint(3268, 3228, 0)); /** * Max Chebyshev "radius" for Quetzal / near-destination checks — guards use {@code distanceTo2D < OFFSET}. @@ -434,6 +445,15 @@ private static WalkerPhase currentWalkerPhase() { return WalkerPhase.STARTUP; } + private static boolean isClientThread() { + Client client = Microbot.getClient(); + return client != null && client.isClientThread(); + } + + private static int reachedDistanceOrDefault() { + return config != null ? config.reachedDistance() : 10; + } + private static ObstaclePolicy obstaclePolicyForCurrentPhase() { return currentWalkerPhase() == WalkerPhase.STARTUP ? STARTUP_OBSTACLE_POLICY @@ -455,6 +475,11 @@ static boolean shouldSkipStartupPreclickSegmentHandlers(boolean startupBeforeFir return true; } + static boolean shouldRunActiveRouteIdleNudge(boolean idleNudgeDue, + boolean immediateRouteTransportPending) { + return idleNudgeDue && !immediateRouteTransportPending; + } + /** * Same-plane Chebyshev distance from player to {@code dest} strictly less than {@code maxChebyshevExclusive}. * Requires matching {@link WorldPoint#getPlane()} before using {@link WorldPoint#distanceTo2D} — that method only @@ -921,7 +946,7 @@ public static int totalRecalcs() { ); public static boolean walkTo(int x, int y, int plane) { - return walkTo(x, y, plane, config.reachedDistance()); + return walkTo(x, y, plane, reachedDistanceOrDefault()); } /** @@ -937,7 +962,7 @@ public static boolean walkTo(int x, int y, int plane, int distance) { * result is {@code false}, same as any non-arrival outcome. */ public static boolean walkTo(WorldPoint target) { - return walkWithState(target, config.reachedDistance()) == WalkerState.ARRIVED; + return walkWithState(target, reachedDistanceOrDefault()) == WalkerState.ARRIVED; } /** @@ -991,6 +1016,10 @@ public static WalkerState walkWithState(WorldPoint target, int distance) { log.warn("[Walker] walk rejected: null target"); return WalkerState.EXIT; } + if (isClientThread()) { + log.warn("Please do not call the walker from the main thread"); + return WalkerState.EXIT; + } if (!walkerLock.tryLock()) { log.warn("[Walker] concurrent walk request detected, waiting for in-flight walk (held by {}); new target={}", Thread.currentThread().getName(), target); @@ -1031,6 +1060,11 @@ public static WalkerState walkWithStateTry(WorldPoint target, int distance, long log.warn("[Walker] walk rejected: null target"); return WalkerState.EXIT; } + if (isClientThread()) + { + log.warn("Please do not call the walker from the main thread"); + return WalkerState.EXIT; + } if (lockWaitMs < 0) { throw new IllegalArgumentException("lockWaitMs must be >= 0"); @@ -1080,6 +1114,10 @@ public static WalkerState walkWithStateTry(WorldPoint target, int distance, long */ private static WalkerState walkWithStateInternal(WorldPoint target, int distance) { Objects.requireNonNull(target, "walk target"); + if (isClientThread()) { + log.warn("Please do not call the walker from the main thread"); + return WalkerState.EXIT; + } WorldPoint playerLocWalk = Rs2Player.getWorldLocation(); if (playerLocWalk == null) { return WalkerState.MOVING; @@ -1120,11 +1158,6 @@ private static WalkerState walkWithStateInternal(WorldPoint target, int distance idleNudgeStationarySinceMs = System.currentTimeMillis(); lastActiveRouteIdleNudgeAtMs = 0L; - if (Microbot.getClient().isClientThread()) { - log.warn("Please do not call the walker from the main thread"); - return WalkerState.EXIT; - } - closeWorldMap(); if (Rs2Bank.isOpen()) { Rs2Bank.closeBank(); @@ -1138,7 +1171,7 @@ private static WalkerState walkWithStateInternal(WorldPoint target, int distance * @return */ public static WalkerState walkWithState(WorldPoint target) { - return walkWithState(target, config.reachedDistance()); + return walkWithState(target, reachedDistanceOrDefault()); } /** @@ -1306,6 +1339,9 @@ private static WalkerState processWalk(WorldPoint target, int distance, int part } } + int earlyRouteStartIdx = stabilizeRouteProgressIndex(path, walkLoop.closestTileIndex(path), target, walkLoop.playerLoc); + boolean immediateRouteTransportPending = hasImmediatePlannedTransportStep(path, earlyRouteStartIdx, walkLoop.playerLoc); + // Do not clear walk target while a sticky minimap interim is active — breaks // isWalkCancelled and forces EXIT while the flag is still carrying the player. // Partial paths end at an intermediate waypoint (dst still far from {@code target}); @@ -1349,18 +1385,25 @@ private static WalkerState processWalk(WorldPoint target, int distance, int part lastMovedTimeMs = System.currentTimeMillis(); stuckCount = 0; clearInterimTarget("stall-recalc"); - setTarget(target); - if (!Rs2Player.isMoving() && !Rs2Player.isAnimating() && !Rs2Player.isInteracting()) { + if (immediateRouteTransportPending) { + WebWalkLog.spDebug("stall_recovery_suppressed | reason=immediate-route-transport idx={}", earlyRouteStartIdx); + } else if (!Rs2Player.isMoving() && !Rs2Player.isAnimating() && !Rs2Player.isInteracting()) { + setTarget(target); tryIssueRouteRecoveryClick(rawPath, path, target, "stall recovery click"); + continue; + } else { + setTarget(target); + continue; } - continue; } - if (shouldIssueActiveRouteIdleNudge - && tryIssueRouteRecoveryClick(rawPath, path, target, "active route idle nudge")) { - lastAttemptedMinimapClick = null; - lastAttemptedMinimapClickOk = false; - lastAttemptedMinimapClickAtMs = 0L; - continue; + if (shouldRunActiveRouteIdleNudge(shouldIssueActiveRouteIdleNudge, immediateRouteTransportPending)) { + if (tryIssueRouteRecoveryClick(rawPath, path, target, "active route idle nudge")) { + lastAttemptedMinimapClick = null; + lastAttemptedMinimapClickOk = false; + lastAttemptedMinimapClickAtMs = 0L; + continue; + } + lastActiveRouteIdleNudgeAtMs = System.currentTimeMillis(); } if (stuckCount > 10) { var reachable = Rs2Tile.getReachableTilesFromTile(Rs2Player.getWorldLocation(), 5).keySet(); @@ -1462,6 +1505,31 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { Map doorEdgesAttemptedThisTail = new HashMap<>(); ObstaclePolicy startupPolicy = obstaclePolicyForCurrentPhase(); + WorldPoint activeInterimPlayer = Rs2Player.getWorldLocation(); + long activeInterimNowMs = System.currentTimeMillis(); + if (!Rs2Player.isInteracting() + && !Rs2Player.isAnimating() + && !isDoorInteractionSettling() + && !isTransportInteractionSettling() + && (target == null + || activeInterimPlayer == null + || activeInterimPlayer.distanceTo(target) > immediateFinishTh) + && shouldYieldForActiveRouteInterim(activeInterimPlayer, path, activeInterimNowMs)) { + exitReason = "interim-in-flight"; + WebWalkLog.earlyExit(exitReason, + activeInterimPlayer, + target, + path.get(path.size() - 1), + indexOfStartPoint, + path.size()); + walkerDiag("tail exempt exitReason=%s tailBefore=%d early=true interim=%s", + exitReason, + processWalkTail, + interimTargetWp); + processWalkTail--; + continue; + } + boolean postTransportWindow = lastTransportHandledAtMs > 0 && System.currentTimeMillis() - lastTransportHandledAtMs <= POST_TRANSPORT_PATH_TMARK_WINDOW_MS; boolean allowRawSceneScan = startupPolicy.allowBroadRawHandlers() && rawPath != null && path != null; @@ -1597,6 +1665,8 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { boolean upcomingNearbyTransport = hasUpcomingNearbyTransportStep(path, i, playerNearSeg, POST_TRANSPORT_RAW_SCAN_TRANSPORT_LOOKAHEAD_EDGES, POST_TRANSPORT_RAW_SCAN_TRANSPORT_MAX_DIST); + boolean startupBeforeFirstClick = currentWalkerPhase() == WalkerPhase.STARTUP; + boolean immediateSegmentTransportStep = hasImmediatePlannedTransportStep(path, i, playerNearSeg); boolean recentDoorAttemptNearSegment = hasRecentDoorAttemptNearIndex(path, i); boolean skipPostTransportSegmentHandlers = recentTransportWindow && !upcomingNearbyTransport @@ -1604,8 +1674,9 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { && !isDoorInteractionSettling() && !isRecoveryMovementInFlight() && reachableTilesCache.containsKey(currentWorldPoint); - boolean skipStartupPreclickSegmentHandlers = shouldSkipStartupPreclickSegmentHandlers( - currentWalkerPhase() == WalkerPhase.STARTUP, + boolean skipStartupPreclickSegmentHandlers = !immediateSegmentTransportStep + && shouldSkipStartupPreclickSegmentHandlers( + startupBeforeFirstClick, i, indexOfStartPoint, recentDoorAttemptNearSegment, @@ -1625,7 +1696,9 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { long segmentHandlerStartAt = System.currentTimeMillis(); int rawI = (i < smoothedToRaw.length) ? smoothedToRaw[i] : 0; int rawEnd = rawEndForSmoothedIndex(i, smoothedToRaw, rawPath, path); - if (!Rs2Player.isMoving() && !isDoorInteractionSettling() && !isRecoveryMovementInFlight()) { + boolean startupImmediateTransportOnly = startupBeforeFirstClick && immediateSegmentTransportStep; + if (!startupImmediateTransportOnly + && !Rs2Player.isMoving() && !isDoorInteractionSettling() && !isRecoveryMovementInFlight()) { doorOrTransportResult = handleDoorsInRawSegment(rawPath, rawI, rawEnd, obstaclePolicy.segmentDoorTimeoutMs(), doorEdgesAttemptedThisTail, reachableTilesCache); @@ -1641,7 +1714,8 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { boolean allowPathAdjacentProbe = !recentTransportWindow || upcomingNearbyTransport || recentDoorAttemptNearSegment; - if (!Rs2Player.isMoving() && obstaclePolicy.allowPathAdjacentProbe() + if (!startupImmediateTransportOnly + && !Rs2Player.isMoving() && obstaclePolicy.allowPathAdjacentProbe() && allowPathAdjacentProbe) { if (tryHandleBlockingPathObjectsWithTimeout(rawPath, rawI, 5, 10, obstaclePolicy.pathAdjacentProbeTimeoutMs(), doorEdgesAttemptedThisTail)) { @@ -1652,8 +1726,10 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { } } - doorOrTransportResult = handleRockfallInRawSegment(rawPath, rawI, rawEnd, - reachableTilesCache); + if (!startupImmediateTransportOnly) { + doorOrTransportResult = handleRockfallInRawSegment(rawPath, rawI, rawEnd, + reachableTilesCache); + } if (doorOrTransportResult) { tmarkPostTransport("post_transport_segment_handler", target, "stage=rockfall handled=true i=" + i + " ms=" + (System.currentTimeMillis() - segmentHandlerStartAt)); @@ -1661,7 +1737,9 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { break; } - boolean allowSegmentTransportScan = !recentTransportWindow || upcomingNearbyTransport; + boolean allowSegmentTransportScan = !recentTransportWindow + || upcomingNearbyTransport + || immediateSegmentTransportStep; if ((PohTeleports.isInHouse() || !inInstance) && allowSegmentTransportScan) { doorOrTransportResult = handleTransportsInRawSegment(rawPath, rawI, rawEnd); } @@ -1697,7 +1775,7 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { if (playerLoc != null) { int unreachableDist = currentWorldPoint.distanceTo2D(playerLoc); if (unreachableDist <= HANDLER_RANGE + 2) { - log.info("[Walker] unreachable path tile near player: tile={} idx={}/{} player={} target={}", + log.info("[Walker] local reachability miss near player; checking blockers/recovery: tile={} idx={}/{} player={} target={}", currentWorldPoint, i, path.size(), playerLoc, target); int edgeIdx = Math.max(indexOfStartPoint, i - 1); @@ -1761,13 +1839,13 @@ && tryIssueRouteContinuationClick(rawPath, path, target)) { } if (handlePendingDoorNearRawPath(rawPath, obstaclePolicy.unreachableDoorTimeoutMs(), doorEdgesAttemptedThisTail, playerLoc, 2, 14)) { - exitReason = "door-handled-unreachable-raw-scan"; + exitReason = "door-handled-local-reachability-raw-scan"; break; } if (handleDoorsInRawSegment(rawPath, rawEdgeStart, rawEdgeEnd, obstaclePolicy.unreachableDoorTimeoutMs(), doorEdgesAttemptedThisTail, null)) { - exitReason = "door-handled-unreachable"; + exitReason = "door-handled-local-reachability"; break; } if (isRecoveryMovementInFlight()) { @@ -1858,8 +1936,12 @@ && handleUnresolvedDoorNearRawPath(rawPath, rawEdgeStart, recoverTarget = path.get(safeIdx); } int rawAnchorIndex = rawIndexForSmoothedIndex(recoverIdx, smoothedToRaw, rawPath); - WorldPoint rawRecoveryTarget = findFurthestReachableRawPathPoint(rawPath, playerLoc, - recoveryMinimapReach - 1, rawAnchorIndex); + WorldPoint rawRecoveryTarget = inInstance ? null : findFurthestRawPathPointMatching( + rawPath, + playerLoc, + recoveryMinimapReach - 1, + rawAnchorIndex, + Rs2Walker::isKnownWalkableOrUnloaded); if (rawRecoveryTarget != null && !rawRecoveryTarget.equals(playerLoc) && (dangerCfg == null @@ -1888,11 +1970,14 @@ && walkFastCanvas(recoverTarget)) { clickedRecoveryTarget = recoverTarget; log.debug("[Walker] unreachable recovery: scene click -> {}", recoverTarget); } - log.info("[Walker] unreachable optimistic recovery: clicked={} to={} pathTile={} idx={}", + log.info("[Walker] route-backed local recovery click: clicked={} to={} pathTile={} idx={}", clicked, clicked ? clickedRecoveryTarget : recoverTarget, currentWorldPoint, recoverIdx); if (clicked) { - markFirstMovementClick("first_recovery_click", target, playerLoc, + markFirstMovementClick("first_local_recovery_click", target, playerLoc, "to=" + compactWorldPoint(clickedRecoveryTarget)); + hintRouteProgressIndex(path, + Math.min(recoverIdx, i + INTERIM_CLOSE_TILES), + target); lastUnreachableRecoveryClickAtMs = System.currentTimeMillis(); // Sticky interim: subsequent iterations travel toward this point via the // interim-in-flight path instead of re-running the (false-negative) @@ -1912,10 +1997,10 @@ && walkFastCanvas(recoverTarget)) { // spurious stall-recalc right after issuing recovery movement. lastMovedTimeMs = System.currentTimeMillis(); stuckCount = 0; - exitReason = "unreachable-recovery-click"; + exitReason = "local-recovery-click"; break; } - exitReason = "tile-unreachable-near-player"; + exitReason = "local-reachability-miss-no-click"; break; } } @@ -2075,9 +2160,21 @@ && walkFastCanvas(recoverTarget)) { } WorldPoint posBefore = playerLoc; - WorldPoint clickTarget = inInstance ? targetWp : getPointWithWallDistance(targetWp); - if (!inInstance) { - int rawAnchorIndex = rawIndexForSmoothedIndex(i, smoothedToRaw, rawPath); + int rawAnchorIndex = rawIndexForSmoothedIndex(i, smoothedToRaw, rawPath); + WorldPoint rawRouteTarget = inInstance ? null : findFurthestRawPathPointMatching( + rawPath, + playerLoc, + MINIMAP_REACH_EUCLIDEAN - 1, + rawAnchorIndex, + Rs2Walker::isKnownWalkableOrUnloaded); + WorldPoint clickTarget; + if (rawRouteTarget != null && !rawRouteTarget.equals(playerLoc)) { + targetWp = rawRouteTarget; + clickTarget = rawRouteTarget; + } else { + clickTarget = inInstance ? targetWp : getPointWithWallDistance(targetWp); + } + if (!inInstance && rawRouteTarget == null) { WorldPoint rawReachableTarget = findFurthestReachableRawPathPoint(rawPath, playerLoc, MINIMAP_REACH_EUCLIDEAN - 1, rawAnchorIndex); if (!Rs2Tile.isTileReachable(clickTarget) && rawReachableTarget != null) { @@ -2103,7 +2200,6 @@ && walkFastCanvas(recoverTarget)) { "to=" + compactWorldPoint(clickTarget)); } markStartupPhase("click_candidate_found", target, "to=" + compactWorldPoint(clickTarget)); - int rawAnchorIndex = rawIndexForSmoothedIndex(i, smoothedToRaw, rawPath); WorldPoint clickedTarget = clickMiniMapOrFallback(rawPath, clickTarget, playerLoc, MINIMAP_REACH_EUCLIDEAN - 1, rawPath == null || rawPath.isEmpty(), rawAnchorIndex); boolean clicked = clickedTarget != null; @@ -2116,6 +2212,9 @@ && walkFastCanvas(recoverTarget)) { if (clicked) { markFirstMovementClick("first_minimap_click", target, posBefore, "to=" + compactWorldPoint(clickedTarget)); + hintRouteProgressIndex(path, + Math.min(targetIdx, i + INTERIM_CLOSE_TILES), + target); interimTargetWp = clickedTarget; interimTargetIdx = targetIdx; interimSetAtMs = nowMs; @@ -2150,6 +2249,9 @@ && walkFastCanvas(recoverTarget)) { MINIMAP_REACH_EUCLIDEAN - 1, false, rawAnchorIndex); if (routeRetryTarget != null) { routeRetryClicked = true; + hintRouteProgressIndex(path, + Math.min(targetIdx, i + INTERIM_CLOSE_TILES), + target); lastAttemptedMinimapClick = routeRetryTarget; lastAttemptedMinimapClickOk = true; lastAttemptedMinimapClickAtMs = System.currentTimeMillis(); @@ -2670,7 +2772,7 @@ private static WorldPoint walkRawPathMiniMapTargetToward(List rawPat WorldPoint playerLoc, int maxEuclidean, int rawAnchorIndex) { - WorldPoint fallback = findFurthestVisibleReachableRawPathPoint(rawPath, playerLoc, + WorldPoint fallback = findFurthestVisibleKnownRawPathPoint(rawPath, playerLoc, maxEuclidean, rawAnchorIndex); if (fallback == null || fallback.equals(playerLoc) || fallback.equals(target)) { return null; @@ -2752,6 +2854,18 @@ static WorldPoint findFurthestReachableRawPathPoint(List rawPath, WorldPoint playerLoc, int maxEuclidean, int rawAnchorIndex) { + Set reachable = playerLoc == null + ? Collections.emptySet() + : Rs2Tile.getReachableTilesFromTile(playerLoc, Math.max(2, maxEuclidean)).keySet(); + return findFurthestRawPathPointMatching(rawPath, playerLoc, maxEuclidean, rawAnchorIndex, + reachable::contains); + } + + static WorldPoint findFurthestRawPathPointMatching(List rawPath, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex, + Predicate isCandidate) { if (rawPath == null || rawPath.isEmpty() || playerLoc == null) { return null; } @@ -2763,7 +2877,6 @@ static WorldPoint findFurthestReachableRawPathPoint(List rawPath, int maxSq = maxEuclidean * maxEuclidean; int maxRouteSteps = maxEuclidean + 2; int routeSteps = 0; - Set reachable = Rs2Tile.getReachableTilesFromTile(playerLoc, Math.max(2, maxEuclidean)).keySet(); WorldPoint best = null; for (int rawIndex = closestRawIndex; rawIndex < rawPath.size(); rawIndex++) { WorldPoint candidate = rawPath.get(rawIndex); @@ -2780,58 +2893,31 @@ static WorldPoint findFurthestReachableRawPathPoint(List rawPath, if (euclideanSq(candidate, playerLoc) > maxSq) { break; } - if (reachable.contains(candidate)) { + if (!candidate.equals(playerLoc) && (isCandidate == null || isCandidate.test(candidate))) { best = candidate; } } return best; } - static WorldPoint findFurthestVisibleReachableRawPathPoint(List rawPath, - WorldPoint playerLoc, - int maxEuclidean) { - return findFurthestVisibleReachableRawPathPoint(rawPath, playerLoc, maxEuclidean, -1); + static WorldPoint findFurthestVisibleKnownRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean) { + return findFurthestVisibleKnownRawPathPoint(rawPath, playerLoc, maxEuclidean, -1); } - static WorldPoint findFurthestVisibleReachableRawPathPoint(List rawPath, - WorldPoint playerLoc, - int maxEuclidean, - int rawAnchorIndex) { + static WorldPoint findFurthestVisibleKnownRawPathPoint(List rawPath, + WorldPoint playerLoc, + int maxEuclidean, + int rawAnchorIndex) { if (rawPath == null || rawPath.isEmpty() || playerLoc == null) { return null; } - int closestRawIndex = rawPathForwardAnchorIndex(rawPath, playerLoc, rawAnchorIndex); - if (closestRawIndex < 0) { - return null; - } - int maxSq = maxEuclidean * maxEuclidean; - int maxRouteSteps = maxEuclidean + 2; - int routeSteps = 0; - Set reachable = Rs2Tile.getReachableTilesFromTile(playerLoc, Math.max(2, maxEuclidean)).keySet(); - WorldPoint best = null; - for (int rawIndex = closestRawIndex; rawIndex < rawPath.size(); rawIndex++) { - WorldPoint candidate = rawPath.get(rawIndex); - if (candidate == null || candidate.getPlane() != playerLoc.getPlane()) { - break; - } - if (rawIndex > closestRawIndex) { - WorldPoint previous = rawPath.get(rawIndex - 1); - routeSteps += rawPathStepDistance(previous, candidate); - if (routeSteps > maxRouteSteps) { - break; - } - } - if (euclideanSq(candidate, playerLoc) > maxSq) { - break; - } - if (!candidate.equals(playerLoc) - && reachable.contains(candidate) - && isMiniMapClickable(candidate, 5)) { - best = candidate; - } - } - return best; + return findFurthestRawPathPointMatching(rawPath, playerLoc, maxEuclidean, rawAnchorIndex, + candidate -> !candidate.equals(playerLoc) + && isKnownWalkableOrUnloaded(candidate) + && isMiniMapClickable(candidate, 5)); } private static int rawPathStepDistance(WorldPoint previous, WorldPoint current) { @@ -2943,16 +3029,17 @@ private static boolean tryIssueRouteMovementClick(List rawPath, return false; } int targetIdx = stabilizeRouteProgressIndex(path, getClosestTileIndex(path, playerLoc), target, playerLoc); + int startIdx = Math.max(0, targetIdx); int[] routeSmoothedToRaw = mapSmoothedToRaw(path, rawPath); int rawAnchorIndex = rawIndexForSmoothedIndex(targetIdx, routeSmoothedToRaw, rawPath); - WorldPoint clickTarget = findFurthestReachableRawPathPoint( + WorldPoint clickTarget = findFurthestRawPathPointMatching( rawPath, playerLoc, maxEuclidean, - rawAnchorIndex); + rawAnchorIndex, + Rs2Walker::isKnownWalkableOrUnloaded); if (clickTarget == null) { - int startIdx = Math.max(0, targetIdx); int clickableIdx = findFurthestForwardClickableIndex(path, startIdx, playerLoc, wp -> { Set ts = ShortestPathPlugin.getTransports().get(wp); @@ -2997,6 +3084,9 @@ private static boolean tryIssueRouteMovementClick(List rawPath, target, playerLoc, "to=" + compactWorldPoint(clickedTarget)); + hintRouteProgressIndex(path, + Math.min(targetIdx, startIdx + INTERIM_CLOSE_TILES), + target); interimTargetWp = clickedTarget; interimTargetIdx = targetIdx; interimSetAtMs = System.currentTimeMillis(); @@ -3538,6 +3628,7 @@ private static List applyTransportFiltering(List transport t.getType() == TransportType.BOAT || t.getType() == TransportType.CHARTER_SHIP || t.getType() == TransportType.SHIP || t.getType() == TransportType.MINECART || t.getType() == TransportType.MAGIC_CARPET || t.getType() == TransportType.SPIRIT_TREE || + (t.getType() == TransportType.TRANSPORT && t.getCurrencyAmount() > 0) || (t.getType() == TransportType.SEASONAL_TRANSPORT && Rs2LeaguesTransport.isLeaguesActive() && t.getDisplayInfo() != null @@ -5431,6 +5522,31 @@ private static boolean shouldYieldForActiveRecoveryInterim(WorldPoint playerLoc, Rs2Player.isMoving()); } + private static boolean shouldYieldForActiveRouteInterim(WorldPoint playerLoc, + List path, + long nowMs) { + WorldPoint interim = interimTargetWp; + if (interim == null) { + return false; + } + recordInterimDistanceProgress(interim, playerLoc, nowMs); + if (playerLoc != null && path != null && !path.isEmpty()) { + int bestIdxNow = getClosestTileIndex(path, playerLoc); + if (bestIdxNow > interimLastBestPathIdx) { + interimLastBestPathIdx = bestIdxNow; + interimLastProgressAtMs = nowMs; + } + } + return shouldDeferRouteWorkForActiveInterim(interim, + playerLoc, + interimSetAtMs, + interimLastProgressAtMs, + nowMs, + lastMovedTimeMs, + Rs2Player.isMoving(), + INTERIM_CLOSE_TILES); + } + static boolean shouldYieldForActiveRecoveryInterim(WorldPoint interim, WorldPoint playerLoc, long setAtMs, @@ -5445,16 +5561,46 @@ static boolean shouldYieldForActiveRecoveryInterim(WorldPoint interim, if (shouldClearInterimTarget(interim, playerLoc, setAtMs, lastProgressAtMs, nowMs)) { return false; } - if (playerMoving) { + if (shouldDeferRouteWorkForActiveInterim(interim, + playerLoc, + setAtMs, + lastProgressAtMs, + nowMs, + lastMovedAtMs, + playerMoving, + INTERIM_CLOSE_TILES)) { return true; } - if (isRecentEvent(nowMs, lastProgressAtMs, INTERIM_PROGRESS_TIMEOUT_MS)) { + return isRecentEvent(nowMs, lastRecoveryClickAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS); + } + + static boolean shouldDeferRouteWorkForActiveInterim(WorldPoint interim, + WorldPoint playerLoc, + long setAtMs, + long lastProgressAtMs, + long nowMs, + long lastMovedAtMs, + boolean playerMoving, + int handoffTiles) { + if (interim == null) { + return false; + } + if (shouldClearInterimTarget(interim, playerLoc, setAtMs, lastProgressAtMs, nowMs)) { + return false; + } + if (playerLoc == null || playerLoc.getPlane() != interim.getPlane()) { + return false; + } + if (playerLoc.distanceTo2D(interim) <= Math.max(0, handoffTiles)) { + return false; + } + if (playerMoving) { return true; } - if (isRecentEvent(nowMs, lastMovedAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS)) { + if (isRecentEvent(nowMs, lastProgressAtMs, INTERIM_PROGRESS_TIMEOUT_MS)) { return true; } - return isRecentEvent(nowMs, lastRecoveryClickAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS); + return isRecentEvent(nowMs, lastMovedAtMs, RECOVERY_MOVEMENT_IN_FLIGHT_MS); } private static void clearInterimTarget(String reason) { @@ -5584,6 +5730,20 @@ private static boolean hasExplicitTransportStep(List path, int index return matchesDirectedTransportCatalogEdge(path.get(index), path.get(index + 1)); } + private static boolean hasImmediatePlannedTransportStep(List path, + int routeStartIdx, + WorldPoint playerLoc) { + if (path == null || routeStartIdx < 0 || routeStartIdx >= path.size() - 1 || playerLoc == null) { + return false; + } + WorldPoint origin = path.get(routeStartIdx); + if (origin == null || origin.getPlane() != playerLoc.getPlane() + || origin.distanceTo2D(playerLoc) > HANDLER_RANGE) { + return false; + } + return hasExplicitTransportStep(path, routeStartIdx); + } + /** * Whether this path edge is covered by a transport catalog row (same coordinates loaded from TSV into * {@link ShortestPathPlugin#getTransports()}). Includes strict origin-destination steps (including @@ -7227,6 +7387,35 @@ static int stabilizeRouteProgressIndex(List path, int closestIdx, Wo return routeProgressIdx; } + static void hintRouteProgressIndex(List path, int hintedIdx, WorldPoint target) { + if (path == null || path.isEmpty() || hintedIdx < 0 || hintedIdx >= path.size()) { + return; + } + + WorldPoint pathStart = path.get(0); + WorldPoint pathEnd = path.get(path.size() - 1); + boolean routeChanged = routeProgressTarget == null + || !routeProgressTarget.equals(target) + || routeProgressPathSize != path.size() + || !Objects.equals(routeProgressPathStart, pathStart) + || !Objects.equals(routeProgressPathEnd, pathEnd) + || routeProgressIdx >= path.size(); + if (routeChanged) { + routeProgressTarget = target; + routeProgressPathStart = pathStart; + routeProgressPathEnd = pathEnd; + routeProgressPathSize = path.size(); + routeProgressIdx = hintedIdx; + recordRouteProgressAdvanced(); + return; + } + + if (hintedIdx > routeProgressIdx) { + routeProgressIdx = hintedIdx; + recordRouteProgressAdvanced(); + } + } + static int advanceIndexPastRecentTransportEdge(List path, int index, WorldPoint playerLoc) { if (path == null || path.isEmpty() || index < 0 || index >= path.size() || !isRecentTransportEdgeWindow()) { @@ -7497,7 +7686,10 @@ && recentlyOpenedStationaryDoorOnSegment(path.get(indexOfStartPoint), path.get(i pathFirstIndex.putIfAbsent(path.get(idx), idx); } - for (Transport transport : transports) { + List orderedTransports = new ArrayList<>(transports); + orderedTransports.sort(Comparator.comparingInt(Rs2Walker::transportHandlingPreference)); + + for (Transport transport : orderedTransports) { Collection worldPointCollections; //in some cases the getOrigin is null, for teleports that start the player location if (transport.getOrigin() == null) { @@ -7821,8 +8013,10 @@ && recentlyOpenedStationaryDoorOnSegment(path.get(indexOfStartPoint), path.get(i final boolean allowClosedVariant = "Climb-down".equalsIgnoreCase(transportAction) || "Climb down".equalsIgnoreCase(transportAction); + final boolean allowAlKharidTollGateVariant = isAlKharidTollGateObjectId(transportObjectId); List objects = Rs2GameObject.getAll(o -> { if (o.getId() == transportObjectId) return true; + if (allowAlKharidTollGateVariant && isAlKharidTollGateObjectId(o.getId())) return true; Integer legacyClosed = OPEN_TO_CLOSED_MAPPINGS.get(transportObjectId); if (legacyClosed != null && o.getId() == legacyClosed) return true; if (!allowClosedVariant) return false; @@ -8384,6 +8578,61 @@ static Set adjacentSamePlaneTransportSuppressionPoints(Transport tra return points; } + private static int transportHandlingPreference(Transport transport) { + if (isAlKharidTollGateTransport(transport) && transport.getCurrencyAmount() > 0) { + return 1; + } + return 0; + } + + private static boolean isAlKharidTollGateTransport(Transport transport, TileObject tileObject) { + return isAlKharidTollGateTransport(transport) + && tileObject != null + && isAlKharidTollGateObjectId(tileObject.getId()); + } + + private static boolean isAlKharidTollGateTransport(Transport transport) { + return transport != null + && isAlKharidTollGateObjectId(transport.getObjectId()) + && AL_KHARID_TOLL_GATE_POINTS.contains(transport.getOrigin()) + && AL_KHARID_TOLL_GATE_POINTS.contains(transport.getDestination()); + } + + private static boolean isAlKharidTollGateObjectId(int objectId) { + return AL_KHARID_TOLL_GATE_OBJECT_IDS.contains(objectId); + } + + private static boolean isPayTollAction(String action) { + return action != null && action.toLowerCase(Locale.ROOT).startsWith("pay-toll"); + } + + private static boolean handleAlKharidTollGate(Transport transport) { + if (Rs2Player.isMoving()) { + Rs2Player.waitForWalking(); + } + + boolean confirmed = false; + if (sleepUntil(Rs2Dialogue::hasSelectAnOption, 2500)) { + confirmed = Rs2Dialogue.clickOption("Yes, okay", "Yes"); + } + + boolean reachedDestination = sleepUntil(() -> { + WorldPoint now = Rs2Player.getWorldLocation(); + WorldPoint destination = transport.getDestination(); + return now != null + && destination != null + && now.getPlane() == destination.getPlane() + && now.distanceTo2D(destination) <= 1; + }, POST_HANDLE_OBJECT_LANDING_WAIT_MS); + if (!confirmed && !reachedDestination) { + WebWalkLog.spWarn( + "Al Kharid toll gate confirmation unresolved dest={} at={}", + compactWorldPoint(transport.getDestination()), + compactWorldPoint(Rs2Player.getWorldLocation())); + } + return true; + } + private static boolean handleObjectExceptions(Transport transport, TileObject tileObject) { for (Map.Entry entry : OPEN_TO_CLOSED_MAPPINGS.entrySet()) { final int closedTrapdoorId = entry.getKey(); @@ -8415,6 +8664,10 @@ private static boolean handleObjectExceptions(Transport transport, TileObject ti } } + if (isAlKharidTollGateTransport(transport, tileObject) && isPayTollAction(transport.getAction())) { + return handleAlKharidTollGate(transport); + } + //Al kharid broken wall will animate once and then stop and then animate again if (tileObject.getId() == ObjectID.KHARID_POSHWALL_TOPLESS || tileObject.getId() == ObjectID.KHARID_BIGWINDOW) { Rs2Player.waitForAnimation(); @@ -8623,7 +8876,7 @@ private static boolean handleTeleportItem(Transport transport) { for (Integer itemId : itemIds) { if (Rs2Walker.currentTarget == null) break; // reachedDistance <= 0: do not treat as "already at destination" (legacy: raw distance < 0 never true). - int reachRd = config.reachedDistance(); + int reachRd = reachedDistanceOrDefault(); if (reachRd > 0 && isPlayerWithinChebyshevOf(transport.getDestination(), reachRd)) { break; } @@ -9107,14 +9360,16 @@ private static boolean isStuckTooLong() { * @param start */ public void setStart(WorldPoint start) { - if (ShortestPathPlugin.getPathfinder() == null) { + Pathfinder pathfinder = ShortestPathPlugin.getPathfinder(); + if (pathfinder == null) { return; } + Set targets = pathfinder.getTargets(); ShortestPathPlugin.setStartPointSet(true); - if (Microbot.getClient().isClientThread()) { - Microbot.getClientThread().runOnSeperateThread(() -> restartPathfinding(start, ShortestPathPlugin.getPathfinder().getTargets())); + if (isClientThread()) { + Microbot.getClientThread().runOnSeperateThread(() -> restartPathfinding(start, targets)); } else { - restartPathfinding(start, ShortestPathPlugin.getPathfinder().getTargets()); + restartPathfinding(start, targets); } } @@ -10404,7 +10659,8 @@ private static boolean isCurrencyBasedTransport(TransportType transportType) { || transportType == TransportType.CHARTER_SHIP || transportType == TransportType.SHIP || transportType == TransportType.MINECART - || transportType == TransportType.MAGIC_CARPET; + || transportType == TransportType.MAGIC_CARPET + || transportType == TransportType.TRANSPORT; } private static int getCurrencyItemId(String currencyName) { @@ -10454,7 +10710,7 @@ public static boolean walkWithBankedTransports(WorldPoint target) { return walkWithBankedTransports(target, false); } public static boolean walkWithBankedTransports(WorldPoint target, boolean forceBanking) { - int d = config != null ? config.reachedDistance() : 10; + int d = reachedDistanceOrDefault(); return walkWithBankedTransportsAndState(target, d, forceBanking) == WalkerState.ARRIVED; } public static boolean walkWithBankedTransports(WorldPoint target, int distance, boolean forceBanking){ @@ -10475,7 +10731,7 @@ public static WalkerState walkWithBankedTransportsAndState(WorldPoint target, in log.warn("Cannot travel to null target location"); return WalkerState.EXIT; } - if (Microbot.getClient().isClientThread()) { + if (isClientThread()) { log.error("Please do not call the walker from the main thread"); return WalkerState.EXIT; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/banking/Rs2WalkerBankingPlanner.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/banking/Rs2WalkerBankingPlanner.java index 64f3c61a2e..287a41bba8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/banking/Rs2WalkerBankingPlanner.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/banking/Rs2WalkerBankingPlanner.java @@ -80,7 +80,8 @@ public static boolean hasRequiredTransportItems(Transport transport) { || transport.getType() == TransportType.CHARTER_SHIP || transport.getType() == TransportType.SHIP || transport.getType() == TransportType.MINECART - || transport.getType() == TransportType.MAGIC_CARPET) { + || transport.getType() == TransportType.MAGIC_CARPET + || (transport.getType() == TransportType.TRANSPORT && transport.getCurrencyAmount() > 0)) { if (transport.getType() == TransportType.TELEPORTATION_SPELL && transport.getDisplayInfo() != null) { String spellName = transport.getDisplayInfo().contains(":") ? transport.getDisplayInfo().split(":")[0].trim() @@ -405,7 +406,8 @@ private static boolean isCurrencyBasedTransport(TransportType transportType) { || transportType == TransportType.CHARTER_SHIP || transportType == TransportType.SHIP || transportType == TransportType.MINECART - || transportType == TransportType.MAGIC_CARPET; + || transportType == TransportType.MAGIC_CARPET + || transportType == TransportType.TRANSPORT; } private static int getCurrencyItemId(String currencyName) { diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/blocked_edges.tsv b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/blocked_edges.tsv index 49bc9a2141..4b6822e52d 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/blocked_edges.tsv +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/blocked_edges.tsv @@ -1,5 +1,7 @@ # Origin Destination Bidirectional Display info # Static collision edge overrides for map data gaps. These block movement across the edge, not the whole tile. +3267 3227 0 3268 3227 0 true Al Kharid toll gate +3267 3228 0 3268 3228 0 true Al Kharid toll gate 3229 3472 0 3229 3471 0 true Varrock Palace garden south fence 3230 3472 0 3230 3471 0 true Varrock Palace garden south fence 3231 3472 0 3231 3471 0 true Varrock Palace garden south fence diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/restrictions.tsv b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/restrictions.tsv index 539c6d881f..c66bd5a99f 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/restrictions.tsv +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/restrictions.tsv @@ -20,11 +20,7 @@ 3207 3217 0 Recipe for Disaster 3213 3222 0 Recipe for Disaster 3213 3221 0 Recipe for Disaster -# Al Kharid Gate -3267 3228 0 Prince Ali Rescue -3267 3227 0 Prince Ali Rescue -3268 3227 0 Prince Ali Rescue -3268 3228 0 Prince Ali Rescue +# Al Kharid toll gate is modeled as transports plus blocked edge overrides. 2936 9810 0 63 Agility # Tree near Draynor Manor 3138 3352 0 @@ -236,4 +232,4 @@ 2432 3118 0 2431 3118 0 2385 3068 0 -2385 3069 0 \ No newline at end of file +2385 3069 0 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/transports.tsv b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/transports.tsv index 28fc583725..da52a59975 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/transports.tsv +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/microbot/shortestpath/transports.tsv @@ -1018,6 +1018,14 @@ 3097 3432 2 3097 3432 1 Climb-down;Ladder;16685 # Al Kharid +3267 3227 0 3268 3227 0 Pay-toll(10gp);Gate;2786 10 Coins 2 +3267 3228 0 3268 3228 0 Pay-toll(10gp);Gate;2787 10 Coins 2 +3268 3227 0 3267 3227 0 Pay-toll(10gp);Gate;2788 10 Coins 2 +3268 3228 0 3267 3228 0 Pay-toll(10gp);Gate;2789 10 Coins 2 +3267 3227 0 3268 3227 0 Open;Gate;2786 Prince Ali Rescue 1 +3267 3228 0 3268 3228 0 Open;Gate;2787 Prince Ali Rescue 1 +3268 3227 0 3267 3227 0 Open;Gate;2788 Prince Ali Rescue 1 +3268 3228 0 3267 3228 0 Open;Gate;2789 Prince Ali Rescue 1 3298 3124 0 3297 3124 0 Open;Prison door;2692 3297 3124 0 3298 3124 0 Open;Prison door;2692 3303 3117 0 3304 3115 0 Go-through;Shantay pass;4031 1854 2 diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathCoreTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathCoreTest.java index 4adaf188ef..2bbc7972bc 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathCoreTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/shortestpath/ShortestPathCoreTest.java @@ -1,5 +1,6 @@ package net.runelite.client.plugins.microbot.shortestpath; +import net.runelite.api.Quest; import net.runelite.api.VarPlayer; import net.runelite.api.coords.WorldArea; import net.runelite.api.coords.WorldPoint; @@ -14,6 +15,10 @@ public class ShortestPathCoreTest { private static SplitFlagMap collisionMap; + private static final WorldPoint AL_KHARID_GATE_WEST_SOUTH = new WorldPoint(3267, 3227, 0); + private static final WorldPoint AL_KHARID_GATE_WEST_NORTH = new WorldPoint(3267, 3228, 0); + private static final WorldPoint AL_KHARID_GATE_EAST_SOUTH = new WorldPoint(3268, 3227, 0); + private static final WorldPoint AL_KHARID_GATE_EAST_NORTH = new WorldPoint(3268, 3228, 0); @BeforeClass public static void loadCollisionMap() { @@ -193,6 +198,52 @@ public void testTransportLoadingDoesNotThrow() { assertTrue("Should load at least 100 transport origins", transports.size() > 100); } + @Test + public void testAlKharidTollGateTransportsLoaded() { + HashMap> transports = Transport.loadAllFromResources(); + + assertTollGateTransport(transports, AL_KHARID_GATE_WEST_SOUTH, AL_KHARID_GATE_EAST_SOUTH, + "Pay-toll(10gp)", 10, false); + assertTollGateTransport(transports, AL_KHARID_GATE_WEST_NORTH, AL_KHARID_GATE_EAST_NORTH, + "Pay-toll(10gp)", 10, false); + assertTollGateTransport(transports, AL_KHARID_GATE_EAST_SOUTH, AL_KHARID_GATE_WEST_SOUTH, + "Pay-toll(10gp)", 10, false); + assertTollGateTransport(transports, AL_KHARID_GATE_EAST_NORTH, AL_KHARID_GATE_WEST_NORTH, + "Pay-toll(10gp)", 10, false); + + assertTollGateTransport(transports, AL_KHARID_GATE_WEST_SOUTH, AL_KHARID_GATE_EAST_SOUTH, + "Open", 0, true); + assertTollGateTransport(transports, AL_KHARID_GATE_WEST_NORTH, AL_KHARID_GATE_EAST_NORTH, + "Open", 0, true); + assertTollGateTransport(transports, AL_KHARID_GATE_EAST_SOUTH, AL_KHARID_GATE_WEST_SOUTH, + "Open", 0, true); + assertTollGateTransport(transports, AL_KHARID_GATE_EAST_NORTH, AL_KHARID_GATE_WEST_NORTH, + "Open", 0, true); + } + + @Test + public void testAlKharidTollGateIsEdgeBlockedNotTileRestricted() { + Set gateTiles = new HashSet<>(Arrays.asList( + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_WEST_SOUTH), + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_WEST_NORTH), + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_EAST_SOUTH), + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_EAST_NORTH))); + + List restrictions = Restriction.loadAllFromResources(); + assertFalse("Al Kharid gate tiles must not be quest-only restrictions", + restrictions.stream().anyMatch(r -> gateTiles.contains(r.getPackedWorldPoint()))); + + PathfinderConfig config = createMinimalConfig(); + assertTrue("South Al Kharid gate edge should be blocked without transport", + config.isBlockedTransportStep( + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_WEST_SOUTH), + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_EAST_SOUTH))); + assertTrue("North Al Kharid gate edge should be blocked without transport", + config.isBlockedTransportStep( + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_WEST_NORTH), + WorldPointUtil.packWorldPoint(AL_KHARID_GATE_EAST_NORTH))); + } + @Test public void testNewTransportTypesLoaded() { HashMap> transports = Transport.loadAllFromResources(); @@ -259,6 +310,27 @@ && new WorldPoint(3221, 3218, 0).equals(t.getDestination())) return lumbridgeHomeTeleport.get(); } + private static void assertTollGateTransport(HashMap> transports, + WorldPoint origin, WorldPoint destination, String action, int currencyAmount, boolean princeAliRequired) { + Optional match = transports.getOrDefault(origin, Collections.emptySet()).stream() + .filter(t -> destination.equals(t.getDestination())) + .filter(t -> action.equals(t.getAction())) + .filter(t -> "Gate".equals(t.getName())) + .findFirst(); + + assertTrue("Missing Al Kharid toll gate transport " + action + " from " + origin + " to " + destination, + match.isPresent()); + Transport transport = match.get(); + assertEquals("Gate transport should use normal TRANSPORT type", + TransportType.TRANSPORT, transport.getType()); + assertEquals("Unexpected gate currency amount", currencyAmount, transport.getCurrencyAmount()); + if (currencyAmount > 0) { + assertEquals("Unexpected gate currency name", "Coins", transport.getCurrencyName()); + } + assertEquals("Unexpected Prince Ali Rescue requirement on gate transport", + princeAliRequired, transport.getQuests().containsKey(Quest.PRINCE_ALI_RESCUE)); + } + @Test public void testFairyRingTransportsExist() { HashMap> transports = Transport.loadAllFromResources(); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java index 5de440bd1e..b117cae7f6 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/walker/Rs2WalkerUnitTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -458,6 +459,26 @@ public void stabilizeRouteProgressIndex_doesNotJumpBackToEarlierNearbyBranch() { assertEquals(6, Rs2Walker.stabilizeRouteProgressIndex(path, 6, target, new WorldPoint(3201, 3201, 0))); } + @Test + public void hintRouteProgressIndex_keepsProgressAnchoredAheadOfEarlierBranch() { + WorldPoint target = new WorldPoint(3200, 3201, 0); + List path = Arrays.asList( + new WorldPoint(3200, 3200, 0), + new WorldPoint(3201, 3200, 0), + new WorldPoint(3202, 3200, 0), + new WorldPoint(3203, 3200, 0), + new WorldPoint(3203, 3201, 0), + new WorldPoint(3202, 3201, 0), + new WorldPoint(3201, 3201, 0), + target); + + Rs2Walker.hintRouteProgressIndex(path, 5, target); + + assertEquals("a clicked-ahead route checkpoint should not snap back to a nearby earlier branch", + 5, + Rs2Walker.stabilizeRouteProgressIndex(path, 2, target, new WorldPoint(3202, 3201, 0))); + } + @Test public void findForwardRecoveryIndex_prefersLaterReachableBranch() { WorldPoint player = new WorldPoint(1000, 1000, 0); @@ -508,6 +529,87 @@ public void findFurthestForwardClickableIndex_doesNotBacktrackToEarlierNearbyBra assertEquals("normal route following should interpolate toward the forward tile, not backtrack", 3, idx); } + @Test + public void findFurthestRawPathPointMatching_keepsPrimaryClickOnForwardRawRoute() { + WorldPoint player = new WorldPoint(1000, 1000, 0); + List rawPath = Arrays.asList( + new WorldPoint(998, 1000, 0), + new WorldPoint(999, 1000, 0), + new WorldPoint(1000, 1001, 0), + new WorldPoint(1010, 1000, 0), + new WorldPoint(1009, 1000, 0), + new WorldPoint(1008, 1000, 0)); + + WorldPoint target = Rs2Walker.findFurthestRawPathPointMatching( + rawPath, + player, + 13, + 3, + wp -> true); + + assertEquals("raw-route selection must not snap back to an earlier nearby branch", + new WorldPoint(1008, 1000, 0), target); + } + + @Test + public void findFurthestRawPathPointMatching_honorsCandidatePredicate() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + WorldPoint blocked = new WorldPoint(3203, 3200, 0); + WorldPoint allowed = new WorldPoint(3202, 3200, 0); + List rawPath = Arrays.asList( + new WorldPoint(3200, 3200, 0), + new WorldPoint(3201, 3200, 0), + allowed, + blocked); + + WorldPoint target = Rs2Walker.findFurthestRawPathPointMatching( + rawPath, + player, + 13, + 0, + wp -> !wp.equals(blocked)); + + assertEquals("primary raw-route target must be the furthest acceptable raw tile", + allowed, target); + } + + @Test + public void findFurthestRawPathPointMatching_doesNotReturnCurrentTile() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + List rawPath = Arrays.asList( + player, + new WorldPoint(3215, 3200, 0)); + + WorldPoint target = Rs2Walker.findFurthestRawPathPointMatching( + rawPath, + player, + 10, + 0, + wp -> true); + + assertNull("same-tile route targets are no-op clicks, not recovery candidates", target); + } + + @Test + public void findFurthestRawPathPointMatching_stopsBeforeRouteStepBudgetIsExceeded() { + WorldPoint player = new WorldPoint(3200, 3200, 0); + List rawPath = Arrays.asList( + new WorldPoint(3200, 3200, 0), + new WorldPoint(3205, 3200, 0), + new WorldPoint(3210, 3200, 0), + new WorldPoint(3216, 3200, 0)); + + WorldPoint target = Rs2Walker.findFurthestRawPathPointMatching( + rawPath, + player, + 13, + 0, + wp -> true); + + assertEquals("route step budget keeps one minimap click from spanning too far ahead", + new WorldPoint(3210, 3200, 0), target); + } + @Test public void findFurthestForwardClickableIndex_stopsBeforeTransportOrigin() { WorldPoint player = new WorldPoint(3200, 3200, 0); @@ -791,6 +893,58 @@ public void shouldYieldForActiveRecoveryInterim_recentRecoveryClick_returnsTrue( false)); } + @Test + public void shouldDeferRouteWorkForActiveInterim_movingFarCheckpoint_returnsTrue() { + assertTrue(Rs2Walker.shouldDeferRouteWorkForActiveInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2880, 3396, 0), + 1_000L, + 4_500L, + 5_000L, + 0L, + true, + 5)); + } + + @Test + public void shouldDeferRouteWorkForActiveInterim_recentProgressStoppedFar_returnsTrue() { + assertTrue(Rs2Walker.shouldDeferRouteWorkForActiveInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2880, 3396, 0), + 1_000L, + 4_900L, + 5_000L, + 0L, + false, + 5)); + } + + @Test + public void shouldDeferRouteWorkForActiveInterim_closeCheckpoint_returnsFalse() { + assertFalse(Rs2Walker.shouldDeferRouteWorkForActiveInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2886, 3396, 0), + 1_000L, + 4_500L, + 5_000L, + 0L, + true, + 5)); + } + + @Test + public void shouldDeferRouteWorkForActiveInterim_staleStoppedCheckpoint_returnsFalse() { + assertFalse(Rs2Walker.shouldDeferRouteWorkForActiveInterim( + new WorldPoint(2890, 3396, 0), + new WorldPoint(2880, 3396, 0), + 1_000L, + 1_500L, + 5_000L, + 0L, + false, + 5)); + } + @Test public void interimPreclickTiles_runHandsOffEarlierThanWalk() { assertEquals(6, Rs2Walker.interimPreclickTiles(false)); @@ -805,6 +959,13 @@ public void routeMovementClickPhase_labelsContinuationSeparatelyFromRecovery() { assertEquals("route_movement_click", Rs2Walker.routeMovementClickPhase("other")); } + @Test + public void shouldRunActiveRouteIdleNudge_waitsForImmediateTransport() { + assertFalse(Rs2Walker.shouldRunActiveRouteIdleNudge(true, true)); + assertTrue(Rs2Walker.shouldRunActiveRouteIdleNudge(true, false)); + assertFalse(Rs2Walker.shouldRunActiveRouteIdleNudge(false, false)); + } + @Test public void shouldSkipStartupPreclickSegmentHandlers_skipsBeforeFirstMovementClick() { assertTrue(Rs2Walker.shouldSkipStartupPreclickSegmentHandlers( From 6c78e87328cb1c8d17642696df9006dd1a2e5b7e Mon Sep 17 00:00:00 2001 From: infuse21 Date: Sun, 19 Jul 2026 17:08:16 +0100 Subject: [PATCH 4/5] Updated questhelper to upstream Zoinkwiz/quest-helper commit ae1f441248b9742c1eaa667b18052785eb6ed058 (4.16.1) and marked the sync as successful in .quest-helper-sync. Kept the Microbot-specific integration intact: hidden always-on plugin wiring, QuestScript, config toggles, custom quest logic, resource path fixes, and the agent start hook. I also restored compatibility accessors needed by the automation runner and preserved precise farming patch coordinates where they matched older local data. --- .../microbot/questhelper/.quest-helper-sync | 24 +- .../questhelper/QuestHelperConfig.java | 69 +- .../questhelper/QuestHelperPlugin.java | 81 +- .../bank/banktab/QuestBankTab.java | 10 +- .../bank/banktab/QuestBankTabInterface.java | 4 - .../banktab/QuestHelperBankTagService.java | 18 +- .../questhelper/bikeshedder/BikeShedder.java | 352 ------ .../collections/ItemCollections.java | 59 + .../collections/KeyringCollection.java | 32 +- .../collections/TeleportCollections.java | 2 +- .../questhelper/config/ConfigKeys.java | 71 -- .../LeagueFiltering.java} | 49 +- .../domain/QuetzalDestination.java | 44 + .../ardougne/ArdougneEasy.java | 7 +- .../ardougne/ArdougneElite.java | 8 +- .../ardougne/ArdougneHard.java | 2 +- .../ardougne/ArdougneMedium.java | 6 +- .../achievementdiaries/desert/DesertEasy.java | 2 +- .../desert/DesertElite.java | 2 +- .../falador/FaladorEasy.java | 2 +- .../falador/FaladorElite.java | 6 +- .../fremennik/FremennikElite.java | 6 +- .../fremennik/FremennikMedium.java | 11 +- .../kandarin/KandarinEasy.java | 38 +- .../kandarin/KandarinElite.java | 2 +- .../kandarin/KandarinHard.java | 2 +- .../kandarin/KandarinMedium.java | 10 +- .../karamja/KaramjaElite.java | 12 +- .../karamja/KaramjaMedium.java | 11 +- .../kourend/KourendEasy.java | 6 +- .../kourend/KourendMedium.java | 2 +- .../lumbridgeanddraynor/LumbridgeEasy.java | 10 +- .../lumbridgeanddraynor/LumbridgeElite.java | 6 +- .../morytania/MorytaniaEasy.java | 8 +- .../morytania/MorytaniaElite.java | 6 +- .../morytania/MorytaniaMedium.java | 2 +- .../varrock/VarrockMedium.java | 6 +- .../westernprovinces/WesternMedium.java | 3 +- .../wilderness/WildernessEasy.java | 6 +- .../charting/ChartingConditionalStep.java | 1 - .../activities/charting/ChartingHelper.java | 24 +- .../charting/ChartingSeaSection.java | 1 - .../charting/ChartingTaskDefinition.java | 3 +- .../charting/ChartingTasksData.java | 11 +- .../steps/ChartingCaveTelescopeStep.java | 2 +- .../charting/steps/ChartingCrateStep.java | 5 +- .../charting/steps/ChartingCurrentStep.java | 6 +- .../steps/ChartingGenericObjectStep.java | 3 + .../steps/ChartingPuzzleWrapStep.java | 1 - .../charting/steps/ChartingTaskNpcStep.java | 2 +- .../steps/ChartingTaskObjectStep.java | 1 - .../charting/steps/ChartingTaskStep.java | 1 - .../charting/steps/ChartingWeatherStep.java | 1 + .../AlfredGrimhandsBarcrawl.java | 239 ++-- .../barbariantraining/BarbarianTraining.java | 515 +++----- .../miniquests/daddyshome/DaddysHome.java | 16 +- .../miniquests/enchantedkey/EnchantedKey.java | 2 +- .../enchantedkey/EnchantedKeyDigStep.java | 3 +- .../lairoftarnrazorlor/TarnRoute.java | 6 +- .../themagearenai/TheMageArenaI.java | 3 +- .../miniquests/themagearenaii/MA2Locator.java | 31 +- .../themagearenaii/MageArenaBossStep.java | 312 ++++- .../themagearenaii/MageArenaSolver.java | 2 + .../MageArenaSpawnLocation.java | 5 +- .../themagearenaii/TheMageArenaII.java | 34 +- .../miniquests/valetotems/ValeTotems.java | 17 +- .../farmruns/FarmingConfigChangeHandler.java | 1 - .../mischelpers/farmruns/FarmingPatch.java | 33 +- .../mischelpers/farmruns/FarmingRegion.java | 50 +- .../mischelpers/farmruns/FarmingUtils.java | 2 + .../mischelpers/farmruns/FarmingWorld.java | 603 ++++------ .../helpers/mischelpers/farmruns/HerbRun.java | 43 +- .../farmruns/PatchImplementation.java | 41 +- .../mischelpers/farmruns/PaymentTracker.java | 5 +- .../helpers/mischelpers/farmruns/TreeRun.java | 637 +++++++--- .../mischelpers/knightswaves/KnightWaves.java | 6 +- .../StrongholdOfSecurity.java | 20 +- .../APorcineOfInterest.java | 183 ++- .../quests/bearyoursoul/BearYourSoul.java | 2 +- .../belowicemountain/BelowIceMountain.java | 21 +- .../BeneathCursedSands.java | 7 +- .../helpers/quests/biohazard/Biohazard.java | 19 +- .../BlackKnightFortress.java | 20 +- .../childrenofthesun/ChildrenOfTheSun.java | 18 +- .../clientofkourend/ClientOfKourend.java | 12 +- .../helpers/quests/clocktower/ClockTower.java | 22 +- .../quests/cooksassistant/CooksAssistant.java | 20 +- .../CreatureOfFenkenstrain.java | 4 +- .../quests/currentaffairs/CurrentAffairs.java | 22 +- .../quests/deathontheisle/DeathOnTheIsle.java | 21 +- .../DeathToTheDorgeshuun.java | 6 +- .../quests/demonslayer/DemonSlayer.java | 20 +- .../quests/demonslayer/IncantationStep.java | 3 +- .../quests/deserttreasure/DesertTreasure.java | 4 +- .../deserttreasureii/DesertTreasureII.java | 4 +- .../deserttreasureii/PerseriyaSteps.java | 10 +- .../deserttreasureii/WhispererSteps.java | 2 +- .../quests/deviousminds/DeviousMinds.java | 5 +- .../quests/doricsquest/DoricsQuest.java | 86 +- .../quests/dragonslayer/DragonSlayer.java | 6 +- .../quests/druidicritual/DruidicRitual.java | 12 +- .../quests/dwarfcannon/DwarfCannon.java | 23 +- .../ElementalWorkshopI.java | 8 +- .../ElementalWorkshopII.java | 32 +- .../quests/enakhraslament/EnakhrasLament.java | 13 +- .../EnlightenedJourney.java | 2 +- .../helpers/quests/fairytalei/FairytaleI.java | 1 + .../quests/fairytaleii/FairytaleII.java | 18 +- .../helpers/quests/fightarena/FightArena.java | 12 +- .../forgettabletale/ForgettableTale.java | 7 +- .../GardenOfTranquillity.java | 4 +- .../quests/gertrudescat/GertrudesCat.java | 19 +- .../quests/ghostsahoy/DyeShipSteps.java | 31 +- .../goblindiplomacy/GoblinDiplomacy.java | 203 ++-- .../helpers/quests/grimtales/GrimTales.java | 3 +- .../quests/hauntedmine/HauntedMine.java | 8 +- .../helpers/quests/hazeelcult/HazeelCult.java | 19 +- .../quests/heroesquest/HeroesQuest.java | 4 +- .../helpers/quests/holygrail/HolyGrail.java | 21 +- .../helpers/quests/impcatcher/ImpCatcher.java | 15 +- .../quests/junglepotion/JunglePotion.java | 313 +++-- .../landofthegoblins/LandOfTheGoblins.java | 5 +- .../helpers/quests/lostcity/LostCity.java | 278 +++-- .../quests/makinghistory/MakingHistory.java | 2 +- .../quests/merlinscrystal/MerlinsCrystal.java | 21 +- .../misthalinmystery/MisthalinMystery.java | 22 +- .../quests/monkeymadnessi/MonkeyMadnessI.java | 2 +- .../monkeymadnessii/AgilityDungeonSteps.java | 10 +- .../quests/monksfriend/MonksFriend.java | 26 +- .../mountaindaughter/MountainDaughter.java | 6 +- .../mourningsendparti/MourningsEndPartI.java | 2 +- .../MourningsEndPartII.java | 2 +- .../quests/murdermystery/MurderMystery.java | 23 +- .../MyArmsBigAdventure.java | 2 +- .../quests/naturespirit/NatureSpirit.java | 407 ++++--- .../observatoryquest/ObservatoryQuest.java | 23 +- .../observatoryquest/StarSignAnswer.java | 92 -- .../quests/onesmallfavour/OneSmallFavour.java | 1062 +++++++++++------ .../quests/pandemonium/Pandemonium.java | 463 ++++--- .../piratestreasure/PiratesTreasure.java | 16 +- .../piratestreasure/RumSmugglingStep.java | 16 +- .../helpers/quests/plaguecity/PlagueCity.java | 18 +- .../quests/priestinperil/PriestInPeril.java | 467 +++++--- .../princealirescue/PrinceAliRescue.java | 73 +- .../quests/pryingtimes/PryingTimes.java | 20 +- .../quests/ragandboneman/RagAndBoneManII.java | 8 +- .../quests/ratcatchers/RatCatchers.java | 6 +- .../quests/recipefordisaster/RFDDwarf.java | 2 +- .../recipefordisaster/RFDPiratePete.java | 7 +- .../recipefordisaster/RFDSkrachUglogwee.java | 2 +- .../quests/recruitmentdrive/DoorPuzzle.java | 90 +- .../recruitmentdrive/LadyTableStep.java | 111 +- .../recruitmentdrive/MissCheeversStep.java | 384 ++++++ .../recruitmentdrive/MsCheevesSetup.java | 384 ------ .../MsHynnAnswerDialogQuizStep.java | 67 +- .../recruitmentdrive/RecruitmentDrive.java | 683 ++++++----- .../recruitmentdrive/SirRenItchoodStep.java | 58 +- .../quests/romeoandjuliet/RomeoAndJuliet.java | 14 +- .../quests/runemysteries/RuneMysteries.java | 12 +- .../scorpioncatcher/ScorpionCatcher.java | 361 +++--- .../helpers/quests/scrambled/EggSolver.java | 7 +- .../helpers/quests/scrambled/Scrambled.java | 17 +- .../helpers/quests/seaslug/SeaSlug.java | 317 +++-- .../shadowofthestorm/IncantationStep.java | 26 +- .../quests/shadowofthestorm/SearchKilns.java | 91 -- .../shadowofthestorm/ShadowOfTheStorm.java | 468 +++++--- .../shadowsofcustodia/ShadowsOfCustodia.java | 18 +- .../quests/sheepherder/SheepHerder.java | 20 +- .../quests/sheepshearer/SheepShearer.java | 26 +- .../ShieldOfArravBlackArmGang.java | 6 +- .../quests/shilovillage/ShiloVillage.java | 534 +++++---- .../sinsofthefather/DoorPuzzleStep.java | 85 +- .../helpers/quests/swansong/FishMonkfish.java | 6 +- .../taibwowannaitrio/TaiBwoWannaiTrio.java | 2 +- .../quests/templeofikov/TempleOfIkov.java | 33 +- .../thecurseofarrav/TheCurseOfArrav.java | 1 + .../helpers/quests/thedigsite/TheDigSite.java | 638 ++++++---- .../quests/thefinaldawn/TheFinalDawn.java | 17 +- .../quests/theforsakentower/JugPuzzle.java | 3 +- .../thefremennikisles/TheFremennikIsles.java | 2 +- .../TheFremennikTrials.java | 8 +- .../helpers/quests/thegolem/TheGolem.java | 20 +- .../TheHeartOfDarkness.java | 18 +- .../quests/theidesofmilk/TheIdesOfMilk.java | 316 +++++ .../theknightssword/TheKnightsSword.java | 269 +++-- .../quests/thelosttribe/TheLostTribe.java | 437 ++++--- .../ThePathOfGlouphrie.java | 4 +- .../thepathofglouphrie/YewnocksPuzzle.java | 51 +- .../sections/TheWarpedDepths.java | 2 + .../helpers/quests/theredreef/TheRedReef.java | 559 +++++++++ .../therestlessghost/TheRestlessGhost.java | 12 +- .../quests/theslugmenace/PuzzleStep.java | 2 +- .../quests/thetouristtrap/TheTouristTrap.java | 2 +- .../ThroneOfMiscellania.java | 15 +- .../quests/toweroflife/PuzzleSolver.java | 22 +- .../treegnomevillage/TreeGnomeVillage.java | 19 +- .../quests/tribaltotem/PuzzleStep.java | 71 +- .../quests/tribaltotem/TribalTotem.java | 5 +- .../trollstronghold/TrollStronghold.java | 6 +- .../quests/troubledtortugans/RepairTown.java | 3 +- .../troubledtortugans/TroubledTortugans.java | 21 +- .../quests/vampyreslayer/VampyreSlayer.java | 242 ++-- .../helpers/quests/wanted/Wanted.java | 6 +- .../helpers/quests/watchtower/Watchtower.java | 8 +- .../quests/waterfallquest/WaterfallQuest.java | 16 +- .../quests/whatliesbelow/WhatLiesBelow.java | 3 +- .../whileguthixsleeps/WhileGuthixSleeps.java | 2 +- .../quests/witchshouse/WitchsHouse.java | 21 +- .../quests/witchspotion/WitchsPotion.java | 9 +- .../quests/xmarksthespot/XMarksTheSpot.java | 10 +- .../managers/ItemAndLastUpdated.java | 27 + .../managers/NewVersionManager.java | 2 +- .../managers/QuestContainerManager.java | 5 +- .../questhelper/managers/QuestManager.java | 3 + .../managers/QuestMenuHandler.java | 3 +- .../overlays/QuestHelperMinimapOverlay.java | 5 + .../overlays/QuestHelperOverlay.java | 1 + .../QuestHelperWorldArrowOverlay.java | 5 + .../overlays/QuestHelperWorldLineOverlay.java | 5 + .../overlays/QuestHelperWorldOverlay.java | 19 +- .../questhelper/panel/JGenerator.java | 4 +- .../panel/ManualStepSkipStore.java | 112 ++ .../questhelper/panel/PanelDetails.java | 7 +- .../questhelper/panel/QuestHelperPanel.java | 275 ++++- .../questhelper/panel/QuestOverviewPanel.java | 42 +- .../panel/QuestRequirementsPanel.java | 7 +- .../questhelper/panel/QuestRewardsPanel.java | 2 +- .../questhelper/panel/QuestStepPanel.java | 448 ------- .../panel/TopLevelPanelDetails.java | 1 - .../questorders/IronmanOptimalQuestGuide.java | 5 +- .../panel/questorders/OptimalQuestGuide.java | 5 +- .../panel/questorders/ReleaseDate.java | 5 +- .../AbstractQuestSection.java | 2 +- .../queststepsection/QuestSectionSection.java | 14 +- .../queststepsection/QuestStepPanel.java | 279 ++++- .../regionfiltering/RegionFilterPanel.java | 193 +++ .../playerquests/bikeshedder/BikeShedder.java | 173 ++- .../playerquests/cookshelper/CooksHelper.java | 255 ---- .../questhelper/questhelpers/QuestHelper.java | 69 +- .../questinfo/ExternalQuestResources.java | 2 + .../questinfo/LeagueQuestRegions.java | 294 +++++ .../questhelper/questinfo/LeagueRegion.java | 53 + .../questinfo/QuestHelperQuest.java | 13 +- .../questhelper/questinfo/QuestVarbits.java | 4 +- .../requirements/AbstractRequirement.java | 2 +- .../requirements/ChatMessageRequirement.java | 2 +- .../questhelper/requirements/Requirement.java | 2 +- .../requirements/StepIsActiveRequirement.java | 4 +- .../conditional/ConditionForStep.java | 1 + .../requirements/conditional/Conditions.java | 1 + .../conditional/ObjectCondition.java | 2 +- .../requirements/item/ItemRequirement.java | 9 +- .../requirements/item/ItemRequirements.java | 2 +- .../requirements/item/KeyringRequirement.java | 99 +- .../requirements/item/TrackedContainers.java | 1 + .../requirements/npc/DialogRequirement.java | 38 +- .../npc/NoFollowerRequirement.java | 3 +- .../requirements/npc/NpcRequirement.java | 8 +- .../requirements/player/Boosts.java | 4 +- .../player/FreeInventorySlotRequirement.java | 1 + .../player/FreePortTaskSlotsRequirement.java | 5 +- .../player/ShipInPortRequirement.java | 5 +- .../sailing/HasBoatResistanceRequirement.java | 2 +- .../requirements/util/InventorySlots.java | 2 +- .../requirements/util/ItemSlots.java | 75 +- .../questhelper/requirements/util/Port.java | 62 +- .../requirements/var/VarbitRequirement.java | 3 +- .../requirements/zone/ZoneRequirement.java | 12 +- .../questhelper/runeliteobjects/Cheerer.java | 18 +- .../runeliteobjects/GlobalFakeObjects.java | 9 + .../ExtendedRuneliteObject.java | 2 +- .../RuneliteObjectManager.java | 17 +- .../AchievementDiaryStepManager.java | 32 +- .../BarbarianTrainingStateTracker.java | 341 ------ .../statemanagement/PlayerStateManager.java | 106 +- .../questhelper/steps/BoardShipStep.java | 1 - .../questhelper/steps/ConditionalStep.java | 66 +- .../questhelper/steps/DetailedQuestStep.java | 50 +- .../microbot/questhelper/steps/DigStep.java | 10 +- .../microbot/questhelper/steps/EmoteStep.java | 14 +- .../questhelper/steps/NpcEmoteStep.java | 2 +- .../microbot/questhelper/steps/NpcStep.java | 19 +- .../questhelper/steps/ObjectStep.java | 36 +- .../questhelper/steps/PortTaskStep.java | 2 - .../questhelper/steps/PuzzleStep.java | 2 +- .../questhelper/steps/PuzzleWrapperStep.java | 3 +- .../microbot/questhelper/steps/QuestStep.java | 102 +- .../questhelper/steps/WidgetStep.java | 4 +- .../questhelper/steps/WorldEntityStep.java | 159 +++ .../steps/choice/DialogChoiceStep.java | 2 +- .../steps/choice/WidgetChoiceStep.java | 4 +- .../questhelper/steps/emote/QuestEmote.java | 4 +- .../steps/overlay/DirectionArrow.java | 4 +- .../questhelper/steps/tools/DefinedPoint.java | 1 - .../steps/tools/QuestPerspective.java | 93 +- .../steps/widget/WidgetHighlight.java | 19 + .../microbot/questhelper/util/Utils.java | 3 +- 297 files changed, 11166 insertions(+), 7356 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bikeshedder/BikeShedder.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/ConfigKeys.java rename runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/{requirements/RegionHintArrowRequirement.java => config/LeagueFiltering.java} (56%) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/domain/QuetzalDestination.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/StarSignAnswer.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MissCheeversStep.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsCheevesSetup.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/SearchKilns.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theidesofmilk/TheIdesOfMilk.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theredreef/TheRedReef.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/ManualStepSkipStore.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestStepPanel.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/regionfiltering/RegionFilterPanel.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/cookshelper/CooksHelper.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueQuestRegions.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueRegion.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/BarbarianTrainingStateTracker.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WorldEntityStep.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/.quest-helper-sync b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/.quest-helper-sync index 98091843fe..8c8874920d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/.quest-helper-sync +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/.quest-helper-sync @@ -8,16 +8,22 @@ # Use the quest-helper update scripts to manage synchronization. # Current sync position - this is the last external commit that has been integrated -5539626281a502ba8c44fe59b8b57bce32fe4f16 +ae1f441248b9742c1eaa667b18052785eb6ed058 # Sync metadata (for script reference) -# External repo HEAD at last check: 5539626281a502ba8c44fe59b8b57bce32fe4f16 -# Last sync date: 2025-08-29 -# Sync method: automated script with manual package transformation -# Integration branch: quest-helper-update-20250829_063754 -# Local commit: cb416ef02a (quest-helper: polish Enakhras Lament) +# External repo HEAD at last check: ae1f441248b9742c1eaa667b18052785eb6ed058 +# Last sync date: 2026-07-19 +# Sync method: upstream source mirror with manual package transformation and Microbot hook preservation +# Integration branch: local workspace +# Local commit: pending # Sync history log: +# 2026-07-19 - Complete sync to upstream ae1f4412 (Quest Helper 4.16.1 source) +# - Mirrored upstream src/main/java and src/main/resources into the Microbot package +# - Preserved Microbot QuestScript, custom quest logic, config toggles, and agent-server start hook +# - Package transformation: com.questhelper -> net.runelite.client.plugins.microbot.questhelper +# - Status: SUCCESS +# # 2025-08-29 07:14:46 - Applied commit 55396262 (Polish enahkras lament #2294) # - Enhanced EnakhrasLament.java with better code organization # - Fixed Shadow Room brazier puzzle sequence and locations @@ -43,9 +49,9 @@ # - Status: INITIALIZED # Integration status -# Current external version: 4.10.0+ +# Current external version: 4.16.1 # Integration health: HEALTHY -# Last validation: 2025-08-29 +# Last validation: 2026-07-19 # Compilation status: SUCCESS # Package transformation: COMPLETE -# Sync file location: CORRECT (moved from project root) \ No newline at end of file +# Sync file location: CORRECT (moved from project root) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperConfig.java index 78c6ae488c..22715fc5bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperConfig.java @@ -46,6 +46,8 @@ public interface QuestHelperConfig extends Config String QUEST_HELPER_GROUP = "questhelper"; String QUEST_BACKGROUND_GROUP = "questhelpervars"; String QUEST_HELPER_SIDEBAR_ORDER_KEY_START = "quest-sidebar-order-"; + /** Per-helper persisted manual step skips (JSON map of stable slot id to true). */ + String QUEST_HELPER_MANUAL_SKIPS_KEY_PREFIX = "manual-step-skips-"; enum QuestOrdering implements Comparator { @@ -237,32 +239,33 @@ enum InventoryItemHighlightStyle } @ConfigSection( - position = 0, - name = "Microbot", - description = "Microbot Options", - closedByDefault = false + position = 0, + name = "Microbot", + description = "Microbot Options", + closedByDefault = false ) String microbotSection = "microbotSection"; - @ConfigItem( - keyName = "TurnOn", - name = "Enable QuestHelper", - description = "Enable the quest helper that will automatically help with quests.", - section = microbotSection + keyName = "TurnOn", + name = "Enable QuestHelper", + description = "Enable the quest helper that will automatically help with quests.", + section = microbotSection ) - default boolean startStopQuestHelper() { + default boolean startStopQuestHelper() + { return true; } @ConfigItem( - keyName = "obtainMissingItems", - name = "Obtain Missing Items", - description = "Controls whether the quest helper automatically obtains missing items from the bank and Grand Exchange. 'Ask' will prompt you the first time items are needed.", - section = microbotSection, - position = 1 + keyName = "obtainMissingItems", + name = "Obtain Missing Items", + description = "Controls whether the quest helper automatically obtains missing items from the bank and Grand Exchange. 'Ask' will prompt you the first time items are needed.", + section = microbotSection, + position = 1 ) - default ObtainMissingItemsOption obtainMissingItems() { + default ObtainMissingItemsOption obtainMissingItems() + { return ObtainMissingItemsOption.ASK; } @@ -332,14 +335,15 @@ public String toString() } @ConfigItem( - keyName = "valeTotemsWoodType", - name = "Vale Totems wood type", - description = "Which wood type the quester should gather for the Vale Totems miniquest. " + - "Must match the wood you used to build the totem. " + - "Leave on 'Ask me' to be prompted the first time the quest runs.", - section = microbotSection + keyName = "valeTotemsWoodType", + name = "Vale Totems wood type", + description = "Which wood type the quester should gather for the Vale Totems miniquest. " + + "Must match the wood you used to build the totem. " + + "Leave on 'Ask me' to be prompted the first time the quest runs.", + section = microbotSection ) - default ValeTotemsWoodType valeTotemsWoodType() { + default ValeTotemsWoodType valeTotemsWoodType() + { return ValeTotemsWoodType.ASK; } @@ -791,6 +795,25 @@ default boolean showCompletedQuests() return false; } + enum RegionFilterVisibility + { + AUTO, + SHOW, + HIDE + } + + @ConfigItem( + keyName = "regionFilterVisibility", + name = "Region filtering", + description = "Controls when the league region filter is shown. Auto shows it only on league worlds.", + position = 5, + section = filterSection + ) + default RegionFilterVisibility regionFilterVisibility() + { + return RegionFilterVisibility.AUTO; + } + @ConfigSection( position = 5, name = "Development", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperPlugin.java index 3f272b847c..f1b8c045ec 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/QuestHelperPlugin.java @@ -29,9 +29,9 @@ import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Provides; -import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankTabItems; import net.runelite.client.plugins.microbot.questhelper.bank.banktab.PotionStorage; +import net.runelite.client.plugins.microbot.questhelper.bank.banktab.QuestBankTabInterface; import net.runelite.client.plugins.microbot.questhelper.managers.*; import net.runelite.client.plugins.microbot.questhelper.panel.QuestHelperPanel; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; @@ -39,6 +39,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.Cheerer; import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.GlobalFakeObjects; +import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.RuneliteConfigSetter; import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.RuneliteObjectManager; import net.runelite.client.plugins.microbot.questhelper.statemanagement.PlayerStateManager; import net.runelite.client.plugins.microbot.questhelper.tools.Icon; @@ -49,7 +50,7 @@ import net.runelite.api.events.*; import net.runelite.api.gameval.InventoryID; import net.runelite.api.gameval.VarPlayerID; -import net.runelite.client.RuneLite; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.callback.ClientThread; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; @@ -60,9 +61,11 @@ import net.runelite.client.events.RuneScapeProfileChanged; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SkillIconManager; +import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.bank.BankSearch; +import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.components.colorpicker.ColorPickerManager; @@ -101,6 +104,7 @@ public class QuestHelperPlugin extends Plugin @Inject private ClientThread clientThread; + @Getter @Inject private EventBus eventBus; @@ -162,6 +166,17 @@ public class QuestHelperPlugin extends Plugin @Inject public SkillIconManager skillIconManager; + @Inject + public SpriteManager spriteManager; + + @Inject + private QuestBankTabInterface questBankTabInterface; + + public boolean fullCrate; + + @Inject + QuestScript questScript; + private QuestHelperPanel panel; private NavigationButton navButton; @@ -170,9 +185,9 @@ public class QuestHelperPlugin extends Plugin private final Collection configEvents = Arrays.asList("orderListBy", "filterListBy", "questDifficulty", "showCompletedQuests"); private final Collection configItemEvents = Arrays.asList("highlightNeededQuestItems", "highlightNeededMiniquestItems", "highlightNeededAchievementDiaryItems"); - public boolean fullCrate; - @Inject - QuestScript questScript; + + @Getter + private boolean inCutscene = false; @Provides QuestHelperConfig getConfig(ConfigManager configManager) @@ -234,6 +249,7 @@ protected void startUp() throws IOException @Override protected void shutDown() { + questScript.shutdown(); runeliteObjectManager.shutDown(); eventBus.unregister(playerStateManager); @@ -260,6 +276,7 @@ protected void shutDown() public void onGameTick(GameTick event) { questBankManager.loadInitialStateFromConfig(client); + playerStateManager.loadInitialStateFromConfig(); questManager.updateQuestState(); } @@ -314,6 +331,7 @@ public void onGameStateChanged(final GameStateChanged event) questBankManager.saveBankToConfig(); SwingUtilities.invokeLater(() -> panel.refresh(Collections.emptyList(), true, new HashMap<>())); questBankManager.emptyState(); + playerStateManager.emptyState(); questManager.shutDownQuest(true); profileChanged = true; } @@ -325,7 +343,10 @@ public void onGameStateChanged(final GameStateChanged event) GlobalFakeObjects.createNpcs(client, runeliteObjectManager, configManager, config); newVersionManager.updateChatWithNotificationIfNewVersion(); questBankManager.setUnknownInitialState(); + playerStateManager.setUnknownInitialState(); potionStorage.updateCachedPotions = true; + boolean isLeague = client.getWorldType().contains(WorldType.SEASONAL); + SwingUtilities.invokeLater(() -> panel.updateRegionFilterVisibility(isLeague)); clientThread.invokeAtTickEnd(() -> { questManager.setupRequirements(); questManager.setupOnLogin(); @@ -342,6 +363,11 @@ private void onRuneScapeProfileChanged(RuneScapeProfileChanged ev) @Subscribe public void onVarbitChanged(VarbitChanged event) { + if (event.getVarbitId() == VarbitID.CUTSCENE_STATUS) + { + this.inCutscene = event.getValue() == 1; + } + if (!(client.getGameState() == GameState.LOGGED_IN)) { return; @@ -376,6 +402,12 @@ public void onConfigChanged(ConfigChanged event) return; } + if ("regionFilterVisibility".equals(event.getKey())) + { + boolean isLeague = client.getWorldType().contains(WorldType.SEASONAL); + SwingUtilities.invokeLater(() -> panel.updateRegionFilterVisibility(isLeague)); + } + if (configEvents.contains(event.getKey()) || event.getKey().contains("skillfilter")) { clientThread.invokeLater(questManager::updateQuestList); @@ -452,6 +484,37 @@ else if (developerMode && commandExecuted.getCommand().equals("qh-inv")) } log.debug(String.valueOf(inv)); } + else if (developerMode && commandExecuted.getCommand().equals("qh")) + { + var args = commandExecuted.getArguments(); + if (args.length == 0) + { + return; + } + var subCommand = args[0]; + if (subCommand.equals("container")) + { + if (args.length < 2) + { + return; + } + var container = args[1]; + switch (container) + { + case "keyring": + var keyringItems = QuestContainerManager.getKeyRingData().getItems(); + for (var item : keyringItems) + { + log.debug("Key ring item: {}", item); + } + break; + } + } + else if (subCommand.equals("cheer")) + { + addCheerer(); + } + } } @Subscribe(priority = 100) @@ -470,6 +533,11 @@ public List getPluginBankTagItemsForSections() return questBankManager.getBankTagService().getPluginBankTagItemsForSections(false); } + public boolean isBankTabOpen() + { + return questBankTabInterface.isQuestTabActive(); + } + public @Nullable QuestHelper getSelectedQuest() { return questManager.getSelectedQuest(); @@ -530,7 +598,8 @@ public void onMenuEntryAdded(MenuEntryAdded event) @Subscribe public void onChatMessage(ChatMessage chatMessage) { - if (chatMessage.getMessage().equals("The crate is full of bananas.")) { + if (chatMessage.getMessage().equals("The crate is full of bananas.")) + { fullCrate = true; } if (config.showFan() && chatMessage.getType() == ChatMessageType.GAMEMESSAGE) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTab.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTab.java index 90c88c4c77..041de959ee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTab.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTab.java @@ -34,10 +34,12 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.*; import net.runelite.api.events.*; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.InventoryID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarClientID; +import net.runelite.api.gameval.VarbitID; import net.runelite.api.widgets.ItemQuantityMode; import net.runelite.api.widgets.JavaScriptCallback; import net.runelite.api.widgets.Widget; @@ -55,13 +57,15 @@ import javax.inject.Inject; import javax.inject.Singleton; -import java.awt.*; import java.awt.Point; -import java.util.*; +import java.awt.*; import java.util.List; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.runelite.client.plugins.microbot.questhelper.bank.banktab.PotionStorage.COMPONENTS_PER_POTION; +import static net.runelite.client.plugins.microbot.questhelper.bank.banktab.PotionStorage.VIAL_IDX; import static net.runelite.client.plugins.banktags.BankTagsPlugin.*; @Singleton diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTabInterface.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTabInterface.java index 849b9d7035..32e6be9e82 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTabInterface.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestBankTabInterface.java @@ -132,10 +132,6 @@ public void handleClick(MenuOptionClicked event) return; } String menuOption = event.getMenuOption(); - if (menuOption == null) - { - return; - } // If click a base tab, close boolean clickedTabTag = menuOption.startsWith("View tab") && !event.getMenuTarget().equals("quest-helper"); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestHelperBankTagService.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestHelperBankTagService.java index 48d4486ff5..fc2b9b77dd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestHelperBankTagService.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bank/banktab/QuestHelperBankTagService.java @@ -32,6 +32,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.api.Client; import net.runelite.api.gameval.ItemID; +import net.runelite.client.config.ConfigManager; import javax.inject.Inject; import javax.inject.Singleton; @@ -50,6 +51,9 @@ public class QuestHelperBankTagService @Inject private Client client; + @Inject + private ConfigManager configManager; + ArrayList taggedItems; ArrayList taggedItemsForBank; @@ -221,14 +225,18 @@ private void getItemsFromRequirement(List pluginItems, ItemRequirem else if (itemRequirement instanceof KeyringRequirement) { KeyringRequirement keyringRequirement = (KeyringRequirement) itemRequirement; - KeyringRequirement fakeRequirement = new KeyringRequirement(keyringRequirement.getName(), plugin.getConfigManager(), - keyringRequirement.getKeyringCollection()); - if (keyringRequirement.hasKeyOnKeyRing()) + var keyringCollection = keyringRequirement.getKeyringCollection(); + var fakeRequirement = keyringRequirement.copy(); + if (keyringCollection.hasKeyOnKeyRing(configManager)) { fakeRequirement.addAlternates(ItemID.FAVOUR_KEY_RING); + // NOTE: If the key is on your key ring _AND_ in your bank, we will still suggest using the key ring. + pluginItems.add(new BankTabItem(fakeRequirement, ItemID.FAVOUR_KEY_RING)); + } + else + { + pluginItems.add(makeBankTabItem(fakeRequirement)); } - pluginItems.add(makeBankTabItem(fakeRequirement)); - } else { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bikeshedder/BikeShedder.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bikeshedder/BikeShedder.java deleted file mode 100644 index 67222f288e..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/bikeshedder/BikeShedder.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2024, pajlada - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.bikeshedder; - -import com.google.common.collect.ImmutableMap; -import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; -import net.runelite.client.plugins.microbot.questhelper.collections.TeleportCollections; -import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; -import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; -import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.player.SpellbookRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.Spellbook; -import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.client.plugins.microbot.questhelper.steps.widget.NormalSpells; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.InterfaceID; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - -public class BikeShedder extends BasicQuestHelper -{ - private DetailedQuestStep moveToLumbridge; - private DetailedQuestStep confuseHans; - private DetailedQuestStep equipLightbearer; - - private ItemRequirement anyLog; - private ObjectStep useLogOnBush; - - private ItemRequirement oneCoin; - private ItemRequirement manyCoins; - private ObjectStep useCoinOnBush; - private ObjectStep useManyCoinsOnBush; - - private ItemRequirement varrockTeleport; - private ItemRequirement ardougneTeleport; - private ItemRequirement faladorTeleport; - - private Zone conditionalRequirementZone; - private ZoneRequirement conditionalRequirementZoneRequirement; - private ZoneRequirement conditionalRequirementZoneSouthRequirement; - private ZoneRequirement conditionalRequirementZoneNorthRequirement; - private ItemRequirement conditionalRequirementCoins; - private DetailedQuestStep conditionalRequirementLookAtCoins; - private ItemRequirement conditionalRequirementGoldBar; - private WidgetTextRequirement lookAtCooksAssistantRequirement; - private DetailedQuestStep lookAtCooksAssistant; - private WidgetTextRequirement lookAtCooksAssistantTextRequirement; - private ZoneRequirement byStaircaseInSunrisePalace; - private ObjectStep goDownstairsInSunrisePalace; - private DetailedQuestStep haveRunes; - private ItemRequirement lightbearer; - private ItemRequirement elemental30Unique; - private ItemRequirement elemental30; - private ItemRequirement anyCoins; - private ItemStep getCoins; - - // Sailing - private NpcStep talkToNpcOnBoat; - private NpcStep talkToKlarenceFromShip; - private ObjectStep useSalvagingHook; - private ObjectStep useObjectOffBoat; - private ZoneRequirement onBoat1; - private ZoneRequirement onBoat2; - private ZoneRequirement onBoat3; - private ZoneRequirement onBoat4; - - @Override - public Map loadSteps() - { - var lumbridge = new Zone(new WorldPoint(3217, 3210, 0), new WorldPoint(3226, 3228, 0)); - var outsideLumbridge = new ZoneRequirement(false, lumbridge); - moveToLumbridge.setHighlightZone(lumbridge); - var steps = new ConditionalStep(this, confuseHans); - - // aldarin bank - var plankNoBank = new ItemRequirement("Plank (no bank)", ItemID.WOODPLANK); - { - // Do not check bank for plank - var plankStep = new DetailedQuestStep(this, "Plank requirement will not check bank", plankNoBank); - var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will not check bank (Requirement used as conditional step passed)", plankNoBank); - var cPlankStep = new ConditionalStep(this, plankStep); - cPlankStep.addStep(plankNoBank, plankStepPassed); - steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2926, 0)), cPlankStep); - } - - { - // Check bank for plank using alsoCheckBank - var plank = plankNoBank.alsoCheckBank(); - plank.setName("Plank (check bank 1)"); - var plankStep = new DetailedQuestStep(this, "Plank requirement will check bank 1", plank); - var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will check bank 1 (Requirement used as conditional step passed)", plank); - var cPlankStep = new ConditionalStep(this, plankStep); - cPlankStep.addStep(plank, plankStepPassed); - steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2925, 0)), cPlankStep); - } - - { - // Check bank for plank using setShouldCheckBank - var plank = new ItemRequirement("Plank (no bank)", ItemID.WOODPLANK); - plank.setShouldCheckBank(true); - plank.setName("Plank (check bank 2)"); - var plankStep = new DetailedQuestStep(this, "Plank requirement will check bank 2", plank); - var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will check bank 2 (Requirement used as conditional step passed)", plank); - var cPlankStep = new ConditionalStep(this, plankStep); - cPlankStep.addStep(plank, plankStepPassed); - steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2924, 0)), cPlankStep); - } - - // mistrock bank - { - // does not need to be equipped - var blueWizardHat = new ItemRequirement("Blue wizard hat", ItemID.BLUEWIZHAT); - var step = new DetailedQuestStep(this, "Blue wizard hat, does not have to be equipped", blueWizardHat); - var stepPassed = new DetailedQuestStep(this, "Blue wizard hat, does not have to be equipped (Requirement used as conditional step passed)", blueWizardHat); - var cStep = new ConditionalStep(this, step); - cStep.addStep(blueWizardHat, stepPassed); - steps.addStep(new ZoneRequirement(new WorldPoint(1383, 2866, 0)), cStep); - } - - { - // must be equipped - var blueWizardHat = new ItemRequirement("Blue wizard hat", ItemID.BLUEWIZHAT); - blueWizardHat.setMustBeEquipped(true); - var step = new DetailedQuestStep(this, "Blue wizard hat, must be equipped", blueWizardHat); - var stepPassed = new DetailedQuestStep(this, "Blue wizard hat, must be equipped (Requirement used as conditional step passed)", blueWizardHat); - var cStep = new ConditionalStep(this, step); - cStep.addStep(blueWizardHat, stepPassed); - steps.addStep(new ZoneRequirement(new WorldPoint(1382, 2866, 0)), cStep); - } - - // Boat - steps.addStep(onBoat1, talkToNpcOnBoat); - steps.addStep(onBoat2, talkToKlarenceFromShip); - steps.addStep(onBoat3, useSalvagingHook); - steps.addStep(onBoat4, useObjectOffBoat); - - steps.addStep(byStaircaseInSunrisePalace, goDownstairsInSunrisePalace); - steps.addStep(outsideLumbridge, moveToLumbridge); - steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3218, 0)), haveRunes); - steps.addStep(new ZoneRequirement(new WorldPoint(3222, 3218, 0)), equipLightbearer); - steps.addStep(new ZoneRequirement(new WorldPoint(3223, 3218, 0)), useLogOnBush); - steps.addStep(new ZoneRequirement(new WorldPoint(3222, 3217, 0)), useCoinOnBush); - steps.addStep(new ZoneRequirement(new WorldPoint(3223, 3216, 0)), useManyCoinsOnBush); - steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3216, 0)), getCoins); - steps.addStep(conditionalRequirementZoneRequirement, conditionalRequirementLookAtCoins); - steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3221, 0)), lookAtCooksAssistant); - - return new ImmutableMap.Builder() - .put(-1, steps) - .build(); - } - - @Override - protected void setupRequirements() - { - moveToLumbridge = new DetailedQuestStep(this, new WorldPoint(3221, 3218, 0), "Move to outside Lumbridge Castle"); - - var normalSpellbook = new SpellbookRequirement(Spellbook.NORMAL); - - confuseHans = new NpcStep(this, NpcID.HANS, new WorldPoint(3221, 3218, 0), "Cast Confuse on Hans", normalSpellbook); - confuseHans.addSpellHighlight(NormalSpells.CONFUSE); - - lightbearer = new ItemRequirement("Lightbearer", ItemID.LIGHTBEARER).highlighted(); - equipLightbearer = new DetailedQuestStep(this, "Equip a Lightbearer", lightbearer.equipped()); - - anyLog = new ItemRequirement("Any log", ItemCollections.LOGS_FOR_FIRE).highlighted(); - - useLogOnBush = new ObjectStep(this, ObjectID.PVPW_ARMOURSTAND_BUSH, new WorldPoint(3223, 3217, 0), "Use log on bush", anyLog); - useLogOnBush.addIcon(ItemID.LOGS); - - varrockTeleport = TeleportCollections.VARROCK_TELEPORT.getItemRequirement(); - ardougneTeleport = TeleportCollections.ARDOUGNE_TELEPORT.getItemRequirement(); - faladorTeleport = TeleportCollections.FALADOR_TELEPORT.getItemRequirement(); - - oneCoin = new ItemRequirement("Coins", ItemCollections.COINS, 1); - oneCoin.setHighlightInInventory(true); - useCoinOnBush = new ObjectStep(this, ObjectID.PVPW_ARMOURSTAND_BUSH, new WorldPoint(3223, 3217, 0), "Use coins on the bush.", oneCoin); - useCoinOnBush.addIcon(ItemID.COINS); - - manyCoins = new ItemRequirement("Coins", ItemCollections.COINS, 100); - manyCoins.setHighlightInInventory(true); - useManyCoinsOnBush = new ObjectStep(this, ObjectID.PVPW_ARMOURSTAND_BUSH, new WorldPoint(3223, 3217, 0), "Use many coins on the bush.", manyCoins); - useManyCoinsOnBush.addIcon(ItemID.COINS); - - conditionalRequirementZone = new Zone(new WorldPoint(3223, 3221, 0), new WorldPoint(3223, 3223, 0)); - conditionalRequirementZoneRequirement = new ZoneRequirement(conditionalRequirementZone); - conditionalRequirementZoneSouthRequirement = new ZoneRequirement(new WorldPoint(3223, 3221, 0)); - conditionalRequirementZoneNorthRequirement = new ZoneRequirement(new WorldPoint(3223, 3223, 0)); - - conditionalRequirementCoins = new ItemRequirement("Coins", ItemCollections.COINS, 50); - conditionalRequirementCoins.setTooltip("Obtained by robbing a bank"); - conditionalRequirementCoins.setHighlightInInventory(true); - conditionalRequirementCoins.setConditionToHide(conditionalRequirementZoneSouthRequirement); - - conditionalRequirementGoldBar = new ItemRequirement("Gold Bar", ItemID.GOLD_BAR, 1); - conditionalRequirementGoldBar.setTooltip("Obtained by robbing a bank"); - conditionalRequirementGoldBar.setHighlightInInventory(true); - conditionalRequirementGoldBar.setConditionToHide(or(conditionalRequirementZoneNorthRequirement, conditionalRequirementZoneSouthRequirement)); - - conditionalRequirementLookAtCoins = new DetailedQuestStep(this, "Admire the coins in your inventory.", conditionalRequirementCoins); - - lookAtCooksAssistantRequirement = new WidgetTextRequirement(InterfaceID.Questjournal.TITLE, "Cook's Assistant"); - lookAtCooksAssistantRequirement.setDisplayText("Cook's Assistant quest journal open"); - lookAtCooksAssistantTextRequirement = new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "he now lets me use his high quality range"); - lookAtCooksAssistantTextRequirement.setDisplayText("Cook's Assistant quest journal open & received reward (checking text)"); - lookAtCooksAssistant = new DetailedQuestStep(this, "Open the Cook's Assistant quest journal. You must have started the quest for this test to work.", lookAtCooksAssistantRequirement, lookAtCooksAssistantTextRequirement); - - var upstairsInSunrisePalace = new Zone(new WorldPoint(1684, 3162, 1), new WorldPoint(1691, 3168, 1)); - byStaircaseInSunrisePalace = new ZoneRequirement(upstairsInSunrisePalace); - goDownstairsInSunrisePalace = new ObjectStep(getQuest().getQuestHelper(), ObjectID.CIVITAS_PALACE_STAIRS_DOWN, new WorldPoint(1690, 3164, 1), "Climb downstairs, ensure stairs are well highlighted!"); - - - var fire30 = new ItemRequirement("Fire runes", ItemID.FIRERUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 63)); - var air30 = new ItemRequirement("Air runes", ItemID.AIRRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 66)); - var water30 = new ItemRequirement("Water runes", ItemID.WATERRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 56)); - var earth30 = new ItemRequirement("Earth runes", ItemID.EARTHRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 60)); - elemental30Unique = new ItemRequirements(LogicType.OR, "Elemental runes as ItemRequirements OR", air30, water30, earth30, fire30); - elemental30Unique.addAlternates(ItemID.FIRERUNE, ItemID.EARTHRUNE, ItemID.AIRRUNE); - elemental30 = new ItemRequirement("Elemental rune as ItemRequirement", List.of(ItemID.AIRRUNE, ItemID.EARTHRUNE, ItemID.WATERRUNE, - ItemID.FIRERUNE), 30); - elemental30.setTooltip("You have potato"); - haveRunes = new DetailedQuestStep(this, "Compare rune checks for ItemRequirement and ItemRequirements with OR.", elemental30, elemental30Unique); - - anyCoins = new ItemRequirement("Coins", ItemCollections.COINS); - getCoins = new ItemStep(this, new WorldPoint(3224, 3215, 0), "Get coins", anyCoins); - - // Sailing - - var zones1 = new Zone[] { - new Zone(new WorldPoint(3843, 6402, 1), new WorldPoint(3844, 6402, 1)), // Tutorial - new Zone(new WorldPoint(3842, 6389, 1), new WorldPoint(3876, 6389, 1)), - new Zone(new WorldPoint(3842, 6365, 1), new WorldPoint(3860, 6365, 1)), - new Zone(new WorldPoint(3843, 6354, 1), new WorldPoint(3884, 6354, 1)) - }; - onBoat1 = new ZoneRequirement(zones1); - - var zones2 = new Zone[] { - new Zone(new WorldPoint(3843, 6403, 1), new WorldPoint(3844, 6403, 1)), // Tutorial - new Zone(new WorldPoint(3842, 6390, 1), new WorldPoint(3876, 6390, 1)), - new Zone(new WorldPoint(3842, 6366, 1), new WorldPoint(3860, 6366, 1)), - new Zone(new WorldPoint(3843, 6355, 1), new WorldPoint(3884, 6355, 1)) - }; - onBoat2 = new ZoneRequirement(zones2); - - var zones3 = new Zone[] { - new Zone(new WorldPoint(3843, 6404, 1), new WorldPoint(3844, 6404, 1)), // Tutorial - new Zone(new WorldPoint(3842, 6391, 1), new WorldPoint(3876, 6391, 1)), - new Zone(new WorldPoint(3842, 6367, 1), new WorldPoint(3860, 6367, 1)), - new Zone(new WorldPoint(3843, 6356, 1), new WorldPoint(3884, 6356, 1)) - }; - onBoat3 = new ZoneRequirement(zones3); - - var zones4 = new Zone[] { - new Zone(new WorldPoint(3843, 6405, 1), new WorldPoint(3844, 6405, 1)), // Tutorial - new Zone(new WorldPoint(3842, 6312, 1), new WorldPoint(3876, 6392, 1)), - new Zone(new WorldPoint(3842, 6368, 1), new WorldPoint(3860, 6368, 1)), - new Zone(new WorldPoint(3843, 6357, 1), new WorldPoint(3884, 6357, 1)) - }; - onBoat4 = new ZoneRequirement(zones4); - - talkToNpcOnBoat = new NpcStep(this, NpcID.SAILING_INTRO_ANNE_BOAT, "Talk to a ship NPC."); - List shipNpcs = new ArrayList<>(); - for (int i = NpcID.SAILING_CREW_GENERIC_1_WORLD; i <= NpcID.SAILING_CREW_GHOST_JENKINS_CARGO_3; i++) - { - shipNpcs.add(i); - } - talkToNpcOnBoat.addHighlightZones(zones1); - talkToNpcOnBoat.addAlternateNpcs(shipNpcs.toArray(new Integer[0])); - - talkToKlarenceFromShip = new NpcStep(this, NpcID.KLARENSE, new WorldPoint(3046, 3205, 0), "Klarence off the ship."); - talkToKlarenceFromShip.setHighlightZone(new Zone(new WorldPoint(3044, 3202, 0), new WorldPoint(3050, 3205, 0))); - talkToKlarenceFromShip.addHighlightZones(zones2); - List salvagingHookIds = new ArrayList<>(); - for (int i = ObjectID.SAILING_INTRO_SALVAGING_HOOK; i <= ObjectID.SALVAGING_HOOK_LARGE_DRAGON_B; i++) - { - salvagingHookIds.add(i); - } - - useSalvagingHook = new ObjectStep(this, ObjectID.SAILING_INTRO_SALVAGING_HOOK, "Use the salvaging hook."); - useSalvagingHook.addAlternateObjects(salvagingHookIds.toArray(new Integer[0])); - useSalvagingHook.addHighlightZones(zones3); - - useObjectOffBoat = new ObjectStep(this, ObjectID.DRAGONSHIPGANGPLANK_ON, new WorldPoint(3047, 3205, 0), "Click Klarense's gangplank."); - useObjectOffBoat.setHighlightZone(new Zone(new WorldPoint(3044, 3202, 0), new WorldPoint(3050, 3205, 0))); - useObjectOffBoat.addHighlightZones(zones4); - } - - @Override - public List getItemRecommended() { - return Arrays.asList(varrockTeleport, ardougneTeleport, faladorTeleport, elemental30, elemental30Unique); - } - - @Override - public List getPanels() - { - var panels = new ArrayList(); - - panels.add(new PanelDetails("Move to Lumbridge", List.of(moveToLumbridge))); - panels.add(new PanelDetails("Normal Spellbook", List.of(confuseHans))); - panels.add(new PanelDetails("Equip Lightbearer", List.of(equipLightbearer), List.of(lightbearer))); - panels.add(new PanelDetails("Use log on mysterious bush", List.of(useLogOnBush), List.of(anyLog))); - panels.add(new PanelDetails("Use coins on mysterious bush", List.of(useCoinOnBush, useManyCoinsOnBush), List.of(oneCoin, manyCoins))); - panels.add(new PanelDetails("Conditional requirement", List.of(conditionalRequirementLookAtCoins), List.of(conditionalRequirementCoins, conditionalRequirementGoldBar))); - panels.add(new PanelDetails("Item step", List.of(getCoins), List.of(anyCoins))); - panels.add(new PanelDetails("Quest state", List.of(lookAtCooksAssistant), List.of(lookAtCooksAssistantRequirement, lookAtCooksAssistantTextRequirement))); - panels.add(new PanelDetails("Ensure staircase upstairs in Sunrise Palace is highlighted", List.of(goDownstairsInSunrisePalace), List.of())); - panels.add(new PanelDetails("Sailing", List.of(talkToNpcOnBoat, talkToKlarenceFromShip, useSalvagingHook, useObjectOffBoat), List.of())); - - return panels; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/ItemCollections.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/ItemCollections.java index 37a15faf42..4fe8c70dff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/ItemCollections.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/ItemCollections.java @@ -243,6 +243,39 @@ public enum ItemCollections ItemID.WILDERNESS_SWORD_ELITE )), + THROWING_KNIVES("Throwing Knives", ImmutableList.of( + ItemID.BRONZE_KNIFE, ItemID.BRONZE_KNIFE_P, ItemID.BRONZE_KNIFE_P_, ItemID.BRONZE_KNIFE_P__, + ItemID.IRON_KNIFE, ItemID.IRON_KNIFE_P, ItemID.IRON_KNIFE_P_, ItemID.IRON_KNIFE_P__, + ItemID.STEEL_KNIFE, ItemID.STEEL_KNIFE_P, ItemID.STEEL_KNIFE_P_, ItemID.STEEL_KNIFE_P__, + ItemID.BLACK_KNIFE, ItemID.BLACK_KNIFE_P, ItemID.BLACK_KNIFE_P_, ItemID.BLACK_KNIFE_P__, + ItemID.MITHRIL_KNIFE, ItemID.MITHRIL_KNIFE_P, ItemID.MITHRIL_KNIFE_P_, ItemID.MITHRIL_KNIFE_P__, + ItemID.ADAMANT_KNIFE, ItemID.ADAMANT_KNIFE_P, ItemID.ADAMANT_KNIFE_P_, ItemID.ADAMANT_KNIFE_P__, + ItemID.RUNE_KNIFE, ItemID.RUNE_KNIFE_P, ItemID.RUNE_KNIFE_P_, ItemID.RUNE_KNIFE_P__, + ItemID.DRAGON_KNIFE, ItemID.DRAGON_KNIFE_P, ItemID.DRAGON_KNIFE_P_, ItemID.DRAGON_KNIFE_P__ + )), + + DARTS("Darts", ImmutableList.of( + ItemID.BRONZE_DART, ItemID.BRONZE_DART_P, ItemID.BRONZE_DART_P_, ItemID.BRONZE_DART_P__, + ItemID.IRON_DART, ItemID.IRON_DART_P, ItemID.IRON_DART_P_, ItemID.IRON_DART_P__, + ItemID.STEEL_DART, ItemID.STEEL_DART_P, ItemID.STEEL_DART_P_, ItemID.STEEL_DART_P__, + ItemID.BLACK_DART, ItemID.BLACK_DART_P, ItemID.BLACK_DART_P_, ItemID.BLACK_DART_P__, + ItemID.MITHRIL_DART, ItemID.MITHRIL_DART_P, ItemID.MITHRIL_DART_P_, ItemID.MITHRIL_DART_P__, + ItemID.ADAMANT_DART, ItemID.ADAMANT_DART_P, ItemID.ADAMANT_DART_P_, ItemID.ADAMANT_DART_P__, + ItemID.RUNE_DART, ItemID.RUNE_DART_P, ItemID.RUNE_DART_P_, ItemID.RUNE_DART_P__, + ItemID.AMETHYST_DART, ItemID.AMETHYST_DART_P, ItemID.AMETHYST_DART_P_, ItemID.AMETHYST_DART_P__, + ItemID.DRAGON_DART, ItemID.DRAGON_DART_P, ItemID.DRAGON_DART_P_, ItemID.DRAGON_DART_P__ + )), + + THROWING_AXES("Throwing Axes", ImmutableList.of( + ItemID.BRONZE_THROWNAXE, + ItemID.IRON_THROWNAXE, + ItemID.STEEL_THROWNAXE, + ItemID.MITHRIL_THROWNAXE, + ItemID.ADAMNT_THROWNAXE, + ItemID.RUNE_THROWNAXE, + ItemID.DRAGON_THROWNAXE + )), + METAL_ARROWS(ImmutableList.of( ItemID.RUNE_ARROW, ItemID.ADAMANT_ARROW, @@ -2211,6 +2244,25 @@ public enum ItemCollections ItemID.WILDBLOOD_HOP_SEED )), + /// Things you can slash webs with that are safe to bring to wildy + SLASH_WEB_KNIFE(ImmutableList.of( + ItemID.KNIFE, + ItemID.WILDERNESS_SWORD_ELITE, + ItemID.WILDERNESS_SWORD_HARD, + ItemID.WILDERNESS_SWORD_MEDIUM, + ItemID.WILDERNESS_SWORD_EASY + )), + + BOAT_REPAIR_KITS(ImmutableList.of( + ItemID.BOAT_REPAIR_KIT_ROSEWOOD, + ItemID.BOAT_REPAIR_KIT_IRONWOOD, + ItemID.BOAT_REPAIR_KIT_CAMPHOR, + ItemID.BOAT_REPAIR_KIT_MAHOGANY, + ItemID.BOAT_REPAIR_KIT_TEAK, + ItemID.BOAT_REPAIR_KIT_OAK, + ItemID.BOAT_REPAIR_KIT + )), + BUSH_SEEDS(ImmutableList.of( ItemID.REDBERRY_BUSH_SEED, ItemID.CADAVABERRY_BUSH_SEED, @@ -2252,6 +2304,13 @@ public enum ItemCollections ItemID.CA_OFFHAND_EASY )), + ARDOUGNE_CLOAK(ImmutableList.of( + ItemID.ARDY_CAPE_EASY, + ItemID.ARDY_CAPE_MEDIUM, + ItemID.ARDY_CAPE_HARD, + ItemID.ARDY_CAPE_ELITE + )), + PROSPECTOR_HELMET(ImmutableList.of( ItemID.MOTHERLODE_REWARD_HAT, ItemID.FOSSIL_MOTHERLODE_REWARD_HAT, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/KeyringCollection.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/KeyringCollection.java index aae9f687d5..341738056a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/KeyringCollection.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/KeyringCollection.java @@ -24,16 +24,11 @@ */ package net.runelite.client.plugins.microbot.questhelper.collections; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.KeyringRequirement; +import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import lombok.Getter; import net.runelite.api.gameval.ItemID; import net.runelite.client.config.ConfigManager; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - public enum KeyringCollection { SHINY_KEY(ItemID.IKOV_SHINYKEY), @@ -50,14 +45,18 @@ public enum KeyringCollection ENCHANTED_KEY(ItemID.MAKINGHISTORY_KEY), NEW_KEY(ItemID.MOURNING_EXCAVATION_KEY); + private final String CONFIG_GROUP = QuestHelperConfig.QUEST_BACKGROUND_GROUP; + @Getter private final int itemID; + KeyringCollection(int itemID) { this.itemID = itemID; } - public String toChatText() + /// The name of this key as seen in the chat box. + public String chatboxText() { return name().toLowerCase().replaceAll("_", " "); } @@ -67,19 +66,20 @@ public String runeliteName() return name().toLowerCase().replaceAll("_", ""); } - public static List allKeyRequirements(ConfigManager configManager) + public boolean hasKeyOnKeyRing(ConfigManager configManager) { - List keys = new ArrayList<>(); - for (KeyringCollection keyringCollection : Collections.unmodifiableList(Arrays.asList(values()))) - { - keys.add(new KeyringRequirement(configManager, keyringCollection)); - } + var value = configManager.getRSProfileConfiguration(CONFIG_GROUP, runeliteName()); - return keys; + return "true".equals(value); } - public KeyringRequirement getRequirement(ConfigManager configManager) + public void setHasKeyOnKeyRing(ConfigManager configManager, boolean value) { - return new KeyringRequirement(configManager, this); + if (configManager.getRSProfileKey() == null) + { + return; + } + + configManager.setRSProfileConfiguration(CONFIG_GROUP, runeliteName(), value ? "true" : "false"); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/TeleportCollections.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/TeleportCollections.java index 5e57251daf..258d034304 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/TeleportCollections.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/collections/TeleportCollections.java @@ -29,7 +29,7 @@ public ItemRequirement getItemRequirement() ItemRequirement varrockRunes = new ItemRequirements("Varrock teleport runes", new ItemRequirement("Law rune", ItemID.LAWRUNE, 1), new ItemRequirement("Air rune", ItemID.AIRRUNE, 3), - new ItemRequirement("Water rune", ItemID.WATERRUNE, 1) + new ItemRequirement("Fire rune", ItemID.FIRERUNE, 1) ); return new ItemRequirements(LogicType.OR, "Teleport to Varrock. Varrock teleport tablet/spell, Chronicle, Ring of Wealth (Grand Exchange [2])", varrockTele, varrockRunes); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/ConfigKeys.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/ConfigKeys.java deleted file mode 100644 index 5a7402bf71..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/ConfigKeys.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2024, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.config; - -import lombok.Getter; - -public enum ConfigKeys -{ - // Barbarian Training Enums - BARBARIAN_TRAINING_STARTED_FISHING("barbariantrainingstartedfishing"), - BARBARIAN_TRAINING_STARTED_HARPOON("barbariantrainingstartedharpoon"), - BARBARIAN_TRAINING_STARTED_SEED_PLANTING("barbariantrainingstartedseedplanting"), - BARBARIAN_TRAINING_STARTED_POT_SMASHING("barbariantrainingstartedpotsmashing"), - BARBARIAN_TRAINING_STARTED_FIREMAKING("barbariantrainingstartedfiremaking"), - BARBARIAN_TRAINING_STARTED_PYREMAKING("barbariantrainingstartedpyremaking"), - BARBARIAN_TRAINING_STARTED_HERBLORE("barbariantrainingstartedherblore"), - BARBARIAN_TRAINING_STARTED_SPEAR("barbariantrainingstartedspear"), - BARBARIAN_TRAINING_STARTED_HASTA("barbariantrainingstartedhasta"), - - // Finished Barbarian Training Enums - BARBARIAN_TRAINING_FINISHED_FISHING("barbariantrainingfinishedfishing"), - BARBARIAN_TRAINING_FINISHED_HARPOON("barbariantrainingfinishedharpoon"), - BARBARIAN_TRAINING_FINISHED_SEED_PLANTING("barbariantrainingfinishedseedplanting"), - BARBARIAN_TRAINING_FINISHED_POT_SMASHING("barbariantrainingfinishedpotsmashing"), - BARBARIAN_TRAINING_FINISHED_FIREMAKING("barbariantrainingfinishedfiremaking"), - BARBARIAN_TRAINING_FINISHED_PYREMAKING("barbariantrainingfinishedpyremaking"), - BARBARIAN_TRAINING_FINISHED_SPEAR("barbariantrainingfinishedspear"), - BARBARIAN_TRAINING_FINISHED_HASTA("barbariantrainingfinishedhasta"), - BARBARIAN_TRAINING_FINISHED_HERBLORE("barbariantrainingfinishedherblore"), - - // Mid-conditions - BARBARIAN_TRAINING_PLANTED_SEED("barbariantrainingplantedseed"), - BARBARIAN_TRAINING_SMASHED_POT("barbariantrainingsmashedpot"), - BARBARIAN_TRAINING_BOW_FIRE("barbariantrainingbowfire"), - BARBARIAN_TRAINING_PYRE_MADE("barbariantrainingpyremade"), - BARBARIAN_TRAINING_BARBFISHED("barbariantrainingbarbfished"), - BARBARIAN_TRAINING_HARPOONED_FISH("barbariantrainingharpoonedfish"), - BARBARIAN_TRAINING_MADE_POTION("barbariantrainingmadepotion"), - BARBARIAN_TRAINING_MADE_SPEAR("barbariantrainingmadespear"), - BARBARIAN_TRAINING_MADE_HASTA("barbariantrainingmadehasta"); - - @Getter - final String key; - - ConfigKeys(String key) - { - this.key = key; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/RegionHintArrowRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/LeagueFiltering.java similarity index 56% rename from runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/RegionHintArrowRequirement.java rename to runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/LeagueFiltering.java index 6d58100b98..7328abe254 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/RegionHintArrowRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/config/LeagueFiltering.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Zoinkwiz + * Copyright (c) 2026, Syrif * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,43 +22,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.microbot.questhelper.requirements; +package net.runelite.client.plugins.microbot.questhelper.config; -import net.runelite.api.Client; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; -import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; +import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; +import net.runelite.client.plugins.microbot.questhelper.questinfo.LeagueQuestRegions; +import net.runelite.client.plugins.microbot.questhelper.questinfo.LeagueRegion; -public class RegionHintArrowRequirement extends SimpleRequirement -{ - private final Zone zone; +import java.util.EnumSet; - public RegionHintArrowRequirement(WorldPoint worldPoint) - { - assert(worldPoint != null); - this.zone = new Zone(worldPoint, worldPoint); - } +/** + * Filters quests by league regions selected in the panel UI. + * When no regions are selected, all quests pass. When regions are selected, + * only quests completable with those regions are shown. + */ +public class LeagueFiltering +{ + private static EnumSet selectedRegions = null; - public RegionHintArrowRequirement(Zone zone) + public static void setSelectedRegions(EnumSet regions) { - assert(zone != null); - this.zone = zone; + selectedRegions = (regions == null || regions.isEmpty()) ? null : regions; } - public boolean check(Client client) + public static boolean passesLeagueFilter(QuestHelper questHelper) { - WorldPoint hintArrowPoint = client.getHintArrowPoint(); - if (hintArrowPoint == null) + if (selectedRegions == null) { - return false; + return true; } - - WorldPoint wp = QuestPerspective.getWorldPointConsideringWorldView(client, client.getTopLevelWorldView(), hintArrowPoint); - if (wp == null) - { - return false; - } - - return zone.contains(wp); + return LeagueQuestRegions.isCompletableWith(questHelper.getQuest(), selectedRegions); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/domain/QuetzalDestination.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/domain/QuetzalDestination.java new file mode 100644 index 0000000000..bfd66ce012 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/domain/QuetzalDestination.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026, pajlada + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.domain; + +import lombok.RequiredArgsConstructor; + +/// Mapping from quetzal destinations to the model ID used in the quetzal map widget. +/// +/// See {@link net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight#createQuetzalHighlight} +@RequiredArgsConstructor +public enum QuetzalDestination +{ + CIVITAS_ILLA_FORTIS(51208), + THE_TEOMAT(51205), + SUNSET_COAST(51187), + HUNTER_GUILD(51185), + ALDARIN(54547), + QUETZACALLI_GORGE(54539), + TAL_TEKLAN(56665); + + public final int modelID; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneEasy.java index c7fab86e21..7b46a4c89a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneEasy.java @@ -41,6 +41,8 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.List; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -49,9 +51,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarPlayerID; -import java.util.ArrayList; -import java.util.List; - public class ArdougneEasy extends ComplexStateQuestHelper { // Required items @@ -279,7 +278,7 @@ public List getPanels() sections.add(PanelDetails.lockedPanel( "Identify Sword", notIdentifySword, - identifySword, + identifySwordTask, List.of( identifySword ), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneElite.java index 09d5b1c246..63c427560f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneElite.java @@ -119,11 +119,11 @@ public QuestStep loadStep() doElite.addStep(notPickHero, pickHeroTask); runeCrossbowTask = new ConditionalStep(this, spinString); - runeCrossbowTask.addStep(new Conditions(madeString, crossbowString), moveToYan); - runeCrossbowTask.addStep(new Conditions(inYanille, madeString, crossbowString), smithLimbs); - runeCrossbowTask.addStep(new Conditions(inYanille, madeLimbs, crossbowString, runeLimbs), fletchStock); - runeCrossbowTask.addStep(new Conditions(inYanille, madeStock, crossbowString, runeLimbs, yewStock), makeUnstrungCross); runeCrossbowTask.addStep(new Conditions(inYanille, madeCrossU, runeCrossbowU, crossbowString), runeCrossbow); + runeCrossbowTask.addStep(new Conditions(inYanille, madeStock, crossbowString, runeLimbs, yewStock), makeUnstrungCross); + runeCrossbowTask.addStep(new Conditions(inYanille, madeLimbs, crossbowString, runeLimbs), fletchStock); + runeCrossbowTask.addStep(new Conditions(inYanille, madeString, crossbowString), smithLimbs); + runeCrossbowTask.addStep(new Conditions(madeString, crossbowString), moveToYan); doElite.addStep(notRuneCrossbow, runeCrossbowTask); return doElite; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneHard.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneHard.java index d08ea96525..cee94899a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneHard.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneHard.java @@ -187,7 +187,7 @@ protected void setupRequirements() var hasCompletedSOTE = new QuestRequirement(QuestHelperQuest.SONG_OF_THE_ELVES, QuestState.FINISHED); - newKey = new KeyringRequirement("New key", configManager, KeyringCollection.NEW_KEY).showConditioned(notDeathRune).isNotConsumed().hideConditioned(hasCompletedSOTE); + newKey = new KeyringRequirement("New key", KeyringCollection.NEW_KEY).showConditioned(notDeathRune).isNotConsumed().hideConditioned(hasCompletedSOTE); newKey.setTooltip("Another can be found on the desk in the south-east room of the Mourner HQ basement."); mournerBoots = new ItemRequirement("Mourner boots", ItemID.MOURNING_MOURNER_BOOTS).isNotConsumed().hideConditioned(hasCompletedSOTE); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneMedium.java index 78ae2a463c..1a8c9e4ebf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/ardougne/ArdougneMedium.java @@ -52,7 +52,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import net.runelite.client.game.FishingSpot; import java.util.ArrayList; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertEasy.java index cf00c7c3de..99af7a2e11 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertEasy.java @@ -39,8 +39,8 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; -import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertElite.java index ae515eed2a..61129b38e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/desert/DesertElite.java @@ -225,7 +225,7 @@ public List getItemRequirements() { return Arrays.asList(rawPie, waterRune.quantity(6), bloodRune.quantity(2), deathRune.quantity(4), dragonDartTip, feather, kqHead, mahoganyPlank.quantity(2), goldLeaves.quantity(2), coins.quantity(50000), saw, - hammer, kqHead); + hammer); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorEasy.java index 05cd374f16..a53d8be127 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorEasy.java @@ -157,7 +157,7 @@ protected void setupRequirements() //Required bucket = new ItemRequirement("Bucket", ItemID.BUCKET_EMPTY).showConditioned(notFilledWater).isNotConsumed(); - tiara = new ItemRequirement("Silver Tiara", ItemID.TIARA).showConditioned(notMindTiara); + tiara = new ItemRequirement("Tiara", ItemID.TIARA).showConditioned(notMindTiara); mindTalisman = new ItemRequirement("Mind Talisman", ItemID.MIND_TALISMAN).showConditioned(notMindTiara); hammer = new ItemRequirement("Hammer", ItemID.HAMMER).showConditioned(new Conditions(LogicType.OR, notMotherloadMine, notBluriteLimbs)).isNotConsumed(); pickaxe = new ItemRequirement("Any Pickaxe", ItemCollections.PICKAXES) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorElite.java index 950d2727f9..114ddbe74d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/falador/FaladorElite.java @@ -50,7 +50,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikElite.java index ff4824e6a6..43b00dee03 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikElite.java @@ -51,7 +51,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikMedium.java index 3826ed2387..1a670253cf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/fremennik/FremennikMedium.java @@ -52,7 +52,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; @@ -443,7 +447,10 @@ public List getItemRewards() @Override public List getUnlockRewards() { - return Arrays.asList(new UnlockReward("Improved rate of gaining approval on Miscellania.")); + return Arrays.asList( + new UnlockReward("Improved rate of gaining approval on Miscellania."), + new UnlockReward("Unlocking infinite charges for your lyre with Fossegrimen costs 600 of each fish rather than 800") + ); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinEasy.java index 7b17d45795..ac75ab0c37 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinEasy.java @@ -40,6 +40,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; @@ -53,16 +54,19 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarPlayerID; +import net.runelite.api.gameval.VarbitID; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; public class KandarinEasy extends ComplexStateQuestHelper { // Items required - ItemRequirement combatGear, bigFishingNet, coins, juteSeed, seedDibber, rake, batteredKey, + ItemRequirement combatGear, bigFishingNet, coins, juteSeed, seedDibber, rake, spade, batteredKey, emptyFishbowl, fishBowl, seaweed, fishBowlSeaweed, tinyNet, genericFishbowl; // Items recommended @@ -79,7 +83,7 @@ public class KandarinEasy extends ComplexStateQuestHelper QuestStep killFire, killEarth, killWater, killAir; - NpcStep catchMackerel, killEle; + NpcStep catchMackerel; Zone workshop; @@ -127,8 +131,7 @@ public QuestStep loadStep() killEleTask.addStep(new Conditions(inWorkshop, killedFire, killedEarth, killedWater), killAir); killEleTask.addStep(new Conditions(inWorkshop, killedFire, killedEarth), killWater); killEleTask.addStep(new Conditions(inWorkshop, killedFire), killEarth); - killEleTask.addStep(new Conditions(inWorkshop), killFire); - killEleTask.addStep(inWorkshop, killEle); + killEleTask.addStep(inWorkshop, killFire); doEasy.addStep(notKillEle, killEleTask); plantJuteTask = new ConditionalStep(this, plantJute); @@ -175,8 +178,11 @@ protected void setupRequirements() seaweed = new ItemRequirement("Seaweed", ItemID.SEAWEED).showConditioned(notPetFish); juteSeed = new ItemRequirement("Jute seeds", ItemID.JUTE_SEED).showConditioned(notPlantJute); rake = new ItemRequirement("Rake", ItemID.RAKE).showConditioned(notPlantJute).isNotConsumed(); - seedDibber = new ItemRequirement("Seed dibber", ItemID.DIBBER).showConditioned(notPlantJute).isNotConsumed(); - batteredKey = new KeyringRequirement("Battered Key", configManager, KeyringCollection.BATTERED_KEY).showConditioned(notKillEle).isNotConsumed(); + var needSeedDibber = not(new VarbitRequirement(VarbitID.BRUT_FARMING_PLANTING, 3)); + seedDibber = new ItemRequirement("Seed dibber", ItemID.DIBBER).showConditioned(and(notPlantJute, needSeedDibber)).isNotConsumed(); + spade = new ItemRequirement("Spade (if existing plant in hops patch)", ItemID.SPADE).showConditioned(notPlantJute).isNotConsumed(); + + batteredKey = new KeyringRequirement("Battered Key", KeyringCollection.BATTERED_KEY).showConditioned(notKillEle).isNotConsumed(); batteredKey.setTooltip("You can get another by searching the bookcase in the house south of the Elemental " + "Workshop, then reading the book you get from it"); @@ -227,18 +233,14 @@ public void setupSteps() "Speak with Sherlock west of Catherby."); moveToWorkshop = new ObjectStep(this, ObjectID.ELEMENTAL_WORKSHOP_SPIRALSTAIRSTOP, new WorldPoint(2711, 3498, 0), "Enter the Elemental Workshop in Seers' Village.", batteredKey, combatGear, food); - killEle = new NpcStep(this, NpcID.ELEMENTAL_FIRE, new WorldPoint(2719, 9889, 0), - "Kill one of each of the 4 elementals.", combatGear, food); - killEle.addAlternateNpcs(NpcID.ELEMENTAL_WATER, NpcID.ELEMENTAL_AIR, NpcID.ELEMENTAL_EARTH); killFire = new NpcStep(this, NpcID.ELEMENTAL_FIRE, new WorldPoint(2719, 9877, 0), - "Kill one of each of the 4 elementals.", true, combatGear, food); + "Kill one of the fire elementals.", true, combatGear, food); killEarth = new NpcStep(this, NpcID.ELEMENTAL_EARTH, new WorldPoint(2700, 9903, 0), - "Kill one of each of the 4 elementals.", true, combatGear, food); + "Kill one of the earth elementals. Only the roaming ones work for this.", true, combatGear, food); killWater = new NpcStep(this, NpcID.ELEMENTAL_WATER, new WorldPoint(2719, 9903, 0), - "Kill one of each of the 4 elementals.", true, combatGear, food); + "Kill one of the water elementals.", true, combatGear, food); killAir = new NpcStep(this, NpcID.ELEMENTAL_AIR, new WorldPoint(2735, 9891, 0), - "Kill one of each of the 4 elementals.", true, combatGear, food); - killEle.addSubSteps(killFire, killEarth, killWater, killAir); + "Kill one of the air elementals.", true, combatGear, food); buyStew = new NpcStep(this, NpcID.FORESTERS_BARTENDER, new WorldPoint(2691, 3494, 0), "Talk with the bartender in Seers' Village and buy a stew.", coins.quantity(20)); @@ -247,7 +249,7 @@ public void setupSteps() "Play the organ in Seers' Village Church."); plantJute = new ObjectStep(this, ObjectID.FARMING_HOPS_PATCH_4, new WorldPoint(2669, 3523, 0), "Plant 3 jute seeds in the hops patch north west of Seers' Village.", juteSeed.quantity(3), - seedDibber, rake); + seedDibber, rake, spade); plantJute.addIcon(ItemID.JUTE_SEED); cupTea = new NpcStep(this, NpcID.BROTHER_GALAHAD, new WorldPoint(2612, 3474, 0), "Talk with Galahad west of McGrubor's Wood until he gives you some tea."); @@ -264,7 +266,7 @@ public void setupSteps() public List getItemRequirements() { return Arrays.asList(coins.quantity(33), bigFishingNet, juteSeed.quantity(3), - seedDibber, rake, batteredKey, genericFishbowl, seaweed, combatGear); + seedDibber, rake, spade, batteredKey, genericFishbowl, seaweed, combatGear); } @Override @@ -354,14 +356,14 @@ public List getPanels() buyStewSteps.setLockingStep(buyStewTask); allSteps.add(buyStewSteps); - PanelDetails killElesSteps = new PanelDetails("Defeat Elementals", Arrays.asList(moveToWorkshop, killEle), + PanelDetails killElesSteps = new PanelDetails("Defeat Elementals", Arrays.asList(moveToWorkshop, killFire, killEarth, killWater, killAir), eleWorkI, batteredKey, combatGear, food); killElesSteps.setDisplayCondition(notKillEle); killElesSteps.setLockingStep(killEleTask); allSteps.add(killElesSteps); PanelDetails plantJuteSteps = new PanelDetails("Plant Jute", Collections.singletonList(plantJute), - new SkillRequirement(Skill.FARMING, 13, true), juteSeed.quantity(3), seedDibber, rake); + new SkillRequirement(Skill.FARMING, 13, true), juteSeed.quantity(3), seedDibber, rake, spade); plantJuteSteps.setDisplayCondition(notPlantJute); plantJuteSteps.setLockingStep(plantJuteTask); allSteps.add(plantJuteSteps); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinElite.java index 976de10ded..41134fa0bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinElite.java @@ -147,7 +147,7 @@ protected void setupRequirements() spade = new ItemRequirement("Spade", ItemID.SPADE).showConditioned(notPickDwarf).isNotConsumed(); rake = new ItemRequirement("Rake", ItemID.RAKE).showConditioned(notPickDwarf).isNotConsumed(); compost = new ItemRequirement("Any compost", ItemCollections.COMPOST).showConditioned(notPickDwarf); - harpoon = new ItemRequirement("Harpoon", ItemID.HARPOON).showConditioned(not5Shark).isNotConsumed(); + harpoon = new ItemRequirement("Harpoon", ItemCollections.HARPOONS).showConditioned(not5Shark).isNotConsumed(); cookingGaunt = new ItemRequirement("Cooking gauntlets", ItemID.GAUNTLETS_OF_COOKING).showConditioned(not5Shark).isNotConsumed(); stamPot = new ItemRequirement("Stamina potion (2)", ItemID._2DOSESTAMINA).showConditioned(notStamMix); caviar = new ItemRequirement("Caviar", ItemID.BRUT_CAVIAR).showConditioned(notStamMix); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinHard.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinHard.java index f7df8c3107..304f5709b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinHard.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinHard.java @@ -174,7 +174,7 @@ protected void setupRequirements() Conditions not70Agility = new Conditions(LogicType.NOR, new SkillRequirement(Skill.AGILITY, 70, true)); - dustyKey = new KeyringRequirement("Dusty Key", configManager, KeyringCollection.DUSTY_KEY).showConditioned(new Conditions(not70Agility, + dustyKey = new KeyringRequirement("Dusty Key", KeyringCollection.DUSTY_KEY).showConditioned(new Conditions(not70Agility, notWaterOrb)).isNotConsumed(); dustyKey.setTooltip("You can get this by killing the Jailer in the Black Knights Base in Taverley Dungeon and" + " using the key he drops to enter the jail cell there to talk to Velrak for the dusty key"); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinMedium.java index af183ee3e3..4954a50711 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kandarin/KandarinMedium.java @@ -55,11 +55,14 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarPlayerID; +import net.runelite.api.gameval.VarbitID; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; public class KandarinMedium extends ComplexStateQuestHelper { @@ -187,7 +190,7 @@ protected void setupRequirements() hornDust = new ItemRequirement("Horn Dust", ItemID.UNICORN_HORN_DUST, 1).showConditioned(notSuperAnti); vialOfWater = new ItemRequirement("Vial of water", ItemID.VIAL_WATER, 1).showConditioned(notSuperAnti); iritLeaf = new ItemRequirement("Irit leaf", ItemID.IRIT_LEAF, 1).showConditioned(notSuperAnti); - dustyKey = new KeyringRequirement("Dusty Key", configManager, KeyringCollection.DUSTY_KEY).showConditioned(new Conditions(not70Agility, + dustyKey = new KeyringRequirement("Dusty Key", KeyringCollection.DUSTY_KEY).showConditioned(new Conditions(not70Agility, notGrapOb)).isNotConsumed(); dustyKey.setTooltip("You can get this by killing the Jailer in the Black Knights Base in Taverley Dungeon and" + " using the key he drops to enter the jail cell there to talk to Velrak for the dusty key"); @@ -198,11 +201,12 @@ protected void setupRequirements() bowString = new ItemRequirement("Bow string", ItemID.BOW_STRING).showConditioned(notStringMaple); limpSeed = new ItemRequirement("Limpwurt seed", ItemID.LIMPWURT_SEED).showConditioned(notPickLimp); rake = new ItemRequirement("Rake", ItemID.RAKE).showConditioned(notPickLimp).isNotConsumed(); - seedDib = new ItemRequirement("Seed dibber", ItemID.DIBBER).showConditioned(notPickLimp).isNotConsumed(); + var needSeedDibber = not(new VarbitRequirement(VarbitID.BRUT_FARMING_PLANTING, 3)); + seedDib = new ItemRequirement("Seed dibber", ItemID.DIBBER).showConditioned(and(notPickLimp, needSeedDibber)).isNotConsumed(); primedMind = new ItemRequirement("Mind bar", ItemID.ELEM_MIND_BAR).showConditioned(notMindHelm); hammer = new ItemRequirement("Hammer", ItemID.HAMMER).showConditioned(notMindHelm).isNotConsumed(); beatenBook = new ItemRequirement("Beaten Book", ItemID.ELEMENTAL_WORKSHOP_HELM_BOOK).showConditioned(notMindHelm); - batteredKey = new KeyringRequirement("Battered Key", configManager, KeyringCollection.BATTERED_KEY).showConditioned(notMindHelm); + batteredKey = new KeyringRequirement("Battered Key", KeyringCollection.BATTERED_KEY).showConditioned(notMindHelm); batteredKey.setTooltip("You can get another by searching the bookcase in the house south of the Elemental " + "Workshop, then reading the book you get from it"); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaElite.java index 8dcecb3816..35c3f76957 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaElite.java @@ -206,18 +206,18 @@ public List getPanels() { List allSteps = new ArrayList<>(); - PanelDetails palmSteps = new PanelDetails("Check Palm Tree Health", Collections.singletonList(checkPalm), - new SkillRequirement(Skill.FARMING, 68, true), palmTreeSapling, rake, spade); - palmSteps.setDisplayCondition(notCheckedPalm); - palmSteps.setLockingStep(checkedPalmTask); - allSteps.add(palmSteps); - PanelDetails calquatSteps = new PanelDetails("Check Calquat Tree Health", Collections.singletonList(checkCalquat), farming72, calquatSapling, rake, spade); calquatSteps.setDisplayCondition(notCheckedCalquat); calquatSteps.setLockingStep(checkedCalquatTask); allSteps.add(calquatSteps); + PanelDetails palmSteps = new PanelDetails("Check Palm Tree Health", Collections.singletonList(checkPalm), + new SkillRequirement(Skill.FARMING, 68, true), palmTreeSapling, rake, spade); + palmSteps.setDisplayCondition(notCheckedPalm); + palmSteps.setLockingStep(checkedPalmTask); + allSteps.add(palmSteps); + PanelDetails equipCapeSteps = new PanelDetails("Equip Fire / Infernal Cape", Collections.singletonList(equipCape), fireCapeOrInfernal); equipCapeSteps.setDisplayCondition(notEquippedCape); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaMedium.java index 5326e82b35..5885eef185 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/karamja/KaramjaMedium.java @@ -73,7 +73,7 @@ public class KaramjaMedium extends BasicQuestHelper Requirement grandTree, taiBwoWannaiTrio, dragonSlayerI, shiloVillage, junglePotion; - QuestStep enterAgilityArena, tag2Pillars, enterVolcano, returnThroughWall, useCart, doCleanup, makeSpiderStick, cookSpider, + QuestStep enterAgilityArena, tagPillar, enterVolcano, returnThroughWall, useCart, doCleanup, makeSpiderStick, cookSpider, climbUpToBoat, travelToKhazard, cutTeak, cutMahogany, catchKarambwanji, catchKarambwan, getMachete, flyToKaramja, growFruitTree, trapGraahk, chopVines, crossLava, climbBrimhavenStaircase, charterFromShipyard, mineRedTopaz, enterCrandor, enterBrimDungeonVine, enterBrimDungeonLava, enterBrimDungeonStairs, claimReward; @@ -108,7 +108,7 @@ public Map loadSteps() doMedium.addStep(notEnteredCrandor, enteredCrandorTask); claimedTicketTask = new ConditionalStep(this, enterAgilityArena); - claimedTicketTask.addStep(inAgilityArena, tag2Pillars); + claimedTicketTask.addStep(inAgilityArena, tagPillar); doMedium.addStep(notClaimedTicket, claimedTicketTask); usedCartTask = new ConditionalStep(this, useCart); @@ -269,7 +269,7 @@ public void setupSteps() enterAgilityArena = new ObjectStep(this, ObjectID.AGILITYARENA_LADDERDOWN, new WorldPoint(2809, 3194, 0), "Pay Cap'n Izzy" + " No Beard 200 coins and enter the Agility Arena in Brimhaven.", coins.quantity(200)); - tag2Pillars = new DetailedQuestStep(this, "Tag 2 marked pillars in a row."); + tagPillar = new DetailedQuestStep(this, "Tag a marked pillar."); enterVolcano = new ObjectStep(this, ObjectID.VOLCANO_ENTRANCE, new WorldPoint(2857, 3169, 0), "Enter the Karamja Volcano."); returnThroughWall = new ObjectStep(this, ObjectID.DRAGONSECRETDOOR, new WorldPoint(2836, 9600, 0), "Return back through the shortcut."); @@ -289,9 +289,12 @@ public void setupSteps() travelToKhazard.addSubSteps(climbUpToBoat); cutTeak = new ObjectStep(this, ObjectID.TEAKTREE, new WorldPoint(2822, 3078, 0), "Chop a teak tree down either in" + " the Hardwood Grove in Tai Bwo Wannai or in the Kharazi Jungle (requires Legends' Quest started).", axe, tradingSticks.quantity(100)); + ((ObjectStep) cutTeak).addAlternateObjects(ObjectID.TEAKTREE_UPDATE); + cutTeak.addDialogStep("Okay, I'll pay 100 trading sticks to enter."); cutMahogany = new ObjectStep(this, ObjectID.MAHOGANYTREE, new WorldPoint(2820, 3080, 0), "Chop a mahogany tree " + "down either in the Hardwood Grove in Tai Bwo Wannai or in the Kharazi Jungle (requires Legends' Quest started).", axe, tradingSticks.quantity(100)); + cutMahogany.addDialogStep("Okay, I'll pay 100 trading sticks to enter."); catchKarambwanji = new NpcStep(this, NpcID._0_43_47_KARAMBWANJI, new WorldPoint(2791,3019,0), "Using your small fishing net, catch some raw karambwanji just south of Tai Bwo Wannai, or buy some from the GE.", smallFishingNet); catchKarambwan = new NpcStep(this, NpcID._0_45_48_KARAMBWAN, new WorldPoint(2899, 3119, 0), @@ -413,7 +416,7 @@ public List getPanels() allSteps.add(enteredCrandorSteps); PanelDetails enterAgiSteps = new PanelDetails("Claim a ticket in The Agility Arena", - Arrays.asList(enterAgilityArena, tag2Pillars), coins.quantity(200)); + Arrays.asList(enterAgilityArena, tagPillar), coins.quantity(200)); enterAgiSteps.setDisplayCondition(notClaimedTicket); enterAgiSteps.setLockingStep(claimedTicketTask); allSteps.add(enterAgiSteps); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendEasy.java index 53fed369b3..64669b1504 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendEasy.java @@ -43,7 +43,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendMedium.java index 901115012d..2bc2bca010 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/kourend/KourendMedium.java @@ -256,7 +256,7 @@ public void onGameTick(GameTick event) public void setupSteps() { // Travel to Fairy Ring - travelFairyRing = new ObjectStep(this, ObjectID.POH_FAIRY_RING, new WorldPoint(2658, 3230, 0), + travelFairyRing = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, new WorldPoint(2658, 3230, 0), "Travel from any fairy ring to south of Mount Karuulm (CIR).", dramenStaff.highlighted()); // Kill a lizardman diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeEasy.java index 5b15a57d47..6b380f2a13 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeEasy.java @@ -46,7 +46,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; @@ -289,7 +293,6 @@ public List getItemRecommended() public List getGeneralRequirements() { List reqs = new ArrayList<>(); - reqs.add(new SkillRequirement(Skill.AGILITY, 10, true)); reqs.add(new SkillRequirement(Skill.FIREMAKING, 15, true)); reqs.add(new SkillRequirement(Skill.FISHING, 15, true)); reqs.add(new SkillRequirement(Skill.MINING, 15, true)); @@ -332,8 +335,7 @@ public List getPanels() { List allSteps = new ArrayList<>(); - PanelDetails draynorRooftopsSteps = new PanelDetails("Draynor Rooftops", Collections.singletonList(drayAgi), - new SkillRequirement(Skill.AGILITY, 10, true)); + PanelDetails draynorRooftopsSteps = new PanelDetails("Draynor Rooftops", Collections.singletonList(drayAgi)); draynorRooftopsSteps.setDisplayCondition(notDrayAgi); draynorRooftopsSteps.setLockingStep(drayAgiTask); allSteps.add(draynorRooftopsSteps); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeElite.java index 20ddcfdeaf..6e50050029 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/lumbridgeanddraynor/LumbridgeElite.java @@ -49,7 +49,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaEasy.java index 8936535a4c..ad2e31c184 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaEasy.java @@ -29,6 +29,7 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.ComplexStateQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; +import net.runelite.client.plugins.microbot.questhelper.requirements.ComplexRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; @@ -291,15 +292,16 @@ public List getGeneralRequirements() if (questHelperPlugin.getPlayerStateManager().getAccountType().isAnyIronman()) { - // 47 Farming is required to get a Watermelon for the scarecrow step - reqs.add(new SkillRequirement(Skill.FARMING, 47, true)); + // 47 Farming or completion of Troubled Tortugans is required to get a Watermelon for the scarecrow step + reqs.add(new ComplexRequirement(LogicType.OR, "47 Farming OR Finished Troubled Tortugans for a watermelon", + new QuestRequirement(QuestHelperQuest.TROUBLED_TORTUGANS, QuestState.FINISHED), + new SkillRequirement(Skill.FARMING, 47, true))); } else { reqs.add(new SkillRequirement(Skill.FARMING, 23, true)); } - reqs.add(ghostsAhoy); reqs.add(natureSpirit); return reqs; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaElite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaElite.java index 0645bf64be..c723aed03f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaElite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaElite.java @@ -48,7 +48,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaMedium.java index 7e2fdc8a67..837d16db63 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/morytania/MorytaniaMedium.java @@ -172,7 +172,7 @@ protected void setupRequirements() steelBar = new ItemRequirement("Steel bar", ItemID.STEEL_BAR).showConditioned(notCannonBall); ammoMould = new ItemRequirement("Ammo mould", ItemID.AMMO_MOULD).showConditioned(notCannonBall).isNotConsumed(); ammoMould.addAlternates(ItemID.DOUBLE_AMMO_MOULD); - slayerGloves = new ItemRequirement("Slayer gloves", ItemID.SLAYERGUIDE_SLAYER_GLOVES).showConditioned(notFeverSpider).isNotConsumed(); + slayerGloves = new ItemRequirement("Slayer gloves", ItemID.DEAL_SLAYER_GLOVES).showConditioned(notFeverSpider).isNotConsumed(); ectophial = new ItemRequirement("Ectophial", ItemID.ECTOPHIAL).showConditioned(notEctophialTP).isNotConsumed(); restorePot = new ItemRequirement("Restore potion (4)", ItemID._4DOSESTATRESTORE).showConditioned(notGuthBalance); garlic = new ItemRequirement("Garlic", ItemID.GARLIC).showConditioned(notGuthBalance); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/varrock/VarrockMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/varrock/VarrockMedium.java index c7926e2955..fd66e8f4e9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/varrock/VarrockMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/varrock/VarrockMedium.java @@ -48,7 +48,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/westernprovinces/WesternMedium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/westernprovinces/WesternMedium.java index b87bae14cd..1dc7c98cb6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/westernprovinces/WesternMedium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/westernprovinces/WesternMedium.java @@ -55,6 +55,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; public class WesternMedium extends ComplexStateQuestHelper { @@ -136,8 +137,8 @@ public QuestStep loadStep() doMedium.addStep(notApeBass, apeBassTask); apeTeakTask = new ConditionalStep(this, moveToApeTeak); + apeTeakTask.addStep(and(inApeAtoll, teakLogs, choppedLogs), apeTeakBurn); apeTeakTask.addStep(inApeAtoll, apeTeakChop); - apeTeakTask.addStep(new Conditions(inApeAtoll, teakLogs, choppedLogs), apeTeakBurn); doMedium.addStep(notApeTeak, apeTeakTask); interPestTask = new ConditionalStep(this, moveToPest); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/wilderness/WildernessEasy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/wilderness/WildernessEasy.java index 13b83d76d8..2a139a97e8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/wilderness/WildernessEasy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/achievementdiaries/wilderness/WildernessEasy.java @@ -47,7 +47,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingConditionalStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingConditionalStep.java index acdae9c6d6..7bac94818e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingConditionalStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingConditionalStep.java @@ -36,7 +36,6 @@ import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; import net.runelite.api.Client; import net.runelite.api.coords.WorldPoint; - import java.util.Map; public class ChartingConditionalStep extends ReorderableConditionalStep diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingHelper.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingHelper.java index 4677c3d31c..d8f70bd858 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingHelper.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingHelper.java @@ -24,22 +24,32 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting; -import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; -import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.*; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingCaveTelescopeStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingCrateStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingCurrentStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingDivingStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingGenericObjectStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingPuzzleWrapStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingTaskStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingTelescopeStep; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.steps.ChartingWeatherStep; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.panel.TopLevelPanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.ComplexStateQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.questinfo.HelperConfig; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.StepIsActiveRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import net.runelite.client.plugins.microbot.questhelper.questinfo.HelperConfig; import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.api.gameval.VarbitID; - -import java.util.*; - +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; public class ChartingHelper extends ComplexStateQuestHelper diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingSeaSection.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingSeaSection.java index f8a3c231ab..914c86de2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingSeaSection.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingSeaSection.java @@ -25,7 +25,6 @@ package net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting; import lombok.Getter; - import java.util.List; @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTaskDefinition.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTaskDefinition.java index f9d1a59a7c..184d0d495c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTaskDefinition.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTaskDefinition.java @@ -24,10 +24,9 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import lombok.Getter; import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; - import java.util.ArrayList; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTasksData.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTasksData.java index 5d6779ea15..8797e96b5b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTasksData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/ChartingTasksData.java @@ -24,13 +24,12 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.VarbitID; +import java.util.List; import net.runelite.client.plugins.microbot.questhelper.requirements.sailing.BoatResistanceType; import net.runelite.client.plugins.microbot.questhelper.requirements.sailing.HasBoatResistanceRequirement; - -import java.util.List; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.coords.WorldPoint; // All data generated from the OSRS Wiki (https://oldschool.runescape.wiki/w/Sea_charting) public final class ChartingTasksData @@ -369,7 +368,7 @@ private ChartingTasksData() )), new ChartingSeaSection(27, "Mythic Sea", List.of( new ChartingTaskDefinition(ChartingType.CRATE, "Find a Sealed crate west of the Void Knights' Outpost and sample the contents.", new WorldPoint(2556, 2664, 0), "Shrouded Ocean", 12, VarbitID.SAILING_CHARTING_DRINK_CRATE_MYTHS_MIXER_COMPLETE, ItemID.SAILING_CHARTING_DRINK_CRATE_MYTHS_MIXER), - new ChartingTaskDefinition(ChartingType.GENERIC, "Find an abandoned camp on Anglers' Retreat. Watch out for Fetid waters!", new WorldPoint(2476, 2707, 0), "Shrouded Ocean", 1, VarbitID.SAILING_CHARTING_GENERIC_ABANDONED_CAMP_COMPLETE), + new ChartingTaskDefinition(ChartingType.GENERIC, "Find an abandoned camp on Anglers' Retreat. Watch out for Fetid waters!", new WorldPoint(2476, 2707, 0), "Shrouded Ocean", 51, VarbitID.SAILING_CHARTING_GENERIC_ABANDONED_CAMP_COMPLETE), new ChartingTaskDefinition(ChartingType.CURRENT, "Test the currents east of Anglers' Retreat. Watch out for Fetid waters!", new WorldPoint(2495, 2708, 0), new WorldPoint(2533, 2736, 0), "Shrouded Ocean", 40, VarbitID.SAILING_CHARTING_CURRENT_DUCK_MYTHIC_SEA_COMPLETE), new ChartingTaskDefinition(ChartingType.DIVING, "With help from a mermaid guide, document the water depth south of the Myths' Guild. Watch out for Fetid waters!", new WorldPoint(2446, 2784, 0), "Shrouded Ocean", 40, VarbitID.SAILING_CHARTING_MERMAID_GUIDE_MYTHIC_SEA_COMPLETE, "The answer is 'Cabbage', 'Onion', 'Tomato'.", List.of(ItemID.CABBAGE, ItemID.ONION, ItemID.TOMATO)) )), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCaveTelescopeStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCaveTelescopeStep.java index 2f66459c73..bed74d3936 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCaveTelescopeStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCaveTelescopeStep.java @@ -33,12 +33,12 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import lombok.Getter; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ObjectID; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCrateStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCrateStep.java index 2acbeaf141..a5c4aad951 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCrateStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCrateStep.java @@ -32,8 +32,9 @@ import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; public class ChartingCrateStep extends ChartingTaskObjectStep { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCurrentStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCurrentStep.java index d5d56dda2b..922868da90 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCurrentStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingCurrentStep.java @@ -28,13 +28,15 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; public class ChartingCurrentStep extends ChartingTaskObjectStep { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingGenericObjectStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingGenericObjectStep.java index 1ba16f7b9f..b545e6665d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingGenericObjectStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingGenericObjectStep.java @@ -27,8 +27,11 @@ import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.ChartingTaskDefinition; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.api.GameObject; import net.runelite.api.TileObject; +import net.runelite.api.gameval.ItemID; +import java.util.List; // This is a lazy implementation where we fully trust the location of the object to only have one thing to work public class ChartingGenericObjectStep extends ChartingTaskObjectStep diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingPuzzleWrapStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingPuzzleWrapStep.java index 98acdc3aa0..6cc8bde879 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingPuzzleWrapStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingPuzzleWrapStep.java @@ -33,7 +33,6 @@ import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.Skill; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; public class ChartingPuzzleWrapStep extends PuzzleWrapperStep implements ChartingTaskInterface diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskNpcStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskNpcStep.java index 0bf8cd55f7..947902f699 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskNpcStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskNpcStep.java @@ -33,9 +33,9 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import lombok.Getter; import net.runelite.api.Skill; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; @Getter public class ChartingTaskNpcStep extends NpcStep implements ChartingTaskInterface diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskObjectStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskObjectStep.java index 8af4bd4a3a..33bbbd5477 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskObjectStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskObjectStep.java @@ -33,7 +33,6 @@ import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import lombok.Getter; import net.runelite.api.Skill; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskStep.java index 03e2b5bf21..ed442ca034 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingTaskStep.java @@ -33,7 +33,6 @@ import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import lombok.Getter; import net.runelite.api.Skill; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingWeatherStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingWeatherStep.java index c8e77aa44c..7e977883af 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingWeatherStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/activities/charting/steps/ChartingWeatherStep.java @@ -33,6 +33,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import lombok.Getter; import net.runelite.api.Skill; import net.runelite.api.gameval.ItemID; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/alfredgrimhandsbarcrawl/AlfredGrimhandsBarcrawl.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/alfredgrimhandsbarcrawl/AlfredGrimhandsBarcrawl.java index 61100712b4..cf2ee0242f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/alfredgrimhandsbarcrawl/AlfredGrimhandsBarcrawl.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/alfredgrimhandsbarcrawl/AlfredGrimhandsBarcrawl.java @@ -24,13 +24,11 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.alfredgrimhandsbarcrawl; - import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.ComplexStateQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -40,59 +38,74 @@ import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.util.QHObjectID; +import java.util.ArrayList; +import java.util.List; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.VarPlayerID; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - public class AlfredGrimhandsBarcrawl extends ComplexStateQuestHelper { - //Items Required - ItemRequirement coins208, coins50, coins10, coins70, coins8, coins7, coins15, coins18, coins12, barcrawlCard; - - //Items Recommended - ItemRequirement gamesNecklace, varrockTeleport, faladorTeleport, glory, ardougneTeleport, camelotTeleport, - duelingRing; - - Requirement notTalkedToGuard, notTalkedToBlueMoon, notTalkedToJollyBoar, notTalkedToRisingSun, - notTalkedToRustyAnchor, - notTalkedToZambo, notTalkedToDeadMansChest, notTalkedToFlyingHorseInn, notTalkedToForestersArms, notTalkedToBlurberry, - notTalkedToDragonInn, inGrandTreeF1; - - QuestStep talkToGuardToGetCard, talkToBlueMoon, talkToJollyBoar, talkToRisingSun, talkToRustyAnchor, talkToZambo, - talkToDeadMansChest, talkToFlyingHorseInn, talkToForestersArms, goUpToBlurberry, talkToBlurberry, - talkToDragonInn, talkToGuardAgain; - - //Zones + // Required items + ItemRequirement coins208; + + // Recommended items + ItemRequirement gamesNecklace; + ItemRequirement varrockTeleport; + ItemRequirement lumberyardTeleport; + ItemRequirement faladorTeleport; + ItemRequirement glory; + ItemRequirement ardougneTeleport; + ItemRequirement camelotTeleport; + ItemRequirement duelingRing; + + // Mid-quest item requirements + ItemRequirement coins50; + ItemRequirement coins10; + ItemRequirement coins70; + ItemRequirement coins8; + ItemRequirement coins7; + ItemRequirement coins15; + ItemRequirement coins18; + ItemRequirement coins12; + ItemRequirement barcrawlCard; + + // Zones Zone grandTreeF1; - @Override - public QuestStep loadStep() - { - initializeRequirements(); - setupZones(); - setupConditions(); - setupSteps(); + // Miscellaneous requirements + VarplayerRequirement notTalkedToGuard; + VarplayerRequirement notTalkedToBlueMoon; + VarplayerRequirement notTalkedToJollyBoar; + VarplayerRequirement notTalkedToRisingSun; + VarplayerRequirement notTalkedToRustyAnchor; + VarplayerRequirement notTalkedToZambo; + VarplayerRequirement notTalkedToDeadMansChest; + VarplayerRequirement notTalkedToFlyingHorseInn; + VarplayerRequirement notTalkedToForestersArms; + VarplayerRequirement notTalkedToBlurberry; + VarplayerRequirement notTalkedToDragonInn; + ZoneRequirement inGrandTreeF1; + + // Steps + NpcStep talkToGuardToGetCard; + NpcStep talkToBlueMoon; + NpcStep talkToJollyBoar; + NpcStep talkToRisingSun; + NpcStep talkToRustyAnchor; + NpcStep talkToZambo; + NpcStep talkToDeadMansChest; + NpcStep talkToFlyingHorseInn; + NpcStep talkToForestersArms; + ObjectStep goUpToBlurberry; + NpcStep talkToBlurberry; + NpcStep talkToDragonInn; + NpcStep talkToGuardAgain; - ConditionalStep barcrawl = new ConditionalStep(this, talkToGuardAgain); - barcrawl.addStep(notTalkedToGuard, talkToGuardToGetCard); - barcrawl.addStep(notTalkedToBlueMoon, talkToBlueMoon); - barcrawl.addStep(notTalkedToJollyBoar, talkToJollyBoar); - barcrawl.addStep(notTalkedToRisingSun, talkToRisingSun); - barcrawl.addStep(notTalkedToRustyAnchor, talkToRustyAnchor); - barcrawl.addStep(notTalkedToZambo, talkToZambo); - barcrawl.addStep(notTalkedToDeadMansChest, talkToDeadMansChest); - barcrawl.addStep(notTalkedToFlyingHorseInn, talkToFlyingHorseInn); - barcrawl.addStep(notTalkedToForestersArms, talkToForestersArms); - barcrawl.addStep(new Conditions(notTalkedToBlurberry, inGrandTreeF1), talkToBlurberry); - barcrawl.addStep(notTalkedToBlurberry, goUpToBlurberry); - barcrawl.addStep(notTalkedToDragonInn, talkToDragonInn); - - return barcrawl; + public void setupZones() + { + grandTreeF1 = new Zone(new WorldPoint(2437, 3474, 1), new WorldPoint(2493, 3511, 1)); } @Override @@ -110,6 +123,8 @@ protected void setupRequirements() gamesNecklace = new ItemRequirement("Games necklace", ItemCollections.GAMES_NECKLACES); varrockTeleport = new ItemRequirement("Varrock teleport", ItemID.POH_TABLET_VARROCKTELEPORT); + lumberyardTeleport = new ItemRequirement("Lumberyard teleport", ItemID.TELEPORTSCROLL_LUMBERYARD); + lumberyardTeleport.addAlternates(ItemID.RING_OF_ELEMENTS_CHARGED); faladorTeleport = new ItemRequirement("Falador teleport", ItemID.POH_TABLET_FALADORTELEPORT); glory = new ItemRequirement("Amulet of Glory", ItemCollections.AMULET_OF_GLORIES).isNotConsumed(); ardougneTeleport = new ItemRequirement("Ardougne teleport", ItemID.POH_TABLET_ARDOUGNETELEPORT); @@ -118,15 +133,6 @@ protected void setupRequirements() barcrawlCard = new ItemRequirement("Barcrawl card", ItemID.BARCRAWL_CARD); barcrawlCard.setTooltip("If you've lost it you can get another from the Barbarian Guard"); - } - - public void setupZones() - { - grandTreeF1 = new Zone(new WorldPoint(2437, 3474, 1), new WorldPoint(2493, 3511, 1)); - } - - public void setupConditions() - { inGrandTreeF1 = new ZoneRequirement(grandTreeF1); notTalkedToGuard = new VarplayerRequirement(VarPlayerID.BARCRAWL, false, 0); @@ -144,65 +150,89 @@ public void setupConditions() public void setupSteps() { - talkToGuardToGetCard = new NpcStep(this, NpcID.BARBGUARD1_PRECRAWL, new WorldPoint(2544, 3568, 0), - "Talk to a barbarian guard outside the Barbarian Agility Course."); - talkToGuardToGetCard.addDialogSteps("I want to come through this gate.", - "Looks can be deceiving, I am in fact a barbarian."); - + talkToGuardToGetCard = new NpcStep(this, NpcID.BARBGUARD1_PRECRAWL, new WorldPoint(2544, 3568, 0), "Talk to a barbarian guard outside the Barbarian Agility Course at the Barbarian Outpost to learn about Alfred Grimhand's Barcrawl."); + talkToGuardToGetCard.addDialogSteps("I want to come through this gate.", "Looks can be deceiving, I am in fact a barbarian."); - talkToBlueMoon = new NpcStep(this, NpcID.BLUEMOON_BARTENDER, new WorldPoint(3226, 3399, 0), - "Talk to the bartender in the Blue Moon Inn in Varrock.", coins50); + talkToBlueMoon = new NpcStep(this, NpcID.BLUEMOON_BARTENDER, new WorldPoint(3226, 3399, 0), "Talk to the bartender in the Blue Moon Inn in Varrock.", coins50); talkToBlueMoon.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - talkToJollyBoar = new NpcStep(this, NpcID.JOLLYBOAR_BARTENDER, new WorldPoint(3279, 3488, 0), - "Talk to the bartender in the Jolly Boar Inn north east of Varrock.", coins10); + talkToJollyBoar = new NpcStep(this, NpcID.JOLLYBOAR_BARTENDER, new WorldPoint(3279, 3488, 0), "Talk to the bartender in the Jolly Boar Inn north east of Varrock.", coins10); + talkToJollyBoar.addTeleport(lumberyardTeleport); talkToJollyBoar.addDialogStep("I'm doing Alfred Grimhands Barcrawl."); - talkToRisingSun = new NpcStep(this, NpcID.RISINGSUN_BARMAID2, new WorldPoint(2956, 3370, 0), - "Talk to a bartender in the Rising Sun Inn in Falador.", true, coins70); + talkToRisingSun = new NpcStep(this, NpcID.RISINGSUN_BARMAID2, new WorldPoint(2956, 3370, 0), "Talk to a bartender in the Rising Sun Inn in Falador.", true, coins70); talkToRisingSun.addDialogStep("I'm doing Alfred Grimhand's barcrawl."); - ((NpcStep) talkToRisingSun).addAlternateNpcs(NpcID.RISINGSUN_BARMAID, NpcID.RISINGSUN_BARMAID3); + talkToRisingSun.addAlternateNpcs(NpcID.RISINGSUN_BARMAID, NpcID.RISINGSUN_BARMAID3); - talkToRustyAnchor = new NpcStep(this, NpcID.RUSTYANCHOR_BARTENDER, new WorldPoint(3046, 3257, 0), - "Talk to the bartender in the Rusty Anchor in Port Sarim.", coins8); + talkToRustyAnchor = new NpcStep(this, NpcID.RUSTYANCHOR_BARTENDER, new WorldPoint(3046, 3257, 0), "Talk to the bartender in the Rusty Anchor in Port Sarim.", coins8); talkToRustyAnchor.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - talkToZambo = new NpcStep(this, NpcID.ZEMBO, new WorldPoint(2927, 3144, 0), - "Talk to Zembo in the Karamja Spirits Bar on Musa Point.", coins7); + + talkToZambo = new NpcStep(this, NpcID.ZEMBO, new WorldPoint(2927, 3144, 0), "Talk to Zembo in the Karamja Spirits Bar on Musa Point.", coins7); talkToZambo.addDialogStep("I'm doing Alfred Grimhand's barcrawl."); - talkToDeadMansChest = new NpcStep(this, NpcID.DEADMANS_BARTENDER, new WorldPoint(2796, 3156, 0), - "Talk to the bartender in the Dead Man's Chest in Brimhaven.", coins15); + + talkToDeadMansChest = new NpcStep(this, NpcID.DEADMANS_BARTENDER, new WorldPoint(2796, 3156, 0), "Talk to the bartender in the Dead Man's Chest in Brimhaven.", coins15); talkToDeadMansChest.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - talkToFlyingHorseInn = new NpcStep(this, NpcID.FLYINGHORSE_BARTENDER, new WorldPoint(2574, 3323, 0), - "Talk to the bartender in the Flying Horse Inn in Ardougne.", coins8); + + talkToFlyingHorseInn = new NpcStep(this, NpcID.FLYINGHORSE_BARTENDER, new WorldPoint(2574, 3323, 0), "Talk to the bartender in the Flying Horse Inn in Ardougne.", coins8); talkToFlyingHorseInn.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - talkToForestersArms = new NpcStep(this, NpcID.FORESTERS_BARTENDER, new WorldPoint(2690, 3494, 0), - "Talk to the bartender in the Forester's Arms in Seers' Village.", coins18); + + talkToForestersArms = new NpcStep(this, NpcID.FORESTERS_BARTENDER, new WorldPoint(2690, 3494, 0), "Talk to the bartender in the Forester's Arms in Seers' Village.", coins18); talkToForestersArms.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - goUpToBlurberry = new ObjectStep(this, QHObjectID.GRAND_TREE_F0_LADDER, new WorldPoint(2466, 3495, 0), - "Talk to Blurberry in the Grand Tree.", coins10); - talkToBlurberry = new NpcStep(this, NpcID.BLURBERRY, new WorldPoint(2482, 3491, 1), - "Talk to Blurberry in the Grand Tree.", coins10); + goUpToBlurberry = new ObjectStep(this, QHObjectID.GRAND_TREE_F0_LADDER, new WorldPoint(2466, 3495, 0), "Talk to Blurberry in the Grand Tree.", coins10); + talkToBlurberry = new NpcStep(this, NpcID.BLURBERRY, new WorldPoint(2482, 3491, 1), "Talk to Blurberry in the Grand Tree.", coins10); talkToBlurberry.addSubSteps(goUpToBlurberry); - talkToDragonInn = new NpcStep(this, NpcID.DRAGON_BARTENDER, new WorldPoint(2556, 3079, 0), - "Talk to the bartender in Dragon Inn in Yanille.", coins12); + + talkToDragonInn = new NpcStep(this, NpcID.DRAGON_BARTENDER, new WorldPoint(2556, 3079, 0), "Talk to the bartender in Dragon Inn in Yanille.", coins12); talkToDragonInn.addDialogStep("I'm doing Alfred Grimhand's Barcrawl."); - talkToGuardAgain = new NpcStep(this, NpcID.BARBGUARD1_PRECRAWL, new WorldPoint(2544, 3568, 0), - "Return to the barbarian guards outside the Barbarian Agility Course."); + talkToGuardAgain = new NpcStep(this, NpcID.BARBGUARD1_PRECRAWL, new WorldPoint(2544, 3568, 0), "Return to the barbarian guards outside the Barbarian Agility Course."); + } + + @Override + public QuestStep loadStep() + { + initializeRequirements(); + setupSteps(); + + var barcrawl = new ConditionalStep(this, talkToGuardAgain); + barcrawl.addStep(notTalkedToGuard, talkToGuardToGetCard); + barcrawl.addStep(notTalkedToBlueMoon, talkToBlueMoon); + barcrawl.addStep(notTalkedToJollyBoar, talkToJollyBoar); + barcrawl.addStep(notTalkedToRisingSun, talkToRisingSun); + barcrawl.addStep(notTalkedToRustyAnchor, talkToRustyAnchor); + barcrawl.addStep(notTalkedToZambo, talkToZambo); + barcrawl.addStep(notTalkedToDeadMansChest, talkToDeadMansChest); + barcrawl.addStep(notTalkedToFlyingHorseInn, talkToFlyingHorseInn); + barcrawl.addStep(notTalkedToForestersArms, talkToForestersArms); + barcrawl.addStep(and(notTalkedToBlurberry, inGrandTreeF1), talkToBlurberry); + barcrawl.addStep(notTalkedToBlurberry, goUpToBlurberry); + barcrawl.addStep(notTalkedToDragonInn, talkToDragonInn); + + return barcrawl; } @Override public List getItemRequirements() { - return List.of(coins208); + return List.of( + coins208 + ); } @Override public List getItemRecommended() { - return List.of(gamesNecklace, varrockTeleport, faladorTeleport, glory, ardougneTeleport, - camelotTeleport, duelingRing); + return List.of( + gamesNecklace, + varrockTeleport, + lumberyardTeleport, + faladorTeleport, + glory, + ardougneTeleport, + camelotTeleport, + duelingRing + ); } @Override @@ -217,14 +247,29 @@ public List getUnlockRewards() @Override public ArrayList getPanels() { - var allSteps = new ArrayList(); - - allSteps.add(new PanelDetails("Getting started", List.of(talkToGuardToGetCard))); - - allSteps.add(new PanelDetails("Drinking", Arrays.asList(talkToBlueMoon, talkToJollyBoar, talkToRisingSun, - talkToRustyAnchor, talkToZambo, talkToDeadMansChest, talkToFlyingHorseInn, talkToForestersArms, talkToBlurberry, - talkToDragonInn, talkToGuardAgain), barcrawlCard, coins208)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Getting started", List.of( + talkToGuardToGetCard + ))); + + sections.add(new PanelDetails("Drinking", List.of( + talkToBlueMoon, + talkToJollyBoar, + talkToRisingSun, + talkToRustyAnchor, + talkToZambo, + talkToDeadMansChest, + talkToFlyingHorseInn, + talkToForestersArms, + talkToBlurberry, + talkToDragonInn, + talkToGuardAgain + ), List.of( + barcrawlCard, + coins208 + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/barbariantraining/BarbarianTraining.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/barbariantraining/BarbarianTraining.java index 0179424eb5..e41e977228 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/barbariantraining/BarbarianTraining.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/barbariantraining/BarbarianTraining.java @@ -26,33 +26,26 @@ import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; -import net.runelite.client.plugins.microbot.questhelper.config.ConfigKeys; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; -import net.runelite.client.plugins.microbot.questhelper.requirements.ChatMessageRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.MesBoxRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.MultiChatMessageRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; -import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; import java.util.*; @@ -61,49 +54,143 @@ public class BarbarianTraining extends BasicQuestHelper { // Items Required - ItemRequirement barbFishingRod, tinderbox, bow, knife, fish, combatGear, antifireShield, chewedBones, bronzeBar, logs, hammer, - roe, attackPotion, sapling, seed, spade, oakLogs, axe, feathers, barbarianAttackPotion; + ItemRequirement barbFishingRod; + ItemRequirement tinderbox; + ItemRequirement bow; + ItemRequirement knife; + ItemRequirement fish; + ItemRequirement combatGear; + ItemRequirement antifireShield; + ItemRequirement chewedBones; + ItemRequirement bronzeBar; + ItemRequirement logs; + ItemRequirement hammer; + ItemRequirement roe; + ItemRequirement attackPotion; + ItemRequirement sapling; + ItemRequirement seed; + ItemRequirement spade; + ItemRequirement oakLogs; + ItemRequirement axe; + ItemRequirement feathers; + ItemRequirement barbarianAttackPotion; // Items recommended - ItemRequirement gamesNecklace, catherbyTeleport; - - Requirement fishing48, agility15, strength15, fishing55, strength35, firemaking35, crafting11, farming15, smithing5; - - QuestRequirement druidicRitual, taiBwoWannaiTrio; - - Requirement taskedWithFishing, taskedWithHarpooning, taskedWithFarming, taskedWithBowFiremaking, taskedWithPyre, taskedWithPotSmashing, - taskedWithSpears, taskedWithHastae, taskedWithHerblore; + ItemRequirement gamesNecklace; + ItemRequirement catherbyTeleport; + + Requirement fishing48; + Requirement agility15; + Requirement strength15; + Requirement fishing55; + Requirement strength35; + Requirement firemaking35; + Requirement crafting11; + Requirement farming15; + Requirement smithing5; + + QuestRequirement druidicRitual; + QuestRequirement taiBwoWannaiTrio; Requirement chewedBonesNearby; - Requirement plantedSeed, smashedPot, litFireWithBow, sacrificedRemains, caughtBarbarianFish, - caughtFishWithoutHarpoon, madePotion, madeSpear, madeHasta; - - DetailedQuestStep talkToOttoAboutFishing, searchBed, catchFish, talkToOttoAfterFish; - - DetailedQuestStep talkToOttoAboutBarehanded, fishHarpoon, talkToOttoAfterHarpoon; - - DetailedQuestStep talkToOttoAboutBow, lightLogWithBow, talkToOttoAfterBow; - - DetailedQuestStep talkToOttoAboutPyre, enterWhirlpool, goDownToBrutalGreen, goUpToMithrilDragons, killMithrilDragons, - pickupChewedBones, useLogOnPyre, talkToOttoAfterPyre; - - DetailedQuestStep talkToOttoAboutFarming, plantSeed, talkToOttoAfterPlantingSeed; - - DetailedQuestStep talkToOttoAboutPots, plantSapling, talkToOttoAfterSmashingPot; - - DetailedQuestStep talkToOttoAboutSpears, makeBronzeSpear, talkToOttoAfterBronzeSpear, talkToOttoAboutHastae, makeBronzeHasta, talkToOttoAfterMakingHasta; - - DetailedQuestStep talkToOttoAboutHerblore, getBarbRodForHerblore, fishForHerblore, dissectFish, useRoeOnAttackPotion, talkToOttoAfterPotion; - - ConditionalStep fishingSteps, harpoonSteps, seedSteps, potSmashingSteps, firemakingSteps, pyreSteps, spearSteps, - spearAndHastaeSteps, herbloreSteps; - - Requirement finishedFishing, finishedHarpoon, finishedSeedPlanting, finishedPotSmashing, finishedFiremaking, finishedPyre, finishedSpear, finishedHasta, finishedHerblore; - - Zone ancientCavernF0, ancientCavernF1, ancientCavernArrivalRoom; - - ZoneRequirement inAncientCavernF0, inAncientCavernF1, inAncientCavernArrivalRoom; + DetailedQuestStep talkToOttoAboutFishing; + DetailedQuestStep searchBed; + DetailedQuestStep catchFish; + DetailedQuestStep talkToOttoAfterFish; + + DetailedQuestStep talkToOttoAboutBarehanded; + DetailedQuestStep fishHarpoon; + DetailedQuestStep talkToOttoAfterHarpoon; + + DetailedQuestStep talkToOttoAboutBow; + DetailedQuestStep lightLogWithBow; + DetailedQuestStep talkToOttoAfterBow; + + DetailedQuestStep talkToOttoAboutPyre; + DetailedQuestStep enterWhirlpool; + DetailedQuestStep goDownToBrutalGreen; + DetailedQuestStep goUpToMithrilDragons; + DetailedQuestStep killMithrilDragons; + DetailedQuestStep pickupChewedBones; + DetailedQuestStep useLogOnPyre; + DetailedQuestStep talkToOttoAfterPyre; + + DetailedQuestStep talkToOttoAboutFarming; + DetailedQuestStep plantSeed; + DetailedQuestStep talkToOttoAfterPlantingSeed; + + DetailedQuestStep talkToOttoAboutPots; + DetailedQuestStep plantSapling; + DetailedQuestStep talkToOttoAfterSmashingPot; + + DetailedQuestStep talkToOttoAboutSpears; + DetailedQuestStep makeBronzeSpear; + DetailedQuestStep talkToOttoAfterBronzeSpear; + DetailedQuestStep talkToOttoAboutHastae; + DetailedQuestStep makeBronzeHasta; + DetailedQuestStep talkToOttoAfterMakingHasta; + + DetailedQuestStep talkToOttoAboutHerblore; + DetailedQuestStep getBarbRodForHerblore; + DetailedQuestStep fishForHerblore; + DetailedQuestStep dissectFish; + DetailedQuestStep useRoeOnAttackPotion; + DetailedQuestStep talkToOttoAfterPotion; + + ConditionalStep fishingSteps; + ConditionalStep harpoonSteps; + ConditionalStep seedSteps; + ConditionalStep potSmashingSteps; + ConditionalStep firemakingSteps; + ConditionalStep pyreSteps; + ConditionalStep spearSteps; + ConditionalStep spearAndHastaeSteps; + ConditionalStep herbloreSteps; + + Zone ancientCavernF0; + Zone ancientCavernF1; + Zone ancientCavernArrivalRoom; + + ZoneRequirement inAncientCavernF0; + ZoneRequirement inAncientCavernF1; + ZoneRequirement inAncientCavernArrivalRoom; + + VarbitRequirement taskedWithFishing; + VarbitRequirement caughtBarbarianFish; + VarbitRequirement finishedFishing; + + VarbitRequirement taskedWithHerblore; + VarbitRequirement madePotion; + VarbitRequirement finishedHerblore; + + VarbitRequirement taskedWithHarpooning; + VarbitRequirement caughtFishWithoutHarpoon; + VarbitRequirement finishedHarpoon; + + VarbitRequirement taskedWithFarming; + VarbitRequirement plantedSeed; + VarbitRequirement finishedSeedPlanting; + + VarbitRequirement taskedWithPotSmashing; + VarbitRequirement smashedPot; + VarbitRequirement finishedPotSmashing; + + VarbitRequirement taskedWithBowFiremaking; + VarbitRequirement litFireWithBow; + VarbitRequirement finishedFiremaking; + + VarbitRequirement taskedWithSpears; + VarbitRequirement madeSpear; + VarbitRequirement finishedSpear; + + VarbitRequirement taskedWithHastae; + VarbitRequirement madeHasta; + VarbitRequirement finishedHasta; + + VarbitRequirement taskedWithPyre; + VarbitRequirement sacrificedRemains; + VarbitRequirement finishedPyre; @Override public Map loadSteps() @@ -189,13 +276,10 @@ public Map loadSteps() allSteps.addDialogSteps("Let's talk about my training.", "I seek more knowledge."); allSteps.setCheckAllChildStepsOnListenerCall(true); - - // Started, 9613 + // Controlled by VarbitID.BRUT_MINIQUEST, specifying the number of miniquests completed steps.put(0, allSteps); steps.put(1, allSteps); - // Increments after doing a task steps.put(2, allSteps); - // 9610, 0->1 at some point??? Probably for pot smashing, or for whirlpool? steps.put(3, allSteps); steps.put(4, allSteps); steps.put(5, allSteps); @@ -259,281 +343,64 @@ public void setupRequirements() crafting11 = new SkillRequirement(Skill.CRAFTING, 11); farming15 = new SkillRequirement(Skill.FARMING, 15, true); smithing5 = new SkillRequirement(Skill.SMITHING, 5, true); + + var barbFishing = new VarbitBuilder(VarbitID.BRUT_FISHING_R); + taskedWithFishing = barbFishing.eq(1); + caughtBarbarianFish = barbFishing.eq(2); + finishedFishing = barbFishing.eq(3); + finishedFishing.setDisplayText("Finished Barbarian Fishing"); + + var barbHerblore = new VarbitBuilder(VarbitID.BRUT_HERB_POTION); + taskedWithHerblore = barbHerblore.eq(1); + madePotion = barbHerblore.eq(2); + finishedHerblore = barbHerblore.eq(3); + finishedHerblore.setDisplayText("Finished Barbarian Herblore"); + + var barbHarpooning = new VarbitBuilder(VarbitID.BRUT_FISHING_S); + taskedWithHarpooning = barbHarpooning.eq(1); + caughtFishWithoutHarpoon = barbHarpooning.eq(2); + finishedHarpoon = barbHarpooning.eq(3); + finishedHarpoon.setDisplayText("Finished Barbarian Harpooning"); + + var barbPlanting = new VarbitBuilder(VarbitID.BRUT_FARMING_PLANTING); + taskedWithFarming = barbPlanting.eq(1); + plantedSeed = barbPlanting.eq(2); + finishedSeedPlanting = barbPlanting.eq(3); + finishedSeedPlanting.setDisplayText("Finished Barbarian Planting"); + + var barbPotSmashing = new VarbitBuilder(VarbitID.BRUT_FARMING_SMASHING); + taskedWithPotSmashing = barbPotSmashing.eq(1); + smashedPot = barbPotSmashing.eq(2); + finishedPotSmashing = barbPotSmashing.eq(3); + finishedPotSmashing.setDisplayText("Finished Barbarian Pot Smashing"); + + var barbFiremaking = new VarbitBuilder(VarbitID.BRUT_FIRE); + taskedWithBowFiremaking = barbFiremaking.eq(1); + litFireWithBow = barbFiremaking.eq(2); + finishedFiremaking = barbFiremaking.eq(3); + finishedFiremaking.setDisplayText("Finished Barbarian Firemaking"); + + var barbSpear = new VarbitBuilder(VarbitID.BRUT_SMITH_SPEAR); + taskedWithSpears = barbSpear.eq(1); + madeSpear = barbSpear.eq(2); + finishedSpear = barbSpear.eq(3); + finishedSpear.setDisplayText("Finished Barbarian Spear Smithing"); + + var barbHasta = new VarbitBuilder(VarbitID.BRUT_SMITH_HASTA); + taskedWithHastae = barbHasta.eq(1); + madeHasta = barbHasta.eq(2); + finishedHasta = barbHasta.eq(3); + finishedHasta.setDisplayText("Finished Barbarian Hastae Smithing"); + + var barbPyre = new VarbitBuilder(VarbitID.BRUT_CRAFT_SHIP); + taskedWithPyre = barbPyre.eq(1); + sacrificedRemains = barbPyre.eq(2); + finishedPyre = barbPyre.eq(3); + finishedPyre.setDisplayText("Finished Barbarian Pyremaking"); } public void setupConditions() { - // Started tasks - - taskedWithFishing = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_FISHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Certainly. Take the rod from under my bed and fish in the lake. When you have caught a few fish, I am sure you will be ready to talk more with me."), - new DialogRequirement("Alas, I do not sense that you have been successful in your fishing yet. The look in your eyes is not that of the osprey."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "fish with a new") - ) - ); - - taskedWithHarpooning = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_HARPOON.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("... and I thought fishing was a safe way to pass the time."), - new DialogRequirement("I see you need encouragement in learning the ways of fishing without a harpoon."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "fish with my") - ) - ); - - taskedWithFarming = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_SEED_PLANTING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Remember to be calm, and good luck."), - new DialogRequirement("I see you have yet to be successful in planting a seed with your fists."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "plant a seed with") - ) - ); - - taskedWithPotSmashing = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_POT_SMASHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("May the spirits guide you into success."), - new DialogRequirement("You have not yet attempted to plant a tree. Why not?"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to smash pots after") - ) - ); - - taskedWithBowFiremaking = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_FIREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("The spirits will aid you. The power they supply will guide your hands. Go and benefit from their guidance upon oak logs."), - new DialogRequirement("By now you know my response."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "light a fire with") - ) - ); - - taskedWithPyre = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_PYREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Dive into the whirlpool in the lake to the east. The spirits will use their abilities to ensure you arrive in the correct location. Be warned, their influence fades, so you must find y"), - new DialogRequirement("I will repeat myself fully, since this is quite complex. Listen well."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to create pyre ships") - ) - ); - - taskedWithHerblore = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_HERBLORE.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Have I become so predictable? But yes, I do indeed require a potion. It is of the highest importance that you bring me a lesser attack potion combined with fish roe."), - new DialogRequirement("Do you have my potion?"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to make a new type") - ) - ); - - taskedWithSpears = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Note well that you will require wood for the spear shafts. The quality of wood must be similar to that of the metal involved."), - new DialogRequirement("You do not exude the presence of one who has poured his soul into manufacturing spears."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to smith spears") - ) - ); - - taskedWithHastae = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_STARTED_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Indeed. You may use our special anvil for this spear type too. The ways of black and dragon hastae are beyond our knowledge, however."), - new DialogRequirement("Take some wood and metal and make a spear upon the
nearby anvil, then you may return to me. As an
example, you may use bronze bars with normal logs or
iron bars with oak logs."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, " has tasked me with learning how to smith a hasta") - ) - ); - - // Finished tasks - finishedFishing = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_FISHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Patience young one. These are fish which are fat with eggs rather than fat of flesh. It is these eggs that are the thing to make use of."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to catch a fish with the new rod!") - ), - "Finished Barbarian Fishing" - ); - - finishedHarpoon = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_HARPOON.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("I mean that when you eventually die and find peace, at least the spirits you encounter will be your friends. Alas for you adventurous sort, the natural ways of passing are close to imp"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to fish with my hands!") - ), - "Finished Barbarian Harpooning" - ); - - finishedSeedPlanting = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_SEED_PLANTING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("No child, but we all have potential to improve our strength."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to plant a seed with my fists!") - ), - "Finished Barbarian Seed Planting" - ); - - finishedPotSmashing = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_POT_SMASHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("It will become more natural with practice."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to smash a plant pot without littering!") - ), - "Finished Barbarian Pot Smashing" - ); - - finishedFiremaking = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_FIREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Fine news indeed!"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to light a fire with a bow!") - ), - "Finished Barbarian Firemaking" - ); - - finishedPyre = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_PYREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("On this great day you have my eternal thanks. May you find riches while rescuing my spiritual ancestors in the caverns for many moons to come."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a pyre ship!") - ), - "Finished Barbarian Pyremaking" - ); - - finishedSpear = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("The manufacture of spears is now yours as a speciality. Use your skill well."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to smith a spear!") - ), - "Finished Barbarian Spear Smithing" - ); - - finishedHasta = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("To live life to it's fullest of course - that you may be a peaceful spirit when your time ends."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a hasta!") - ), - "Finished Barbarian Hasta Smithing" - ); - - finishedHerblore = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_FINISHED_HERBLORE.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("I will take that off your hands now. I will say no more than that I am eternally grateful."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a new potion!") - ), - "Finished Barbarian Herblore" - ); - - // Mid-conditions - plantedSeed = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_PLANTED_SEED.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You plant "), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to plant a seed with my fists!") - ) - ); - - smashedPot = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_SMASHED_POT.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You plant "), - new ChatMessageRequirement(" sapling"), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smash a pot without littering!") - ) - ); - - litFireWithBow = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_BOW_FIRE.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("The fire catches and the logs begin to burn."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to light a fire with a bow!") - ) - ); - - sacrificedRemains = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_PYRE_MADE.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("The ancient barbarian is laid to rest."), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to create a pyre ship! I should let") - ) - ); - - caughtBarbarianFish = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_BARBFISHED.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You catch a leaping trout.", "You catch a leaping salmon.", "You catch a leaping sturgeon."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to catch a fish with the new rod! I should let") - ) - ); - - caughtFishWithoutHarpoon = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_HARPOONED_FISH.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You catch a raw tuna.", "You catch a swordfish.", "You catch a shark.", "You catch a shark!"), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to fish with my hands! I should let Otto know") - ) - ); - - madePotion = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_MADE_POTION.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You combine your potion with the fish eggs."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to make a new type of potion! I should let") - ) - ); - - madeSpear = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_MADE_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You make a "), - new ChatMessageRequirement(" spear."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smith a spear!") - ) - ); - - madeHasta = new RuneliteRequirement( - getConfigManager(), ConfigKeys.BARBARIAN_TRAINING_MADE_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You make a "), - new ChatMessageRequirement(" hasta."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smith a hasta!") - ) - ); - - // For harpooning, - // You catch a tuna. - ancientCavernArrivalRoom = new Zone(new WorldPoint(1762, 5364, 1), new WorldPoint(1769, 5359, 1)); ancientCavernF0 = new Zone(new WorldPoint(1734, 5318, 0), new WorldPoint(1800, 5400, 0)); ancientCavernF1 = new Zone(new WorldPoint(1734, 5318, 1), new WorldPoint(1800, 5400, 1)); @@ -593,9 +460,9 @@ public void setupSteps() pickupChewedBones = new ItemStep(this, "Pick up the chewed bones.", chewedBones); useLogOnPyre = new ObjectStep(this, ObjectID.BRUT_BURNED_GROUND, new WorldPoint(2506, 3518, 0), "Construct a pyre on the lake near Otto.", logs, chewedBones, tinderbox, axe); - useLogOnPyre.addDialogStep("I've created a pyre ship!"); talkToOttoAfterPyre = new NpcStep(this, NpcID.BRUT_OTTO, new WorldPoint(2500, 3488, 0), "Return to Otto and tell him about the succesful pyre-making."); + talkToOttoAfterPyre.addDialogStep("I've created a pyre ship!"); // Barbarian Farming talkToOttoAboutFarming = new NpcStep(this, NpcID.BRUT_OTTO, new WorldPoint(2500, 3488, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/daddyshome/DaddysHome.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/daddyshome/DaddysHome.java index 8214a77b8a..e5f22510d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/daddyshome/DaddysHome.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/daddyshome/DaddysHome.java @@ -29,6 +29,8 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; @@ -38,17 +40,17 @@ import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; public class DaddysHome extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKey.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKey.java index fc8e5808d2..6e49d97982 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKey.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKey.java @@ -70,7 +70,7 @@ public Map loadSteps() protected void setupRequirements() { spade = new ItemRequirement("Spade", ItemID.SPADE).isNotConsumed(); - key = new KeyringRequirement("Enchanted key", configManager, KeyringCollection.ENCHANTED_KEY); + key = new KeyringRequirement("Enchanted key", KeyringCollection.ENCHANTED_KEY); varrockTeleports = new ItemRequirement("Varrock teleports", ItemID.POH_TABLET_VARROCKTELEPORT); ardougneTeleports = new ItemRequirement("Ardougne teleports", ItemID.POH_TABLET_ARDOUGNETELEPORT); rellekkaTeleports = new ItemRequirement("Rellekka teleport", ItemID.NZONE_TELETAB_RELLEKKA); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKeyDigStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKeyDigStep.java index 3e6bd6e3b8..72b02d328f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKeyDigStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/enchantedkey/EnchantedKeyDigStep.java @@ -42,7 +42,6 @@ import net.runelite.api.gameval.VarbitID; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @@ -185,7 +184,7 @@ public boolean update(final String message) return false; } - final WorldPoint localWorld = Rs2Player.getWorldLocation(); + final WorldPoint localWorld = player.getWorldLocation(); if (localWorld == null) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/lairoftarnrazorlor/TarnRoute.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/lairoftarnrazorlor/TarnRoute.java index d145cc52d6..98e3576b6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/lairoftarnrazorlor/TarnRoute.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/lairoftarnrazorlor/TarnRoute.java @@ -43,7 +43,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.Prayer; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; import java.util.Arrays; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenai/TheMageArenaI.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenai/TheMageArenaI.java index fc1f5000a7..35303c6638 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenai/TheMageArenaI.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenai/TheMageArenaI.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.themagearenai; +import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; @@ -86,7 +87,7 @@ protected void setupRequirements() { runesForCasts = new ItemRequirement("Runes for fighting Kolodion", -1, -1); runesForCasts.setDisplayItemId(ItemID.DEATHRUNE); - knife = new ItemRequirement("Knife or sharp weapon to cut through a web", ItemID.KNIFE).isNotConsumed(); + knife = new ItemRequirement("Knife or sharp weapon to cut through a web", ItemCollections.SLASH_WEB_KNIFE).isNotConsumed(); godCape = new ItemRequirement("God cape", ItemID.ZAMORAK_CAPE).isNotConsumed(); godCape.addAlternates(ItemID.GUTHIX_CAPE, ItemID.SARADOMIN_CAPE); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MA2Locator.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MA2Locator.java index 320158b135..c9585dbe4f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MA2Locator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MA2Locator.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.themagearenaii; +import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; @@ -38,7 +39,9 @@ import net.runelite.api.QuestState; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; +import net.runelite.client.ui.overlay.components.PanelComponent; +import java.awt.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -46,10 +49,10 @@ public class MA2Locator extends ComplexStateQuestHelper { - ItemRequirement zamorakStaff, guthixStaff, saradominStaff, runesForCasts, magicCombatGear, knife, brews, restores + ItemRequirement zamorakStaff, guthixStaff, saradominStaff, godStaff, runesForCasts, magicCombatGear, knife, brews, restores , food, recoils, enchantedSymbol, justicarsHand, demonsHeart, entRoots, godCape; - QuestStep locateFollowerSara; + QuestStep locateFollowers; Zone cavern; @@ -59,7 +62,7 @@ public QuestStep loadStep() initializeRequirements(); setupSteps(); - return locateFollowerSara; + return locateFollowers; } @Override @@ -71,6 +74,11 @@ protected void setupRequirements() guthixStaff.setTooltip("You can buy one from the Chamber Guardian in the Mage Arena Cavern for 80k"); saradominStaff = new ItemRequirement("Saradomin staff", ItemID.SARADOMIN_STAFF); saradominStaff.setTooltip("You can buy one from the Chamber Guardian in the Mage Arena Cavern for 80k"); + + godStaff = new ItemRequirement("God staff matching boss you're killing", ItemID.SARADOMIN_STAFF); + godStaff.addAlternates(ItemID.ZAMORAK_STAFF, ItemID.GUTHIX_STAFF); + godStaff.setTooltip("You can buy one from the Chamber Guardian in the Mage Arena Cavern for 80k"); + runesForCasts = new ItemRequirements("Runes for 50+ casts of god spells", new ItemRequirement("Blood runes", ItemID.BLOODRUNE, -1), new ItemRequirement("Air runes", ItemID.AIRRUNE, -1), @@ -102,7 +110,7 @@ protected void setupZones() public void setupSteps() { - locateFollowerSara = new MageArenaBossStep(this, saradominStaff, "desired", "", + locateFollowers = new MageArenaBossStep(this, godStaff, "", enchantedSymbol, food); } @@ -146,8 +154,21 @@ public List getGeneralRequirements() public List getPanels() { List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Upgrading the God Cape", Collections.singletonList(locateFollowerSara), + allSteps.add(new PanelDetails("Upgrading the God Cape", Collections.singletonList(locateFollowers), knife, saradominStaff, guthixStaff, zamorakStaff, runesForCasts)); return allSteps; } + + @Override + public void renderDebugOverlay(Graphics graphics, QuestHelperPlugin plugin, PanelComponent panelComponent) + { + super.renderDebugOverlay(graphics, plugin, panelComponent); + + var currentStep = this.getCurrentStep(); + if (currentStep instanceof MageArenaBossStep) + { + var bossStep = (MageArenaBossStep) currentStep; + bossStep.renderDebugOverlay(graphics, plugin, panelComponent); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaBossStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaBossStep.java index 076b82da09..569947a4cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaBossStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaBossStep.java @@ -31,18 +31,27 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.tools.DefinedPoint; import lombok.NonNull; import net.runelite.api.ChatMessageType; +import net.runelite.api.KeyCode; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.VarbitID; +import net.runelite.api.widgets.JavaScriptCallback; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @@ -52,8 +61,11 @@ import java.awt.image.BufferedImage; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class MageArenaBossStep extends DetailedQuestStep @@ -77,33 +89,79 @@ public class MageArenaBossStep extends DetailedQuestStep ItemRequirement[] baseRequirements; - @Nullable - private MageArenaSolver mageArenaSolver; + private God godToFind; + + private God lastGodClicked; + + /// Set to true after the user clicks "Activate" on the MA2 Enchanted Symbol. + /// This helps ensure we don't add key and mouse listeners to unrelated dialogs. + private boolean clickedActivateOnSymbol = false; + + private final Map mageArenaSolvers = new HashMap<>(); boolean foundLocation = false; int currentVar = 0; + boolean allowChangingBoss; + + // We need this as a player can press multiple keys in the options dialog, but only the first press counts + boolean keyPressedOnce; + + /// If set, will be used when "Activate" is clicked to figure out whether it's the last option available (only a thing during MA2) + private final @Nullable VarbitRequirement finishedSaradomin; + + /// If set, will be used when "Activate" is clicked to figure out whether it's the last option available (only a thing during MA2) + private final @Nullable VarbitRequirement finishedGuthix; + + /// If set, will be used when "Activate" is clicked to figure out whether it's the last option available (only a thing during MA2) + private final @Nullable VarbitRequirement finishedZamorak; + public MageArenaBossStep(QuestHelper questHelper, ItemRequirement staff, String bossName, - String abilityDetail, ItemRequirement... requirements) + String abilityDetail, + VarbitRequirement finishedSaradomin, + VarbitRequirement finishedGuthix, + VarbitRequirement finishedZamorak, + ItemRequirement... requirements) { super(questHelper, originalTextStart + bossName + originalTextEnd, requirements); this.bossName = bossName; this.abilityDetail = abilityDetail; this.staff = staff; this.baseRequirements = requirements; + this.godToFind = God.getByName(bossName); + + this.finishedSaradomin = finishedSaradomin; + this.finishedGuthix = finishedGuthix; + this.finishedZamorak = finishedZamorak; + } + + public MageArenaBossStep(QuestHelper questHelper, ItemRequirement staff, + String abilityDetail, ItemRequirement... requirements) + { + super(questHelper, originalTextStart + "desired" + originalTextEnd, requirements); + this.bossName = "desired"; + this.abilityDetail = abilityDetail; + this.staff = staff; + this.baseRequirements = requirements; + this.allowChangingBoss = true; + this.godToFind = God.SARADOMIN; + + this.finishedSaradomin = null; + this.finishedGuthix = null; + this.finishedZamorak = null; } @Override public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin, @NonNull List additionalText, @NonNull List additionalRequirements) { super.makeOverlayHint(panelComponent, plugin, additionalText, additionalRequirements); - if (mageArenaSolver == null) + if (mageArenaSolvers == null) { return; } - final Collection digLocations = mageArenaSolver.getPossibleLocations(); + final Collection digLocations = mageArenaSolvers.get(godToFind).getPossibleLocations(); List locations = digLocations.stream() .map(MageArenaSpawnLocation::getArea) .distinct() @@ -169,16 +227,47 @@ public void resetState() setWorldPoint(DefinedPoint.of(null)); Set locations = Arrays.stream(MageArenaSpawnLocation.values()) - .collect(Collectors.toSet()); + .collect(Collectors.toSet()); + + if (mageArenaSolvers == null) return; + + mageArenaSolvers.forEach(((god, mageArenaSolver) -> + mageArenaSolver.resetSolver(locations) + )); - if (mageArenaSolver != null) + if (mageArenaSolvers.get(godToFind).getPossibleLocations().size() == 1) { - mageArenaSolver.resetSolver(locations); + this.setWorldPoint(mageArenaSolvers.get(godToFind).getPossibleLocations().iterator().next().getWorldPoint()); } - if (mageArenaSolver.getPossibleLocations().size() == 1) + } + + @Override + public void setWorldPoint(DefinedPoint definedPoint) + { + super.setWorldPoint(definedPoint); + + if (definedPoint == null || definedPoint.getWorldPoint() == null) { - this.setWorldPoint(mageArenaSolver.getPossibleLocations().iterator().next().getWorldPoint()); + setHighlightZone(java.util.Collections.emptyList()); + return; } + + final WorldPoint worldPoint = definedPoint.getWorldPoint(); + final int maxDistance = MageArenaTemperature.SHAKING.getMaxDistance(); + + final WorldPoint minPoint = new WorldPoint( + worldPoint.getX() - maxDistance, + worldPoint.getY() - maxDistance, + worldPoint.getPlane() + ); + + final WorldPoint maxPoint = new WorldPoint( + worldPoint.getX() + maxDistance, + worldPoint.getY() + maxDistance, + worldPoint.getPlane() + ); + + setHighlightZone(new Zone(minPoint, maxPoint)); } @Override @@ -201,9 +290,130 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) OverlayUtil.renderTileOverlay(client, graphics, localLocation, getSymbolLocation(), questHelper.getConfig().targetOverlayColor()); } + @Override + public void onWidgetLoaded(WidgetLoaded widgetLoaded) + { + super.onWidgetLoaded(widgetLoaded); + if (widgetLoaded.getGroupId() != InterfaceID.CHATMENU) return; + if (!clickedActivateOnSymbol) return; + + clickedActivateOnSymbol = false; + clientThread.invokeAtTickEnd(this::addListeners); + } + + public void addListeners() + { + final AtomicInteger SARADOMIN_KC = new AtomicInteger(-1); + final AtomicInteger GUTHIX_KC = new AtomicInteger(-1); + final AtomicInteger ZAMORAK_KC = new AtomicInteger(-1); + var chatMenu = client.getWidget(InterfaceID.Chatmenu.OPTIONS); + if (chatMenu == null || chatMenu.isHidden()) return; + if (chatMenu.getChildren() == null || chatMenu.getChildren().length < 4) return; + + for (var i = 1; i < 4; ++i) + { + var button = chatMenu.getChild(i); + if (button == null) + { + return; + } + var buttonText = button.getText(); + var buttonIndex = button.getIndex(); + if ("Saradomin".equals(buttonText)) + { + button.setOnClickListener((JavaScriptCallback) ev -> { handleBossButtonClick(God.SARADOMIN); }); + if (buttonIndex == 1) SARADOMIN_KC.set(KeyCode.KC_1); + else if (buttonIndex == 2) SARADOMIN_KC.set(KeyCode.KC_2); + else if (buttonIndex == 3) SARADOMIN_KC.set(KeyCode.KC_3); + } + else if ("Guthix".equals(buttonText)) + { + button.setOnClickListener((JavaScriptCallback) ev -> {handleBossButtonClick(God.GUTHIX);}); + if (buttonIndex == 1) GUTHIX_KC.set(KeyCode.KC_1); + else if (buttonIndex == 2) GUTHIX_KC.set(KeyCode.KC_2); + else if (buttonIndex == 3) GUTHIX_KC.set(KeyCode.KC_3); + } + else if ("Zamorak".equals(buttonText)) + { + button.setOnClickListener((JavaScriptCallback) ev -> { handleBossButtonClick(God.ZAMORAK); }); + if (buttonIndex == 1) ZAMORAK_KC.set(KeyCode.KC_1); + else if (buttonIndex == 2) ZAMORAK_KC.set(KeyCode.KC_2); + else if (buttonIndex == 3) ZAMORAK_KC.set(KeyCode.KC_3); + } + } + + keyPressedOnce = false; + + chatMenu.setHasListener(true); + chatMenu.setOnKeyListener((JavaScriptCallback) ev -> { + if (keyPressedOnce) return; + keyPressedOnce = true; + var saradominKc = SARADOMIN_KC.get(); + var guthixKc = GUTHIX_KC.get(); + var zamorakKc = ZAMORAK_KC.get(); + if (saradominKc != -1 && ev.getTypedKeyCode() == saradominKc) handleBossButtonClick(God.SARADOMIN); + if (guthixKc != -1 && ev.getTypedKeyCode() == guthixKc) handleBossButtonClick(God.GUTHIX); + if (zamorakKc != -1 && ev.getTypedKeyCode() == zamorakKc) handleBossButtonClick(God.ZAMORAK); + }); + chatMenu.revalidate(); + } + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked e) + { + if (e.getItemId() == ItemID.MA2_SYMBOL && "Activate".equals(e.getMenuOption())) + { + if (finishedSaradomin != null && finishedGuthix != null && finishedZamorak != null) { + var finishedSaradomin = this.finishedSaradomin.check(client); + var finishedGuthix = this.finishedGuthix.check(client); + var finishedZamorak = this.finishedZamorak.check(client); + + if (finishedSaradomin && finishedGuthix && !finishedZamorak) + { + // User only has Zamorak left + handleBossButtonClick(God.ZAMORAK); + return; + } + + if (finishedSaradomin && !finishedGuthix && finishedZamorak) + { + // User only has Guthix left + handleBossButtonClick(God.GUTHIX); + return; + } + + if (!finishedSaradomin && finishedGuthix && finishedZamorak) + { + // User only has Saradomin left + handleBossButtonClick(God.SARADOMIN); + return; + } + } + + clickedActivateOnSymbol = true; + } + } + + private void handleBossButtonClick(God godClicked) + { + if (allowChangingBoss && godToFind != godClicked) + { + // Technically this could be set to the last wp of the previous god tracking, but that + // Seemed to cause issues sometimes so something seems wrong with that assumption + mageArenaSolvers.get(godClicked).setLastWorldPoint(null); + godToFind = godClicked; + } + else + { + lastGodClicked = godClicked; + } + } + + @Override public void onChatMessage(ChatMessage chatMessage) { + super.onChatMessage(chatMessage); + if (chatMessage.getType() == ChatMessageType.GAMEMESSAGE) { update(chatMessage.getMessage()); @@ -212,7 +422,15 @@ public void onChatMessage(ChatMessage chatMessage) public void update(final String message) { - if (mageArenaSolver == null) + final MageArenaTemperatureChange temperatureChange = MageArenaTemperatureChange.of(message); + + if (mageArenaSolvers == null || mageArenaSolvers.get(godToFind) == null) + { + return; + } + + // If looking only for a specific boss, don't bother checking others + if (!allowChangingBoss && lastGodClicked != godToFind) { return; } @@ -235,13 +453,12 @@ public void update(final String message) return; } - final MageArenaTemperatureChange temperatureChange = MageArenaTemperatureChange.of(message); - - mageArenaSolver.signal(localWorld, temperature, temperatureChange); + final MageArenaSolver currentMageArenaSolver = mageArenaSolvers.get(godToFind); + currentMageArenaSolver.signal(localWorld, temperature, temperatureChange); - if (mageArenaSolver.getPossibleLocations().size() == 1) + if (currentMageArenaSolver.getPossibleLocations().size() == 1) { - this.setWorldPoint(mageArenaSolver.getPossibleLocations().iterator().next().getWorldPoint()); + this.setWorldPoint(currentMageArenaSolver.getPossibleLocations().iterator().next().getWorldPoint()); } else { @@ -255,14 +472,20 @@ public void startUp() { super.startUp(); currentVar = client.getVarbitValue(VarbitID.MA2_TIMER_REMAINING); - Set locations = - Arrays.stream(MageArenaSpawnLocation.values()) + + mageArenaSolvers.put(God.SARADOMIN, new MageArenaSolver(Arrays.stream(MageArenaSpawnLocation.values()).collect(Collectors.toSet()))); + mageArenaSolvers.put(God.GUTHIX, new MageArenaSolver(Arrays.stream(MageArenaSpawnLocation.values()).collect(Collectors.toSet()))); + mageArenaSolvers.put(God.ZAMORAK, new MageArenaSolver(Arrays.stream(MageArenaSpawnLocation.values()).collect(Collectors.toSet()))); + + var locations = Arrays.stream(MageArenaSpawnLocation.values()) .collect(Collectors.toSet()); - mageArenaSolver = new MageArenaSolver(locations); + if (locations.size() == 1) { this.setWorldPoint(locations.iterator().next().getWorldPoint()); } + + addListeners(); } @Override @@ -276,4 +499,55 @@ private BufferedImage getSymbolLocation() { return itemManager.getImage(ItemID.MA2_SYMBOL); } + + public void renderDebugOverlay(Graphics graphics, QuestHelperPlugin plugin, PanelComponent panelComponent) + { + panelComponent.getChildren().add(LineComponent.builder() + .left("God name") + .leftColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .right(this.bossName) + .rightColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .build() + ); + + panelComponent.getChildren().add(LineComponent.builder() + .left("God to find") + .leftColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .right(this.godToFind.name) + .rightColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .build() + ); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pending") + .leftColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .right(clickedActivateOnSymbol ? "y" : "n") + .rightColor(ColorScheme.BRAND_ORANGE_TRANSPARENT) + .build() + ); + } + + enum God + { + SARADOMIN("Saradomin"), + GUTHIX("Guthix"), + ZAMORAK("Zamorak"); + + final String name; + + God(String name) + { + this.name = name; + } + + public static God getByName(String name) + { + for (God god : God.values()) + { + if (god.name.equals(name)) return god; + } + // Failure catch + return SARADOMIN; + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSolver.java index 87383dcbc0..d46335f5ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSolver.java @@ -49,7 +49,9 @@ public class MageArenaSolver { @Setter private Set possibleLocations; + @Nullable + @Setter private WorldPoint lastWorldPoint; public MageArenaSolver(Set possibleLocations) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSpawnLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSpawnLocation.java index 39c8ca96a0..aa23732a44 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSpawnLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/MageArenaSpawnLocation.java @@ -48,13 +48,12 @@ public enum MageArenaSpawnLocation NORTH_EAST_LAVA_DRAGON_4(new WorldPoint(3247, 3862, 0), "North east of the Lava Dragon Isle."), WEST_LAVA_DRAGON(new WorldPoint(3146, 3895, 0), "West of the Lava Dragon Isle."), WEST_LAVA_DRAGON_2(new WorldPoint(3163, 3833, 0), "West of the Lava Dragon Isle."), - WEST_DEMONIC_RUINS(new WorldPoint(3314, 3876, 0), "West of the Demonic Ruins."), + EAST_DEMONIC_RUINS(new WorldPoint(3314, 3876, 0), "East of the Demonic Ruins."), EAST_LAVA_DRAGON_ISLE(new WorldPoint(3246, 3834, 0), "East of the Lava Dragon Isle."), EAST_LAVA_DRAGON_ISLE_2(new WorldPoint(3279, 3823, 0), "East of the Lava Dragon Isle."), SOUTH_EAST_LAVA_DRAGON_ISLE(new WorldPoint(3266, 3814, 0), "South east of the Lava Dragon Isle."), EAST_ROGUE(new WorldPoint(3306, 3936, 0), "East of the Rogues' Castle."), - // TODO: This one isn't a precise position - EAST_ROGUE_2(new WorldPoint(3343, 3911, 0), "East of the Rogues' Castle."), + EAST_ROGUE_2(new WorldPoint(3335, 3902, 0), "East of the Rogues' Castle."), WEST_ROGUE(new WorldPoint(3261, 3909, 0), "West of the Rogues' Castle."); private final WorldPoint worldPoint; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/TheMageArenaII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/TheMageArenaII.java index d3cd649cc1..1029c9420a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/TheMageArenaII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/themagearenaii/TheMageArenaII.java @@ -35,7 +35,9 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; @@ -46,6 +48,7 @@ import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarPlayerID; import net.runelite.api.gameval.VarbitID; import java.util.*; @@ -55,7 +58,14 @@ public class TheMageArenaII extends BasicQuestHelper ItemRequirement zamorakStaff, guthixStaff, saradominStaff, runesForCasts, magicCombatGear, knife, brews, restores , food, recoils, enchantedSymbol, justicarsHand, demonsHeart, entRoots, godCape; - Requirement inCavern, givenHand, givenHeart, givenRoots; + Requirement inCavern; + VarbitRequirement givenHand; + VarbitRequirement givenHeart; + VarbitRequirement givenRoots; + + VarplayerRequirement unlockedSaradominStrike; + VarplayerRequirement unlockedClawsOfGuthix; + VarplayerRequirement unlockedFlamesOfZamorak; QuestStep enterCavern, talkToKolodion, locateFollowerSara, locateFollowerGuthix, locateFollowerZammy, enterCavernWithHand, enterCavernWithHeart, enterCavernWithRoots, giveKolodionHeart, giveKolodionHand, @@ -115,7 +125,7 @@ protected void setupRequirements() new ItemRequirement("Fire runes", ItemID.FIRERUNE, -1)); magicCombatGear = new ItemRequirement("Magic combat gear", -1, 1).isNotConsumed(); magicCombatGear.setDisplayItemId(BankSlotIcons.getMagicCombatGear()); - knife = new ItemRequirement("Knife or sharp weapon to cut through a web", ItemID.KNIFE).isNotConsumed(); + knife = new ItemRequirement("Knife or sharp weapon to cut through a web", ItemCollections.SLASH_WEB_KNIFE).isNotConsumed(); brews = new ItemRequirement("Saradomin brews", ItemCollections.SARADOMIN_BREWS, -1); restores = new ItemRequirement("Super restores", ItemCollections.SUPER_RESTORE_POTIONS, -1); food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); @@ -130,6 +140,13 @@ protected void setupRequirements() godCape = new ItemRequirement("God cape", ItemID.ZAMORAK_CAPE).isNotConsumed(); godCape.addAlternates(ItemID.GUTHIX_CAPE, ItemID.SARADOMIN_CAPE); godCape.setHighlightInInventory(true); + + unlockedSaradominStrike = new VarplayerRequirement(VarPlayerID.SARAMAGE, 100, Operation.GREATER_EQUAL, "Unlocked Saradomin Strike"); + unlockedSaradominStrike.setTooltip("Unlocked by casting the Saradomin Strike 100 times within the mage arena"); + unlockedClawsOfGuthix = new VarplayerRequirement(VarPlayerID.GUTHMAGE, 100, Operation.GREATER_EQUAL, "Unlocked Claws of Guthix"); + unlockedClawsOfGuthix.setTooltip("Unlocked by casting the Claws of Guthix 100 times within the mage arena"); + unlockedFlamesOfZamorak = new VarplayerRequirement(VarPlayerID.ZAMOMAGE, 100, Operation.GREATER_EQUAL, "Unlocked Flames of Zamorak"); + unlockedFlamesOfZamorak.setTooltip("Unlocked by casting the Flames of Zamorak 100 times within the mage arena"); } @Override @@ -161,14 +178,15 @@ public void setupSteps() locateFollowerSara = new MageArenaBossStep(this, saradominStaff, "Saradomin", "If he fires a blue wave at " + "you, move off your tile to avoid it. If you don't, he will pull you into melee distance.", - enchantedSymbol, food); + givenHand, givenRoots, givenHeart, enchantedSymbol, food); locateFollowerSara.addDialogStep("Saradomin"); locateFollowerGuthix = new MageArenaBossStep(this, guthixStaff, "Guthix", "If he spawns green orbs, destroy " + - "them to stop them healing him.", enchantedSymbol, food); + "them to stop them healing him.", + givenHand, givenRoots, givenHeart, enchantedSymbol, food); locateFollowerGuthix.addDialogStep("Guthix"); locateFollowerZammy = new MageArenaBossStep(this, zamorakStaff, "Zamorak", "If he fires an energy ball at " + "you, move away away from the boss to reduce the damage you take.", - enchantedSymbol, food); + givenHand, givenRoots, givenHeart, enchantedSymbol, food); locateFollowerZammy.addDialogStep("Zamorak"); enterCavernWithHand = new ObjectStep(this, ObjectID.MAGEARENA_LEVER_TO_CELLAR, new WorldPoint(3090, 3956, 0), "Return with" + @@ -237,7 +255,9 @@ public List getGeneralRequirements() ArrayList reqs = new ArrayList<>(); reqs.add(new SkillRequirement(Skill.MAGIC, 75)); reqs.add(new QuestRequirement(QuestHelperQuest.THE_MAGE_ARENA, QuestState.FINISHED)); - reqs.add(new ItemRequirement("Unlocked all 3 god spells", -1, -1)); + reqs.add(unlockedSaradominStrike); + reqs.add(unlockedClawsOfGuthix); + reqs.add(unlockedFlamesOfZamorak); return reqs; } @@ -252,7 +272,7 @@ public List getPanels() { List allSteps = new ArrayList<>(); allSteps.add(new PanelDetails("Upgrading the God Cape", Arrays.asList(enterCavern, - talkToKolodion, locateAndKillMinions), knife, saradominStaff, guthixStaff, zamorakStaff, runesForCasts)); + talkToKolodion, locateAndKillMinions, useGodCapeOnKolidion), knife, saradominStaff, guthixStaff, zamorakStaff, unlockedSaradominStrike, unlockedClawsOfGuthix, unlockedFlamesOfZamorak, runesForCasts)); return allSteps; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/valetotems/ValeTotems.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/valetotems/ValeTotems.java index c716a0340a..e985036891 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/valetotems/ValeTotems.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/miniquests/valetotems/ValeTotems.java @@ -32,14 +32,21 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -48,14 +55,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - /** * The quest guide for the "Vale Totems" OSRS quest */ @@ -153,7 +152,7 @@ protected void setupRequirements() oneDecorativeItem.setTooltip("You can also use Willow, Maple, Yew, Magic, or Redwood decorative items, but it needs to match the logs you used to build the totem."); needToBuildTotem = new VarbitRequirement(VarbitID.ENT_TOTEMS_BROKEN_CHAT, 1); - isTotemBaseBuilt = new VarbitRequirement(VarbitID.ENT_TOTEMS_SITE_1_BASE, 1); + isTotemBaseBuilt = new VarbitRequirement(VarbitID.ENT_TOTEMS_SITE_1_BASE, 0, Operation.GREATER); isBuffaloNearby = or( new VarbitRequirement(VarbitID.ENT_TOTEMS_SITE_1_ANIMAL_1, 1), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingConfigChangeHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingConfigChangeHandler.java index 09ddde6c43..e580be9e8b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingConfigChangeHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingConfigChangeHandler.java @@ -28,7 +28,6 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.config.ConfigManager; import net.runelite.client.events.ConfigChanged; - import java.util.function.Consumer; public class FarmingConfigChangeHandler diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingPatch.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingPatch.java index 01c49e4e82..36f7e1f383 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingPatch.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingPatch.java @@ -48,14 +48,28 @@ public class FarmingPatch private final PatchImplementation implementation; private int farmer = -1; private final int patchNumber; - @Getter + @Getter(AccessLevel.NONE) private final WorldPoint location; - @Getter private final Shape patchArea; + FarmingPatch(String name, @Varbit int varbit, PatchImplementation implementation) + { + this(name, varbit, implementation, null, new Polygon(), -1, -1); + } + + FarmingPatch(String name, @Varbit int varbit, PatchImplementation implementation, int farmer) + { + this(name, varbit, implementation, null, new Polygon(), farmer, -1); + } + + FarmingPatch(String name, @Varbit int varbit, PatchImplementation implementation, int farmer, int patchNumber) + { + this(name, varbit, implementation, null, new Polygon(), farmer, patchNumber); + } + FarmingPatch(String name, @Varbit int varbit, PatchImplementation implementation, WorldPoint location) { - this(name, varbit, implementation, location, new Polygon(), -1); + this(name, varbit, implementation, location, new Polygon(), -1, -1); } FarmingPatch(String name, @Varbit int varbit, PatchImplementation implementation, WorldPoint location, Shape patchArea) @@ -79,6 +93,19 @@ public class FarmingPatch this.patchArea = patchArea; } + public WorldPoint getLocation() + { + if (location != null) + { + return location; + } + if (region == null) + { + return null; + } + return WorldPoint.fromRegion(region.getRegionID(), 32, 32, 0); + } + String configKey() { return region.getRegionID() + "." + varbit; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingRegion.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingRegion.java index 288f603bab..f0dbdcf5bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingRegion.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingRegion.java @@ -24,22 +24,16 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns; -import java.util.Collections; -import java.util.HashSet; import lombok.Getter; import net.runelite.api.coords.WorldPoint; -import java.util.Set; -import org.jetbrains.annotations.NotNull; - @Getter -public class FarmingRegion implements Comparable +public class FarmingRegion { private final String name; private final int regionID; private final boolean definite; private final FarmingPatch[] patches; - private final Set regionIDs; FarmingRegion(String name, int regionID, boolean definite, FarmingPatch... patches) { @@ -47,56 +41,20 @@ public class FarmingRegion implements Comparable this.regionID = regionID; this.definite = definite; this.patches = patches; - this.regionIDs = Set.of(regionID); - for (FarmingPatch p : patches) - { - p.setRegion(this); - } - } - - FarmingRegion(String name, int regionID, boolean definite, Set regionIDs, FarmingPatch... patches) - { - this.name = name; - this.regionID = regionID; - this.definite = definite; - this.patches = patches; - - Set allRegionIds = new HashSet<>(regionIDs); - allRegionIds.add(regionID); - this.regionIDs = Collections.unmodifiableSet(allRegionIds); - for (FarmingPatch p : patches) { p.setRegion(this); } } - /** - * Check if the given WorldPoint is within this farming region - * Checks if the point's regionID is in this region's regionIDs set - * - * @param loc The WorldPoint to check - * @return true if the point is within this farming region - */ public boolean isInBounds(WorldPoint loc) { - return regionIDs.contains(loc.getRegionID()); + return true; } @Override public String toString() { - String sb = "FarmingRegion{name='" + name + '\'' + - ", regionID=" + regionID + - ", definite=" + definite + - ", patches=" + patches.length + - '}'; - return sb; - } - - @Override - public int compareTo(@NotNull FarmingRegion o) - { - return Integer.compare(regionID, o.getRegionID()); + return name; } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingUtils.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingUtils.java index 8280a86e6c..e03879a7bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingUtils.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingUtils.java @@ -27,6 +27,8 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import java.util.ArrayList; +import java.util.List; import net.runelite.api.Client; import net.runelite.api.gameval.ItemID; import net.runelite.client.config.ConfigManager; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingWorld.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingWorld.java index 6f2416d201..52f4a864f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingWorld.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/FarmingWorld.java @@ -30,15 +30,21 @@ import com.google.common.collect.Multimaps; import com.google.inject.Singleton; import java.awt.Polygon; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; import lombok.Getter; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.VarbitID; import net.runelite.client.plugins.timetracking.Tab; -import java.util.*; -import java.util.stream.Collectors; - @Singleton public class FarmingWorld { @@ -46,12 +52,13 @@ public class FarmingWorld private Multimap regions = HashMultimap.create(); @Getter + @SuppressWarnings("PMD.ImmutableField") private Map> tabs = new HashMap<>(); private final Comparator tabSorter = Comparator - .comparing(FarmingPatch::getImplementation) - .thenComparing((FarmingPatch p) -> p.getRegion().getName()) - .thenComparing(FarmingPatch::getName); + .comparing(FarmingPatch::getImplementation) + .thenComparing((FarmingPatch p) -> p.getRegion().getName()) + .thenComparing(FarmingPatch::getName); @Getter private final FarmingRegion farmingGuildRegion; @@ -60,120 +67,104 @@ public class FarmingWorld { // Some of these patches get updated in multiple regions. // It may be worth it to add a specialization for these patches - add(new FarmingRegion("Al Kharid", 13106, false, Set.of(13105, 13362), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CACTUS, new WorldPoint(3317, 3203, 0), - new Polygon( + add(new FarmingRegion("Al Kharid", 13106, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CACTUS, new WorldPoint(3317, 3203, 0), new Polygon( new int[]{3315, 3315, 3316, 3316}, new int[]{3202, 3203, 3203, 3202}, 4 - ), - NpcID.FARMING_GARDENER_CACTUS) - )); + ), NpcID.FARMING_GARDENER_CACTUS) + ), 13362, 13105); - add(new FarmingRegion("Aldarin", 5421, false, Set.of(5165, 5166, 5422, 5677, 5678), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(1366, 2941, 0), - new Polygon( + add(new FarmingRegion("Aldarin", 5421, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(1366, 2941, 0), new Polygon( new int[]{1363, 1363, 1366, 1366}, new int[]{2937, 2940, 2940, 2937}, 4 - ), - NpcID.FARMING_GARDENER_HOPS_5) + ), NpcID.FARMING_GARDENER_HOPS_5) + ), 5165, 5166, 5422, 5677, 5678); + + add(new FarmingRegion("Anglers' Retreat", 9770, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HARDWOOD_TREE, NpcID.FARMING_GARDENER_HARDWOOD_TREE_5) )); - add(new FarmingRegion("Ardougne", 10290, false, Set.of(10546), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2616, 3226, 0), - new Polygon( + add(new FarmingRegion("Ardougne", 10290, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2616, 3226, 0), new Polygon( new int[]{2617, 2617, 2618, 2618}, new int[]{3225, 3226, 3226, 3225}, 4 - ), - NpcID.FARMING_GARDENER_BUSH_4) - )); + ), NpcID.FARMING_GARDENER_BUSH_4) + ), 10546); add(new FarmingRegion("Ardougne", 10548, false, - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(2672, 3379, 0), - new Polygon( + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(2672, 3379, 0), new Polygon( new int[]{2662, 2662, 2671, 2671, 2663, 2663}, new int[]{3377, 3379, 3379, 3378, 3378, 3377}, 6 - ), - NpcID.KRAGEN, 0), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(2672, 3371, 0), - new Polygon( + ), NpcID.KRAGEN, 0), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(2672, 3371, 0), new Polygon( new int[]{2662, 2662, 2663, 2663, 2671, 2671}, new int[]{3370, 3372, 3372, 3371, 3371, 3370}, 6 - ), - NpcID.KRAGEN, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(2668, 3375, 0), - new Polygon( + ), NpcID.KRAGEN, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(2668, 3375, 0), new Polygon( new int[]{2666, 2666, 2667, 2667}, new int[]{3374, 3375, 3375, 3374}, - 4) - ), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(2672, 3375, 0), - new Polygon( + 4)), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(2672, 3375, 0), new Polygon( new int[]{2670, 2670, 2671, 2671}, new int[]{3374, 3375, 3375, 3374}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(2662, 3375, 0)) + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST) )); - add(new FarmingRegion("Avium Savannah", 6702, true, Set.of(6446), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HARDWOOD_TREE, new WorldPoint(1685, 2971, 0), - new Polygon( + add(new FarmingRegion("Auburnvale", 5427, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, NpcID.FARMING_GARDENER_TREE_7), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.BELLADONNA) + ), 5428, 5684); + + add(new FarmingRegion("Avium Savannah", 6702, true, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HARDWOOD_TREE, new WorldPoint(1685, 2971, 0), new Polygon( new int[]{1686, 1686, 1688, 1688}, new int[]{2971, 2973, 2973, 2971}, 4 - ), - NpcID.FROG_QUEST_MARCELLUS) - )); + ), NpcID.FROG_QUEST_MARCELLUS) + ), 6446); - add(new FarmingRegion("Brimhaven", 11058, false, Set.of(11057), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2766, 3213, 0), - new Polygon( + add(new FarmingRegion("Brimhaven", 11058, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2766, 3213, 0), new Polygon( new int[]{2764, 2764, 2765, 2765}, new int[]{3212, 3213, 3213, 3212}, 4 - ), - NpcID.GARTH), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SPIRIT_TREE, new WorldPoint(2800, 3202, 0), - new Polygon( + ), NpcID.GARTH), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SPIRIT_TREE, new WorldPoint(2800, 3202, 0), new Polygon( new int[]{2801, 2801, 2803, 2803}, new int[]{3202, 3204, 3204, 3202}, 4 - ), - NpcID.FARMING_GARDENER_SPIRIT_TREE_3) - )); + ), NpcID.FARMING_GARDENER_SPIRIT_TREE_3) + ), 11057); - add(new FarmingRegion("Catherby", 11062, false, Set.of(11061, 11318, 11317), - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(2814, 3466, 0), - new Polygon( + add(new FarmingRegion("Catherby", 11062, false, + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(2814, 3466, 0), new Polygon( new int[]{2805, 2805, 2814, 2814, 2806, 2806}, new int[]{3466, 3468, 3468, 3467, 3467, 3466}, 6 - ), - NpcID.DANTAERA, 0), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(2815, 3460, 0), - new Polygon( + ), NpcID.DANTAERA, 0), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(2815, 3460, 0), new Polygon( new int[]{2805, 2805, 2806, 2806, 2814, 2814}, new int[]{3459, 3461, 3461, 3460, 3460, 3459}, 6 - ), - NpcID.DANTAERA, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(2810, 3465, 0), - new Polygon( + ), NpcID.DANTAERA, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(2810, 3465, 0), new Polygon( new int[]{2809, 2809, 2810, 2810}, new int[]{3463, 3464, 3464, 3463}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(2815, 3464, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(2815, 3464, 0), new Polygon( new int[]{2813, 2813, 2814, 2814}, new int[]{3463, 3464, 3464, 3463}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(2805, 3464, 0)) + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST) ) { @Override @@ -186,15 +177,13 @@ public boolean isInBounds(WorldPoint loc) } return true; } - }); + }, 11061, 11318, 11317); add(new FarmingRegion("Catherby", 11317, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2860, 3432, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2860, 3432, 0), new Polygon( new int[]{2860, 2860, 2861, 2861}, new int[]{3433, 3434, 3434, 3433}, 4 - ), - NpcID.FARMING_GARDENER_FRUIT_4) + ), NpcID.FARMING_GARDENER_FRUIT_4) ) { //The fruit tree patch is always sent when upstairs in 11317 @@ -205,119 +194,92 @@ public boolean isInBounds(WorldPoint loc) } }); - add(new FarmingRegion("Civitas illa Fortis", 6192, false, Set.of(6447, 6448, 6449, 6191, 6193), - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(1586, 3102, 0), - new Polygon( + add(new FarmingRegion("Civitas illa Fortis", 6192, false, + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(1586, 3102, 0), new Polygon( new int[]{1581, 1581, 1585, 1585, 1582, 1582}, new int[]{3098, 3103, 3103, 3102, 3102, 3098}, 6 - ), - NpcID.FORTIS_GARDENER, 0), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(1591, 3098, 0), - new Polygon( + ), NpcID.FORTIS_GARDENER, 0), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(1591, 3098, 0), new Polygon( new int[]{1585, 1585, 1589, 1589, 1590, 1590}, new int[]{3094, 3095, 3095, 3098, 3098, 3094}, 6 - ), - NpcID.FORTIS_GARDENER, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(1587, 3099, 0), - new Polygon( + ), NpcID.FORTIS_GARDENER, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(1587, 3099, 0), new Polygon( new int[]{1585, 1585, 1586, 1586}, new int[]{3098, 3099, 3099, 3098}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(1581, 3094, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(1581, 3094, 0), new Polygon( new int[]{1581, 1581, 1582, 1582}, new int[]{3094, 3095, 3095, 3094}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(1587, 3103, 0)) - )); + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST) + ), 6447, 6448, 6449, 6191, 6193); add(new FarmingRegion("Champions' Guild", 12596, true, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(3181, 3356, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(3181, 3356, 0), new Polygon( new int[]{3181, 3181, 3182, 3182}, new int[]{3357, 3358, 3358, 3357}, 4 - ), - NpcID.FARMING_GARDENER_BUSH_1) + ), NpcID.FARMING_GARDENER_BUSH_1) )); add(new FarmingRegion("Draynor Manor", 12340, false, - new FarmingPatch("Belladonna", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BELLADONNA, new WorldPoint(3088, 3355, 0), - new Polygon( - new int[]{3086, 3086, 3087, 3087}, - new int[]{3354, 3355, 3355, 3354}, - 4 - )) + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BELLADONNA) )); - add(new FarmingRegion("Entrana", 11060, false, Set.of(11316), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2812, 3334, 0), - new Polygon( + add(new FarmingRegion("Entrana", 11060, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2812, 3334, 0), new Polygon( new int[]{2809, 2809, 2812, 2812}, new int[]{3335, 3338, 3338, 3335}, 4 - ), - NpcID.FRANCIS) - )); + ), NpcID.FRANCIS) + ), 11316); add(new FarmingRegion("Etceteria", 10300, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2592, 3862, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2592, 3862, 0), new Polygon( new int[]{2591, 2591, 2592, 2592}, new int[]{3863, 3864, 3864, 3863}, 4 - ), - NpcID.FARMING_GARDENER_BUSH_3), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SPIRIT_TREE, new WorldPoint(2613, 3856, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_BUSH_3), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SPIRIT_TREE, new WorldPoint(2613, 3856, 0), new Polygon( new int[]{2612, 2612, 2614, 2614}, new int[]{3857, 3859, 3859, 3857}, 4 - ), - NpcID.FARMING_GARDENER_SPIRIT_TREE_2) + ), NpcID.FARMING_GARDENER_SPIRIT_TREE_2) )); - add(new FarmingRegion("Falador", 11828, false, Set.of(12084), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3004, 3371, 0), - new Polygon( + add(new FarmingRegion("Falador", 11828, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3004, 3371, 0), new Polygon( new int[]{3003, 3003, 3005, 3005}, new int[]{3372, 3374, 3374, 3372}, 4 - ), - NpcID.FARMING_GARDENER_TREE_2) - )); + ), NpcID.FARMING_GARDENER_TREE_2) + ), 12084); add(new FarmingRegion("Falador", 12083, false, - new FarmingPatch("North West", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3052, 3307, 0), - new Polygon( + new FarmingPatch("North West", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3052, 3307, 0), new Polygon( new int[]{3050, 3050, 3054, 3054, 3051, 3051}, new int[]{3307, 3312, 3312, 3311, 3311, 3307}, 6 - ), - NpcID.ELSTAN, 0), - new FarmingPatch("South East", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3055, 3305, 0), - new Polygon( + ), NpcID.ELSTAN, 0), + new FarmingPatch("South East", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3055, 3305, 0), new Polygon( new int[]{3055, 3055, 3058, 3058, 3059, 3059}, new int[]{3303, 3304, 3304, 3308, 3308, 3303}, 6 - ), - NpcID.ELSTAN, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3053, 3307, 0), - new Polygon( + ), NpcID.ELSTAN, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3053, 3307, 0), new Polygon( new int[]{3054, 3054, 3055, 3055}, new int[]{3307, 3308, 3308, 3307}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(3057, 3311, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(3057, 3311, 0), new Polygon( new int[]{3058, 3058, 3059, 3059}, new int[]{3311, 3312, 3312, 3311}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(3056, 3311, 0)) + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST) ) { @Override @@ -328,28 +290,22 @@ public boolean isInBounds(WorldPoint loc) } }); - add(new FarmingRegion("Fossil Island", 14651, false, Set.of(14907, 14908, 15164, 14652, 14906, 14650, 15162, 15163), - new FarmingPatch("East", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3713, 3835, 0), - new Polygon( + add(new FarmingRegion("Fossil Island", 14651, false, + new FarmingPatch("East", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3713, 3835, 0), new Polygon( new int[]{3714, 3714, 3716, 3716}, new int[]{3834, 3836, 3836, 3834}, 4 - ), - NpcID.FOSSIL_SQUIRREL_GARDENER1), - new FarmingPatch("Middle", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3708, 3835, 0), - new Polygon( + ), NpcID.FOSSIL_SQUIRREL_GARDENER1), + new FarmingPatch("Middle", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3708, 3835, 0), new Polygon( new int[]{3707, 3707, 3709, 3709}, new int[]{3832, 3834, 3834, 3832}, 4 - ), - NpcID.FOSSIL_SQUIRREL_GARDENER2), - new FarmingPatch("West", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3701, 3836, 0), - new Polygon( + ), NpcID.FOSSIL_SQUIRREL_GARDENER2), + new FarmingPatch("West", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.HARDWOOD_TREE, new WorldPoint(3701, 3836, 0), new Polygon( new int[]{3701, 3701, 3703, 3703}, new int[]{3836, 3838, 3838, 3836}, 4 - ), - NpcID.FOSSIL_SQUIRREL_GARDENER3) + ), NpcID.FOSSIL_SQUIRREL_GARDENER3) ) { @Override @@ -366,194 +322,168 @@ public boolean isInBounds(WorldPoint loc) //East and west ladders to rope bridge if ((loc.getX() == 3729 || loc.getX() == 3728 || loc.getX() == 3747 || loc.getX() == 3746) - && loc.getY() <= 3832 && loc.getY() >= 3830) + && loc.getY() <= 3832 && loc.getY() >= 3830) { return false; } return loc.getPlane() == 0; } - }); + }, 14907, 14908, 15164, 14652, 14906, 14650, 15162, 15163); add(new FarmingRegion("Seaweed", 15008, false, - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SEAWEED, new WorldPoint(3733, 10272, 1), - new Polygon( + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SEAWEED, new WorldPoint(3733, 10272, 1), new Polygon( new int[]{3733, 3733, 3734, 3734}, new int[]{10273, 10274, 10274, 10273}, 4 - ), - NpcID.FOSSIL_GARDENER_UNDERWATER, 0), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SEAWEED, new WorldPoint(3733, 10269, 1), - new Polygon( + ), NpcID.FOSSIL_GARDENER_UNDERWATER, 0), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.SEAWEED, new WorldPoint(3733, 10269, 1), new Polygon( new int[]{3733, 3733, 3734, 3734}, new int[]{10267, 10268, 10268, 10267}, 4 - ), - NpcID.FOSSIL_GARDENER_UNDERWATER, 1) + ), NpcID.FOSSIL_GARDENER_UNDERWATER, 1) )); - add(new FarmingRegion("Gnome Stronghold", 9781, true, Set.of(9782, 9526, 9525), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(2437, 3417, 0), - new Polygon( + add(new FarmingRegion("Gnome Stronghold", 9781, true, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(2437, 3417, 0), new Polygon( new int[]{2437, 2437, 2435, 2435}, new int[]{3416, 3414, 3414, 3416}, 4 - ), - NpcID.FARMING_GARDENER_TREE_GNOME), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.FRUIT_TREE, new WorldPoint(2475, 3447, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_TREE_GNOME), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.FRUIT_TREE, new WorldPoint(2475, 3447, 0), new Polygon( new int[]{2475, 2475, 2476, 2476}, new int[]{3445, 3446, 3446, 3445}, 4 - ), - NpcID.FARMING_GARDENER_FRUIT_1) - )); + ), NpcID.FARMING_GARDENER_FRUIT_1) + ), 9782, 9526, 9525); + + add(new FarmingRegion("Great Conch", 12581, true, + new FarmingPatch("East", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CORAL, NpcID.TORTUGAN_CORAL_FARMER, 0), + new FarmingPatch("West", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.CORAL, NpcID.TORTUGAN_CORAL_FARMER, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.CALQUAT, NpcID.FARMING_GARDENER_CALQUAT_3) + ), 12325, 12326, 12327, 12580, 12581, 12582, 12583, 12836, 12837, 12838, 12839, 13092, 13093, 13194); add(new FarmingRegion("Harmony", 15148, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3795, 2838, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3795, 2838, 0), new Polygon( new int[]{3794, 3794}, new int[]{2833, 2838}, 2 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.HERB, new WorldPoint(3790, 3839, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.HERB, new WorldPoint(3790, 3839, 0), new Polygon( new int[]{3789, 3789, 3790, 3790}, new int[]{2837, 2838, 2838, 2837}, 4 )) )); - add(new FarmingRegion("Kourend", 6967, false, Set.of(6711), - new FarmingPatch("North East", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(1739, 3553, 0), - new Polygon( + add(new FarmingRegion("Kastori", 5423, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CALQUAT, NpcID.FARMING_GARDENER_CALQUAT_2), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.FRUIT_TREE, NpcID.FARMING_GARDENER_FRUIT_7), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER) + ), 5167, 5424); + + add(new FarmingRegion("Kourend", 6967, false, + new FarmingPatch("North East", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(1739, 3553, 0), new Polygon( new int[]{1733, 1733, 1739, 1739, 1738, 1738}, new int[]{3558, 3559, 3559, 3554, 3554, 3558}, 6 - ), - NpcID.HOSIDIUS_ALLOTMENT_GARDENER, 0), - new FarmingPatch("South West", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(1735, 3552, 0), - new Polygon( + ), NpcID.HOSIDIUS_ALLOTMENT_GARDENER, 0), + new FarmingPatch("South West", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(1735, 3552, 0), new Polygon( new int[]{1730, 1730, 1731, 1731, 1735, 1735}, new int[]{3550, 3555, 3555, 3551, 3551, 3550}, 6 - ), - NpcID.HOSIDIUS_ALLOTMENT_GARDENER, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(1735, 3553, 0), - new Polygon( + ), NpcID.HOSIDIUS_ALLOTMENT_GARDENER, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(1735, 3553, 0), new Polygon( new int[]{1734, 1734, 1735, 1734}, new int[]{3554, 3555, 3555, 1734}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(1739, 3552, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(1739, 3552, 0), new Polygon( new int[]{1738, 1738, 1739, 1739}, new int[]{3550, 3551, 3551, 3550}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(1730, 3557, 0)), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_F, PatchImplementation.SPIRIT_TREE, new WorldPoint(1695, 3543, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_F, PatchImplementation.SPIRIT_TREE, new WorldPoint(1695, 3543, 0), new Polygon( new int[]{1692, 1692, 1694, 1694}, new int[]{3541, 3543, 3543, 3541}, 4 - ), - NpcID.FARMING_GARDENER_SPIRIT_TREE_4) - )); - - /* - Not implemented - */ + ), NpcID.FARMING_GARDENER_SPIRIT_TREE_4) + ), 6711); add(new FarmingRegion("Kourend", 7223, false, - new FarmingPatch("East 1", VarbitID.FARMING_TRANSMIT_A1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("East 2", VarbitID.FARMING_TRANSMIT_A2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("East 3", VarbitID.FARMING_TRANSMIT_B1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("East 4", VarbitID.FARMING_TRANSMIT_B2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("East 5", VarbitID.FARMING_TRANSMIT_C1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("East 6", VarbitID.FARMING_TRANSMIT_C2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 1", VarbitID.FARMING_TRANSMIT_D1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 2", VarbitID.FARMING_TRANSMIT_D2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 3", VarbitID.FARMING_TRANSMIT_E1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 4", VarbitID.FARMING_TRANSMIT_E2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 5", VarbitID.FARMING_TRANSMIT_F1, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)), - new FarmingPatch("West 6", VarbitID.FARMING_TRANSMIT_F2, PatchImplementation.GRAPES, new WorldPoint(-1, -1, 0)) - )); - - add(new FarmingRegion("Lletya", 9265, false, Set.of(11103), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2345, 3162, 0), - new Polygon( + new FarmingPatch("East 1", VarbitID.FARMING_TRANSMIT_A1, PatchImplementation.GRAPES), + new FarmingPatch("East 2", VarbitID.FARMING_TRANSMIT_A2, PatchImplementation.GRAPES), + new FarmingPatch("East 3", VarbitID.FARMING_TRANSMIT_B1, PatchImplementation.GRAPES), + new FarmingPatch("East 4", VarbitID.FARMING_TRANSMIT_B2, PatchImplementation.GRAPES), + new FarmingPatch("East 5", VarbitID.FARMING_TRANSMIT_C1, PatchImplementation.GRAPES), + new FarmingPatch("East 6", VarbitID.FARMING_TRANSMIT_C2, PatchImplementation.GRAPES), + new FarmingPatch("West 1", VarbitID.FARMING_TRANSMIT_D1, PatchImplementation.GRAPES), + new FarmingPatch("West 2", VarbitID.FARMING_TRANSMIT_D2, PatchImplementation.GRAPES), + new FarmingPatch("West 3", VarbitID.FARMING_TRANSMIT_E1, PatchImplementation.GRAPES), + new FarmingPatch("West 4", VarbitID.FARMING_TRANSMIT_E2, PatchImplementation.GRAPES), + new FarmingPatch("West 5", VarbitID.FARMING_TRANSMIT_F1, PatchImplementation.GRAPES), + new FarmingPatch("West 6", VarbitID.FARMING_TRANSMIT_F2, PatchImplementation.GRAPES) + )); + + add(new FarmingRegion("Lletya", 9265, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2345, 3162, 0), new Polygon( new int[]{2346, 2346, 2347, 2347}, new int[]{3161, 3162, 3162, 3161}, 4 - ), - NpcID.FARMING_GARDENER_FRUIT_TREE_5) - )); + ), NpcID.FARMING_GARDENER_FRUIT_TREE_5) + ), 11103); add(new FarmingRegion("Lumbridge", 12851, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(3232, 3317, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(3232, 3317, 0), new Polygon( new int[]{3227, 3227, 3231, 3231}, new int[]{3313, 3317, 3317, 3313}, 4 - ), - NpcID.FARMING_GARDENER_HOPS_3) + ), NpcID.FARMING_GARDENER_HOPS_3) )); - add(new FarmingRegion("Lumbridge", 12594, false, Set.of(12850), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3195, 3230, 0), - new Polygon( + add(new FarmingRegion("Lumbridge", 12594, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3195, 3230, 0), new Polygon( new int[]{3192, 3192, 3194, 3194}, new int[]{3230, 3232, 3232, 3230}, 4 - ), - NpcID.FARMING_GARDENER_TREE_4) - )); + ), NpcID.FARMING_GARDENER_TREE_4) + ), 12850); - add(new FarmingRegion("Morytania", 13622, false, Set.of(13878), - new FarmingPatch("Mushroom", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.MUSHROOM, new WorldPoint(3451, 3474, 0), - new Polygon( + add(new FarmingRegion("Morytania", 13622, false, + new FarmingPatch("Mushroom", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.MUSHROOM, new WorldPoint(3451, 3474, 0), new Polygon( new int[]{3451, 3451, 3452, 3452}, new int[]{3472, 3473, 3473, 3472}, 4 )) - )); - add(new FarmingRegion("Morytania", 14391, false, Set.of(14390), - new FarmingPatch("North West", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3597, 3524, 0), - new Polygon( + ), 13878); + add(new FarmingRegion("Morytania", 14391, false, + new FarmingPatch("North West", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3597, 3524, 0), new Polygon( new int[]{3597, 3597, 3601, 3601, 3598, 3598}, new int[]{3525, 3530, 3530, 3529, 3529, 3525}, 6 - ), - NpcID.LYRA, 0), - new FarmingPatch("South East", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3601, 3522, 0), - new Polygon( + ), NpcID.LYRA, 0), + new FarmingPatch("South East", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3601, 3522, 0), new Polygon( new int[]{3602, 3602, 3605, 3605, 3606, 3606}, new int[]{3521, 3522, 3522, 3526, 3526, 3521}, 6 - ), - NpcID.LYRA, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3601, 3524, 0), - new Polygon( + ), NpcID.LYRA, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3601, 3524, 0), new Polygon( new int[]{3601, 3601, 3602, 3602}, new int[]{3225, 3226, 3226, 3225}, 4 - ) - ), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(3605, 3528, 0), - new Polygon( + )), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.HERB, new WorldPoint(3605, 3528, 0), new Polygon( new int[]{3605, 3605, 3606, 3606}, new int[]{3529, 3530, 3530, 3529}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST, new WorldPoint(3609, 3522, 0)) - )); + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.COMPOST) + ), 14390); - add(new FarmingRegion("Port Sarim", 12082, false, Set.of(12083), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SPIRIT_TREE, new WorldPoint(3059, 3257, 0), - new Polygon( + add(new FarmingRegion("Port Sarim", 12082, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SPIRIT_TREE, new WorldPoint(3059, 3257, 0), new Polygon( new int[]{3059, 3059, 3061, 3061}, new int[]{3257, 3259, 3259, 3257}, 4 - ), - NpcID.FARMING_GARDENER_SPIRIT_TREE_1) + ), NpcID.FARMING_GARDENER_SPIRIT_TREE_1) ) { @Override @@ -561,90 +491,74 @@ public boolean isInBounds(WorldPoint loc) { return loc.getY() < 3272; } - }); + }, 12083); - add(new FarmingRegion("Rimmington", 11570, false, Set.of(11826), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2940, 3223, 0), - new Polygon( + add(new FarmingRegion("Rimmington", 11570, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.BUSH, new WorldPoint(2940, 3223, 0), new Polygon( new int[]{2940, 2940, 2941, 2941}, new int[]{3221, 3222, 3222, 3221}, 4 - ), - NpcID.FARMING_GARDENER_BUSH_2) - )); + ), NpcID.FARMING_GARDENER_BUSH_2) + ), 11826); - add(new FarmingRegion("Seers' Village", 10551, false, Set.of(10550), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2669, 3522, 0), - new Polygon( + add(new FarmingRegion("Seers' Village", 10551, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2669, 3522, 0), new Polygon( new int[]{2664, 2664, 2669, 2669}, new int[]{3523, 3528, 3528, 3523}, 4 - ), - NpcID.FARMING_GARDENER_HOPS_4) - )); + ), NpcID.FARMING_GARDENER_HOPS_4) + ), 10550); add(new FarmingRegion("Tai Bwo Wannai", 11056, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CALQUAT, new WorldPoint(2796, 3103, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.CALQUAT, new WorldPoint(2796, 3103, 0), new Polygon( new int[]{2795, 2795, 2797, 2797}, new int[]{3100, 3102, 3102, 3100}, 4 - ), - NpcID.FARMING_GARDENER_CALQUAT) + ), NpcID.FARMING_GARDENER_CALQUAT) )); - add(new FarmingRegion("Taverley", 11573, false, Set.of(11829), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(2936, 3440, 0), - new Polygon( + add(new FarmingRegion("Taverley", 11573, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(2936, 3440, 0), new Polygon( new int[]{2935, 2935, 2937, 2937}, new int[]{3437, 3439, 3439, 3437}, 4 - ), - NpcID.FARMING_GARDENER_TREE_1) - )); + ), NpcID.FARMING_GARDENER_TREE_1) + ), 11829); - add(new FarmingRegion("Tree Gnome Village", 9777, true, Set.of(10033), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2488, 3180, 0), - new Polygon( + add(new FarmingRegion("Tree Gnome Village", 9777, true, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.FRUIT_TREE, new WorldPoint(2488, 3180, 0), new Polygon( new int[]{2489, 2489, 2490, 2490}, new int[]{3179, 3180, 3180, 3179}, 4 - ), - NpcID.FARMING_GARDENER_FRUIT_2) - )); + ), NpcID.FARMING_GARDENER_FRUIT_2) + ), 10033); add(new FarmingRegion("Troll Stronghold", 11321, true, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HERB, new WorldPoint(2827, 3693, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HERB, new WorldPoint(2827, 3693, 0), new Polygon( new int[]{2826, 2826, 2827, 2827}, new int[]{3694, 3695, 3695, 3694}, 4 )) )); - add(new FarmingRegion("Varrock", 12854, false, Set.of(12853), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3229, 3457, 0), - new Polygon( + add(new FarmingRegion("Varrock", 12854, false, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.TREE, new WorldPoint(3229, 3457, 0), new Polygon( new int[]{3228, 3228, 3230, 3230}, new int[]{3458, 3460, 3460, 3458}, 4 - ), - NpcID.FARMING_GARDENER_TREE_3_02) - )); + ), NpcID.FARMING_GARDENER_TREE_3_02) + ), 12853); add(new FarmingRegion("Yanille", 10288, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2573, 3106, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HOPS, new WorldPoint(2573, 3106, 0), new Polygon( new int[]{2574, 2574, 2577, 2577}, new int[]{3103, 3106, 3106, 3103}, 4 - ), - NpcID.FARMING_GARDENER_HOPS_1) + ), NpcID.FARMING_GARDENER_HOPS_1) )); add(new FarmingRegion("Weiss", 11325, false, - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HERB, new WorldPoint(2849, 3933, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.HERB, new WorldPoint(2849, 3933, 0), new Polygon( new int[]{2848, 2848, 2849, 2849}, new int[]{3934, 3935, 3935, 3934}, 4 @@ -652,8 +566,7 @@ public boolean isInBounds(WorldPoint loc) )); add(new FarmingRegion("Farming Guild", 5021, true, - new FarmingPatch("Hespori", VarbitID.FARMING_TRANSMIT_J, PatchImplementation.HESPORI, new WorldPoint(1246, 10085, 0), - new Polygon( + new FarmingPatch("Hespori", VarbitID.FARMING_TRANSMIT_J, PatchImplementation.HESPORI, new WorldPoint(1246, 10085, 0), new Polygon( new int[]{1246, 1248, 1248, 1246}, new int[]{10086, 10088, 10088, 10086}, 4 @@ -661,121 +574,95 @@ public boolean isInBounds(WorldPoint loc) )); //Full 3x3 region area centered on farming guild - add(farmingGuildRegion = new FarmingRegion("Farming Guild", 4922, true, Set.of(5177, 5178, 5179, 4921, 4923, 4665, 4666, 4667), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_G, PatchImplementation.TREE, new WorldPoint(1233, 3734, 0), - new Polygon( + add(farmingGuildRegion = new FarmingRegion("Farming Guild", 4922, true, + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_G, PatchImplementation.TREE, new WorldPoint(1233, 3734, 0), new Polygon( new int[]{1231, 1231, 1233, 1233}, new int[]{3735, 3737, 3737, 3735}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T2), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.HERB, new WorldPoint(1238, 3728, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T2), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.HERB, new WorldPoint(1238, 3728, 0), new Polygon( new int[]{1238, 1238, 1239, 1239}, new int[]{3726, 3727, 3727, 3726}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.BUSH, new WorldPoint(1261, 3732, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.BUSH, new WorldPoint(1261, 3732, 0), new Polygon( new int[]{1260, 1260, 1261, 1261}, new int[]{3733, 3734, 3734, 3733}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T1, 3), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_H, PatchImplementation.FLOWER, new WorldPoint(1261, 3727, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T1, 3), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_H, PatchImplementation.FLOWER, new WorldPoint(1261, 3727, 0), new Polygon( new int[]{1260, 1260, 1261, 1261}, new int[]{3725, 3726, 3726, 3725}, 4 )), - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.ALLOTMENT, new WorldPoint(1266, 3732, 0), - new Polygon( + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.ALLOTMENT, new WorldPoint(1266, 3732, 0), new Polygon( new int[]{1267, 1267, 1268, 1268, 1272, 1272}, new int[]{3732, 3736, 3736, 3733, 3733, 3732}, 6 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T1, 1), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.ALLOTMENT, new WorldPoint(1266, 3727, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T1, 1), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.ALLOTMENT, new WorldPoint(1266, 3727, 0), new Polygon( new int[]{1267, 1267, 1272, 1272, 1268, 1268}, new int[]{3723, 3727, 3727, 3726, 3726, 3723}, 6 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T1, 2), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_N, PatchImplementation.BIG_COMPOST, new WorldPoint(1271, 3729, 0)), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_F, PatchImplementation.CACTUS, new WorldPoint(1264, 3746, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T1, 2), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_N, PatchImplementation.BIG_COMPOST), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_F, PatchImplementation.CACTUS, new WorldPoint(1264, 3746, 0), new Polygon( new int[]{1264, 1264, 1265, 1265}, new int[]{3747, 3748, 3748, 3747}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T1, 0), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SPIRIT_TREE, new WorldPoint(1251, 3749, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T1, 0), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.SPIRIT_TREE, new WorldPoint(1251, 3749, 0), new Polygon( new int[]{1252, 1252, 1254, 1254}, new int[]{3749, 3751, 3751, 3749}, 4 - ), - NpcID.FARMING_GARDENER_SPIRIT_TREE_5), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_K, PatchImplementation.FRUIT_TREE, new WorldPoint(1243, 3757, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_SPIRIT_TREE_5), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_K, PatchImplementation.FRUIT_TREE, new WorldPoint(1243, 3757, 0), new Polygon( new int[]{1242, 1242, 1243, 1243}, new int[]{3758, 3759, 3758, 3758}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_T3), - new FarmingPatch("Anima", VarbitID.FARMING_TRANSMIT_M, PatchImplementation.ANIMA, new WorldPoint(1233, 3725, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_T3), + new FarmingPatch("Anima", VarbitID.FARMING_TRANSMIT_M, PatchImplementation.ANIMA, new WorldPoint(1233, 3725, 0), new Polygon( new int[]{1231, 1231, 1233, 1233}, new int[]{3722, 3724, 3724, 3722}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_L, PatchImplementation.CELASTRUS, new WorldPoint(1245, 3752, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_L, PatchImplementation.CELASTRUS, new WorldPoint(1245, 3752, 0), new Polygon( new int[]{1243, 1243, 1245, 1245}, new int[]{3749, 3751, 3751, 3749}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_CELASTRUS), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_I, PatchImplementation.REDWOOD, new WorldPoint(1233, 3752, 0), - new Polygon( + ), NpcID.FARMING_GARDENER_FARMGUILD_CELASTRUS), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_I, PatchImplementation.REDWOOD, new WorldPoint(1233, 3752, 0), new Polygon( new int[]{1225, 1225, 1232, 1232}, new int[]{3751, 3758, 3758, 3751}, 4 - ), - NpcID.FARMING_GARDENER_FARMGUILD_REDWOOD) - )); + ), NpcID.FARMING_GARDENER_FARMGUILD_REDWOOD) + ), 5177, 5178, 5179, 4921, 4923, 4665, 4666, 4667); //All of Prifddinas, and all of Prifddinas Underground - add(new FarmingRegion("Prifddinas", 13151, false, Set.of(12895, 12894, 13150, 12994, 12993, 12737, 12738, 12126, 12127, 13250), - new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3293, 6105, 0), - new Polygon( + add(new FarmingRegion("Prifddinas", 13151, false, + new FarmingPatch("North", VarbitID.FARMING_TRANSMIT_A, PatchImplementation.ALLOTMENT, new WorldPoint(3293, 6105, 0), new Polygon( new int[]{3288, 3288, 3293, 3293, 3289, 3289}, new int[]{6101, 6104, 6104, 6103, 6103, 6101}, 6 - ), - NpcID.PRIF_GARDENER, 0), - new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3294, 6096, 0), - new Polygon( + ), NpcID.PRIF_GARDENER, 0), + new FarmingPatch("South", VarbitID.FARMING_TRANSMIT_B, PatchImplementation.ALLOTMENT, new WorldPoint(3294, 6096, 0), new Polygon( new int[]{3288, 3288, 3289, 3289, 3293, 3293}, new int[]{6095, 6098, 6098, 6096, 6096, 6095}, 6 - ), - NpcID.PRIF_GARDENER, 1), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3294, 6100, 0), - new Polygon( + ), NpcID.PRIF_GARDENER, 1), + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_C, PatchImplementation.FLOWER, new WorldPoint(3294, 6100, 0), new Polygon( new int[]{3292, 3292, 3293, 3293}, new int[]{6099, 6100, 6100, 6099}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.CRYSTAL_TREE, new WorldPoint(3291, 6117, 0), - new Polygon( + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_E, PatchImplementation.CRYSTAL_TREE, new WorldPoint(3291, 6117, 0), new Polygon( new int[]{3291, 3291, 3292, 3292}, new int[]{6118, 6119, 6119, 6118}, 4 )), - new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.COMPOST, new WorldPoint(3288, 6100, 0)) - )); + new FarmingPatch("", VarbitID.FARMING_TRANSMIT_D, PatchImplementation.COMPOST) + ), 12895, 12894, 13150, + /* Underground */ 12994, 12993, 12737, 12738, 12126, 12127, 13250); // Finalize this.regions = Multimaps.unmodifiableMultimap(this.regions); @@ -787,25 +674,25 @@ public boolean isInBounds(WorldPoint loc) this.tabs = Collections.unmodifiableMap(umtabs); } - private void add(FarmingRegion r) + private void add(FarmingRegion r, int... extraRegions) { regions.put(r.getRegionID(), r); - for (int er : r.getRegionIDs()) + for (int er : extraRegions) { regions.put(er, r); } for (FarmingPatch p : r.getPatches()) { tabs - .computeIfAbsent(p.getImplementation().getTab(), k -> new TreeSet<>(tabSorter)) - .add(p); + .computeIfAbsent(p.getImplementation().getTab(), k -> new TreeSet<>(tabSorter)) + .add(p); } } Collection getRegionsForLocation(WorldPoint location) { return this.regions.get(location.getRegionID()).stream() - .filter(region -> region.isInBounds(location)) - .collect(Collectors.toSet()); + .filter(region -> region.isInBounds(location)) + .collect(Collectors.toSet()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/HerbRun.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/HerbRun.java index cf76611eed..5351434349 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/HerbRun.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/HerbRun.java @@ -26,7 +26,6 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; -import net.runelite.client.plugins.microbot.questhelper.config.ConfigKeys; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.panel.TopLevelPanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.ComplexStateQuestHelper; @@ -40,6 +39,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.QuestState; @@ -77,6 +77,8 @@ public class HerbRun extends ComplexStateQuestHelper // Recommended items ItemRequirement compost; + ItemRequirement enoughCompost; + ItemRequirement bottomlessBucket; ItemRequirement ectophial; ItemRequirement magicSec; ItemRequirement explorerRing2; @@ -87,7 +89,6 @@ public class HerbRun extends ComplexStateQuestHelper ItemRequirement icyBasalt; ItemRequirement stonyBasalt; ItemRequirement farmingGuildTeleport; - ItemRequirement hosidiusHouseTeleport; ItemRequirement hunterWhistle; ItemRequirement harmonyTeleport; ItemRequirement gracefulHood; @@ -109,7 +110,8 @@ public class HerbRun extends ComplexStateQuestHelper QuestRequirement accessToTrollStronghold; SkillRequirement accessToFarmingGuildPatch; QuestRequirement accessToVarlamore; - RuneliteRequirement unlockedBarbarianPlanting; + QuestRequirement accessToMorytania; + VarbitRequirement unlockedBarbarianPlanting; ManualRequirement ardougneEmpty; ManualRequirement catherbyEmpty; @@ -220,8 +222,9 @@ protected void setupRequirements() accessToWeiss = new QuestRequirement(QuestHelperQuest.MAKING_FRIENDS_WITH_MY_ARM, QuestState.FINISHED); accessToTrollStronghold = new QuestRequirement(QuestHelperQuest.MY_ARMS_BIG_ADVENTURE, QuestState.FINISHED); accessToVarlamore = new QuestRequirement(QuestHelperQuest.CHILDREN_OF_THE_SUN, QuestState.FINISHED); + accessToMorytania = new QuestRequirement(QuestHelperQuest.PRIEST_IN_PERIL, QuestState.FINISHED); - unlockedBarbarianPlanting = new RuneliteRequirement(configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_SEED_PLANTING.getKey()); + unlockedBarbarianPlanting = new VarbitRequirement(VarbitID.BRUT_FARMING_PLANTING, Operation.EQUAL, 3, "Unlocked Barbarian Planting"); spade = new ItemRequirement("Spade", ItemID.SPADE); dibber = new ItemRequirement("Seed dibber", ItemID.DIBBER).hideConditioned(unlockedBarbarianPlanting); @@ -247,6 +250,10 @@ protected void setupRequirements() } compost = new ItemRequirement("Compost", ItemCollections.COMPOST); compost.setDisplayMatchedItemName(true); + + bottomlessBucket = new ItemRequirement("Bottomless Compost Bucket", ItemID.BOTTOMLESS_COMPOST_BUCKET_FILLED); + enoughCompost = new ItemRequirements(LogicType.OR, "Compost or bottomless bucket", bottomlessBucket, compost); + ectophial = new ItemRequirement("Ectophial", ItemID.ECTOPHIAL).showConditioned(new QuestRequirement(QuestHelperQuest.GHOSTS_AHOY, QuestState.FINISHED)); ectophial.addAlternates(ItemID.ECTOPHIAL_EMPTY); magicSec = new ItemRequirement("Magic secateurs", ItemID.FAIRY_ENCHANTED_SECATEURS).showConditioned(new QuestRequirement(QuestHelperQuest.FAIRYTALE_I__GROWING_PAINS, QuestState.FINISHED)); @@ -256,20 +263,19 @@ protected void setupRequirements() ardyCloak2.addAlternates(ItemID.ARDY_CAPE_HARD, ItemID.ARDY_CAPE_ELITE); xericsTalisman = new ItemRequirement("Xeric's talisman", ItemID.XERIC_TALISMAN); - hosidiusHouseTeleport = new ItemRequirement("Teleport to Hosidius House", ItemID.NZONE_TELETAB_KOUREND); - hosidiusHouseTeleport.addAlternates(ItemID.XERIC_TALISMAN); + xericsTalisman.addAlternates(ItemID.NZONE_TELETAB_KOUREND); var catherbyRunes = new ItemRequirements("Catherby teleport runes", new ItemRequirement("Law rune", ItemID.LAWRUNE), new ItemRequirement("Air rune", ItemID.AIRRUNE, 5)); var catherbyTablet = new ItemRequirement("Catherby tablet", ItemID.LUNAR_TABLET_CATHERBY_TELEPORT); - catherbyTeleport = new ItemRequirements(LogicType.OR, "Catherby teleport", catherbyRunes, catherbyTablet); + catherbyTeleport = new ItemRequirements(LogicType.OR, "Catherby teleport", catherbyTablet, catherbyRunes); var trollheimRunes = new ItemRequirements("Trollheim teleport runes", new ItemRequirement("Law rune", ItemID.LAWRUNE, 2), new ItemRequirement("Fire rune", ItemID.FIRERUNE, 2)); var trollheimTablet = new ItemRequirement("Trollheim tablet", ItemID.NZONE_TELETAB_TROLLHEIM); - trollheimTeleport = new ItemRequirements(LogicType.OR, "Trollheim teleport", trollheimRunes, trollheimTablet) - .hideConditioned(new QuestRequirement(QuestHelperQuest.MAKING_FRIENDS_WITH_MY_ARM, QuestState.FINISHED)); + trollheimTeleport = new ItemRequirements(LogicType.OR, "Trollheim teleport", trollheimTablet, trollheimRunes) + .showConditioned(new QuestRequirement(QuestHelperQuest.MAKING_FRIENDS_WITH_MY_ARM, QuestState.FINISHED)); icyBasalt = new ItemRequirement("Icy basalt", ItemID.WEISS_TELEPORT_BASALT).showConditioned(new QuestRequirement(QuestHelperQuest.MAKING_FRIENDS_WITH_MY_ARM, QuestState.FINISHED)); stonyBasalt = new ItemRequirement("Stony basalt", ItemID.STRONGHOLD_TELEPORT_BASALT).showConditioned(new QuestRequirement(QuestHelperQuest.MAKING_FRIENDS_WITH_MY_ARM, QuestState.FINISHED)); @@ -279,7 +285,7 @@ protected void setupRequirements() farmingGuildTeleport.addAlternates(ItemCollections.SKILLS_NECKLACES); farmingGuildTeleport.addAlternates(ItemCollections.FAIRY_STAFF); - harmonyTeleport = new ItemRequirement("Harmony Teleport", ItemID.TELETAB_HARMONY); + harmonyTeleport = new ItemRequirement("Harmony Teleport", ItemID.TELETAB_HARMONY).showConditioned(accessToHarmony); hunterWhistle = new ItemRequirement("Quetzal whistle", ItemID.HG_QUETZALWHISTLE_PERFECTED).showConditioned(accessToVarlamore); hunterWhistle.addAlternates(ItemID.HG_QUETZALWHISTLE_BASIC); @@ -370,7 +376,7 @@ public void setupSteps() faladorPlant.addIcon(ItemID.RANARR_SEED); faladorPatch.addSubSteps(faladorPlant); - hosidiusPlant = new ObjectStep(this, ObjectID.FARMING_HERB_PATCH_6, new WorldPoint(1738, 3550, 0), "Plant your seeds into the Hosidius patch.", hosidiusHouseTeleport); + hosidiusPlant = new ObjectStep(this, ObjectID.FARMING_HERB_PATCH_6, new WorldPoint(1738, 3550, 0), "Plant your seeds into the Hosidius patch.", xericsTalisman); hosidiusPlant.addIcon(ItemID.RANARR_SEED); hosidiusPatch.addSubSteps(hosidiusPlant); @@ -385,6 +391,7 @@ public void setupSteps() harmonyPatch.addSubSteps(harmonyPlant); morytaniaPlant = new ObjectStep(this, ObjectID.FARMING_HERB_PATCH_4, new WorldPoint(3605, 3529, 0), "Plant your seeds into the Morytania patch.", ectophial); + morytaniaPlant.conditionToHideInSidebar(new Conditions(LogicType.NOR, accessToMorytania)); morytaniaPlant.addIcon(ItemID.RANARR_SEED); morytaniaPatch.addSubSteps(morytaniaPlant); @@ -423,8 +430,8 @@ public QuestStep loadStep() steps.addStep(catherbyReady, catherbyPatch); steps.addStep(catherbyEmpty, catherbyPlant); - steps.addStep(morytaniaReady, morytaniaPatch); - steps.addStep(morytaniaEmpty, morytaniaPlant); + steps.addStep(new Conditions(accessToMorytania, morytaniaReady), morytaniaPatch); + steps.addStep(new Conditions(accessToMorytania, morytaniaEmpty), morytaniaPlant); steps.addStep(hosidiusReady, hosidiusPatch); steps.addStep(hosidiusEmpty, hosidiusPlant); @@ -566,7 +573,7 @@ public List getItemRequirements() @Override public List getItemRecommended() { - return Arrays.asList(compost, ectophial, magicSec, explorerRing2, ardyCloak2, xericsTalisman, hosidiusHouseTeleport, catherbyTeleport, + return Arrays.asList(enoughCompost, ectophial, magicSec, explorerRing2, ardyCloak2, xericsTalisman, catherbyTeleport, trollheimTeleport, icyBasalt, stonyBasalt, farmingGuildTeleport, hunterWhistle, harmonyTeleport, gracefulOutfit, farmersOutfit); } @@ -588,11 +595,11 @@ private void prepopulateSidebarPanels() new PanelDetails("Falador", Collections.singletonList(faladorPatch)).withId(1), new PanelDetails("Ardougne", Collections.singletonList(ardougnePatch)).withId(2), new PanelDetails("Catherby", Collections.singletonList(catherbyPatch)).withId(3), - new PanelDetails("Morytania", Collections.singletonList(morytaniaPatch)).withId(4), + new PanelDetails("Morytania", Collections.singletonList(morytaniaPatch)).withId(4).withHideCondition(nor(accessToMorytania)), new PanelDetails("Hosidius", Collections.singletonList(hosidiusPatch)).withId(5), - new PanelDetails("Varlamore", Collections.singletonList(varlamorePatch)).withId(6), - new PanelDetails("Troll Stronghold", Collections.singletonList(trollStrongholdPatch)).withId(7), - new PanelDetails("Weiss", Collections.singletonList(weissPatch)).withId(8), + new PanelDetails("Varlamore", Collections.singletonList(varlamorePatch)).withId(6).withHideCondition(nor(accessToVarlamore)), + new PanelDetails("Troll Stronghold", Collections.singletonList(trollStrongholdPatch)).withId(7).withHideCondition(nor(accessToTrollStronghold)), + new PanelDetails("Weiss", Collections.singletonList(weissPatch)).withId(8).withHideCondition(nor(accessToWeiss)), new PanelDetails("Harmony Island", Collections.singletonList(harmonyPatch)).withId(9).withHideCondition(nor(accessToHarmony)) ); allSteps.add(farmRunSidebar); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PatchImplementation.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PatchImplementation.java index f7a1c2e1fb..226f95622f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PatchImplementation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PatchImplementation.java @@ -24,13 +24,12 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns; +import javax.annotation.Nullable; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.runelite.client.plugins.timetracking.Tab; import net.runelite.client.plugins.timetracking.farming.Produce; -import javax.annotation.Nullable; - @RequiredArgsConstructor @Getter public enum PatchImplementation @@ -1261,7 +1260,7 @@ PatchState forVarbitValue(int value) if (value == 33) { // Apple tree stump[Clear,Inspect,Guide] 7961 - return new PatchState(Produce.APPLE, CropState.HARVESTABLE, 0); + return new PatchState(Produce.APPLE, CropState.STUMP, 0); } if (value == 34) { @@ -1291,7 +1290,7 @@ PatchState forVarbitValue(int value) if (value == 60) { // Banana tree stump[Clear,Inspect,Guide] 8019 - return new PatchState(Produce.BANANA, CropState.HARVESTABLE, 0); + return new PatchState(Produce.BANANA, CropState.STUMP, 0); } if (value == 61) { @@ -1331,7 +1330,7 @@ PatchState forVarbitValue(int value) if (value == 97) { // Orange tree stump[Clear,Inspect,Guide] 8077 - return new PatchState(Produce.ORANGE, CropState.HARVESTABLE, 0); + return new PatchState(Produce.ORANGE, CropState.STUMP, 0); } if (value == 98) { @@ -1361,7 +1360,7 @@ PatchState forVarbitValue(int value) if (value == 124) { // Curry tree stump[Clear,Inspect,Guide] 8046 - return new PatchState(Produce.CURRY, CropState.HARVESTABLE, 0); + return new PatchState(Produce.CURRY, CropState.STUMP, 0); } if (value == 125) { @@ -1396,7 +1395,7 @@ PatchState forVarbitValue(int value) if (value == 161) { // Pineapple plant stump[Clear,Inspect,Guide] 7992 - return new PatchState(Produce.PINEAPPLE, CropState.HARVESTABLE, 0); + return new PatchState(Produce.PINEAPPLE, CropState.STUMP, 0); } if (value == 162) { @@ -1426,7 +1425,7 @@ PatchState forVarbitValue(int value) if (value == 188) { // Papaya tree stump[Clear,Inspect,Guide] 8131 - return new PatchState(Produce.PAPAYA, CropState.HARVESTABLE, 0); + return new PatchState(Produce.PAPAYA, CropState.STUMP, 0); } if (value == 189) { @@ -1461,7 +1460,7 @@ PatchState forVarbitValue(int value) if (value == 225) { // Palm tree stump[Clear,Inspect,Guide] 8104 - return new PatchState(Produce.PALM, CropState.HARVESTABLE, 0); + return new PatchState(Produce.PALM, CropState.STUMP, 0); } if (value == 226) { @@ -1491,7 +1490,7 @@ PatchState forVarbitValue(int value) if (value == 252) { // Dragonfruit tree stump[Clear,Inspect,Guide] 34034 - return new PatchState(Produce.DRAGONFRUIT, CropState.HARVESTABLE, 0); + return new PatchState(Produce.DRAGONFRUIT, CropState.STUMP, 0); } if (value == 253) { @@ -1867,7 +1866,7 @@ PatchState forVarbitValue(int value) if (value == 14) { // Oak tree stump[Clear,Inspect,Guide] 8468 - return new PatchState(Produce.OAK, CropState.HARVESTABLE, 0); + return new PatchState(Produce.OAK, CropState.STUMP, 0); } if (value >= 15 && value <= 20) { @@ -1887,7 +1886,7 @@ PatchState forVarbitValue(int value) if (value == 23) { // Willow tree stump[Clear,Inspect,Guide] 8489 - return new PatchState(Produce.WILLOW, CropState.HARVESTABLE, 0); + return new PatchState(Produce.WILLOW, CropState.STUMP, 0); } if (value >= 24 && value <= 31) { @@ -1907,7 +1906,7 @@ PatchState forVarbitValue(int value) if (value == 34) { // Tree stump[Clear,Inspect,Guide] 8445 - return new PatchState(Produce.MAPLE, CropState.HARVESTABLE, 0); + return new PatchState(Produce.MAPLE, CropState.STUMP, 0); } if (value >= 35 && value <= 44) { @@ -1927,7 +1926,7 @@ PatchState forVarbitValue(int value) if (value == 47) { // Yew tree stump[Clear,Inspect,Guide] 8514 - return new PatchState(Produce.YEW, CropState.HARVESTABLE, 0); + return new PatchState(Produce.YEW, CropState.STUMP, 0); } if (value >= 48 && value <= 59) { @@ -1947,7 +1946,7 @@ PatchState forVarbitValue(int value) if (value == 62) { // Magic Tree Stump[Clear,Inspect,Guide] 8410 - return new PatchState(Produce.MAGIC, CropState.HARVESTABLE, 0); + return new PatchState(Produce.MAGIC, CropState.STUMP, 0); } if (value >= 63 && value <= 72) { @@ -2150,7 +2149,7 @@ PatchState forVarbitValue(int value) if (value == 17) { // Tree stump[Clear,Inspect,Guide] 30446 - return new PatchState(Produce.TEAK, CropState.HARVESTABLE, 0); + return new PatchState(Produce.TEAK, CropState.STUMP, 0); } if (value >= 18 && value <= 23) { @@ -2180,7 +2179,7 @@ PatchState forVarbitValue(int value) if (value == 40) { // Mahogany tree stump[Clear,Inspect,Guide] 30418 - return new PatchState(Produce.MAHOGANY, CropState.HARVESTABLE, 0); + return new PatchState(Produce.MAHOGANY, CropState.STUMP, 0); } if (value >= 41 && value <= 47) { @@ -2210,7 +2209,7 @@ PatchState forVarbitValue(int value) if (value == 65) { // Camphor tree stump[Clear,Inspect,Guide] 58724 - return new PatchState(Produce.CAMPHOR, CropState.HARVESTABLE, 0); + return new PatchState(Produce.CAMPHOR, CropState.STUMP, 0); } if (value >= 66 && value <= 72) { @@ -2240,7 +2239,7 @@ PatchState forVarbitValue(int value) if (value == 90) { // Ironwood tree stump[Clear,Inspect,Guide] 58755 - return new PatchState(Produce.IRONWOOD, CropState.HARVESTABLE, 0); + return new PatchState(Produce.IRONWOOD, CropState.STUMP, 0); } if (value >= 91 && value <= 97) { @@ -2270,7 +2269,7 @@ PatchState forVarbitValue(int value) if (value == 116) { // Rosewood tree stump[Clear,Inspect,Guide] 58786 - return new PatchState(Produce.ROSEWOOD, CropState.HARVESTABLE, 0); + return new PatchState(Produce.ROSEWOOD, CropState.STUMP, 0); } if (value >= 117 && value <= 124) { @@ -2751,7 +2750,7 @@ PatchState forVarbitValue(int value) if (value == 28) { // Celastrus tree stump[Clear,Inspect,Guide] 33721 - return new PatchState(Produce.CELASTRUS, CropState.HARVESTABLE, 0); + return new PatchState(Produce.CELASTRUS, CropState.STUMP, 0); } if (value >= 29 && value <= 255) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PaymentTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PaymentTracker.java index e60d07530c..f3086e0569 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PaymentTracker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/PaymentTracker.java @@ -24,15 +24,14 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns; +import javax.inject.Inject; +import javax.inject.Singleton; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.timetracking.TimeTrackingConfig; -import javax.inject.Inject; -import javax.inject.Singleton; - @Slf4j @RequiredArgsConstructor( access = AccessLevel.PRIVATE, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/TreeRun.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/TreeRun.java index be0e8318a0..0fd0dcbaee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/TreeRun.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/farmruns/TreeRun.java @@ -28,7 +28,13 @@ import com.google.inject.Inject; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; -import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.*; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.FruitTreeSapling; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.GracefulOrFarming; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.HardwoodTreeSapling; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.TreeSapling; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.CalquatTreeSapling; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.PayOrCut; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.FarmingUtils.PayOrCompost; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.panel.TopLevelPanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.ComplexStateQuestHelper; @@ -46,6 +52,8 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.client.plugins.microbot.questhelper.steps.widget.LunarSpells; import net.runelite.client.plugins.microbot.questhelper.steps.widget.NormalSpells; +import java.util.Set; + import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; import net.runelite.api.QuestState; import net.runelite.api.Skill; @@ -56,11 +64,9 @@ import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.timetracking.Tab; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; @@ -71,6 +77,8 @@ * */ public class TreeRun extends ComplexStateQuestHelper { + private static final String TREE_PROTECTION_DIALOG = "Would you look after my crops for me?"; + @Inject private FarmingWorld farmingWorld; @@ -88,6 +96,9 @@ public class TreeRun extends ComplexStateQuestHelper DetailedQuestStep farmingGuildTreePatchCheckHealth, lumbridgeTreePatchCheckHealth, faladorTreePatchCheckHealth, taverleyTreePatchCheckHealth, varrockTreePatchCheckHealth, gnomeStrongholdTreePatchCheckHealth, auburnvaleTreePatchCheckHealth; + DetailedQuestStep farmingGuildTreePatchCutDown, lumbridgeTreePatchCutDown, faladorTreePatchCutDown, + taverleyTreePatchCutDown, varrockTreePatchCutDown, gnomeStrongholdTreePatchCutDown, + auburnvaleTreePatchCutDown; DetailedQuestStep farmingGuildTreePatchPlant, lumbridgeTreePatchPlant, faladorTreePatchPlant, taverleyTreePatchPlant, varrockTreePatchPlant, gnomeStrongholdTreePatchPlant, auburnvaleTreePatchPlant; @@ -118,6 +129,10 @@ public class TreeRun extends ComplexStateQuestHelper DetailedQuestStep farmingGuildFruitTreePatchDig, gnomeStrongholdFruitTreePatchDig, gnomeVillageFruitTreePatchDig, brimhavenFruitTreePatchDig, lletyaFruitTreePatchDig, catherbyFruitTreePatchDig, taiBwoWannaiCalquatPatchDig, kastoriFruitTreePatchDig, kastoriCalquatPatchDig, greatConchCalquatPatchDig; + DetailedQuestStep farmingGuildFruitTreePatchCutDown, gnomeStrongholdFruitTreePatchCutDown, gnomeVillageFruitTreePatchCutDown, + brimhavenFruitTreePatchCutDown, lletyaFruitTreePatchCutDown, catherbyFruitTreePatchCutDown, + kastoriFruitTreePatchCutDown; + DetailedQuestStep taiBwoWannaiCalquatPatchRemove, kastoriCalquatPatchRemove, greatConchCalquatPatchRemove; DetailedQuestStep guildFruitProtect, strongholdFruitProtect, villageFruitProtect, brimhavenFruitProtect, lletyaFruitProtect, catherbyFruitProtect, taiBwoWannaiCalquatProtect, kastoriFruitProtect, @@ -133,6 +148,8 @@ public class TreeRun extends ComplexStateQuestHelper DetailedQuestStep eastHardwoodTreePatchClear, westHardwoodTreePatchClear, middleHardwoodTreePatchClear, savannahClear, anglersClear; + DetailedQuestStep eastHardwoodTreePatchCutDown, westHardwoodTreePatchCutDown, middleHardwoodTreePatchCutDown, + savannahCutDown, anglersCutDown; DetailedQuestStep eastHardwoodProtect, westHardwoodProtect, middleHardwoodProtect, savannahProtect, anglersProtect; @@ -165,15 +182,17 @@ public class TreeRun extends ComplexStateQuestHelper gnomeStrongholdTreeStates, auburnvaleStates; PatchStates gnomeStrongholdFruitStates, gnomeVillageStates, brimhavenStates, catherbyStates, lletyaStates, - farmingGuildFruitStates, taiBwoWannaiStates, kastoriStates, greatConchStates; + farmingGuildFruitStates, taiBwoWannaiStates, kastoriFruitStates, kastoriCalquatStates, greatConchStates; PatchStates eastHardwoodStates, middleHardwoodStates, westHardwoodStates, savannahStates, anglersRetreatStates; Requirement allGrowing; - ConditionalStep farmingGuildStep, lumbridgeStep, varrockStep, faladorStep, taverleyStep, strongholdStep, - villageStep, lletyaStep, catherbyStep, brimhavenStep, fossilIslandStep, savannahStep, auburnvaleStep, - kastoriStep, anglersRetreatStep, greatConchStep; + ReorderableConditionalStep farmingGuildStep, strongholdStep, karamjaStep, fossilIslandStep, kastoriStep; + ConditionalStep farmingGuildTreeStep, farmingGuildFruitStep, lumbridgeStep, varrockStep, faladorStep, taverleyStep, + strongholdTreeStep, strongholdFruitStep, villageStep, lletyaStep, catherbyStep, brimhavenStep, + taiBwoWannaiStep, fossilIslandEastStep, fossilIslandMiddleStep, fossilIslandWestStep, savannahStep, + auburnvaleStep, kastoriFruitStep, kastoriCalquatStep, anglersRetreatStep, greatConchStep; private final String PAY_OR_CUT = "payOrCutTree"; private final String PAY_OR_COMPOST = "payOrCompostTree"; @@ -193,194 +212,216 @@ public QuestStep loadStep() // Varrock -> Gnome Stronghold Fruit -> Gnome Stronghold Tree -> Gnome Village -> catherby // -> Brimhaven -> lletya -> east hardwood -> middle hardwood -> west hardwood. - farmingGuildStep = new ConditionalStep(this, farmingGuildTreePatchCheckHealth); - farmingGuildStep.addStep(farmingGuildTreeStates.getIsUnchecked(), farmingGuildTreePatchCheckHealth); - farmingGuildStep.addStep(farmingGuildTreeStates.getIsHarvestable(), farmingGuildTreePatchClear); - farmingGuildStep.addStep(farmingGuildTreeStates.getIsStump(), farmingGuildTreePatchDig); - farmingGuildStep.addStep(farmingGuildTreeStates.getIsEmpty(), farmingGuildTreePatchPlant); - farmingGuildStep.addStep(nor(farmingGuildTreeStates.getIsProtected(), usingCompostorNothing), farmingGuildTreePayForProtection); - - farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsUnchecked()), farmingGuildFruitTreePatchCheckHealth); - farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsHarvestable()), farmingGuildFruitTreePatchClear); - farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsStump()), farmingGuildFruitTreePatchDig); - farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsEmpty()), farmingGuildFruitTreePatchPlant); - farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, nor(farmingGuildFruitStates.getIsProtected(), usingCompostorNothing)), guildFruitProtect); - - steps.addStep(and(accessToFarmingGuildTreePatch, nand(farmingGuildTreeStates.getIsGrowing(), - farmingGuildFruitStates.getIsGrowing())), farmingGuildStep.withId(0)); + farmingGuildTreeStep = (ConditionalStep) new ConditionalStep(this, farmingGuildTreePatchCheckHealth).withId(-1); + farmingGuildTreeStep.addStep(farmingGuildTreeStates.getIsUnchecked(), farmingGuildTreePatchCheckHealth); + farmingGuildTreeStep.addStep(farmingGuildTreeStates.getIsStump(), farmingGuildTreePatchDig); + farmingGuildTreeStep.addStep(and(farmingGuildTreeStates.getIsHarvestable(), not(payingForRemoval)), farmingGuildTreePatchCutDown); + farmingGuildTreeStep.addStep(farmingGuildTreeStates.getIsHarvestable(), farmingGuildTreePatchClear); + farmingGuildTreeStep.addStep(farmingGuildTreeStates.getIsEmpty(), farmingGuildTreePatchPlant); + farmingGuildTreeStep.addStep(nor(farmingGuildTreeStates.getIsProtected(), usingCompostorNothing), farmingGuildTreePayForProtection); + + // TODO: Ideally we should allow for null steps to be rejected and propagate up conditionalstep chains + farmingGuildStep = new ReorderableConditionalStep(this, new DetailedQuestStep(this, "Unreachable.")); + farmingGuildStep.addStep(not(farmingGuildTreeStates.getIsGrowing()), farmingGuildTreeStep); + + farmingGuildFruitStep = (ConditionalStep) new ConditionalStep(this, farmingGuildFruitTreePatchCheckHealth).withId(-2); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsUnchecked()), farmingGuildFruitTreePatchCheckHealth); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsHarvestable(), not(payingForRemoval)), farmingGuildFruitTreePatchCutDown); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsHarvestable()), farmingGuildFruitTreePatchClear); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsStump()), farmingGuildFruitTreePatchDig); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, farmingGuildFruitStates.getIsEmpty()), farmingGuildFruitTreePatchPlant); + farmingGuildFruitStep.addStep(and(accessToFarmingGuildFruitTreePatch, nor(farmingGuildFruitStates.getIsProtected(), usingCompostorNothing)), guildFruitProtect); + farmingGuildStep.addStep(and(accessToFarmingGuildFruitTreePatch, not(farmingGuildFruitStates.getIsGrowing())), farmingGuildFruitStep); + steps.addStep(or(and(accessToFarmingGuildTreePatch, not(farmingGuildTreeStates.getIsGrowing())), and(accessToFarmingGuildFruitTreePatch, not(farmingGuildFruitStates.getIsGrowing()))), farmingGuildStep.withId(0)); lumbridgeStep = new ConditionalStep(this, lumbridgeTreePatchCheckHealth); lumbridgeStep.addStep(lumbridgeStates.getIsUnchecked(), lumbridgeTreePatchCheckHealth); + lumbridgeStep.addStep(and(lumbridgeStates.getIsHarvestable(), not(payingForRemoval)), lumbridgeTreePatchCutDown); lumbridgeStep.addStep(lumbridgeStates.getIsEmpty(), lumbridgeTreePatchPlant); lumbridgeStep.addStep(lumbridgeStates.getIsHarvestable(), lumbridgeTreePatchClear); lumbridgeStep.addStep(lumbridgeStates.getIsStump(), lumbridgeTreePatchDig); lumbridgeStep.addStep(nor(usingCompostorNothing, lumbridgeStates.getIsProtected()), lumbridgeTreeProtect); - - steps.addStep(nor(lumbridgeStates.getIsGrowing()), lumbridgeStep.withId(1)); + steps.addStep(not(lumbridgeStates.getIsGrowing()), lumbridgeStep.withId(1)); faladorStep = new ConditionalStep(this, faladorTreePatchCheckHealth); faladorStep.addStep(faladorStates.getIsUnchecked(), faladorTreePatchCheckHealth); + faladorStep.addStep(and(faladorStates.getIsHarvestable(), not(payingForRemoval)), faladorTreePatchCutDown); faladorStep.addStep(faladorStates.getIsEmpty(), faladorTreePatchPlant); faladorStep.addStep(faladorStates.getIsHarvestable(), faladorTreePatchClear); faladorStep.addStep(faladorStates.getIsStump(), faladorTreePatchDig); faladorStep.addStep(nor(usingCompostorNothing, faladorStates.getIsProtected()), faladorTreeProtect); - - steps.addStep(nor(faladorStates.getIsGrowing()), faladorStep.withId(2)); + steps.addStep(not(faladorStates.getIsGrowing()), faladorStep.withId(2)); taverleyStep = new ConditionalStep(this, taverleyTreePatchCheckHealth); taverleyStep.addStep(taverleyStates.getIsUnchecked(), taverleyTreePatchCheckHealth); + taverleyStep.addStep(and(taverleyStates.getIsHarvestable(), not(payingForRemoval)), taverleyTreePatchCutDown); taverleyStep.addStep(taverleyStates.getIsEmpty(), taverleyTreePatchPlant); taverleyStep.addStep(taverleyStates.getIsHarvestable(), taverleyTreePatchClear); taverleyStep.addStep(taverleyStates.getIsStump(), taverleyTreePatchDig); taverleyStep.addStep(nor(usingCompostorNothing, taverleyStates.getIsProtected()), taverleyTreeProtect); - - steps.addStep(nor(taverleyStates.getIsGrowing()), taverleyStep.withId(3)); + steps.addStep(not(taverleyStates.getIsGrowing()), taverleyStep.withId(3)); varrockStep = new ConditionalStep(this, varrockTreePatchCheckHealth); varrockStep.addStep(varrockStates.getIsUnchecked(), varrockTreePatchCheckHealth); + varrockStep.addStep(and(varrockStates.getIsHarvestable(), not(payingForRemoval)), varrockTreePatchCutDown); varrockStep.addStep(varrockStates.getIsEmpty(), varrockTreePatchPlant); varrockStep.addStep(varrockStates.getIsHarvestable(), varrockTreePatchClear); varrockStep.addStep(varrockStates.getIsStump(), varrockTreePatchDig); varrockStep.addStep(nor(usingCompostorNothing, varrockStates.getIsProtected()), varrockTreeProtect); - - steps.addStep(nor(varrockStates.getIsGrowing()), varrockStep.withId(4)); - - strongholdStep = new ConditionalStep(this, gnomeStrongholdFruitTreePatchCheckHealth); - strongholdStep.addStep(gnomeStrongholdFruitStates.getIsUnchecked(), gnomeStrongholdFruitTreePatchCheckHealth); - strongholdStep.addStep(gnomeStrongholdFruitStates.getIsEmpty(), gnomeStrongholdFruitTreePatchPlant); - strongholdStep.addStep(gnomeStrongholdFruitStates.getIsHarvestable(), gnomeStrongholdFruitTreePatchClear); - strongholdStep.addStep(gnomeStrongholdFruitStates.getIsStump(), gnomeStrongholdFruitTreePatchDig); - strongholdStep.addStep(nor(usingCompostorNothing, gnomeStrongholdFruitStates.getIsProtected()), strongholdFruitProtect); - - strongholdStep.addStep(gnomeStrongholdTreeStates.getIsUnchecked(), gnomeStrongholdTreePatchCheckHealth); - strongholdStep.addStep(gnomeStrongholdTreeStates.getIsEmpty(), gnomeStrongholdTreePatchPlant); - strongholdStep.addStep(gnomeStrongholdTreeStates.getIsHarvestable(), gnomeStrongholdTreePatchClear); - strongholdStep.addStep(gnomeStrongholdTreeStates.getIsStump(), gnomeStrongholdTreePatchDig); - strongholdStep.addStep(nor(usingCompostorNothing, gnomeStrongholdTreeStates.getIsProtected()), strongholdTreeProtect); - - steps.addStep(nand(gnomeStrongholdTreeStates.getIsGrowing(), - gnomeStrongholdFruitStates.getIsGrowing()), strongholdStep.withId(5)); + steps.addStep(not(varrockStates.getIsGrowing()), varrockStep.withId(4)); + + strongholdFruitStep = (ConditionalStep) new ConditionalStep(this, gnomeStrongholdFruitTreePatchCheckHealth).withId(51); + strongholdFruitStep.addStep(gnomeStrongholdFruitStates.getIsUnchecked(), gnomeStrongholdFruitTreePatchCheckHealth); + strongholdFruitStep.addStep(and(gnomeStrongholdFruitStates.getIsHarvestable(), not(payingForRemoval)), gnomeStrongholdFruitTreePatchCutDown); + strongholdFruitStep.addStep(gnomeStrongholdFruitStates.getIsEmpty(), gnomeStrongholdFruitTreePatchPlant); + strongholdFruitStep.addStep(gnomeStrongholdFruitStates.getIsHarvestable(), gnomeStrongholdFruitTreePatchClear); + strongholdFruitStep.addStep(gnomeStrongholdFruitStates.getIsStump(), gnomeStrongholdFruitTreePatchDig); + strongholdFruitStep.addStep(nor(usingCompostorNothing, gnomeStrongholdFruitStates.getIsProtected()), strongholdFruitProtect); + strongholdStep = new ReorderableConditionalStep(this, new DetailedQuestStep(this, "Unreachable.")); + strongholdStep.addStep(not(gnomeStrongholdFruitStates.getIsGrowing()), strongholdFruitStep); + strongholdTreeStep = (ConditionalStep) new ConditionalStep(this, gnomeStrongholdTreePatchCheckHealth).withId(52); + strongholdTreeStep.addStep(gnomeStrongholdTreeStates.getIsUnchecked(), gnomeStrongholdTreePatchCheckHealth); + strongholdTreeStep.addStep(and(gnomeStrongholdTreeStates.getIsHarvestable(), not(payingForRemoval)), gnomeStrongholdTreePatchCutDown); + strongholdTreeStep.addStep(gnomeStrongholdTreeStates.getIsEmpty(), gnomeStrongholdTreePatchPlant); + strongholdTreeStep.addStep(gnomeStrongholdTreeStates.getIsHarvestable(), gnomeStrongholdTreePatchClear); + strongholdTreeStep.addStep(gnomeStrongholdTreeStates.getIsStump(), gnomeStrongholdTreePatchDig); + strongholdTreeStep.addStep(nor(usingCompostorNothing, gnomeStrongholdTreeStates.getIsProtected()), strongholdTreeProtect); + strongholdStep.addStep(not(gnomeStrongholdTreeStates.getIsGrowing()), strongholdTreeStep); + steps.addStep(nand(gnomeStrongholdFruitStates.getIsGrowing(), gnomeStrongholdTreeStates.getIsGrowing()), strongholdStep.withId(5)); villageStep = new ConditionalStep(this, gnomeVillageFruitTreePatchCheckHealth); villageStep.addStep(gnomeVillageStates.getIsUnchecked(), gnomeVillageFruitTreePatchCheckHealth); + villageStep.addStep(and(gnomeVillageStates.getIsHarvestable(), not(payingForRemoval)), gnomeVillageFruitTreePatchCutDown); villageStep.addStep(gnomeVillageStates.getIsEmpty(), gnomeVillageFruitTreePatchPlant); villageStep.addStep(gnomeVillageStates.getIsHarvestable(), gnomeVillageFruitTreePatchClear); villageStep.addStep(gnomeVillageStates.getIsStump(), gnomeVillageFruitTreePatchDig); villageStep.addStep(nor(usingCompostorNothing, gnomeVillageStates.getIsProtected()), villageFruitProtect); - - steps.addStep(nor(gnomeVillageStates.getIsGrowing()), villageStep.withId(6)); + steps.addStep(not(gnomeVillageStates.getIsGrowing()), villageStep.withId(6)); catherbyStep = new ConditionalStep(this, catherbyFruitTreePatchCheckHealth); catherbyStep.addStep(catherbyStates.getIsUnchecked(), catherbyFruitTreePatchCheckHealth); + catherbyStep.addStep(and(catherbyStates.getIsHarvestable(), not(payingForRemoval)), catherbyFruitTreePatchCutDown); catherbyStep.addStep(catherbyStates.getIsEmpty(), catherbyFruitTreePatchPlant); catherbyStep.addStep(catherbyStates.getIsHarvestable(), catherbyFruitTreePatchClear); catherbyStep.addStep(catherbyStates.getIsStump(), catherbyFruitTreePatchDig); catherbyStep.addStep(nor(usingCompostorNothing, catherbyStates.getIsProtected()), catherbyFruitProtect); + steps.addStep(not(catherbyStates.getIsGrowing()), catherbyStep.withId(7)); - steps.addStep(nor(catherbyStates.getIsGrowing()), catherbyStep.withId(7)); - - brimhavenStep = new ConditionalStep(this, brimhavenFruitTreePatchCheckHealth); + brimhavenStep = (ConditionalStep) new ConditionalStep(this, brimhavenFruitTreePatchCheckHealth).withId(81); brimhavenStep.addStep(brimhavenStates.getIsUnchecked(), brimhavenFruitTreePatchCheckHealth); + brimhavenStep.addStep(and(brimhavenStates.getIsHarvestable(), not(payingForRemoval)), brimhavenFruitTreePatchCutDown); brimhavenStep.addStep(brimhavenStates.getIsEmpty(), brimhavenFruitTreePatchPlant); brimhavenStep.addStep(brimhavenStates.getIsHarvestable(), brimhavenFruitTreePatchClear); brimhavenStep.addStep(brimhavenStates.getIsStump(), brimhavenFruitTreePatchDig); brimhavenStep.addStep(nor(usingCompostorNothing, brimhavenStates.getIsProtected()), brimhavenFruitProtect); - brimhavenStep.addStep(taiBwoWannaiStates.getIsUnchecked(), taiBwoWannaiCalquatPatchCheckHealth); - brimhavenStep.addStep(taiBwoWannaiStates.getIsEmpty(), taiBwoWannaiCalquatPatchPlant); - brimhavenStep.addStep(taiBwoWannaiStates.getIsHarvestable(), taiBwoWannaiCalquatPatchClear); - brimhavenStep.addStep(taiBwoWannaiStates.getIsStump(), taiBwoWannaiCalquatPatchDig); - brimhavenStep.addStep(nor(usingCompostorNothing, taiBwoWannaiStates.getIsProtected()), + karamjaStep = new ReorderableConditionalStep(this, new DetailedQuestStep(this, "Unreachable.")); + karamjaStep.addStep(not(brimhavenStates.getIsGrowing()), brimhavenStep); + + taiBwoWannaiStep = (ConditionalStep) new ConditionalStep(this, taiBwoWannaiCalquatPatchCheckHealth).withId(82); + taiBwoWannaiStep.addStep(taiBwoWannaiStates.getIsUnchecked(), taiBwoWannaiCalquatPatchCheckHealth); + taiBwoWannaiStep.addStep(and(taiBwoWannaiStates.getIsHarvestable(), not(payingForRemoval)), taiBwoWannaiCalquatPatchRemove); + taiBwoWannaiStep.addStep(taiBwoWannaiStates.getIsEmpty(), taiBwoWannaiCalquatPatchPlant); + taiBwoWannaiStep.addStep(taiBwoWannaiStates.getIsHarvestable(), taiBwoWannaiCalquatPatchClear); + taiBwoWannaiStep.addStep(taiBwoWannaiStates.getIsStump(), taiBwoWannaiCalquatPatchDig); + taiBwoWannaiStep.addStep(nor(usingCompostorNothing, taiBwoWannaiStates.getIsProtected()), taiBwoWannaiCalquatProtect); - - steps.addStep(nand(brimhavenStates.getIsGrowing(), taiBwoWannaiStates.getIsGrowing()), brimhavenStep.withId(8)); + karamjaStep.addStep(not(taiBwoWannaiStates.getIsGrowing()), taiBwoWannaiStep); + steps.addStep(nand(brimhavenStates.getIsGrowing(), taiBwoWannaiStates.getIsGrowing()), karamjaStep.withId(8)); lletyaStep = new ConditionalStep(this, lletyaFruitTreePatchCheckHealth); lletyaStep.addStep(lletyaStates.getIsUnchecked(), lletyaFruitTreePatchCheckHealth); + lletyaStep.addStep(and(lletyaStates.getIsHarvestable(), not(payingForRemoval)), lletyaFruitTreePatchCutDown); lletyaStep.addStep(lletyaStates.getIsEmpty(), lletyaFruitTreePatchPlant); lletyaStep.addStep(lletyaStates.getIsHarvestable(), lletyaFruitTreePatchClear); lletyaStep.addStep(lletyaStates.getIsStump(), lletyaFruitTreePatchDig); lletyaStep.addStep(nor(usingCompostorNothing, lletyaStates.getIsProtected()), lletyaFruitProtect); - - steps.addStep(and(accessToLletya, nor(lletyaStates.getIsGrowing())), lletyaStep.withId(9)); - - fossilIslandStep = new ConditionalStep(this, eastHardwoodTreePatchCheckHealth); - fossilIslandStep.addStep(eastHardwoodStates.getIsUnchecked(), eastHardwoodTreePatchCheckHealth); - fossilIslandStep.addStep(eastHardwoodStates.getIsEmpty(), eastHardwoodTreePatchPlant); - fossilIslandStep.addStep(eastHardwoodStates.getIsHarvestable(), eastHardwoodTreePatchClear); - fossilIslandStep.addStep(eastHardwoodStates.getIsStump(), eastHardwoodTreePatchDig); - fossilIslandStep.addStep(nor(usingCompostorNothing, eastHardwoodStates.getIsProtected()), eastHardwoodProtect); - - fossilIslandStep.addStep(middleHardwoodStates.getIsUnchecked(), middleHardwoodTreePatchCheckHealth); - fossilIslandStep.addStep(middleHardwoodStates.getIsEmpty(), middleHardwoodTreePatchPlant); - fossilIslandStep.addStep(middleHardwoodStates.getIsHarvestable(), middleHardwoodTreePatchClear); - fossilIslandStep.addStep(middleHardwoodStates.getIsStump(), middleHardwoodTreePatchDig); - fossilIslandStep.addStep(nor(usingCompostorNothing, middleHardwoodStates.getIsProtected()), middleHardwoodProtect); - - fossilIslandStep.addStep(westHardwoodStates.getIsUnchecked(), westHardwoodTreePatchCheckHealth); - fossilIslandStep.addStep(westHardwoodStates.getIsEmpty(), westHardwoodTreePatchPlant); - fossilIslandStep.addStep(westHardwoodStates.getIsHarvestable(), westHardwoodTreePatchClear); - fossilIslandStep.addStep(westHardwoodStates.getIsStump(), westHardwoodTreePatchDig); - fossilIslandStep.addStep(nor(usingCompostorNothing, westHardwoodStates.getIsProtected()), westHardwoodProtect); - - steps.addStep(and(accessToFossilIsland, - nand(eastHardwoodStates.getIsGrowing(), westHardwoodStates.getIsGrowing(), middleHardwoodStates.getIsGrowing())), - fossilIslandStep.withId(10)); + steps.addStep(and(accessToLletya, not(lletyaStates.getIsGrowing())), lletyaStep.withId(9)); + + fossilIslandEastStep = (ConditionalStep) new ConditionalStep(this, eastHardwoodTreePatchCheckHealth).withId(101); + fossilIslandEastStep.addStep(eastHardwoodStates.getIsUnchecked(), eastHardwoodTreePatchCheckHealth); + fossilIslandEastStep.addStep(and(eastHardwoodStates.getIsHarvestable(), not(payingForRemoval)), eastHardwoodTreePatchCutDown); + fossilIslandEastStep.addStep(eastHardwoodStates.getIsEmpty(), eastHardwoodTreePatchPlant); + fossilIslandEastStep.addStep(eastHardwoodStates.getIsHarvestable(), eastHardwoodTreePatchClear); + fossilIslandEastStep.addStep(eastHardwoodStates.getIsStump(), eastHardwoodTreePatchDig); + fossilIslandEastStep.addStep(nor(usingCompostorNothing, eastHardwoodStates.getIsProtected()), eastHardwoodProtect); + fossilIslandStep = new ReorderableConditionalStep(this, new DetailedQuestStep(this, "Unreachable.")); + fossilIslandStep.addStep(not(eastHardwoodStates.getIsGrowing()), fossilIslandEastStep); + fossilIslandMiddleStep = (ConditionalStep) new ConditionalStep(this, middleHardwoodTreePatchCheckHealth).withId(102); + fossilIslandMiddleStep.addStep(middleHardwoodStates.getIsUnchecked(), middleHardwoodTreePatchCheckHealth); + fossilIslandMiddleStep.addStep(and(middleHardwoodStates.getIsHarvestable(), not(payingForRemoval)), middleHardwoodTreePatchCutDown); + fossilIslandMiddleStep.addStep(middleHardwoodStates.getIsEmpty(), middleHardwoodTreePatchPlant); + fossilIslandMiddleStep.addStep(middleHardwoodStates.getIsHarvestable(), middleHardwoodTreePatchClear); + fossilIslandMiddleStep.addStep(middleHardwoodStates.getIsStump(), middleHardwoodTreePatchDig); + fossilIslandMiddleStep.addStep(nor(usingCompostorNothing, middleHardwoodStates.getIsProtected()), middleHardwoodProtect); + fossilIslandStep.addStep(not(middleHardwoodStates.getIsGrowing()), fossilIslandMiddleStep); + + fossilIslandWestStep = (ConditionalStep) new ConditionalStep(this, westHardwoodTreePatchCheckHealth).withId(103); + fossilIslandWestStep.addStep(westHardwoodStates.getIsUnchecked(), westHardwoodTreePatchCheckHealth); + fossilIslandWestStep.addStep(and(westHardwoodStates.getIsHarvestable(), not(payingForRemoval)), westHardwoodTreePatchCutDown); + fossilIslandWestStep.addStep(westHardwoodStates.getIsEmpty(), westHardwoodTreePatchPlant); + fossilIslandWestStep.addStep(westHardwoodStates.getIsHarvestable(), westHardwoodTreePatchClear); + fossilIslandWestStep.addStep(westHardwoodStates.getIsStump(), westHardwoodTreePatchDig); + fossilIslandWestStep.addStep(nor(usingCompostorNothing, westHardwoodStates.getIsProtected()), westHardwoodProtect); + fossilIslandStep.addStep(not(westHardwoodStates.getIsGrowing()), fossilIslandWestStep); + steps.addStep(and(accessToFossilIsland, nand(eastHardwoodStates.getIsGrowing(), middleHardwoodStates.getIsGrowing(), westHardwoodStates.getIsGrowing())), fossilIslandStep.withId(10)); savannahStep = new ConditionalStep(this, savannahCheckHealth); savannahStep.addStep(savannahStates.getIsUnchecked(), savannahCheckHealth); + savannahStep.addStep(and(savannahStates.getIsHarvestable(), not(payingForRemoval)), savannahCutDown); savannahStep.addStep(savannahStates.getIsEmpty(), savannahPlant); savannahStep.addStep(savannahStates.getIsHarvestable(), savannahClear); savannahStep.addStep(savannahStates.getIsStump(), savannahDig); savannahStep.addStep(nor(usingCompostorNothing, savannahStates.getIsProtected()), savannahProtect); - - steps.addStep(and(accessToSavannah, nor(savannahStates.getIsGrowing())), savannahStep.withId(11)); + steps.addStep(and(accessToSavannah, not(savannahStates.getIsGrowing())), savannahStep.withId(11)); auburnvaleStep = new ConditionalStep(this, auburnvaleTreePatchCheckHealth); auburnvaleStep.addStep(auburnvaleStates.getIsUnchecked(), auburnvaleTreePatchCheckHealth); + auburnvaleStep.addStep(and(auburnvaleStates.getIsHarvestable(), not(payingForRemoval)), auburnvaleTreePatchCutDown); auburnvaleStep.addStep(auburnvaleStates.getIsEmpty(), auburnvaleTreePatchPlant); auburnvaleStep.addStep(auburnvaleStates.getIsHarvestable(), auburnvaleTreePatchClear); auburnvaleStep.addStep(auburnvaleStates.getIsStump(), auburnvaleTreePatchDig); auburnvaleStep.addStep(nor(usingCompostorNothing, auburnvaleStates.getIsProtected()), auburnvaleTreeProtect); - - steps.addStep(and(accessToVarlamore, nor(auburnvaleStates.getIsGrowing())), auburnvaleStep.withId(12)); - - - //kastoriStep, anglersRetreatStep, greatConchStep; - - kastoriStep = new ConditionalStep(this, kastoriFruitTreePatchCheckHealth); - kastoriStep.addStep(kastoriStates.getIsUnchecked(), kastoriFruitTreePatchCheckHealth); - kastoriStep.addStep(kastoriStates.getIsEmpty(), kastoriFruitTreePatchPlant); - kastoriStep.addStep(kastoriStates.getIsHarvestable(), kastoriFruitTreePatchClear); - kastoriStep.addStep(kastoriStates.getIsStump(), kastoriFruitTreePatchDig); - kastoriStep.addStep(nor(usingCompostorNothing, kastoriStates.getIsProtected()), kastoriFruitProtect); - - kastoriStep.addStep(kastoriStates.getIsUnchecked(), kastoriCalquatPatchCheckHealth); - kastoriStep.addStep(kastoriStates.getIsEmpty(), kastoriCalquatPatchPlant); - kastoriStep.addStep(kastoriStates.getIsHarvestable(), kastoriCalquatPatchClear); - kastoriStep.addStep(kastoriStates.getIsStump(), kastoriCalquatPatchDig); - kastoriStep.addStep(nor(usingCompostorNothing, kastoriStates.getIsProtected()), kastoriCalquatProtect); - - steps.addStep(and(accessToVarlamore, nand(kastoriStates.getIsGrowing(), kastoriStates.getIsGrowing())), kastoriStep.withId(13)); + steps.addStep(and(accessToVarlamore, not(auburnvaleStates.getIsGrowing())), auburnvaleStep.withId(12)); + + kastoriFruitStep = (ConditionalStep) new ConditionalStep(this, kastoriFruitTreePatchCheckHealth).withId(131); + kastoriFruitStep.addStep(kastoriFruitStates.getIsUnchecked(), kastoriFruitTreePatchCheckHealth); + kastoriFruitStep.addStep(and(kastoriFruitStates.getIsHarvestable(), not(payingForRemoval)), kastoriFruitTreePatchCutDown); + kastoriFruitStep.addStep(kastoriFruitStates.getIsEmpty(), kastoriFruitTreePatchPlant); + kastoriFruitStep.addStep(kastoriFruitStates.getIsHarvestable(), kastoriFruitTreePatchClear); + kastoriFruitStep.addStep(kastoriFruitStates.getIsStump(), kastoriFruitTreePatchDig); + kastoriFruitStep.addStep(nor(usingCompostorNothing, kastoriFruitStates.getIsProtected()), kastoriFruitProtect); + + kastoriCalquatStep = (ConditionalStep) new ConditionalStep(this, kastoriCalquatPatchCheckHealth).withId(132); + kastoriCalquatStep.addStep(kastoriCalquatStates.getIsUnchecked(), kastoriCalquatPatchCheckHealth); + kastoriCalquatStep.addStep(and(kastoriCalquatStates.getIsHarvestable(), not(payingForRemoval)), kastoriCalquatPatchRemove); + kastoriCalquatStep.addStep(kastoriCalquatStates.getIsEmpty(), kastoriCalquatPatchPlant); + kastoriCalquatStep.addStep(kastoriCalquatStates.getIsHarvestable(), kastoriCalquatPatchClear); + kastoriCalquatStep.addStep(kastoriCalquatStates.getIsStump(), kastoriCalquatPatchDig); + kastoriCalquatStep.addStep(nor(usingCompostorNothing, kastoriCalquatStates.getIsProtected()), kastoriCalquatProtect); + + + kastoriStep = new ReorderableConditionalStep(this, new DetailedQuestStep(this, "Unreachable.")); + kastoriStep.addStep(not(kastoriFruitStates.getIsGrowing()), kastoriFruitStep); + kastoriStep.addStep(not(kastoriCalquatStates.getIsGrowing()), kastoriCalquatStep); + steps.addStep(and(accessToVarlamore, nand(kastoriFruitStates.getIsGrowing(), kastoriCalquatStates.getIsGrowing())), kastoriStep.withId(13)); anglersRetreatStep = new ConditionalStep(this, anglersCheckHealth); anglersRetreatStep.addStep(anglersRetreatStates.getIsUnchecked(), anglersCheckHealth); + anglersRetreatStep.addStep(and(anglersRetreatStates.getIsHarvestable(), not(payingForRemoval)), anglersCutDown); anglersRetreatStep.addStep(anglersRetreatStates.getIsEmpty(), anglersPlant); anglersRetreatStep.addStep(anglersRetreatStates.getIsHarvestable(), anglersClear); anglersRetreatStep.addStep(anglersRetreatStates.getIsStump(), anglersDig); anglersRetreatStep.addStep(nor(usingCompostorNothing, anglersRetreatStates.getIsProtected()), anglersProtect); - - steps.addStep(and(accessToAnglersRetreat, nor(anglersRetreatStates.getIsGrowing())), - anglersRetreatStep.withId(14)); + steps.addStep(and(accessToAnglersRetreat, not(anglersRetreatStates.getIsGrowing())), anglersRetreatStep.withId(14)); greatConchStep = new ConditionalStep(this, greatConchCalquatPatchCheckHealth); greatConchStep.addStep(greatConchStates.getIsUnchecked(), greatConchCalquatPatchCheckHealth); + greatConchStep.addStep(and(greatConchStates.getIsHarvestable(), not(payingForRemoval)), greatConchCalquatPatchRemove); greatConchStep.addStep(greatConchStates.getIsEmpty(), greatConchCalquatPatchPlant); greatConchStep.addStep(greatConchStates.getIsHarvestable(), greatConchCalquatPatchClear); greatConchStep.addStep(greatConchStates.getIsStump(), greatConchCalquatPatchDig); greatConchStep.addStep(nor(usingCompostorNothing, greatConchStates.getIsProtected()), greatConchCalquatProtect); - - steps.addStep(and(accessToGreatConch, nor(greatConchStates.getIsGrowing())), - greatConchStep.withId(15)); + steps.addStep(and(accessToGreatConch, not(greatConchStates.getIsGrowing())), greatConchStep.withId(15)); return steps; } @@ -425,7 +466,8 @@ private void setupConditions() gnomeStrongholdFruitStates = new PatchStates("Gnome Stronghold"); lletyaStates = new PatchStates("Lletya", accessToLletya); farmingGuildFruitStates = new PatchStates("Farming Guild", accessToFarmingGuildFruitTreePatch); - kastoriStates = new PatchStates("Kastori", accessToVarlamore); + kastoriFruitStates = new PatchStates("Kastori", accessToVarlamore); + kastoriCalquatStates = new PatchStates("Kastori", accessToVarlamore); greatConchStates = new PatchStates("Great Conch", accessToGreatConch); westHardwoodStates = new PatchStates("Fossil Island", "West"); @@ -440,7 +482,8 @@ private void setupConditions() gnomeStrongholdFruitStates.getIsGrowing(), or(not(accessToLletya), lletyaStates.getIsGrowing()), or(not(accessToVarlamore), auburnvaleStates.getIsGrowing()), - or(not(accessToVarlamore), kastoriStates.getIsGrowing()), + or(not(accessToVarlamore), kastoriFruitStates.getIsGrowing()), + or(not(accessToVarlamore), kastoriCalquatStates.getIsGrowing()), or(not(accessToFarmingGuildTreePatch), farmingGuildTreeStates.getIsGrowing()), or(not(accessToFarmingGuildFruitTreePatch), farmingGuildFruitStates.getIsGrowing()), or(not(accessToFossilIsland), and(westHardwoodStates.getIsGrowing(), middleHardwoodStates.getIsGrowing(), eastHardwoodStates.getIsGrowing())), @@ -465,7 +508,7 @@ public void setupRequirements() .hideConditioned(new VarbitRequirement(VarbitID.FARMING_BLOCKWEEDS, 2)); coins = new ItemRequirement("Coins to quickly remove trees.", ItemID.COINS) .showConditioned(payingForRemoval); - axe = new ItemRequirement("Any axe you can use", ItemCollections.AXES); + axe = new ItemRequirement("Any axe", ItemCollections.AXES).isNotConsumed().showConditioned(not(payingForRemoval)); TreeSapling treeSaplingEnum = (TreeSapling) FarmingUtils.getEnumFromConfig(configManager, TreeSapling.MAGIC); treeSapling = treeSaplingEnum.getPlantableItemRequirement(itemManager); @@ -578,59 +621,73 @@ private void setupSteps() lumbridgeTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_4, new WorldPoint(3193, 3231, 0), "Speak to Fayeth to clear the patch."); + lumbridgeTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); lumbridgeTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); faladorTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_2, new WorldPoint(3004, 3373, 0), "Speak to Heskel to clear the patch."); + faladorTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); faladorTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); taverleyTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_1, new WorldPoint(2936, 3438, 0), "Speak to Alain to clear the patch."); + taverleyTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); taverleyTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); varrockTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_3_02, new WorldPoint(3229, 3459, 0), "Speak to Treznor to clear the patch."); + varrockTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); varrockTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); gnomeStrongholdTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_GNOME, new WorldPoint(2436, 3415, 0), "Speak to Prissy Scilla to clear the patch."); + gnomeStrongholdTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); gnomeStrongholdTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); farmingGuildTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FARMGUILD_T2, new WorldPoint(1232, 3736, 0), "Speak to Rosie to clear the patch."); + farmingGuildTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); farmingGuildTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); auburnvaleTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_7, new WorldPoint(1367, 3322, 0), "Speak to Aub to clear the patch."); + auburnvaleTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); auburnvaleTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); lumbridgeTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_4, new WorldPoint(3193, 3231, 0), "Speak to Fayeth to protect the patch."); - lumbridgeTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + lumbridgeTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + lumbridgeTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); faladorTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_2, new WorldPoint(3004, 3373, 0), "Speak to Heskel to protect the patch."); - faladorTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + faladorTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + faladorTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); taverleyTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_1, new WorldPoint(2936, 3438, 0), "Speak to Alain to protect the patch."); - taverleyTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + taverleyTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + taverleyTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); varrockTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_3_02, new WorldPoint(3229, 3459, 0), "Speak to Treznor to protect the patch."); - varrockTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + varrockTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + varrockTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); strongholdTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_GNOME, new WorldPoint(2436, 3415, 0), "Speak to Prissy Scilla to protect the patch."); - strongholdTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + strongholdTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + strongholdTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); farmingGuildTreePayForProtection = new NpcStep(this, NpcID.FARMING_GARDENER_FARMGUILD_T2, new WorldPoint(1232, 3736, 0), "Speak to Rosie to protect the patch."); - farmingGuildTreePayForProtection.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + farmingGuildTreePayForProtection.conditionToHideInSidebar(not(payingForProtection)); + farmingGuildTreePayForProtection.addDialogSteps(TREE_PROTECTION_DIALOG); auburnvaleTreeProtect = new NpcStep(this, NpcID.FARMING_GARDENER_TREE_7, new WorldPoint(1367, 3322, 0), "Speak to Aub to protect the patch."); - auburnvaleTreeProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + auburnvaleTreeProtect.conditionToHideInSidebar(not(payingForProtection)); + auburnvaleTreeProtect.addDialogSteps(TREE_PROTECTION_DIALOG); // Tree Patch Steps lumbridgeTreePatchCheckHealth = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_4, new WorldPoint(3193, 3231, 0), @@ -660,6 +717,44 @@ private void setupSteps() auburnvaleTreePatchCheckHealth.conditionToHideInSidebar(new Conditions(LogicType.NOR, accessToVarlamore)); auburnvaleTreePatchCheckHealth.addTeleport(auburnvaleTeleport); + // Tree Cut Down Steps + farmingGuildTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_6, new WorldPoint(1232, 3736, 0), + "Cut down the tree planted in the Farming Guild.", axe); + farmingGuildTreePatchCutDown.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToFarmingGuildTreePatch), payingForRemoval)); + farmingGuildTreePatchCutDown.addTeleport(farmingGuildTeleport); + + lumbridgeTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_4, new WorldPoint(3193, 3231, 0), + "Cut down the tree planted in Lumbridge.", axe); + lumbridgeTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + lumbridgeTreePatchCutDown.addTeleport(lumbridgeTeleport); + lumbridgeTreePatchCutDown.addSpellHighlight(NormalSpells.LUMBRIDGE_TELEPORT); + lumbridgeTreePatchCutDown.addSpellHighlight(NormalSpells.LUMBRIDGE_HOME_TELEPORT); + + faladorTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_2, new WorldPoint(3004, 3373, 0), + "Cut down the tree planted in Falador.", axe); + faladorTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + faladorTreePatchCutDown.addTeleport(faladorTeleport); + faladorTreePatchCutDown.addSpellHighlight(NormalSpells.FALADOR_TELEPORT); + + taverleyTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_1, new WorldPoint(2936, 3438, 0), + "Cut down the tree planted in Taverley.", axe); + taverleyTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + + varrockTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_3, new WorldPoint(3229, 3459, 0), + "Cut down the tree planted in Varrock.", axe); + varrockTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + varrockTreePatchCutDown.addTeleport(varrockTeleport); + varrockTreePatchCutDown.addSpellHighlight(NormalSpells.VARROCK_TELEPORT); + + gnomeStrongholdTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_5, new WorldPoint(2436, 3415, 0), + "Cut down the tree planted in the Tree Gnome Stronghold.", axe); + gnomeStrongholdTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + + auburnvaleTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_7, new WorldPoint(1367, 3322, 0), + "Cut down the tree planted at Auburnvale.", axe); + auburnvaleTreePatchCutDown.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToVarlamore), payingForRemoval)); + auburnvaleTreePatchCutDown.addTeleport(auburnvaleTeleport); + // Tree Plant Steps lumbridgeTreePatchPlant = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_4, new WorldPoint(3193, 3231, 0), "Plant your sapling in the Lumbridge patch.", treeSapling); @@ -701,26 +796,33 @@ private void setupSteps() // Dig lumbridgeTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_4, new WorldPoint(3193, 3231, 0), "Dig up the tree stump in Lumbridge."); + lumbridgeTreePatchDig.conditionToHideInSidebar(payingForRemoval); faladorTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_2, new WorldPoint(3004, 3373, 0), "Dig up the tree stump in Falador."); + faladorTreePatchDig.conditionToHideInSidebar(payingForRemoval); taverleyTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_1, new WorldPoint(2936, 3438, 0), "Dig up the tree stump in Taverley."); + taverleyTreePatchDig.conditionToHideInSidebar(payingForRemoval); varrockTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_3, new WorldPoint(3229, 3459, 0), "Dig up the tree stump in Varrock."); + varrockTreePatchDig.conditionToHideInSidebar(payingForRemoval); gnomeStrongholdTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_5, new WorldPoint(2436, 3415, 0), "Dig up the tree stump in the Tree Gnome Stronghold."); + gnomeStrongholdTreePatchDig.conditionToHideInSidebar(payingForRemoval); farmingGuildTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_6, new WorldPoint(1232, 3736, 0), "Dig up the tree stump in the Farming Guild tree patch."); + farmingGuildTreePatchDig.conditionToHideInSidebar(payingForRemoval); auburnvaleTreePatchDig = new ObjectStep(this, ObjectID.FARMING_TREE_PATCH_7, new WorldPoint(1367, 3322, 0), "Dig up the tree stump in the Auburnvale tree patch."); + auburnvaleTreePatchDig.conditionToHideInSidebar(payingForRemoval); - faladorTreePatchClear.addSubSteps(faladorTreePatchDig, faladorTreeProtect); - taverleyTreePatchClear.addSubSteps(taverleyTreePatchDig, taverleyTreeProtect); - varrockTreePatchClear.addSubSteps(varrockTreePatchDig, varrockTreeProtect); - gnomeStrongholdTreePatchClear.addSubSteps(gnomeStrongholdTreePatchDig, strongholdTreeProtect); - lumbridgeTreePatchClear.addSubSteps(lumbridgeTreePatchDig, lumbridgeTreeProtect); - farmingGuildTreePatchClear.addSubSteps(farmingGuildTreePatchDig, farmingGuildTreePayForProtection); - auburnvaleTreePatchClear.addSubSteps(auburnvaleTreePatchDig, auburnvaleTreeProtect); + faladorTreePatchClear.addSubSteps(faladorTreePatchDig); + taverleyTreePatchClear.addSubSteps(taverleyTreePatchDig); + varrockTreePatchClear.addSubSteps(varrockTreePatchDig); + gnomeStrongholdTreePatchClear.addSubSteps(gnomeStrongholdTreePatchDig); + lumbridgeTreePatchClear.addSubSteps(lumbridgeTreePatchDig); + farmingGuildTreePatchClear.addSubSteps(farmingGuildTreePatchDig); + auburnvaleTreePatchClear.addSubSteps(auburnvaleTreePatchDig); // Fruit Tree Steps @@ -833,106 +935,192 @@ private void setupSteps() greatConchCalquatPatchCheckHealth.addWidgetHighlightWithTextRequirement(187, 3, "Great Conch", true); greatConchCalquatPatchCheckHealth.addSubSteps(greatConchCalquatPatchPlant); + // Fruit Tree Cut Down Steps + gnomeStrongholdFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_1, new WorldPoint(2476, 3446, 0), + "Cut down the fruit tree planted in the Tree Gnome Stronghold.", axe); + gnomeStrongholdFruitTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + gnomeStrongholdFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(187, 3, "Gnome Stronghold", true); + + gnomeVillageFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_2, new WorldPoint(2490, 3180, 0), + "Cut down the fruit tree planted outside the Tree Gnome Village.", axe); + gnomeVillageFruitTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + gnomeVillageFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(187, 3, "Tree Gnome Village", true); + + brimhavenFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_3, new WorldPoint(2765, 3213, 0), + "Cut down the fruit tree planted in Brimhaven.", axe); + brimhavenFruitTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + brimhavenFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(InterfaceID.MENU, InterfaceID.Menu.LJ_LAYER1 & 0xFFFF, "Brimhaven", true); + brimhavenFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(InterfaceID.CHARTERING_MENU_SIDE, InterfaceID.CharteringMenuSide.LIST_CONTENT & 0xFFFF, "Brimhaven", true); + brimhavenFruitTreePatchCutDown.addWidgetHighlight(new WidgetHighlight(InterfaceID.SAILING_MENU, InterfaceID.SailingMenu.CONTENT & 0xFFFF, 2)); + + catherbyFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_4, new WorldPoint(2860, 3433, 0), + "Cut down the fruit tree planted in Catherby.", axe); + catherbyFruitTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + catherbyFruitTreePatchCutDown.addTeleport(catherbyTeleport); + catherbyFruitTreePatchCutDown.addSpellHighlight(NormalSpells.CAMELOT_TELEPORT); + catherbyFruitTreePatchCutDown.addSpellHighlight(LunarSpells.CATHERBY_TELEPORT); + + lletyaFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_5, new WorldPoint(2347, 3162, 0), + "Cut down the fruit tree planted in Lletya.", axe); + lletyaFruitTreePatchCutDown.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToLletya), payingForRemoval)); + lletyaFruitTreePatchCutDown.addTeleport(crystalTeleport); + + farmingGuildFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_6, new WorldPoint(1242, 3758, 0), + "Cut down the fruit tree planted in the Farming Guild.", axe); + farmingGuildFruitTreePatchCutDown.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToFarmingGuildFruitTreePatch), payingForRemoval)); + farmingGuildFruitTreePatchCutDown.addTeleport(farmingGuildTeleport); + farmingGuildFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(187, 3, "Farming Guild", true); + + kastoriFruitTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_7, new WorldPoint(1350, 3057, 0), + "Cut down the fruit tree planted in Kastori.", axe); + kastoriFruitTreePatchCutDown.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToVarlamore), payingForRemoval)); + kastoriFruitTreePatchCutDown.addTeleport(kastoriTeleport); + kastoriFruitTreePatchCutDown.addWidgetHighlightWithTextRequirement(187, 3, "Kastori", true); + + taiBwoWannaiCalquatPatchRemove = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH, new WorldPoint(2795, 3102, 0), + "Pick the fruit off the calquat and clear the patch in Tai Bwo Wannai."); + taiBwoWannaiCalquatPatchRemove.conditionToHideInSidebar(payingForRemoval); + taiBwoWannaiCalquatPatchRemove.addWidgetHighlightWithTextRequirement(187, 3, "Tai Bwo Wannai", true); + + kastoriCalquatPatchRemove = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH_2, new WorldPoint(1366, 3033, 0), + "Pick the fruit off the calquat and clear the patch in Kastori."); + kastoriCalquatPatchRemove.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToVarlamore), payingForRemoval)); + kastoriCalquatPatchRemove.addTeleport(kastoriTeleport); + kastoriCalquatPatchRemove.addWidgetHighlightWithTextRequirement(187, 3, "Kastori", true); + + greatConchCalquatPatchRemove = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH_3, new WorldPoint(3129, 2406, 0), + "Pick the fruit off the calquat and clear the patch in Great Conch."); + greatConchCalquatPatchRemove.conditionToHideInSidebar(new Conditions(LogicType.OR, new Conditions(LogicType.NOR, accessToGreatConch), payingForRemoval)); + greatConchCalquatPatchRemove.addWidgetHighlightWithTextRequirement(187, 3, "Great Conch", true); + // Clear gnomeStrongholdFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_1, new WorldPoint(2476, 3446, 0), "Pay Bolongo 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + gnomeStrongholdFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); gnomeStrongholdFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); gnomeVillageFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_2, new WorldPoint(2490, 3180, 0), "Pay Gileth 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + gnomeVillageFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); gnomeVillageFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); brimhavenFruitTreePatchClear = new NpcStep(this, NpcID.GARTH, new WorldPoint(2765, 3213, 0), "Pay Garth 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + brimhavenFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); brimhavenFruitTreePatchClear.addWidgetHighlightWithTextRequirement(InterfaceID.MENU, InterfaceID.Menu.LJ_LAYER1 & 0xFFFF, "Brimhaven", true); brimhavenFruitTreePatchClear.addWidgetHighlightWithTextRequirement(InterfaceID.CHARTERING_MENU_SIDE, InterfaceID.CharteringMenuSide.LIST_CONTENT & 0xFFFF, "Brimhaven", true); brimhavenFruitTreePatchClear.addWidgetHighlight(new WidgetHighlight(InterfaceID.SAILING_MENU, InterfaceID.SailingMenu.CONTENT & 0xFFFF, 2)); brimhavenFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); catherbyFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_4, new WorldPoint(2860, 3433, 0), "Pay Ellena 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + catherbyFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); catherbyFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); lletyaFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_TREE_5, new WorldPoint(2347, 3162, 0), "Pay Liliwen 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + lletyaFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); lletyaFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); farmingGuildFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FARMGUILD_T3, new WorldPoint(1243, 3760, 0), "Pay Nikkie 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + farmingGuildFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); farmingGuildFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); kastoriFruitTreePatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_7, new WorldPoint(1350, 3057, 0), "Pay Ehecatl 200 coins to clear the fruit tree, or pick all the fruit and cut it down."); + kastoriFruitTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); kastoriFruitTreePatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); taiBwoWannaiCalquatPatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT, new WorldPoint(2795, 3102, 0), "Pay Imiago 200 coins to clear the calquat tree, or pick all the fruit and cut it down."); + taiBwoWannaiCalquatPatchClear.conditionToHideInSidebar(not(payingForRemoval)); taiBwoWannaiCalquatPatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); kastoriCalquatPatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT_2, new WorldPoint(1366, 3033, 0), "Pay Tziuhtla 200 coins to clear the calquat tree, or pick all the fruit and cut it down."); + kastoriCalquatPatchClear.conditionToHideInSidebar(not(payingForRemoval)); kastoriCalquatPatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); greatConchCalquatPatchClear = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT_3, new WorldPoint(3129, 2406, 0), "Pay Guppa 200 coins to clear the calquat tree, or pick all the fruit and cut it down."); + greatConchCalquatPatchClear.conditionToHideInSidebar(not(payingForRemoval)); greatConchCalquatPatchClear.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); strongholdFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_1, new WorldPoint(2476, 3446, 0), "Pay Bolongo to protect the patch."); - strongholdFruitProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + strongholdFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + strongholdFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); villageFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_2, new WorldPoint(2490, 3180, 0), "Pay Gileth to protect the patch."); - villageFruitProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + villageFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + villageFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); brimhavenFruitProtect = new NpcStep(this, NpcID.GARTH, new WorldPoint(2765, 3213, 0), "Pay Garth to protect the patch."); - brimhavenFruitProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + brimhavenFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + brimhavenFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); catherbyFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_4, new WorldPoint(2860, 3433, 0), "Pay Ellena to protect the patch."); - catherbyFruitProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + catherbyFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + catherbyFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); lletyaFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_TREE_5, new WorldPoint(2347, 3162, 0), "Pay Liliwen to protect the patch."); - lletyaFruitProtect.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - " + - "chop my tree down please.", "Yes."); + lletyaFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + lletyaFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); guildFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FARMGUILD_T3, new WorldPoint(1243, 3760, 0), "Pay Nikkie to protect the patch."); - guildFruitProtect.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - " + - "chop my tree down please.", "Yes."); + guildFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + guildFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); kastoriFruitProtect = new NpcStep(this, NpcID.FARMING_GARDENER_FRUIT_7, new WorldPoint(1350, 3057, 0), "Pay Ehecatl to protect the patch."); - kastoriFruitProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + kastoriFruitProtect.conditionToHideInSidebar(not(payingForProtection)); + kastoriFruitProtect.addDialogSteps(TREE_PROTECTION_DIALOG); taiBwoWannaiCalquatProtect = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT, new WorldPoint(2795, 3102, 0), "Pay Imiago to protect the patch."); - taiBwoWannaiCalquatProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + taiBwoWannaiCalquatProtect.conditionToHideInSidebar(not(payingForProtection)); + taiBwoWannaiCalquatProtect.addDialogSteps(TREE_PROTECTION_DIALOG); kastoriCalquatProtect = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT_2, new WorldPoint(1366, 3033, 0), "Pay Tziuhtla to protect the patch."); - kastoriCalquatProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + kastoriCalquatProtect.conditionToHideInSidebar(not(payingForProtection)); + kastoriCalquatProtect.addDialogSteps(TREE_PROTECTION_DIALOG); greatConchCalquatProtect = new NpcStep(this, NpcID.FARMING_GARDENER_CALQUAT_3, new WorldPoint(3129, 2406, 0), "Pay Guppa to protect the patch."); - greatConchCalquatProtect.addDialogSteps("Would you chop my tree down for me?","I can't be bothered - I'd rather pay you to do it.", "Here's 200 Coins - chop my tree down please.", "Yes."); + greatConchCalquatProtect.conditionToHideInSidebar(not(payingForProtection)); + greatConchCalquatProtect.addDialogSteps(TREE_PROTECTION_DIALOG); // Dig Fruit Tree Steps gnomeStrongholdFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_1, new WorldPoint(2476, 3446, 0), "Dig up the fruit tree's stump in the Tree Gnome Stronghold."); + gnomeStrongholdFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); gnomeVillageFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_2, new WorldPoint(2490, 3180, 0), "Dig up the fruit tree's stump outside the Tree Gnome Village."); + gnomeVillageFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); brimhavenFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_3, new WorldPoint(2765, 3213, 0), "Dig up the fruit tree's stump in Brimhaven."); + brimhavenFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); catherbyFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_4, new WorldPoint(2860, 3433, 0), "Check the health of the fruit tree planted in Catherby"); + catherbyFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); lletyaFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_5, new WorldPoint(2347, 3162, 0), "Dig up the fruit tree's stump in Lletya."); + lletyaFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); farmingGuildFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_6, new WorldPoint(1242, 3758, 0), "Dig up the fruit tree's stump in the Farming Guild."); + farmingGuildFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); kastoriFruitTreePatchDig = new ObjectStep(this, ObjectID.FARMING_FRUIT_TREE_PATCH_7, new WorldPoint(1350, 3057, 0), "Dig up the fruit tree's stump in Kastori."); + kastoriFruitTreePatchDig.conditionToHideInSidebar(payingForRemoval); taiBwoWannaiCalquatPatchDig = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH, new WorldPoint(2795, 3102, 0), "Dig up the calquat tree's stump in Tai Bwo Wannai."); + taiBwoWannaiCalquatPatchDig.conditionToHideInSidebar(payingForRemoval); kastoriCalquatPatchDig = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH_2, new WorldPoint(1366, 3033, 0), "Dig up the calquat tree's stump in Kastori."); + kastoriCalquatPatchDig.conditionToHideInSidebar(payingForRemoval); greatConchCalquatPatchDig = new ObjectStep(this, ObjectID.FARMING_CALQUAT_TREE_PATCH_3, new WorldPoint(3129, 2406, 0), "Dig up the calquat tree's stump in Great Conch."); - - gnomeStrongholdFruitTreePatchClear.addSubSteps(gnomeStrongholdFruitTreePatchDig, strongholdFruitProtect); - gnomeVillageFruitTreePatchClear.addSubSteps(gnomeVillageFruitTreePatchDig, villageFruitProtect); - brimhavenFruitTreePatchClear.addSubSteps(brimhavenFruitTreePatchDig, brimhavenFruitProtect); - catherbyFruitTreePatchClear.addSubSteps(catherbyFruitTreePatchDig, catherbyFruitProtect); - lletyaFruitTreePatchClear.addSubSteps(lletyaFruitTreePatchDig, lletyaFruitProtect); - farmingGuildFruitTreePatchClear.addSubSteps(farmingGuildFruitTreePatchDig, guildFruitProtect); - kastoriFruitTreePatchClear.addSubSteps(kastoriFruitTreePatchDig, kastoriFruitProtect); - taiBwoWannaiCalquatPatchClear.addSubSteps(taiBwoWannaiCalquatPatchDig, taiBwoWannaiCalquatProtect); - kastoriCalquatPatchClear.addSubSteps(kastoriCalquatPatchDig, kastoriCalquatProtect); - greatConchCalquatPatchClear.addSubSteps(greatConchCalquatPatchDig, greatConchCalquatProtect); + greatConchCalquatPatchDig.conditionToHideInSidebar(payingForRemoval); + + gnomeStrongholdFruitTreePatchClear.addSubSteps(gnomeStrongholdFruitTreePatchDig); + gnomeVillageFruitTreePatchClear.addSubSteps(gnomeVillageFruitTreePatchDig); + brimhavenFruitTreePatchClear.addSubSteps(brimhavenFruitTreePatchDig); + catherbyFruitTreePatchClear.addSubSteps(catherbyFruitTreePatchDig); + lletyaFruitTreePatchClear.addSubSteps(lletyaFruitTreePatchDig); + farmingGuildFruitTreePatchClear.addSubSteps(farmingGuildFruitTreePatchDig); + kastoriFruitTreePatchClear.addSubSteps(kastoriFruitTreePatchDig); + taiBwoWannaiCalquatPatchClear.addSubSteps(taiBwoWannaiCalquatPatchDig); + kastoriCalquatPatchClear.addSubSteps(kastoriCalquatPatchDig); + greatConchCalquatPatchClear.addSubSteps(greatConchCalquatPatchDig); // Hardwood Tree Steps westHardwoodTreePatchCheckHealth = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_3, new WorldPoint(3702, 3837, 0), @@ -968,56 +1156,97 @@ private void setupSteps() anglersPlant = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_5, new WorldPoint(2470, 2704, 0), "Plant your sapling on the hardwood tree patch on Anglers' Retreat.", hardwoodSapling); + // Hardwood Tree Cut Down Steps + eastHardwoodTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_1, new WorldPoint(3715, 3835, 0), + "Cut down the hardwood tree planted on the eastern hardwood tree patch on Fossil Island.", axe); + eastHardwoodTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + + middleHardwoodTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_2, new WorldPoint(3708, 3833, 0), + "Cut down the hardwood tree planted on the centre hardwood tree patch on Fossil Island.", axe); + middleHardwoodTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + + westHardwoodTreePatchCutDown = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_3, new WorldPoint(3702, 3837, 0), + "Cut down the hardwood tree planted on the western hardwood tree patch on Fossil Island.", axe); + westHardwoodTreePatchCutDown.conditionToHideInSidebar(payingForRemoval); + + savannahCutDown = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_4, new WorldPoint(1687, 2972, 0), + "Cut down the hardwood tree planted in the Avium Savannah.", axe); + savannahCutDown.conditionToHideInSidebar(payingForRemoval); + + anglersCutDown = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_5, new WorldPoint(2470, 2704, 0), + "Cut down the hardwood tree planted in the Anglers' Retreat.", axe); + anglersCutDown.conditionToHideInSidebar(payingForRemoval); + westHardwoodTreePatchClear = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER3, new WorldPoint(3702, 3837, 0), "Pay the brown squirrel to remove the west tree."); + westHardwoodTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); westHardwoodTreePatchClear.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 " + "Coins - chop my tree down please.", "Yes."); middleHardwoodTreePatchClear = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER2, new WorldPoint(3702, 3837, 0), "Pay the black squirrel to remove the middle tree."); + middleHardwoodTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); middleHardwoodTreePatchClear.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 " + "Coins - chop my tree down please.", "Yes."); eastHardwoodTreePatchClear = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER1, new WorldPoint(3702, 3837, 0), "Pay the grey squirrel to remove the east tree."); + eastHardwoodTreePatchClear.conditionToHideInSidebar(not(payingForRemoval)); eastHardwoodTreePatchClear.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 " + "Coins - chop my tree down please.", "Yes."); savannahClear = new NpcStep(this, NpcID.FROG_QUEST_MARCELLUS_FARMER, new WorldPoint(1687, 2972, 0), "Pay Marcellus to clear the tree."); + savannahClear.conditionToHideInSidebar(not(payingForRemoval)); savannahClear.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 " + "Coins - chop my tree down please.", "Yes."); anglersClear = new NpcStep(this, NpcID.FARMING_GARDENER_HARDWOOD_TREE_5, new WorldPoint(2470, 2704, 0), "Pay Argo to clear the tree."); + anglersClear.conditionToHideInSidebar(not(payingForRemoval)); anglersClear.addDialogSteps("Would you chop my tree down for me?", "I can't be bothered - I'd rather pay you to do it.", "Here's 200 " + "Coins - chop my tree down please.", "Yes."); westHardwoodTreePatchDig = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_3, new WorldPoint(3702, 3837, 0), "Dig up the western hardwood tree's stump on Fossil Island."); + westHardwoodTreePatchDig.conditionToHideInSidebar(payingForRemoval); middleHardwoodTreePatchDig = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_2, new WorldPoint(3708, 3833, 0), "Dig up the centre hardwood tree's stump on Fossil Island."); + middleHardwoodTreePatchDig.conditionToHideInSidebar(payingForRemoval); eastHardwoodTreePatchDig = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_1, new WorldPoint(3715, 3835, 0), "Dig up the eastern hardwood tree's stump on Fossil Island."); + eastHardwoodTreePatchDig.conditionToHideInSidebar(payingForRemoval); savannahDig = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_4, new WorldPoint(1687, 2972, 0), "Dig up the Savannah hardwood tree's stump."); + savannahDig.conditionToHideInSidebar(payingForRemoval); anglersDig = new ObjectStep(this, ObjectID.FARMING_HARDWOOD_TREE_PATCH_5, new WorldPoint(2470,2704, 0), "Dig up the Anglers' Retreat hardwood tree's stump."); + anglersDig.conditionToHideInSidebar(payingForRemoval); westHardwoodProtect = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER3, new WorldPoint(3702, 3837, 0), "Pay the brown squirrel to protect the west tree."); + westHardwoodProtect.conditionToHideInSidebar(not(payingForProtection)); + westHardwoodProtect.addDialogSteps(TREE_PROTECTION_DIALOG); middleHardwoodProtect = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER2, new WorldPoint(3702, 3837, 0), "Pay the black squirrel to protect the middle tree."); + middleHardwoodProtect.conditionToHideInSidebar(not(payingForProtection)); + middleHardwoodProtect.addDialogSteps(TREE_PROTECTION_DIALOG); eastHardwoodProtect = new NpcStep(this, NpcID.FOSSIL_SQUIRREL_GARDENER1, new WorldPoint(3702, 3837, 0), "Pay the grey squirrel to protect the east tree."); + eastHardwoodProtect.conditionToHideInSidebar(not(payingForProtection)); + eastHardwoodProtect.addDialogSteps(TREE_PROTECTION_DIALOG); savannahProtect = new NpcStep(this, NpcID.FROG_QUEST_MARCELLUS_FARMER, new WorldPoint(1687, 2972, 0), "Pay Marcellus to protect the hardwood tree."); + savannahProtect.conditionToHideInSidebar(not(payingForProtection)); + savannahProtect.addDialogSteps(TREE_PROTECTION_DIALOG); anglersProtect = new NpcStep(this, NpcID.FARMING_GARDENER_HARDWOOD_TREE_5, new WorldPoint(2470, 2704, 0), "Pay Argo to protect the hardwood tree."); - - westHardwoodTreePatchClear.addSubSteps(westHardwoodTreePatchDig, westHardwoodProtect); - middleHardwoodTreePatchClear.addSubSteps(middleHardwoodTreePatchDig, middleHardwoodProtect); - eastHardwoodTreePatchClear.addSubSteps(eastHardwoodTreePatchDig, eastHardwoodProtect); - savannahClear.addSubSteps(savannahDig, savannahProtect); - anglersClear.addSubSteps(anglersDig, anglersProtect); + anglersProtect.conditionToHideInSidebar(not(payingForProtection)); + anglersProtect.addDialogSteps(TREE_PROTECTION_DIALOG); + + westHardwoodTreePatchClear.addSubSteps(westHardwoodTreePatchDig); + middleHardwoodTreePatchClear.addSubSteps(middleHardwoodTreePatchDig); + eastHardwoodTreePatchClear.addSubSteps(eastHardwoodTreePatchDig); + savannahClear.addSubSteps(savannahDig); + anglersClear.addSubSteps(anglersDig); } @Subscribe @@ -1033,10 +1262,10 @@ public void onGameTick(GameTick event) farmingWorld.getTabs().get(Tab.TREE), allTreeSaplings, allProtectionItemTree); handleTreePatches(PatchImplementation.FRUIT_TREE, List.of(farmingGuildFruitStates, brimhavenStates, catherbyStates, gnomeStrongholdFruitStates, gnomeVillageStates, lletyaStates, - kastoriStates), + kastoriFruitStates), farmingWorld.getTabs().get(Tab.FRUIT_TREE), allFruitSaplings, allProtectionItemFruitTree); handleTreePatches(PatchImplementation.CALQUAT, - List.of(taiBwoWannaiStates, kastoriStates, greatConchStates), + List.of(taiBwoWannaiStates, kastoriCalquatStates, greatConchStates), farmingWorld.getTabs().get(Tab.FRUIT_TREE), allCalquatSaplings, allProtectionItemCalquat); handleTreePatches(PatchImplementation.HARDWOOD_TREE, List.of(westHardwoodStates, middleHardwoodStates, eastHardwoodStates, savannahStates, anglersRetreatStates), @@ -1058,8 +1287,9 @@ public void handleTreePatches(PatchImplementation implementation, List getConfigs() @Override public List getItemRequirements() { - return Arrays.asList(spade, rake, compost, coins, allTreeSaplings, allFruitSaplings, allHardwoodSaplings, allCalquatSaplings, allProtectionItemTree, allProtectionItemFruitTree, allProtectionItemHardwood, allProtectionItemCalquat); + return Arrays.asList(spade, rake, compost, coins, axe, allTreeSaplings, allFruitSaplings, allHardwoodSaplings, allCalquatSaplings, allProtectionItemTree, allProtectionItemFruitTree, allProtectionItemHardwood, allProtectionItemCalquat); } @Override @@ -1151,70 +1381,97 @@ public List getPanels() // IDEA: Can add ID to each step. onLoad and onConfigChanged it checks id ordering. List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Wait for Herbs", waitForTree).withHideCondition(nor(allGrowing))); + allSteps.add(new PanelDetails("Wait for Trees", waitForTree).withHideCondition(nor(allGrowing))); - PanelDetails farmingGuildPanel = new PanelDetails("Farming Guild", Arrays.asList(farmingGuildTreePatchCheckHealth, farmingGuildTreePatchClear, - farmingGuildTreePatchPlant, farmingGuildFruitTreePatchCheckHealth, farmingGuildFruitTreePatchClear, - farmingGuildTreePatchPlant)).withId(0); + PanelDetails farmingGuildTreePanel = new PanelDetails("Tree Patch", + Arrays.asList(farmingGuildTreePatchCheckHealth, farmingGuildTreePatchCutDown, farmingGuildTreePatchDig, farmingGuildTreePatchClear, farmingGuildTreePatchPlant, farmingGuildTreePayForProtection)).withId(-1); + farmingGuildTreePanel.setLockingStep(farmingGuildTreeStep); + PanelDetails farmingGuildFruitPanel = new PanelDetails("Fruit Tree Patch", + Arrays.asList(farmingGuildFruitTreePatchCheckHealth, farmingGuildFruitTreePatchCutDown, farmingGuildFruitTreePatchDig, farmingGuildFruitTreePatchClear, farmingGuildFruitTreePatchPlant, guildFruitProtect)).withId(-2); + farmingGuildFruitPanel.setLockingStep((farmingGuildFruitStep)); + var farmingGuildPanel = new TopLevelPanelDetails("Farming Guild", + farmingGuildTreePanel, farmingGuildFruitPanel).withId(0); farmingGuildPanel.setLockingStep(farmingGuildStep); - PanelDetails lumbridgePanel = new PanelDetails("Lumbridge", Arrays.asList(lumbridgeTreePatchCheckHealth, lumbridgeTreePatchClear, lumbridgeTreePatchPlant)).withId(1); + PanelDetails lumbridgePanel = new PanelDetails("Lumbridge", Arrays.asList(lumbridgeTreePatchCheckHealth, lumbridgeTreePatchCutDown, lumbridgeTreePatchDig, lumbridgeTreePatchClear, lumbridgeTreePatchPlant, lumbridgeTreeProtect)).withId(1); lumbridgePanel.setLockingStep(lumbridgeStep); - PanelDetails faladorPanel = new PanelDetails("Falador", Arrays.asList(faladorTreePatchCheckHealth, faladorTreePatchClear, faladorTreePatchPlant)).withId(2); + PanelDetails faladorPanel = new PanelDetails("Falador", Arrays.asList(faladorTreePatchCheckHealth, faladorTreePatchCutDown, faladorTreePatchDig, faladorTreePatchClear, faladorTreePatchPlant, faladorTreeProtect)).withId(2); faladorPanel.setLockingStep(faladorStep); - PanelDetails taverleyPanel = new PanelDetails("Taverley", Arrays.asList(taverleyTreePatchCheckHealth, taverleyTreePatchClear, taverleyTreePatchPlant)).withId(3); + PanelDetails taverleyPanel = new PanelDetails("Taverley", Arrays.asList(taverleyTreePatchCheckHealth, taverleyTreePatchCutDown, taverleyTreePatchDig, taverleyTreePatchClear, taverleyTreePatchPlant, taverleyTreeProtect)).withId(3); taverleyPanel.setLockingStep(taverleyStep); - PanelDetails varrockPanel = new PanelDetails("Varrock", Arrays.asList(varrockTreePatchCheckHealth, varrockTreePatchClear, varrockTreePatchPlant)).withId(4); + PanelDetails varrockPanel = new PanelDetails("Varrock", Arrays.asList(varrockTreePatchCheckHealth, varrockTreePatchCutDown, varrockTreePatchDig, varrockTreePatchClear, varrockTreePatchPlant, varrockTreeProtect)).withId(4); varrockPanel.setLockingStep(varrockStep); - PanelDetails gnomeStrongholdPanel = new PanelDetails("Gnome Stronghold", Arrays.asList(gnomeStrongholdFruitTreePatchCheckHealth, gnomeStrongholdFruitTreePatchClear, gnomeStrongholdFruitTreePatchPlant, - gnomeStrongholdTreePatchCheckHealth, gnomeStrongholdTreePatchClear, gnomeStrongholdFruitTreePatchPlant)).withId(5); + PanelDetails gnomeStrongholdFruitPanel = new PanelDetails("Fruit Tree Patch", + Arrays.asList(gnomeStrongholdFruitTreePatchCheckHealth, gnomeStrongholdFruitTreePatchCutDown, gnomeStrongholdFruitTreePatchDig, gnomeStrongholdFruitTreePatchClear, gnomeStrongholdFruitTreePatchPlant, strongholdFruitProtect)).withId(51); + gnomeStrongholdFruitPanel.setLockingStep(strongholdFruitStep); + PanelDetails gnomeStrongholdTreePanel = new PanelDetails("Tree Patch", + Arrays.asList(gnomeStrongholdTreePatchCheckHealth, gnomeStrongholdTreePatchCutDown, gnomeStrongholdTreePatchDig, gnomeStrongholdTreePatchClear, gnomeStrongholdTreePatchPlant, strongholdTreeProtect)).withId(52); + gnomeStrongholdTreePanel.setLockingStep(strongholdTreeStep); + var gnomeStrongholdPanel = new TopLevelPanelDetails("Gnome Stronghold", + gnomeStrongholdFruitPanel, gnomeStrongholdTreePanel).withId(5); gnomeStrongholdPanel.setLockingStep(strongholdStep); PanelDetails villagePanel = new PanelDetails("Tree Gnome Village", Arrays.asList(gnomeVillageFruitTreePatchCheckHealth, - gnomeVillageFruitTreePatchClear, gnomeVillageFruitTreePatchPlant)).withId(6); + gnomeVillageFruitTreePatchCutDown, gnomeVillageFruitTreePatchDig, gnomeVillageFruitTreePatchClear, gnomeVillageFruitTreePatchPlant, villageFruitProtect)).withId(6); villagePanel.setLockingStep(villageStep); - PanelDetails catherbyPanel = new PanelDetails("Catherby", Arrays.asList(catherbyFruitTreePatchCheckHealth, catherbyFruitTreePatchClear, catherbyFruitTreePatchPlant)).withId(7); + PanelDetails catherbyPanel = new PanelDetails("Catherby", Arrays.asList(catherbyFruitTreePatchCheckHealth, catherbyFruitTreePatchCutDown, catherbyFruitTreePatchDig, catherbyFruitTreePatchClear, catherbyFruitTreePatchPlant, catherbyFruitProtect)).withId(7); catherbyPanel.setLockingStep(catherbyStep); - PanelDetails brimhavenPanel = new PanelDetails("Brimhaven", Arrays.asList(brimhavenFruitTreePatchCheckHealth, brimhavenFruitTreePatchClear, brimhavenFruitTreePatchPlant, - taiBwoWannaiCalquatPatchCheckHealth, taiBwoWannaiCalquatPatchClear, taiBwoWannaiCalquatPatchPlant)).withId(8); + PanelDetails brimhavenPanel = new PanelDetails("Brimhaven", Arrays.asList(brimhavenFruitTreePatchCheckHealth, brimhavenFruitTreePatchCutDown, brimhavenFruitTreePatchDig, brimhavenFruitTreePatchClear, brimhavenFruitTreePatchPlant, brimhavenFruitProtect)).withId(81); brimhavenPanel.setLockingStep(brimhavenStep); + PanelDetails taiBwoWannaiPanel = new PanelDetails("Tai Bwo Wannai", Arrays.asList(taiBwoWannaiCalquatPatchCheckHealth, taiBwoWannaiCalquatPatchRemove, taiBwoWannaiCalquatPatchDig, taiBwoWannaiCalquatPatchClear, taiBwoWannaiCalquatPatchPlant, taiBwoWannaiCalquatProtect)).withId(82); + taiBwoWannaiPanel.setLockingStep(taiBwoWannaiStep); + var karamjaPanel = new TopLevelPanelDetails("Karamja", brimhavenPanel, taiBwoWannaiPanel).withId(8); + karamjaPanel.setLockingStep(karamjaStep); - PanelDetails lletyaPanel = new PanelDetails("Lletya", Arrays.asList(lletyaFruitTreePatchCheckHealth, lletyaFruitTreePatchClear, lletyaFruitTreePatchPlant)).withId(9); + PanelDetails lletyaPanel = new PanelDetails("Lletya", Arrays.asList(lletyaFruitTreePatchCheckHealth, lletyaFruitTreePatchCutDown, lletyaFruitTreePatchDig, lletyaFruitTreePatchClear, lletyaFruitTreePatchPlant, lletyaFruitProtect)).withId(9); lletyaPanel.setLockingStep(lletyaStep); - PanelDetails fossilIslandPanel = new PanelDetails("Fossil Island", Arrays.asList(eastHardwoodTreePatchCheckHealth, eastHardwoodTreePatchClear, eastHardwoodTreePatchPlant, - middleHardwoodTreePatchCheckHealth, middleHardwoodTreePatchClear, middleHardwoodTreePatchPlant, - westHardwoodTreePatchCheckHealth, westHardwoodTreePatchClear, westHardwoodTreePatchPlant)).withId(10); + PanelDetails fossilIslandEastPanel = new PanelDetails("East Hardwood Patch", + Arrays.asList(eastHardwoodTreePatchCheckHealth, eastHardwoodTreePatchCutDown, eastHardwoodTreePatchDig, eastHardwoodTreePatchClear, eastHardwoodTreePatchPlant, eastHardwoodProtect) + ).withId(101); + fossilIslandEastPanel.setLockingStep(fossilIslandEastStep); + PanelDetails fossilIslandMiddlePanel = new PanelDetails("Middle Hardwood Patch", + Arrays.asList(middleHardwoodTreePatchCheckHealth, middleHardwoodTreePatchCutDown, middleHardwoodTreePatchDig, middleHardwoodTreePatchClear, middleHardwoodTreePatchPlant, middleHardwoodProtect) + ).withId(102); + fossilIslandMiddlePanel.setLockingStep(fossilIslandMiddleStep); + PanelDetails fossilIslandWestPanel = new PanelDetails("West Hardwood Patch", + Arrays.asList(westHardwoodTreePatchCheckHealth, westHardwoodTreePatchCutDown, westHardwoodTreePatchDig, westHardwoodTreePatchClear, westHardwoodTreePatchPlant, westHardwoodProtect) + ).withId(103); + fossilIslandWestPanel.setLockingStep(fossilIslandWestStep); + var fossilIslandPanel = new TopLevelPanelDetails("Fossil Island", + fossilIslandEastPanel, fossilIslandMiddlePanel, fossilIslandWestPanel).withId(10); fossilIslandPanel.setLockingStep(fossilIslandStep); - PanelDetails savannahPanel = new PanelDetails("Avium Savannah", Arrays.asList(savannahCheckHealth, savannahClear, savannahPlant)).withId(11); + PanelDetails savannahPanel = new PanelDetails("Avium Savannah", Arrays.asList(savannahCheckHealth, savannahCutDown, savannahDig, savannahClear, savannahPlant, savannahProtect)).withId(11); savannahPanel.setLockingStep(savannahStep); - PanelDetails auburnvalePanel = new PanelDetails("Auburnvale", Arrays.asList(auburnvaleTreePatchCheckHealth, auburnvaleTreePatchClear, auburnvaleTreePatchPlant)).withId(12); + PanelDetails auburnvalePanel = new PanelDetails("Auburnvale", Arrays.asList(auburnvaleTreePatchCheckHealth, auburnvaleTreePatchCutDown, auburnvaleTreePatchDig, auburnvaleTreePatchClear, auburnvaleTreePatchPlant, auburnvaleTreeProtect)).withId(12); auburnvalePanel.setLockingStep(auburnvaleStep); - PanelDetails kastoriPanel = new PanelDetails("Kastori", Arrays.asList(kastoriFruitTreePatchCheckHealth, - kastoriFruitTreePatchClear, kastoriFruitTreePatchPlant, kastoriCalquatPatchCheckHealth, - kastoriCalquatPatchClear, kastoriCalquatPatchPlant)).withId(13); + PanelDetails kastoriFruitPanel = new PanelDetails("Fruit Tree Patch", Arrays.asList(kastoriFruitTreePatchCheckHealth, kastoriFruitTreePatchCutDown, kastoriFruitTreePatchDig, kastoriFruitTreePatchClear, kastoriFruitTreePatchPlant, kastoriFruitProtect)).withId(131); + kastoriFruitPanel.setLockingStep(kastoriFruitStep); + PanelDetails kastoriCalquatPanel = new PanelDetails("Calquat Patch", Arrays.asList(kastoriCalquatPatchCheckHealth, kastoriCalquatPatchRemove, kastoriCalquatPatchDig, kastoriCalquatPatchClear, kastoriCalquatPatchPlant, kastoriCalquatProtect)).withId(132); + kastoriCalquatPanel.setLockingStep(kastoriCalquatStep); + var kastoriPanel = new TopLevelPanelDetails("Kastori", kastoriFruitPanel, kastoriCalquatPanel).withId(13); kastoriPanel.setLockingStep(kastoriStep); PanelDetails anglersPanel = new PanelDetails("Anglers' Retreat", Arrays.asList(anglersCheckHealth, - anglersClear, anglersPlant)).withId(14); + anglersCutDown, anglersDig, anglersClear, anglersPlant, anglersProtect)).withId(14); anglersPanel.setLockingStep(anglersRetreatStep); PanelDetails greatConchPanel = new PanelDetails("Great Conch", - Arrays.asList(greatConchCalquatPatchCheckHealth, greatConchCalquatPatchClear, - greatConchCalquatPatchPlant)).withId(15); + Arrays.asList(greatConchCalquatPatchCheckHealth, greatConchCalquatPatchRemove, greatConchCalquatPatchDig, greatConchCalquatPatchClear, + greatConchCalquatPatchPlant, greatConchCalquatProtect)).withId(15); greatConchPanel.setLockingStep(greatConchStep); - TopLevelPanelDetails farmRunSidebar = new TopLevelPanelDetails("Tree Run", farmingGuildPanel, lumbridgePanel, faladorPanel, taverleyPanel, - varrockPanel, gnomeStrongholdPanel, villagePanel, catherbyPanel, brimhavenPanel, lletyaPanel, fossilIslandPanel, savannahPanel, auburnvalePanel, + var farmRunSidebar = new TopLevelPanelDetails("Tree Run", farmingGuildPanel, lumbridgePanel, faladorPanel, taverleyPanel, + varrockPanel, gnomeStrongholdPanel, villagePanel, catherbyPanel, karamjaPanel, lletyaPanel, fossilIslandPanel, savannahPanel, auburnvalePanel, kastoriPanel, anglersPanel, greatConchPanel); allSteps.add(farmRunSidebar); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/knightswaves/KnightWaves.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/knightswaves/KnightWaves.java index 9f44d8b9a6..6ab3754e78 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/knightswaves/KnightWaves.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/knightswaves/KnightWaves.java @@ -44,7 +44,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/strongholdofsecurity/StrongholdOfSecurity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/strongholdofsecurity/StrongholdOfSecurity.java index 08eec560ee..c32c524cda 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/strongholdofsecurity/StrongholdOfSecurity.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/mischelpers/strongholdofsecurity/StrongholdOfSecurity.java @@ -31,26 +31,28 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.CombatLevelRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class StrongholdOfSecurity extends BasicQuestHelper { static final String[] CORRECT_ANSWERS = { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/aporcineofinterest/APorcineOfInterest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/aporcineofinterest/APorcineOfInterest.java index 9deed8869e..fd151c9d68 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/aporcineofinterest/APorcineOfInterest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/aporcineofinterest/APorcineOfInterest.java @@ -36,62 +36,60 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class APorcineOfInterest extends BasicQuestHelper { - //Items Required - ItemRequirement rope, slashItem, reinforcedGoggles, combatGear, hoof; - - //Items Recommended - ItemRequirement draynorTeleport, faladorFarmTeleport; + // Required items + ItemRequirement rope; + ItemRequirement slashItem; + ItemRequirement combatGear; - Requirement inCave; + // Recommended items + ItemRequirement draynorTeleport; + ItemRequirement faladorFarmTeleport; - DetailedQuestStep readNotice, talkToSarah, useRopeOnHole, enterHole, investigateSkeleton, talkToSpria, enterHoleAgain, killSourhog, - enterHoleForFoot, cutOffFoot, returnToSarah, returnToSpria; + // Mid-quest item requirements + ItemRequirement reinforcedGoggles; + ItemRequirement hoof; - //Zones + // Zones Zone cave; - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - steps.put(0, readNotice); - steps.put(5, talkToSarah); - steps.put(10, useRopeOnHole); - - ConditionalStep investigateCave = new ConditionalStep(this, enterHole); - investigateCave.addStep(inCave, investigateSkeleton); - - steps.put(15, investigateCave); - - steps.put(20, talkToSpria); + // Miscellaneous requirements + Requirement inCave; - ConditionalStep goKillSourhog = new ConditionalStep(this, enterHoleAgain); - goKillSourhog.addStep(inCave, killSourhog); + // Steps + ObjectStep readNotice; + NpcStep talkToSarah; + ObjectStep useRopeOnHole; + ObjectStep enterHole; + ObjectStep investigateSkeleton; + NpcStep talkToSpria; + ObjectStep enterHoleAgain; + NpcStep killSourhog; + ObjectStep enterHoleForFoot; + ObjectStep cutOffFoot; + NpcStep returnToSarah; + NpcStep returnToSpria; - steps.put(25, goKillSourhog); - ConditionalStep getFootSteps = new ConditionalStep(this, enterHoleForFoot); - getFootSteps.addStep(hoof, returnToSarah); - getFootSteps.addStep(inCave, cutOffFoot); - - steps.put(30, getFootSteps); - steps.put(35, returnToSpria); - return steps; + @Override + protected void setupZones() + { + cave = new Zone(new WorldPoint(3152, 9669, 0), new WorldPoint(3181, 9720, 0)); } @Override @@ -102,6 +100,10 @@ protected void setupRequirements() slashItem = new ItemRequirement("A knife or slash weapon", ItemID.KNIFE).isNotConsumed(); slashItem.setTooltip("Except abyssal whip, abyssal tentacle, noxious halberd, or dragon claws."); + // This is not intended to be a full list, but rather just a reasonable list of slash weapons a user might bring. + // This does not fit super well into an item collection since it's not reusable. + slashItem.addAlternates(ItemID.DRAGON_SCIMITAR, ItemID.RUNE_SCIMITAR, ItemID.ADAMANT_SCIMITAR, ItemID.MITHRIL_SCIMITAR, ItemID.STEEL_SCIMITAR, ItemID.IRON_SCIMITAR, ItemID.BRONZE_SCIMITAR); + slashItem.addAlternates(ItemID.DRAGON_LONGSWORD, ItemID.RUNE_LONGSWORD, ItemID.ADAMANT_LONGSWORD, ItemID.MITHRIL_LONGSWORD, ItemID.STEEL_LONGSWORD, ItemID.IRON_LONGSWORD, ItemID.BRONZE_LONGSWORD); reinforcedGoggles = new ItemRequirement("Reinforced goggles", ItemID.SLAYER_REINFORCED_GOGGLES, 1, true).isNotConsumed(); reinforcedGoggles.setTooltip("You can get another pair from Spria"); @@ -110,22 +112,12 @@ protected void setupRequirements() combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); hoof = new ItemRequirement("Sourhog foot", ItemID.PORCINE_SOURHOG_TROPHY); - hoof.setTooltip("You can get another from Sourhog's corpse in his cave"); // Recommended draynorTeleport = new ItemRequirement("Teleport to north Draynor", ItemID.TELETAB_DRAYNOR); draynorTeleport.addAlternates(ItemCollections.AMULET_OF_GLORIES); faladorFarmTeleport = new ItemRequirement("Teleport to Falador Farm", ItemCollections.EXPLORERS_RINGS); - } - @Override - protected void setupZones() - { - cave = new Zone(new WorldPoint(3152, 9669, 0), new WorldPoint(3181, 9720, 0)); - } - - public void setupConditions() - { inCave = new ZoneRequirement(cave); } @@ -153,7 +145,7 @@ public void setupSteps() enterHoleForFoot = new ObjectStep(this, ObjectID.PORCINE_HOLE, new WorldPoint(3151, 3348, 0), "Climb down into the Strange Hole east of Draynor Manor.", slashItem); cutOffFoot = new ObjectStep(this, ObjectID.PORCINE_DEAD_SOURHOG, "Cut off Sourhog's foot.", slashItem); - ((ObjectStep) cutOffFoot).addAlternateObjects(ObjectID.PORCINE_DEAD_SOURHOG_9); + cutOffFoot.addAlternateObjects(ObjectID.PORCINE_DEAD_SOURHOG_9); cutOffFoot.addSubSteps(enterHoleForFoot); returnToSarah = new NpcStep(this, NpcID.FARMING_SHOPKEEPER_1, new WorldPoint(3033, 3293, 0), "Return to Sarah in the South Falador Farm.", hoof); @@ -162,22 +154,65 @@ public void setupSteps() returnToSpria = new NpcStep(this, NpcID.PORCINE_SPRIA, new WorldPoint(3092, 3267, 0), "Return to Spria in Draynor Village."); } + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, readNotice); + steps.put(5, talkToSarah); + steps.put(10, useRopeOnHole); + + var investigateCave = new ConditionalStep(this, enterHole); + investigateCave.addStep(inCave, investigateSkeleton); + + steps.put(15, investigateCave); + + steps.put(20, talkToSpria); + + var goKillSourhog = new ConditionalStep(this, enterHoleAgain); + goKillSourhog.addStep(inCave, killSourhog); + + steps.put(25, goKillSourhog); + + var getFootSteps = new ConditionalStep(this, enterHoleForFoot); + getFootSteps.addStep(hoof.alsoCheckBank(), returnToSarah); + getFootSteps.addStep(inCave, cutOffFoot); + + steps.put(30, getFootSteps); + steps.put(35, returnToSpria); + + return steps; + } + @Override public List getItemRequirements() { - return Arrays.asList(rope, slashItem, combatGear); + return List.of( + rope, + slashItem, + combatGear + ); } @Override public List getItemRecommended() { - return Arrays.asList(draynorTeleport, faladorFarmTeleport); + return List.of( + draynorTeleport, + faladorFarmTeleport + ); } @Override public List getCombatRequirements() { - return Collections.singletonList("Sourhog (level 37)"); + return List.of( + "Sourhog (level 37)" + ); } @Override @@ -189,28 +224,52 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.SLAYER, 1000)); + return List.of( + new ExperienceReward(Skill.SLAYER, 1000) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("Coins", ItemID.COINS, 5000)); + return List.of( + new ItemReward("Coins", ItemID.COINS, 5000) + ); } @Override public List getUnlockRewards() { - return Arrays.asList(new UnlockReward("30 Slayer Points"), new UnlockReward("Access to Sourhog Cave"), new UnlockReward("Sourhogs can be assigned as a slayer task by Spria")); + return List.of( + new UnlockReward("30 Slayer Points"), + new UnlockReward("Access to Sourhog Cave"), + new UnlockReward("Sourhogs can be assigned as a slayer task by Spria") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Arrays.asList(readNotice, talkToSarah, useRopeOnHole, - enterHole, investigateSkeleton, talkToSpria, enterHoleAgain, killSourhog, cutOffFoot, returnToSarah, - returnToSpria), rope, slashItem, combatGear)); - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Helping Sarah", List.of( + readNotice, + talkToSarah, + useRopeOnHole, + enterHole, + investigateSkeleton, + talkToSpria, + enterHoleAgain, + killSourhog, + cutOffFoot, + returnToSarah, + returnToSpria + ), List.of( + rope, + slashItem, + combatGear + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/bearyoursoul/BearYourSoul.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/bearyoursoul/BearYourSoul.java index 78415423df..3311a96adf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/bearyoursoul/BearYourSoul.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/bearyoursoul/BearYourSoul.java @@ -79,7 +79,7 @@ protected void setupRequirements() { dustyKeyOr70AgilOrKeyMasterTeleport = new KeyringRequirement("Dusty key, or another way to get into the deep Taverley Dungeon", - configManager, KeyringCollection.DUSTY_KEY).isNotConsumed(); + KeyringCollection.DUSTY_KEY).isNotConsumed(); spade = new ItemRequirement("Spade", ItemID.SPADE).isNotConsumed(); damagedSoulBearer = new ItemRequirement("Damaged soul bearer", ItemID.ARCEUUS_SOULBEARER_DAMAGED); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/belowicemountain/BelowIceMountain.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/belowicemountain/BelowIceMountain.java index 47de8ce578..e3846db5da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/belowicemountain/BelowIceMountain.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/belowicemountain/BelowIceMountain.java @@ -34,27 +34,30 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestPointRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcEmoteStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.emote.QuestEmote; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class BelowIceMountain extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/beneathcursedsands/BeneathCursedSands.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/beneathcursedsands/BeneathCursedSands.java index 83dd2522d6..5253b48f53 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/beneathcursedsands/BeneathCursedSands.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/beneathcursedsands/BeneathCursedSands.java @@ -227,7 +227,7 @@ public Map loadSteps() steps.put(78, returnToZahur); steps.put(80, talkToZahur); - ConditionalStep chemistryPuzzle = new ConditionalStep(this, warmUpChemistryEquipment); + ConditionalStep chemistryPuzzle = new ConditionalStep(this, warmUpChemistryEquipment, "Warm up Zahur's Chemistry Equipment."); chemistryPuzzle.addStep(new Conditions(inChemistryPuzzle, chemistryValveLeftStepZero, new Conditions(LogicType.NAND, chemistryValveMiddleAtMaximum)), chemistryValveIncreaseMiddle); chemistryPuzzle.addStep(new Conditions(inChemistryPuzzle, chemistryValveLeftStepZero, chemistryValveMiddleAtMaximum, new Conditions(LogicType.NAND, chemistryValveRightAtMaximum)), chemistryValveIncreaseRight); chemistryPuzzle.addStep(new Conditions(inChemistryPuzzle, chemistryValveLeftStepZero, chemistryValveMiddleAtMaximum, chemistryValveRightAtMaximum), chemistryValveDecreaseRight); @@ -273,8 +273,7 @@ protected void setupRequirements() waterskins.addAlternates(ItemID.WATER_SKIN3, ItemID.WATER_SKIN2, ItemID.WATER_SKIN1); waterskins.setTooltip("Used for protection against the desert heat"); antipoison = new ItemRequirement("Antipoison", ItemCollections.ANTIPOISONS); - accessToFairyRings = new ItemRequirement("Access to Fairy Rings", ItemID.DRAMEN_STAFF).isNotConsumed(); - accessToFairyRings.addAlternates(ItemID.LUNAR_MOONCLAN_LIMINAL_STAFF); + accessToFairyRings = new ItemRequirement("Access to Fairy Rings", ItemCollections.FAIRY_STAFF).isNotConsumed(); pharaohsSceptre = new ItemRequirement("Pharaoh's sceptre", ItemCollections.PHAROAH_SCEPTRE).isNotConsumed(); pharaohsSceptre.setTooltip("When visiting Necropolis during the quest, you can unlock the direct teleport by using 'Commune' on the Obelisk."); food = new ItemRequirement("Food", -1, -1); @@ -600,7 +599,7 @@ public List getPanels() Collections.singletonList(meleeCombatGear), Arrays.asList(waterskins, food))); allSteps.add(new PanelDetails("The Ruins of Ullek", Arrays.asList(talkToMaisaExploreCliffs, goFromCampsiteToRuinsOfUllek, inspectFurnace, useCoalOnFurnace, useTinderboxOnFurnace, searchWell, readStoneTablet, digForChest, openChest, craftEmblem, useEmblemOnPillar, confirmScarabRotation, enterDungeonToFightScarabMages, fightScarabMages, climbDownStairsAgain, pullLever, pullSecondLever, enterRiddleDoor), Arrays.asList(meleeCombatGear, coal, tinderbox, spade, ironBar), Arrays.asList(food, antipoison, waterskins))); allSteps.add(new PanelDetails("Riddle of the Tomb", Arrays.asList(solveTombRiddle, enterTombDoor, talkToSpirit, takeRustyKey))); - allSteps.add(new PanelDetails("The Champion of Scabaras", Arrays.asList(unlockBossDoor, fightChampionOfScabaras, talkToScabarasHighPriest), Arrays.asList(rangedCombatGear, food, rustyKey))); + allSteps.add(new PanelDetails("The Champion of Scabaras", Arrays.asList(unlockBossDoor, fightChampionOfScabaras, talkToScabarasHighPriest), Arrays.asList(rangedCombatGear, food, rustyKey), Collections.singletonList(antipoison))); allSteps.add(new PanelDetails("Cure for the Pox", Arrays.asList(talkToMaisaInNardah, purchaseBeef, attemptSteppingStones, pickLilyOfElid, takeLilyToZahur, talkToZahur, chemistryPuzzleWrapped, bringCureToPriest), Arrays.asList(meat, waterskins))); allSteps.add(new PanelDetails("Fight with the Menaphite Akh", Arrays.asList(prepareFightMenaphiteAkh, defeatMenaphiteAkh, finishQuest), Arrays.asList(meleeCombatGear, waterskins))); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/biohazard/Biohazard.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/biohazard/Biohazard.java index ce4261b542..599a40d694 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/biohazard/Biohazard.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/biohazard/Biohazard.java @@ -34,14 +34,27 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -50,10 +63,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class Biohazard extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/blackknightfortress/BlackKnightFortress.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/blackknightfortress/BlackKnightFortress.java index 519d968d12..83034fa512 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/blackknightfortress/BlackKnightFortress.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/blackknightfortress/BlackKnightFortress.java @@ -7,26 +7,28 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestPointRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class BlackKnightFortress extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/childrenofthesun/ChildrenOfTheSun.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/childrenofthesun/ChildrenOfTheSun.java index ecd69d4c0b..8b1e3003ad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/childrenofthesun/ChildrenOfTheSun.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/childrenofthesun/ChildrenOfTheSun.java @@ -28,21 +28,29 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.MultiNpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class ChildrenOfTheSun extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clientofkourend/ClientOfKourend.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clientofkourend/ClientOfKourend.java index 4c082429a5..b235536b89 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clientofkourend/ClientOfKourend.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clientofkourend/ClientOfKourend.java @@ -31,6 +31,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; @@ -39,19 +40,16 @@ import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class ClientOfKourend extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clocktower/ClockTower.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clocktower/ClockTower.java index 46acb955f2..2ff138277c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clocktower/ClockTower.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/clocktower/ClockTower.java @@ -34,6 +34,10 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ObjectCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; @@ -41,20 +45,22 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class ClockTower extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/cooksassistant/CooksAssistant.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/cooksassistant/CooksAssistant.java index 4ad5754e8c..f04f5f3252 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/cooksassistant/CooksAssistant.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/cooksassistant/CooksAssistant.java @@ -29,6 +29,9 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -36,8 +39,16 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -45,13 +56,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class CooksAssistant extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/creatureoffenkenstrain/CreatureOfFenkenstrain.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/creatureoffenkenstrain/CreatureOfFenkenstrain.java index 4fdea31910..547898726d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/creatureoffenkenstrain/CreatureOfFenkenstrain.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/creatureoffenkenstrain/CreatureOfFenkenstrain.java @@ -151,7 +151,9 @@ protected void setupRequirements() silverBar = new ItemRequirement("Silver bar", ItemID.SILVER_BAR); bronzeWire = new ItemRequirement("Bronze wire", ItemID.BRONZECRAFTWIRE, 3); needle = new ItemRequirement("Needle", ItemID.NEEDLE).isNotConsumed(); + needle.setTooltip("Costume needle cannot be used as a substitute"); thread = new ItemRequirement("Thread", ItemID.THREAD, 5); + thread.setTooltip("Costume needle cannot be used as a substitute"); spade = new ItemRequirement("Spade", ItemID.SPADE).isNotConsumed(); coins = new ItemRequirement("Coins at least", ItemCollections.COINS, 100); pickledBrain = new ItemRequirement("Pickled Brain", ItemID.FENK_BRAIN); @@ -268,7 +270,7 @@ public void setupSteps() marbleAmulet.highlighted(), obsidianAmulet.highlighted()); - goDownstairsForStar = new ObjectStep(this, ObjectID.FENK_STAIRS_LV1_TOP, new WorldPoint(3573, 3553, 1), + goDownstairsForStar = new ObjectStep(this, ObjectID.FENK_STAIRS_LV1_TOP, new WorldPoint(3537, 3553, 1), "Go back to the ground floor."); talkToGardenerForHead = new NpcStep(this, NpcID.FENK_GARDENER, new WorldPoint(3548, 3562, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/currentaffairs/CurrentAffairs.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/currentaffairs/CurrentAffairs.java index 97ce8a564d..2a4a10435c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/currentaffairs/CurrentAffairs.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/currentaffairs/CurrentAffairs.java @@ -34,13 +34,25 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.BoardShipStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.SailStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -49,14 +61,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; - public class CurrentAffairs extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathontheisle/DeathOnTheIsle.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathontheisle/DeathOnTheIsle.java index 8388fcbd67..08816c59f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathontheisle/DeathOnTheIsle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathontheisle/DeathOnTheIsle.java @@ -37,6 +37,8 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -45,7 +47,15 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -54,14 +64,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; - /** * The quest guide for the "Death on the Isle" OSRS quest *

@@ -499,6 +501,7 @@ public void setupSteps() accuseAdala.addDialogStep("Accuse Adala."); fightAdala = new NpcStep(this, NpcID.DOTI_ADALA_MASK_INSIDE, new WorldPoint(1446, 2933, 2), "Fight Adala. You cannot lose this fight."); + fightAdala.addAlternateNpcs(NpcID.DOTI_ADALA_BOSS); accuseAdala.addSubSteps(fightAdala); speakToSuspects = new ConditionalStep(this, accuseAdala); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathtothedorgeshuun/DeathToTheDorgeshuun.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathtothedorgeshuun/DeathToTheDorgeshuun.java index 793be31c67..894d00748c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathtothedorgeshuun/DeathToTheDorgeshuun.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deathtothedorgeshuun/DeathToTheDorgeshuun.java @@ -48,7 +48,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/DemonSlayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/DemonSlayer.java index bed24ba5eb..c9f5b58de0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/DemonSlayer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/DemonSlayer.java @@ -30,26 +30,28 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class DemonSlayer extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/IncantationStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/IncantationStep.java index 92ddb2cc21..d377e5721b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/IncantationStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/demonslayer/IncantationStep.java @@ -27,13 +27,12 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.HashMap; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.VarbitID; import net.runelite.api.widgets.Widget; -import java.util.HashMap; - public class IncantationStep extends ConditionalStep { private final HashMap words = new HashMap<>() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasure/DesertTreasure.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasure/DesertTreasure.java index d3b3351819..d2e1f0448a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasure/DesertTreasure.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasure/DesertTreasure.java @@ -49,6 +49,7 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.api.NullItemID; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -58,7 +59,6 @@ import net.runelite.api.gameval.VarbitID; import java.util.*; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; public class DesertTreasure extends BasicQuestHelper @@ -428,7 +428,7 @@ public void setupSteps() talkToArchaeologistAgainAfterTranslation = new NpcStep(this, NpcID.FOURDIAMONDS_INDIANA_VIS, new WorldPoint(3177, 3043, 0), "Talk to the Archaeologist again."); talkToArchaeologistAgainAfterTranslation.addDialogStep("Help him"); talkToArchaeologistAgainAfterTranslation.addTeleport(bedabinTeleport); - buyDrink = new NpcStep(this, NpcID.FOURDIAMONDS_BARTENDER, new WorldPoint(3159, 2978, 0), "Buy a drink from the pub in the Bandit Camp, then talk to the Bartender again.", coins650); + buyDrink = new NpcStep(this, NpcID.FOURDIAMONDS_BARTENDER, new WorldPoint(3159, 2978, 0), "Unequip any god-related items you have on, or else you'll be attacked by bandits. Go buy a drink from the pub in the Bandit Camp, then talk to the Bartender again.", coins650); buyDrink.addDialogStep("Buy a drink"); buyDrink.addDialogStep("Buy a beer"); talkToBartender = new NpcStep(this, NpcID.FOURDIAMONDS_BARTENDER, new WorldPoint(3159, 2978, 0), "Talk to the bartender in the Bandit Camp again."); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/DesertTreasureII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/DesertTreasureII.java index b37cd43295..1c2a8b1d31 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/DesertTreasureII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/DesertTreasureII.java @@ -64,7 +64,9 @@ import java.util.*; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; public class DesertTreasureII extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/PerseriyaSteps.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/PerseriyaSteps.java index b53c01c74e..709bf37e78 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/PerseriyaSteps.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/PerseriyaSteps.java @@ -47,7 +47,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Prayer; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; import java.util.Arrays; import java.util.List; @@ -451,9 +455,7 @@ protected void setupConditions() natureAxonPresent = new NpcRequirement(NpcID.DT2_SCAR_MAZE_3_PATHING_NPC, "Abyssal Axon (Nature)"); completedAxonRoom = new VarbitRequirement(VarbitID.DT2_SCAR_MAZE_CHALLENGE_1_DONE, 1); - nothingInHands = and(new NoItemRequirement("Weapon", ItemSlots.WEAPON), - new NoItemRequirement("Shield", ItemSlots.SHIELD)); - ((Conditions) nothingInHands).setText("Nothing equipped in your hands"); + nothingInHands = new NoItemRequirement("Nothing equipped in your hands.", ItemSlots.EMPTY_HANDS); inNorthOfAbyssRoom2 = new ZoneRequirement(northAbyssRoom2P1, northAbyssRoom2P2, northAbyssRoom2P3, northAbyssRoom2P4, northAbyssRoom2P5); inNerveRoom = new ZoneRequirement(nerveRoom1, nerveRoom2, nerveRoom3); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/WhispererSteps.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/WhispererSteps.java index 19ddc89833..de5cb1dfd0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/WhispererSteps.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deserttreasureii/WhispererSteps.java @@ -1371,7 +1371,7 @@ protected void setupSteps() fightWhispererSidebar.addText("Corrupted seeds: Activate the blackstone fragment in your inventory. Avoid the dark green seeds, and step on the light green ones."); fightWhispererSidebar.addText("Screech: Pillars appear, which you must hide behind to avoid damage."); fightWhispererSidebar.addText("After each special attack, the Whisperer fire out a binding spell if you are within 10 tiles of her, dealing Melee damage."); - fightWhispererSidebar.addText("When she hits 0 health, she will heal back to 100, and start attacking rapidly with random ranged and magic attacks. Finish her off."); + fightWhispererSidebar.addText("When she hits 0 health, she will heal back to 100, and start attacking rapidly, starting with ranged, and alternating every two attacks until the fight ends. Finish her off."); fightWhispererSidebar.addSubSteps(enterTheCathedral, enterRuinsOfCamdozaalFight, descendDownRopeFight); searchEntrails = new ObjectStep(getQuestHelper(), ObjectID.WHISPERER_MEDALLION_LOC, new WorldPoint(2656, 6370, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deviousminds/DeviousMinds.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deviousminds/DeviousMinds.java index 54925d6b55..0e586106b2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deviousminds/DeviousMinds.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/deviousminds/DeviousMinds.java @@ -170,10 +170,9 @@ public void setupSteps() talkToMonk2 = new NpcStep(this, NpcID.DEVIOUS_MONK_HOODED_VISABLE, new WorldPoint(3406, 3494, 0), "Return to the monk near the Paterdomus temple with the bow-sword.", bowSword); talkToMonk2.addDialogStep("Yep, got it right here for you."); - makeIllumPouch = new DetailedQuestStep(this, "Use the Orb on the Large/Colossal Pouch.", orb, largePouch); - + makeIllumPouch = new DetailedQuestStep(this, "Use the Orb on the Large/Colossal Pouch. You will also be going to Entrana via the Abyss, so you must bank all combat gear.", orb, largePouch); teleToAbyss = new NpcStep(this, NpcID.RCU_ZAMMY_MAGE1B, new WorldPoint(3106, 3556, 0), - "Teleport with the Mage of Zamorak IN THE WILDERNESS to the Abyss. You will be attacked by " + + "Teleport with the Mage of Zamorak IN THE WILDERNESS (other players can attack you here) to the Abyss. You will be attacked by " + "monsters upon entering, and your prayer drained to 0!", illumPouch, noEquipment); enterLawRift = new ObjectStep(this, ObjectID.ABYSS_EXIT_TO_LAW, new WorldPoint(3049, 4839, 0), "Enter the central area through a gap/passage/eyes. Enter the Law Rift.", illumPouch, noEquipment); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/doricsquest/DoricsQuest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/doricsquest/DoricsQuest.java index 4172c26e46..5dc9bbf948 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/doricsquest/DoricsQuest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/doricsquest/DoricsQuest.java @@ -35,33 +35,24 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; -import java.util.*; - public class DoricsQuest extends BasicQuestHelper { - //Items Required - ItemRequirement clay, copper, iron; - - //NPC Steps - QuestStep talkToDoric; - - @Override - public Map loadSteps() - { - initializeRequirements(); - setupSteps(); - Map steps = new HashMap<>(); + // Required items + ItemRequirement clay; + ItemRequirement copper; + ItemRequirement iron; - steps.put(0, talkToDoric); - steps.put(10, talkToDoric); - - return steps; - } + // Steps + NpcStep talkToDoric; @Override protected void setupRequirements() @@ -75,25 +66,41 @@ public void setupSteps() { talkToDoric = new NpcStep(this, NpcID.DORIC, new WorldPoint(2951, 3451, 0), "Bring Doric north of Falador all the required items. You can mine them all in the Dwarven Mines, or buy them from the Grand Exchange.", clay, copper, iron); talkToDoric.addDialogStep("I wanted to use your anvils."); + talkToDoric.addDialogStep("Yes."); talkToDoric.addDialogStep("Yes, I will get you the materials."); } + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToDoric); + steps.put(10, talkToDoric); + + return steps; + } + + @Override public List getGeneralRecommended() { - ArrayList req = new ArrayList<>(); - req.add(new SkillRequirement(Skill.MINING, 15, true, "15 Mining to get ores yourself")); - return req; + return List.of( + new SkillRequirement(Skill.MINING, 15, true, "15 Mining to get ores yourself") + ); } @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(clay); - reqs.add(copper); - reqs.add(iron); - return reqs; + return List.of( + clay, + copper, + iron + ); } @Override @@ -105,27 +112,40 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.MINING, 1300)); + return List.of( + new ExperienceReward(Skill.MINING, 1300) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("Coins", ItemID.COINS, 180)); + return List.of( + new ItemReward("Coins", ItemID.COINS, 180) + ); } @Override public List getUnlockRewards() { - return Collections.singletonList(new UnlockReward("Use of Doric's Anvil")); + return List.of( + new UnlockReward("Use of Doric's Anvil") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); + var sections = new ArrayList(); + + sections.add(new PanelDetails("Help Doric", List.of( + talkToDoric + ), List.of( + clay, + copper, + iron + ))); - allSteps.add(new PanelDetails("Help Doric", Collections.singletonList(talkToDoric), clay, copper, iron)); - return allSteps; + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dragonslayer/DragonSlayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dragonslayer/DragonSlayer.java index 2fceb71686..d5e7af0eff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dragonslayer/DragonSlayer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dragonslayer/DragonSlayer.java @@ -45,7 +45,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/druidicritual/DruidicRitual.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/druidicritual/DruidicRitual.java index 80cc332f19..1f8b5c5037 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/druidicritual/DruidicRitual.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/druidicritual/DruidicRitual.java @@ -27,6 +27,7 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; @@ -36,19 +37,16 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - /** * The quest guide for the "Druidic Ritual" OSRS quest *

diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dwarfcannon/DwarfCannon.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dwarfcannon/DwarfCannon.java index 7e6ee12102..8c2869f0d9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dwarfcannon/DwarfCannon.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/dwarfcannon/DwarfCannon.java @@ -30,6 +30,8 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetPresenceRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -37,18 +39,23 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.WidgetStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; public class DwarfCannon extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopi/ElementalWorkshopI.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopi/ElementalWorkshopI.java index 8f0b2679b2..8975eb83aa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopi/ElementalWorkshopI.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopi/ElementalWorkshopI.java @@ -49,7 +49,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.ArrayList; import java.util.Arrays; @@ -150,7 +154,7 @@ protected void setupRequirements() slashedBook = new ItemRequirement("Slashed book", ItemID.ELEMENTAL_WORKSHOP_SHIELD_BOOK_SLASHED); slashedBook.setTooltip("If you've lost it you can get another by searching the bookcase in the building south of " + "the odd wall"); - batteredKey = new KeyringRequirement("Battered Key", configManager, KeyringCollection.BATTERED_KEY); + batteredKey = new KeyringRequirement("Battered Key", KeyringCollection.BATTERED_KEY); batteredKey.setTooltip("If you've lost it you can get another by searching the bookcase in the building south of " + "the odd wall"); elementalOre = new ItemRequirement("Elemental ore", ItemID.ELEMENTAL_WORKSHOP_ORE); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopii/ElementalWorkshopII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopii/ElementalWorkshopII.java index fb8073b2e4..321ba648f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopii/ElementalWorkshopII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/elementalworkshopii/ElementalWorkshopII.java @@ -67,7 +67,7 @@ public class ElementalWorkshopII extends BasicQuestHelper ItemRequirement camelotTeleport, digsiteTeleport; ItemRequirement elementalOre, elementalBar, mindBar, primedBar, beatenBook, scroll, key, craneSchematic, claw, - smallCog, mediumCog, largeCog, pipe; + smallCog, mediumCog, largeCog, pipe, slashedBook; Requirement magic20; @@ -256,7 +256,7 @@ protected void setupRequirements() pickaxe = new ItemRequirement("Any pickaxe", ItemCollections.PICKAXES).isNotConsumed(); hammer = new ItemRequirement("Hammer", ItemCollections.HAMMER).isNotConsumed(); coal = new ItemRequirement("Coal", ItemID.COAL, 8); - batteredKey = new KeyringRequirement("Battered Key", configManager, KeyringCollection.BATTERED_KEY); + batteredKey = new KeyringRequirement("Battered Key", KeyringCollection.BATTERED_KEY); batteredKey.setTooltip("You can get another by searching the bookcase in the house south of the elemental " + "workshop's entrance"); @@ -266,9 +266,9 @@ protected void setupRequirements() elementalOre = new ItemRequirement("Elemental ore", ItemID.ELEMENTAL_WORKSHOP_ORE); elementalOre.addAlternates(ItemID.ELEMENTAL_WORKSHOP_BAR); - elementalBar = new ItemRequirement("Elemental metal", ItemID.ELEMENTAL_WORKSHOP_BAR); + elementalBar = new ItemRequirement("Elemental metal. Bring an additional elemental metal if you want to smith a mind shield after this quest", ItemID.ELEMENTAL_WORKSHOP_BAR); mindBar = new ItemRequirement("Primed mind bar", ItemID.ELEM_MIND_BAR); - primedBar = new ItemRequirement("Primed bar", ItemID.ELEM_PRIMED_BAR); + primedBar = new ItemRequirement("Primed bar. Bring an additional primed bar if you want to smith a mind shield after this quest", ItemID.ELEM_PRIMED_BAR); beatenBook = new ItemRequirement("Beaten book", ItemID.ELEMENTAL_WORKSHOP_HELM_BOOK); beatenBook.setTooltip("You can get another from a bookcase in the Exam Center"); @@ -287,6 +287,10 @@ protected void setupRequirements() pipe = new ItemRequirement("Pipe", ItemID.ELEM2_SPARE_PIPE); magic20 = new SkillRequirement(Skill.MAGIC, 20, true); + + slashedBook = new ItemRequirement("Slashed book if you want to smith a mind shield after this quest", ItemID.ELEMENTAL_WORKSHOP_SHIELD_BOOK_SLASHED); + slashedBook.setTooltip("If you've lost it you can get another by searching the bookcase in the building south of " + + "the odd wall"); } @Override @@ -424,7 +428,7 @@ public void setupSteps() readScroll = new DetailedQuestStep(this, "Read the scroll.", scroll.highlighted()); enterWorkshop = new ObjectStep(this, ObjectID.ELEMENTAL_WORKSHOP_SPIRALSTAIRSTOP, new WorldPoint(2711, 3498, 0), - "Enter the elemental workshop.", batteredKey, beatenBook); + "Enter the elemental workshop.", Arrays.asList(batteredKey, beatenBook), Collections.singletonList(slashedBook)); searchMachinery = new ObjectStep(this, ObjectID.ELEMENTAL_WORKSHOP_2_BOILER_MULTI, new WorldPoint(2715, 9903, 0), ""); @@ -444,6 +448,7 @@ public void setupSteps() mineRock = new NpcStep(this, NpcID.ELEM1_QIP_EARTH_ELEMENTAL_ROCK_VERSION_ROCK, new WorldPoint(2703, 9894, 0), "You need 2 elemental bars. Mine one of the elemental rocks in the west room, ready to fight a level 35.", true, pickaxe); + mineRock.addText("If you want to smith a mind shield after this quest, get a third elemental ore and also smelt it into a bar."); killRock = new NpcStep(this, NpcID.ELEM1_QIP_EARTH_ELEMENTAL_ROCK_VERSION, new WorldPoint(2703, 9897, 0), "Kill the rock elemental that appeared."); pickUpOre = new ItemStep(this, "Pick up the elemental ore.", elementalOre); @@ -520,7 +525,7 @@ public void setupSteps() raiseCraneFromBar = new ObjectStep(this, ObjectID.ELEM2_FIRE_LEVER_2, new WorldPoint(1953, 5148, 2), "Pull the south west lever to raise the claw once more."); pullLeverToMoveToPress = new ObjectStep(this, ObjectID.ELEM2_LEVER_3WAY, new WorldPoint(1953, 5151, 2), - "Pull the central lever to move the jig to the press."); + "Pull the central lever to activate the press."); lowerPress = new ObjectStep(this, ObjectID.ELEM2_EARTH_LEVER_1, new WorldPoint(1950, 5153, 2), "Pull the west lever to move the jig to the press."); pullLeverToMoveToTank = new ObjectStep(this, ObjectID.ELEM2_LEVER_3WAY, new WorldPoint(1953, 5151, 2), @@ -558,6 +563,7 @@ public void setupSteps() pullLeverToMoveToLava = new ObjectStep(this, ObjectID.ELEM2_LEVER_3WAY, new WorldPoint(1953, 5151, 2), "Pull the central lever to move the jig back to the start."); pickUpBar = new NpcStep(this, NpcID.ELEM2_CART_NPC_FLAT_BAR_DRY, new WorldPoint(1954, 5147, 2), "Pick up the primed bar."); + pickUpBar.addText("If you want to smith a mind shield after this quest, repeat this process one more time."); goDownToBasement = new ObjectStep(this, ObjectID.ELEM2_STAIRS_DOOR_OPEN_NO_HATCH, new WorldPoint(1949, 5159, 2), "Go down from the priming room."); @@ -568,11 +574,13 @@ public void setupSteps() "Sit in the extractor chair.", magic20); takeMindBar = new ObjectStep(this, ObjectID.ELEM_EXTRACTOR_GUN, new WorldPoint(1962, 5148, 0), "Take the mind bar."); + takeMindBar.addText("If you want to smith a mind shield after this quest, repeat this process one more time."); goUpFromBasement = new ObjectStep(this, ObjectID.ELEM2_STAIRS2, new WorldPoint(1949, 5160, 0), "Go up the stairs."); makeMindHelmet = new ObjectStep(this, ObjectID.ELEMENTAL_WORKSHOP_WORKBENCH, new WorldPoint(2717, 9888, 0), - "Use the mind bar on one of the workbenches in the central room.", mindBar.highlighted(), hammer, + "Use the mind bar on one of the workbenches in the central room with the beaten book in your inventory.", mindBar.highlighted(), hammer, beatenBook); + makeMindHelmet.addText("If you want to smith a mind shield after this quest, use the remaining mind bar on one of the workbenches with the slashed book in your inventory."); makeMindHelmet.addIcon(ItemID.ELEM_MIND_BAR); goToWorkshopTopFloor = new ConditionalStep(this, enterWorkshop); @@ -605,7 +613,7 @@ public List getItemRequirements() @Override public List getItemRecommended() { - return Arrays.asList(digsiteTeleport, camelotTeleport); + return Arrays.asList(digsiteTeleport, camelotTeleport, slashedBook); } @Override @@ -656,8 +664,8 @@ public ArrayList getPanels() ArrayList allSteps = new ArrayList<>(); allSteps.add(new PanelDetails("Starting off", Arrays.asList(searchBookcase, readBook, readScroll))); - allSteps.add(new PanelDetails("Unlocking the Hatch", Arrays.asList(getKey, unlockHatch), batteredKey, pickaxe, - coal.quantity(8), hammer)); + allSteps.add(new PanelDetails("Unlocking the Hatch", Arrays.asList(getKey, unlockHatch), Arrays.asList(batteredKey, pickaxe, + coal.quantity(8), hammer, beatenBook), Collections.singletonList(slashedBook))); allSteps.add(new PanelDetails("Repairing the crane", Arrays.asList(takeSchematics, goMakeClaw, goRepairCrane))); allSteps.add(new PanelDetails("Repairing the workshop", Arrays.asList(goSortTubes, getCogsAndPipe, goRepairPipe, goPlaceCogs))); @@ -666,10 +674,10 @@ public ArrayList getPanels() pullLeverToMoveToPress, lowerPress, pullLeverToMoveToTank, pullLeverToOpenTankDoor, turnCorkscrew, turnCorkscrewAgain, pullLeverToCloseTankDoor, turnWestValve, turnEastValve, turnEastValveAgain, turnWestValveAgain, pullLeverToOpenTankDoorAgain, turnCorkscrewToRetrieve, turnCorkscrewToRetrieveAgain, pullLeverToCloseTankDoorAgain, pullLeverToMoveToFan, pullFanLever, - pullFanLeverAgain, pullLeverToMoveToLava, pickUpBar), elementalBar)); + pullFanLeverAgain, pullLeverToMoveToLava, pickUpBar), Collections.singletonList(elementalBar))); allSteps.add(new PanelDetails("Making a Mind Helm", Arrays.asList(goDownToBasement, useBarOnGun, operateHat, - takeMindBar, goMakeMindHelmet), primedBar, hammer, beatenBook)); + takeMindBar, goMakeMindHelmet), Arrays.asList(primedBar, hammer, beatenBook), Collections.singletonList(slashedBook))); return allSteps; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enakhraslament/EnakhrasLament.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enakhraslament/EnakhrasLament.java index b1a5569109..39713541b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enakhraslament/EnakhrasLament.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enakhraslament/EnakhrasLament.java @@ -51,10 +51,7 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class EnakhrasLament extends BasicQuestHelper { @@ -265,7 +262,10 @@ protected void setupRequirements() camelHead.setHighlightInInventory(true); breadOrCake = new ItemRequirement("Bread or cake", ItemID.BREAD); - breadOrCake.addAlternates(ItemID.CAKE); + // Excluded mud pie, botanical pie, mushroom pie, dragonfruit pie as unsure if those would work due to inedibility and/or newness of pie + breadOrCake.addAlternates(ItemID.CAKE, ItemID.CHOCOLATE_CAKE, ItemID.REDBERRY_PIE, ItemID.MEAT_PIE, ItemID.APPLE_PIE, ItemID.GARDEN_PIE, ItemID.FISH_PIE, ItemID.ADMIRAL_PIE, ItemID.WILD_PIE, ItemID.SUMMER_PIE); + breadOrCake.addAlternates(ItemID.PLAIN_PIZZA, ItemID.MEAT_PIZZA, ItemID.ANCHOVIE_PIZZA, ItemID.PINEAPPLE_PIZZA); + breadOrCake.addAlternates(ItemID.POTATO_BUTTER, ItemID.POTATO_CHILLI_CARNE, ItemID.POTATO_CHEESE, ItemID.POTATO_EGG_TOMATO, ItemID.POTATO_MUSHROOM_ONION, ItemID.POTATO_TUNA_SWEETCORN); breadOrCake.setHighlightInInventory(true); breadOrCake.setDisplayMatchedItemName(true); @@ -469,7 +469,8 @@ public void setupSteps() goUpFromPuzzleRoom = new ObjectStep(this, ObjectID.ENAKH_TEMPLE_LADDERUP, new WorldPoint(3104, 9332, 1), "Go up the ladder."); passBarrier.addSubSteps(goUpFromPuzzleRoom); - castCrumbleUndead = new NpcStep(this, NpcID.ENAKH_BONEGUARD, new WorldPoint(3104, 9307, 2), "Cast crumble undead on the Boneguard.", earth2, + castCrumbleUndead = new NpcStep(this, NpcID.ENAKH_BONEGUARD, new WorldPoint(3104, 9307, 2), "Cast crumble undead on the Boneguard. " + + "Make sure you take off any armour or weapons which give you a negative magic attack bonus or else you might splash.", earth2, airRuneOrStaff, chaos, onNormals); goDownToFinalRoom = new ObjectStep(this, ObjectID.ENAKH_TEMPLE_PILLAR_LADDER_TOP, new WorldPoint(3105, 9300, 2), "Climb down the stone ladder past " + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enlightenedjourney/EnlightenedJourney.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enlightenedjourney/EnlightenedJourney.java index 823408f905..db91052f07 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enlightenedjourney/EnlightenedJourney.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/enlightenedjourney/EnlightenedJourney.java @@ -196,7 +196,7 @@ public void setupSteps() "Bowl."); talkToAugusteWithBranches = new ObjectStep(this, ObjectID.ZEP_MULTI_BASKET_ENTRANA, new WorldPoint(2807, 3356, 0), - "Get 12 willow branches and use them to make the basket.", willowBranches12.highlighted()); + "Get 12 willow branches and use them on the platform next to Auguste to make the basket.", willowBranches12.highlighted()); talkToAugusteWithBranches.addIcon(ItemID.WILLOW_BRANCH); talkToAugusteWithLogsAndTinderbox = new NpcStep(this, NpcID.ZEP_PICCARD, new WorldPoint(2809, 3354, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytalei/FairytaleI.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytalei/FairytaleI.java index f02e3723d9..8804eb7698 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytalei/FairytaleI.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytalei/FairytaleI.java @@ -216,6 +216,7 @@ public void setupSteps() "you're right!"); talkToFarmers = new NpcStep(this, NpcID.ELSTAN, "Talk to 5 farmers, then return to Martin in Draynor Village. The recommended 5 are:"); + talkToFarmers.addText("If you don't already have one, a secateurs can be purchased from Sarah in South Falador Farm"); talkToFarmers.addText("Frizzy in Port Sarim."); talkToFarmers.addText("Elstan north west of Draynor."); talkToFarmers.addText("Heskel in Falador Park."); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytaleii/FairytaleII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytaleii/FairytaleII.java index e582ddf6ba..26ea977cd5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytaleii/FairytaleII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fairytaleii/FairytaleII.java @@ -266,10 +266,10 @@ public void setupSteps() dramenOrLunarStaff.equipped()); goToHideout = new ObjectStep(this, ObjectID.FAIRYRING_HOMEHUB, new WorldPoint(2412, 4434, 0), - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); goToHideoutSurface = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); goToHideout.addSubSteps(goToHideoutSurface); //varp 817 2->112->133->31 for each destination @@ -285,20 +285,20 @@ public void setupSteps() pickpocketGodfather.addSubSteps(returnToZanarisFromBase, goToZanarisToPickpocket); goToHideoutWithSec = new ObjectStep(this, ObjectID.FAIRYRING_HOMEHUB, new WorldPoint(2412, 4434, 0), - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate, queensSecateurs); goToHideoutSurfaceWithSec = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate, queensSecateurs); giveSecateursToNuff = new NpcStep(this, NpcID.FAIRY_NUFF2, new WorldPoint(2355, 4455, 0), "Give Fairy Nuff the Queen's Secateurs.", queensSecateurs); goToHideoutAfterSec = new ObjectStep(this, ObjectID.FAIRYRING_HOMEHUB, new WorldPoint(2412, 4434, 0), - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); goToHideoutSurfaceAfterSec = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); talkToNuffAfterSec = new NpcStep(this, NpcID.FAIRY_NUFF2, new WorldPoint(2355, 4455, 0), "Talk to Fairy Nuff."); @@ -327,7 +327,7 @@ public void setupSteps() gorakClawPowder.highlighted(), magicEssenceUnf.highlighted(), herbReq); goToHideout2 = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate, magicEssence); ((ObjectStep) goToHideout2).addAlternateObjects(ObjectID.FAIRYRING_HOMEHUB); @@ -336,7 +336,7 @@ public void setupSteps() usePotionOnQueen.addIcon(ItemID._3DOSEMAGICESS); goToHideoutToFinish = new ObjectStep(this, ObjectID.FAIRYRING_MINORHUB, - "Use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); + "While carrying Nuff's certificate, use the Fairy Rings to travel to A.I.R., D.L.R., D.J.Q. then A.J.S.", dramenOrLunarStaff.equipped(), fairyCertificate); ((ObjectStep) goToHideoutToFinish).addAlternateObjects(ObjectID.FAIRYRING_HOMEHUB); talkToQueen = new NpcStep(this, NpcID.FAIRY_QUEEN2, new WorldPoint(2354, 4455, 0), "Talk to the Fairy Queen."); @@ -414,7 +414,7 @@ public ArrayList getPanels() allSteps.add(new PanelDetails("Making a cure", Arrays.asList(goToCkp, waitForStarFlower, pickStarFlower, goToDir, killGorak, pickupGorakClaw, useStarFlowerOnVial, usePestleOnClaw, usePowderOnPotion, - goToHideout2, usePotionOnQueen, talkToQueen), dramenOrLunarStaff, vialOfWater, pestleAndMortar)); + goToHideout2, usePotionOnQueen, talkToQueen), dramenOrLunarStaff, vialOfWater, pestleAndMortar, fairyCertificate)); return allSteps; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fightarena/FightArena.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fightarena/FightArena.java index 8d6552c90a..4376f9b050 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fightarena/FightArena.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/fightarena/FightArena.java @@ -32,6 +32,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; @@ -41,19 +42,16 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class FightArena extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/forgettabletale/ForgettableTale.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/forgettabletale/ForgettableTale.java index 3c6629d302..aa59562de7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/forgettabletale/ForgettableTale.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/forgettabletale/ForgettableTale.java @@ -69,7 +69,7 @@ public class ForgettableTale extends BasicQuestHelper Requirement inKelgdagrim, inWolfUnderground, inPubUpstairs, inConsortium, inPuzzleRoom, givenBeerToDrunkenDwarf, rowdyDwarfMadeRequest, gotRowdySeed, gotKhorvakSeed, gotGaussSeed, plotRaked, keldaGrowing, keldaGrown, - addedWater, addedYeast, addedHop, addedMalt, keldaBrewed, keldaInBarrel, handsFree, shieldFree; + addedWater, addedYeast, addedHop, addedMalt, keldaBrewed, keldaInBarrel, handsFree; Requirement inPurple, inYellow, inBlue, inGreen, inSilver, inWhite, inBrown; @@ -448,8 +448,7 @@ public void setupConditions() inSilver = new VarbitRequirement(VarbitID.GIANTDWARF_CURRENT_COMPANY, 6); // Silver Cog inBrown = new VarbitRequirement(VarbitID.GIANTDWARF_CURRENT_COMPANY, 7); // Brown Engine - handsFree = new NoItemRequirement("No weapon equipped", ItemSlots.WEAPON); - shieldFree = new NoItemRequirement("No shield equipped", ItemSlots.SHIELD); + handsFree = new NoItemRequirement("No weapon or shield equipped", ItemSlots.EMPTY_HANDS); // 837 = 1, entered first puzzle // 839 = 1, cutscene entering done @@ -654,7 +653,7 @@ else if (inBrown.check(client)) goDownFromDirector = new ObjectStep(this, ObjectID.DWARF_KELDAGRIM_WIDE_STAIRS_UPPER, new WorldPoint(2895, 10210, 1), "Go downstairs."); takeSecretCart = new ObjectStep(this, ObjectID.KELDAGRIM_TRAIN_CART, new WorldPoint(2919, 10164, 0), - "", handsFree, shieldFree); + "", handsFree); searchBox1 = new ObjectStep(this, ObjectID.KELDAGRIM_TRACK_JUNCTION_CARD_BOX, new WorldPoint(1862, 4954, 1), "Search the box."); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gardenoftranquility/GardenOfTranquillity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gardenoftranquility/GardenOfTranquillity.java index 8a33e11140..2fcf1cf347 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gardenoftranquility/GardenOfTranquillity.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gardenoftranquility/GardenOfTranquillity.java @@ -457,7 +457,7 @@ public void setupSteps() wateringCan.highlighted()); talkToAlthric = new NpcStep(this, NpcID.BROTHER_ALTHRIC, new WorldPoint(3052, 3502, 0), - "Talk to Brother Altheric in the Edgeville Monastery.", ringOfCharosA.equipped()); + "Talk to Brother Althric in the Edgeville Monastery.", ringOfCharosA.equipped()); talkToAlthric.addDialogSteps("[Charm] These are the most beautiful rosebushes I've ever seen."); useCharosOnWell = new ObjectStep(this, ObjectID.WELL, new WorldPoint(3085, 3503, 0), "Use the Ring of charos(a) on the well in Edgeville.", ringOfCharosA.highlighted()); @@ -571,7 +571,7 @@ public void setupSteps() talkToEllmariaAfterGrown = new NpcStep(this, NpcID.QUEEN_ELLAMARIA, new WorldPoint(3230, 3478, 0), "Talk to Ellamaria once everything's finished growing."); - talkToRoald = new NpcStep(this, NpcID.KING_ROALD_CUTSCENE, new WorldPoint(3221, 3473, 0), + talkToRoald = new NpcStep(this, NpcID.KING_ROALD, new WorldPoint(3221, 3473, 0), "Talk to King Roald in Varrock Castle, watch the cutscene, then finish the dialog with Ellamaria to finish" + " the quest!", ringOfCharosA.equipped()); talkToRoald.addDialogSteps("Ask King Roald to follow me.", "[Charm] Of course, your majesty - please forgive " + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gertrudescat/GertrudesCat.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gertrudescat/GertrudesCat.java index 25d3ace8fa..83a56940a5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gertrudescat/GertrudesCat.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/gertrudescat/GertrudesCat.java @@ -29,7 +29,9 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -37,20 +39,21 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class GertrudesCat extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ghostsahoy/DyeShipSteps.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ghostsahoy/DyeShipSteps.java index 8208a58865..2bad7e60a2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ghostsahoy/DyeShipSteps.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ghostsahoy/DyeShipSteps.java @@ -38,15 +38,12 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.microbot.util.text.Rs2TextSanitizer; -import lombok.extern.slf4j.Slf4j; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; -@Slf4j public class DyeShipSteps extends DetailedOwnerStep { boolean coloursKnown = false; @@ -99,54 +96,36 @@ private void updateCurrentColours() { return; } - String normalized = Rs2TextSanitizer.normalizeGameText(text); - String[] splitOnNewLines = normalized.split("
"); - boolean handledLines = false; + String[] splitOnNewLines = text.split("
"); if (splitOnNewLines.length > 1) { for (String splitOnNewLine : splitOnNewLines) { - if (updateCurrentColoursFromString(Rs2TextSanitizer.stripTagsToSpace(splitOnNewLine))) - { - handledLines = true; - } + updateCurrentColoursFromString(splitOnNewLine); } } - if (handledLines) - { - return; - } - String plain = Rs2TextSanitizer.stripTagsToSpace(normalized); - String[] splitText = plain.split("dye the "); + String[] splitText = text.split("dye the "); if (splitText.length < 2) { - if (log.isDebugEnabled()) - { - int h = plain.hashCode(); - int len = plain.length(); - String prefix = plain.length() > 60 ? plain.substring(0, 60) + "…" : plain; - log.debug("DyeShipSteps: expected 'dye the ' in objectbox text; len={} hash={} prefix='{}'", len, Integer.toHexString(h), prefix); - } return; } updateCurrentColoursFromString(splitText[1]); } - private boolean updateCurrentColoursFromString(String text) + private void updateCurrentColoursFromString(String text) { String[] shapeAndColour = text.split(" (emblem|of the flag) "); if (shapeAndColour.length < 2) { - return false; + return; } String shape = shapeAndColour[0]; String colour = shapeAndColour[1]; shape = shape.replace("The ", ""); colour = colour.replace("is ", ""); currentColours.put(shape, FlagColour.findByKey(colour)); - return true; } public void updateSteps() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/goblindiplomacy/GoblinDiplomacy.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/goblindiplomacy/GoblinDiplomacy.java index 899c5a3926..1327f9eb07 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/goblindiplomacy/GoblinDiplomacy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/goblindiplomacy/GoblinDiplomacy.java @@ -26,17 +26,24 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -44,62 +51,47 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - public class GoblinDiplomacy extends BasicQuestHelper { - //Required items - ItemRequirement goblinMailThree, orangeDye, blueDye, goblinMail, goblinMailTwo, blueArmour, orangeArmour, mailReq; - - Requirement isUpstairs, hasUpstairsArmour, hasWestArmour, hasNorthArmour; - - QuestStep talkToGeneral1, talkToGeneral2, talkToGeneral3, goUpLadder, searchUpLadder, goDownLadder, searchWestHut, searchBehindGenerals, - dyeOrange, dyeBlue, getCrate2, getCrate3; - - //Zones + // Required items + ItemRequirement goblinMailThree; + ItemRequirement orangeDye; + ItemRequirement blueDye; + + // Mid-quest item requirements + ItemRequirement goblinMail; + ItemRequirement goblinMailTwo; + ItemRequirement blueArmour; + ItemRequirement orangeArmour; + ItemRequirement mailReq; + + // Zones Zone upstairs; + // Miscellaneous requirements + ZoneRequirement isUpstairs; + VarbitRequirement hasUpstairsArmour; + VarbitRequirement hasWestArmour; + VarbitRequirement hasNorthArmour; + + // Steps + NpcStep talkToGeneral1; + NpcStep talkToGeneral2; + NpcStep talkToGeneral3; + ObjectStep goUpLadder; + ObjectStep searchUpLadder; + ObjectStep goDownLadder; + ObjectStep searchWestHut; + ObjectStep searchBehindGenerals; + DetailedQuestStep dyeOrange; + DetailedQuestStep dyeBlue; + DetailedQuestStep getCrate2; + DetailedQuestStep getCrate3; + @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - ConditionalStep lootArmour = new ConditionalStep(this, goUpLadder); - lootArmour.addStep(new Conditions(isUpstairs, hasUpstairsArmour), goDownLadder); - lootArmour.addStep(new Conditions(hasUpstairsArmour, hasWestArmour), searchBehindGenerals); - lootArmour.addStep(hasUpstairsArmour, searchWestHut); - lootArmour.addStep(isUpstairs, searchUpLadder); - - ConditionalStep prepareForQuest = new ConditionalStep(this, lootArmour); - prepareForQuest.addStep(new Conditions(goblinMail, blueArmour), dyeOrange); - prepareForQuest.addStep(new Conditions(LogicType.OR, goblinMailThree, new Conditions(hasUpstairsArmour, hasWestArmour, - hasNorthArmour)), dyeBlue); - - ConditionalStep step1 = new ConditionalStep(this, prepareForQuest); - step1.addStep(new Conditions(goblinMail, blueArmour, orangeArmour), talkToGeneral1); - - steps.put(0, step1); - steps.put(3, step1); - - ConditionalStep prepareBlueArmour = new ConditionalStep(this, lootArmour); - prepareBlueArmour.addStep(new Conditions(LogicType.OR, goblinMailTwo, new Conditions(hasUpstairsArmour, hasWestArmour, - hasNorthArmour)), dyeBlue); - - ConditionalStep step2 = new ConditionalStep(this, prepareBlueArmour); - step2.addStep(blueArmour, talkToGeneral2); - - steps.put(4, step2); - - ConditionalStep step3 = new ConditionalStep(this, lootArmour); - step3.addStep(new Conditions(LogicType.OR, goblinMail, new Conditions(hasUpstairsArmour, hasWestArmour, - hasNorthArmour)), talkToGeneral3); - - steps.put(5, step3); - - return steps; + upstairs = new Zone(new WorldPoint(2952, 3495, 2), new WorldPoint(2959, 3498, 2)); } @Override @@ -123,26 +115,16 @@ protected void setupRequirements() blueArmour = new ItemRequirement("Blue goblin mail", ItemID.GOBLIN_ARMOUR_DARKBLUE); orangeArmour = new ItemRequirement("Orange goblin mail", ItemID.GOBLIN_ARMOUR_ORANGE); - } - public void setupConditions() - { isUpstairs = new ZoneRequirement(upstairs); hasUpstairsArmour = new VarbitRequirement(VarbitID.GOBDIP_CRATE3_SEARCHED, 1); hasWestArmour = new VarbitRequirement(VarbitID.GOBDIP_CRATE2_SEARCHED, 1); hasNorthArmour = new VarbitRequirement(VarbitID.GOBDIP_CRATE1_SEARCHED, 1); } - @Override - protected void setupZones() - { - upstairs = new Zone(new WorldPoint(2952, 3495, 2), new WorldPoint(2959, 3498, 2)); - } - public void setupSteps() { - goUpLadder = new ObjectStep(this, ObjectID.GOBLIN_LADDER_BOTTOM, new WorldPoint(2954, 3497, 0), "You need three goblin mails, which you can find around the Goblin " + - "Village. The first is up the ladder in a crate in the south of the village."); + goUpLadder = new ObjectStep(this, ObjectID.GOBLIN_LADDER_BOTTOM, new WorldPoint(2954, 3497, 0), "You need three goblin mails, which you can find around the Goblin Village. The first is up the ladder in a crate in the south of the village."); searchUpLadder = new ObjectStep(this, ObjectID.GOBLIN_OUTPOST_LARGE_CRATE_ARMOUR3, new WorldPoint(2955, 3498, 2), "Search the crate up the ladder."); goUpLadder.addSubSteps(searchUpLadder); goDownLadder = new ObjectStep(this, ObjectID.GOBLIN_LADDER_TOP, new WorldPoint(2954, 3497, 2), "Go back down the ladder."); @@ -158,10 +140,11 @@ public void setupSteps() dyeOrange = new DetailedQuestStep(this, "Use the orange dye on one of the goblin mail.", orangeDye, goblinMail); talkToGeneral1 = new NpcStep(this, NpcID.GENERAL_BENTNOZE_RED, new WorldPoint(2958, 3512, 0), "Talk to one of the Goblin Generals in Goblin Village.", orangeArmour); - talkToGeneral1.addDialogStep("So how is life for the goblins?"); - talkToGeneral1.addDialogStep("Yes, Wartface looks fat"); talkToGeneral1.addDialogStep("Do you want me to pick an armour colour for you?"); talkToGeneral1.addDialogStep("What about a different colour?"); + talkToGeneral1.addDialogStep("Yes."); + talkToGeneral1.addDialogStep("So how is life for the goblins?"); + talkToGeneral1.addDialogStep("Yes, Wartface looks fat"); talkToGeneral1.addDialogStep("I have some orange armour here."); talkToGeneral2 = new NpcStep(this, NpcID.GENERAL_BENTNOZE_RED, new WorldPoint(2958, 3512, 0), "Talk to one of the Goblin Generals in Goblin Village again.", blueArmour); @@ -174,14 +157,54 @@ public void setupSteps() talkToGeneral3.addDialogStep("I have some brown armour here."); } + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + var lootArmour = new ConditionalStep(this, goUpLadder); + lootArmour.addStep(and(isUpstairs, hasUpstairsArmour), goDownLadder); + lootArmour.addStep(and(hasUpstairsArmour, hasWestArmour), searchBehindGenerals); + lootArmour.addStep(hasUpstairsArmour, searchWestHut); + lootArmour.addStep(isUpstairs, searchUpLadder); + + var prepareForQuest = new ConditionalStep(this, lootArmour); + prepareForQuest.addStep(and(goblinMail, blueArmour), dyeOrange); + prepareForQuest.addStep(or(goblinMailThree, and(hasUpstairsArmour, hasWestArmour, hasNorthArmour)), dyeBlue); + + var step1 = new ConditionalStep(this, prepareForQuest); + step1.addStep(and(goblinMail, blueArmour, orangeArmour), talkToGeneral1); + + steps.put(0, step1); + steps.put(3, step1); + + var prepareBlueArmour = new ConditionalStep(this, lootArmour); + prepareBlueArmour.addStep(or(goblinMailTwo, and(hasUpstairsArmour, hasWestArmour, hasNorthArmour)), dyeBlue); + + var step2 = new ConditionalStep(this, prepareBlueArmour); + step2.addStep(blueArmour, talkToGeneral2); + + steps.put(4, step2); + + var step3 = new ConditionalStep(this, lootArmour); + step3.addStep(or(goblinMail, and(hasUpstairsArmour, hasWestArmour, hasNorthArmour)), talkToGeneral3); + + steps.put(5, step3); + + return steps; + } + @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(blueDye); - reqs.add(orangeDye); - reqs.add(mailReq); - return reqs; + return List.of( + blueDye, + orangeDye, + mailReq + ); } @Override @@ -193,24 +216,42 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.CRAFTING, 200)); + return List.of( + new ExperienceReward(Skill.CRAFTING, 200) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("A Gold Bar", ItemID.GOLD_BAR, 1)); + return List.of( + new ItemReward("A Gold Bar", ItemID.GOLD_BAR, 1) + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - PanelDetails getArmours = new PanelDetails("Prepare goblin mail", - Arrays.asList(goUpLadder, getCrate2, getCrate3, dyeBlue, dyeOrange), blueDye, orangeDye, goblinMailThree); - allSteps.add(getArmours); - - allSteps.add(new PanelDetails("Present the armours", Arrays.asList(talkToGeneral1, talkToGeneral2, talkToGeneral3))); - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Prepare goblin mail", List.of( + goUpLadder, + getCrate2, + getCrate3, + dyeBlue, + dyeOrange + ), List.of( + blueDye, + orangeDye, + goblinMailThree + ))); + + sections.add(new PanelDetails("Present the armours", List.of( + talkToGeneral1, + talkToGeneral2, + talkToGeneral3 + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/grimtales/GrimTales.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/grimtales/GrimTales.java index 4a337966ef..ae7d3678c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/grimtales/GrimTales.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/grimtales/GrimTales.java @@ -167,7 +167,8 @@ protected void setupRequirements() tarrominUnfHighlight = new ItemRequirement("Tarromin potion (unf)", ItemID.TARROMINVIAL); tarrominUnfHighlight.setHighlightInInventory(true); - dibber = new ItemRequirement("Seed dibber", ItemID.DIBBER).isNotConsumed(); + var knowsBarbarianPlanting = new VarbitRequirement(VarbitID.BRUT_FARMING_PLANTING, 3); + dibber = new ItemRequirement("Seed dibber", ItemID.DIBBER).hideConditioned(knowsBarbarianPlanting).isNotConsumed(); can = new ItemRequirement("Watering can with at least 1 use", ItemCollections.WATERING_CANS).isNotConsumed(); can.setTooltip("Gricollers' can is also valid. "); axe = new ItemRequirement("Any axe", ItemCollections.AXES).isNotConsumed(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hauntedmine/HauntedMine.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hauntedmine/HauntedMine.java index d945cd5e5c..edae421f0e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hauntedmine/HauntedMine.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hauntedmine/HauntedMine.java @@ -49,7 +49,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; @@ -293,7 +297,7 @@ public void setupSteps() pullLeverG = new ObjectStep(this, ObjectID.HAUNTEDMINE_POINT_LEVER7, new WorldPoint(2769, 4533, 0), "Pull the marked lever."); pullLeverH = new ObjectStep(this, ObjectID.HAUNTEDMINE_POINT_LEVER8, new WorldPoint(2770, 4533, 0), "Pull the marked lever."); - solvePuzzle = new DetailedQuestStep(this, "Pull levers until the tracks are lined up to take the cart to the north east corner."); + solvePuzzle = new DetailedQuestStep(this, "Pull levers until the tracks are lined up to take the cart to the north west corner (the panel's map UI shows north as pointing to the right)."); solvePuzzle.addSubSteps(pullLeverA, pullLeverB, pullLeverC, pullLeverD, pullLeverE, pullLeverF, pullLeverG, pullLeverH); useKeyOnValve = new ObjectStep(this, ObjectID.HAUNTEDMINE_LIFT_VALVE, new WorldPoint(2808, 4496, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hazeelcult/HazeelCult.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hazeelcult/HazeelCult.java index 73dd07c317..d400971199 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hazeelcult/HazeelCult.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/hazeelcult/HazeelCult.java @@ -31,6 +31,8 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -38,7 +40,17 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.MultiNpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -46,11 +58,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class HazeelCult extends BasicQuestHelper { // Recommended items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/heroesquest/HeroesQuest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/heroesquest/HeroesQuest.java index a8a70fd117..78e7348ff1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/heroesquest/HeroesQuest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/heroesquest/HeroesQuest.java @@ -198,8 +198,8 @@ protected void setupRequirements() fishingRod.addAlternates(ItemID.OILY_FISHING_ROD); fishingBait = new ItemRequirement("Fishing bait", ItemID.FISHING_BAIT); jailKey = new ItemRequirement("Jail key", ItemID.JAIL_KEY).isNotConsumed(); - dustyKey = new KeyringRequirement("Dusty Key", configManager, KeyringCollection.DUSTY_KEY).isNotConsumed(); - dustyKeyHint = new KeyringRequirement("Dusty key (obtainable in quest)", configManager, KeyringCollection.DUSTY_KEY).isNotConsumed(); + dustyKey = new KeyringRequirement("Dusty Key", KeyringCollection.DUSTY_KEY).isNotConsumed(); + dustyKeyHint = new KeyringRequirement("Dusty key (obtainable in quest)", KeyringCollection.DUSTY_KEY).isNotConsumed(); harralanderUnf = new ItemRequirement("Harralander potion (unf)", ItemID.HARRALANDERVIAL); pickaxe = new ItemRequirement("Any pickaxe", ItemID.BRONZE_PICKAXE).isNotConsumed(); pickaxe.addAlternates(ItemCollections.PICKAXES); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/holygrail/HolyGrail.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/holygrail/HolyGrail.java index e31e9b165c..b7e6b1d2e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/holygrail/HolyGrail.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/holygrail/HolyGrail.java @@ -38,12 +38,24 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -51,13 +63,6 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class HolyGrail extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/impcatcher/ImpCatcher.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/impcatcher/ImpCatcher.java index e7673923e4..4c90a01025 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/impcatcher/ImpCatcher.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/impcatcher/ImpCatcher.java @@ -33,18 +33,21 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class ImpCatcher extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/junglepotion/JunglePotion.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/junglepotion/JunglePotion.java index edbb3e5c4c..3cfa329b5b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/junglepotion/JunglePotion.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/junglepotion/JunglePotion.java @@ -36,7 +36,15 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -44,33 +52,61 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class JunglePotion extends BasicQuestHelper { - //Items Required - ItemRequirement grimySnakeWeed, snakeWeed, grimyArdrigal, ardrigal, grimySitoFoil, sitoFoil, grimyVolenciaMoss, volenciaMoss, - roguesPurse, grimyRoguesPurse; - - QuestStep startQuest, finishQuest; - - ObjectStep getSnakeWeed, getArdrigal, getSitoFoil, getVolenciaMoss, enterCave, getRoguePurseHerb; - - ConditionalStep cleanAndReturnSnakeWeed, cleanAndReturnArdrigal, cleanAndReturnSitoFoil, cleanAndReturnVolenciaMoss, - getRoguesPurse, cleanAndReturnRoguesPurse; - + // Recommended items + ItemRequirement food; + ItemRequirement antipoison; + ItemRequirement karaTele; + + // Mid-quest item requirements + ItemRequirement grimySnakeWeed; + ItemRequirement snakeWeed; + ItemRequirement grimyArdrigal; + ItemRequirement ardrigal; + ItemRequirement grimySitoFoil; + ItemRequirement sitoFoil; + ItemRequirement grimyVolenciaMoss; + ItemRequirement volenciaMoss; + ItemRequirement roguesPurse; + ItemRequirement grimyRoguesPurse; + + // Zones + Zone undergroundZone; + + // Miscellaneous requirements ZoneRequirement isUnderground; + // Steps + NpcStep startQuest; + ObjectStep getSnakeWeed; + ConditionalStep cleanAndReturnSnakeWeed; + ObjectStep getArdrigal; + ConditionalStep cleanAndReturnArdrigal; + ObjectStep getSitoFoil; + ConditionalStep cleanAndReturnSitoFoil; + ObjectStep getVolenciaMoss; + ConditionalStep cleanAndReturnVolenciaMoss; + ObjectStep enterCave; + ObjectStep getRoguePurseHerb; + ConditionalStep getRoguesPurse; + ConditionalStep cleanAndReturnRoguesPurse; + NpcStep finishQuest; + @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - return getSteps(); + undergroundZone = new Zone(new WorldPoint(2824, 9462, 0), new WorldPoint(2883, 9533, 0)); } @Override protected void setupRequirements() { + food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); + antipoison = new ItemRequirement("Antipoison", ItemCollections.ANTIPOISONS); + karaTele = new ItemRequirement("Teleport to Karamja (Glory/house teleport)", ItemID.NZONE_TELETAB_BRIMHAVEN); + karaTele.addAlternates(ItemCollections.AMULET_OF_GLORIES); + grimySnakeWeed = new ItemRequirement("Grimy Snake Weed", ItemID.UNIDENTIFIED_SNAKE_WEED); grimySnakeWeed.setHighlightInInventory(true); snakeWeed = new ItemRequirement("Snake Weed", ItemID.SNAKE_WEED); @@ -90,116 +126,53 @@ protected void setupRequirements() grimyRoguesPurse = new ItemRequirement("Grimy Rogues Purse", ItemID.UNIDENTIFIED_ROGUES_PURSE); grimyRoguesPurse.setHighlightInInventory(true); roguesPurse = new ItemRequirement("Rogues Purse", ItemID.ROGUES_PURSE); - } - @Override - protected void setupZones() - { - //2824,9462,0 - //2883, 9533, 0 - Zone undergroundZone = new Zone(new WorldPoint(2824, 9462, 0), new WorldPoint(2883, 9533, 0)); isUnderground = new ZoneRequirement(undergroundZone); } - private Map getSteps() - { - Map steps = new HashMap<>(); - - steps.put(0, startQuestStep()); - steps.put(1, getSnakeWeed()); - steps.put(2, returnSnakeWeed()); - steps.put(3, getArdrigal()); - steps.put(4, returnArdigal()); - steps.put(5, getSitoFoil()); - steps.put(6, returnSitoFoil()); - steps.put(7, getVolenciaMoss()); - steps.put(8, returnVolenciaMoss()); - steps.put(9, getRoguesPurse()); - steps.put(10, returnRoguesPurse()); - steps.put(11, finishQuestStep()); - return steps; - } - - private QuestStep startQuestStep() - { - startQuest = talkToTrufitus("Talk to Trufitus in Tai Bwo Wannai on Karamja."); - startQuest.addDialogSteps("It's a nice village, where is everyone?"); - startQuest.addDialogSteps("Me? How can I help?"); - startQuest.addDialogSteps("It sounds like just the challenge for me."); - return startQuest; - } - - private QuestStep returnArdigal() - { - return cleanAndReturnArdrigal = getReturnHerbStep("Ardrigal", grimyArdrigal, ardrigal); - } - - private QuestStep returnSnakeWeed() - { - return cleanAndReturnSnakeWeed = getReturnHerbStep("Snake Weed", grimySnakeWeed, snakeWeed); - } - - private QuestStep returnSitoFoil() - { - return cleanAndReturnSitoFoil = getReturnHerbStep("Sito Foil", grimySitoFoil, sitoFoil); - } - - private QuestStep returnVolenciaMoss() - { - return cleanAndReturnVolenciaMoss = getReturnHerbStep("Volencia Moss", grimyVolenciaMoss, volenciaMoss); - } - - private QuestStep returnRoguesPurse() - { - cleanAndReturnRoguesPurse = getReturnHerbStep("Rogues Purse", grimyRoguesPurse, roguesPurse); - cleanAndReturnRoguesPurse.addStep(isUnderground, new ObjectStep(this, - ObjectID.JP_CAVEROCKSOUT, new WorldPoint(2830, 9522, 0), "Climb out of the cave.")); - return cleanAndReturnRoguesPurse; - } - private ConditionalStep getReturnHerbStep(String herbName, ItemRequirement grimyHerb, ItemRequirement cleanHerb) { NpcStep returnHerb = talkToTrufitus("", cleanHerb); returnHerb.addDialogSteps("Of course!"); - DetailedQuestStep cleanGrimyHerb = new DetailedQuestStep(this, "", grimyHerb); + var cleanGrimyHerb = new DetailedQuestStep(this, "", grimyHerb); - ConditionalStep cleanAndReturnHerb = new ConditionalStep(this, cleanGrimyHerb, "Clean and return the " + herbName + " to Trufitus."); + var cleanAndReturnHerb = new ConditionalStep(this, cleanGrimyHerb, "Clean and return the " + herbName + " to Trufitus."); cleanAndReturnHerb.addStep(cleanHerb, returnHerb); return cleanAndReturnHerb; } - private QuestStep getSnakeWeed() + private NpcStep talkToTrufitus(String text, Requirement... requirements) { - getSnakeWeed = new ObjectStep(this, ObjectID.SNAKE_VINE_FULL, new WorldPoint(2763, 3044, 0), - "Search a marshy jungle vine south of Tai Bwo Wannai for some snake weed."); - getSnakeWeed.addText("If you want to do Zogre Flesh Eaters or Legends' Quest grab one for each as you will need them later."); - return getSnakeWeed; + return new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), text, requirements); } - private QuestStep getArdrigal() + private void setupSteps() { - getArdrigal = new ObjectStep(this, ObjectID.ARDRIGAL_PALM_FULL, new WorldPoint(2871, 3116, 0), - "Search the palm trees north east of Tai Bwo Wannai for an Ardrigal herb."); + startQuest = talkToTrufitus("Talk to Trufitus in Tai Bwo Wannai on Karamja."); + startQuest.addDialogStep("It's a nice village, where is everyone?"); + startQuest.addDialogStep("Me? How can I help?"); + startQuest.addDialogStep("It sounds like just the challenge for me."); + startQuest.addDialogStep("Yes."); + + getSnakeWeed = new ObjectStep(this, ObjectID.SNAKE_VINE_FULL, new WorldPoint(2763, 3044, 0), "Search a marshy jungle vine south of Tai Bwo Wannai for some snake weed."); + getSnakeWeed.addText("If you want to do Zogre Flesh Eaters or Legends' Quest grab one for each as you will need them later."); + + cleanAndReturnSnakeWeed = getReturnHerbStep("Snake Weed", grimySnakeWeed, snakeWeed); + + getArdrigal = new ObjectStep(this, ObjectID.ARDRIGAL_PALM_FULL, new WorldPoint(2871, 3116, 0), "Search the palm trees north east of Tai Bwo Wannai for an Ardrigal herb."); getArdrigal.addText("If you want to do Legends' Quest grab one extra as you will need it later."); - return getArdrigal; - } - private QuestStep getSitoFoil() - { - return getSitoFoil = new ObjectStep(this, ObjectID.SITO_SOIL_FULL, new WorldPoint(2791, 3047, 0), - "Search the scorched earth in the south of Tai Bwo Wannai for a Sito Foil herb."); - } + cleanAndReturnArdrigal = getReturnHerbStep("Ardrigal", grimyArdrigal, ardrigal); - private QuestStep getVolenciaMoss() - { - getVolenciaMoss = new ObjectStep(this, ObjectID.VOLENCIA_MOSS_ROCK_FULL, new WorldPoint(2851, 3036, 0), - "Search the rock for a Volencia Moss herb at the mine south east of Tai Bwo Wannai."); + getSitoFoil = new ObjectStep(this, ObjectID.SITO_SOIL_FULL, new WorldPoint(2791, 3047, 0), "Search the scorched earth in the south of Tai Bwo Wannai for a Sito Foil herb."); + + cleanAndReturnSitoFoil = getReturnHerbStep("Sito Foil", grimySitoFoil, sitoFoil); + + getVolenciaMoss = new ObjectStep(this, ObjectID.VOLENCIA_MOSS_ROCK_FULL, new WorldPoint(2851, 3036, 0), "Search the rock for a Volencia Moss herb at the mine south east of Tai Bwo Wannai."); getVolenciaMoss.addText("If you plan on doing Fairy Tale I then take an extra."); - return getVolenciaMoss; - } - private QuestStep getRoguesPurse() - { + cleanAndReturnVolenciaMoss = getReturnHerbStep("Volencia Moss", grimyVolenciaMoss, volenciaMoss); + enterCave = new ObjectStep(this, ObjectID.POTHOLE_CAVE_ENTRANCE, new WorldPoint(2825, 3119, 0), "Enter the cave to the north by clicking on the rocks."); enterCave.addDialogStep("Yes, I'll enter the cave."); @@ -212,51 +185,62 @@ private QuestStep getRoguesPurse() getRoguesPurse.addStep(isUnderground, getRoguePurseHerb); getRoguesPurse.addSubSteps(enterCave); - return getRoguesPurse; - } - private QuestStep finishQuestStep() - { + cleanAndReturnRoguesPurse = getReturnHerbStep("Rogues Purse", grimyRoguesPurse, roguesPurse); + cleanAndReturnRoguesPurse.addStep(isUnderground, new ObjectStep(this, ObjectID.JP_CAVEROCKSOUT, new WorldPoint(2830, 9522, 0), "Climb out of the cave.")); + finishQuest = talkToTrufitus("Talk to Trufitus to finish the quest."); - return finishQuest; } - private NpcStep talkToTrufitus(String text, Requirement... requirements) + @Override + public Map loadSteps() { - return new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), text, requirements); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, startQuest); + steps.put(1, getSnakeWeed); + steps.put(2, cleanAndReturnSnakeWeed); + steps.put(3, getArdrigal); + steps.put(4, cleanAndReturnArdrigal); + steps.put(5, getSitoFoil); + steps.put(6, cleanAndReturnSitoFoil); + steps.put(7, getVolenciaMoss); + steps.put(8, cleanAndReturnVolenciaMoss); + steps.put(9, getRoguesPurse); + steps.put(10, cleanAndReturnRoguesPurse); + steps.put(11, finishQuest); + + return steps; } @Override - public List getCombatRequirements() + public List getGeneralRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add("Survive against level 53 Jogres and level 46 Harpie Bug Swarms."); - return reqs; + return List.of( + new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED), + new SkillRequirement(Skill.HERBLORE, 3, false) + ); } - //Recommended @Override public List getItemRecommended() { - ArrayList reqs = new ArrayList<>(); - ItemRequirement food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); - - reqs.add(food); - reqs.add(new ItemRequirement("Antipoison", ItemCollections.ANTIPOISONS)); - ItemRequirement karaTele = new ItemRequirement("Teleport to Karamja (Glory/house teleport)", - ItemID.NZONE_TELETAB_BRIMHAVEN); - karaTele.addAlternates(ItemCollections.AMULET_OF_GLORIES); - reqs.add(karaTele); - return reqs; + return List.of( + food, + antipoison, + karaTele + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED)); - req.add(new SkillRequirement(Skill.HERBLORE, 3, false)); - return req; + return List.of( + "Survive against level 53 Jogres and level 46 Harpie Bug Swarms." + ); } @Override @@ -268,38 +252,47 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.HERBLORE, 775)); + return List.of( + new ExperienceReward(Skill.HERBLORE, 775) + ); } @Override public List getPanels() { - List steps = new ArrayList<>(); - - PanelDetails startingPanel = new PanelDetails("Starting quest", - Collections.singletonList(startQuest)); - steps.add(startingPanel); - - PanelDetails snakeWeedPanel = new PanelDetails("Snake Weed", - Arrays.asList(getSnakeWeed, cleanAndReturnSnakeWeed)); - steps.add(snakeWeedPanel); - - PanelDetails ardrigalPanel = new PanelDetails("Ardrigal", - Arrays.asList(getArdrigal, cleanAndReturnArdrigal)); - steps.add(ardrigalPanel); - - PanelDetails sitoFoilpanel = new PanelDetails("Sito Foil", - Arrays.asList(getSitoFoil, cleanAndReturnSitoFoil)); - steps.add(sitoFoilpanel); - - PanelDetails volenciaMossPanel = new PanelDetails("Volencia Moss", - Arrays.asList(getVolenciaMoss, cleanAndReturnVolenciaMoss)); - steps.add(volenciaMossPanel); - - PanelDetails roguesPursePanel = new PanelDetails("Rogues Purse", - Arrays.asList(enterCave, getRoguePurseHerb, cleanAndReturnRoguesPurse)); - steps.add(roguesPursePanel); - - return steps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + startQuest + ))); + + sections.add(new PanelDetails("Snake Weed", List.of( + getSnakeWeed, + cleanAndReturnSnakeWeed + ))); + + sections.add(new PanelDetails("Ardrigal", List.of( + getArdrigal, + cleanAndReturnArdrigal + ))); + + sections.add(new PanelDetails("Sito Foil", List.of( + getSitoFoil, + cleanAndReturnSitoFoil + ))); + + sections.add(new PanelDetails("Volencia Moss", List.of( + getVolenciaMoss, + cleanAndReturnVolenciaMoss + ))); + + sections.add(new PanelDetails("Rogues Purse", List.of( + enterCave, + getRoguePurseHerb, + cleanAndReturnRoguesPurse, + finishQuest + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/landofthegoblins/LandOfTheGoblins.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/landofthegoblins/LandOfTheGoblins.java index 593527e112..7dec619302 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/landofthegoblins/LandOfTheGoblins.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/landofthegoblins/LandOfTheGoblins.java @@ -65,7 +65,7 @@ public class LandOfTheGoblins extends BasicQuestHelper { Requirement noPet; ItemRequirement lightSource, toadflaxPotionUnf, goblinMail, yellowDye, blueDye, orangeDye, purpleDye, blackDye, fishingRod, rawSlimyEel, coins, combatGear; - ItemRequirement tinderbox, dorgeshKaanSphereRec, dramenStaff, skillsNecklace, combatBracelet, lumbridgeTeleport, draynorTeleport, explorersRing, salveAmulet; + ItemRequirement tinderbox, dorgeshKaanSphereRec, dramenStaff, skillsNecklace, combatBracelet, lumbridgeTeleport, draynorTeleport, explorersRing; CombatLevelRequirement recommendedCombatLevel; ItemRequirement pharmakosBerryHighlight, toadflaxUnfHighlight, goblinPotion, goblinPotionHighlight, noEquippedItems, dorgeshKaanSphere, blackGoblinMail, huzamogaarbKey, hemensterWhitefish, pestleAndMortar, vial, @@ -379,7 +379,6 @@ protected void setupRequirements() draynorTeleport = new ItemRequirement("Draynor Village teleport", ItemCollections.AMULET_OF_GLORIES, 2); draynorTeleport.setChargedItem(true); explorersRing = new ItemRequirement("Explorer's ring 3 or 4", Arrays.asList(ItemID.LUMBRIDGE_RING_HARD, ItemID.LUMBRIDGE_RING_ELITE)); - salveAmulet = new ItemRequirement("Salve amulet or Salve amulet (e)", ItemCollections.SALVE_AMULET); pharmakosBerryHighlight = new ItemRequirement("Pharmakos berries", ItemID.LOTG_PHARMAKOS_BERRY); pharmakosBerryHighlight.setHighlightInInventory(true); @@ -679,7 +678,7 @@ public ArrayList getItemRequirements() @Override public ArrayList getItemRecommended() { - return new ArrayList<>(Arrays.asList(tinderbox, dorgeshKaanSphereRec, dramenStaff, skillsNecklace, combatBracelet, lumbridgeTeleport, draynorTeleport, explorersRing, salveAmulet)); + return new ArrayList<>(Arrays.asList(tinderbox, dorgeshKaanSphereRec, dramenStaff, skillsNecklace, combatBracelet, lumbridgeTeleport, draynorTeleport, explorersRing)); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/lostcity/LostCity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/lostcity/LostCity.java index 3e83f50119..020c14df1d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/lostcity/LostCity.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/lostcity/LostCity.java @@ -33,104 +33,102 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class LostCity extends BasicQuestHelper { - //Items Required - ItemRequirement knife, axe, combatGear, teleport, bronzeAxe, dramenBranch, dramenStaff, dramenStaffEquipped; + // Required items + ItemRequirement axe; + ItemRequirement knife; - Requirement onEntrana, inDungeon, shamusNearby, bronzeAxeNearby, dramenSpiritNearby; + // Recommended items + ItemRequirement combatGear; + ItemRequirement teleport; - DetailedQuestStep talkToWarrior, chopTree, talkToShamus, goToEntrana, goDownHole, getAxe, pickupAxe, attemptToCutDramen, killDramenSpirit, cutDramenBranch, - teleportAway, craftBranch, enterZanaris, getAnotherBranch; + // Mid-quest item requirements + ItemRequirement bronzeOrIronAxe; + ItemRequirement dramenBranch; + ItemRequirement dramenStaff; + ItemRequirement dramenStaffEquipped; - //Zones - Zone entrana, entranaDungeon; + // Zones + Zone entrana; + Zone entranaDungeon; - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); + // Miscellaneous requirements + ZoneRequirement onEntrana; + ZoneRequirement inDungeon; + NpcCondition shamusNearby; + Conditions axeNearby; + NpcCondition dramenSpiritNearby; - steps.put(0, talkToWarrior); + // Steps + NpcStep talkToWarrior; - ConditionalStep findShamus = new ConditionalStep(this, chopTree); - findShamus.addStep(shamusNearby, talkToShamus); + ObjectStep chopTree; + NpcStep talkToShamus; - steps.put(1, findShamus); + NpcStep goToEntrana; + ObjectStep goDownHole; + DetailedQuestStep getAxe; + DetailedQuestStep pickupAxe; + ObjectStep attemptToCutDramen; + NpcStep killDramenSpirit; - ConditionalStep killingTheSpirit = new ConditionalStep(this, goToEntrana); - killingTheSpirit.addStep(new Conditions(inDungeon, dramenSpiritNearby), killDramenSpirit); - killingTheSpirit.addStep(new Conditions(inDungeon, bronzeAxe), attemptToCutDramen); - killingTheSpirit.addStep(new Conditions(inDungeon, bronzeAxeNearby), pickupAxe); - killingTheSpirit.addStep(inDungeon, getAxe); - killingTheSpirit.addStep(onEntrana, goDownHole); + ObjectStep cutDramenBranch; + DetailedQuestStep teleportAway; + DetailedQuestStep craftBranch; + ObjectStep enterZanaris; + DetailedQuestStep getAnotherBranch; - steps.put(2, killingTheSpirit); - - ConditionalStep finishQuest = new ConditionalStep(this, getAnotherBranch); - finishQuest.addStep(new Conditions(inDungeon, dramenStaff), teleportAway); - finishQuest.addStep(dramenStaff, enterZanaris); - finishQuest.addStep(new Conditions(inDungeon, dramenBranch), teleportAway); - finishQuest.addStep(dramenBranch, craftBranch); - finishQuest.addStep(new Conditions(inDungeon, bronzeAxe), cutDramenBranch); - finishQuest.addStep(new Conditions(inDungeon, bronzeAxeNearby), pickupAxe); - finishQuest.addStep(inDungeon, getAxe); - finishQuest.addStep(onEntrana, goDownHole); - - steps.put(3, finishQuest); - - steps.put(4, finishQuest); - - steps.put(5, finishQuest); - - return steps; + @Override + protected void setupZones() + { + entrana = new Zone(new WorldPoint(2798, 3327, 0), new WorldPoint(2878, 3394, 1)); + entranaDungeon = new Zone(new WorldPoint(2817, 9722, 0), new WorldPoint(2879, 9784, 0)); } @Override protected void setupRequirements() { - knife = new ItemRequirement("Knife", ItemID.KNIFE).isNotConsumed(); - bronzeAxe = new ItemRequirement("Bronze axe", ItemID.BRONZE_AXE).isNotConsumed(); axe = new ItemRequirement("Any axe", ItemID.BRONZE_AXE).isNotConsumed(); axe.addAlternates(ItemCollections.AXES); + knife = new ItemRequirement("Knife", ItemID.KNIFE).isNotConsumed(); + combatGear = new ItemRequirement("Runes, or a way of dealing damage which you can smuggle onto Entrana. Runes for Crumble Undead (level 39 Magic) are best", -1, -1).isNotConsumed(); combatGear.setDisplayItemId(ItemID.SKULL); teleport = new ItemRequirement("Teleport, preferably to Lumbridge. Home teleport will work if off cooldown", ItemID.RING_OF_ELEMENTS_CHARGED); teleport.addAlternates(ItemID.POH_TABLET_LUMBRIDGETELEPORT); + + bronzeOrIronAxe = new ItemRequirement("Bronze or Iron axe", ItemID.BRONZE_AXE).isNotConsumed(); + bronzeOrIronAxe.addAlternates(ItemID.IRON_AXE); dramenBranch = new ItemRequirement("Dramen branch", ItemID.DRAMEN_BRANCH); dramenStaff = new ItemRequirement("Dramen staff", ItemID.DRAMEN_STAFF); - dramenStaffEquipped = new ItemRequirement("Dramen staff", ItemID.DRAMEN_STAFF, 1, true); - } + dramenStaffEquipped = dramenStaff.equipped(); - @Override - protected void setupZones() - { - entrana = new Zone(new WorldPoint(2798, 3327, 0), new WorldPoint(2878, 3394, 1)); - entranaDungeon = new Zone(new WorldPoint(2817, 9722, 0), new WorldPoint(2879, 9784, 0)); - } - - public void setupConditions() - { onEntrana = new ZoneRequirement(entrana); inDungeon = new ZoneRequirement(entranaDungeon); shamusNearby = new NpcCondition(NpcID.ZANARISLEPRECHAUN); - bronzeAxeNearby = new ItemOnTileRequirement(ItemID.BRONZE_AXE); + axeNearby = or(new ItemOnTileRequirement(ItemID.BRONZE_AXE), new ItemOnTileRequirement(ItemID.IRON_AXE)); dramenSpiritNearby = new NpcCondition(NpcID.TREE_SPIRIT); } @@ -141,59 +139,118 @@ public void setupSteps() talkToWarrior.addDialogStep("What makes you think it's out here?"); talkToWarrior.addDialogStep("If it's hidden how are you planning to find it?"); talkToWarrior.addDialogStep("Looks like you don't know either."); + talkToWarrior.addDialogStep("Yes."); + chopTree = new ObjectStep(this, ObjectID.LEPRECHAUNTREE, new WorldPoint(3139, 3213, 0), "Try cutting the tree just to the west.", axe); chopTree.addDialogStep("I've been in that shed, I didn't see a city."); + talkToShamus = new NpcStep(this, NpcID.ZANARISLEPRECHAUN, new WorldPoint(3138, 3212, 0), "Talk to Shamus."); talkToShamus.addDialogStep("I've been in that shed, I didn't see a city."); + goToEntrana = new NpcStep(this, NpcID.SHIPMONK1_C, new WorldPoint(3047, 3236, 0), "Bank all weapons and armour you have (including the axe), and go to Port Sarim to get a boat to Entrana.", combatGear); + goDownHole = new ObjectStep(this, ObjectID.ENTRANALADDERTOP, new WorldPoint(2820, 3374, 0), "Climb down the ladder on the north side of the island. Once you go down, you can only escape via teleport."); goDownHole.addDialogStep("Well that is a risk I will have to take."); - getAxe = new DetailedQuestStep(this, new WorldPoint(2843, 9760, 0), "Kill zombies until one drops a bronze axe."); - pickupAxe = new DetailedQuestStep(this, "Pick up the bronze axe", bronzeAxe); - attemptToCutDramen = new ObjectStep(this, ObjectID.DRAMENTREE, new WorldPoint(2861, 9735, 0), "Attempt to cut a branch from the Dramen tree. Be prepared for a Tree Spirit (level 101) to appear, which you can safespot behind nearby fungus.", bronzeAxe); + + getAxe = new DetailedQuestStep(this, new WorldPoint(2843, 9760, 0), "Kill zombies until one drops an axe."); + pickupAxe = new DetailedQuestStep(this, "Pick up the axe", bronzeOrIronAxe); + getAxe.addSubSteps(pickupAxe); + + attemptToCutDramen = new ObjectStep(this, ObjectID.DRAMENTREE, new WorldPoint(2861, 9735, 0), "Attempt to cut a branch from the Dramen tree. Be prepared for a Tree Spirit (level 101) to appear, which you can safespot behind nearby fungus.", bronzeOrIronAxe); + killDramenSpirit = new NpcStep(this, NpcID.TREE_SPIRIT, new WorldPoint(2859, 9734, 0), "Kill the Tree Spirit. They can be safespotted behind nearby fungi to the east."); + killDramenSpirit.addSafeSpots(new WorldPoint(2856, 9730, 0)); + cutDramenBranch = new ObjectStep(this, ObjectID.DRAMENTREE, new WorldPoint(2861, 9735, 0), "Cut at least one branch from the Dramen tree. It's recommended you cut at least 4 branches so you don't have to return in future quests."); + teleportAway = new DetailedQuestStep(this, "Teleport away with the branches, preferably to Lumbridge.", dramenBranch); teleportAway.addTeleport(teleport); - getAnotherBranch = new DetailedQuestStep(this, "If you've lost your Dramen branch/staff, you will need to return to Entrana and cut another. You will not need to defeat the Tree Spirit again."); - craftBranch = new DetailedQuestStep(this, "Use a knife on the dramen branch to craft a dramen staff.", knife, dramenBranch); - enterZanaris = new ObjectStep(this, ObjectID.ZANARISDOOR, new WorldPoint(3202, 3169, 0), "Enter the shed south of Lumbridge with your Dramen Staff equipped.", dramenStaffEquipped); + + getAnotherBranch = new DetailedQuestStep(this, "If you've lost your Dramen branch/staff, you will need to return to Entrana and cut another. You will not need to defeat the Tree Spirit again.", dramenBranch); + goToEntrana.addSubSteps(getAnotherBranch); + + craftBranch = new DetailedQuestStep(this, "Use a knife on the dramen branch to craft a dramen staff.", knife.highlighted(), dramenBranch.highlighted()); + + enterZanaris = new ObjectStep(this, ObjectID.ZANARISDOOR, new WorldPoint(3202, 3169, 0), "Enter the shed south of Lumbridge with your Dramen Staff equipped.", dramenStaffEquipped.highlighted()); } @Override - public List getCombatRequirements() + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToWarrior); + + var findShamus = new ConditionalStep(this, chopTree); + findShamus.addStep(shamusNearby, talkToShamus); + + steps.put(1, findShamus); + + var killingTheSpirit = new ConditionalStep(this, goToEntrana); + killingTheSpirit.addStep(and(inDungeon, dramenSpiritNearby), killDramenSpirit); + killingTheSpirit.addStep(and(inDungeon, bronzeOrIronAxe), attemptToCutDramen); + killingTheSpirit.addStep(and(inDungeon, axeNearby), pickupAxe); + killingTheSpirit.addStep(inDungeon, getAxe); + killingTheSpirit.addStep(onEntrana, goDownHole); + + steps.put(2, killingTheSpirit); + + var finishQuest = new ConditionalStep(this, getAnotherBranch); + finishQuest.addStep(and(inDungeon, dramenStaff), teleportAway); + finishQuest.addStep(dramenStaff.alsoCheckBank(), enterZanaris); + finishQuest.addStep(and(inDungeon, dramenBranch), teleportAway); + finishQuest.addStep(dramenBranch.alsoCheckBank(), craftBranch); + finishQuest.addStep(and(inDungeon, bronzeOrIronAxe), cutDramenBranch); + finishQuest.addStep(and(inDungeon, axeNearby), pickupAxe); + finishQuest.addStep(inDungeon, getAxe); + finishQuest.addStep(onEntrana, goDownHole); + + steps.put(3, finishQuest); + + steps.put(4, finishQuest); + + steps.put(5, finishQuest); + + return steps; + } + + @Override + public List getGeneralRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add("Multiple zombies (level 25) (can be safespotted)"); - reqs.add("Dramen Tree Spirit (level 101) (can be safespotted)"); - return reqs; + return List.of( + new SkillRequirement(Skill.CRAFTING, 31, true), + new SkillRequirement(Skill.WOODCUTTING, 36, true) + ); } @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(axe); - reqs.add(knife); - return reqs; + return List.of( + axe, + knife + ); } @Override public List getItemRecommended() { - ArrayList reqs = new ArrayList<>(); - reqs.add(combatGear); - reqs.add(teleport); - return reqs; + return List.of( + combatGear, + teleport + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() { - ArrayList req = new ArrayList<>(); - req.add(new SkillRequirement(Skill.CRAFTING, 31, true)); - req.add(new SkillRequirement(Skill.WOODCUTTING, 36, true)); - return req; + return List.of( + "Multiple zombies (level 25) (can be safespotted)", + "Dramen Tree Spirit (level 101) (can be safespotted)" + ); } @Override @@ -205,22 +262,51 @@ public QuestPointReward getQuestPointReward() @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("Access to Zanaris."), - new UnlockReward("Ability to craft Cosmic Runes"), - new UnlockReward("Ability to buy and wield Dragon Daggers & Longswords")); + return List.of( + new UnlockReward("Access to Zanaris."), + new UnlockReward("Ability to craft Cosmic Runes"), + new UnlockReward("Ability to buy and wield Dragon Daggers & Longswords") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Collections.singletonList(talkToWarrior), axe)); - allSteps.add(new PanelDetails("Finding Shamus", Arrays.asList(chopTree, talkToShamus))); - allSteps.add(new PanelDetails("Getting a Dramen branch", Arrays.asList(goToEntrana, goDownHole, getAxe, attemptToCutDramen, killDramenSpirit, - cutDramenBranch, teleportAway), List.of(), List.of(combatGear, teleport))); - allSteps.add(new PanelDetails("Entering Zanaris", Arrays.asList(craftBranch, enterZanaris), knife)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToWarrior + ), List.of( + axe + ))); + + sections.add(new PanelDetails("Finding Shamus", List.of( + chopTree, + talkToShamus + ))); + + sections.add(new PanelDetails("Getting a Dramen branch", List.of( + goToEntrana, + goDownHole, + getAxe, + attemptToCutDramen, + killDramenSpirit, + cutDramenBranch, + teleportAway + ), List.of( + // No requirements + ), List.of( + combatGear, + teleport + ))); + + sections.add(new PanelDetails("Entering Zanaris", List.of( + craftBranch, + enterZanaris + ), List.of( + knife + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/makinghistory/MakingHistory.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/makinghistory/MakingHistory.java index 2cb99b031c..435a4e3cee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/makinghistory/MakingHistory.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/makinghistory/MakingHistory.java @@ -150,7 +150,7 @@ protected void setupRequirements() portPhasmatysEntry.setTooltip(ectoTokens.getTooltip()); ringOfDueling = new ItemRequirement("Ring of Dueling", ItemCollections.RING_OF_DUELINGS); - enchantedKey = new KeyringRequirement("Enchanted key", configManager, KeyringCollection.ENCHANTED_KEY); + enchantedKey = new KeyringRequirement("Enchanted key", KeyringCollection.ENCHANTED_KEY); enchantedKey.setTooltip("You can get another from the silver merchant in East Ardougne's market"); enchantedKeyHighlighted = new ItemRequirement("Enchanted key", ItemID.MAKINGHISTORY_KEY); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/merlinscrystal/MerlinsCrystal.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/merlinscrystal/MerlinsCrystal.java index 44595dcca7..bed2c7f0d9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/merlinscrystal/MerlinsCrystal.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/merlinscrystal/MerlinsCrystal.java @@ -32,25 +32,28 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ObjectCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; public class MerlinsCrystal extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/misthalinmystery/MisthalinMystery.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/misthalinmystery/MisthalinMystery.java index c1481e5898..414c9e5160 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/misthalinmystery/MisthalinMystery.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/misthalinmystery/MisthalinMystery.java @@ -29,6 +29,7 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; @@ -37,17 +38,24 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.WidgetStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; public class MisthalinMystery extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessi/MonkeyMadnessI.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessi/MonkeyMadnessI.java index 0eab1b1219..506249ce60 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessi/MonkeyMadnessI.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessi/MonkeyMadnessI.java @@ -768,7 +768,7 @@ public void setupSteps() )); killZombie = new NpcStep(this, NpcID.MM_TRANSMOGRIFICATION_SMALL_ZOMBIE_MONKEY, new WorldPoint(2808, 9201, 0), "Kill a zombie monkey for their bones.", true, zombieBones); - killGorilla = new NpcStep(this, NpcID.MM_RELIGIOUS_GUARD, new WorldPoint(2801, 2785, 0), "Kill a gorilla in the temple for their bones.", + killGorilla = new NpcStep(this, NpcID.MM_RELIGIOUS_GUARD, new WorldPoint(2801, 2785, 0), "Kill a gorilla in the temple for their bones. If they can attack you they will heal on hit, so it's recommended to safespot or flinch one.", true, gorillaBones); ((NpcStep) killGorilla).addAlternateNpcs(NpcID.MM_RELIGIOUS_TRAPDOOR_GUARD); killGorilla.setLinePoints(Arrays.asList( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessii/AgilityDungeonSteps.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessii/AgilityDungeonSteps.java index 7de82ad5d8..0ba1c6e419 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessii/AgilityDungeonSteps.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monkeymadnessii/AgilityDungeonSteps.java @@ -42,9 +42,13 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; + import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; import java.util.*; @@ -417,7 +421,7 @@ public void checkSection5Successes() { return; } - WorldPoint currentPosition = Rs2Player.getWorldLocation(); + WorldPoint currentPosition = player.getWorldLocation(); for (int i = 0; i < fifthSectionMap.length; i++) { MM2Route[] pathsFromNode = fifthSectionMap[i].getPaths(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monksfriend/MonksFriend.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monksfriend/MonksFriend.java index adfb1bf830..2129cca22e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monksfriend/MonksFriend.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/monksfriend/MonksFriend.java @@ -24,28 +24,31 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.quests.monksfriend; +import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class MonksFriend extends BasicQuestHelper { // Required items @@ -89,12 +92,9 @@ protected void setupRequirements() log = new ItemRequirement("Logs", ItemID.LOGS); jugOfWater = new ItemRequirement("Jug of Water", ItemID.JUG_WATER); + jugOfWater.setTooltip("You can find one in the Yanille cooking shop"); blanket = new ItemRequirement("Child's blanket", ItemID.CHILDS_BLANKET); - ardougneCloak = new ItemRequirement("Ardougne cloak 1 or higher for teleports to the monastery", ItemID.CERT_ARRAVCERTIFICATE).isNotConsumed(); - } - - public void setupConditions() - { + ardougneCloak = new ItemRequirement("Ardougne cloak 1 or higher for teleports to the monastery", ItemCollections.ARDOUGNE_CLOAK).isNotConsumed(); } public void setupSteps() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mountaindaughter/MountainDaughter.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mountaindaughter/MountainDaughter.java index 8656228c9a..1818879a21 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mountaindaughter/MountainDaughter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mountaindaughter/MountainDaughter.java @@ -44,7 +44,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendparti/MourningsEndPartI.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendparti/MourningsEndPartI.java index d078424a57..4bc1e51ca4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendparti/MourningsEndPartI.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendparti/MourningsEndPartI.java @@ -396,7 +396,7 @@ public void setupSteps() askAboutToads = new NpcStep(this, NpcID.MOURNER_HIDEOUT_GNOME_HEAD, new WorldPoint(2035, 4630, 0), "Ask the gnome about ammo."); getToads = new DetailedQuestStep(this, new WorldPoint(2599, 2966, 0), - "You need to make some dyed toads. Go to Feldip Hills, use a dye on your empty bellows, then use the " + + "You need to make some dyed toads. Go to Feldip Hills (AKS), use a dye on your empty bellows, then use the " + "bellows to inflate a toad. Get at least one toad of each colour.", redToad, yellowToad, greenToad, blueToad); loadGreenToad = new DetailedQuestStep(this, "Add a green toad to the fixed device.", greenToad.highlighted(), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendpartii/MourningsEndPartII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendpartii/MourningsEndPartII.java index 9fe790e908..897b4cd3d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendpartii/MourningsEndPartII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/mourningsendpartii/MourningsEndPartII.java @@ -425,7 +425,7 @@ protected void setupRequirements() ItemCollections.PRAYER_POTIONS, -1); food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); - newKey = new KeyringRequirement("New Key", configManager, KeyringCollection.NEW_KEY); + newKey = new KeyringRequirement("New Key", KeyringCollection.NEW_KEY); newKey.setTooltip("You can get another from Essyllt's desk"); edernsJournal = new ItemRequirement("Edern's journal", ItemID.MOURNING_EDERNS_JOURNAL); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/murdermystery/MurderMystery.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/murdermystery/MurderMystery.java index dc9ceec725..7439a54df9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/murdermystery/MurderMystery.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/murdermystery/MurderMystery.java @@ -31,6 +31,9 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; @@ -39,17 +42,23 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarPlayerID; public class MurderMystery extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/myarmsbigadventure/MyArmsBigAdventure.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/myarmsbigadventure/MyArmsBigAdventure.java index dff3eeb43c..e3647a41ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/myarmsbigadventure/MyArmsBigAdventure.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/myarmsbigadventure/MyArmsBigAdventure.java @@ -385,7 +385,7 @@ public void setupSteps() talkToMyArmAfterBaby = new NpcStep(this, NpcID.MYARM_FIXED, new WorldPoint(2829, 3695, 0), "Talk to My Arm. Be prepared to fight the Giant Roc.", combatGear, spade); - killGiantRoc = new NpcStep(this, NpcID.MYARM_GIANT_ROC, "Kill the Giant Roc. Use protected from ranged, and keep your distance. You can dodge the boulders it throws."); + killGiantRoc = new NpcStep(this, NpcID.MYARM_GIANT_ROC, "Kill the Giant Roc. Use protect from missiles, and keep your distance. You can dodge the boulders it throws."); talkToMyArmAfterHarvest = new NpcStep(this, NpcID.MYARM_FIXED, new WorldPoint(2829, 3695, 0), "Talk to My Arm."); giveSpade = new NpcStep(this, NpcID.MYARM_FIXED, new WorldPoint(2829, 3695, 0), "Give My Arm a spade.", spadeHighlight); giveSpade.addIcon(ItemID.SPADE); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/naturespirit/NatureSpirit.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/naturespirit/NatureSpirit.java index 1cb97897df..ac557aae16 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/naturespirit/NatureSpirit.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/naturespirit/NatureSpirit.java @@ -43,7 +43,15 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -52,113 +60,84 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class NatureSpirit extends BasicQuestHelper { - //Items Required - ItemRequirement ghostspeak, silverSickle, washingBowl, mirror, journal, druidicSpell, druidPouch, blessedSickle, - spellCard, mirrorHighlighted, journalHighlighted, mushroom, mushroomHighlighted, druidPouchFull; - - //Items Recommended - ItemRequirement combatGear, salveTele; - - Requirement inUnderground, fillimanNearby, mirrorNearby, usedMushroom, onOrange, - usedCard, inGrotto, natureSpiritNearby, ghastNearby, prayerPoints; - - QuestStep goDownToDrezel, talkToDrezel, leaveDrezel, enterSwamp, tryToEnterGrotto, talkToFilliman, takeWashingBowl, - takeMirror, useMirrorOnFilliman, searchGrotto, useJournalOnFilliman, goBackDownToDrezel, talkToDrezelForBlessing, - castSpellAndGetMushroom, useMushroom, useSpellCard, standOnOrange, tellFillimanToCast, enterGrotto, searchAltar, - blessSickle, fillPouches, killGhasts, killGhast, enterGrottoAgain, touchAltarAgain, talkToNatureSpiritToFinish, - spawnFillimanForRitual, talkToFillimanInGrotto; - - //Zones - Zone underground, orangeStone, grotto; + // Required items + ItemRequirement ghostspeak; + ItemRequirement silverSickle; + + // Recommended items + ItemRequirement combatGear; + ItemRequirement salveTele; + + // Mid-quest requirements + ItemRequirement washingBowl; + ItemRequirement mirror; + ItemRequirement journal; + ItemRequirement druidicSpell; + ItemRequirement druidPouch; + ItemRequirement blessedSickle; + ItemRequirement spellCard; + ItemRequirement mirrorHighlighted; + ItemRequirement journalHighlighted; + ItemRequirement mushroom; + ItemRequirement mushroomHighlighted; + ItemRequirement druidPouchFull; + + // Zones + Zone underground; + Zone orangeStone; + Zone grotto; + + // Miscellaneous requirements + ZoneRequirement inUnderground; + NpcCondition fillimanNearby; + ItemOnTileRequirement mirrorNearby; + Conditions usedMushroom; + ZoneRequirement onOrange; + Conditions usedCard; + ZoneRequirement inGrotto; + NpcCondition natureSpiritNearby; + NpcCondition ghastNearby; + PrayerPointRequirement prayerPoints; + + // Steps + ObjectStep goDownToDrezel; + NpcStep talkToDrezel; + ObjectStep leaveDrezel; + ObjectStep enterSwamp; + ObjectStep tryToEnterGrotto; + NpcStep talkToFilliman; + DetailedQuestStep takeWashingBowl; + DetailedQuestStep takeMirror; + NpcStep useMirrorOnFilliman; + ObjectStep searchGrotto; + NpcStep useJournalOnFilliman; + ObjectStep goBackDownToDrezel; + NpcStep talkToDrezelForBlessing; + DetailedQuestStep castSpellAndGetMushroom; + ObjectStep useMushroom; + ObjectStep useSpellCard; + DetailedQuestStep standOnOrange; + NpcStep tellFillimanToCast; + ObjectStep enterGrotto; + ObjectStep searchAltar; + NpcStep blessSickle; + DetailedQuestStep fillPouches; + NpcStep killGhasts; + NpcStep killGhast; + ObjectStep enterGrottoAgain; + ObjectStep touchAltarAgain; + NpcStep talkToNatureSpiritToFinish; + ObjectStep spawnFillimanForRitual; + NpcStep talkToFillimanInGrotto; @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - ConditionalStep startQuest = new ConditionalStep(this, goDownToDrezel); - startQuest.addStep(inUnderground, talkToDrezel); - - steps.put(0, startQuest); - - ConditionalStep goEnterSwamp = new ConditionalStep(this, enterSwamp); - goEnterSwamp.addStep(inUnderground, leaveDrezel); - steps.put(1, goEnterSwamp); - steps.put(2, goEnterSwamp); - steps.put(3, goEnterSwamp); - steps.put(4, goEnterSwamp); - steps.put(5, goEnterSwamp); - - ConditionalStep goTalkToFilliman = new ConditionalStep(this, tryToEnterGrotto); - goTalkToFilliman.addStep(fillimanNearby, talkToFilliman); - steps.put(10, goTalkToFilliman); - steps.put(15, goTalkToFilliman); - - ConditionalStep showFillimanReflection = new ConditionalStep(this, takeWashingBowl); - showFillimanReflection.addStep(new Conditions(mirror, fillimanNearby), useMirrorOnFilliman); - showFillimanReflection.addStep(mirror, tryToEnterGrotto); - showFillimanReflection.addStep(mirrorNearby, takeMirror); - steps.put(20, showFillimanReflection); - - ConditionalStep goGetJournal = new ConditionalStep(this, searchGrotto); - goGetJournal.addStep(new Conditions(journal, fillimanNearby), useJournalOnFilliman); - goGetJournal.addStep(journal, tryToEnterGrotto); - steps.put(25, goGetJournal); - - ConditionalStep goOfferHelp = new ConditionalStep(this, tryToEnterGrotto); - goOfferHelp.addStep(fillimanNearby, useJournalOnFilliman); - steps.put(30, goOfferHelp); - - ConditionalStep getBlessed = new ConditionalStep(this, goBackDownToDrezel); - getBlessed.addStep(inUnderground, talkToDrezelForBlessing); - steps.put(35, getBlessed); - - ConditionalStep performRitual = new ConditionalStep(this, castSpellAndGetMushroom); - performRitual.addStep(new Conditions(usedMushroom, usedCard, fillimanNearby, onOrange), tellFillimanToCast); - performRitual.addStep(new Conditions(usedMushroom, usedCard, fillimanNearby), standOnOrange); - performRitual.addStep(new Conditions(usedMushroom, usedCard), spawnFillimanForRitual); - performRitual.addStep(usedMushroom, useSpellCard); - performRitual.addStep(mushroom, useMushroom); - steps.put(40, performRitual); - steps.put(45, performRitual); - steps.put(50, performRitual); - steps.put(55, performRitual); - - ConditionalStep goTalkInGrotto = new ConditionalStep(this, enterGrotto); - goTalkInGrotto.addStep(new Conditions(inGrotto, fillimanNearby), talkToFillimanInGrotto); - goTalkInGrotto.addStep(inGrotto, searchAltar); - steps.put(60, goTalkInGrotto); - - ConditionalStep goBlessSickle = new ConditionalStep(this, enterGrotto); - goBlessSickle.addStep(new Conditions(inGrotto, natureSpiritNearby), blessSickle); - goBlessSickle.addStep(inGrotto, searchAltar); - steps.put(65, goBlessSickle); - steps.put(70, goBlessSickle); - - ConditionalStep goKillGhasts = new ConditionalStep(this, fillPouches); - // TODO: Fix ghast changing form not counting towards becoming nearby - goKillGhasts.addStep(ghastNearby, killGhast); - goKillGhasts.addStep(druidPouchFull, killGhasts); - steps.put(75, goKillGhasts); - steps.put(80, goKillGhasts); - steps.put(85, goKillGhasts); - steps.put(90, goKillGhasts); - steps.put(95, goKillGhasts); - steps.put(100, goKillGhasts); - - ConditionalStep finishOff = new ConditionalStep(this, enterGrottoAgain); - finishOff.addStep(new Conditions(inGrotto, natureSpiritNearby), talkToNatureSpiritToFinish); - finishOff.addStep(inGrotto, touchAltarAgain); - steps.put(105, finishOff); - - return steps; + underground = new Zone(new WorldPoint(3402, 9880, 0), new WorldPoint(3443, 9907, 0)); + orangeStone = new Zone(new WorldPoint(3440, 3335, 0), new WorldPoint(3440, 3335, 0)); + grotto = new Zone(new WorldPoint(3435, 9733, 0), new WorldPoint(3448, 9746, 0)); } @Override @@ -184,23 +163,10 @@ protected void setupRequirements() spellCard.addAlternates(ItemID.BLOOM_SPELL); spellCard.setTooltip("You can get another spell from Filliman"); mushroom = new ItemRequirement("Mort myre fungus", ItemID.MORTMYREMUSHROOM); - mushroomHighlighted = new ItemRequirement("Mort myre fungus", ItemID.MORTMYREMUSHROOM); - mushroomHighlighted.setHighlightInInventory(true); + mushroomHighlighted = mushroom.highlighted(); salveTele = new ItemRequirement("Salve Graveyard Teleports", ItemID.TELETAB_SALVE, 2); combatGear = new ItemRequirement("Combat gear to kill the ghasts", -1, -1).isNotConsumed(); combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); - } - - @Override - protected void setupZones() - { - underground = new Zone(new WorldPoint(3402, 9880, 0), new WorldPoint(3443, 9907, 0)); - orangeStone = new Zone(new WorldPoint(3440, 3335, 0), new WorldPoint(3440, 3335, 0)); - grotto = new Zone(new WorldPoint(3435, 9733, 0), new WorldPoint(3448, 9746, 0)); - } - - public void setupConditions() - { inUnderground = new ZoneRequirement(underground); onOrange = new ZoneRequirement(orangeStone); inGrotto = new ZoneRequirement(grotto); @@ -223,12 +189,13 @@ public void setupConditions() public void setupSteps() { goDownToDrezel = new ObjectStep(this, ObjectID.TRAPDOOR, new WorldPoint(3405, 3507, 0), "Talk to Drezel under the Paterdomus Temple."); - ((ObjectStep) (goDownToDrezel)).addAlternateObjects(ObjectID.TRAPDOOR_OPEN); + goDownToDrezel.addAlternateObjects(ObjectID.TRAPDOOR_OPEN); talkToDrezel = new NpcStep(this, NpcID.PRIESTPERILTRAPPEDMONK_VIS, new WorldPoint(3439, 9896, 0), "Talk to Drezel under the Paterdomus Temple."); talkToDrezel.addDialogSteps("Well, what is it, I may be able to help?", "Yes."); talkToDrezel.addSubSteps(goDownToDrezel); leaveDrezel = new ObjectStep(this, ObjectID.PIP_UNDERGROUND_WALL_SIDE_WITHPORTAL, new WorldPoint(3440, 9886, 0), "Enter the Mort Myre from the north gate."); enterSwamp = new ObjectStep(this, ObjectID.MORTMYRE_METALGATECLOSED_L, new WorldPoint(3444, 3458, 0), "Enter the Mort Myre from the north gate.", ghostspeak); + enterSwamp.addSubSteps(leaveDrezel); tryToEnterGrotto = new ObjectStep(this, ObjectID.GROTTO_DOOR_DRUIDICSPIRIT, new WorldPoint(3440, 3337, 0), "Attempt to enter the Grotto in the south of Mort Myre.", ghostspeak); tryToEnterGrotto.addDialogStep("How long have you been a ghost?"); talkToFilliman = new NpcStep(this, NpcID.FILLIMAN_TARLOCK_SPIRIT, new WorldPoint(3440, 3336, 0), "Talk to Filliman Tarlock.", ghostspeak); @@ -242,12 +209,13 @@ public void setupSteps() useJournalOnFilliman = new NpcStep(this, NpcID.FILLIMAN_TARLOCK_SPIRIT, new WorldPoint(3440, 3336, 0), "Use the journal on Filliman Tarlock.", ghostspeak, journalHighlighted); useJournalOnFilliman.addIcon(ItemID.FILLIMAN_JOURNAL); useJournalOnFilliman.addDialogStep("How can I help?"); - goBackDownToDrezel = new ObjectStep(this, ObjectID.PIPEASTSIDETRAPDOOR, new WorldPoint(3422, 3485, 0), "Talk to Drezel to get blessed."); - ((ObjectStep) (goBackDownToDrezel)).addAlternateObjects(ObjectID.PIPEASTSIDETRAPDOOR_OPEN); - talkToDrezelForBlessing = new NpcStep(this, NpcID.PRIESTPERILTRAPPEDMONK_VIS, new WorldPoint(3439, 9896, 0), "Talk to Drezel under the Paterdomus Temple."); + goBackDownToDrezel = new ObjectStep(this, ObjectID.PIPEASTSIDETRAPDOOR, new WorldPoint(3422, 3485, 0), "Return to Drezel under the Paterdomus Temple to get blessed."); + goBackDownToDrezel.addAlternateObjects(ObjectID.PIPEASTSIDETRAPDOOR_OPEN); + talkToDrezelForBlessing = new NpcStep(this, NpcID.PRIESTPERILTRAPPEDMONK_VIS, new WorldPoint(3439, 9896, 0), "Return to Drezel under the Paterdomus Temple to get blessed."); talkToDrezelForBlessing.addSubSteps(goBackDownToDrezel); talkToDrezelForBlessing.addSubSteps(goBackDownToDrezel); - castSpellAndGetMushroom = new DetailedQuestStep(this, "Cast the druidic spell next to a rotten log in Mort Myre to grow a mushroom. Pick it. If you already have, open the quest journal to re-sync your state.", druidicSpell); + castSpellAndGetMushroom = new ObjectStep(this, ObjectID.LOG_DRUIDICSPIRIT2, "Cast the druidic spell next to a rotten log in Mort Myre to grow a mushroom. Pick it. If you already have, open the quest journal to re-sync your state.", druidicSpell); + castSpellAndGetMushroom.addDialogStep("Could I have another bloom scroll please?"); useMushroom = new ObjectStep(this, ObjectID.STONEDISC_DS_NATURE, new WorldPoint(3439, 3336, 0), "Use the mushroom on the brown stone outside the grotto. If you already have, search it instead.", mushroomHighlighted); useMushroom.addIcon(ItemID.MORTMYREMUSHROOM); useSpellCard = new ObjectStep(this, ObjectID.STONEDISC_DS_SPIRIT, new WorldPoint(3441, 3336, 0), "Use the used spell on the gray stone outside the grotto. If you already have, search it instead.", spellCard); @@ -265,7 +233,7 @@ public void setupSteps() blessSickle = new NpcStep(this, NpcID.FILLIMAN_TARLOCK_NS, new WorldPoint(3441, 9738, 0), "Talk to the Nature Spirit in the grotto to bless your sickle.", ghostspeak, silverSickle); fillPouches = new DetailedQuestStep(this, "Right-click 'bloom' the blessed sickle next to rotten logs for mort myre fungi. Use these to fill the druid pouch.", blessedSickle, prayerPoints - , druidPouch); + , druidPouch); killGhasts = new NpcStep(this, NpcID.GHAST_INVIS, "Use the filled druid pouch on a ghast to make it attackable and kill it. You'll need to kill 3.", druidPouchFull); killGhast = new NpcStep(this, NpcID.GHAST_VIS, "Kill the ghast.", druidPouchFull); killGhasts.addSubSteps(killGhast); @@ -276,36 +244,132 @@ public void setupSteps() } @Override - public List getItemRequirements() + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + var startQuest = new ConditionalStep(this, goDownToDrezel); + startQuest.addStep(inUnderground, talkToDrezel); + steps.put(0, startQuest); + + var goEnterSwamp = new ConditionalStep(this, enterSwamp); + goEnterSwamp.addStep(inUnderground, leaveDrezel); + steps.put(1, goEnterSwamp); + steps.put(2, goEnterSwamp); + steps.put(3, goEnterSwamp); + steps.put(4, goEnterSwamp); + steps.put(5, goEnterSwamp); + + var goTalkToFilliman = new ConditionalStep(this, tryToEnterGrotto); + goTalkToFilliman.addStep(fillimanNearby, talkToFilliman); + steps.put(10, goTalkToFilliman); + steps.put(15, goTalkToFilliman); + + var showFillimanReflection = new ConditionalStep(this, takeWashingBowl); + showFillimanReflection.addStep(new Conditions(mirror, fillimanNearby), useMirrorOnFilliman); + showFillimanReflection.addStep(mirror, tryToEnterGrotto); + showFillimanReflection.addStep(mirrorNearby, takeMirror); + steps.put(20, showFillimanReflection); + + var goGetJournal = new ConditionalStep(this, searchGrotto); + goGetJournal.addStep(new Conditions(journal, fillimanNearby), useJournalOnFilliman); + goGetJournal.addStep(journal, tryToEnterGrotto); + steps.put(25, goGetJournal); + + var goOfferHelp = new ConditionalStep(this, tryToEnterGrotto); + goOfferHelp.addStep(fillimanNearby, useJournalOnFilliman); + steps.put(30, goOfferHelp); + + var getBlessed = new ConditionalStep(this, goBackDownToDrezel); + getBlessed.addStep(inUnderground, talkToDrezelForBlessing); + steps.put(35, getBlessed); + + var performRitual = new ConditionalStep(this, castSpellAndGetMushroom); + performRitual.addStep(new Conditions(usedMushroom, usedCard, fillimanNearby, onOrange), tellFillimanToCast); + performRitual.addStep(new Conditions(usedMushroom, usedCard, fillimanNearby), standOnOrange); + performRitual.addStep(new Conditions(usedMushroom, usedCard), spawnFillimanForRitual); + performRitual.addStep(usedMushroom, useSpellCard); + performRitual.addStep(mushroom, useMushroom); + steps.put(40, performRitual); + steps.put(45, performRitual); + steps.put(50, performRitual); + steps.put(55, performRitual); + + var goTalkInGrotto = new ConditionalStep(this, enterGrotto); + goTalkInGrotto.addStep(new Conditions(inGrotto, fillimanNearby), talkToFillimanInGrotto); + goTalkInGrotto.addStep(inGrotto, searchAltar); + steps.put(60, goTalkInGrotto); + + var goBlessSickle = new ConditionalStep(this, enterGrotto); + goBlessSickle.addStep(new Conditions(inGrotto, natureSpiritNearby), blessSickle); + goBlessSickle.addStep(inGrotto, searchAltar); + steps.put(65, goBlessSickle); + steps.put(70, goBlessSickle); + + var goKillGhasts = new ConditionalStep(this, fillPouches); + // TODO: Fix ghast changing form not counting towards becoming nearby + goKillGhasts.addStep(ghastNearby, killGhast); + goKillGhasts.addStep(druidPouchFull, killGhasts); + steps.put(75, goKillGhasts); + steps.put(80, goKillGhasts); + steps.put(85, goKillGhasts); + steps.put(90, goKillGhasts); + steps.put(95, goKillGhasts); + steps.put(100, goKillGhasts); + + var finishOff = new ConditionalStep(this, enterGrottoAgain); + finishOff.addStep(new Conditions(inGrotto, natureSpiritNearby), talkToNatureSpiritToFinish); + finishOff.addStep(inGrotto, touchAltarAgain); + steps.put(105, finishOff); + + return steps; + } + + + @Override + public List getGeneralRequirements() { - return Arrays.asList(ghostspeak, silverSickle); + return List.of( + new QuestRequirement(QuestHelperQuest.THE_RESTLESS_GHOST, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.PRIEST_IN_PERIL, QuestState.FINISHED) + ); } @Override - public List getItemRecommended() + public List getItemRequirements() { - return Arrays.asList(salveTele, combatGear); + return List.of( + ghostspeak, + silverSickle + ); } @Override - public List getNotes() + public List getItemRecommended() { - return Collections.singletonList("Whilst in Mort Myre, the Ghasts will occasionally rot the food in your inventory."); + return List.of( + salveTele, + combatGear + ); } @Override public List getCombatRequirements() { - return Collections.singletonList("3 Ghasts (level 30)"); + return List.of( + "3 Ghasts (level 30)" + ); } @Override - public List getGeneralRequirements() + public List getNotes() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.THE_RESTLESS_GHOST, QuestState.FINISHED)); - req.add(new QuestRequirement(QuestHelperQuest.PRIEST_IN_PERIL, QuestState.FINISHED)); - return req; + return List.of( + "Whilst in Mort Myre, the Ghasts will occasionally rot the food in your inventory." + ); } @Override @@ -317,33 +381,70 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Arrays.asList( - new ExperienceReward(Skill.CRAFTING, 3000), - new ExperienceReward(Skill.DEFENCE, 2000), - new ExperienceReward(Skill.HITPOINTS, 2000)); + return List.of( + new ExperienceReward(Skill.CRAFTING, 3000), + new ExperienceReward(Skill.DEFENCE, 2000), + new ExperienceReward(Skill.HITPOINTS, 2000) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("Access to Mort Myre Swamp"), - new UnlockReward("Ability to fight Ghasts.")); + return List.of( + new UnlockReward("Access to Mort Myre Swamp"), + new UnlockReward("Ability to fight Ghasts.") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Start the quest", - Arrays.asList(talkToDrezel, enterSwamp, tryToEnterGrotto, talkToFilliman, takeWashingBowl, - takeMirror, useMirrorOnFilliman, searchGrotto, useJournalOnFilliman), ghostspeak, silverSickle, prayerPoints)); - allSteps.add(new PanelDetails("Helping Filliman", - Arrays.asList(talkToDrezelForBlessing, castSpellAndGetMushroom, useMushroom, useSpellCard, standOnOrange, - tellFillimanToCast, enterGrotto, searchAltar, talkToFillimanInGrotto, blessSickle), ghostspeak, silverSickle)); - allSteps.add(new PanelDetails("Killing Ghasts", - Arrays.asList(fillPouches, killGhasts, enterGrottoAgain, talkToNatureSpiritToFinish), ghostspeak, blessedSickle, prayerPoints)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Start the quest", List.of( + talkToDrezel, + enterSwamp, + tryToEnterGrotto, + talkToFilliman, + takeWashingBowl, + takeMirror, + useMirrorOnFilliman, + searchGrotto, + useJournalOnFilliman + ), List.of( + ghostspeak, + silverSickle, + prayerPoints + ))); + + sections.add(new PanelDetails("Helping Filliman", List.of( + talkToDrezelForBlessing, + castSpellAndGetMushroom, + useMushroom, + useSpellCard, + standOnOrange, + tellFillimanToCast, + enterGrotto, + searchAltar, + talkToFillimanInGrotto, + blessSickle + ), List.of( + ghostspeak, + silverSickle + ))); + + sections.add(new PanelDetails("Killing Ghasts", List.of( + fillPouches, + killGhasts, + enterGrottoAgain, + talkToNatureSpiritToFinish + ), List.of( + ghostspeak, + blessedSickle, + prayerPoints + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/ObservatoryQuest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/ObservatoryQuest.java index ecea6eb355..b4760fc6bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/ObservatoryQuest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/ObservatoryQuest.java @@ -30,6 +30,8 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -37,18 +39,23 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; public class ObservatoryQuest extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/StarSignAnswer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/StarSignAnswer.java deleted file mode 100644 index 89661aad86..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/observatoryquest/StarSignAnswer.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2021, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.helpers.quests.observatoryquest; - -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.gameval.NpcID; -import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; -import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestVarPlayer; -import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; - -import java.util.HashMap; - -public class StarSignAnswer extends NpcStep -{ - HashMap starSign = new HashMap<>(); - int currentValue = -1; - - public StarSignAnswer(QuestHelper questHelper) - { - super(questHelper, NpcID.OBSERVATORY_PROFESSOR, new WorldPoint(2440, 3159, - 1), "Tell the professor the constellation you observed."); - starSign.put(0, "Aquarius"); - starSign.put(1, "Capricorn"); - starSign.put(2, "Sagittarius"); - starSign.put(3, "Scorpio"); - starSign.put(4, "Libra"); - starSign.put(5, "Virgo"); - starSign.put(6, "Leo"); - starSign.put(7, "Cancer"); - starSign.put(8, "Gemini"); - starSign.put(9, "Taurus"); - starSign.put(10, "Aries"); - starSign.put(11, "Pisces"); - } - - @Override - public void startUp() - { - super.startUp(); - updateCorrectChoice(); - } - - @Override - public void onVarbitChanged(VarbitChanged varbitChanged) - { - super.onVarbitChanged(varbitChanged); - updateCorrectChoice(); - } - - private void updateCorrectChoice() - { - addDialogSteps("Talk about the Observatory quest."); - int currentStep = client.getVarpValue(QuestVarPlayer.QUEST_OBSERVATORY_QUEST.getId()); - if (currentStep < 2) - { - return; - } - - int newValue = client.getVarbitValue(3828); - if (currentValue != newValue) - { - currentValue = newValue; - String constellation = starSign.get(newValue); - setText("Tell the professor you observed " + constellation + "."); - addDialogStep(constellation); - } - - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/onesmallfavour/OneSmallFavour.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/onesmallfavour/OneSmallFavour.java index 18224d1ca4..b273261a7c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/onesmallfavour/OneSmallFavour.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/onesmallfavour/OneSmallFavour.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.quests.onesmallfavour; +import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; @@ -32,16 +33,32 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.TileStep; +import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -50,265 +67,302 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - public class OneSmallFavour extends BasicQuestHelper { - //Items Required - ItemRequirement steelBars4, steelBars3, steelBar, bronzeBar, ironBar, chisel, guam2, guam, marrentill, harralander, hammer, hammerHighlight, emptyCup, pigeonCages5, pot, hotWaterBowl, softClay, - opal, jade, sapphire, redTopaz, bluntAxe, herbalTincture, guthixRest, uncutSapphire, cupOfWater, - uncutOpal, uncutJade, uncutRedTopaz, stodgyMattress, mattress, animateRockScroll, animateRockScrollHighlight, ironOxide, brokenVane1, brokenVane2, brokenVane3, ornament, - weathervanePillar, directionals, weatherReport, unfiredPotLid, potLid, potWithLid, breathingSalts, chickenCages5, sharpenedAxe, redMahog; - - ItemRequirement guamTea, guam2Tea, harrTea, marrTea, guamMarrTea, guamHarrTea, harrMarrTea, guam2MarrTea, - guam2HarrTea, guamHarrMarrTea, herbTeaMix; - - //Items Recommended - ItemRequirement draynorVillageTeleports, lumbridgeTeleports, varrockTeleports, taverleyOrFaladorTeleports, camelotTeleports, fishingGuildAndDwarvenMineTeleports, ardougneTeleports, khazardTeleports, feldipHillsTeleports, pickaxe; - - Requirement inSanfewRoom, inHamBase, inDwarvenMine, inGoblinCave, lamp1Empty, lamp1Full, lamp2Empty, lamp2Full, - lamp3Empty, lamp3Full, lamp4Empty, lamp4Full, lamp5Empty, lamp5Full, lamp6Empty, lamp6Full, lamp7Empty, lamp7Full, lamp8Empty, lamp8Full, allEmpty, allFull, inScrollSpot, - slagilithNearby, petraNearby, inSeersVillageUpstairs, onRoof, addedOrnaments, addedDirectionals, addedWeathervanePillar, hasOrUsedOrnament, hasOrUsedDirectionals, - hasOrUsedWeathervanePillar; - - DetailedQuestStep talkToYanni, talkToJungleForester, talkToBrian, talkToAggie, goDownToJohanhus, talkToJohanhus, talkToFred, talkToSeth, talkToHorvik, - talkToApoth, talkToTassie, goDownToHammerspike, talkToHammerspike, goUpToSanfew, talkToSanfew, makeGuthixRest, talkToBleemadge, talkToArhein, talkToPhantuwti, enterGoblinCave, - searchWall, talkToCromperty, talkToTindel, talkToRantz, talkToGnormadium, talkToBleemadgeNoTea, take1, take2, take3, take4, take5, take6, take7, take8, - cutSaph, cutJade, cutTopaz, cutOpal, put1, put2, put3, put4, put5, put6, put7, put8, talkToGnormadiumAgain, returnToRantz, returnToTindel, returnToCromperty, getPigeonCages, - enterGoblinCaveAgain, standNextToSculpture, readScroll, killSlagilith, readScrollAgain, talkToPetra, returnToPhantuwti, goUpLadder, goUpToRoof, searchVane, useHammerOnVane, - goDownFromRoof, goDownLadderToSeers, useVane123OnAnvil, useVane2OnAnvil, useVane3OnAnvil, goBackUpLadder, goBackUpToRoof, useVane1, useVane2, useVane3, - goFromRoofToPhantuwti, goDownLadderToPhantuwti, finishWithPhantuwti, returnToArhein, returnToBleemadge, returnToSanfew, goDownToHammerspikeAgain, returnToHammerspike, - killGangMembers, talkToHammerspikeFinal, returnToTassie, spinPotLid, pickUpPot, firePotLid, usePotLidOnPot, returnToApothecary, returnToHorvik, talkToHorvikFinal, returnToSeth, - returnDownToJohnahus, returnToJohnahus, returnToAggie, returnToBrian, returnToForester, returnToYanni, returnUpToSanfew, returnToPhantuwti2, useVane12OnAnvil, useVane13OnAnvil, - useVane23OnAnvil, useVane1OnAnvil, fixAllLamps, searchVaneAgain; - - DetailedQuestStep useBowlOnCup, useHerbsOnCup; - - //Zones - Zone sanfewRoom, hamBase, dwarvenMine, goblinCave, scrollSpot, seersVillageUpstairs, roof; - - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - steps.put(0, talkToYanni); - steps.put(5, talkToJungleForester); - - steps.put(10, talkToBrian); - steps.put(15, talkToBrian); - - steps.put(20, talkToAggie); - - ConditionalStep goTalkToJohanhus = new ConditionalStep(this, goDownToJohanhus); - goTalkToJohanhus.addStep(inHamBase, talkToJohanhus); - - steps.put(25, goTalkToJohanhus); - steps.put(30, goTalkToJohanhus); - steps.put(35, goTalkToJohanhus); - steps.put(40, goTalkToJohanhus); - - steps.put(45, talkToFred); - steps.put(50, talkToSeth); - steps.put(55, talkToHorvik); - steps.put(60, talkToApoth); - steps.put(62, talkToApoth); - steps.put(63, talkToApoth); - - steps.put(65, talkToTassie); - - ConditionalStep goTalkToHammerspike = new ConditionalStep(this, goDownToHammerspike); - goTalkToHammerspike.addStep(inDwarvenMine, talkToHammerspike); - steps.put(70, goTalkToHammerspike); - - ConditionalStep goTalkToSanfew = new ConditionalStep(this, goUpToSanfew); - goTalkToSanfew.addStep(inSanfewRoom, talkToSanfew); - - steps.put(75, goTalkToSanfew); - - ConditionalStep makeGuthixRestForGnome = new ConditionalStep(this, useBowlOnCup); - makeGuthixRestForGnome.addStep(guthixRest, talkToBleemadge); - makeGuthixRestForGnome.addStep(new Conditions(LogicType.OR, herbTeaMix, cupOfWater), useHerbsOnCup); - - steps.put(80, makeGuthixRestForGnome); - steps.put(81, makeGuthixRestForGnome); - steps.put(82, makeGuthixRestForGnome); - steps.put(83, makeGuthixRestForGnome); - steps.put(84, makeGuthixRestForGnome); - - steps.put(86, talkToBleemadgeNoTea); - - steps.put(88, talkToArhein); - - steps.put(90, talkToPhantuwti); - - ConditionalStep investigateWall = new ConditionalStep(this, enterGoblinCave); - investigateWall.addStep(inGoblinCave, searchWall); - - steps.put(95, investigateWall); - - steps.put(100, talkToCromperty); - - steps.put(105, talkToTindel); - - steps.put(110, talkToRantz); - - steps.put(115, talkToGnormadium); - - ConditionalStep repairLights = new ConditionalStep(this, take1); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full, lamp8Empty, sapphire), put8); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full, lamp8Empty), cutSaph); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full), take8); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Empty, opal), put7); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Empty), cutOpal); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full), take7); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Empty, redTopaz), - put6); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Empty), cutTopaz); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full), take6); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Empty, jade), put5); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Empty), cutJade); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Full), take5); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Empty, sapphire), put4); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full, lamp4Empty), cutSaph); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Full), take4); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Empty, opal), put3); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full, lamp3Empty), cutOpal); - repairLights.addStep(new Conditions(lamp1Full, lamp2Full), take3); - repairLights.addStep(new Conditions(lamp1Full, lamp2Empty, redTopaz), put2); - repairLights.addStep(new Conditions(lamp1Full, lamp2Empty), cutTopaz); - repairLights.addStep(lamp1Full, take2); - repairLights.addStep(new Conditions(lamp1Empty, jade), put1); - repairLights.addStep(lamp1Empty, cutJade); - - steps.put(120, repairLights); - - steps.put(125, talkToGnormadiumAgain); - - steps.put(130, returnToRantz); - - steps.put(135, returnToTindel); - - steps.put(140, returnToCromperty); - - ConditionalStep fightSlagilith = new ConditionalStep(this, getPigeonCages); - fightSlagilith.addStep(slagilithNearby, killSlagilith); - fightSlagilith.addStep(inScrollSpot, readScroll); - fightSlagilith.addStep(inGoblinCave, standNextToSculpture); - fightSlagilith.addStep(pigeonCages5.alsoCheckBank(), enterGoblinCaveAgain); - - steps.put(145, fightSlagilith); - steps.put(150, fightSlagilith); - - ConditionalStep freePetra = new ConditionalStep(this, getPigeonCages); - freePetra.addStep(petraNearby, talkToPetra); - freePetra.addStep(inScrollSpot, readScroll); - freePetra.addStep(inGoblinCave, standNextToSculpture); - freePetra.addStep(pigeonCages5.alsoCheckBank(), enterGoblinCaveAgain); + // Required items + ItemRequirement steelBars4; + ItemRequirement bronzeBar; + ItemRequirement ironBar; + ItemRequirement chisel; + ItemRequirement guam2; + ItemRequirement marrentill; + ItemRequirement harralander; + ItemRequirement hammer; + ItemRequirement emptyCup; + ItemRequirement pot; + ItemRequirement hotWaterBowl; + + // Recommended items + ItemRequirement draynorVillageTeleports; + ItemRequirement lumbridgeTeleports; + ItemRequirement varrockTeleports; + ItemRequirement taverleyOrFaladorTeleports; + ItemRequirement camelotTeleports; + ItemRequirement fishingGuildAndDwarvenMineTeleports; + ItemRequirement ardougneTeleports; + ItemRequirement khazardTeleports; + ItemRequirement feldipHillsTeleports; + ItemRequirement pickaxe; + ItemRequirement opal2; + ItemRequirement jade2; + ItemRequirement redTopaz2; + ItemRequirement coins3000; + ItemRequirement combatGear; + + // Mid-quest item requirements + ItemRequirement opal; + ItemRequirement jade; + ItemRequirement redTopaz; + ItemRequirement sapphire; + ItemRequirement softClay; + ItemRequirement bluntAxe; + ItemRequirement herbalTincture; + ItemRequirement guthixRest; + ItemRequirement uncutSapphire; + ItemRequirement cupOfWater; + ItemRequirement uncutOpal; + ItemRequirement uncutJade; + ItemRequirement uncutRedTopaz; + ItemRequirement stodgyMattress; + ItemRequirement mattress; + ItemRequirement animateRockScroll; + ItemRequirement animateRockScrollHighlight; + ItemRequirement ironOxide; + ItemRequirement brokenVane1; + ItemRequirement brokenVane2; + ItemRequirement brokenVane3; + ItemRequirement ornament; + ItemRequirement weathervanePillar; + ItemRequirement directionals; + ItemRequirement weatherReport; + ItemRequirement unfiredPotLid; + ItemRequirement potLid; + ItemRequirement potWithLid; + ItemRequirement breathingSalts; + ItemRequirement chickenCages5; + ItemRequirement sharpenedAxe; + ItemRequirement redMahog; + ItemRequirement steelBars3; + ItemRequirement steelBar; + ItemRequirement guam; + ItemRequirement hammerHighlight; + ItemRequirement pigeonCages5; + ItemRequirement guamTea; + ItemRequirement guam2Tea; + ItemRequirement harrTea; + ItemRequirement marrTea; + ItemRequirement guamMarrTea; + ItemRequirement guamHarrTea; + ItemRequirement harrMarrTea; + ItemRequirement guam2MarrTea; + ItemRequirement guam2HarrTea; + ItemRequirement guamHarrMarrTea; + ItemRequirement herbTeaMix; + + // Zones + Zone sanfewRoom; + Zone hamBase; + Zone dwarvenMine; + Zone goblinCave; + Zone scrollSpot; + Zone seersVillageUpstairs; + Zone roof; + + // Miscellaneous requirements + ZoneRequirement inSanfewRoom; + ZoneRequirement inHamBase; + ZoneRequirement inDwarvenMine; + ZoneRequirement inGoblinCave; + VarbitRequirement lamp1Empty; + VarbitRequirement lamp1Full; + VarbitRequirement lamp2Empty; + VarbitRequirement lamp2Full; + VarbitRequirement lamp3Empty; + VarbitRequirement lamp3Full; + VarbitRequirement lamp4Empty; + VarbitRequirement lamp4Full; + VarbitRequirement lamp5Empty; + VarbitRequirement lamp5Full; + VarbitRequirement lamp6Empty; + VarbitRequirement lamp6Full; + VarbitRequirement lamp7Empty; + VarbitRequirement lamp7Full; + VarbitRequirement lamp8Empty; + VarbitRequirement lamp8Full; + VarbitRequirement allFull; + ZoneRequirement inScrollSpot; + NpcCondition slagilithNearby; + NpcCondition petraNearby; + ZoneRequirement inSeersVillageUpstairs; + ZoneRequirement onRoof; + VarbitRequirement addedOrnaments; + VarbitRequirement addedDirectionals; + VarbitRequirement addedWeathervanePillar; + Conditions hasOrUsedOrnament; + Conditions hasOrUsedDirectionals; + Conditions hasOrUsedWeathervanePillar; + FreeInventorySlotRequirement freeSlots3; + + // Steps + NpcStep talkToYanni; + + NpcStep talkToJungleForester; + + NpcStep talkToBrian; + + NpcStep talkToAggie; + + ObjectStep goDownToJohanhus; + NpcStep talkToJohanhus; + + NpcStep talkToFred; + + NpcStep talkToSeth; + + NpcStep talkToHorvik; + + NpcStep talkToApoth; + + NpcStep talkToTassie; + + ObjectStep goDownToHammerspike; + NpcStep talkToHammerspike; + + ObjectStep goUpToSanfew; + NpcStep talkToSanfew; + + DetailedQuestStep useBowlOnCup; + DetailedQuestStep useHerbsOnCup; + DetailedQuestStep makeGuthixRest; + NpcStep talkToBleemadge; + + NpcStep talkToBleemadgeNoTea; + + NpcStep talkToArhein; + + NpcStep talkToPhantuwti; + + ObjectStep enterGoblinCave; + ObjectStep searchWall; + + NpcStep talkToCromperty; + + NpcStep talkToTindel; + + NpcStep talkToRantz; + + NpcStep talkToGnormadium; - steps.put(152, freePetra); - steps.put(155, freePetra); + ObjectStep take1; + ObjectStep take2; + ObjectStep take3; + ObjectStep take4; + ObjectStep take5; + ObjectStep take6; + ObjectStep take7; + ObjectStep take8; + DetailedQuestStep cutSaph; + DetailedQuestStep cutJade; + DetailedQuestStep cutTopaz; + DetailedQuestStep cutOpal; + ObjectStep put1; + ObjectStep put2; + ObjectStep put3; + ObjectStep put4; + ObjectStep put5; + ObjectStep put6; + ObjectStep put7; + ObjectStep put8; + DetailedQuestStep fixAllLamps; - steps.put(160, returnToPhantuwti); - steps.put(165, returnToPhantuwti2); - steps.put(170, returnToPhantuwti2); + NpcStep talkToGnormadiumAgain; - ConditionalStep repairVane = new ConditionalStep(this, goUpLadder); - repairVane.addStep(onRoof, searchVane); - repairVane.addStep(inSeersVillageUpstairs, goUpToRoof); - - steps.put(175, repairVane); + NpcStep returnToRantz; - ConditionalStep hitVane = new ConditionalStep(this, goUpLadder); - hitVane.addStep(onRoof, useHammerOnVane); - hitVane.addStep(inSeersVillageUpstairs, goUpToRoof); + NpcStep returnToTindel; - steps.put(176, hitVane); + NpcStep returnToCromperty; - ConditionalStep getVaneBits = new ConditionalStep(this, goUpLadder); - getVaneBits.addStep(onRoof, searchVaneAgain); - getVaneBits.addStep(inSeersVillageUpstairs, goUpToRoof); + DetailedQuestStep getPigeonCages; + ObjectStep enterGoblinCaveAgain; + DetailedQuestStep standNextToSculpture; + DetailedQuestStep readScroll; + NpcStep killSlagilith; - steps.put(177, getVaneBits); + DetailedQuestStep readScrollAgain; + NpcStep talkToPetra; - ConditionalStep repairVaneParts = new ConditionalStep(this, useVane123OnAnvil); + NpcStep returnToPhantuwti; - repairVaneParts.addStep(new Conditions(addedOrnaments, addedDirectionals, weathervanePillar, onRoof), useVane3); - repairVaneParts.addStep(new Conditions(addedOrnaments, directionals, onRoof), useVane2); - repairVaneParts.addStep(new Conditions(ornament, onRoof), useVane1); - repairVaneParts.addStep(onRoof, goDownFromRoof); - repairVaneParts.addStep(new Conditions(hasOrUsedDirectionals, hasOrUsedOrnament, hasOrUsedWeathervanePillar, inSeersVillageUpstairs), goBackUpToRoof); - repairVaneParts.addStep(inSeersVillageUpstairs, goDownLadderToSeers); - repairVaneParts.addStep(new Conditions(hasOrUsedDirectionals, hasOrUsedOrnament, hasOrUsedWeathervanePillar), goBackUpLadder); - repairVaneParts.addStep(new Conditions(hasOrUsedDirectionals, hasOrUsedOrnament), useVane3OnAnvil); - repairVaneParts.addStep(new Conditions(hasOrUsedOrnament, hasOrUsedWeathervanePillar), useVane1OnAnvil); - repairVaneParts.addStep(new Conditions(hasOrUsedDirectionals, hasOrUsedWeathervanePillar), useVane2OnAnvil); - repairVaneParts.addStep(hasOrUsedOrnament, useVane13OnAnvil); - repairVaneParts.addStep(hasOrUsedWeathervanePillar, useVane12OnAnvil); - repairVaneParts.addStep(hasOrUsedDirectionals, useVane23OnAnvil); + NpcStep returnToPhantuwti2; - steps.put(180, repairVaneParts); + ObjectStep goUpLadder; + ObjectStep goUpToRoof; + ObjectStep searchVane; - ConditionalStep reportBackToPhantuwti = new ConditionalStep(this, finishWithPhantuwti); - reportBackToPhantuwti.addStep(inSeersVillageUpstairs, goDownLadderToPhantuwti); - reportBackToPhantuwti.addStep(onRoof, goFromRoofToPhantuwti); + ObjectStep useHammerOnVane; - steps.put(185, reportBackToPhantuwti); + ObjectStep searchVaneAgain; - steps.put(190, returnToArhein); + ObjectStep goDownFromRoof; + ObjectStep goDownLadderToSeers; + ObjectStep useVane123OnAnvil; + ObjectStep useVane12OnAnvil; + ObjectStep useVane13OnAnvil; + ObjectStep useVane23OnAnvil; + ObjectStep useVane1OnAnvil; + ObjectStep useVane2OnAnvil; + ObjectStep useVane3OnAnvil; - steps.put(195, returnToBleemadge); + ObjectStep goBackUpLadder; + ObjectStep goBackUpToRoof; + ObjectStep useVane1; + ObjectStep useVane2; + ObjectStep useVane3; - ConditionalStep goAndReturnToSanfew = new ConditionalStep(this, returnUpToSanfew); - goAndReturnToSanfew.addStep(inSanfewRoom, returnToSanfew); - steps.put(200, goAndReturnToSanfew); + ObjectStep goFromRoofToPhantuwti; + ObjectStep goDownLadderToPhantuwti; + NpcStep finishWithPhantuwti; - ConditionalStep dealWithHammerspike = new ConditionalStep(this, goDownToHammerspikeAgain); - dealWithHammerspike.addStep(inDwarvenMine, returnToHammerspike); + NpcStep returnToArhein; - steps.put(205, dealWithHammerspike); + NpcStep returnToBleemadge; - ConditionalStep sortOutGangMembers = new ConditionalStep(this, goDownToHammerspikeAgain); - sortOutGangMembers.addStep(inDwarvenMine, killGangMembers); + ObjectStep returnUpToSanfew; + NpcStep returnToSanfew; - steps.put(210, sortOutGangMembers); - steps.put(215, sortOutGangMembers); - steps.put(220, sortOutGangMembers); - steps.put(225, dealWithHammerspike); + ObjectStep goDownToHammerspikeAgain; + NpcStep returnToHammerspike; - steps.put(230, returnToTassie); + NpcStep killGangMembers; - ConditionalStep makePotAndReturnToApoth = new ConditionalStep(this, spinPotLid); - makePotAndReturnToApoth.addStep(potWithLid, returnToApothecary); - makePotAndReturnToApoth.addStep(new Conditions(potLid, pot), usePotLidOnPot); - makePotAndReturnToApoth.addStep(potLid, pickUpPot); - makePotAndReturnToApoth.addStep(unfiredPotLid, firePotLid); + NpcStep talkToHammerspikeFinal; - steps.put(235, makePotAndReturnToApoth); + NpcStep returnToTassie; - steps.put(240, returnToHorvik); + ObjectStep spinPotLid; + ItemStep pickUpPot; + ObjectStep firePotLid; + DetailedQuestStep usePotLidOnPot; + NpcStep returnToApothecary; - steps.put(245, talkToHorvikFinal); + NpcStep returnToHorvik; - steps.put(250, returnToSeth); + NpcStep talkToHorvikFinal; - ConditionalStep goFinishWithJohanhus = new ConditionalStep(this, returnDownToJohnahus); - goFinishWithJohanhus.addStep(inHamBase, returnToJohnahus); + NpcStep returnToSeth; - steps.put(255, goFinishWithJohanhus); + ObjectStep returnDownToJohnahus; + NpcStep returnToJohnahus; - steps.put(260, returnToAggie); + NpcStep returnToAggie; - steps.put(265, returnToBrian); + NpcStep returnToBrian; - steps.put(270, returnToForester); + NpcStep returnToForester; - steps.put(275, returnToYanni); + NpcStep returnToYanni; - return steps; + @Override + protected void setupZones() + { + sanfewRoom = new Zone(new WorldPoint(2893, 3423, 1), new WorldPoint(2903, 3433, 1)); + hamBase = new Zone(new WorldPoint(3140, 9600, 0), new WorldPoint(3190, 9655, 0)); + dwarvenMine = new Zone(new WorldPoint(2960, 9696, 0), new WorldPoint(3062, 9854, 0)); + goblinCave = new Zone(new WorldPoint(2560, 9792, 0), new WorldPoint(2623, 9855, 0)); + scrollSpot = new Zone(new WorldPoint(2616, 9835, 0), new WorldPoint(2619, 9835, 0)); + seersVillageUpstairs = new Zone(new WorldPoint(2698, 3468, 1), new WorldPoint(2717, 3476, 1)); + roof = new Zone(new WorldPoint(2695, 3469, 3), new WorldPoint(2716, 3476, 3)); } @Override @@ -353,6 +407,18 @@ protected void setupRequirements() pickaxe = new ItemRequirement("Any pickaxe to kill Slagilith", ItemCollections.PICKAXES).isNotConsumed(); + combatGear = new ItemRequirement("Combat gear to fight Slagilith and the dwarf gang members", -1, -1); + combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); + + opal2 = new ItemRequirement("Opal", ItemID.OPAL, 2); + opal2.setHighlightInInventory(true); + jade2 = new ItemRequirement("Jade", ItemID.JADE, 2); + jade2.setHighlightInInventory(true); + redTopaz2 = new ItemRequirement("Red topaz", ItemID.RED_TOPAZ, 2); + redTopaz2.setHighlightInInventory(true); + coins3000 = new ItemRequirement("Coins", ItemID.COINS, 3000); + coins3000.setTooltip("Alternatively for purchasing backup gems from Gnormadium Avlafrim"); + bluntAxe = new ItemRequirement("Blunt axe", ItemID.FAVOUR_JUNGLEFORESTERAXE_BLUNT); bluntAxe.setTooltip("You can get another from a Jungle Forester south of Shilo Village"); herbalTincture = new ItemRequirement("Herbal tincture", ItemID.FAVOUR_HERBAL_TINCTURE); @@ -360,9 +426,9 @@ protected void setupRequirements() harrTea = new ItemRequirement("Herb tea mix (harralander)", ItemID.FAVOUR_CUP_HARRALANDER); guamTea = new ItemRequirement("Herb tea mix (guam)", ItemID.FAVOUR_CUP_GUAM); - marrTea = new ItemRequirement("Herb tea mix (marrentill)", ItemID.FAVOUR_CUP_MARRENTILL); + marrTea = new ItemRequirement("Herb tea mix (marrentill)", ItemID.FAVOUR_CUP_MARRENTILL); harrMarrTea = new ItemRequirement("Herb tea mix (harr/marr)", ItemID.FAVOUR_CUP_HARRALANDER_MARRENTILL); - guamHarrTea = new ItemRequirement("Herb tea mix (harr/guam)", ItemID.FAVOUR_CUP_HARRALANDER_GUAM); + guamHarrTea = new ItemRequirement("Herb tea mix (harr/guam)", ItemID.FAVOUR_CUP_HARRALANDER_GUAM); guam2Tea = new ItemRequirement("Herb tea mix (2 guam)", ItemID.FAVOUR_CUP_GUAM_GUAM); guamMarrTea = new ItemRequirement("Herb tea mix (marr/guam)", ItemID.FAVOUR_CUP_GUAM_MARRENTILL); guamHarrMarrTea = new ItemRequirement("Herb tea mix (harr/marr/guam)", ItemID.FAVOUR_CUP_HARRALANDER_MARRENTILL_GUAM); @@ -377,12 +443,9 @@ protected void setupRequirements() sapphire = new ItemRequirement("Sapphire", ItemID.SAPPHIRE); sapphire.setHighlightInInventory(true); - opal = new ItemRequirement("Opal", ItemID.OPAL); - opal.setHighlightInInventory(true); - jade = new ItemRequirement("Jade", ItemID.JADE); - jade.setHighlightInInventory(true); - redTopaz = new ItemRequirement("Red topaz", ItemID.RED_TOPAZ); - redTopaz.setHighlightInInventory(true); + opal = opal2.quantity(1); + jade = jade2.quantity(1); + redTopaz = redTopaz2.quantity(1); uncutSapphire = new ItemRequirement("Uncut sapphire", ItemID.UNCUT_SAPPHIRE); uncutSapphire.setHighlightInInventory(true); @@ -440,29 +503,14 @@ protected void setupRequirements() breathingSalts.setTooltip("You can get more by bringing the Apothecary another airtight pot and 200 gp"); chickenCages5 = new ItemRequirement("Chicken cage", ItemID.FAVOUR_CHICKEN_CAGE, 5); - chickenCages5.setTooltip("You can get more chicken cages by bringing Horvik a pidgeon cage and 100 coins per cage"); + chickenCages5.setTooltip("You can get more chicken cages by bringing Horvik a pigeon cage and 100 coins per cage"); sharpenedAxe = new ItemRequirement("Sharpened axe", ItemID.FAVOUR_JUNGLEFORESTERAXE_SHARP); sharpenedAxe.setTooltip("You can get another from Brian in Port Sarim"); redMahog = new ItemRequirement("Red mahogany log", ItemID.FAVOUR_MAHOGANY_LOG); redMahog.setTooltip("You can get another from a jungle forester for 200 gp"); - } - - @Override - protected void setupZones() - { - sanfewRoom = new Zone(new WorldPoint(2893, 3423, 1), new WorldPoint(2903, 3433, 1)); - hamBase = new Zone(new WorldPoint(3140, 9600, 0), new WorldPoint(3190, 9655, 0)); - dwarvenMine = new Zone(new WorldPoint(2960, 9696, 0), new WorldPoint(3062, 9854, 0)); - goblinCave = new Zone(new WorldPoint(2560, 9792, 0), new WorldPoint(2623, 9855, 0)); - scrollSpot = new Zone(new WorldPoint(2616, 9835, 0), new WorldPoint(2619, 9835, 0)); - seersVillageUpstairs = new Zone(new WorldPoint(2698, 3468, 1), new WorldPoint(2717, 3476, 1)); - roof = new Zone(new WorldPoint(2695, 3469, 3), new WorldPoint(2716, 3476, 3)); - } - public void setupConditions() - { inSanfewRoom = new ZoneRequirement(sanfewRoom); inHamBase = new ZoneRequirement(hamBase); inDwarvenMine = new ZoneRequirement(dwarvenMine); @@ -477,8 +525,6 @@ public void setupConditions() lamp7Empty = new VarbitRequirement(VarbitID.OPALLIGHT2_TAKEN, 1); lamp8Empty = new VarbitRequirement(VarbitID.SAPPHIRELIGHT2_TAKEN, 1); - allEmpty = new VarbitRequirement(VarbitID.CHECKLANDINGLIGHTS, 255); - lamp1Full = new VarbitRequirement(VarbitID.JADELIGHT1_FIXED, 1); lamp2Full = new VarbitRequirement(VarbitID.TOPAZLIGHT1_FIXED, 1); lamp3Full = new VarbitRequirement(VarbitID.OPALLIGHT1_FIXED, 1); @@ -501,19 +547,23 @@ public void setupConditions() addedDirectionals = new VarbitRequirement(VarbitID.DIRECTIONALSFIXED, 1); addedWeathervanePillar = new VarbitRequirement(VarbitID.ROTATINGPILLARFIXED, 1); - hasOrUsedDirectionals = new Conditions(LogicType.OR, addedDirectionals, directionals.alsoCheckBank()); - hasOrUsedOrnament = new Conditions(LogicType.OR, addedOrnaments, ornament.alsoCheckBank()); - hasOrUsedWeathervanePillar = new Conditions(LogicType.OR, addedWeathervanePillar, weathervanePillar.alsoCheckBank()); + hasOrUsedDirectionals = or(addedDirectionals, directionals.alsoCheckBank()); + hasOrUsedOrnament = or(addedOrnaments, ornament.alsoCheckBank()); + hasOrUsedWeathervanePillar = or(addedWeathervanePillar, weathervanePillar.alsoCheckBank()); + + freeSlots3 = new FreeInventorySlotRequirement(3); } - public void setupSteps() + void setupSteps() { talkToYanni = new NpcStep(this, NpcID.SHILOANTIQUES, new WorldPoint(2836, 2983, 0), "Talk to Yanni Salika in Shilo Village. CKR fairy ring or take cart from Brimhaven."); + talkToYanni.addDialogStep("Is there anything else interesting to do around here?"); talkToYanni.addDialogStep("Yes."); - talkToYanni.addDialogSteps("Is there anything else interesting to do around here?", "Ok, see you in a tick!"); + talkToJungleForester = new NpcStep(this, new int[]{NpcID.JUNGLEFORESTER_F, NpcID.JUNGLEFORESTER_M}, new WorldPoint(2861, 2942, 0), "Talk to a Jungle Forester south of Shilo Village.", true); - talkToJungleForester.addDialogSteps("I'll get going then!", "I need to talk to you about red mahogany."); + talkToJungleForester.addDialogStep("I need to talk to you about red mahogany."); talkToJungleForester.addDialogStep("Okay, I'll take your axe to get it sharpened."); + talkToBrian = new NpcStep(this, NpcID.BRIAN, new WorldPoint(3027, 3249, 0), "Talk to Brian in the Port Sarim axe shop.", bluntAxe); talkToBrian.addDialogStep("Do you sharpen axes?"); talkToBrian.addDialogStepWithExclusion("Look, can you sharpen this cursed axe or what?", "Ok, ok, I'll do it! I'll go and see Aggie."); @@ -561,32 +611,24 @@ public void setupSteps() talkToSanfew.addDialogSteps("A dwarf I know wants to become an initiate.", "Yep, it's a deal."); talkToSanfew.addSubSteps(goUpToSanfew); - useBowlOnCup = new DetailedQuestStep(this, "Use a bowl of hot water on an empty cup.", - hotWaterBowl.highlighted(), emptyCup.highlighted()); - useHerbsOnCup = new DetailedQuestStep(this, - "Use 2 guams, a marrentill and a harralander on the cup.", - guam2.hideConditioned(new Conditions(LogicType.OR, guamTea, guam2Tea, guamMarrTea, guamHarrTea, - guamHarrMarrTea)).highlighted(), - guam.hideConditioned(new Conditions(LogicType.OR, cupOfWater, marrTea, harrTea, guam2Tea, guam2MarrTea, - guam2HarrTea)).highlighted(), - marrentill.hideConditioned(new Conditions(LogicType.OR, marrTea, harrMarrTea, guamMarrTea, guam2MarrTea, - guamHarrMarrTea)).highlighted(), - harralander.hideConditioned(new Conditions(LogicType.OR, harrTea, harrMarrTea, guamHarrTea, guam2HarrTea, - guamHarrMarrTea)).highlighted(), - cupOfWater.hideConditioned(new Conditions(LogicType.OR, guamTea, harrTea, marrTea, harrMarrTea, guamHarrTea, - guam2Tea, guam2MarrTea, guamMarrTea, guam2HarrTea, guamHarrMarrTea)).highlighted(), - herbTeaMix.hideConditioned(new Conditions(LogicType.NOR, guamTea, harrTea, marrTea, harrMarrTea, - guamHarrTea, guam2Tea, guam2MarrTea, guamMarrTea, guam2HarrTea, guamHarrMarrTea)).highlighted()); + useBowlOnCup = new DetailedQuestStep(this, "Use a bowl of hot water on an empty cup.", hotWaterBowl.highlighted(), emptyCup.highlighted()); + useHerbsOnCup = new DetailedQuestStep(this, "Use 2 guams, a marrentill and a harralander on the cup.", + guam2.hideConditioned(or(guamTea, guam2Tea, guamMarrTea, guamHarrTea, guamHarrMarrTea)).highlighted(), + guam.hideConditioned(or(cupOfWater, marrTea, harrTea, guam2Tea, guam2MarrTea, guam2HarrTea)).highlighted(), + marrentill.hideConditioned(or(marrTea, harrMarrTea, guamMarrTea, guam2MarrTea, guamHarrMarrTea)).highlighted(), + harralander.hideConditioned(or(harrTea, harrMarrTea, guamHarrTea, guam2HarrTea, guamHarrMarrTea)).highlighted(), + cupOfWater.hideConditioned(or(guamTea, harrTea, marrTea, harrMarrTea, guamHarrTea, guam2Tea, guam2MarrTea, guamMarrTea, guam2HarrTea, guamHarrMarrTea)).highlighted(), + herbTeaMix.hideConditioned(nor(guamTea, harrTea, marrTea, harrMarrTea, guamHarrTea, guam2Tea, guam2MarrTea, guamMarrTea, guam2HarrTea, guamHarrMarrTea)).highlighted()); makeGuthixRest = new DetailedQuestStep(this, "Make Guthix Rest by using a bowl of hot water on an empty tea cup, then using 2 guams, a marrentill and a harralander on it.", emptyCup, hotWaterBowl, guam2, marrentill, harralander); makeGuthixRest.addSubSteps(useBowlOnCup, useHerbsOnCup); talkToBleemadge = new NpcStep(this, NpcID.PILOT_WHITE_WOLF_BASE, new WorldPoint(2847, 3498, 0), "Right-click talk to Captain Bleemadge on White Wolf Mountain.", guthixRest); - ((NpcStep) talkToBleemadge).addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, + talkToBleemadge.addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, NpcID.PILOT_WHITE_WOLF_AL_KHARID, NpcID.PILOT_WHITE_WOLF_VARROCK, NpcID.PILOT_WHITE_WOLF_OGRE, NpcID.PILOT_WHITE_WOLF_APE); talkToBleemadge.addDialogStep("I have a special tea here for you from Sanfew!"); talkToBleemadgeNoTea = new NpcStep(this, NpcID.PILOT_WHITE_WOLF_BASE, new WorldPoint(2847, 3498, 0), "Right-click talk to Captain Bleemadge on White Wolf Mountain."); - ((NpcStep) talkToBleemadgeNoTea).addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, + talkToBleemadgeNoTea.addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, NpcID.PILOT_WHITE_WOLF_AL_KHARID, NpcID.PILOT_WHITE_WOLF_VARROCK, NpcID.PILOT_WHITE_WOLF_OGRE, NpcID.PILOT_WHITE_WOLF_APE); talkToBleemadgeNoTea.addDialogStep("How was that tea?"); @@ -607,7 +649,7 @@ public void setupSteps() searchWall = new ObjectStep(this, ObjectID.FAVOUR_LADY_IN_WALL, new WorldPoint(2621, 9835, 0), "Right-click search the sculpture in the wall in the north east corner of the cave."); talkToCromperty = new NpcStep(this, NpcID.CROMPERTY_PRE_DIARY, new WorldPoint(2684, 3323, 0), "Talk to Wizard Cromperty in north east Ardougne."); - ((NpcStep) talkToCromperty).addAlternateNpcs(NpcID.CROMPERTY_PRE_DIARY, NpcID.CROMPERTY_POST_DIARY); + talkToCromperty.addAlternateNpcs(NpcID.CROMPERTY_PRE_DIARY, NpcID.CROMPERTY_POST_DIARY); talkToCromperty.addDialogStep("Chat."); talkToCromperty.addDialogStep("I need to talk to you about a girl stuck in some rock!"); talkToCromperty.addDialogStep("Oh! Ok, one more 'small favour' isn't going to kill me...I hope!"); @@ -668,7 +710,7 @@ public void setupSteps() returnToTindel.addDialogStep("I have the mattress."); returnToCromperty = new NpcStep(this, NpcID.CROMPERTY_PRE_DIARY, new WorldPoint(2684, 3323, 0), "Return to Wizard Cromperty in north east Ardougne.", ironOxide); - ((NpcStep) returnToCromperty).addAlternateNpcs(NpcID.CROMPERTY_PRE_DIARY, NpcID.CROMPERTY_POST_DIARY); + returnToCromperty.addAlternateNpcs(NpcID.CROMPERTY_PRE_DIARY, NpcID.CROMPERTY_POST_DIARY); returnToCromperty.addDialogStep("Chat."); returnToCromperty.addDialogStep("I have that iron oxide you asked for!"); @@ -676,14 +718,14 @@ public void setupSteps() enterGoblinCaveAgain = new ObjectStep(this, ObjectID.MCANNONCAVE, new WorldPoint(2624, 3393, 0), "Enter the cave south east of the Fishing Guild. " + "Be prepared to fight the Slagilith(level 92, takes reduced damage from anything other than pickaxes).", Arrays.asList(pigeonCages5, animateRockScroll), Collections.singletonList(pickaxe)); - standNextToSculpture = new DetailedQuestStep(this, new WorldPoint(2616, 9835, 0), "Use the animate rock scroll next to the sculpture in the north east cavern.", animateRockScroll); + standNextToSculpture = new TileStep(this, new WorldPoint(2616, 9835, 0), "Use the animate rock scroll next to the sculpture in the north east cavern.", animateRockScroll); readScroll = new DetailedQuestStep(this, "Read the animate rock scroll.", animateRockScrollHighlight); standNextToSculpture.addSubSteps(readScroll); killSlagilith = new NpcStep(this, NpcID.SLAGILITH, new WorldPoint(2617, 9837, 0), "Kill the Slagilith. They take reduced damage from anything other than a pickaxe."); killSlagilith.addRecommended(pickaxe); - readScrollAgain = new DetailedQuestStep(this, "Read the animate rock scroll.", animateRockScrollHighlight); + readScrollAgain = new DetailedQuestStep(this, "Read the animate rock scroll again.", animateRockScrollHighlight); talkToPetra = new NpcStep(this, NpcID.FAVOUR_PETRA, new WorldPoint(2617, 9837, 0), "Talk to Petra Fiyed."); returnToPhantuwti = new NpcStep(this, NpcID.FAVOUR_PHANTUWTI_FARSIGHT, new WorldPoint(2702, 3473, 0), "Return to Phantuwti in the south west house of Seers' Village."); @@ -705,9 +747,11 @@ public void setupSteps() searchVane.addSubSteps(goUpLadder, goUpToRoof); useHammerOnVane = new ObjectStep(this, ObjectID.OSF_WEATHERVANE, new WorldPoint(2702, 3476, 3), "Use a hammer on the weathervane.", hammerHighlight); useHammerOnVane.addIcon(ItemID.HAMMER); - searchVaneAgain = new ObjectStep(this, ObjectID.OSF_WEATHERVANE, new WorldPoint(2702, 3476, 3), "Right-click search the weathervane on top of the Seers' building again."); + + searchVaneAgain = new ObjectStep(this, ObjectID.OSF_WEATHERVANE, new WorldPoint(2702, 3476, 3), "Right-click search the weathervane on top of the Seers' building again.", freeSlots3); goDownFromRoof = new ObjectStep(this, ObjectID.FAVOUR_ROOF_TRAPDOOR, new WorldPoint(2715, 3472, 3), "Climb down from the roof."); + goDownFromRoof.addDialogStep("Yes."); goDownLadderToSeers = new ObjectStep(this, ObjectID.KR_LADDERTOP, new WorldPoint(2715, 3470, 1), "Repair the vane parts on the anvil in north Seers' Village."); useVane123OnAnvil = new ObjectStep(this, ObjectID.ANVIL, new WorldPoint(2712, 3495, 0), "Repair the vane parts on an anvil. You can find one in the north of Seers' Village.", brokenVane1, brokenVane2, brokenVane3, hammer, steelBar, ironBar, bronzeBar); useVane12OnAnvil = new ObjectStep(this, ObjectID.ANVIL, new WorldPoint(2712, 3495, 0), "Repair the vane parts on an anvil. You can find one in the north of Seers' Village.", brokenVane1, brokenVane2, hammer, steelBar, bronzeBar); @@ -726,6 +770,7 @@ public void setupSteps() goBackUpLadder.addSubSteps(goBackUpToRoof, useVane1, useVane2, useVane3); goFromRoofToPhantuwti = new ObjectStep(this, ObjectID.FAVOUR_ROOF_TRAPDOOR, new WorldPoint(2715, 3472, 3), "Return to Phantuwti."); + goFromRoofToPhantuwti.addDialogStep("Yes."); goDownLadderToPhantuwti = new ObjectStep(this, ObjectID.KR_LADDERTOP_DIRECTIONAL, new WorldPoint(2699, 3476, 1), "Return to Phantuwti."); finishWithPhantuwti = new NpcStep(this, NpcID.FAVOUR_PHANTUWTI_FARSIGHT, new WorldPoint(2702, 3473, 0), "Return to Phantuwti in the south west house of Seers' Village."); finishWithPhantuwti.addSubSteps(goFromRoofToPhantuwti, goDownLadderToPhantuwti); @@ -737,28 +782,29 @@ public void setupSteps() returnToBleemadge = new NpcStep(this, NpcID.PILOT_WHITE_WOLF_BASE, new WorldPoint(2847, 3498, 0), "Right-click talk to Captain Bleemadge on White Wolf Mountain."); returnToBleemadge.addDialogStep("Hey there, did you get your T.R.A.S.H?"); - ((NpcStep) returnToBleemadge).addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, + returnToBleemadge.addAlternateNpcs(NpcID.PILOT_WHITE_WOLF_GRANDTREE, NpcID.PILOT_WHITE_WOLF_KARAMJA, NpcID.PILOT_WHITE_WOLF_AL_KHARID, NpcID.PILOT_WHITE_WOLF_VARROCK, NpcID.PILOT_WHITE_WOLF_OGRE, NpcID.PILOT_WHITE_WOLF_APE); returnUpToSanfew = new ObjectStep(this, ObjectID.SPIRALSTAIRS, new WorldPoint(2899, 3429, 0), "Return to Sanfew upstairs in the Taverley herblore store."); returnToSanfew = new NpcStep(this, NpcID.SANFEW, new WorldPoint(2899, 3429, 1), "Return to Sanfew upstairs in the Taverley herblore store."); returnToSanfew.addDialogStep("Hi there, the Gnome Pilot has agreed to take you to see the ogres!"); + returnToSanfew.addSubSteps(returnUpToSanfew); goDownToHammerspikeAgain = new ObjectStep(this, ObjectID.FAI_DWARF_TRAPDOOR_DOWN, new WorldPoint(3019, 3450, 0), "Return to the Dwarven Mine and talk to Hammerspike Stoutbeard in the west side."); returnToHammerspike = new NpcStep(this, NpcID.FAVOUR_HAMMERSPIKE_STOUTBEARD, new WorldPoint(2968, 9811, 0), "Return to Hammerspike Stoutbeard in the west cavern of the Dwarven Mine."); returnToHammerspike.addSubSteps(goDownToHammerspikeAgain); killGangMembers = new NpcStep(this, NpcID.FAVOUR_GANGSTER_DWARF, new WorldPoint(2968, 9811, 0), - "Kill 3 dwarf gang members until Hammerspike gives in. One dwarf gang member should appear after each kill.", true); - ((NpcStep) killGangMembers).addAlternateNpcs(NpcID.FAVOUR_GANGSTER_DWARF_2, NpcID.FAVOUR_GANGSTER_DWARF_3); - talkToHammerspikeFinal = new NpcStep(this, NpcID.FAVOUR_HAMMERSPIKE_STOUTBEARD, new WorldPoint(2968, 9811, 0), "Return to Hammerspike Stoutbeard in the west cavern of the Dwarven Mine."); + "Kill 3 dwarf gang members until Hammerspike gives in. One dwarf gang member should appear after each kill.", true); + killGangMembers.addAlternateNpcs(NpcID.FAVOUR_GANGSTER_DWARF_2, NpcID.FAVOUR_GANGSTER_DWARF_3); + talkToHammerspikeFinal = new NpcStep(this, NpcID.FAVOUR_HAMMERSPIKE_STOUTBEARD, new WorldPoint(2968, 9811, 0), "Return to Hammerspike Stoutbeard in the west cavern of the Dwarven Mine after killing his dwarf gang members."); returnToTassie = new NpcStep(this, NpcID.FAVOUR_TASSIE_SLIPCAST, new WorldPoint(3085, 3409, 0), "Return to Tassie Slipcast in the Barbarian Village pottery building."); spinPotLid = new ObjectStep(this, ObjectID.POTTERYWHEEL, new WorldPoint(3087, 3409, 0), "Spin the clay into a pot lid.", softClay); - spinPotLid.addWidgetHighlightWithItemIdRequirement(270, 19, ItemID.POTLID_UNFIRED, true); + spinPotLid.addWidgetHighlight(WidgetHighlight.createMultiskillByItemId(ItemID.POTLID_UNFIRED)); pickUpPot = new ItemStep(this, "Get a pot to put your lid on. There's one in the Barbarian Village helmet shop.", pot); firePotLid = new ObjectStep(this, ObjectID.FAI_BARBARIAN_POTTERY_OVEN, new WorldPoint(3085, 3407, 0), "Fire the unfired pot lid.", unfiredPotLid); - firePotLid.addWidgetHighlightWithItemIdRequirement(270, 19, ItemID.POTLID, true); + firePotLid.addWidgetHighlight(WidgetHighlight.createMultiskillByItemId(ItemID.POTLID_UNFIRED)); usePotLidOnPot = new DetailedQuestStep(this, "Use the pot lid on a pot.", pot, potLid); returnToApothecary = new NpcStep(this, NpcID.APOTHECARY, new WorldPoint(3196, 3404, 0), "Return to the Apothecary in west Varrock.", potWithLid); returnToApothecary.addDialogStep("Talk about One Small Favour."); @@ -784,62 +830,293 @@ public void setupSteps() } @Override - public List getItemRequirements() + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + Map steps = new HashMap<>(); + + steps.put(0, talkToYanni); + steps.put(5, talkToJungleForester); + + steps.put(10, talkToBrian); + steps.put(15, talkToBrian); + + steps.put(20, talkToAggie); + + var goTalkToJohanhus = new ConditionalStep(this, goDownToJohanhus); + goTalkToJohanhus.addStep(inHamBase, talkToJohanhus); + + steps.put(25, goTalkToJohanhus); + steps.put(30, goTalkToJohanhus); + steps.put(35, goTalkToJohanhus); + steps.put(40, goTalkToJohanhus); + + steps.put(45, talkToFred); + steps.put(50, talkToSeth); + steps.put(55, talkToHorvik); + steps.put(60, talkToApoth); + steps.put(62, talkToApoth); + steps.put(63, talkToApoth); + + steps.put(65, talkToTassie); + + var goTalkToHammerspike = new ConditionalStep(this, goDownToHammerspike); + goTalkToHammerspike.addStep(inDwarvenMine, talkToHammerspike); + steps.put(70, goTalkToHammerspike); + + var goTalkToSanfew = new ConditionalStep(this, goUpToSanfew); + goTalkToSanfew.addStep(inSanfewRoom, talkToSanfew); + + steps.put(75, goTalkToSanfew); + + var makeGuthixRestForGnome = new ConditionalStep(this, useBowlOnCup); + makeGuthixRestForGnome.addStep(guthixRest, talkToBleemadge); + makeGuthixRestForGnome.addStep(or(herbTeaMix, cupOfWater), useHerbsOnCup); + + steps.put(80, makeGuthixRestForGnome); + steps.put(81, makeGuthixRestForGnome); + steps.put(82, makeGuthixRestForGnome); + steps.put(83, makeGuthixRestForGnome); + steps.put(84, makeGuthixRestForGnome); + + steps.put(86, talkToBleemadgeNoTea); + + steps.put(88, talkToArhein); + + steps.put(90, talkToPhantuwti); + + var investigateWall = new ConditionalStep(this, enterGoblinCave); + investigateWall.addStep(inGoblinCave, searchWall); + + steps.put(95, investigateWall); + + steps.put(100, talkToCromperty); + + steps.put(105, talkToTindel); + + steps.put(110, talkToRantz); + + steps.put(115, talkToGnormadium); + + var repairLights = new ConditionalStep(this, take1); + repairLights.addStep(allFull, talkToGnormadiumAgain); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full, lamp8Empty, sapphire), put8); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full, lamp8Empty), cutSaph); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Full), take8); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Empty, opal), put7); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full, lamp7Empty), cutOpal); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Full), take7); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Empty, redTopaz), put6); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full, lamp6Empty), cutTopaz); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Full), take6); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Empty, jade), put5); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full, lamp5Empty), cutJade); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Full), take5); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Empty, sapphire), put4); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full, lamp4Empty), cutSaph); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Full), take4); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Empty, opal), put3); + repairLights.addStep(and(lamp1Full, lamp2Full, lamp3Empty), cutOpal); + repairLights.addStep(and(lamp1Full, lamp2Full), take3); + repairLights.addStep(and(lamp1Full, lamp2Empty, redTopaz), put2); + repairLights.addStep(and(lamp1Full, lamp2Empty), cutTopaz); + repairLights.addStep(lamp1Full, take2); + repairLights.addStep(and(lamp1Empty, jade), put1); + repairLights.addStep(lamp1Empty, cutJade); + + steps.put(120, repairLights); + + steps.put(125, talkToGnormadiumAgain); + + steps.put(130, returnToRantz); + + steps.put(135, returnToTindel); + + steps.put(140, returnToCromperty); + + var fightSlagilith = new ConditionalStep(this, getPigeonCages); + fightSlagilith.addStep(slagilithNearby, killSlagilith); + fightSlagilith.addStep(inScrollSpot, readScroll); + fightSlagilith.addStep(inGoblinCave, standNextToSculpture); + fightSlagilith.addStep(pigeonCages5.alsoCheckBank(), enterGoblinCaveAgain); + + steps.put(145, fightSlagilith); + steps.put(150, fightSlagilith); + + var freePetra = new ConditionalStep(this, getPigeonCages); + freePetra.addStep(petraNearby, talkToPetra); + freePetra.addStep(inScrollSpot, readScrollAgain); + freePetra.addStep(inGoblinCave, standNextToSculpture); + freePetra.addStep(pigeonCages5.alsoCheckBank(), enterGoblinCaveAgain); + + steps.put(152, freePetra); + steps.put(155, freePetra); + + steps.put(160, returnToPhantuwti); + steps.put(165, returnToPhantuwti2); + steps.put(170, returnToPhantuwti2); + + var repairVane = new ConditionalStep(this, goUpLadder); + repairVane.addStep(onRoof, searchVane); + repairVane.addStep(inSeersVillageUpstairs, goUpToRoof); + + steps.put(175, repairVane); + + var hitVane = new ConditionalStep(this, goUpLadder); + hitVane.addStep(onRoof, useHammerOnVane); + hitVane.addStep(inSeersVillageUpstairs, goUpToRoof); + + steps.put(176, hitVane); + + var getVaneBits = new ConditionalStep(this, goUpLadder); + getVaneBits.addStep(onRoof, searchVaneAgain); + getVaneBits.addStep(inSeersVillageUpstairs, goUpToRoof); + + steps.put(177, getVaneBits); + + var repairVaneParts = new ConditionalStep(this, useVane123OnAnvil); + + repairVaneParts.addStep(and(addedOrnaments, addedDirectionals, weathervanePillar, onRoof), useVane3); + repairVaneParts.addStep(and(addedOrnaments, directionals, onRoof), useVane2); + repairVaneParts.addStep(and(ornament, onRoof), useVane1); + repairVaneParts.addStep(onRoof, goDownFromRoof); + repairVaneParts.addStep(and(hasOrUsedDirectionals, hasOrUsedOrnament, hasOrUsedWeathervanePillar, inSeersVillageUpstairs), goBackUpToRoof); + repairVaneParts.addStep(inSeersVillageUpstairs, goDownLadderToSeers); + repairVaneParts.addStep(and(hasOrUsedDirectionals, hasOrUsedOrnament, hasOrUsedWeathervanePillar), goBackUpLadder); + repairVaneParts.addStep(and(hasOrUsedDirectionals, hasOrUsedOrnament), useVane3OnAnvil); + repairVaneParts.addStep(and(hasOrUsedOrnament, hasOrUsedWeathervanePillar), useVane1OnAnvil); + repairVaneParts.addStep(and(hasOrUsedDirectionals, hasOrUsedWeathervanePillar), useVane2OnAnvil); + repairVaneParts.addStep(hasOrUsedOrnament, useVane13OnAnvil); + repairVaneParts.addStep(hasOrUsedWeathervanePillar, useVane12OnAnvil); + repairVaneParts.addStep(hasOrUsedDirectionals, useVane23OnAnvil); + + steps.put(180, repairVaneParts); + + var reportBackToPhantuwti = new ConditionalStep(this, finishWithPhantuwti); + reportBackToPhantuwti.addStep(inSeersVillageUpstairs, goDownLadderToPhantuwti); + reportBackToPhantuwti.addStep(onRoof, goFromRoofToPhantuwti); + + steps.put(185, reportBackToPhantuwti); + + steps.put(190, returnToArhein); + + steps.put(195, returnToBleemadge); + + var goAndReturnToSanfew = new ConditionalStep(this, returnUpToSanfew); + goAndReturnToSanfew.addStep(inSanfewRoom, returnToSanfew); + steps.put(200, goAndReturnToSanfew); + + var dealWithHammerspike = new ConditionalStep(this, goDownToHammerspikeAgain); + dealWithHammerspike.addStep(inDwarvenMine, returnToHammerspike); + + steps.put(205, dealWithHammerspike); + + var sortOutGangMembers = new ConditionalStep(this, goDownToHammerspikeAgain); + sortOutGangMembers.addStep(inDwarvenMine, killGangMembers); + + steps.put(210, sortOutGangMembers); + steps.put(215, sortOutGangMembers); + steps.put(220, sortOutGangMembers); + + var dealWithHammerspikeAfterKillingHisGang = new ConditionalStep(this, goDownToHammerspikeAgain); + dealWithHammerspikeAfterKillingHisGang.addStep(inDwarvenMine, talkToHammerspikeFinal); + steps.put(225, dealWithHammerspikeAfterKillingHisGang); + + steps.put(230, returnToTassie); + + var makePotAndReturnToApoth = new ConditionalStep(this, spinPotLid); + makePotAndReturnToApoth.addStep(potWithLid, returnToApothecary); + makePotAndReturnToApoth.addStep(and(potLid, pot), usePotLidOnPot); + makePotAndReturnToApoth.addStep(potLid, pickUpPot); + makePotAndReturnToApoth.addStep(unfiredPotLid, firePotLid); + + steps.put(235, makePotAndReturnToApoth); + + steps.put(240, returnToHorvik); + + steps.put(245, talkToHorvikFinal); + + steps.put(250, returnToSeth); + + var goFinishWithJohanhus = new ConditionalStep(this, returnDownToJohnahus); + goFinishWithJohanhus.addStep(inHamBase, returnToJohnahus); + + steps.put(255, goFinishWithJohanhus); + + steps.put(260, returnToAggie); + + steps.put(265, returnToBrian); + + steps.put(270, returnToForester); + + steps.put(275, returnToYanni); + + return steps; + } + + @Override + public List getGeneralRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(steelBars4); - reqs.add(bronzeBar); - reqs.add(ironBar); - reqs.add(chisel); - reqs.add(guam2); - reqs.add(marrentill); - reqs.add(harralander); - reqs.add(hammer); - reqs.add(emptyCup); - reqs.add(pot); - reqs.add(hotWaterBowl); - - return reqs; + return List.of( + new QuestRequirement(QuestHelperQuest.RUNE_MYSTERIES, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.SHILO_VILLAGE, QuestState.FINISHED), + new SkillRequirement(Skill.AGILITY, 36, true), + new SkillRequirement(Skill.CRAFTING, 25, true), + new SkillRequirement(Skill.HERBLORE, 18, true), + new SkillRequirement(Skill.SMITHING, 30, true) + ); } + @Override - public List getItemRecommended() + public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(draynorVillageTeleports); - reqs.add(lumbridgeTeleports); - reqs.add(varrockTeleports); - reqs.add(taverleyOrFaladorTeleports); - reqs.add(camelotTeleports); - reqs.add(fishingGuildAndDwarvenMineTeleports); - reqs.add(ardougneTeleports); - reqs.add(khazardTeleports); - reqs.add(feldipHillsTeleports); - reqs.add(opal.quantity(2)); - reqs.add(jade.quantity(2)); - reqs.add(redTopaz.quantity(2)); - reqs.add(pickaxe); - return reqs; + return List.of( + steelBars4, + bronzeBar, + ironBar, + chisel, + guam2, + marrentill, + harralander, + hammer, + emptyCup, + pot, + hotWaterBowl + ); } @Override - public List getCombatRequirements() + public List getItemRecommended() { - return Arrays.asList("Slagilith (level 92)", "3x Dwarf gang members (level 44)"); + return List.of( + draynorVillageTeleports, + lumbridgeTeleports, + varrockTeleports, + taverleyOrFaladorTeleports, + camelotTeleports, + fishingGuildAndDwarvenMineTeleports, + ardougneTeleports, + khazardTeleports, + feldipHillsTeleports, + opal2, + jade2, + redTopaz2, + coins3000, + pickaxe + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.RUNE_MYSTERIES, QuestState.FINISHED)); - req.add(new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED)); - req.add(new QuestRequirement(QuestHelperQuest.SHILO_VILLAGE, QuestState.FINISHED)); - req.add(new SkillRequirement(Skill.AGILITY, 36, true)); - req.add(new SkillRequirement(Skill.CRAFTING, 25, true)); - req.add(new SkillRequirement(Skill.HERBLORE, 18, true)); - req.add(new SkillRequirement(Skill.SMITHING, 30, true)); - return req; + return List.of( + "Slagilith (level 92)", + "3x Dwarf gang members (level 44)" + ); } @Override @@ -851,36 +1128,117 @@ public QuestPointReward getQuestPointReward() @Override public List getItemRewards() { - return Arrays.asList( - new ItemReward("10,000 Experience Lamps (Any skill over level 30)", ItemID.THOSF_REWARD_LAMP, 2), //4447 is placeholder for filter - new ItemReward("A Steel Keyring", ItemID.FAVOUR_KEY_RING, 1)); + return List.of( + new ItemReward("10,000 Experience Lamps (Any skill over level 30)", ItemID.THOSF_REWARD_LAMP, 2), + new ItemReward("A Steel Keyring", ItemID.FAVOUR_KEY_RING, 1) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("The ability to make Guthix Rest tea."), - new UnlockReward("Gnome Glider in Feldip Hills.")); + return List.of( + new UnlockReward("The ability to make Guthix Rest tea."), + new UnlockReward("Gnome Glider in Feldip Hills.") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Collections.singletonList(talkToYanni))); - allSteps.add(new PanelDetails("A few small favours", Arrays.asList(talkToJungleForester, talkToBrian, talkToAggie, talkToJohanhus, talkToFred, talkToSeth, - talkToHorvik, talkToApoth, talkToTassie, talkToHammerspike, talkToSanfew, makeGuthixRest, talkToBleemadge, talkToArhein, talkToPhantuwti, enterGoblinCave, - searchWall, talkToCromperty, talkToTindel, talkToRantz, talkToGnormadium, fixAllLamps), - chisel, steelBars3, emptyCup, hotWaterBowl, guam2, marrentill, harralander)); - allSteps.add(new PanelDetails("Completing the favours", Arrays.asList(talkToGnormadiumAgain, returnToRantz, - returnToTindel, returnToCromperty, getPigeonCages, enterGoblinCaveAgain, standNextToSculpture, killSlagilith, - readScrollAgain, talkToPetra, returnToPhantuwti, searchVane, useHammerOnVane, searchVaneAgain, - useVane123OnAnvil, goBackUpLadder, finishWithPhantuwti, returnToArhein, returnToBleemadge, returnToSanfew, - returnToHammerspike, killGangMembers, talkToHammerspikeFinal, returnToTassie, spinPotLid, firePotLid, pickUpPot, - usePotLidOnPot, returnToApothecary, returnToHorvik, talkToHorvikFinal, returnToSeth, returnToJohnahus, returnToAggie, - returnToBrian, returnToForester, returnToYanni), bronzeBar, ironBar, steelBar, hammer, pot)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToYanni + ))); + + sections.add(new PanelDetails("A few small favours", List.of( + talkToJungleForester, + talkToBrian, + talkToAggie, + talkToJohanhus, + talkToFred, + talkToSeth, + talkToHorvik, + talkToApoth, + talkToTassie, + talkToHammerspike, + talkToSanfew, + makeGuthixRest, + talkToBleemadge, + talkToArhein, + talkToPhantuwti, + enterGoblinCave, + searchWall, + talkToCromperty, + talkToTindel, + talkToRantz, + talkToGnormadium, + fixAllLamps + ), List.of( + chisel, + steelBars3, + emptyCup, + hotWaterBowl, + guam2, + marrentill, + harralander + ), List.of( + opal2, + jade2, + redTopaz2, + coins3000 + ))); + + sections.add(new PanelDetails("Completing the favours", List.of( + talkToGnormadiumAgain, + returnToRantz, + returnToTindel, + returnToCromperty, + getPigeonCages, + enterGoblinCaveAgain, + standNextToSculpture, + killSlagilith, + readScrollAgain, + talkToPetra, + returnToPhantuwti, + searchVane, + useHammerOnVane, + searchVaneAgain, + useVane123OnAnvil, + goBackUpLadder, + finishWithPhantuwti, + returnToArhein, + returnToBleemadge, + returnToSanfew, + returnToHammerspike, + killGangMembers, + talkToHammerspikeFinal, + returnToTassie, + spinPotLid, + firePotLid, + pickUpPot, + usePotLidOnPot, + returnToApothecary, + returnToHorvik, + talkToHorvikFinal, + returnToSeth, + returnToJohnahus, + returnToAggie, + returnToBrian, + returnToForester, + returnToYanni + ), List.of( + bronzeBar, + ironBar, + steelBar, + hammer, + pot + ), List.of( + combatGear, + pickaxe + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pandemonium/Pandemonium.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pandemonium/Pandemonium.java index 1d1cfc0ac4..8360d6e890 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pandemonium/Pandemonium.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pandemonium/Pandemonium.java @@ -27,11 +27,14 @@ import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.NoItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.ShipInPortRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.ItemSlots; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Port; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; @@ -41,143 +44,106 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.BoardShipStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.SailStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - -import java.util.*; -import java.util.regex.Pattern; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; public class Pandemonium extends BasicQuestHelper { - NpcStep getToPandemonium, talkToWill, boardWAShip, explainJob, explainJob2, learnWhereYouAre, learnWhoWAare, talkToRibs, findLocationWA, enterShipyard, informAboutShip, showCup, getLogBook, getNewJob, talkToJim, meetGrog, finishQuest; - ObjectStep buildCargoHold, embarkShipSY, disembarkShipSY, leaveShipyard,dropCargoInCargoHold, disembarkShipPS, deliverCargo, disembarkShipP, getHammer, getSaw; - Zone pandemonium, portSarim, pandemoniumDockZone, portSarimDockZone, shipWreckZone; - DetailedQuestStep navigateShip, watchSalvageCutscene, takeHelm, takeHelm2, takeHelm3, raiseSails, raiseSails2, raiseSails3, salvageShipwreck, sailToPortSarim, pickupCargo, pickupCargoShip, sailToPandemonium, letGoOfHelm, letGoOfHelm2; - BoardShipStep boardShip, boardShip2, boardShip3; - Requirement onPandemonium, boatAtPortSarim, onboardShip, takenHelm, setSails, sailing, atShipwreck, notAtShipwreck, canSalvage, hammerAndSaw, atShipyard, atPortSarimDock, atPandemoniumDock, holdingCargo, cargoPickedUp, cargoNotPickedUp, cargoInCargoHold; - ItemRequirement hammer, saw, cup; + // Required items + ItemRequirement hammer; + ItemRequirement saw; + + // Mid-quest item requirements + ItemRequirement cup; + + // Zones + Zone pandemonium; + Zone portSarim; + Zone pandemoniumDockZone; + Zone portSarimDockZone; + Zone shipWreckZone; + + // Miscellaneous requirements + ZoneRequirement onPandemonium; + ShipInPortRequirement boatAtPortSarim; + VarbitRequirement onboardShip; + VarbitRequirement takenHelm; + VarbitRequirement setSails; + Conditions sailing; + VarbitRequirement atShipwreck; + Conditions canSalvage; + VarbitRequirement atShipyard; + VarbitRequirement holdingCargo; + VarbitRequirement cargoPickedUp; + Conditions cargoNotPickedUp; + ZoneRequirement atPortSarimDock; + ZoneRequirement atPandemoniumDock; + Conditions cargoInCargoHold; NoItemRequirement nothingInHands; - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - steps.put(0, talkToWill); - steps.put(2, talkToWill); - - steps.put(4, boardWAShip); - - ConditionalStep goListenOnShip = new ConditionalStep(this, talkToWill); - goListenOnShip.addStep(onboardShip, explainJob); - steps.put(6, goListenOnShip); - - ConditionalStep cNavigateToShipwreckOnShip = new ConditionalStep(this, takeHelm); - cNavigateToShipwreckOnShip.addStep(canSalvage, salvageShipwreck); - cNavigateToShipwreckOnShip.addStep(atShipwreck, explainJob2); - cNavigateToShipwreckOnShip.addStep(sailing, navigateShip); - cNavigateToShipwreckOnShip.addStep(takenHelm, raiseSails); - cNavigateToShipwreckOnShip.addStep(notAtShipwreck, takeHelm); - - ConditionalStep cNavigateToShipwreck = new ConditionalStep(this, boardWAShip); - cNavigateToShipwreck.addStep(and(new VarbitRequirement(VarbitID.CUTSCENE_STATUS, 1), canSalvage), watchSalvageCutscene); - cNavigateToShipwreck.addStep(onboardShip, cNavigateToShipwreckOnShip); - steps.put(8, cNavigateToShipwreck); - steps.put(10, cNavigateToShipwreck); - steps.put(12, cNavigateToShipwreck); - steps.put(14, cNavigateToShipwreck); - - ConditionalStep cLearnWhereYouAre = new ConditionalStep(this, getToPandemonium); - cLearnWhereYouAre.addStep(onPandemonium, learnWhereYouAre); - steps.put(16, cLearnWhereYouAre); - ConditionalStep cLearnWhoWAare = new ConditionalStep(this, getToPandemonium); - cLearnWhoWAare.addStep(onPandemonium, learnWhoWAare); - steps.put(18, cLearnWhoWAare); - ConditionalStep cTalkToRibs = new ConditionalStep(this, getToPandemonium); - cTalkToRibs.addStep(onPandemonium, talkToRibs); - steps.put(20, cTalkToRibs); - ConditionalStep cFindLocationWA = new ConditionalStep(this, getToPandemonium); - cFindLocationWA.addStep(onPandemonium, findLocationWA); - steps.put(22, cFindLocationWA); - ConditionalStep cInformAboutShip = new ConditionalStep(this, getToPandemonium); - cInformAboutShip.addStep(onPandemonium, informAboutShip); - steps.put(24, cInformAboutShip); - ConditionalStep cShowCup = new ConditionalStep(this, getToPandemonium); - cShowCup.addStep(onPandemonium, showCup); - steps.put(26, cShowCup); - - ConditionalStep cBuildCargoHold = new ConditionalStep(this, getToPandemonium); - cBuildCargoHold.addStep(and(atShipyard, onboardShip), buildCargoHold); - cBuildCargoHold.addStep(and(atShipyard, hammerAndSaw), embarkShipSY); - cBuildCargoHold.addStep(and(atShipyard, saw), getHammer); - cBuildCargoHold.addStep(atShipyard, getSaw); - cBuildCargoHold.addStep(onPandemonium, enterShipyard); - steps.put(28, cBuildCargoHold); - - - ConditionalStep cGetLogBook = new ConditionalStep(this, getToPandemonium); - cGetLogBook.addStep(onPandemonium, getLogBook); - cGetLogBook.addStep(atShipyard, leaveShipyard); - steps.put(30, cGetLogBook); // Jim - - steps.put(32, getNewJob); // Jim - steps.put(34, boardShip); - ConditionalStep cSailToPortSarim = new ConditionalStep(this, boardShip); - cSailToPortSarim.addStep(and(not(atPortSarimDock), sailing), sailToPortSarim); - cSailToPortSarim.addStep(and(not(atPortSarimDock), takenHelm), raiseSails2); - cSailToPortSarim.addStep(and(not(atPortSarimDock), onboardShip), takeHelm2); - steps.put(36, cSailToPortSarim); - ConditionalStep cCheckPortMaster = new ConditionalStep(this, cSailToPortSarim); - cCheckPortMaster.addStep(and(boatAtPortSarim, holdingCargo, not(onboardShip)), boardShip2); - cCheckPortMaster.addStep(and(boatAtPortSarim, cargoNotPickedUp, not(onboardShip)), pickupCargo); - cCheckPortMaster.addStep(and(atPortSarimDock, cargoNotPickedUp, takenHelm), letGoOfHelm); - cCheckPortMaster.addStep(and(atPortSarimDock, cargoNotPickedUp, onboardShip), disembarkShipPS); - steps.put(38, cCheckPortMaster); - ConditionalStep cSailToPandemonium = new ConditionalStep(this, cCheckPortMaster); - cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip, takenHelm, sailing), sailToPandemonium); - cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip, takenHelm), raiseSails3); - cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip), takeHelm3); - cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoPickedUp, holdingCargo, onboardShip), dropCargoInCargoHold); - - ConditionalStep cDeliverCargo = new ConditionalStep(this, cSailToPandemonium); - cDeliverCargo.addStep(and(onPandemonium, not(onboardShip), holdingCargo), deliverCargo); - cDeliverCargo.addStep(and(atPandemoniumDock, onboardShip, holdingCargo), disembarkShipP); - cDeliverCargo.addStep(and(atPandemoniumDock, onboardShip, nor(takenHelm, setSails), cargoInCargoHold), pickupCargoShip); - cDeliverCargo.addStep(and(onPandemonium, not(onboardShip), cargoInCargoHold), boardShip3); - cDeliverCargo.addStep(and(atPandemoniumDock, cargoInCargoHold, takenHelm), letGoOfHelm2); - steps.put(40, cDeliverCargo); - steps.put(42, cDeliverCargo); - steps.put(44, talkToJim); - steps.put(46, meetGrog); - steps.put(48, finishQuest); - - return steps; - } - - public void setupConditions() - { - onboardShip = new VarbitRequirement(VarbitID.SAILING_BOARDED_BOAT, 1); - takenHelm = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_HELM_STATUS, 2); - setSails = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_BOAT_MOVE_MODE, 0, Operation.GREATER); - canSalvage = and(atShipwreck, new VarbitRequirement(VarbitID.SAILING_INTRO, 14, Operation.GREATER_EQUAL)); // At wreck, with explanation about salvaging - sailing = and(takenHelm, setSails, onboardShip); - - atShipyard = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_SHIPYARD_MODE, 1); - holdingCargo = new VarbitRequirement(VarbitID.SAILING_CARRYING_CARGO, 1); - - cargoPickedUp = new VarbitRequirement(VarbitID.PORT_TASK_SLOT_0_CARGO_TAKEN, 1); - cargoNotPickedUp = not(cargoPickedUp); - cargoInCargoHold = and(cargoPickedUp, not(holdingCargo)); - - nothingInHands = new NoItemRequirement("Nothing equipped in your hands.",ItemSlots.WEAPON, ItemSlots.SHIELD); - } + // Steps + NpcStep getToPandemonium; + NpcStep talkToWill; + NpcStep boardWAShip; + NpcStep explainJob; + NpcStep explainJob2; + NpcStep learnWhereYouAre; + NpcStep learnWhoWAare; + NpcStep talkToRibs; + NpcStep findLocationWA; + NpcStep enterShipyard; + NpcStep informAboutShip; + NpcStep showCup; + NpcStep getLogBook; + NpcStep getNewJob; + NpcStep talkToJim; + NpcStep meetGrog; + NpcStep finishQuest; + ObjectStep buildCargoHold; + ObjectStep embarkShipSY; + ObjectStep disembarkShipSY; + ObjectStep leaveShipyard; + ObjectStep dropCargoInCargoHold; + ObjectStep disembarkShipPS; + ObjectStep deliverCargo; + ObjectStep disembarkShipP; + ObjectStep getHammer; + ObjectStep getSaw; + DetailedQuestStep navigateShip; + DetailedQuestStep watchSalvageCutscene; + DetailedQuestStep takeHelm; + DetailedQuestStep takeHelm2; + DetailedQuestStep takeHelm3; + DetailedQuestStep raiseSails; + DetailedQuestStep raiseSails2; + DetailedQuestStep raiseSails3; + DetailedQuestStep salvageShipwreck; + DetailedQuestStep sailToPortSarim; + DetailedQuestStep pickupCargo; + DetailedQuestStep pickupCargoShip; + DetailedQuestStep sailToPandemonium; + DetailedQuestStep letGoOfHelm; + DetailedQuestStep letGoOfHelm2; + BoardShipStep boardShip; + BoardShipStep boardShip2; + BoardShipStep boardShip3; @Override protected void setupZones() @@ -187,12 +153,6 @@ protected void setupZones() portSarim = new Zone(new WorldPoint(3027, 3192, 0), new WorldPoint(3050, 3204, 0)); pandemoniumDockZone = new Zone(new WorldPoint(3065, 2974, 0), new WorldPoint(3084, 2998, 0)); portSarimDockZone = new Zone(new WorldPoint(3045, 3183, 0), new WorldPoint(3061, 3208, 0)); - atShipwreck = new VarbitRequirement(VarbitID.SAILING_INTRO_REACHED_WRECK, 1); - notAtShipwreck = not(atShipwreck); - onPandemonium = new ZoneRequirement(pandemonium); - boatAtPortSarim = new ShipInPortRequirement(Port.PORT_SARIM); - atPandemoniumDock = new ZoneRequirement(pandemoniumDockZone); - atPortSarimDock = new ZoneRequirement(portSarimDockZone); } @Override @@ -202,11 +162,32 @@ protected void setupRequirements() hammer.setTooltip("You can pick this up at the shipyard."); saw = new ItemRequirement("Saw", ItemCollections.SAW).isNotConsumed().canBeObtainedDuringQuest(); saw.setTooltip("You can pick this up at the shipyard."); - hammerAndSaw = and(hammer, saw); // Quest items cup = new ItemRequirement("Old cup", ItemID.SAILING_INTRO_CUP); cup.setTooltip("You can get another from Steve Beanie behind the bar on Pandemonium"); + + atShipwreck = new VarbitRequirement(VarbitID.SAILING_INTRO_REACHED_WRECK, 1); + onPandemonium = new ZoneRequirement(pandemonium); + boatAtPortSarim = new ShipInPortRequirement(Port.PORT_SARIM); + atPandemoniumDock = new ZoneRequirement(pandemoniumDockZone); + atPortSarimDock = new ZoneRequirement(portSarimDockZone); + + // Miscellaneous requirements + onboardShip = new VarbitRequirement(VarbitID.SAILING_BOARDED_BOAT, 1); + takenHelm = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_HELM_STATUS, 2); + setSails = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_BOAT_MOVE_MODE, 0, Operation.GREATER); + canSalvage = and(atShipwreck, new VarbitRequirement(VarbitID.SAILING_INTRO, 14, Operation.GREATER_EQUAL)); // At wreck, with explanation about salvaging + sailing = and(takenHelm, setSails, onboardShip); + + atShipyard = new VarbitRequirement(VarbitID.SAILING_SIDEPANEL_SHIPYARD_MODE, 1); + holdingCargo = new VarbitRequirement(VarbitID.SAILING_CARRYING_CARGO, 1); + + cargoPickedUp = new VarbitRequirement(VarbitID.PORT_TASK_SLOT_0_CARGO_TAKEN, 1); + cargoNotPickedUp = not(cargoPickedUp); + cargoInCargoHold = and(cargoPickedUp, not(holdingCargo)); + + nothingInHands = new NoItemRequirement("Nothing equipped in your hands.", ItemSlots.EMPTY_HANDS); } public void setupSteps() @@ -248,7 +229,7 @@ public void setupSteps() // Your mighty vessel enterShipyard = new NpcStep(this, NpcID.JUNIOR_JIM, new WorldPoint(3059, 2979, 0), "Talk to Junior Jim to enter the shipyard."); getHammer = new ObjectStep(this, ObjectID.CRATE_HAMMERS, "Pick up a hammer from the crate of hammers."); - getSaw = new ObjectStep(this, ObjectID.CRATE_SAWS, "Pick up a from the crate of saws."); + getSaw = new ObjectStep(this, ObjectID.CRATE_SAWS, "Pick up a saw from the crate of saws."); embarkShipSY = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_PROXY_WIDE, "Board your vessel."); buildCargoHold = new ObjectStep(this, ObjectID.SAILING_BOAT_FACILITY_PLACEHOLDER_RAFT_0, "Build the Cargo Hold."); disembarkShipSY = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_SHIPYARD_DISEMBARK, "Disembark your vessel."); @@ -264,7 +245,7 @@ public void setupSteps() sailToPortSarim = new SailStep(this, Port.PORT_SARIM); letGoOfHelm = new ObjectStep(this, ObjectID.SAILING_BOAT_STEERING_KANDARIN_1X3_WOOD_IN_USE, new WorldPoint(3843, 6460, 1), "Let go of the helm."); disembarkShipPS = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_DISEMBARK, new WorldPoint(3051, 3193, 0), "Leave your ship."); - + pickupCargo = new ObjectStep(this, ObjectID.DOCK_LOADING_BAY_LEDGER_TABLE_WITHDRAW, new WorldPoint(3028, 3194, 0), "Pick up the cargo from the ledger table on the docks.", nothingInHands); boardShip2 = new BoardShipStep(this); dropCargoInCargoHold = new ObjectStep(this, ObjectID.SAILING_BOAT_CARGO_HOLD_REGULAR_RAFT, "Deposit the crate into your cargo hold."); @@ -274,7 +255,11 @@ public void setupSteps() sailToPandemonium = new SailStep(this, Port.PANDEMONIUM); letGoOfHelm2 = new ObjectStep(this, ObjectID.SAILING_BOAT_STEERING_KANDARIN_1X3_WOOD_IN_USE, new WorldPoint(3843, 6460, 1), "Let go of the helm."); pickupCargoShip = new ObjectStep(this, ObjectID.SAILING_BOAT_CARGO_HOLD_REGULAR_RAFT, "Pick up the cargo from your ship's cargo hold.", nothingInHands); + + // In case the user boards the Pandemonium without picking up the cargo from their ship boardShip3 = new BoardShipStep(this); + pickupCargoShip.addSubSteps(boardShip3); + disembarkShipP = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_DISEMBARK, new WorldPoint(3070, 2987, 0), "Leave your ship."); deliverCargo = new ObjectStep(this, ObjectID.DOCK_LOADING_BAY_LEDGER_TABLE_DEPOSIT, new WorldPoint(3061, 2985, 0), "Deliver the cargo at the ledger table on the docks."); //Finish up @@ -284,15 +269,119 @@ public void setupSteps() } @Override - public QuestPointReward getQuestPointReward() + public Map loadSteps() { - return new QuestPointReward(1); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToWill); + steps.put(2, talkToWill); + + steps.put(4, boardWAShip); + + var goListenOnShip = new ConditionalStep(this, talkToWill); + goListenOnShip.addStep(onboardShip, explainJob); + steps.put(6, goListenOnShip); + + var cNavigateToShipwreckOnShip = new ConditionalStep(this, takeHelm); + cNavigateToShipwreckOnShip.addStep(canSalvage, salvageShipwreck); + cNavigateToShipwreckOnShip.addStep(atShipwreck, explainJob2); + cNavigateToShipwreckOnShip.addStep(sailing, navigateShip); + cNavigateToShipwreckOnShip.addStep(takenHelm, raiseSails); + cNavigateToShipwreckOnShip.addStep(not(atShipwreck), takeHelm); + + var cNavigateToShipwreck = new ConditionalStep(this, boardWAShip); + cNavigateToShipwreck.addStep(and(new VarbitRequirement(VarbitID.CUTSCENE_STATUS, 1), canSalvage), watchSalvageCutscene); + cNavigateToShipwreck.addStep(onboardShip, cNavigateToShipwreckOnShip); + steps.put(8, cNavigateToShipwreck); + steps.put(10, cNavigateToShipwreck); + steps.put(12, cNavigateToShipwreck); + steps.put(14, cNavigateToShipwreck); + + var cLearnWhereYouAre = new ConditionalStep(this, getToPandemonium); + cLearnWhereYouAre.addStep(onPandemonium, learnWhereYouAre); + steps.put(16, cLearnWhereYouAre); + var cLearnWhoWAare = new ConditionalStep(this, getToPandemonium); + cLearnWhoWAare.addStep(onPandemonium, learnWhoWAare); + steps.put(18, cLearnWhoWAare); + var cTalkToRibs = new ConditionalStep(this, getToPandemonium); + cTalkToRibs.addStep(onPandemonium, talkToRibs); + steps.put(20, cTalkToRibs); + var cFindLocationWA = new ConditionalStep(this, getToPandemonium); + cFindLocationWA.addStep(onPandemonium, findLocationWA); + steps.put(22, cFindLocationWA); + var cInformAboutShip = new ConditionalStep(this, getToPandemonium); + cInformAboutShip.addStep(onPandemonium, informAboutShip); + steps.put(24, cInformAboutShip); + var cShowCup = new ConditionalStep(this, getToPandemonium); + cShowCup.addStep(onPandemonium, showCup); + steps.put(26, cShowCup); + + var cBuildCargoHold = new ConditionalStep(this, getToPandemonium); + cBuildCargoHold.addStep(and(atShipyard, onboardShip), buildCargoHold); + cBuildCargoHold.addStep(and(atShipyard, hammer, saw), embarkShipSY); + cBuildCargoHold.addStep(and(atShipyard, saw), getHammer); + cBuildCargoHold.addStep(atShipyard, getSaw); + cBuildCargoHold.addStep(onPandemonium, enterShipyard); + steps.put(28, cBuildCargoHold); + + + var cGetLogBook = new ConditionalStep(this, getToPandemonium); + cGetLogBook.addStep(onPandemonium, getLogBook); + cGetLogBook.addStep(atShipyard, leaveShipyard); + steps.put(30, cGetLogBook); // Jim + + steps.put(32, getNewJob); // Jim + steps.put(34, boardShip); + var cSailToPortSarim = new ConditionalStep(this, boardShip); + cSailToPortSarim.addStep(and(atPortSarimDock, cargoNotPickedUp, takenHelm), letGoOfHelm); + cSailToPortSarim.addStep(and(atPortSarimDock, cargoNotPickedUp, onboardShip), disembarkShipPS); + cSailToPortSarim.addStep(and(not(atPortSarimDock), sailing), sailToPortSarim); + cSailToPortSarim.addStep(and(not(atPortSarimDock), takenHelm), raiseSails2); + cSailToPortSarim.addStep(and(not(atPortSarimDock), onboardShip), takeHelm2); + steps.put(36, cSailToPortSarim); + var cCheckPortMaster = new ConditionalStep(this, cSailToPortSarim); + cCheckPortMaster.addStep(and(boatAtPortSarim, holdingCargo, not(onboardShip)), boardShip2); + cCheckPortMaster.addStep(and(boatAtPortSarim, cargoNotPickedUp, not(onboardShip)), pickupCargo); + cCheckPortMaster.addStep(and(atPortSarimDock, cargoNotPickedUp, takenHelm), letGoOfHelm); + cCheckPortMaster.addStep(and(atPortSarimDock, cargoNotPickedUp, onboardShip), disembarkShipPS); + steps.put(38, cCheckPortMaster); + var cSailToPandemonium = new ConditionalStep(this, cCheckPortMaster); + cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip, takenHelm, sailing), sailToPandemonium); + cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip, takenHelm), raiseSails3); + cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoInCargoHold, onboardShip), takeHelm3); + cSailToPandemonium.addStep(and(not(atPandemoniumDock), cargoPickedUp, holdingCargo, onboardShip), dropCargoInCargoHold); + + var cDeliverCargo = new ConditionalStep(this, cSailToPandemonium); + cDeliverCargo.addStep(and(onPandemonium, not(onboardShip), holdingCargo), deliverCargo); + cDeliverCargo.addStep(and(atPandemoniumDock, onboardShip, holdingCargo), disembarkShipP); + cDeliverCargo.addStep(and(atPandemoniumDock, onboardShip, nor(takenHelm, setSails), cargoInCargoHold), pickupCargoShip); + cDeliverCargo.addStep(and(onPandemonium, not(onboardShip), cargoInCargoHold), boardShip3); + cDeliverCargo.addStep(and(atPandemoniumDock, cargoInCargoHold, takenHelm), letGoOfHelm2); + steps.put(40, cDeliverCargo); + steps.put(42, cDeliverCargo); + steps.put(44, talkToJim); + steps.put(46, meetGrog); + steps.put(48, finishQuest); + + return steps; } @Override public List getItemRequirements() { - return Arrays.asList(hammer, saw); + return List.of( + hammer, + saw + ); + } + + @Override + public QuestPointReward getQuestPointReward() + { + return new QuestPointReward(1); } @Override @@ -304,29 +393,93 @@ public List getExperienceRewards() @Override public List getItemRewards() { - return Arrays.asList( + return List.of( new ItemReward("Sawmill Coupon (wood plank)", ItemID.SAWMILL_COUPON, 25), new ItemReward("Repair kits", ItemID.BOAT_REPAIR_KIT, 2), - new ItemReward("Spyglass", ItemID.SAILING_CHARTING_SPYGLASS, 1)); + new ItemReward("Spyglass", ItemID.SAILING_CHARTING_SPYGLASS, 1) + ); } @Override public List getUnlockRewards() { - return Arrays.asList(new UnlockReward("Access to the Sailing Skill"), new UnlockReward("Access to Pandemonium"), new UnlockReward("Your very own mighty ship!")); + return List.of( + new UnlockReward("Access to the Sailing Skill"), + new UnlockReward("Access to Pandemonium"), + new UnlockReward("Your very own mighty ship!") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("You got the job!", Arrays.asList(talkToWill, boardWAShip))); - allSteps.add(new PanelDetails("What's the job?", Arrays.asList(explainJob, takeHelm, raiseSails, navigateShip, explainJob2, salvageShipwreck, watchSalvageCutscene))); - allSteps.add(new PanelDetails("You lost the job!", Arrays.asList(getToPandemonium, learnWhereYouAre, learnWhoWAare, talkToRibs, findLocationWA, informAboutShip, showCup))); - allSteps.add(new PanelDetails("Your mighty vessel", Arrays.asList(enterShipyard, getSaw, getHammer, embarkShipSY, buildCargoHold, disembarkShipSY, leaveShipyard, getLogBook))); - allSteps.add(new PanelDetails("You got the job... again!", Arrays.asList(getNewJob, boardShip, takeHelm2, raiseSails2, sailToPortSarim, letGoOfHelm, disembarkShipPS, pickupCargo, boardShip2))); - allSteps.add(new PanelDetails("Deliver the cargo.", Arrays.asList(dropCargoInCargoHold, takeHelm3, raiseSails3, sailToPandemonium, letGoOfHelm2, pickupCargoShip, disembarkShipP, deliverCargo))); - allSteps.add(new PanelDetails("Finishing up", Arrays.asList(talkToJim, meetGrog, finishQuest))); - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("You got the job!", List.of( + talkToWill, + boardWAShip + ))); + + sections.add(new PanelDetails("What's the job?", List.of( + explainJob, + takeHelm, + raiseSails, + navigateShip, + explainJob2, + salvageShipwreck, + watchSalvageCutscene + ))); + + sections.add(new PanelDetails("You lost the job!", List.of( + getToPandemonium, + learnWhereYouAre, + learnWhoWAare, + talkToRibs, + findLocationWA, + informAboutShip, + showCup + ))); + + sections.add(new PanelDetails("Your mighty vessel", List.of( + enterShipyard, + getSaw, + getHammer, + embarkShipSY, + buildCargoHold, + disembarkShipSY, + leaveShipyard, + getLogBook + ))); + + sections.add(new PanelDetails("You got the job... again!", List.of( + getNewJob, + boardShip, + takeHelm2, + raiseSails2, + sailToPortSarim, + letGoOfHelm, + disembarkShipPS, + pickupCargo, + boardShip2 + ))); + + sections.add(new PanelDetails("Deliver the cargo.", List.of( + dropCargoInCargoHold, + takeHelm3, + raiseSails3, + sailToPandemonium, + letGoOfHelm2, + pickupCargoShip, + disembarkShipP, + deliverCargo + ))); + + sections.add(new PanelDetails("Finishing up", List.of( + talkToJim, + meetGrog, + finishQuest + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/PiratesTreasure.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/PiratesTreasure.java index 0766746b7b..c3c4b80bb6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/PiratesTreasure.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/PiratesTreasure.java @@ -33,16 +33,20 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; - +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DigStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; public class PiratesTreasure extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/RumSmugglingStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/RumSmugglingStep.java index 805f3e4c30..8075c234ce 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/RumSmugglingStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/piratestreasure/RumSmugglingStep.java @@ -32,22 +32,24 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.List; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.List; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class RumSmugglingStep extends ConditionalStep { private final PiratesTreasure pt; @@ -171,7 +173,7 @@ private void setupRequirements() private void setupSteps() { goToKaramja = new NpcStep(getQuestHelper(), NpcID.SEAMAN_LORRIS, new WorldPoint(3027, 3222, 0), - "Talk to one of the Seamen on the docks in Port Sarim to go to Karamja.", new ItemRequirement("Coins", ItemCollections.COINS, 60)); + "Talk to one of the Seamen on the docks in Port Sarim to go to Musa Point.", new ItemRequirement("Coins", ItemCollections.COINS, 60)); goToKaramja.addDialogStep("Yes please."); talkToZambo = new NpcStep(getQuestHelper(), NpcID.ZEMBO, new WorldPoint(2929, 3145, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/plaguecity/PlagueCity.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/plaguecity/PlagueCity.java index f2e6906212..ea5c10ad94 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/plaguecity/PlagueCity.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/plaguecity/PlagueCity.java @@ -28,13 +28,22 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ObjectCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -42,13 +51,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class PlagueCity extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/priestinperil/PriestInPeril.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/priestinperil/PriestInPeril.java index 9bbc283069..c739999b53 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/priestinperil/PriestInPeril.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/priestinperil/PriestInPeril.java @@ -27,10 +27,11 @@ import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -38,150 +39,104 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class PriestInPeril extends BasicQuestHelper { - //Items Required - ItemRequirement runeEssence, lotsOfRuneEssence, bucket, weaponAndArmour, goldenKey, rangedMagedGear, - murkyWater, ironKey, blessedWaterHighlighted, bucketHighlighted, goldenKeyHighlighted; - - //Items Recommended - ItemRequirement runePouches, varrockTeleport; - - Requirement inUnderground, hasGoldenOrIronKey, inTempleGroundFloor, inTemple, inTempleFirstFloor, inTempleSecondFloor; - - QuestStep talkToRoald, goToTemple, goDownToDog, killTheDog, climbUpAfterKillingDog, returnToKingRoald, returnToTemple, killMonk, talkToDrezel, - goUpToFloorTwoTemple, goUpToFloorOneTemple, goDownToFloorOneTemple, goDownToGroundFloorTemple, enterUnderground, fillBucket, useKeyForKey, - openDoor, useBlessedWater, blessWater, goUpWithWaterToSurface, goUpWithWaterToFirstFloor, goUpWithWaterToSecondFloor, talkToDrezelAfterFreeing, - goDownToFloorOneAfterFreeing, goDownToGroundFloorAfterFreeing, enterUndergroundAfterFreeing, talkToDrezelUnderground, bringDrezelEssence; + // Required items + ItemRequirement runeEssence; + ItemRequirement bucket; + + // Recommended items + ItemRequirement varrockTeleport; + ItemRequirement runePouches; + + // Mid-quest requirements + ItemRequirement lotsOfRuneEssence; + ItemRequirement weaponAndArmour; + ItemRequirement goldenKey; + ItemRequirement rangedMagedGear; + ItemRequirement murkyWater; + ItemRequirement ironKey; + ItemRequirement blessedWaterHighlighted; + ItemRequirement bucketHighlighted; + ItemRequirement goldenKeyHighlighted; + + // Zones + Zone underground; + Zone temple1; + Zone temple2; + Zone temple3; + Zone temple4; + Zone temple5; + Zone temple6; + Zone templeFloorOne; + Zone templeFloorTwo; + + // Miscellaneous requirements + ZoneRequirement inUnderground; + ZoneRequirement inTempleGroundFloor; + ZoneRequirement inTemple; + ZoneRequirement inTempleFirstFloor; + ZoneRequirement inTempleSecondFloor; + Conditions hasGoldenOrIronKey; + + // Steps + NpcStep talkToRoald; + ObjectStep goToTemple; + ObjectStep goDownToDog; + NpcStep killTheDog; + ObjectStep climbUpAfterKillingDog; + NpcStep returnToKingRoald; + ObjectStep returnToTemple; + NpcStep killMonk; + NpcStep talkToDrezel; + ObjectStep goUpToFloorTwoTemple; + ObjectStep goUpToFloorOneTemple; + ObjectStep goDownToFloorOneTemple; + ObjectStep goDownToGroundFloorTemple; + ObjectStep enterUnderground; + ObjectStep fillBucket; + DetailedQuestStep useKeyForKey; + ObjectStep openDoor; + ObjectStep useBlessedWater; + NpcStep blessWater; + ObjectStep goUpWithWaterToSurface; + ObjectStep goUpWithWaterToFirstFloor; + ObjectStep goUpWithWaterToSecondFloor; + NpcStep talkToDrezelAfterFreeing; + ObjectStep goDownToFloorOneAfterFreeing; + ObjectStep goDownToGroundFloorAfterFreeing; + ObjectStep enterUndergroundAfterFreeing; + NpcStep talkToDrezelUnderground; + NpcStep bringDrezelEssence; - //Zones - Zone underground, temple1, temple2, temple3, temple4, temple5, temple6, templeFloorOne, templeFloorTwo; @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - steps.put(0, talkToRoald); - steps.put(1, goToTemple); - - ConditionalStep goDownAndKillDog = new ConditionalStep(this, goDownToDog); - goDownAndKillDog.addStep(inUnderground, killTheDog); - - steps.put(2, goDownAndKillDog); - - ConditionalStep reportKillingDog = new ConditionalStep(this, returnToKingRoald); - reportKillingDog.addStep(inUnderground, climbUpAfterKillingDog); - steps.put(3, reportKillingDog); - - ConditionalStep goTalkToDrezel = new ConditionalStep(this, returnToTemple); - goTalkToDrezel.addStep(new Conditions(hasGoldenOrIronKey, inTempleSecondFloor), talkToDrezel); - goTalkToDrezel.addStep(new Conditions(hasGoldenOrIronKey, inTempleFirstFloor), goUpToFloorTwoTemple); - goTalkToDrezel.addStep(new Conditions(hasGoldenOrIronKey, inTempleGroundFloor), goUpToFloorOneTemple); - goTalkToDrezel.addStep(inTemple, killMonk); - steps.put(4, goTalkToDrezel); - - ConditionalStep goGetKey = new ConditionalStep(this, returnToTemple); - goGetKey.addStep(new Conditions(ironKey, murkyWater, inTempleSecondFloor), openDoor); - goGetKey.addStep(new Conditions(ironKey, murkyWater, inTempleFirstFloor), goUpWithWaterToSecondFloor); - goGetKey.addStep(new Conditions(ironKey, murkyWater, inUnderground), goUpWithWaterToSurface); - goGetKey.addStep(new Conditions(ironKey, murkyWater), goUpWithWaterToFirstFloor); - goGetKey.addStep(new Conditions(ironKey, inUnderground), fillBucket); - goGetKey.addStep(new Conditions(hasGoldenOrIronKey, inUnderground), useKeyForKey); - goGetKey.addStep(new Conditions(hasGoldenOrIronKey, inTempleSecondFloor), goDownToFloorOneTemple); - goGetKey.addStep(new Conditions(hasGoldenOrIronKey, inTempleFirstFloor), goDownToGroundFloorTemple); - goGetKey.addStep(hasGoldenOrIronKey, enterUnderground); - goGetKey.addStep(inTemple, killMonk); - steps.put(5, goGetKey); - - ConditionalStep goGetWater = new ConditionalStep(this, enterUnderground); - goGetWater.addStep(new Conditions(blessedWaterHighlighted, inTempleSecondFloor), useBlessedWater); - goGetWater.addStep(new Conditions(murkyWater, inTempleSecondFloor), blessWater); - goGetWater.addStep(new Conditions(murkyWater, inTempleFirstFloor), goUpWithWaterToSecondFloor); - goGetWater.addStep(new Conditions(murkyWater, inUnderground), goUpWithWaterToSurface); - goGetWater.addStep(murkyWater, goUpWithWaterToFirstFloor); - goGetWater.addStep(inUnderground, fillBucket); - goGetWater.addStep(inTempleSecondFloor, goDownToFloorOneTemple); - goGetWater.addStep(inTempleFirstFloor, goDownToGroundFloorTemple); - steps.put(6, goGetWater); - - ConditionalStep goTalkToDrezelAfterFreeing = new ConditionalStep(this, goUpWithWaterToFirstFloor); - goTalkToDrezelAfterFreeing.addStep(inTempleSecondFloor, talkToDrezelAfterFreeing); - goTalkToDrezelAfterFreeing.addStep(inTempleFirstFloor, goUpWithWaterToSecondFloor); - steps.put(7, goTalkToDrezelAfterFreeing); - - ConditionalStep goDownToDrezel = new ConditionalStep(this, enterUndergroundAfterFreeing); - goDownToDrezel.addStep(inUnderground, talkToDrezelUnderground); - goDownToDrezel.addStep(inTempleFirstFloor, goDownToGroundFloorAfterFreeing); - goDownToDrezel.addStep(inTempleSecondFloor, goDownToFloorOneAfterFreeing); - steps.put(8, goDownToDrezel); - steps.put(9, goDownToDrezel); - - steps.put(10, bringDrezelEssence); - steps.put(11, bringDrezelEssence); - steps.put(12, bringDrezelEssence); - steps.put(13, bringDrezelEssence); - steps.put(14, bringDrezelEssence); - steps.put(15, bringDrezelEssence); - steps.put(16, bringDrezelEssence); - steps.put(17, bringDrezelEssence); - steps.put(18, bringDrezelEssence); - steps.put(19, bringDrezelEssence); - steps.put(20, bringDrezelEssence); - steps.put(21, bringDrezelEssence); - steps.put(22, bringDrezelEssence); - steps.put(23, bringDrezelEssence); - steps.put(24, bringDrezelEssence); - steps.put(25, bringDrezelEssence); - steps.put(26, bringDrezelEssence); - steps.put(27, bringDrezelEssence); - steps.put(28, bringDrezelEssence); - steps.put(29, bringDrezelEssence); - steps.put(30, bringDrezelEssence); - steps.put(31, bringDrezelEssence); - steps.put(32, bringDrezelEssence); - steps.put(33, bringDrezelEssence); - steps.put(34, bringDrezelEssence); - steps.put(35, bringDrezelEssence); - steps.put(36, bringDrezelEssence); - steps.put(37, bringDrezelEssence); - steps.put(38, bringDrezelEssence); - steps.put(39, bringDrezelEssence); - steps.put(40, bringDrezelEssence); - steps.put(41, bringDrezelEssence); - steps.put(42, bringDrezelEssence); - steps.put(43, bringDrezelEssence); - steps.put(44, bringDrezelEssence); - steps.put(45, bringDrezelEssence); - steps.put(46, bringDrezelEssence); - steps.put(47, bringDrezelEssence); - steps.put(48, bringDrezelEssence); - steps.put(49, bringDrezelEssence); - steps.put(50, bringDrezelEssence); - steps.put(51, bringDrezelEssence); - steps.put(52, bringDrezelEssence); - steps.put(53, bringDrezelEssence); - steps.put(54, bringDrezelEssence); - steps.put(55, bringDrezelEssence); - steps.put(56, bringDrezelEssence); - steps.put(57, bringDrezelEssence); - steps.put(58, bringDrezelEssence); - steps.put(59, bringDrezelEssence); - // There is a 60th step before the final 61, but the 'Quest Completed!' message pops up prior to it - - return steps; + underground = new Zone(new WorldPoint(3402, 9880, 0), new WorldPoint(3443, 9907, 0)); + temple1 = new Zone(new WorldPoint(3409, 3483, 0), new WorldPoint(3411, 3494, 0)); + temple2 = new Zone(new WorldPoint(3408, 3485, 0), new WorldPoint(3408, 3486, 0)); + temple3 = new Zone(new WorldPoint(3408, 3491, 0), new WorldPoint(3408, 3492, 0)); + temple4 = new Zone(new WorldPoint(3412, 3484, 0), new WorldPoint(3415, 3493, 0)); + temple5 = new Zone(new WorldPoint(3416, 3483, 0), new WorldPoint(3417, 3494, 0)); + temple6 = new Zone(new WorldPoint(3418, 3484, 0), new WorldPoint(3418, 3493, 0)); + templeFloorOne = new Zone(new WorldPoint(3408, 3483, 1), new WorldPoint(3419, 3494, 1)); + templeFloorTwo = new Zone(new WorldPoint(3408, 3483, 2), new WorldPoint(3419, 3494, 2)); } @Override @@ -211,36 +166,20 @@ protected void setupRequirements() ironKey = new ItemRequirement("Iron key", ItemID.PIPKEY_IRON); blessedWaterHighlighted = new ItemRequirement("Blessed water", ItemID.BUCKET_BLESSEDWATER); blessedWaterHighlighted.setHighlightInInventory(true); - } - - @Override - protected void setupZones() - { - underground = new Zone(new WorldPoint(3402, 9880, 0), new WorldPoint(3443, 9907, 0)); - temple1 = new Zone(new WorldPoint(3409, 3483, 0), new WorldPoint(3411, 3494, 0)); - temple2 = new Zone(new WorldPoint(3408, 3485, 0), new WorldPoint(3408, 3486, 0)); - temple3 = new Zone(new WorldPoint(3408, 3491, 0), new WorldPoint(3408, 3492, 0)); - temple4 = new Zone(new WorldPoint(3412, 3484, 0), new WorldPoint(3415, 3493, 0)); - temple5 = new Zone(new WorldPoint(3416, 3483, 0), new WorldPoint(3417, 3494, 0)); - temple6 = new Zone(new WorldPoint(3418, 3484, 0), new WorldPoint(3418, 3493, 0)); - templeFloorOne = new Zone(new WorldPoint(3408, 3483, 1), new WorldPoint(3419, 3494, 1)); - templeFloorTwo = new Zone(new WorldPoint(3408, 3483, 2), new WorldPoint(3419, 3494, 2)); - } - public void setupConditions() - { inUnderground = new ZoneRequirement(underground); inTempleGroundFloor = new ZoneRequirement(temple1, temple2, temple3, temple4, temple5, temple6); inTempleFirstFloor = new ZoneRequirement(templeFloorOne); inTempleSecondFloor = new ZoneRequirement(templeFloorTwo); inTemple = new ZoneRequirement(temple1, temple2, temple3, temple4, temple5, temple6, templeFloorOne, templeFloorTwo); - hasGoldenOrIronKey = new Conditions(LogicType.OR, goldenKey, ironKey); + hasGoldenOrIronKey = or(goldenKey, ironKey); } + public void setupSteps() { - talkToRoald = new NpcStep(this, NpcID.KING_ROALD_CUTSCENE, new WorldPoint(3222, 3473, 0), "Speak to King Roald in Varrock Castle."); + talkToRoald = new NpcStep(this, NpcID.KING_ROALD, new WorldPoint(3222, 3473, 0), "Speak to King Roald in Varrock Castle."); talkToRoald.addDialogStep("I'm looking for a quest!"); talkToRoald.addDialogStep("Yes."); goToTemple = new ObjectStep(this, ObjectID.PRIESTPERILTEMPLEDOORR, new WorldPoint(3408, 3488, 0), @@ -248,13 +187,15 @@ public void setupSteps() goToTemple.addDialogSteps("I'll get going.", "Roald sent me to check on Drezel.", "Sure. I'm a helpful person!"); goDownToDog = new ObjectStep(this, ObjectID.TRAPDOOR, new WorldPoint(3405, 3507, 0), "Go down the ladder north of the temple."); goDownToDog.addDialogStep("Yes."); - ((ObjectStep) (goDownToDog)).addAlternateObjects(ObjectID.TRAPDOOR_OPEN); + goDownToDog.addAlternateObjects(ObjectID.TRAPDOOR_OPEN); killTheDog = new NpcStep(this, NpcID.PRIESTPERIL_GUARDIAN_MODEL, new WorldPoint(3405, 9901, 0), "Kill the Temple Guardian (level 30). It is immune to magic so you will need to use either ranged or melee."); + killTheDog.addSubSteps(goDownToDog); climbUpAfterKillingDog = new ObjectStep(this, ObjectID.LADDER_FROM_CELLAR, new WorldPoint(3405, 9907, 0), "Climb back up the ladder and return to King Roald."); - returnToKingRoald = new NpcStep(this, NpcID.KING_ROALD_CUTSCENE, new WorldPoint(3222, 3473, 0), + returnToKingRoald = new NpcStep(this, NpcID.KING_ROALD, new WorldPoint(3222, 3473, 0), "Return to King Roald."); + returnToKingRoald.addDialogStep("About that job I'm doing..."); returnToKingRoald.addSubSteps(climbUpAfterKillingDog); returnToTemple = new ObjectStep(this, ObjectID.PRIESTPERILTEMPLEDOORR, new WorldPoint(3408, 3488, 0), @@ -270,13 +211,13 @@ public void setupSteps() fillBucket = new ObjectStep(this, ObjectID.PRIESTPERIL_WELL, new WorldPoint(3423, 9890, 0), "Use the bucket on the well in the central room.", bucketHighlighted); fillBucket.addIcon(ItemID.BUCKET_EMPTY); - useKeyForKey = new DetailedQuestStep(this, "Go to the central room, and study the monuments to find which has a key on it. Use the Golden Key on it.", goldenKeyHighlighted); + useKeyForKey = new DetailedQuestStep(this, new WorldPoint(3421, 9888, 0), "Go to the central room, and study the monuments to find which has a key on it. Use the Golden Key on it.", goldenKeyHighlighted); goDownToFloorOneTemple = new ObjectStep(this, ObjectID.LADDERTOP, new WorldPoint(3410, 3485, 2), "Go down to the underground of the temple.", bucket); - goDownToGroundFloorTemple = new ObjectStep(this, ObjectID.SPIRALSTAIRSTOP, new WorldPoint(3417, 3485, 0), "Go down to the underground of the temple.", bucket); + goDownToGroundFloorTemple = new ObjectStep(this, ObjectID.SPIRALSTAIRSTOP, new WorldPoint(3417, 3485, 1), "Go down to the underground of the temple.", bucket); enterUnderground = new ObjectStep(this, ObjectID.TRAPDOOR, new WorldPoint(3405, 3507, 0), "Go down to the underground of the temple.", bucket); enterUnderground.addSubSteps(goDownToFloorOneTemple, goDownToGroundFloorTemple); - ((ObjectStep) (enterUnderground)).addAlternateObjects(ObjectID.TRAPDOOR_OPEN); + enterUnderground.addAlternateObjects(ObjectID.TRAPDOOR_OPEN); goUpWithWaterToSurface = new ObjectStep(this, ObjectID.LADDER_FROM_CELLAR, new WorldPoint(3405, 9907, 0), "Go back up to the top floor of the temple."); @@ -294,9 +235,9 @@ public void setupSteps() talkToDrezelAfterFreeing = new NpcStep(this, NpcID.PRIESTPERILTRAPPEDMONK_VIS, new WorldPoint(3418, 3489, 2), "Talk to Drezel again."); goDownToFloorOneAfterFreeing = new ObjectStep(this, ObjectID.LADDERTOP, new WorldPoint(3410, 3485, 2), "Go down to the underground of the temple.", lotsOfRuneEssence); - goDownToGroundFloorAfterFreeing = new ObjectStep(this, ObjectID.SPIRALSTAIRSTOP, new WorldPoint(3417, 3485, 0), "Go down to the underground of the temple.", lotsOfRuneEssence); + goDownToGroundFloorAfterFreeing = new ObjectStep(this, ObjectID.SPIRALSTAIRSTOP, new WorldPoint(3417, 3485, 1), "Go down to the underground of the temple.", lotsOfRuneEssence); enterUndergroundAfterFreeing = new ObjectStep(this, ObjectID.TRAPDOOR, new WorldPoint(3405, 3507, 0), "Go down to the underground of the temple.", lotsOfRuneEssence); - ((ObjectStep) (enterUndergroundAfterFreeing)).addAlternateObjects(ObjectID.TRAPDOOR_OPEN); + enterUndergroundAfterFreeing.addAlternateObjects(ObjectID.TRAPDOOR_OPEN); talkToDrezelUnderground = new NpcStep(this, NpcID.PRIESTPERILTRAPPEDMONK_VIS, new WorldPoint(3439, 9896, 0), "Talk to Drezel in the east of the underground temple area.", lotsOfRuneEssence); talkToDrezelUnderground.addSubSteps(goDownToFloorOneAfterFreeing, goDownToGroundFloorAfterFreeing, enterUndergroundAfterFreeing); @@ -304,28 +245,150 @@ public void setupSteps() } @Override - public List getItemRecommended() + public Map loadSteps() { - ArrayList reqs = new ArrayList<>(); - reqs.add(varrockTeleport); - reqs.add(runePouches); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToRoald); + steps.put(1, goToTemple); + + var goDownAndKillDog = new ConditionalStep(this, goDownToDog); + goDownAndKillDog.addStep(inUnderground, killTheDog); + + steps.put(2, goDownAndKillDog); - return reqs; + var reportKillingDog = new ConditionalStep(this, returnToKingRoald); + reportKillingDog.addStep(inUnderground, climbUpAfterKillingDog); + steps.put(3, reportKillingDog); + + var goTalkToDrezel = new ConditionalStep(this, returnToTemple); + goTalkToDrezel.addStep(and(hasGoldenOrIronKey, inTempleSecondFloor), talkToDrezel); + goTalkToDrezel.addStep(and(hasGoldenOrIronKey, inTempleFirstFloor), goUpToFloorTwoTemple); + goTalkToDrezel.addStep(and(hasGoldenOrIronKey, inTempleGroundFloor), goUpToFloorOneTemple); + goTalkToDrezel.addStep(inTemple, killMonk); + steps.put(4, goTalkToDrezel); + + var goGetKey = new ConditionalStep(this, returnToTemple); + goGetKey.addStep(and(ironKey, murkyWater, inTempleSecondFloor), openDoor); + goGetKey.addStep(and(ironKey, murkyWater, inTempleFirstFloor), goUpWithWaterToSecondFloor); + goGetKey.addStep(and(ironKey, murkyWater, inUnderground), goUpWithWaterToSurface); + goGetKey.addStep(and(ironKey, murkyWater), goUpWithWaterToFirstFloor); + goGetKey.addStep(and(ironKey, inUnderground), fillBucket); + goGetKey.addStep(and(hasGoldenOrIronKey, inUnderground), useKeyForKey); + goGetKey.addStep(and(hasGoldenOrIronKey, inTempleSecondFloor), goDownToFloorOneTemple); + goGetKey.addStep(and(hasGoldenOrIronKey, inTempleFirstFloor), goDownToGroundFloorTemple); + goGetKey.addStep(hasGoldenOrIronKey, enterUnderground); + goGetKey.addStep(inTemple, killMonk); + steps.put(5, goGetKey); + + var goGetWater = new ConditionalStep(this, enterUnderground); + goGetWater.addStep(and(blessedWaterHighlighted, inTempleSecondFloor), useBlessedWater); + goGetWater.addStep(and(murkyWater, inTempleSecondFloor), blessWater); + goGetWater.addStep(and(murkyWater, inTempleFirstFloor), goUpWithWaterToSecondFloor); + goGetWater.addStep(and(murkyWater, inUnderground), goUpWithWaterToSurface); + goGetWater.addStep(murkyWater, goUpWithWaterToFirstFloor); + goGetWater.addStep(inUnderground, fillBucket); + goGetWater.addStep(inTempleSecondFloor, goDownToFloorOneTemple); + goGetWater.addStep(inTempleFirstFloor, goDownToGroundFloorTemple); + steps.put(6, goGetWater); + + var goTalkToDrezelAfterFreeing = new ConditionalStep(this, goUpWithWaterToFirstFloor); + goTalkToDrezelAfterFreeing.addStep(inTempleSecondFloor, talkToDrezelAfterFreeing); + goTalkToDrezelAfterFreeing.addStep(inTempleFirstFloor, goUpWithWaterToSecondFloor); + steps.put(7, goTalkToDrezelAfterFreeing); + + var goDownToDrezel = new ConditionalStep(this, enterUndergroundAfterFreeing); + goDownToDrezel.addStep(inUnderground, talkToDrezelUnderground); + goDownToDrezel.addStep(inTempleFirstFloor, goDownToGroundFloorAfterFreeing); + goDownToDrezel.addStep(inTempleSecondFloor, goDownToFloorOneAfterFreeing); + steps.put(8, goDownToDrezel); + steps.put(9, goDownToDrezel); + + steps.put(10, bringDrezelEssence); + steps.put(11, bringDrezelEssence); + steps.put(12, bringDrezelEssence); + steps.put(13, bringDrezelEssence); + steps.put(14, bringDrezelEssence); + steps.put(15, bringDrezelEssence); + steps.put(16, bringDrezelEssence); + steps.put(17, bringDrezelEssence); + steps.put(18, bringDrezelEssence); + steps.put(19, bringDrezelEssence); + steps.put(20, bringDrezelEssence); + steps.put(21, bringDrezelEssence); + steps.put(22, bringDrezelEssence); + steps.put(23, bringDrezelEssence); + steps.put(24, bringDrezelEssence); + steps.put(25, bringDrezelEssence); + steps.put(26, bringDrezelEssence); + steps.put(27, bringDrezelEssence); + steps.put(28, bringDrezelEssence); + steps.put(29, bringDrezelEssence); + steps.put(30, bringDrezelEssence); + steps.put(31, bringDrezelEssence); + steps.put(32, bringDrezelEssence); + steps.put(33, bringDrezelEssence); + steps.put(34, bringDrezelEssence); + steps.put(35, bringDrezelEssence); + steps.put(36, bringDrezelEssence); + steps.put(37, bringDrezelEssence); + steps.put(38, bringDrezelEssence); + steps.put(39, bringDrezelEssence); + steps.put(40, bringDrezelEssence); + steps.put(41, bringDrezelEssence); + steps.put(42, bringDrezelEssence); + steps.put(43, bringDrezelEssence); + steps.put(44, bringDrezelEssence); + steps.put(45, bringDrezelEssence); + steps.put(46, bringDrezelEssence); + steps.put(47, bringDrezelEssence); + steps.put(48, bringDrezelEssence); + steps.put(49, bringDrezelEssence); + steps.put(50, bringDrezelEssence); + steps.put(51, bringDrezelEssence); + steps.put(52, bringDrezelEssence); + steps.put(53, bringDrezelEssence); + steps.put(54, bringDrezelEssence); + steps.put(55, bringDrezelEssence); + steps.put(56, bringDrezelEssence); + steps.put(57, bringDrezelEssence); + steps.put(58, bringDrezelEssence); + steps.put(59, bringDrezelEssence); + // There is a 60th step before the final 61, but the 'Quest Completed!' message pops up prior to it + + return steps; } @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(runeEssence); - reqs.add(bucket); - return reqs; + return List.of( + runeEssence, + bucket + ); } + @Override + public List getItemRecommended() + { + return List.of( + weaponAndArmour, + varrockTeleport, + runePouches + ); + } + + @Override public List getCombatRequirements() { - return Arrays.asList("Temple Guardian (level 30). You cannot use Magic. Rings of recoil will not award the kill.", "Monk of Zamorak (level 30)"); + return List.of( + "Temple Guardian (level 30). You cannot use Magic. Rings of recoil will not award the kill.", + "Monk of Zamorak (level 30)" + ); } @Override @@ -337,31 +400,75 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.PRAYER, 1406)); + return List.of( + new ExperienceReward(Skill.PRAYER, 1406) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("Wolfbane Dagger", ItemID.DAGGER_WOLFBANE, 1)); + return List.of( + new ItemReward("Wolfbane Dagger", ItemID.DAGGER_WOLFBANE, 1) + ); } @Override public List getUnlockRewards() { - return Collections.singletonList(new UnlockReward("Access to Canifis and Morytania")); + return List.of( + new UnlockReward("Access to Canifis and Morytania") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Start the quest", Collections.singletonList(talkToRoald))); - allSteps.add(new PanelDetails("Go to the temple", Arrays.asList(goToTemple, killTheDog, returnToKingRoald), weaponAndArmour)); - allSteps.add(new PanelDetails("Return to the temple", Arrays.asList(returnToTemple, killMonk, talkToDrezel), weaponAndArmour, bucket, lotsOfRuneEssence)); - allSteps.add(new PanelDetails("Freeing Drezel", Arrays.asList(enterUnderground, useKeyForKey, fillBucket, goUpWithWaterToSecondFloor, openDoor, blessWater, useBlessedWater, talkToDrezelAfterFreeing), weaponAndArmour, bucket, lotsOfRuneEssence)); - allSteps.add(new PanelDetails("Curing the Salve", Arrays.asList(talkToDrezelUnderground, bringDrezelEssence), runeEssence)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Start the quest", List.of( + talkToRoald + ))); + + sections.add(new PanelDetails("Go to the temple", List.of( + goToTemple, + killTheDog, + returnToKingRoald + ), List.of( + weaponAndArmour + ))); + + sections.add(new PanelDetails("Return to the temple", List.of( + returnToTemple, + killMonk, + talkToDrezel + ), List.of( + weaponAndArmour, + bucket, + lotsOfRuneEssence + ))); + + sections.add(new PanelDetails("Freeing Drezel", List.of( + enterUnderground, + useKeyForKey, + fillBucket, + goUpWithWaterToSecondFloor, + openDoor, + blessWater, + useBlessedWater, + talkToDrezelAfterFreeing + ), List.of( + weaponAndArmour, + bucket, + lotsOfRuneEssence + ))); + + sections.add(new PanelDetails("Curing the Salve", List.of( + talkToDrezelUnderground, bringDrezelEssence + ), List.of( + runeEssence + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/princealirescue/PrinceAliRescue.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/princealirescue/PrinceAliRescue.java index df394cbc6c..3a8b00e831 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/princealirescue/PrinceAliRescue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/princealirescue/PrinceAliRescue.java @@ -30,7 +30,6 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; @@ -51,19 +50,18 @@ public class PrinceAliRescue extends BasicQuestHelper { //Items Required - ItemRequirement softClay, ballsOfWool3, yellowDye, redberries, ashes, bucketOfWater, potOfFlour, bronzeBar, pinkSkirt, beers3, rope, coins100, wig, dyedWig, paste, keyMould, key, + ItemRequirement softClay, ballsOfWool3, yellowDye, redberries, ashes, bucketOfWater, potOfFlour, bronzeBar, pinkSkirt, beers3, rope, coins100, wig, dyedWig, paste, keyPrint, key, ropeReqs, yellowDyeReqs, ropeHighlighted, keyHighlighted; //Items Recommended ItemRequirement glory; - Requirement hasOrGivenKeyMould, inCell, givenKeyMould, hasWigPasteAndKey; + Requirement hasOrUsedKeyPrint, inCell, hasWigPasteAndKey; + RuneliteRequirement madeKey; - RuneliteRequirement madeMould; + QuestStep talkToHassan, talkToOsman, talkToNed, talkToAggie, dyeWig, talkToKeli, makeKey, talkToLeela, reobtainKey, talkToJoe, useRopeOnKeli, useKeyOnDoor, talkToAli, returnToHassan; - QuestStep talkToHassan, talkToOsman, talkToNed, talkToAggie, dyeWig, talkToKeli, bringImprintToOsman, talkToLeela, talkToJoe, useRopeOnKeli, useKeyOnDoor, talkToAli, returnToHassan; - - ConditionalStep makeDyedWig, makePaste, makeKeyMould, getKey; + ConditionalStep makeDyedWig, makePaste, makeKeyPrint, getKey; //Zones Zone cell; @@ -86,39 +84,38 @@ public Map loadSteps() makePaste = new ConditionalStep(this, talkToAggie); makePaste.setLockingCondition(paste.alsoCheckBank()); - makeKeyMould = new ConditionalStep(this, talkToKeli); - makeKeyMould.setLockingCondition(hasOrGivenKeyMould); + makeKeyPrint = new ConditionalStep(this, talkToKeli); + makeKeyPrint.setLockingCondition(hasOrUsedKeyPrint); - getKey = new ConditionalStep(this, bringImprintToOsman); - getKey.setLockingCondition(givenKeyMould); + getKey = new ConditionalStep(this, makeKey); ConditionalStep prepareToSaveAli = new ConditionalStep(this, makeDyedWig); - prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank(), - new Conditions(LogicType.OR, madeMould, givenKeyMould)), talkToLeela); - prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank(), hasOrGivenKeyMould), getKey); - prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank()), makeKeyMould); + prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank(), madeKey), talkToLeela); + prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank(), hasOrUsedKeyPrint), getKey); + prepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank()), makeKeyPrint); prepareToSaveAli.addStep(dyedWig.alsoCheckBank(), makePaste); steps.put(20, prepareToSaveAli); - ConditionalStep getJoeDrunk = new ConditionalStep(this, makeDyedWig); + ConditionalStep reprepareToSaveAli = new ConditionalStep(this, makeDyedWig); + reprepareToSaveAli.addStep(new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank()), reobtainKey); + reprepareToSaveAli.addStep(dyedWig.alsoCheckBank(), makePaste); + + ConditionalStep getJoeDrunk = new ConditionalStep(this, reprepareToSaveAli); getJoeDrunk.addStep(hasWigPasteAndKey, talkToJoe); - getJoeDrunk.addStep(dyedWig.alsoCheckBank(), makePaste); steps.put(30, getJoeDrunk); steps.put(31, getJoeDrunk); steps.put(32, getJoeDrunk); steps.put(33, getJoeDrunk); - ConditionalStep tieUpKeli = new ConditionalStep(this, makeDyedWig); + ConditionalStep tieUpKeli = new ConditionalStep(this, reprepareToSaveAli); tieUpKeli.addStep(hasWigPasteAndKey, useRopeOnKeli); - tieUpKeli.addStep(dyedWig.alsoCheckBank(), makePaste); steps.put(40, tieUpKeli); - ConditionalStep freeAli = new ConditionalStep(this, makeDyedWig); + ConditionalStep freeAli = new ConditionalStep(this, reprepareToSaveAli); freeAli.addStep(new Conditions(hasWigPasteAndKey, inCell), talkToAli); freeAli.addStep(hasWigPasteAndKey, useKeyOnDoor); - freeAli.addStep(dyedWig.alsoCheckBank(), makePaste); steps.put(50, freeAli); steps.put(100, returnToHassan); @@ -150,7 +147,7 @@ protected void setupRequirements() wig.setHighlightInInventory(true); dyedWig = new ItemRequirement("Wig (dyed)", ItemID.BLONDWIG); paste = new ItemRequirement("Paste", ItemID.SKINPASTE); - keyMould = new ItemRequirement("Key print", ItemID.KEYPRINT); + keyPrint = new ItemRequirement("Key print", ItemID.KEYPRINT); key = new ItemRequirement("Bronze key", ItemID.PRINCESKEY); key.setTooltip("You can get another from Leela for 15 coins"); @@ -164,17 +161,15 @@ public void setupConditions() { inCell = new ZoneRequirement(cell); hasWigPasteAndKey = new Conditions(dyedWig.alsoCheckBank(), paste.alsoCheckBank(), key.alsoCheckBank()); - givenKeyMould = new Conditions(true, LogicType.OR, // TODO quest journal widget text outdated - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I have duplicated a key, I need to get it from"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I got a duplicated cell door key"), - new WidgetTextRequirement(11, 2, true, "You give Osman the imprint along with a bronze bar."), - new DialogRequirement("I'll use this to have a copy of the key made. I'll send it to Leela once it's ready."), - new DialogRequirement("I think I have everything needed."), + + var usedKeyPrint = new Conditions(true, LogicType.OR, + new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "made a copy of the key to his cell"), key.alsoCheckBank()); - madeMould = new RuneliteRequirement(getConfigManager(), "princealikeymouldhandedin", "true", givenKeyMould); - madeMould.initWithValue("false"); - hasOrGivenKeyMould = new Conditions(LogicType.OR, keyMould, givenKeyMould, key.alsoCheckBank()); + madeKey = new RuneliteRequirement(getConfigManager(), "princealikeymouldhandedin", "true", usedKeyPrint); + madeKey.initWithValue("false"); + + hasOrUsedKeyPrint = new Conditions(LogicType.OR, keyPrint, madeKey); } @Override @@ -197,15 +192,17 @@ public void setupSteps() talkToAggie = new NpcStep(this, NpcID.AGGIE_1OP, new WorldPoint(3086, 3257, 0), "Talk to Aggie in Draynor Village to get some paste.", redberries, ashes, potOfFlour, bucketOfWater); talkToAggie.addDialogStep("Can you make skin paste?"); talkToAggie.addDialogStep("Yes please. Mix me some skin paste."); - talkToKeli = new NpcStep(this, NpcID.LADY_KELI_VIS, new WorldPoint(3127, 3244, 0), "Talk to Keli in the jail east of Draynor Village. If you've already made the key mould, open the quest journal to re-sync.", softClay); + talkToKeli = new NpcStep(this, NpcID.LADY_KELI_VIS, new WorldPoint(3127, 3244, 0), "Talk to Keli in the jail east of Draynor Village. If you've already made the key print, open the quest journal to re-sync.", softClay); talkToKeli.addDialogStep("Heard of you? You're famous in Gielinor!"); talkToKeli.addDialogStep("What's your latest plan then?"); talkToKeli.addDialogStep("How do you know someone won't try to free him?"); talkToKeli.addDialogStep("Could I see the key please?"); talkToKeli.addDialogStep("Could I touch the key for a moment please?"); - bringImprintToOsman = new NpcStep(this, NpcID.OSMAN, new WorldPoint(3285, 3179, 0), "Bring the key print to Osman north of the Al Kharid Palace. If " + - "you already have, open the quest journal to re-sync.", keyMould, bronzeBar); + makeKey = new ObjectStep(this, ObjectID.FAI_FALADOR_FURNACE, new WorldPoint(3227, 3256, 0), "Use the key print on any furnace with a bronze bar in your inventory to make a key.", keyPrint.highlighted(), bronzeBar); talkToLeela = new NpcStep(this, NpcID.LEELA, new WorldPoint(3113, 3262, 0), "Talk to Leela east of Draynor Village.", beers3, dyedWig, paste, rope, pinkSkirt); + reobtainKey = new NpcStep(this, NpcID.LEELA, new WorldPoint(3113, 3262, 0), "Talk to Leela east of Draynor Village for another key. It'll cost 15gp.", coins100.quantity(15)); + talkToLeela.addSubSteps(reobtainKey); + talkToJoe = new NpcStep(this, NpcID.JOE_VIS, new WorldPoint(3124, 3245, 0), "Bring everything to the jail and give Joe there three beers.", beers3, key, dyedWig, paste, rope, pinkSkirt); talkToJoe.addDialogStep("I have some beer here. Fancy one?"); useRopeOnKeli = new NpcStep(this, NpcID.LADY_KELI_VIS, new WorldPoint(3127, 3244, 0), "Use rope on Keli.", ropeHighlighted); @@ -287,11 +284,11 @@ public List getPanels() makePastePanel.setLockingStep(makePaste); allSteps.add(makePastePanel); - PanelDetails makeKeyMouldPanel = new PanelDetails("Make a key mould", Collections.singletonList(talkToKeli), softClay); - makeKeyMouldPanel.setLockingStep(makeKeyMould); - allSteps.add(makeKeyMouldPanel); + PanelDetails makeKeyPrintPanel = new PanelDetails("Make a key print", Collections.singletonList(talkToKeli), softClay); + makeKeyPrintPanel.setLockingStep(makeKeyPrint); + allSteps.add(makeKeyPrintPanel); - PanelDetails getKeyPanel = new PanelDetails("Make the key", Collections.singletonList(bringImprintToOsman), bronzeBar, keyMould); + PanelDetails getKeyPanel = new PanelDetails("Make the key", Collections.singletonList(makeKey), bronzeBar, keyPrint); getKeyPanel.setLockingStep(getKey); allSteps.add(getKeyPanel); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pryingtimes/PryingTimes.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pryingtimes/PryingTimes.java index c625f54b27..6e21173da6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pryingtimes/PryingTimes.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/pryingtimes/PryingTimes.java @@ -43,7 +43,18 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PortTaskStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.runelite.client.plugins.microbot.questhelper.steps.SailStep; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -51,10 +62,9 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; - -import java.util.*; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; public class PryingTimes extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ragandboneman/RagAndBoneManII.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ragandboneman/RagAndBoneManII.java index 544bf9cd52..ab58653f45 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ragandboneman/RagAndBoneManII.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ragandboneman/RagAndBoneManII.java @@ -55,7 +55,11 @@ import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameTick; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.eventbus.Subscribe; import java.util.*; @@ -211,7 +215,7 @@ protected void setupRequirements() logs = new ItemRequirement("Logs", ItemID.LOGS); tinderbox = new ItemRequirement("Tinderbox", ItemID.TINDERBOX).isNotConsumed(); lightSource = new ItemRequirement("Light source", ItemCollections.LIGHT_SOURCES).isNotConsumed(); - dustyKey = new KeyringRequirement("Dusty Key", configManager, KeyringCollection.DUSTY_KEY).isNotConsumed(); + dustyKey = new KeyringRequirement("Dusty Key", KeyringCollection.DUSTY_KEY).isNotConsumed(); dustyKey.canBeObtainedDuringQuest(); mirrorShield = new ItemRequirement("Mirror shield", ItemID.SLAYER_MIRROR_SHIELD).isNotConsumed(); mirrorShield.addAlternates(ItemID.VIKINGEXILE_V_SHIELD, ItemID.V_SHIELD); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ratcatchers/RatCatchers.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ratcatchers/RatCatchers.java index 40a971a3ed..72e8d43bac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ratcatchers/RatCatchers.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/ratcatchers/RatCatchers.java @@ -49,7 +49,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.SpriteID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDDwarf.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDDwarf.java index 6200b6aba1..9592e7bf52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDDwarf.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDDwarf.java @@ -144,7 +144,7 @@ protected void setupRequirements() asgoldianAle4 = new ItemRequirement("Asgoldian ale", ItemID.HUNDRED_DWARF_ASGARNIAN_ALE, 4); // Recommended - taverleyTeleport = new ItemRequirement("Teleport to taverley", ItemID.NZONE_TELETAB_TAVERLEY); + taverleyTeleport = new ItemRequirement("Teleport to Taverley", ItemID.NZONE_TELETAB_TAVERLEY); taverleyTeleport.addAlternates(ItemCollections.COMBAT_BRACELETS); teleportFalador = new ItemRequirement("Teleport to Falador", ItemID.POH_TABLET_FALADORTELEPORT); teleportLumbridge = new ItemRequirement("Teleport to Lumbridge", ItemID.POH_TABLET_LUMBRIDGETELEPORT); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDPiratePete.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDPiratePete.java index af346440f1..eb088118a0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDPiratePete.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDPiratePete.java @@ -61,7 +61,7 @@ public class RFDPiratePete extends BasicQuestHelper { ItemRequirement combatGear, pestleHighlighted, rawCodHighlighted, knifeHighlighted, breadHighlighted, divingAparatus, divingHelmet, fishBowl, bronzeWire3, needle, fishCake, fishCakeHighlighted, rocks5, mudskipperHide5, crabMeat, kelp, groundKelpHighlighted, groundCrabMeatHighlighted, kelpHighlighted, crabMeatHighlighted, - rawFishCake, groundCod, breadcrumbs; + rawFishCake, groundCod, breadcrumbs, emptySlotsX6; WeightRequirement canSwim; @@ -162,6 +162,7 @@ protected void setupRequirements() fishBowl = new ItemRequirement("Empty fishbowl", ItemID.FISHBOWL_EMPTY); bronzeWire3 = new ItemRequirement("Bronze wire", ItemID.BRONZECRAFTWIRE, 3); needle = new ItemRequirement("Needle", ItemID.NEEDLE).isNotConsumed(); + needle.setTooltip("Costume needle cannot be used as a substitute"); fishCake = new ItemRequirement("Cooked fishcake", ItemID.HUNDRED_PIRATE_FISHCAKE); fishCakeHighlighted = new ItemRequirement("Cooked fishcake", ItemID.HUNDRED_PIRATE_FISHCAKE); fishCakeHighlighted.setHighlightInInventory(true); @@ -185,6 +186,8 @@ protected void setupRequirements() groundCod = new ItemRequirement("Ground cod", ItemID.HUNDRED_PIRATE_GROUND_COD); groundCod.setTooltip("You can make this by use a pestle and mortar on a raw cod"); breadcrumbs = new ItemRequirement("Breadcrumbs", ItemID.HUNDRED_PIRATE_BREADCRUMBS); + emptySlotsX6 = new ItemRequirement("Empty inventory slots at minimum", -1, 6); + emptySlotsX6.setTooltip("Have an additional empty slot for each additional kelp beyond the minimum of 1"); combatGear = new ItemRequirement("Combat gear", -1, -1); combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); @@ -341,7 +344,7 @@ public List getPanels() { List allSteps = new ArrayList<>(); allSteps.add(new PanelDetails("Starting off", Arrays.asList(inspectPete, talkToCook, talkToMurphy, talkToMurphyAgain), fishBowl)); - allSteps.add(new PanelDetails("Get Crab and Kelp", Arrays.asList(goDiving, pickKelp, talkToNung, pickUpRocks, enterCave, killMudksippers5, returnToNung, giveNungWire, killCrab, climbAnchor), divingHelmet, divingAparatus, bronzeWire3, needle)); + allSteps.add(new PanelDetails("Get Crab and Kelp", Arrays.asList(goDiving, pickKelp, talkToNung, pickUpRocks, enterCave, killMudksippers5, returnToNung, giveNungWire, killCrab, climbAnchor), Arrays.asList(divingHelmet, divingAparatus, bronzeWire3, needle, emptySlotsX6, canSwim), Collections.singletonList(combatGear))); allSteps.add(new PanelDetails("Saving Pete", Arrays.asList(grindCrab, grindKelp, usePestleOnCod, useKnifeOnBread, talkToCookAgain, useCrabOnKelp, cookCake, useCakeOnPete), pestleHighlighted, knifeHighlighted, rawCodHighlighted, breadHighlighted, crabMeat, kelp)); return allSteps; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDSkrachUglogwee.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDSkrachUglogwee.java index edfcb62abc..74ec05479d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDSkrachUglogwee.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recipefordisaster/RFDSkrachUglogwee.java @@ -220,7 +220,7 @@ public void setupSteps() getToad.addSubSteps(fillUpBellows); getRock = new ObjectStep(this, ObjectID.SWAMP_ROCK1, new WorldPoint(2567, 2960, 0), "Mine a pile of rocks near the Feldip Hills Fairy Ring for a rock.", pickaxe); useBellowOnToadInInv = new DetailedQuestStep(this, "Use the bellows on your toad with a ball of wool in your inventory.", ogreBellowsFilled, toad, ballOfWool); - dropBalloonToad = new DetailedQuestStep(this, new WorldPoint(2593, 2964, 0), "Drop the balloon toad near a swamp and wait for a Jubbly to arrive.", toadReady, ogreBowAndArrows); + dropBalloonToad = new DetailedQuestStep(this, new WorldPoint(2635, 2965, 0), "Drop the balloon toad in the dark area south of Rantz's cave and wait for a Jubbly to arrive.", toadReady, ogreBowAndArrows); killJubbly = new NpcStep(this, NpcID._100_JUBBLY_BIRD, "Kill then pluck jubbly.", ogreBowAndArrows); pickUpRawJubbly = new ItemStep(this, "Pick up the raw jubbly.", rawJubbly); lootJubbly = new NpcStep(this, NpcID._100_JUBBLY_BIRD_DEAD, "Pluck the jubbly's carcass."); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/DoorPuzzle.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/DoorPuzzle.java index 5a8f81a6bf..292f8e9a95 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/DoorPuzzle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/DoorPuzzle.java @@ -28,43 +28,25 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; import net.runelite.api.events.GameTick; import net.runelite.api.gameval.InterfaceID; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.ui.FontManager; -import java.awt.*; -import java.util.HashMap; -import java.util.Map; - public class DoorPuzzle extends QuestStep { + private final HashMap highlightButtons = new HashMap<>(); + private final HashMap distance = new HashMap<>(); private Character ENTRY_ONE; private Character ENTRY_TWO; private Character ENTRY_THREE; private Character ENTRY_FOUR; - private final int SLOT_ONE = 43; - private final int SLOT_TWO = 44; - private final int SLOT_THREE = 45; - private final int SLOT_FOUR = 46; - - private final int ARROW_ONE_LEFT = 47; - private final int ARROW_ONE_RIGHT = 48; - private final int ARROW_TWO_LEFT = 49; - private final int ARROW_TWO_RIGHT = 50; - private final int ARROW_THREE_LEFT = 51; - private final int ARROW_THREE_RIGHT = 52; - private final int ARROW_FOUR_LEFT = 53; - private final int ARROW_FOUR_RIGHT = 54; - - private final int COMPLETE = 56; - - private final HashMap highlightButtons = new HashMap<>(); - private final HashMap distance = new HashMap<>(); - public DoorPuzzle(QuestHelper questHelper, String word) { super(questHelper, "Click the highlighted arrows to move the slots to the solution."); @@ -73,10 +55,10 @@ public DoorPuzzle(QuestHelper questHelper, String word) ENTRY_THREE = word.charAt(2); ENTRY_FOUR = word.charAt(3); - highlightButtons.put(1, ARROW_ONE_RIGHT); - highlightButtons.put(2, ARROW_TWO_RIGHT); - highlightButtons.put(3, ARROW_THREE_RIGHT); - highlightButtons.put(4, ARROW_FOUR_RIGHT); + highlightButtons.put(1, InterfaceID.RdCombolock.RDA_RIGHT); + highlightButtons.put(2, InterfaceID.RdCombolock.RDB_RIGHT); + highlightButtons.put(3, InterfaceID.RdCombolock.RDC_RIGHT); + highlightButtons.put(4, InterfaceID.RdCombolock.RDD_RIGHT); distance.put(1, 0); distance.put(2, 0); @@ -84,13 +66,23 @@ public DoorPuzzle(QuestHelper questHelper, String word) distance.put(4, 0); } + @Override + public void startUp() + { + super.startUp(); + + // Recalculate once when the step starts up to ensure highlights aren't wrong for a tick + updateSolvedPositionState(); + } + public void updateWord(String word) { ENTRY_ONE = word.charAt(0); ENTRY_TWO = word.charAt(1); - ENTRY_THREE = word.charAt(2); - ENTRY_FOUR = word.charAt(3); + ENTRY_THREE = word.charAt(2); + ENTRY_FOUR = word.charAt(3); setText("Click the highlighted arrows to move the slots to the solution. The answer is " + word + "."); + updateSolvedPositionState(); } @Subscribe @@ -101,19 +93,20 @@ public void onGameTick(GameTick gameTick) private void updateSolvedPositionState() { - highlightButtons.replace(1, matchStateToSolution(SLOT_ONE, ENTRY_ONE, ARROW_ONE_RIGHT, ARROW_ONE_LEFT)); - highlightButtons.replace(2, matchStateToSolution(SLOT_TWO, ENTRY_TWO, ARROW_TWO_RIGHT, ARROW_TWO_LEFT)); - highlightButtons.replace(3, matchStateToSolution(SLOT_THREE, ENTRY_THREE, ARROW_THREE_RIGHT, ARROW_THREE_LEFT)); - highlightButtons.replace(4, matchStateToSolution(SLOT_FOUR, ENTRY_FOUR, ARROW_FOUR_RIGHT, ARROW_FOUR_LEFT)); - distance.replace(1, matchStateToDistance(SLOT_ONE, ENTRY_ONE)); - distance.replace(2, matchStateToDistance(SLOT_TWO, ENTRY_TWO)); - distance.replace(3, matchStateToDistance(SLOT_THREE, ENTRY_THREE)); - distance.replace(4, matchStateToDistance(SLOT_FOUR, ENTRY_FOUR)); + highlightButtons.replace(1, matchStateToSolution(InterfaceID.RdCombolock.RDA, ENTRY_ONE, InterfaceID.RdCombolock.RDA_RIGHT, InterfaceID.RdCombolock.RDA_LEFT)); + highlightButtons.replace(2, matchStateToSolution(InterfaceID.RdCombolock.RDB, ENTRY_TWO, InterfaceID.RdCombolock.RDB_RIGHT, InterfaceID.RdCombolock.RDB_LEFT)); + highlightButtons.replace(3, matchStateToSolution(InterfaceID.RdCombolock.RDC, ENTRY_THREE, InterfaceID.RdCombolock.RDC_RIGHT, InterfaceID.RdCombolock.RDC_LEFT)); + highlightButtons.replace(4, matchStateToSolution(InterfaceID.RdCombolock.RDD, ENTRY_FOUR, InterfaceID.RdCombolock.RDD_RIGHT, InterfaceID.RdCombolock.RDD_LEFT)); + + distance.replace(1, matchStateToDistance(InterfaceID.RdCombolock.RDA, ENTRY_ONE)); + distance.replace(2, matchStateToDistance(InterfaceID.RdCombolock.RDB, ENTRY_TWO)); + distance.replace(3, matchStateToDistance(InterfaceID.RdCombolock.RDC, ENTRY_THREE)); + distance.replace(4, matchStateToDistance(InterfaceID.RdCombolock.RDD, ENTRY_FOUR)); if (highlightButtons.get(1) + highlightButtons.get(2) + highlightButtons.get(3) + highlightButtons.get(4) == 0) { - highlightButtons.put(5, COMPLETE); + highlightButtons.put(5, InterfaceID.RdCombolock.RDENTER); } else { @@ -123,19 +116,28 @@ private void updateSolvedPositionState() private int matchStateToSolution(int slot, Character target, int arrowRightId, int arrowLeftId) { - Widget widget = client.getWidget(InterfaceID.RD_COMBOLOCK, slot); - if (widget == null) return 0; + Widget widget = client.getWidget(slot); + if (widget == null) + { + return 0; + } char current = widget.getText().charAt(0); int currentPos = (int) current - (int) 'A'; int id = Math.floorMod(currentPos - target, 26) < Math.floorMod(target - currentPos, 26) ? arrowRightId : arrowLeftId; - if (current != target) return id; + if (current != target) + { + return id; + } return 0; } private int matchStateToDistance(int slot, Character target) { - Widget widget = client.getWidget(InterfaceID.RD_COMBOLOCK, slot); - if (widget == null) return 0; + Widget widget = client.getWidget(slot); + if (widget == null) + { + return 0; + } char current = widget.getText().charAt(0); return Math.min(Math.floorMod(current - target, 26), Math.floorMod(target - current, 26)); } @@ -151,7 +153,7 @@ public void makeWidgetOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) continue; } - Widget widget = client.getWidget(InterfaceID.RD_COMBOLOCK, entry.getValue()); + Widget widget = client.getWidget(entry.getValue()); if (widget != null) { graphics.setColor(new Color(questHelper.getConfig().targetOverlayColor().getRed(), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/LadyTableStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/LadyTableStep.java index 8f3713f1f6..522c6f0fa3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/LadyTableStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/LadyTableStep.java @@ -25,113 +25,70 @@ */ package net.runelite.client.plugins.microbot.questhelper.helpers.quests.recruitmentdrive; -import com.google.inject.Inject; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; -import net.runelite.client.plugins.microbot.questhelper.steps.DetailedOwnerStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; -import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.api.Client; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.VarbitChanged; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class LadyTableStep extends DetailedOwnerStep +public class LadyTableStep extends ObjectStep { - @Inject - protected Client client; + private final Statue[] statues = new Statue[]{ + new Statue("Unknown", new WorldPoint(0, 0, 0)), + new Statue("Bronze Halberd", new WorldPoint(2452, 4976, 0)), + new Statue("Silver Halberd", new WorldPoint(2452, 4979, 0)), + new Statue("Gold Halberd", new WorldPoint(2452, 4982, 0)), - private Statue[] statues; + new Statue("Bronze 2H", new WorldPoint(2450, 4976, 0)), + new Statue("Silver 2H", new WorldPoint(2450, 4979, 0)), + new Statue("Gold 2H", new WorldPoint(2450, 4982, 0)), - private ObjectStep clickMissingStatue, leaveRoom; + new Statue("Gold Mace", new WorldPoint(2456, 4982, 0)), + new Statue("Silver Mace", new WorldPoint(2456, 4979, 0)), + new Statue("Bronze mace", new WorldPoint(2456, 4976, 0)), - VarbitRequirement finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM2_COMPLETE, 1); + new Statue("Bronze axe", new WorldPoint(2454, 4976, 0)), + new Statue("Silver axe", new WorldPoint(2454, 4979, 0)), + new Statue("Gold axe", new WorldPoint(2454, 4972, 0)) + }; public LadyTableStep(QuestHelper questHelper, Requirement... requirements) { - super(questHelper, requirements); + super(questHelper, ObjectID.RD_1G, new WorldPoint(0, 0, 0), "Click the missing statue.", requirements); + + addAlternateObjects(ObjectID.RD_1S, ObjectID.RD_1B, + ObjectID.RD_2G, ObjectID.RD_2S, ObjectID.RD_2B, ObjectID.RD_3G, + ObjectID.RD_3S, ObjectID.RD_3B, ObjectID.RD_4G, ObjectID.RD_4B); } @Override public void startUp() { super.startUp(); - Statue answerStatue = statues[client.getVarbitValue(VarbitID.RD_TEMPLOCK_2)]; - clickMissingStatue.setText("Click the " + answerStatue.text + " once it appears."); - clickMissingStatue.setWorldPoint(answerStatue.point); + + var answerIndex = client.getVarbitValue(VarbitID.RD_TEMPLOCK_2); + if (answerIndex < statues.length) + { + var answerStatue = statues[answerIndex]; + setText("Click the " + answerStatue.text + " once it appears."); + setWorldPoint(answerStatue.point); + } } @Override public void onVarbitChanged(VarbitChanged varbitChanged) { super.onVarbitChanged(varbitChanged); - Statue answerStatue = statues[client.getVarbitValue(VarbitID.RD_TEMPLOCK_2)]; - clickMissingStatue.setText("Click the " + answerStatue.text + " once it appears."); - clickMissingStatue.setWorldPoint(answerStatue.point); - } - @Override - public void setupSteps() - { - statues = new Statue[]{ - new Statue("Unknown", new WorldPoint(0, 0, 0)), - new Statue("Bronze Halberd", new WorldPoint(2452, 4976, 0)), - new Statue("Silver Halberd", new WorldPoint(2452, 4979, 0)), - new Statue("Gold Halberd", new WorldPoint(2452, 4982, 0)), - - new Statue("Bronze 2H", new WorldPoint(2450, 4976, 0)), - new Statue("Silver 2H", new WorldPoint(2450, 4979, 0)), - new Statue("Gold 2H", new WorldPoint(2450, 4982, 0)), - - new Statue("Gold Mace", new WorldPoint(2456, 4982, 0)), - new Statue("Silver Mace", new WorldPoint(2456, 4979, 0)), - new Statue("Bronze mace", new WorldPoint(2456, 4976, 0)), - - new Statue("Bronze axe", new WorldPoint(2454, 4976, 0)), - new Statue("Silver axe", new WorldPoint(2454, 4979, 0)), - new Statue("Gold axe", new WorldPoint(2454, 4972, 0)) - }; - - leaveRoom = new ObjectStep(questHelper, ObjectID.RD_ROOM2_EXITDOOR, "Leave through the door to enter the portal and continue."); - clickMissingStatue = new ObjectStep(questHelper, 0, statues[0].point, "CLick the missing statue."); - clickMissingStatue.addAlternateObjects(ObjectID.RD_1G, ObjectID.RD_1S, ObjectID.RD_1B, - ObjectID.RD_2G, ObjectID.RD_2S, ObjectID.RD_2B, ObjectID.RD_3G, - ObjectID.RD_3S, ObjectID.RD_3B, ObjectID.RD_4G, ObjectID.RD_4B); - } - - @Override - public Collection getSteps() - { - List step = new ArrayList<>(); - - step.add(clickMissingStatue); - step.add(leaveRoom); - return step; - } - - @Override - protected void updateSteps() - { - if (finishedRoom.check(client)) + if (varbitChanged.getVarbitId() == VarbitID.RD_TEMPLOCK_2) { - startUpStep(leaveRoom); + var answerIndex = varbitChanged.getValue(); + var answerStatue = statues[answerIndex]; + setText("Click the " + answerStatue.text + " once it appears."); + setWorldPoint(answerStatue.point); } - startUpStep(clickMissingStatue); - } - - public List getPanelSteps() - { - List steps = new ArrayList<>(); - steps.add(clickMissingStatue); - steps.add(leaveRoom); - - return steps; } static class Statue diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MissCheeversStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MissCheeversStep.java new file mode 100644 index 0000000000..1b76dbd736 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MissCheeversStep.java @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2020, Patyfatycake + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABI`LITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.helpers.quests.recruitmentdrive; + +import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.List; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; + +@SuppressWarnings("FieldCanBeLocal") +public class MissCheeversStep extends ConditionalStep +{ + // Requirements + ItemRequirement magnet; + ItemRequirement aceticAcid; + ItemRequirement vialOfLiquid; + ItemRequirement cupricSulfate; + ItemRequirement gypsum; + ItemRequirement sodiumChloride; + ItemRequirement bronzeWire; + ItemRequirement tin; + ItemRequirement shears; + ItemRequirement chisel; + ItemRequirement nitrousOxide; + ItemRequirement tinOrePowder; + ItemRequirement cupricOrePowder; + ItemRequirement knife; + ItemRequirement metalSpade; + ItemRequirement metalSpadeHead; + ItemRequirement ashes; + ItemRequirement gypsumTin; + ItemRequirement tinKeyPrint; + ItemRequirement tinWithCupricOre; + ItemRequirement tinWithTinOre; + ItemRequirement tinWithAllOre; + ItemRequirement bronzeKey; + + VarbitRequirement hasRetrievedThreeVials; + VarbitRequirement hasSpadeHeadOnDoor; + VarbitRequirement hasCupricSulfateOnDoor; + VarbitRequirement hasVialOfLiquidOnDoor; + VarbitRequirement hasFirstDoorOpen; + VarbitRequirement hasLiquidInTin; + + // Steps + ObjectStep getMagnet; + ObjectStep getTwoVials; + ObjectStep getCupricSulfate; + ObjectStep getGypsum; + ObjectStep getSodiumChloride; + ObjectStep getWire; + ObjectStep getTin; + ObjectStep getShears; + ObjectStep getChisel; + ObjectStep getNitrousOxide; + ObjectStep getTinOrePowder; + ObjectStep getCupricOrePowder; + ObjectStep getThreeVials; + ObjectStep getKnife; + ItemStep getMetalSpade; + + // Destroying first door steps + QuestStep useSpadeOnBunsenBurner; + QuestStep useSpadeHeadOnDoor; + QuestStep useCupricSulfateOnDoor; + QuestStep useVialOfLiquidOnDoor; + QuestStep openDoor; + // Creating second door key steps + QuestStep useVialOfLiquidOnCakeTin; + QuestStep useGypsumOnTin; + QuestStep useTinOnKey; + QuestStep useCupricOrePowderOnTin; + QuestStep useTinOrePowderOnTin; + QuestStep useTinOnBunsenBurner; + QuestStep useEquipmentOnTin; + + PuzzleWrapperStep pwGetMagnet; + PuzzleWrapperStep pwGetTwoVials; + PuzzleWrapperStep pwGetCupricSulfate; + PuzzleWrapperStep pwGetGypsum; + PuzzleWrapperStep pwGetSodiumChloride; + PuzzleWrapperStep pwGetWire; + PuzzleWrapperStep pwGetTin; + PuzzleWrapperStep pwGetShears; + PuzzleWrapperStep pwGetChisel; + PuzzleWrapperStep pwGetNitrousOxide; + PuzzleWrapperStep pwGetTinOrePowder; + PuzzleWrapperStep pwGetCupricOrePowder; + PuzzleWrapperStep pwGetThreeVials; + PuzzleWrapperStep pwGetKnife; + PuzzleWrapperStep pwGetMetalSpade; + PuzzleWrapperStep pwUseSpadeOnBunsenBurner; + PuzzleWrapperStep pwUseSpadeHeadOnDoor; + PuzzleWrapperStep pwUseCupricSulfateOnDoor; + PuzzleWrapperStep pwUseVialOfLiquidOnDoor; + PuzzleWrapperStep pwOpenDoor; + PuzzleWrapperStep pwUseVialOfLiquidOnCakeTin; + PuzzleWrapperStep pwUseGypsumOnTin; + PuzzleWrapperStep pwUseTinOnKey; + PuzzleWrapperStep pwUseCupricOrePowderOnTin; + PuzzleWrapperStep pwUseTinOrePowderOnTin; + PuzzleWrapperStep pwUseTinOnBunsenBurner; + PuzzleWrapperStep pwUseEquipmentOnTin; + + public MissCheeversStep(QuestHelper questHelper, Requirement... requirements) + { + // null safety - addSteps sets the null conditional step + super(questHelper, null, requirements); + + setupRequirements(); + setupSteps(); + addSteps(); + } + + public void setupRequirements() + { + magnet = new ItemRequirement("Magnet", ItemID.RD_MAGNET); + + aceticAcid = new ItemRequirement("Acetic Acid", ItemID.RD_ACETIC_ACID); + + vialOfLiquid = new ItemRequirement(true, "Vial of Liquid", ItemID.RD_DIHYDROGEN_MONOXIDE); + vialOfLiquid.setTooltip("Take from the shelf on the north side or the south side."); + + cupricSulfate = new ItemRequirement(true, "Cupric Sulfate", ItemID.RD_CUPRIC_SULPHATE); + cupricSulfate.setTooltip("Take from the shelves on the north side"); + + gypsum = new ItemRequirement(true, "Gypsum", ItemID.RD_GYPSUM); + + sodiumChloride = new ItemRequirement("Sodium Chloride", ItemID.RD_SODIUM_CHLORIDE); + + bronzeWire = new ItemRequirement(true, "Bronze Wire", ItemID.RD_WIRE); + + tin = new ItemRequirement(true, "Tin", ItemID.RD_TIN); + // TODO set tip + + shears = new ItemRequirement("Shears", ItemID.RD_SHEARS); + + chisel = new ItemRequirement(true, "Chisel", ItemID.RD_CHISEL); + + nitrousOxide = new ItemRequirement("Nitrous Oxide", ItemID.RD_NITORUS_OXIDE); + + tinOrePowder = new ItemRequirement(true, "Tin Ore Powder", ItemID.RD_TIN_ORE_POWDER); + + cupricOrePowder = new ItemRequirement(true, "Cupric Ore Powder", ItemID.RD_COPPER_ORE_POWDER); + + knife = new ItemRequirement(true, "Knife", ItemID.RD_KNIFE); + + metalSpade = new ItemRequirement(true, "Metal Spade", ItemID.RD_METAL_SPADE); + metalSpade.setTooltip("If you are missing this item pick another up off the table."); + + metalSpadeHead = new ItemRequirement(true, "Metal Spade", ItemID.RD_METAL_SPADE_NO_HANDLE); + metalSpadeHead.setTooltip("If you are missing this item pick up a metal spade off the table and use it on the bunsen burner."); + ashes = new ItemRequirement(true, "Ashes", ItemID.ASHES); + ashes.setTooltip("If you are missing this item pick up a metal spade off the table and use it on the bunsen burner."); + + gypsumTin = new ItemRequirement(true, "Tin", ItemID.RD_TINFULL); + + tinKeyPrint = new ItemRequirement(true, "Tin", ItemID.RD_KEYMOULD); + + tinWithCupricOre = new ItemRequirement(true, "Tin", ItemID.RD_FULL_KEYMOULD_COPPER); + + tinWithTinOre = new ItemRequirement(true, "Tin", ItemID.RD_FULL_KEYMOULD_UNHEATED); + + tinWithAllOre = new ItemRequirement(true, "Tin", ItemID.RD_FULL_KEYMOULD_COMPLETE); + + bronzeKey = new ItemRequirement("Bronze Key", ItemID.RD_PUZZLEROOM_KEY); + + hasRetrievedThreeVials = new VarbitRequirement(VarbitID.RD_SPARE_WATER, 3); + hasSpadeHeadOnDoor = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 1); + hasCupricSulfateOnDoor = new VarbitRequirement(VarbitID.RD_REACT_ON_SPADE, 1); + hasVialOfLiquidOnDoor = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 2); + hasFirstDoorOpen = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 3); + + hasLiquidInTin = new VarbitRequirement(VarbitID.RD_WATER_IN_TIN, 1); + } + + private void setupSteps() + { + getMagnet = new ObjectStep(questHelper, ObjectID.RD_BOOKSHELF_OLD_TALL, "Get the magnet from the old bookshelf."); + getTwoVials = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_1, "Get two vials from the shelves"); + getTwoVials.addDialogStep("Take both vials."); + getCupricSulfate = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_2, "Get Cupric Sulfate from the shelves."); + getCupricSulfate.addDialogStep("YES"); + getGypsum = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_3, "Get Gypsum from the shelves."); + getGypsum.addDialogStep("YES"); + getSodiumChloride = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_4, "Get Sodium Chloride from the shelves."); + getSodiumChloride.addDialogStep("YES"); + getWire = new ObjectStep(questHelper, ObjectID.RD_SMALL_CRATES, new WorldPoint(2475, 4943, 0), "Get Wire from the crate."); + getTin = new ObjectStep(questHelper, ObjectID.RD_LARGE_CRATE, new WorldPoint(2476, 4943, 0), "Get Tin from the crate."); + getShears = new ObjectStep(questHelper, ObjectID.RD_CHEST_CLOSED, "Get Shears from the chest."); + getShears.addAlternateObjects(ObjectID.RD_CHEST_OPEN); + getChisel = new ObjectStep(questHelper, ObjectID.RD_LARGE_CRATES, new WorldPoint(2476, 4937, 0), "Get a Chisel from the crate."); + getNitrousOxide = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_5, "Get Nitrous Oxide from the Shelves."); + getNitrousOxide.addDialogStep("YES"); + getTinOrePowder = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_6, "Get Tin Ore Powder from the Shelves."); + getTinOrePowder.addDialogStep("YES"); + getCupricOrePowder = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_7, "Get Cupric Ore Powder from the Shelves."); + getCupricOrePowder.addDialogStep("YES"); + getThreeVials = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_8, "Get Three Vials Of Liquid from the Shelves."); + getThreeVials.addDialogStep("Take all three vials"); + getKnife = new ObjectStep(questHelper, ObjectID.RD_BOOKSHELF_OLD_TALL3, "Get a Knife from the old bookshelf."); + getMetalSpade = new ItemStep(questHelper, "Get the metal spade off the table", metalSpade); + + useSpadeOnBunsenBurner = new ObjectStep(questHelper, ObjectID.RD_WOODEN_TABLE_BUNSEN_BURNER, "Use the spade in your inventory on the bunsen burner", metalSpade); + useSpadeOnBunsenBurner.addIcon(ItemID.RD_METAL_SPADE); + + useSpadeHeadOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use the spade in your inventory on the door.", metalSpadeHead); + useSpadeHeadOnDoor.addIcon(ItemID.RD_METAL_SPADE_NO_HANDLE); + + useCupricSulfateOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use Cupric Sulfate in your inventory on the door.", cupricSulfate); + useCupricSulfateOnDoor.addIcon(ItemID.RD_CUPRIC_SULPHATE); + + useVialOfLiquidOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use vial of liquid in your inventory on the door.", vialOfLiquid); + useVialOfLiquidOnDoor.addIcon(ItemID.RD_DIHYDROGEN_MONOXIDE); + + openDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Open the door."); + + useVialOfLiquidOnCakeTin = new DetailedQuestStep(questHelper, "Use a vial of liquid on the tin in your inventory.", tin, vialOfLiquid); + + useGypsumOnTin = new DetailedQuestStep(questHelper, "Use a vial of Gypsum on the tin in your inventory.", gypsum, tin); + + useTinOnKey = new ObjectStep(questHelper, ObjectID.RD_KEY_CHAINED, "Use tin full with Gypsum on the key on the ground.", gypsumTin); + useTinOnKey.addIcon(ItemID.RD_TINFULL); + + useCupricOrePowderOnTin = new DetailedQuestStep(questHelper, "Use Tin on the cupric ore powder in your inventory.", tinKeyPrint, cupricOrePowder); + + useTinOrePowderOnTin = new DetailedQuestStep(questHelper, "Use Tin on the tin ore powder in your inventory.", tinWithCupricOre, tinOrePowder); + + useTinOnBunsenBurner = new ObjectStep(questHelper, ObjectID.RD_WOODEN_TABLE_BUNSEN_BURNER, "Use your tin with the bunsen burner to create a bronze key.", tinWithTinOre); + useTinOnBunsenBurner.addIcon(ItemID.RD_FULL_KEYMOULD_UNHEATED); + + useEquipmentOnTin = new DetailedQuestStep(questHelper, "Use your chisel, knife or bronze wires on your tin in your inventory.", tinWithAllOre, chisel, knife, bronzeWire); + + pwGetMagnet = getMagnet.puzzleWrapStep(true); + pwGetTwoVials = getTwoVials.puzzleWrapStep(true); + pwGetCupricSulfate = getCupricSulfate.puzzleWrapStep(true); + pwGetGypsum = getGypsum.puzzleWrapStep(true); + pwGetSodiumChloride = getSodiumChloride.puzzleWrapStep(true); + pwGetWire = getWire.puzzleWrapStep(true); + pwGetTin = getTin.puzzleWrapStep(true); + pwGetShears = getShears.puzzleWrapStep(true); + pwGetChisel = getChisel.puzzleWrapStep(true); + pwGetNitrousOxide = getNitrousOxide.puzzleWrapStep(true); + pwGetTinOrePowder = getTinOrePowder.puzzleWrapStep(true); + pwGetCupricOrePowder = getCupricOrePowder.puzzleWrapStep(true); + pwGetThreeVials = getThreeVials.puzzleWrapStep(true); + pwGetKnife = getKnife.puzzleWrapStep(true); + pwGetMetalSpade = getMetalSpade.puzzleWrapStep(true); + pwUseSpadeOnBunsenBurner = useSpadeOnBunsenBurner.puzzleWrapStep(true); + pwUseSpadeHeadOnDoor = useSpadeHeadOnDoor.puzzleWrapStep(true); + pwUseCupricSulfateOnDoor = useCupricSulfateOnDoor.puzzleWrapStep(true); + pwUseVialOfLiquidOnDoor = useVialOfLiquidOnDoor.puzzleWrapStep(true); + pwOpenDoor = openDoor.puzzleWrapStep(true); + pwUseVialOfLiquidOnCakeTin = useVialOfLiquidOnCakeTin.puzzleWrapStep(true); + pwUseGypsumOnTin = useGypsumOnTin.puzzleWrapStep(true); + pwUseTinOnKey = useTinOnKey.puzzleWrapStep(true); + pwUseCupricOrePowderOnTin = useCupricOrePowderOnTin.puzzleWrapStep(true); + pwUseTinOrePowderOnTin = useTinOrePowderOnTin.puzzleWrapStep(true); + pwUseTinOnBunsenBurner = useTinOnBunsenBurner.puzzleWrapStep(true); + pwUseEquipmentOnTin = useEquipmentOnTin.puzzleWrapStep(true); + } + + private void addSteps() + { + this.addStep(null, pwGetMagnet); + setupSecondDoorKeyStep(); + destroyFirstDoorSteps(); + retrieveItemSteps(); + } + + /*** + * Steps and conditions required to create the key for the second door. + */ + private void setupSecondDoorKeyStep() + { + this.addStep(and(hasFirstDoorOpen, tinWithAllOre), pwUseEquipmentOnTin); + this.addStep(and(hasFirstDoorOpen, tinWithTinOre), pwUseTinOnBunsenBurner); + this.addStep(and(hasFirstDoorOpen, tinWithCupricOre), pwUseTinOrePowderOnTin); + this.addStep(and(hasFirstDoorOpen, tinKeyPrint), pwUseCupricOrePowderOnTin); + this.addStep(and(hasFirstDoorOpen, gypsumTin), pwUseTinOnKey); + this.addStep(and(hasFirstDoorOpen, hasLiquidInTin), pwUseGypsumOnTin); + this.addStep(hasFirstDoorOpen, pwUseVialOfLiquidOnCakeTin); + } + + /*** + * Steps and conditions required to destroy the first door. + */ + private void destroyFirstDoorSteps() + { + this.addStep(and(magnet, aceticAcid, vialOfLiquid, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife, ashes, hasVialOfLiquidOnDoor), pwOpenDoor); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife, ashes, hasCupricSulfateOnDoor), pwUseVialOfLiquidOnDoor); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife, ashes, hasSpadeHeadOnDoor), pwUseCupricSulfateOnDoor); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife, metalSpadeHead, ashes), pwUseSpadeHeadOnDoor); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife, metalSpade), pwUseSpadeOnBunsenBurner); + } + + /** + * First stage to retrieve all required items to pass the room. + */ + private void retrieveItemSteps() + { + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials, knife), pwGetMetalSpade); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder, hasRetrievedThreeVials), pwGetKnife); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder, cupricOrePowder), pwGetThreeVials); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide, tinOrePowder), pwGetCupricOrePowder); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, nitrousOxide, nitrousOxide), pwGetTinOrePowder); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears, chisel), pwGetNitrousOxide); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin, shears), pwGetChisel); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire, tin), pwGetShears); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride, bronzeWire), pwGetTin); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum, sodiumChloride), pwGetWire); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate, gypsum), pwGetSodiumChloride); + this.addStep(and(magnet, aceticAcid, vialOfLiquid, cupricSulfate), pwGetGypsum); + this.addStep(and(magnet, aceticAcid, vialOfLiquid), pwGetCupricSulfate); + this.addStep(magnet, pwGetTwoVials); + } + + public List getPanelSteps() + { + return List.of( + pwGetMagnet, + pwGetTwoVials, + pwGetCupricSulfate, + pwGetGypsum, + pwGetSodiumChloride, + pwGetWire, + pwGetTin, + pwGetShears, + pwGetChisel, + pwGetNitrousOxide, + pwGetTinOrePowder, + pwGetCupricOrePowder, + pwGetThreeVials, + pwGetKnife, + pwGetMetalSpade, + pwUseSpadeOnBunsenBurner, + pwUseSpadeHeadOnDoor, + pwUseCupricSulfateOnDoor, + pwUseVialOfLiquidOnDoor, + pwOpenDoor, + pwUseVialOfLiquidOnCakeTin, + pwUseGypsumOnTin, + pwUseTinOnKey, + pwUseCupricOrePowderOnTin, + pwUseTinOrePowderOnTin, + pwUseTinOnBunsenBurner, + pwUseEquipmentOnTin + ); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsCheevesSetup.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsCheevesSetup.java deleted file mode 100644 index b80ed3d212..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsCheevesSetup.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2020, Patyfatycake - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABI`LITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.helpers.quests.recruitmentdrive; - -import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; -import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; -import net.runelite.client.plugins.microbot.questhelper.steps.*; -import lombok.Getter; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.ObjectID; -import net.runelite.api.gameval.VarbitID; - -import java.util.ArrayList; -import java.util.List; - -public class MsCheevesSetup -{ - private QuestHelper questHelper; - - @Getter - private ZoneRequirement isInMsCheeversRoom; - - @Getter - private ConditionalStep conditionalStep; - - private ObjectStep getMagnetStep, getTwoVials, getCupricSulfate, - getGypsum, getSodiumChloride, getWire, getTin, getShears, - getChisel, getNitrousOxide, getTinOrePowder, getCupricOrePowder, getThreeVials, - getKnife, leaveRoom; - private ItemStep getMetalSpade; - - // TODO: Clean up to just use ItemRequirement - private Requirement hasMagnet, hasAceticAcid, hasOneVialOfLiquid, - hasCupricSulfate, hasGypsum, hasSodiumChloride, hasWire, hasTin, - hasShears, hasChisel, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasKnife, hasMetalSpade, hasMetalSpadeHead, hasAshes, hasBronzeKey; - - private VarbitRequirement finishedRoom; - - // Destroying first door steps - private QuestStep useSpadeOnBunsenBurner, useSpadeHeadOnDoor, useCupricSulfateOnDoor, useVialOfLiquidOnDoor, openDoor; - private VarbitRequirement hasRetrievedThreeVials, hasSpadeHeadOnDoor, hasCupricSulfateOnDoor, hasVialOfLiquidOnDoor, hasFirstDoorOpen; - private ItemRequirement metalSpade, metalSpadeHead, ashes, cupricSulfate, vialOfLiquid; - - // Creating second door key steps - private QuestStep useVialOfLiquidOnCakeTin, useGypsumOnTin, useTinOnKey, useCupricOrePowderOnTin, useTinOrePowderOnTin, useTinOnBunsenBurner, useEquipmentOnTin; - private ItemRequirement tin, gypsumTin, gypsum, tinKeyPrint, cupricOrePowder, tinOrePowder, tinWithCupricOre, - tinWithTinOre, tinWithAllOre, bronzeKey, knife, chisel, bronzeWire; - private VarbitRequirement hasLiquidInTin; - ItemRequirement hasGypsumTin, hasTinKeyPrint, hasTinCupricOre, hasTinWithTinOre, hasTinWithAllOre; - - public MsCheevesSetup(QuestHelper questHelper) - { - this.questHelper = questHelper; - setupRequirements(); - setupZoneCondition(); - setupConditions(); - setupSteps(); - addSteps(); - } - - private void setupSteps() - { - getMagnetStep = new ObjectStep(questHelper, ObjectID.RD_BOOKSHELF_OLD_TALL, "Get the magnet from the old bookshelf."); - getTwoVials = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_1, "Get two vials from the shelves"); - getTwoVials.addDialogStep("Take both vials."); - getCupricSulfate = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_2, "Get Cupric Sulfate from the shelves."); - getCupricSulfate.addDialogStep("YES"); - getGypsum = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_3, "Get Gypsum from the shelves."); - getGypsum.addDialogStep("YES"); - getSodiumChloride = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_4, "Get Sodium Chloride from the shelves."); - getSodiumChloride.addDialogStep("YES"); - getWire = new ObjectStep(questHelper, ObjectID.RD_SMALL_CRATES, new WorldPoint(2475, 4943, 0), "Get Wire from the crate."); - getTin = new ObjectStep(questHelper, ObjectID.RD_LARGE_CRATE, new WorldPoint(2476, 4943, 0), "Get Tin from the crate."); - getShears = new ObjectStep(questHelper, ObjectID.RD_CHEST_CLOSED, "Get Shears from the chest."); - getShears.addAlternateObjects(ObjectID.RD_CHEST_OPEN); - getChisel = new ObjectStep(questHelper, ObjectID.RD_LARGE_CRATES, new WorldPoint(2476, 4937, 0), "Get a Chisel from the crate."); - getNitrousOxide = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_5, "Get Nitrous Oxide from the Shelves."); - getNitrousOxide.addDialogStep("YES"); - getTinOrePowder = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_6, "Get Tin Ore Powder from the Shelves."); - getTinOrePowder.addDialogStep("YES"); - getCupricOrePowder = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_7, "Get Curpic Ore Powder from the Shelves."); - getCupricOrePowder.addDialogStep("YES"); - getThreeVials = new ObjectStep(questHelper, ObjectID.RD_SHELVES_CHEMICALS_8, "Get Three Vials Of Liquid from the Shelves."); - getThreeVials.addDialogStep("Take all three vials"); - getKnife = new ObjectStep(questHelper, ObjectID.RD_BOOKSHELF_OLD_TALL3, "Get a Knife from the old bookshelf."); - getMetalSpade = new ItemStep(questHelper, "Get the metal spade off the table", metalSpade); - - useSpadeOnBunsenBurner = new ObjectStep(questHelper, ObjectID.RD_WOODEN_TABLE_BUNSEN_BURNER, "Use the spade in your inventory on the bunsen burner" - , metalSpade); - useSpadeOnBunsenBurner.addIcon(ItemID.RD_METAL_SPADE); - - useSpadeHeadOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use the spade in your inventory on the door.", - metalSpadeHead); - useSpadeHeadOnDoor.addIcon(ItemID.RD_METAL_SPADE_NO_HANDLE); - - useCupricSulfateOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use Cupric Sulfate in your inventory on the door.", - cupricSulfate); - useCupricSulfateOnDoor.addIcon(ItemID.RD_CUPRIC_SULPHATE); - - useVialOfLiquidOnDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Use vial of liquid in your inventory on the door.", - vialOfLiquid); - useVialOfLiquidOnDoor.addIcon(ItemID.RD_DIHYDROGEN_MONOXIDE); - - openDoor = new ObjectStep(questHelper, ObjectID.RD_STONE_DOOR, "Open the door."); - - useVialOfLiquidOnCakeTin = new DetailedQuestStep(questHelper, "Use a vial of liquid on the tin in your inventory.", - tin, vialOfLiquid); - - useGypsumOnTin = new DetailedQuestStep(questHelper, "Use a vial of Gypsum on the tin in your inventory.", - gypsum, tin); - - useTinOnKey = new ObjectStep(questHelper, ObjectID.RD_KEY_CHAINED, "Use tin full with Gypsum on the key on the ground.", - gypsumTin); - useTinOnKey.addIcon(ItemID.RD_TINFULL); - - useCupricOrePowderOnTin = new DetailedQuestStep(questHelper, "Use Tin on the cupric ore powder in your inventory.", - tinKeyPrint, cupricOrePowder); - - useTinOrePowderOnTin = new DetailedQuestStep(questHelper, "Use Tin on the tin ore powder in your inventory.", - tinWithCupricOre, tinOrePowder); - - useTinOnBunsenBurner = new ObjectStep(questHelper, ObjectID.RD_WOODEN_TABLE_BUNSEN_BURNER, - "Use your tin with the bunsen burner to create a bronze key.", tinWithTinOre); - useTinOnBunsenBurner.addIcon(ItemID.RD_FULL_KEYMOULD_UNHEATED); - - useEquipmentOnTin = new DetailedQuestStep(questHelper, "Use your chisel, knife or bronze wires on your tin in your inventory.", - tinWithAllOre, chisel, knife, bronzeWire); - - leaveRoom = new ObjectStep(questHelper, ObjectID.RD_ROOM6_EXITDOOR, new WorldPoint(2478, 4940, 0), "Leave the room by the second door to enter the portal"); - } - - private void addSteps() - { - conditionalStep = new ConditionalStep(questHelper, getMagnetStep); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasBronzeKey, finishedRoom), leaveRoom); - setupSecondDoorKeyStep(); - destroyFirstDoorSteps(); - retrieveItemSteps(); - } - - public List GetPanelSteps() - { - List steps = new ArrayList<>(); - steps.add(getMagnetStep); - steps.add(getTwoVials); - steps.add(getCupricSulfate); - steps.add(getGypsum); - steps.add(getSodiumChloride); - steps.add(getWire); - steps.add(getTin); - steps.add(getShears); - steps.add(getChisel); - steps.add(getNitrousOxide); - steps.add(getTinOrePowder); - steps.add(getCupricOrePowder); - steps.add(getThreeVials); - steps.add(getKnife); - steps.add(getMetalSpade); - steps.add(useSpadeOnBunsenBurner); - steps.add(useSpadeHeadOnDoor); - steps.add(useCupricSulfateOnDoor); - steps.add(useVialOfLiquidOnDoor); - steps.add(openDoor); - steps.add(useVialOfLiquidOnCakeTin); - steps.add(useGypsumOnTin); - steps.add(useTinOnKey); - steps.add(useCupricOrePowderOnTin); - steps.add(useTinOrePowderOnTin); - steps.add(useTinOnBunsenBurner); - steps.add(useEquipmentOnTin); - steps.add(leaveRoom); - return steps; - } - - /*** - * Steps and conditions required to create the key for the second door. - */ - private void setupSecondDoorKeyStep() - { - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasTinWithAllOre), useEquipmentOnTin); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasTinWithTinOre), useTinOnBunsenBurner); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasTinCupricOre), useTinOrePowderOnTin); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasTinKeyPrint), useCupricOrePowderOnTin); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasGypsumTin), useTinOnKey); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen, hasLiquidInTin), useGypsumOnTin); - conditionalStep.addStep(new Conditions(hasFirstDoorOpen), useVialOfLiquidOnCakeTin); - } - - /*** - * Steps and conditions required to destroy the first door. - */ - private void destroyFirstDoorSteps() - { - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife, hasAshes, hasVialOfLiquidOnDoor), openDoor); - - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife, hasAshes, hasCupricSulfateOnDoor), useVialOfLiquidOnDoor); - - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife, hasAshes, hasSpadeHeadOnDoor), useCupricSulfateOnDoor); - - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife, hasMetalSpadeHead, hasAshes), useSpadeHeadOnDoor); - - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife, hasMetalSpade), useSpadeOnBunsenBurner); - } - - /** - * First stage to retrieve all required items to pass the room. - */ - private void retrieveItemSteps() - { - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials, hasKnife), getMetalSpade); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder, - hasRetrievedThreeVials), getKnife); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder, hasCupricOrePowder) - , getThreeVials); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide, hasTinOrePowder), getCupricOrePowder); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasNitrousOxide, hasNitrousOxide), getTinOrePowder); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears, hasChisel), getNitrousOxide); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin, hasShears), getChisel); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire, hasTin), getShears); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride, hasWire), getTin); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum, - hasSodiumChloride), getWire); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate, hasGypsum), - getSodiumChloride); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid, hasCupricSulfate), getGypsum); - conditionalStep.addStep(new Conditions(hasMagnet, hasAceticAcid, hasOneVialOfLiquid), getCupricSulfate); - conditionalStep.addStep(hasMagnet, getTwoVials); - } - - private void setupZoneCondition() - { - Zone missCheevesZone = new Zone(new WorldPoint(2466, 4936, 0), - new WorldPoint(2480, 4947, 0)); - isInMsCheeversRoom = new ZoneRequirement(missCheevesZone); - } - - public void setupRequirements() - { - metalSpade = new ItemRequirement("Metal Spade", ItemID.RD_METAL_SPADE); - metalSpade.setTooltip("If you are missing this item pick another up off the table."); - metalSpade.setHighlightInInventory(true); - metalSpadeHead = new ItemRequirement("Metal Spade", ItemID.RD_METAL_SPADE_NO_HANDLE); - metalSpadeHead.setHighlightInInventory(true); - metalSpadeHead.setTooltip("If you are missing this item pick up a metal spade off the table and use it on the bunsen burner."); - ashes = new ItemRequirement("Ashes", ItemID.ASHES); - ashes.setHighlightInInventory(true); - ashes.setTooltip("If you are missing this item pick up a metal spade off the table and use it on the bunsen burner."); - cupricSulfate = new ItemRequirement("Cupric Sulfate", ItemID.RD_CUPRIC_SULPHATE); - cupricSulfate.setHighlightInInventory(true); - cupricSulfate.setTooltip("Take from the shelves on the north side"); - - vialOfLiquid = new ItemRequirement("Vial of Liquid", ItemID.RD_DIHYDROGEN_MONOXIDE); - vialOfLiquid.setHighlightInInventory(true); - vialOfLiquid.setTooltip("Take from the shelf on the north side or the south side."); - - tin = new ItemRequirement("Tin", ItemID.RD_TIN); - tin.setHighlightInInventory(true); - //TODO set tip - - gypsumTin = new ItemRequirement("Tin", ItemID.RD_TINFULL); - gypsumTin.setHighlightInInventory(true); - - gypsum = new ItemRequirement("Gypsum", ItemID.RD_GYPSUM); - gypsum.setHighlightInInventory(true); - - tinKeyPrint = new ItemRequirement("Tin", ItemID.RD_KEYMOULD); - tinKeyPrint.setHighlightInInventory(true); - - tinWithCupricOre = new ItemRequirement("Tin", ItemID.RD_FULL_KEYMOULD_COPPER); - tinWithCupricOre.setHighlightInInventory(true); - - cupricOrePowder = new ItemRequirement("Cupric Ore Powder", ItemID.RD_COPPER_ORE_POWDER); - cupricOrePowder.setHighlightInInventory(true); - - tinOrePowder = new ItemRequirement("Tin Ore Powder", ItemID.RD_TIN_ORE_POWDER); - tinOrePowder.setHighlightInInventory(true); - - tinWithTinOre = new ItemRequirement("Tin", ItemID.RD_FULL_KEYMOULD_UNHEATED); - tinWithTinOre.setHighlightInInventory(true); - // duplicateBronzeKey = new ItemRequirement("Duplicate bronze key", ItemID.PRINCESKEY); - - tinWithAllOre = new ItemRequirement("Tin", ItemID.RD_FULL_KEYMOULD_COMPLETE); - tinWithAllOre.setHighlightInInventory(true); - - chisel = new ItemRequirement("Chisel", ItemID.RD_CHISEL); - chisel.setHighlightInInventory(true); - - bronzeWire = new ItemRequirement("Bronze Wire", ItemID.RD_WIRE); - bronzeWire.setHighlightInInventory(true); - - knife = new ItemRequirement("Knife", ItemID.RD_KNIFE); - knife.setHighlightInInventory(true); - - bronzeKey = new ItemRequirement("Bronze Key", ItemID.RD_PUZZLEROOM_KEY); - } - - private void setupConditions() - { - hasMagnet = new ItemRequirements(new ItemRequirement("Magnet", ItemID.RD_MAGNET)); - hasAceticAcid = new ItemRequirements(new ItemRequirement("Acetic Acid", ItemID.RD_ACETIC_ACID)); - hasOneVialOfLiquid = vialOfLiquid; - hasCupricSulfate = cupricSulfate; - hasGypsum = gypsum; - hasSodiumChloride = new ItemRequirements(new ItemRequirement("Sodium Chloride", ItemID.RD_SODIUM_CHLORIDE)); - hasTin = tin; - hasWire = bronzeWire; - hasShears = new ItemRequirements(new ItemRequirement("Shears", ItemID.RD_SHEARS)); - hasChisel = chisel; - hasNitrousOxide = new ItemRequirements(new ItemRequirement("Nitrous Oxide", ItemID.RD_NITORUS_OXIDE)); - hasTinOrePowder = tinOrePowder; - hasCupricOrePowder = cupricOrePowder; - hasKnife = knife; - hasMetalSpade = metalSpade; - hasMetalSpadeHead = metalSpadeHead; - hasAshes = ashes; - - hasGypsumTin = gypsumTin; - hasTinKeyPrint = tinKeyPrint; - hasTinCupricOre = tinWithCupricOre; - hasTinWithTinOre = tinWithTinOre; - hasTinWithAllOre = tinWithAllOre; - - hasBronzeKey = bronzeKey; - - hasRetrievedThreeVials = new VarbitRequirement(VarbitID.RD_SPARE_WATER, 3); - hasSpadeHeadOnDoor = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 1); - hasCupricSulfateOnDoor = new VarbitRequirement(VarbitID.RD_REACT_ON_SPADE, 1); - hasVialOfLiquidOnDoor = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 2); - hasFirstDoorOpen = new VarbitRequirement(VarbitID.RD_ROOM6_STONE_DOOR, 3); - finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM6_COMPLETE, 1); - - hasLiquidInTin = new VarbitRequirement(VarbitID.RD_WATER_IN_TIN, 1); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsHynnAnswerDialogQuizStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsHynnAnswerDialogQuizStep.java index e9caf82dd3..55e406002d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsHynnAnswerDialogQuizStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/MsHynnAnswerDialogQuizStep.java @@ -26,22 +26,13 @@ package net.runelite.client.plugins.microbot.questhelper.helpers.quests.recruitmentdrive; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; -import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; -import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; -import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.api.events.VarbitChanged; -import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.List; - -public class MsHynnAnswerDialogQuizStep extends ConditionalStep +public class MsHynnAnswerDialogQuizStep extends NpcStep { - private QuestStep leaveRoom, talkToMsHynnTerprett; - String[] answers = { "unknown", "10", @@ -51,56 +42,46 @@ public class MsHynnAnswerDialogQuizStep extends ConditionalStep "zero" }; - public MsHynnAnswerDialogQuizStep(QuestHelper questHelper, QuestStep step, Requirement... requirements) + public MsHynnAnswerDialogQuizStep(QuestHelper questHelper) { - super(questHelper, step, requirements); + super(questHelper, NpcID.RD_OBSERVER_ROOM_7, "Talk to Ms Hynn Terprett and answer the riddle."); - talkToMsHynnTerprett = step; - talkToMsHynnTerprett.addDialogSteps( + this.addDialogSteps( "The wolves.", "Bucket A (32 degrees)", "The number of false statements here is three.", - "Zero."); - addSteps(); + "Zero." + ); } - @Override - public void startUp() + private void updateAnswer(int answerID) { - super.startUp(); - int answerID = client.getVarbitValue(VarbitID.RD_TEMPLOCK_2); - if (answerID == 0) + if (answerID == 0 || answerID > answers.length) { + this.setText("Talk to Ms Hynn Terprett and answer the riddle."); return; } - String answer = "The answer is " + answers[answerID] + "."; - talkToMsHynnTerprett.setText("Talk to Ms Hynn Terprett and answer the riddle. " + answer); + var answer = "The answer is " + answers[answerID] + "."; + this.setText("Talk to Ms Hynn Terprett and answer the riddle. " + answer); } @Override - public void onVarbitChanged(VarbitChanged varbitChanged) + public void startUp() { - int answerID = client.getVarbitValue(VarbitID.RD_TEMPLOCK_2); - if (answerID == 0) - { - return; - } - String answer = "The answer is " + answers[answerID] + "."; - talkToMsHynnTerprett.setText("Talk to Ms Hynn Terprett and answer the riddle. " + answer); + super.startUp(); + this.updateAnswer(client.getVarbitValue(VarbitID.RD_TEMPLOCK_2)); } - private void addSteps() + @Override + public void onVarbitChanged(VarbitChanged event) { - VarbitRequirement finishedRoomCondition = new VarbitRequirement(VarbitID.RD_ROOM7_COMPLETE, 1); - leaveRoom = new ObjectStep(questHelper, ObjectID.RD_ROOM7_EXITDOOR, "Leave through the door to enter the portal and continue."); + super.onVarbitChanged(event); - addStep(finishedRoomCondition, leaveRoom); - } + if (event.getVarbitId() != VarbitID.RD_TEMPLOCK_2) + { + return; + } - public List getPanelSteps() - { - List steps = new ArrayList<>(); - steps.add(leaveRoom); - return steps; + this.updateAnswer(event.getValue()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/RecruitmentDrive.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/RecruitmentDrive.java index 55e2025ffc..d57589e75c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/RecruitmentDrive.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/RecruitmentDrive.java @@ -27,13 +27,14 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; +import net.runelite.client.plugins.microbot.questhelper.requirements.ConfigRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.NoItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.ItemSlots; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -42,7 +43,16 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -51,89 +61,120 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - public class RecruitmentDrive extends BasicQuestHelper { - private NoItemRequirement noItemRequirement; - private ZoneRequirement isFirstFloorCastle, isSecondFloorCastle, - isInSirTinleysRoom, isInMsHynnRoom, isInSirKuamsRoom, - isInSirSpishyusRoom, isInSirRenItchood, isInladyTableRoom; - - private ConditionalStep conditionalTalkToSirAmikVarze; - - private QuestStep talkToSirTiffy; - - //Sir Tinsley steps - QuestStep doNothingStep, talkToSirTinley, leaveSirTinleyRoom; + // Mid-quest requirements + NoItemRequirement noItemRequirement; + + // Zones + Zone firstFloorZone; + Zone secondFloorZone; + Zone missCheeversZone; + Zone sirTinleyRoomZone; + Zone msHynnRoomZone; + Zone sirKuamRoomZone; + Zone sirSphishyusZone; + Zone sirRenItchoodZone; + Zone ladyTableZone; + + // Miscellaneous requirements + ZoneRequirement isFirstFloorCastle; + ZoneRequirement isSecondFloorCastle; + ZoneRequirement isInMissCheeversRoom; + ZoneRequirement isInSirTinleysRoom; + ZoneRequirement isInMsHynnRoom; + ZoneRequirement isInSirKuamsRoom; + ZoneRequirement isInSirSpishyusRoom; + ZoneRequirement isInSirRenItchood; + ZoneRequirement isInladyTableRoom; + + // Steps + ConditionalStep cTalkToSirAmikVarze; + ObjectStep climbBottomSteps; + ObjectStep climbSecondSteps; + NpcStep talkToSirAmikVarze; + + ObjectStep climbDownSecondFloorStaircase; + ObjectStep climbDownfirstFloorStaircase; + QuestStep talkToSirTiffy; + + // Sir Tinley steps + PuzzleWrapperStep talkToSirTinley; + PuzzleWrapperStep doNothingStep; + ObjectStep leaveSirTinleyRoom; + ConditionalStep sirTinleyStep; // Sir Kuam Ferentse steps - QuestStep talkToSirKuam, killSirLeye, leaveSirKuamRoom; + NpcStep talkToSirKuam; + NpcStep killSirLeye; + PuzzleWrapperStep pwKillSirLeye; + ObjectStep leaveSirKuamRoom; + ConditionalStep sirKuamStep; // Sir Spishyus - QuestStep moveChickenOnRightToLeft, moveFoxOnRightToLeft, moveChickenOnLeftToRight, - moveGrainOnRightToLeft, moveChickenOnRightToLeftAgain, finishedSpishyusRoom; + QuestStep moveChickenOnRightToLeft; + QuestStep moveFoxOnRightToLeft; + QuestStep moveChickenOnLeftToRight; + QuestStep moveGrainOnRightToLeft; + QuestStep moveChickenOnRightToLeftAgain; + QuestStep leaveSirSpishyusRoom; + ConditionalStep sirSpishyusPuzzle; + ConditionalStep cSirSpishyus; + PuzzleWrapperStep pwSirSpishyusStep; // Sir Ren SirRenItchoodStep sirRenStep; // Lady Table LadyTableStep ladyTableStep; + PuzzleWrapperStep pwLadyTableStep; + ObjectStep leaveLadyTableRoom; + ConditionalStep cLadyTableStep; // Ms Hynn - private QuestStep talkToMsHynnTerprett; - private MsHynnAnswerDialogQuizStep msHynnDialogQuiz; - - // Ms Cheeves - private MsCheevesSetup msCheevesSetup; - - @Override - public Map loadSteps() - { - initializeRequirements(); - - return getSteps(); - } - - private Map getSteps() - { - Map steps = new HashMap<>(); - - steps.put(0, TalkToSirAmikVarze()); - steps.put(1, TalkToSirTiffyInFaladorPark()); + MsHynnAnswerDialogQuizStep msHynnDialogQuiz; + PuzzleWrapperStep pwMsHynnTerprett; + ObjectStep leaveMsHynnTerprettRoom; + ConditionalStep msHynnTerprettStep; - return steps; - } - - @Override - protected void setupRequirements() - { - noItemRequirement = new NoItemRequirement("No items or equipment carried", ItemSlots.ANY_EQUIPPED_AND_INVENTORY); - } + // Miss Cheevers + MissCheeversStep missCheeversStep; + PuzzleWrapperStep pwMissCheeversStep; + ObjectStep leaveMissCheeversRoom; + ConditionalStep cMissCheevers; @Override protected void setupZones() { - Zone firstFloorZone = new Zone(new WorldPoint(2954, 3335, 1), + firstFloorZone = new Zone(new WorldPoint(2954, 3335, 1), new WorldPoint(2966, 3343, 1)); - Zone secondFloorZone = new Zone(new WorldPoint(2955, 3334, 2), + secondFloorZone = new Zone(new WorldPoint(2955, 3334, 2), new WorldPoint(2964, 3342, 2)); - Zone sirTinleyRoomZone = new Zone(new WorldPoint(2471, 4954, 0), + missCheeversZone = new Zone(new WorldPoint(2466, 4936, 0), + new WorldPoint(2480, 4947, 0)); + sirTinleyRoomZone = new Zone(new WorldPoint(2471, 4954, 0), new WorldPoint(2481, 4960, 0)); - Zone msHynnRoomZone = new Zone(new WorldPoint(2446, 4934, 0), + msHynnRoomZone = new Zone(new WorldPoint(2446, 4934, 0), new WorldPoint(2457, 4946, 0)); - Zone sirKuamRoomZone = new Zone(new WorldPoint(2453, 4958, 0), + sirKuamRoomZone = new Zone(new WorldPoint(2453, 4958, 0), new WorldPoint(2466, 4970, 0)); - Zone sirSphishyusZone = new Zone(new WorldPoint(2469, 4968, 0), + sirSphishyusZone = new Zone(new WorldPoint(2469, 4968, 0), new WorldPoint(2492, 4980, 0)); - Zone sirRenItchoodZone = new Zone(new WorldPoint(2438, 4952, 0), + sirRenItchoodZone = new Zone(new WorldPoint(2438, 4952, 0), new WorldPoint(2448, 4962, 0)); - Zone ladyTableZone = new Zone(new WorldPoint(2445, 4974, 0), + ladyTableZone = new Zone(new WorldPoint(2445, 4974, 0), new WorldPoint(2461, 4987, 0)); + } + + @Override + protected void setupRequirements() + { + noItemRequirement = new NoItemRequirement("No items or equipment carried", ItemSlots.ANY_EQUIPPED_AND_INVENTORY); isFirstFloorCastle = new ZoneRequirement(firstFloorZone); isSecondFloorCastle = new ZoneRequirement(secondFloorZone); + isInMissCheeversRoom = new ZoneRequirement(missCheeversZone); isInSirTinleysRoom = new ZoneRequirement(sirTinleyRoomZone); isInMsHynnRoom = new ZoneRequirement(msHynnRoomZone); isInSirKuamsRoom = new ZoneRequirement(sirKuamRoomZone); @@ -142,222 +183,282 @@ protected void setupZones() isInladyTableRoom = new ZoneRequirement(ladyTableZone); } - private QuestStep TalkToSirTiffyInFaladorPark() + public void setupSteps() { - WorldPoint firstFloorStairsPosition = new WorldPoint(2955, 3338, 1); - WorldPoint secondFloorStairsPosition = new WorldPoint(2960, 3339, 2); + climbBottomSteps = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRS, new WorldPoint(2955, 3339, 0), + "Climb up the stairs to the first floor on the Falador Castle."); - ObjectStep climbDownSecondFloorStaircase = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRSTOP, - secondFloorStairsPosition, "Climb down the stairs from the second floor."); - ObjectStep climbDownfirstFloorStaircase = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRSTOP, - firstFloorStairsPosition, "Climb down the stairs from the first floor."); + climbSecondSteps = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRS, new WorldPoint(2961, 3339, 1), + "Climb up the stairs to talk to Sir Amik Varze."); + talkToSirAmikVarze = new NpcStep(this, NpcID.SIR_AMIK_VARZE, ""); + talkToSirAmikVarze.addDialogStep("Yes."); - talkToSirTiffy = new NpcStep(this, NpcID.RD_TELEPORTER_GUY, - "Talk to Sir Tiffy Cashien in Falador Park.", noItemRequirement); + climbDownSecondFloorStaircase = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRSTOP, new WorldPoint(2960, 3339, 2), "Climb down the stairs from the second floor."); + climbDownfirstFloorStaircase = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRSTOP, new WorldPoint(2955, 3338, 1), "Climb down the stairs from the first floor."); - ConditionalStep conditionalTalkToSirTiffy = new ConditionalStep(this, talkToSirTiffy); - conditionalTalkToSirTiffy.addStep(isSecondFloorCastle, climbDownSecondFloorStaircase); - conditionalTalkToSirTiffy.addStep(isFirstFloorCastle, climbDownfirstFloorStaircase); + talkToSirTiffy = new NpcStep(this, NpcID.RD_TELEPORTER_GUY, new WorldPoint(2997, 3373, 0), "Talk to Sir Tiffy Cashien in Falador Park.", noItemRequirement); talkToSirTiffy.addDialogStep("Yes, let's go!"); - talkToSirTiffy.addSubSteps(climbDownfirstFloorStaircase, - climbDownSecondFloorStaircase); - getMsCheeves(); + talkToSirTiffy.addSubSteps(climbDownfirstFloorStaircase, climbDownSecondFloorStaircase); - // Testing steps below - conditionalTalkToSirTiffy.addStep(isInSirTinleysRoom, getSirTinley()); - conditionalTalkToSirTiffy.addStep(isInMsHynnRoom, getMsHynnTerprett()); - conditionalTalkToSirTiffy.addStep(isInSirRenItchood, getSirRenItchood()); - conditionalTalkToSirTiffy.addStep(isInladyTableRoom, getLadyTableStep()); - conditionalTalkToSirTiffy.addStep(isInSirSpishyusRoom, getSirSpishyus()); - conditionalTalkToSirTiffy.addStep(isInSirKuamsRoom, getSirKuam()); - - conditionalTalkToSirTiffy.addStep(msCheevesSetup.getIsInMsCheeversRoom(), msCheevesSetup.getConditionalStep()); - return conditionalTalkToSirTiffy; - } + // Testing grounds + // Miss Cheevers + { + missCheeversStep = new MissCheeversStep(this); + pwMissCheeversStep = missCheeversStep.puzzleWrapStepWithDefaultText("Solve Miss Cheevers' puzzle."); + pwMissCheeversStep.conditionToHideInSidebar(new ConfigRequirement(this.getConfig()::solvePuzzles)); - private LadyTableStep getLadyTableStep() - { - this.ladyTableStep = new LadyTableStep(this); - return this.ladyTableStep; - } + leaveMissCheeversRoom = new ObjectStep(this, ObjectID.RD_ROOM6_EXITDOOR, new WorldPoint(2478, 4940, 0), "Leave the room by the second door to enter the portal."); - private QuestStep getSirKuam() - { - VarbitRequirement finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM3_COMPLETE, 1); + var finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM6_COMPLETE, 1); - talkToSirKuam = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_3, "Talk to Sir Kuam Ferentse to have him spawn Sir Leye."); - killSirLeye = new NpcStep(this, NpcID.RD_COMBAT_NPC_ROOM_3, - "Defeat Sir Leye to win this challenge. You must use the steel warhammer or your barehands to deal the final hit on him.", true); + cMissCheevers = new ConditionalStep(this, pwMissCheeversStep); + cMissCheevers.addStep(and(missCheeversStep.hasFirstDoorOpen, missCheeversStep.bronzeKey, finishedRoom), leaveMissCheeversRoom); + } + + // Sir Tinley + { + talkToSirTinley = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_4, "Talk to Sir Tinley. Once you have pressed continue do not do anything or you will fail.").puzzleWrapStepWithDefaultText("Talk to Sir Tinley and solve his puzzle."); + doNothingStep = new DetailedQuestStep(this, "Press Continue and do nothing. Sir Tinley will eventually talk to you and let you pass.").puzzleWrapStepWithDefaultText("Talk to Sir Tinley and solve his puzzle.").withNoHelpHiddenInSidebar(true); + leaveSirTinleyRoom = new ObjectStep(this, ObjectID.RD_ROOM4_EXITDOOR, "Leave through the portal to continue."); - leaveSirKuamRoom = new ObjectStep(this, ObjectID.RD_ROOM3_EXITDOOR, "Leave through the portal to continue."); - NpcCondition npcCondition = new NpcCondition(NpcID.RD_COMBAT_NPC_ROOM_3); + var waitForCondition = new VarbitRequirement(VarbitID.RD_TEMPLOCK_2, 1, Operation.GREATER_EQUAL); + var finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM4_COMPLETE, 1); - ConditionalStep sirKuamConditional = new ConditionalStep(this, talkToSirKuam); + talkToSirTinley.addSubSteps(doNothingStep); - sirKuamConditional.addStep(finishedRoom, leaveSirKuamRoom); - sirKuamConditional.addStep(npcCondition, killSirLeye); - return sirKuamConditional; - } + sirTinleyStep = new ConditionalStep(this, talkToSirTinley); + sirTinleyStep.addStep(finishedRoom, leaveSirTinleyRoom); + sirTinleyStep.addStep(waitForCondition, doNothingStep); + } - private void getMsCheeves() - { - msCheevesSetup = new MsCheevesSetup(this); - } + // Ms Hynn Terprett + { + var finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM7_COMPLETE, 1); - private QuestStep getSirSpishyus() - { - WorldPoint chickenOnLeftPoint = new WorldPoint(2473, 4970, 0); - WorldPoint chickenOnRightPoint = new WorldPoint(2487, 4974, 0); - WorldPoint foxOnRightPoint = new WorldPoint(2485, 4974, 0); - WorldPoint grainOnRightPoint = new WorldPoint(2486, 4974, 0); - - VarbitRequirement foxOnRightSide = new VarbitRequirement(VarbitID.RD_FOXLEFT, 0); - VarbitRequirement foxOnLeftSide = new VarbitRequirement(VarbitID.RD_FOXRIGHT, 1); - VarbitRequirement foxNotOnRightSide = new VarbitRequirement(VarbitID.RD_FOXLEFT, 1); - VarbitRequirement foxNotOnLeftSide = new VarbitRequirement(VarbitID.RD_FOXRIGHT, 0); - VarbitRequirement chickenOnRightSide = new VarbitRequirement(VarbitID.RD_CHICKLEFT, 0); - VarbitRequirement chickenOnLeftSide = new VarbitRequirement(VarbitID.RD_CHICKRIGHT, 1); - VarbitRequirement chickenNotOnRightSide = new VarbitRequirement(VarbitID.RD_CHICKLEFT, 1); - VarbitRequirement chickenNotOnLeftSide = new VarbitRequirement(VarbitID.RD_CHICKRIGHT, 0); - VarbitRequirement grainOnRightSide = new VarbitRequirement(VarbitID.RD_GRAINLEFT, 0); - VarbitRequirement grainOnLeftSide = new VarbitRequirement(VarbitID.RD_GRAINRIGHT, 1); - VarbitRequirement grainNotOnRightSide = new VarbitRequirement(VarbitID.RD_GRAINLEFT, 1); - VarbitRequirement grainNotOnLeftSide = new VarbitRequirement(VarbitID.RD_GRAINRIGHT, 0); - VarbitRequirement finishedSpishyus = new VarbitRequirement(VarbitID.RD_ROOM1_COMPLETE, 1); - - Conditions foxPickedUp = new Conditions(LogicType.AND, foxNotOnLeftSide, foxNotOnRightSide); - Conditions chickenPickedUp = new Conditions(LogicType.AND, chickenNotOnRightSide, chickenNotOnLeftSide); - Conditions grainPickedUp = new Conditions(LogicType.AND, grainNotOnLeftSide, grainNotOnRightSide); - - moveChickenOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI, chickenOnRightPoint, - getSpishyusPickupText("Chicken", true)); - finishedSpishyusRoom = new ObjectStep(this, ObjectID.RD_ROOM1_EXITDOOR, "Leave through the portal to continue."); - - moveFoxOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_FOX_MULTI, foxOnRightPoint, - getSpishyusPickupText("Fox", true)); - - DetailedQuestStep moveChickenToLeft = new DetailedQuestStep(this, getSpishyusMoveText("Chicken", false)); - moveChickenOnRightToLeft.addSubSteps(moveChickenToLeft); - - DetailedQuestStep moveFoxToLeft = new DetailedQuestStep(this, getSpishyusMoveText("Fox", false)); - moveFoxOnRightToLeft.addSubSteps(moveFoxToLeft); - - moveChickenOnLeftToRight = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI_RIGHT, chickenOnLeftPoint, - getSpishyusPickupText("Chicken", false)); - DetailedQuestStep moveChickenToRight = new DetailedQuestStep(this, getSpishyusMoveText("Chicken", true)); - moveChickenOnLeftToRight.addSubSteps(moveChickenToRight); - - moveGrainOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_GRAIN_MULTI, grainOnRightPoint, - getSpishyusPickupText("Grain", true)); - DetailedQuestStep moveGrainToLeft = new DetailedQuestStep(this, getSpishyusMoveText("Grain", false)); - moveGrainOnRightToLeft.addSubSteps(moveGrainToLeft); - - moveChickenOnRightToLeftAgain = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI, chickenOnRightPoint, - getSpishyusPickupText("Chicken", true)); - DetailedQuestStep moveChickenToLeftAgain = new DetailedQuestStep(this, getSpishyusMoveText("Chicken", false)); - moveChickenOnRightToLeftAgain.addSubSteps(moveChickenToLeftAgain); - - ConditionalStep sirSpishyus = new ConditionalStep(this, moveChickenOnRightToLeft); - sirSpishyus.addStep(finishedSpishyus, finishedSpishyusRoom); - - sirSpishyus.addStep(new Conditions(chickenOnRightSide, foxOnRightSide, grainOnRightSide), moveChickenOnRightToLeft); - sirSpishyus.addStep(new Conditions(chickenPickedUp, foxOnRightSide, grainOnRightSide), moveChickenToLeft); - sirSpishyus.addStep(new Conditions(chickenOnLeftSide, foxOnRightSide, grainOnRightSide), moveFoxOnRightToLeft); - sirSpishyus.addStep(new Conditions(chickenOnLeftSide, foxPickedUp, grainOnRightSide), moveFoxToLeft); - sirSpishyus.addStep(new Conditions(chickenOnLeftSide, foxOnLeftSide, grainOnRightSide), moveChickenOnLeftToRight); - sirSpishyus.addStep(new Conditions(chickenPickedUp, foxOnLeftSide, grainOnRightSide), moveChickenToRight); - - sirSpishyus.addStep(new Conditions(chickenOnRightSide, foxOnLeftSide, grainOnRightSide), moveGrainOnRightToLeft); - sirSpishyus.addStep(new Conditions(chickenOnRightSide, foxOnLeftSide, grainPickedUp), moveGrainToLeft); - sirSpishyus.addStep(new Conditions(chickenOnRightSide, foxOnLeftSide, grainOnLeftSide), moveChickenOnRightToLeftAgain); - sirSpishyus.addStep(new Conditions(chickenPickedUp, foxOnLeftSide, grainOnLeftSide), moveChickenToLeftAgain); - - return sirSpishyus; - } + msHynnDialogQuiz = new MsHynnAnswerDialogQuizStep(this); + pwMsHynnTerprett = msHynnDialogQuiz.puzzleWrapStepWithDefaultText("Talk to Ms Hynn Terprett and answer the riddle."); - private String getSpishyusPickupText(String itemName, boolean moveRightToLeft) - { - String firstSide = moveRightToLeft ? "east" : "west"; - String secondSide = moveRightToLeft ? "west" : "east"; - return "Pickup the " + itemName + " on the " + firstSide + " and move it to the " - + secondSide + " side by crossing the bridge"; - } + leaveMsHynnTerprettRoom = new ObjectStep(this, ObjectID.RD_ROOM7_EXITDOOR, "Leave through the door to enter the portal and continue."); - private String getSpishyusMoveText(String itemName, boolean rightSide) - { - String dropSide = rightSide ? "east" : "west"; - return "Cross the bridge to the " + dropSide + " and drop the " + itemName + " from your equipped items."; - } + msHynnTerprettStep = new ConditionalStep(this, pwMsHynnTerprett); + msHynnTerprettStep.addStep(finishedRoom, leaveMsHynnTerprettRoom); + } - private QuestStep getSirRenItchood() - { - NpcStep talkToSirRenItchood = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_5, "Talk to Sir Ren Itchood to receive the clue."); - talkToSirRenItchood.addDialogSteps("Can I have the clue for the door?"); + // Sir Ren Itchood + { + var talkToSirRenItchood = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_5, "Talk to Sir Ren Itchood to receive the clue."); + talkToSirRenItchood.addDialogSteps("Can I have the clue for the door?"); - sirRenStep = new SirRenItchoodStep(this, talkToSirRenItchood); - return sirRenStep; - } + sirRenStep = new SirRenItchoodStep(this, talkToSirRenItchood); + } - private QuestStep getSirTinley() - { - talkToSirTinley = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_4, - "Talk to Sir Tinley. \n Once you have pressed continue do not do anything or you will fail."); - doNothingStep = new DetailedQuestStep(this, - "Press Continue and do nothing. Sir Tinley will eventually talk to you and let you pass."); - leaveSirTinleyRoom = new ObjectStep(this, ObjectID.RD_ROOM4_EXITDOOR, "Leave through the portal to continue."); + // Lady Table + { + ladyTableStep = new LadyTableStep(this); + pwLadyTableStep = ladyTableStep.puzzleWrapStepWithDefaultText("Solve Lady Table's puzzle."); + + leaveLadyTableRoom = new ObjectStep(this, ObjectID.RD_ROOM2_EXITDOOR, "Leave through the door to enter the portal and continue."); + + var finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM2_COMPLETE, 1); + + cLadyTableStep = new ConditionalStep(this, pwLadyTableStep); + cLadyTableStep.addStep(finishedRoom, leaveLadyTableRoom); + } + + // Sir Spishyus + { + var chickenOnLeftPoint = new WorldPoint(2473, 4970, 0); + var chickenOnRightPoint = new WorldPoint(2487, 4974, 0); + var foxOnRightPoint = new WorldPoint(2485, 4974, 0); + var grainOnRightPoint = new WorldPoint(2486, 4974, 0); + + var foxOnRightSide = new VarbitRequirement(VarbitID.RD_FOXLEFT, 0); + var foxOnLeftSide = new VarbitRequirement(VarbitID.RD_FOXRIGHT, 1); + var foxNotOnRightSide = new VarbitRequirement(VarbitID.RD_FOXLEFT, 1); + var foxNotOnLeftSide = new VarbitRequirement(VarbitID.RD_FOXRIGHT, 0); + var chickenOnRightSide = new VarbitRequirement(VarbitID.RD_CHICKLEFT, 0); + var chickenOnLeftSide = new VarbitRequirement(VarbitID.RD_CHICKRIGHT, 1); + var chickenNotOnRightSide = new VarbitRequirement(VarbitID.RD_CHICKLEFT, 1); + var chickenNotOnLeftSide = new VarbitRequirement(VarbitID.RD_CHICKRIGHT, 0); + var grainOnRightSide = new VarbitRequirement(VarbitID.RD_GRAINLEFT, 0); + var grainOnLeftSide = new VarbitRequirement(VarbitID.RD_GRAINRIGHT, 1); + var grainNotOnRightSide = new VarbitRequirement(VarbitID.RD_GRAINLEFT, 1); + var grainNotOnLeftSide = new VarbitRequirement(VarbitID.RD_GRAINRIGHT, 0); + var finishedSpishyus = new VarbitRequirement(VarbitID.RD_ROOM1_COMPLETE, 1); + + var westSide = new Zone(new WorldPoint(2472, 4976, 0), new WorldPoint(2479, 4968, 0)); + var playerOnWestSide = new ZoneRequirement(westSide); + var playerOnEastSide = not(playerOnWestSide); + + var foxPickedUp = and(foxNotOnLeftSide, foxNotOnRightSide); + var chickenPickedUp = and(chickenNotOnRightSide, chickenNotOnLeftSide); + var grainPickedUp = and(grainNotOnLeftSide, grainNotOnRightSide); + + moveChickenOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI, chickenOnRightPoint, getSpishyusPickupText("Chicken", true)).puzzleWrapStep(true); + + moveFoxOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_FOX_MULTI, foxOnRightPoint, getSpishyusPickupText("Fox", true)).puzzleWrapStep(true); + + var moveChickenToLeft = new ObjectStep(this, ObjectID.RD_BRIDGE_LEFT, new WorldPoint(2483, 4972, 0), getSpishyusMoveText("Chicken", false)); + moveChickenToLeft.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveChickenOnRightToLeft).getSolvingStep().addSubSteps(moveChickenToLeft); + + var moveFoxToWest = new ObjectStep(this, ObjectID.RD_BRIDGE_LEFT, new WorldPoint(2483, 4972, 0), getSpishyusMoveText("Fox", false)); + moveFoxToWest.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveFoxOnRightToLeft).getSolvingStep().addSubSteps(moveFoxToWest); + + moveChickenOnLeftToRight = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI_RIGHT, chickenOnLeftPoint, getSpishyusPickupText("Chicken", false)).puzzleWrapStep(true); + var moveChickenToRight = new ObjectStep(this, ObjectID.RD_BRIDGE_RIGHT, new WorldPoint(2477, 4972, 0), getSpishyusMoveText("Chicken", true)); + moveChickenToRight.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveChickenOnLeftToRight).getSolvingStep().addSubSteps(moveChickenToRight); + + moveGrainOnRightToLeft = new ObjectStep(this, ObjectID.RD_ROOM2_GRAIN_MULTI, grainOnRightPoint, getSpishyusPickupText("Grain", true)).puzzleWrapStep(true); + var moveGrainToLeft = new ObjectStep(this, ObjectID.RD_BRIDGE_LEFT, new WorldPoint(2483, 4972, 0), getSpishyusMoveText("Grain", false)); + moveGrainToLeft.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveGrainOnRightToLeft).getSolvingStep().addSubSteps(moveGrainToLeft); + + moveChickenOnRightToLeftAgain = new ObjectStep(this, ObjectID.RD_ROOM2_CHICKEN_MULTI, chickenOnRightPoint, getSpishyusPickupText("Chicken", true)).puzzleWrapStep(true); + var moveChickenToLeftAgain = new ObjectStep(this, ObjectID.RD_BRIDGE_LEFT, new WorldPoint(2483, 4972, 0), getSpishyusMoveText("Chicken", false)); + moveChickenToLeftAgain.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveChickenOnRightToLeftAgain).getSolvingStep().addSubSteps(moveChickenToLeftAgain); + + sirSpishyusPuzzle = new ConditionalStep(this, moveChickenOnRightToLeft, "Solve Sir Spishyus' riddle."); - VarbitRequirement waitForCondition = new VarbitRequirement(VarbitID.RD_TEMPLOCK_2, 1, Operation.GREATER_EQUAL); - VarbitRequirement finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM4_COMPLETE, 1); + var dropChickenWest = new DetailedQuestStep(this, "Drop the Chicken on the west side from your equipped items."); + ((PuzzleWrapperStep) moveChickenOnRightToLeft).getSolvingStep().addSubSteps(dropChickenWest); + + // 1. Move Chicken from east to west + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnRightSide, grainOnRightSide), moveChickenOnRightToLeft); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnRightSide, grainOnRightSide, playerOnEastSide), moveChickenToLeft); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnRightSide, grainOnRightSide), dropChickenWest); - ConditionalStep sirTinleyStep = new ConditionalStep(this, talkToSirTinley); - sirTinleyStep.addStep(finishedRoom, leaveSirTinleyRoom); - sirTinleyStep.addStep(waitForCondition, doNothingStep); + var moveToEastSide1 = new ObjectStep(this, ObjectID.RD_BRIDGE_RIGHT, new WorldPoint(2477, 4972, 0), "Cross the bridge to the east side."); + moveToEastSide1.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveFoxOnRightToLeft).getSolvingStep().addSubSteps(moveToEastSide1); - return sirTinleyStep; + var dropFoxWest = new DetailedQuestStep(this, "Drop the Fox on the west side from your equipped items."); + ((PuzzleWrapperStep) moveFoxOnRightToLeft).getSolvingStep().addSubSteps(dropFoxWest); + + // 2. Return to east side, then move Fox from east to west + sirSpishyusPuzzle.addStep(and(chickenOnLeftSide, foxOnRightSide, grainOnRightSide, playerOnWestSide), moveToEastSide1); + sirSpishyusPuzzle.addStep(and(chickenOnLeftSide, foxOnRightSide, grainOnRightSide), moveFoxOnRightToLeft); + sirSpishyusPuzzle.addStep(and(chickenOnLeftSide, foxPickedUp, grainOnRightSide, playerOnEastSide), moveFoxToWest); + sirSpishyusPuzzle.addStep(and(chickenOnLeftSide, foxPickedUp, grainOnRightSide), dropFoxWest); + + var dropChickenEast = new DetailedQuestStep(this, "Drop the Chicken on the east side from your equipped items."); + ((PuzzleWrapperStep) moveChickenOnLeftToRight).getSolvingStep().addSubSteps(dropChickenEast); + + // 3. Move chicken from west to east + sirSpishyusPuzzle.addStep(and(chickenOnLeftSide, foxOnLeftSide, grainOnRightSide), moveChickenOnLeftToRight); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnLeftSide, grainOnRightSide, playerOnWestSide), moveChickenToRight); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnLeftSide, grainOnRightSide), dropChickenEast); + + var dropGrainWest = new DetailedQuestStep(this, "Drop the Grain on the west side from your equipped items."); + ((PuzzleWrapperStep) moveGrainOnRightToLeft).getSolvingStep().addSubSteps(dropGrainWest); + + // 4. Move grain from east to west + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnLeftSide, grainOnRightSide), moveGrainOnRightToLeft); + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnLeftSide, grainPickedUp, playerOnEastSide), moveGrainToLeft); + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnLeftSide, grainPickedUp), dropGrainWest); + + var moveToEastSide2 = new ObjectStep(this, ObjectID.RD_BRIDGE_RIGHT, new WorldPoint(2477, 4972, 0), "Cross the bridge to the east side."); + moveToEastSide2.setForceClickboxHighlight(true); + ((PuzzleWrapperStep) moveChickenOnRightToLeftAgain).getSolvingStep().addSubSteps(moveToEastSide2); + + var dropChickenWest2 = new DetailedQuestStep(this, "Drop the Chicken on the west side from your equipped items."); + ((PuzzleWrapperStep) moveChickenOnRightToLeftAgain).getSolvingStep().addSubSteps(dropChickenWest2); + + // 5. Cross the bridge to the east, then move the chicken from east to west + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnLeftSide, grainOnLeftSide, playerOnWestSide), moveToEastSide2); + sirSpishyusPuzzle.addStep(and(chickenOnRightSide, foxOnLeftSide, grainOnLeftSide), moveChickenOnRightToLeftAgain); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnLeftSide, grainOnLeftSide, playerOnEastSide), moveChickenToLeftAgain); + sirSpishyusPuzzle.addStep(and(chickenPickedUp, foxOnLeftSide, grainOnLeftSide), dropChickenWest2); + + pwSirSpishyusStep = sirSpishyusPuzzle.puzzleWrapStepWithDefaultText("Solve Sir Spishyus' riddle."); + pwSirSpishyusStep.conditionToHideInSidebar(new ConfigRequirement(this.getConfig()::solvePuzzles)); + + leaveSirSpishyusRoom = new ObjectStep(this, ObjectID.RD_ROOM1_EXITDOOR, "Leave through the portal to continue."); + + cSirSpishyus = new ConditionalStep(this, pwSirSpishyusStep); + cSirSpishyus.addStep(finishedSpishyus, leaveSirSpishyusRoom); + } + + // Sir Kuam + { + var finishedRoom = new VarbitRequirement(VarbitID.RD_ROOM3_COMPLETE, 1); + + talkToSirKuam = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_3, "Talk to Sir Kuam Ferentse to have him spawn Sir Leye."); + killSirLeye = new NpcStep(this, NpcID.RD_COMBAT_NPC_ROOM_3, "Defeat Sir Leye to win this challenge. You must use the steel warhammer or your bare hands to deal the final hit on him.", true); + pwKillSirLeye = killSirLeye.puzzleWrapStepWithDefaultText("Defeat Sir Leye to win this challenge."); + + leaveSirKuamRoom = new ObjectStep(this, ObjectID.RD_ROOM3_EXITDOOR, "Leave through the portal to continue."); + var npcCondition = new NpcCondition(NpcID.RD_COMBAT_NPC_ROOM_3); + + sirKuamStep = new ConditionalStep(this, talkToSirKuam); + sirKuamStep.addStep(finishedRoom, leaveSirKuamRoom); + sirKuamStep.addStep(npcCondition, pwKillSirLeye); + } } - private QuestStep getMsHynnTerprett() + @Override + public Map loadSteps() { - talkToMsHynnTerprett = new NpcStep(this, NpcID.RD_OBSERVER_ROOM_7, - "Talk to Ms Hynn Terprett and answer the riddle."); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + cTalkToSirAmikVarze = new ConditionalStep(this, climbBottomSteps, "Talk to Sir Amik Varze."); + cTalkToSirAmikVarze.addStep(isFirstFloorCastle, climbSecondSteps); + cTalkToSirAmikVarze.addStep(isSecondFloorCastle, talkToSirAmikVarze); + steps.put(0, cTalkToSirAmikVarze); + + var cTestingGrounds = new ConditionalStep(this, talkToSirTiffy); + cTestingGrounds.addStep(isSecondFloorCastle, climbDownSecondFloorStaircase); + cTestingGrounds.addStep(isFirstFloorCastle, climbDownfirstFloorStaircase); + + // Testing steps below + cTestingGrounds.addStep(isInMissCheeversRoom, cMissCheevers); + cTestingGrounds.addStep(isInSirTinleysRoom, sirTinleyStep); + cTestingGrounds.addStep(isInMsHynnRoom, msHynnTerprettStep); + cTestingGrounds.addStep(isInSirRenItchood, sirRenStep); + cTestingGrounds.addStep(isInladyTableRoom, cLadyTableStep); + cTestingGrounds.addStep(isInSirSpishyusRoom, cSirSpishyus); + cTestingGrounds.addStep(isInSirKuamsRoom, sirKuamStep); + + steps.put(1, cTestingGrounds); - msHynnDialogQuiz = new MsHynnAnswerDialogQuizStep(this, talkToMsHynnTerprett); - return msHynnDialogQuiz; + return steps; } - private QuestStep TalkToSirAmikVarze() + private String getSpishyusPickupText(String itemName, boolean moveRightToLeft) { - WorldPoint bottomStairsPosition = new WorldPoint(2955, 3339, 0); - WorldPoint secondStairsPosition = new WorldPoint(2961, 3339, 1); - ObjectStep climbBottomSteps = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRS, bottomStairsPosition, - "Climb up the stairs to the first floor on the Falador Castle."); + String firstSide = moveRightToLeft ? "east" : "west"; + String secondSide = moveRightToLeft ? "west" : "east"; + return "Pick up the " + itemName + " on the " + firstSide + " and move it to the " + + secondSide + " side by crossing the bridge"; + } - ObjectStep climbSecondSteps = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_SPIRALSTAIRS, secondStairsPosition, - "Climb up the stairs to talk to Sir Amik Vaze."); - NpcStep talkToSirAmikVarze = new NpcStep(this, NpcID.SIR_AMIK_VARZE, ""); - talkToSirAmikVarze.addDialogStep("Yes please"); - - conditionalTalkToSirAmikVarze = new ConditionalStep(this, climbBottomSteps, - "Talk to Sir Amik Varze."); - conditionalTalkToSirAmikVarze.addStep(isFirstFloorCastle, climbSecondSteps); - conditionalTalkToSirAmikVarze.addStep(isSecondFloorCastle, talkToSirAmikVarze); - conditionalTalkToSirAmikVarze.addSubSteps(climbSecondSteps, climbBottomSteps, talkToSirAmikVarze); - return conditionalTalkToSirAmikVarze; + private String getSpishyusMoveText(String itemName, boolean rightSide) + { + String dropSide = rightSide ? "east" : "west"; + return "Cross the bridge to the " + dropSide + " and drop the " + itemName + " from your equipped items."; } @Override - public List getCombatRequirements() + public List getGeneralRequirements() { - return Collections.singletonList("Sir Leye (level 20) with no items"); + return List.of( + new QuestRequirement(QuestHelperQuest.BLACK_KNIGHTS_FORTRESS, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED) + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(new QuestRequirement(QuestHelperQuest.BLACK_KNIGHTS_FORTRESS, QuestState.FINISHED)); - reqs.add(new QuestRequirement(QuestHelperQuest.DRUIDIC_RITUAL, QuestState.FINISHED)); - return reqs; + return List.of( + "Sir Leye (level 20) with no items" + ); } @Override @@ -369,69 +470,87 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Arrays.asList( - new ExperienceReward(Skill.PRAYER, 1000), - new ExperienceReward(Skill.AGILITY, 1000), - new ExperienceReward(Skill.HERBLORE, 1000)); + return List.of( + new ExperienceReward(Skill.PRAYER, 1000), + new ExperienceReward(Skill.AGILITY, 1000), + new ExperienceReward(Skill.HERBLORE, 1000) + ); } @Override public List getItemRewards() { - return Arrays.asList( - new ItemReward("Initiate Helm", ItemID.BASIC_TK_HELM, 1), - new ItemReward("Coins", ItemID.COINS, 3000)); + return List.of( + new ItemReward("Initiate Helm", ItemID.BASIC_TK_HELM, 1), + new ItemReward("Coins", ItemID.COINS, 3000) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("Ability to respawn in Falador"), - new UnlockReward("Access to Initiate Armor")); + return List.of( + new UnlockReward("Ability to respawn in Falador"), + new UnlockReward("Access to Initiate Armor") + ); } @Override public List getPanels() { - List steps = new ArrayList<>(); - - PanelDetails startingPanel = new PanelDetails("Starting out", - new ArrayList<>(Collections.singletonList(conditionalTalkToSirAmikVarze))); - - PanelDetails testing = new PanelDetails("Start the testing", - Collections.singletonList(talkToSirTiffy), noItemRequirement); - - PanelDetails sirTinleysRoom = new PanelDetails("Sir Tinley", - Arrays.asList(talkToSirTinley, doNothingStep, leaveSirTinleyRoom)); - - List hynnSteps = new ArrayList<>(); - hynnSteps.add(talkToMsHynnTerprett); - hynnSteps.addAll(msHynnDialogQuiz.getPanelSteps()); - PanelDetails msHynnsRoom = new PanelDetails("Ms Hynn Terprett", hynnSteps); - - PanelDetails sirKuamRoom = new PanelDetails("Sir Kuam", - Arrays.asList(talkToSirKuam, killSirLeye, leaveSirKuamRoom)); - - PanelDetails sirSpishyusRoom = new PanelDetails("Sir Spishyus", - Arrays.asList(moveChickenOnRightToLeft, moveFoxOnRightToLeft, - moveChickenOnLeftToRight, moveGrainOnRightToLeft, moveChickenOnRightToLeftAgain)); - - PanelDetails sirRensRoom = new PanelDetails("Sir Ren Itchood", sirRenStep.getPanelSteps()); - - PanelDetails missCheeversRoom = new PanelDetails("Mis Cheevers", msCheevesSetup.GetPanelSteps()); - - PanelDetails ladyTable = new PanelDetails("Lady Table", ladyTableStep.getPanelSteps()); - - steps.add(startingPanel); - steps.add(testing); - steps.add(sirKuamRoom); - steps.add(sirSpishyusRoom); - steps.add(msHynnsRoom); - steps.add(sirTinleysRoom); - steps.add(sirRensRoom); - steps.add(missCheeversRoom); - steps.add(ladyTable); - return steps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting out", List.of( + cTalkToSirAmikVarze + ))); + + sections.add(new PanelDetails("Start the testing", List.of( + talkToSirTiffy + ), List.of( + noItemRequirement + ))); + + sections.add(new PanelDetails("Sir Tinley", List.of( + talkToSirTinley, + doNothingStep, + leaveSirTinleyRoom + ))); + + sections.add(new PanelDetails("Ms. Hynn Terprett", List.of( + pwMsHynnTerprett, + leaveMsHynnTerprettRoom + ))); + + sections.add(new PanelDetails("Sir Kuam Ferentse", List.of( + talkToSirKuam, + pwKillSirLeye, + leaveSirKuamRoom + ))); + + sections.add(new PanelDetails("Sir Spishyus", List.of( + pwSirSpishyusStep, + moveChickenOnRightToLeft, + moveFoxOnRightToLeft, + moveChickenOnLeftToRight, + moveGrainOnRightToLeft, + moveChickenOnRightToLeftAgain, + leaveSirSpishyusRoom + ))); + + sections.add(new PanelDetails("Sir Ren Itchood", + sirRenStep.getPanelSteps() + )); + + var missCheeversSection = new PanelDetails("Miss Cheevers", pwMissCheeversStep); + missCheeversSection.addSteps(missCheeversStep.getPanelSteps()); + missCheeversSection.addSteps(leaveMissCheeversRoom); + sections.add(missCheeversSection); + + sections.add(new PanelDetails("Lady Table", List.of( + pwLadyTableStep, + leaveLadyTableRoom + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/SirRenItchoodStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/SirRenItchoodStep.java index b7c1e17cf3..1ef8b3219f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/SirRenItchoodStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/recruitmentdrive/SirRenItchoodStep.java @@ -27,31 +27,29 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.List; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.List; - public class SirRenItchoodStep extends ConditionalStep { - private String answer = null; - - private String[] answers = { + private final String[] answers = { "NULL", "TIME", "FISH", "RAIN", "BITE", "MEAT", "LAST" }; + private final QuestStep talkToRen; - private Requirement answerWidgetOpen; - private DoorPuzzle enterDoorcode; - private QuestStep talkToRen, openAnswerWidget, leaveRoom; - private VarbitRequirement finishedRoomCondition; + private DoorPuzzle enterDoorCode; + private PuzzleWrapperStep pwEnterDoorCode; + private QuestStep tryOpenDoor; + private QuestStep leaveRoom; public SirRenItchoodStep(QuestHelper questHelper, QuestStep step, Requirement... requirements) { @@ -71,42 +69,48 @@ public void startUp() return; } String answer = answers[answerID]; - enterDoorcode.updateWord(answer); + enterDoorCode.updateWord(answer); } @Override public void onVarbitChanged(VarbitChanged varbitChanged) { super.onVarbitChanged(varbitChanged); - int answerID = client.getVarbitValue(VarbitID.RD_TEMPLOCK_1); + + if (varbitChanged.getVarbitId() != VarbitID.RD_TEMPLOCK_1) + { + return; + } + var answerID = varbitChanged.getValue(); if (answerID == 0) { return; } - String answer = answers[answerID]; - enterDoorcode.updateWord(answer); + var answer = answers[answerID]; + enterDoorCode.updateWord(answer); } private void addRenSteps() { - finishedRoomCondition = new VarbitRequirement(VarbitID.RD_ROOM5_COMPLETE, 1); - openAnswerWidget = new ObjectStep(questHelper, ObjectID.RD_ROOM5_EXITDOOR, "Open the door to be prompted to enter a code."); - answerWidgetOpen = new WidgetTextRequirement(285, 55, "Combination Lock Door"); - enterDoorcode = new DoorPuzzle(questHelper, "NONE"); + var finishedRoomCondition = new VarbitRequirement(VarbitID.RD_ROOM5_COMPLETE, 1); + var answerWidgetOpen = new WidgetTextRequirement(InterfaceID.RdCombolock.RDCOMBOLOCK, "Combination Lock Door"); + tryOpenDoor = new ObjectStep(questHelper, ObjectID.RD_ROOM5_EXITDOOR, "Open the door to be prompted to enter a code."); + enterDoorCode = new DoorPuzzle(questHelper, "NONE"); + pwEnterDoorCode = enterDoorCode.puzzleWrapStepWithDefaultText("Solve the door combination lock using the hints from Sir Ren Itchood."); leaveRoom = new ObjectStep(questHelper, ObjectID.RD_ROOM5_EXITDOOR, "Leave through the door to enter the portal and continue."); addStep(finishedRoomCondition, leaveRoom); - addStep(new Conditions(answerWidgetOpen), enterDoorcode); - addStep(null, openAnswerWidget); + addStep(answerWidgetOpen, pwEnterDoorCode); + addStep(null, tryOpenDoor); } public List getPanelSteps() { - List steps = new ArrayList<>(); - steps.add(talkToRen); - steps.add(openAnswerWidget); - steps.add(enterDoorcode); - steps.add(leaveRoom); - return steps; + return List.of( + talkToRen, + tryOpenDoor, + pwEnterDoorCode, + leaveRoom + ); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/romeoandjuliet/RomeoAndJuliet.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/romeoandjuliet/RomeoAndJuliet.java index 8ef44238f4..a3429528a9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/romeoandjuliet/RomeoAndJuliet.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/romeoandjuliet/RomeoAndJuliet.java @@ -27,6 +27,7 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; @@ -34,17 +35,14 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; public class RomeoAndJuliet extends BasicQuestHelper { @@ -151,7 +149,7 @@ public Map loadSteps() steps.put(50, bringPotionToJuliet); var cFinishQuest = new ConditionalStep(this, finishQuest); - cFinishQuest.addStep(inJulietRoom, goDownstairsToFinishQuest); + giveLetterToRomeo.addStep(inJulietRoom, goDownstairsToFinishQuest); steps.put(60, cFinishQuest); return steps; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/runemysteries/RuneMysteries.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/runemysteries/RuneMysteries.java index c09884adb5..ec48d061e4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/runemysteries/RuneMysteries.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/runemysteries/RuneMysteries.java @@ -29,6 +29,7 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -40,19 +41,16 @@ import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.util.QHObjectID; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class RuneMysteries extends BasicQuestHelper { // Recommended items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scorpioncatcher/ScorpionCatcher.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scorpioncatcher/ScorpionCatcher.java index c9f9666182..a72acc34f3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scorpioncatcher/ScorpionCatcher.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scorpioncatcher/ScorpionCatcher.java @@ -6,19 +6,27 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.KeyringRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -26,71 +34,82 @@ import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class ScorpionCatcher extends BasicQuestHelper { - ItemRequirement dustyKey, jailKey, scorpionCageMissingTaverley, scorpionCageMissingMonastery, scorpionCageEmptyOrTaverley, scorpionCageTaverleyAndMonastery, scorpionCageFull, food, - antiDragonShield, antiPoison, teleRunesFalador, gamesNecklace, gloryOrCombatBracelet, camelotTeleport; - QuestRequirement fairyRingAccess; - Zone sorcerersTower3, sorcerersTower2, sorcerersTower1, taverleyDungeon, deepTaverleyDungeon1, deepTaverleyDungeon2, deepTaverleyDungeon3, deepTaverleyDungeon4, - jailCell, taverleyScorpionRoom, upstairsMonastery, barbarianOutpost; - Requirement has70Agility, has80Agility, inTaverleyDungeon, inDeepTaverleyDungeon, inJailCell, inSorcerersTower1, inSorcerersTower2, - inSorcerersTower3, inTaverleyScorpionRoom, inUpstairsMonastery, inBarbarianOutpost, jailKeyNearby; - QuestStep speakToThormac, speakToSeer1, enterTaverleyDungeon, goThroughPipe, goOverStrangeFloor, killJailerForKey, - getDustyFromAdventurer, enterDeeperTaverley, pickUpJailKey, - searchOldWall, catchTaverleyScorpion, sorcerersTowerLadder0, sorcerersTowerLadder1, sorcerersTowerLadder2, enterMonastery, catchMonasteryScorpion, - catchOutpostScorpion, enterOutpost, returnToThormac; - + // Required items + ItemRequirement dustyKey; + + // Recommended items + ItemRequirement antiDragonShield; + ItemRequirement antiPoison; + ItemRequirement food; + ItemRequirement teleRunesFalador; + ItemRequirement camelotTeleport; + ItemRequirement gamesNecklace; + ItemRequirement gloryOrCombatBracelet; + + // Mid-quest item requirements + ItemRequirement jailKey; + ItemRequirement scorpionCageMissingTaverley; + ItemRequirement scorpionCageMissingMonastery; + ItemRequirement scorpionCageEmptyOrTaverley; + ItemRequirement scorpionCageTaverleyAndMonastery; + ItemRequirement scorpionCageFull; + + // Zones + Zone sorcerersTower3; + Zone sorcerersTower2; + Zone sorcerersTower1; + Zone taverleyDungeon; + Zone deepTaverleyDungeon1; + Zone deepTaverleyDungeon2; + Zone deepTaverleyDungeon3; + Zone deepTaverleyDungeon4; + Zone jailCell; + Zone taverleyScorpionRoom; + Zone upstairsMonastery; + Zone barbarianOutpost; + + // Miscellaneous requirements + SkillRequirement has70Agility; + SkillRequirement has80Agility; + ZoneRequirement inTaverleyDungeon; + ZoneRequirement inDeepTaverleyDungeon; + ZoneRequirement inJailCell; + ZoneRequirement inSorcerersTower1; + ZoneRequirement inSorcerersTower2; + ZoneRequirement inSorcerersTower3; + ZoneRequirement inTaverleyScorpionRoom; + ZoneRequirement inUpstairsMonastery; + ZoneRequirement inBarbarianOutpost; + ItemOnTileRequirement jailKeyNearby; + + // Steps + ObjectStep sorcerersTowerLadder0; + ObjectStep sorcerersTowerLadder1; + ObjectStep sorcerersTowerLadder2; + ConditionalStep goToTopOfTower; + + ConditionalStep beginQuest; + NpcStep speakToThormac; + + NpcStep speakToSeer1; + QuestStep enterTaverleyDungeon; + ObjectStep goThroughPipe; + ObjectStep goOverStrangeFloor; + NpcStep killJailerForKey; + NpcStep getDustyFromAdventurer; + ObjectStep enterDeeperTaverley; + ItemStep pickUpJailKey; + ObjectStep searchOldWall; + NpcStep catchTaverleyScorpion; + ObjectStep enterMonastery; + NpcStep catchMonasteryScorpion; + NpcStep catchOutpostScorpion; + ObjectStep enterOutpost; + NpcStep returnToThormac; ConditionalStep finishQuest; - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - - Map steps = new HashMap<>(); - - ConditionalStep goToTopOfTower = new ConditionalStep(this, sorcerersTowerLadder0); - goToTopOfTower.addStep(inSorcerersTower1, sorcerersTowerLadder1); - goToTopOfTower.addStep(inSorcerersTower2, sorcerersTowerLadder2); - - ConditionalStep beginQuest = new ConditionalStep(this, goToTopOfTower); - beginQuest.addStep(inSorcerersTower3, speakToThormac); - - finishQuest = new ConditionalStep(this, goToTopOfTower, - "Return to Thormac to finish the quest.", scorpionCageFull); - finishQuest.addStep(inSorcerersTower3, returnToThormac); - - ConditionalStep goGetTaverleyScorpion = new ConditionalStep(this, enterTaverleyDungeon); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyScorpionRoom), catchTaverleyScorpion); - goGetTaverleyScorpion.addStep(new Conditions(inDeepTaverleyDungeon), searchOldWall); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon, has80Agility), goOverStrangeFloor); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon, has70Agility), goThroughPipe); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon, dustyKey), enterDeeperTaverley); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon, new Conditions(LogicType.OR, inJailCell, jailKey)), getDustyFromAdventurer); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon, jailKeyNearby), pickUpJailKey); - goGetTaverleyScorpion.addStep(new Conditions(inTaverleyDungeon), killJailerForKey); - - ConditionalStep scorpions = new ConditionalStep(this, finishQuest); - scorpions.addStep(scorpionCageMissingTaverley.alsoCheckBank(), goGetTaverleyScorpion); - - scorpions.addStep(new Conditions(scorpionCageMissingMonastery, inUpstairsMonastery), catchMonasteryScorpion); - scorpions.addStep(scorpionCageMissingMonastery.alsoCheckBank(), enterMonastery); - - scorpions.addStep(new Conditions(scorpionCageTaverleyAndMonastery, inBarbarianOutpost), catchOutpostScorpion); - scorpions.addStep(scorpionCageTaverleyAndMonastery.alsoCheckBank(), enterOutpost); - - steps.put(0, beginQuest); - steps.put(1, speakToSeer1); - steps.put(2, scorpions); - steps.put(3, scorpions); - - return steps; - } - @Override protected void setupZones() { @@ -114,8 +133,13 @@ protected void setupZones() @Override protected void setupRequirements() { - dustyKey = new KeyringRequirement("Dusty Key", configManager, KeyringCollection.DUSTY_KEY).isNotConsumed(); + has70Agility = new SkillRequirement(Skill.AGILITY, 70, true); + has80Agility = new SkillRequirement(Skill.AGILITY, 80, true); + + dustyKey = new KeyringRequirement("Dusty Key", KeyringCollection.DUSTY_KEY).isNotConsumed(); dustyKey.setTooltip("Not needed if you have level 70 Agility, can be obtained during the quest"); + dustyKey.setConditionToHide(has70Agility); + jailKey = new ItemRequirement("Jail Key", ItemID.JAIL_KEY); scorpionCageMissingTaverley = new ItemRequirement("Scorpion Cage", ItemID.SCORPIONCAGEEMPTY); @@ -143,15 +167,6 @@ protected void setupRequirements() gamesNecklace = new ItemRequirement("Games Necklace", ItemCollections.GAMES_NECKLACES); gloryOrCombatBracelet = new ItemRequirement("A charged glory or a combat bracelet", ItemCollections.AMULET_OF_GLORIES); gloryOrCombatBracelet.addAlternates(ItemCollections.COMBAT_BRACELETS); - fairyRingAccess = new QuestRequirement(QuestHelperQuest.FAIRYTALE_II__CURE_A_QUEEN, QuestState.IN_PROGRESS, "Fairy ring access"); - fairyRingAccess.setTooltip(QuestHelperQuest.FAIRYTALE_II__CURE_A_QUEEN.getName() + " is required to at least be started in order to use fairy rings"); - - } - - private void setupConditions() - { - has70Agility = new SkillRequirement(Skill.AGILITY, 70, true); - has80Agility = new SkillRequirement(Skill.AGILITY, 80, true); inSorcerersTower1 = new ZoneRequirement(sorcerersTower1); inSorcerersTower2 = new ZoneRequirement(sorcerersTower2); @@ -170,34 +185,26 @@ private void setupConditions() private void setupSteps() { - speakToThormac = new NpcStep(this, NpcID.THORMAC, new WorldPoint(2702, 3405, 3), "Speak to Thormac on the top floor of the Sorcerer's Tower south of Seer's Village."); + sorcerersTowerLadder0 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2701, 3408, 0), "Climb to the top of the Sorcerer's Tower south of Seers' Village."); + sorcerersTowerLadder1 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2704, 3403, 1), "Climb to the top of the Sorcerer's Tower south of Seers' Village."); + sorcerersTowerLadder2 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2699, 3405, 2), "Climb to the top of the Sorcerer's Tower south of Seers' Village."); + + goToTopOfTower = new ConditionalStep(this, sorcerersTowerLadder0); + goToTopOfTower.addStep(inSorcerersTower1, sorcerersTowerLadder1); + goToTopOfTower.addStep(inSorcerersTower2, sorcerersTowerLadder2); + + speakToThormac = new NpcStep(this, NpcID.THORMAC, new WorldPoint(2702, 3405, 3), ""); speakToThormac.addDialogStep("What do you need assistance with?"); - speakToThormac.addDialogStep("So how would I go about catching them then?"); - speakToThormac.addDialogStep("Ok, I will do it then"); - - sorcerersTowerLadder0 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2701, 3408, 0), - "Climb to the top of the Sorcerer's Tower south of Seers' Village."); - sorcerersTowerLadder1 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2704, 3403, 1), - "Climb to the top of the Sorcerer's Tower south of Seers' Village."); - sorcerersTowerLadder2 = new ObjectStep(this, ObjectID.LADDER, new WorldPoint(2699, 3405, 2), - "Climb to the top of the Sorcerer's Tower south of Seers' Village."); - speakToThormac.addSubSteps(sorcerersTowerLadder0, sorcerersTowerLadder1, sorcerersTowerLadder2); - - speakToSeer1 = new NpcStep(this, NpcID.SEER, new WorldPoint(2710, 3484, 0), - "Speak to a seer in Seer's Village."); + speakToThormac.addDialogStep("Yes."); + + beginQuest = new ConditionalStep(this, goToTopOfTower, "Speak to Thormac on the top floor of the Sorcerer's Tower south of Seer's Village."); + beginQuest.addStep(inSorcerersTower3, speakToThormac); + + speakToSeer1 = new NpcStep(this, NpcID.SEER, new WorldPoint(2710, 3484, 0), "Speak to a seer in Seer's Village."); speakToSeer1.addDialogStep("I need to locate some scorpions."); speakToSeer1.addDialogStep("Your friend Thormac sent me to speak to you."); - if (client.getRealSkillLevel(Skill.AGILITY) >= 70) - { - enterTaverleyDungeon = new ObjectStep(this, ObjectID.LADDER_OUTSIDE_TO_UNDERGROUND, new WorldPoint(2884, 3397, 0), - "Go to Taverley Dungeon. As you're 70 Agility, you don't need a dusty key.", scorpionCageMissingTaverley); - } - else - { - enterTaverleyDungeon = new ObjectStep(this, ObjectID.LADDER_OUTSIDE_TO_UNDERGROUND, new WorldPoint(2884, 3397, 0), - "Go to Taverley Dungeon. Bring a dusty key if you have one, otherwise you can get one in the dungeon.", scorpionCageMissingTaverley, dustyKey); - } + enterTaverleyDungeon = new ObjectStep(this, ObjectID.LADDER_OUTSIDE_TO_UNDERGROUND, new WorldPoint(2884, 3397, 0), "Go to Taverley Dungeon.", scorpionCageMissingTaverley, dustyKey); goOverStrangeFloor = new ObjectStep(this, ObjectID.TAVERLY_DUNGEON_FLOOR_SPIKES_SC, new WorldPoint(2879, 9813, 0), "Go over the strange floor."); @@ -212,53 +219,99 @@ private void setupSteps() getDustyFromAdventurer.addDialogStep("Yes please!"); enterDeeperTaverley = new ObjectStep(this, ObjectID.DEEPDUNGEONDOOR, new WorldPoint(2924, 9803, 0), "Enter the gate to the deeper Taverley dungeon.", dustyKey); - enterTaverleyDungeon.addSubSteps(goThroughPipe, goOverStrangeFloor, killJailerForKey, getDustyFromAdventurer, enterDeeperTaverley); + enterTaverleyDungeon.addSubSteps(goThroughPipe, goOverStrangeFloor, killJailerForKey, pickUpJailKey, getDustyFromAdventurer, enterDeeperTaverley); searchOldWall = new ObjectStep(this, ObjectID.SCORPIONWALL, new WorldPoint(2875, 9799, 0), "Search the Old wall."); - // TODO: Highlight item - catchTaverleyScorpion = new NpcStep(this, NpcID.QUESTSCORPIONA, "Use the scorpion cage on the scorpion.", scorpionCageMissingTaverley); + catchTaverleyScorpion = new NpcStep(this, NpcID.QUESTSCORPIONA, "Use the scorpion cage on the scorpion.", scorpionCageMissingTaverley.highlighted()); catchTaverleyScorpion.addIcon(ItemID.SCORPIONCAGEEMPTY); - enterMonastery = new ObjectStep(this, ObjectID.MONASTERYLADDER, new WorldPoint(3057, 3483, 0), - "Enter the Edgeville Monastery."); - // TODO: Highlight item - catchMonasteryScorpion = new NpcStep(this, NpcID.QUESTSCORPIONC, "Use the scorpion cage on the scorpion.", - scorpionCageMissingMonastery); + enterMonastery = new ObjectStep(this, ObjectID.MONASTERYLADDER, new WorldPoint(3057, 3483, 0), "Enter the Edgeville Monastery."); + enterMonastery.addDialogStep("Well can I join your order?"); + catchMonasteryScorpion = new NpcStep(this, NpcID.QUESTSCORPIONC, "Use the scorpion cage on the scorpion.", scorpionCageMissingMonastery.highlighted()); catchMonasteryScorpion.addIcon(ItemID.SCORPIONCAGEEMPTY); - enterOutpost = new ObjectStep(this, ObjectID.BARBARIANGATEL, new WorldPoint(2545, 3570, 0), - "Enter the Barbarian Outpost."); - // TODO: Highlight item - catchOutpostScorpion = new NpcStep(this, NpcID.QUESTSCORPIONB, new WorldPoint(2553, 3570, 0), - "Use the scorpion cage on the scorpion.", scorpionCageTaverleyAndMonastery); + enterOutpost = new ObjectStep(this, ObjectID.BARBARIANGATEL, new WorldPoint(2545, 3570, 0), "Enter the Barbarian Outpost."); + catchOutpostScorpion = new NpcStep(this, NpcID.QUESTSCORPIONB, new WorldPoint(2553, 3570, 0), "Use the scorpion cage on the scorpion.", scorpionCageTaverleyAndMonastery.highlighted()); catchOutpostScorpion.addIcon(ItemID.SCORPIONCAGEEMPTY); - returnToThormac = new NpcStep(this, NpcID.THORMAC, - "", scorpionCageFull); + returnToThormac = new NpcStep(this, NpcID.THORMAC, "", scorpionCageFull); + + finishQuest = new ConditionalStep(this, goToTopOfTower, "Return to Thormac to finish the quest.", scorpionCageFull); + finishQuest.addStep(inSorcerersTower3, returnToThormac); + } + + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, beginQuest); + steps.put(1, speakToSeer1); + + var goGetTaverleyScorpion = new ConditionalStep(this, enterTaverleyDungeon); + goGetTaverleyScorpion.addStep(and(inTaverleyScorpionRoom), catchTaverleyScorpion); + goGetTaverleyScorpion.addStep(and(inDeepTaverleyDungeon), searchOldWall); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon, has80Agility), goOverStrangeFloor); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon, has70Agility), goThroughPipe); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon, dustyKey), enterDeeperTaverley); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon, or(inJailCell, jailKey)), getDustyFromAdventurer); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon, jailKeyNearby), pickUpJailKey); + goGetTaverleyScorpion.addStep(and(inTaverleyDungeon), killJailerForKey); + + var scorpions = new ConditionalStep(this, finishQuest); + scorpions.addStep(scorpionCageMissingTaverley.alsoCheckBank(), goGetTaverleyScorpion); + + scorpions.addStep(and(scorpionCageMissingMonastery, inUpstairsMonastery), catchMonasteryScorpion); + scorpions.addStep(scorpionCageMissingMonastery.alsoCheckBank(), enterMonastery); + + scorpions.addStep(and(scorpionCageTaverleyAndMonastery, inBarbarianOutpost), catchOutpostScorpion); + scorpions.addStep(scorpionCageTaverleyAndMonastery.alsoCheckBank(), enterOutpost); + + steps.put(2, scorpions); + steps.put(3, scorpions); + + return steps; } @Override - public ArrayList getItemRequirements() + public List getGeneralRequirements() { - ArrayList reqs = new ArrayList<>(); - if (client.getRealSkillLevel(Skill.AGILITY) < 70) - { - reqs.add(dustyKey); - } + return List.of( + new QuestRequirement(QuestHelperQuest.ALFRED_GRIMHANDS_BARCRAWL, QuestState.FINISHED), + new SkillRequirement(Skill.PRAYER, 31) + ); + } - return reqs.isEmpty() ? null : reqs; + @Override + public List getItemRequirements() + { + return List.of( + dustyKey + ); } @Override - public ArrayList getItemRecommended() + public List getItemRecommended() { - return new ArrayList<>(Arrays.asList(antiDragonShield, antiPoison, food, teleRunesFalador, camelotTeleport, gamesNecklace, - gloryOrCombatBracelet)); + return List.of( + antiDragonShield, + antiPoison, + food, + teleRunesFalador, + camelotTeleport, + gamesNecklace, + gloryOrCombatBracelet + ); } @Override - public ArrayList getCombatRequirements() + public List getCombatRequirements() { - return new ArrayList<>(Collections.singletonList("The ability to run past level 172 black demons and level 64 poison spiders")); + return List.of( + "The ability to run past level 172 black demons and level 64 poison spiders" + ); } @Override @@ -270,36 +323,52 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.STRENGTH, 6625)); + return List.of( + new ExperienceReward(Skill.STRENGTH, 6625) + ); } @Override public List getUnlockRewards() { - return Collections.singletonList(new UnlockReward("Ability to have Thormac turn a Battlestaff into a Mystic Staff for 40,000 Coins.")); + return List.of( + new UnlockReward("Ability to have Thormac turn a Battlestaff into a Mystic Staff for 40,000 Coins.") + ); } @Override - public ArrayList getPanels() + public List getPanels() { - ArrayList allSteps = new ArrayList<>(); - - allSteps.add(new PanelDetails("Talk to Thormac", new ArrayList<>(Collections.singletonList(speakToThormac)))); - allSteps.add(new PanelDetails("The first scorpion", new ArrayList<>(Arrays.asList(speakToSeer1, enterTaverleyDungeon, searchOldWall, catchTaverleyScorpion)))); - allSteps.add(new PanelDetails("The second scorpion", new ArrayList<>(Arrays.asList(enterMonastery, catchMonasteryScorpion)))); - allSteps.add(new PanelDetails("The third scorpion", new ArrayList<>(Arrays.asList(enterOutpost, catchOutpostScorpion)))); - allSteps.add(new PanelDetails("Finishing up", new ArrayList<>(Collections.singletonList(finishQuest)))); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Talk to Thormac", List.of( + beginQuest + ))); + + sections.add(new PanelDetails("The first scorpion", List.of( + speakToSeer1, + enterTaverleyDungeon, + searchOldWall, + catchTaverleyScorpion + ), List.of( + dustyKey + ))); + + sections.add(new PanelDetails("The second scorpion", List.of( + enterMonastery, + catchMonasteryScorpion + ))); + + sections.add(new PanelDetails("The third scorpion", List.of( + enterOutpost, + catchOutpostScorpion + ))); + + sections.add(new PanelDetails("Finishing up", List.of( + finishQuest + ))); + + return sections; } - @Override - public ArrayList getGeneralRequirements() - { - ArrayList reqs = new ArrayList<>(); - reqs.add(new QuestRequirement(QuestHelperQuest.ALFRED_GRIMHANDS_BARCRAWL, QuestState.FINISHED)); - reqs.add(new SkillRequirement(Skill.PRAYER, 31)); - - return reqs; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/EggSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/EggSolver.java index 0e7d7940a2..d69b6fa6d3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/EggSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/EggSolver.java @@ -32,15 +32,14 @@ import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; +import java.awt.*; +import java.util.List; +import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.gameval.InterfaceID; import net.runelite.api.widgets.Widget; -import javax.annotation.Nullable; -import java.awt.*; -import java.util.List; - @Slf4j public class EggSolver extends DetailedOwnerStep { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/Scrambled.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/Scrambled.java index 69ed9eef58..cd2246d656 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/Scrambled.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/scrambled/Scrambled.java @@ -30,6 +30,7 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcHintArrowRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; @@ -43,10 +44,6 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.*; -import net.runelite.api.QuestState; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; import java.util.ArrayList; import java.util.HashMap; @@ -54,7 +51,17 @@ import java.util.Map; import java.util.regex.Pattern; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.QuestState; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.VarbitID; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; /** * The quest guide for the "Scrambled" OSRS quest diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/seaslug/SeaSlug.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/seaslug/SeaSlug.java index 4804a8acf8..63e4083bac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/seaslug/SeaSlug.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/seaslug/SeaSlug.java @@ -27,45 +27,151 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class SeaSlug extends BasicQuestHelper { - //Items Required - ItemRequirement swampPaste, glass, dampSticks, torch, litTorch, drySticks; + // Required items + ItemRequirement swampPaste; + + // Mid-quest requirements + ItemRequirement glass; + ItemRequirement dampSticks; + ItemRequirement torch; + ItemRequirement litTorch; + ItemRequirement drySticks; + + // Zones + Zone platformFirstFloor; + Zone platformGroundFloor; + Zone island; + + // Miscellaneous requirements + ZoneRequirement onPlatformGroundFloor; + ZoneRequirement onPlatformFirstFloor; + ZoneRequirement onPlatform; + ZoneRequirement onIsland; + + // Steps + NpcStep talkToCaroline; + NpcStep talkToHolgart; + NpcStep talkToHolgartWithSwampPaste; + NpcStep travelWithHolgart; + DetailedQuestStep pickupGlass; + DetailedQuestStep pickupDampSticks; + ObjectStep climbLadder; + NpcStep talkToKennith; + ObjectStep goDownLadder; + NpcStep goToIsland; + NpcStep goToIslandFromMainland; + NpcStep talkToKent; + NpcStep returnFromIsland; + NpcStep talkToBaileyForTorch; + DetailedQuestStep useGlassOnDampSticks; + DetailedQuestStep rubSticks; + ObjectStep goBackUpLadder; + NpcStep talkToKennithAgain; + ObjectStep kickWall; + NpcStep talkToKennithAfterKicking; + ObjectStep activateCrane; + ObjectStep goDownLadderAgain; + NpcStep returnWithHolgart; + NpcStep finishQuest; + NpcStep travelWithHolgartFreeingKennith; - Requirement onPlatformGroundFloor, onPlatformFirstFloor, onPlatform, onIsland; + @Override + protected void setupZones() + { + platformGroundFloor = new Zone(new WorldPoint(2760, 3271, 0), new WorldPoint(2795, 3293, 0)); + platformFirstFloor = new Zone(new WorldPoint(2760, 3271, 1), new WorldPoint(2795, 3293, 1)); + island = new Zone(new WorldPoint(2787, 3312, 0), new WorldPoint(2802, 3327, 0)); + } - QuestStep talkToCaroline, talkToHolgart, talkToHolgartWithSwampPaste, travelWithHolgart, pickupGlass, pickupDampSticks, - climbLadder, talkToKennith, goDownLadder, goToIsland, goToIslandFromMainland, talkToKent, returnFromIsland, talkToBaileyForTorch, useGlassOnDampSticks, - rubSticks, goBackUpLadder, talkToKennithAgain, kickWall, talkToKennithAfterKicking, activateCrane, goDownLadderAgain, - returnWithHolgart, finishQuest, travelWithHolgartFreeingKennith; + @Override + protected void setupRequirements() + { + swampPaste = new ItemRequirement("Swamp paste", ItemID.SWAMPPASTE); + dampSticks = new ItemRequirement("Damp sticks", ItemID.DAMP_STICKS); + dampSticks.setHighlightInInventory(true); + drySticks = new ItemRequirement("Dry sticks", ItemID.DRY_STICKS); + drySticks.setHighlightInInventory(true); + torch = new ItemRequirement("Unlit torch", ItemID.TORCH_UNLIT); + litTorch = new ItemRequirement("Lit torch", ItemID.TORCH_LIT); + glass = new ItemRequirement("Broken glass", ItemID.BROKEN_GLASS); + glass.setHighlightInInventory(true); - //Zones - Zone platformFirstFloor, platformGroundFloor, island; + onPlatformFirstFloor = new ZoneRequirement(platformFirstFloor); + onPlatformGroundFloor = new ZoneRequirement(platformGroundFloor); + onPlatform = new ZoneRequirement(platformFirstFloor, platformGroundFloor); + onIsland = new ZoneRequirement(island); + } + + public void setupSteps() + { + talkToCaroline = new NpcStep(this, NpcID.CAROLINE, new WorldPoint(2717, 3303, 0), "Talk to Caroline just north of Witchaven, east of East Ardougne."); + talkToCaroline.addDialogStep("Yes."); + talkToHolgart = new NpcStep(this, NpcID.HOLGARTLANDNOTRAVEL, new WorldPoint(2717, 3303, 0), "Talk to Holgart nearby and give him some swamp paste.", swampPaste); + talkToHolgartWithSwampPaste = new NpcStep(this, NpcID.HOLGARTLANDNOTRAVEL, new WorldPoint(2717, 3303, 0), "Give Holgart some swamp paste.", swampPaste); + talkToHolgart.addSubSteps(talkToHolgartWithSwampPaste); + travelWithHolgart = new NpcStep(this, NpcID.HOLGARTLANDTRAVEL, new WorldPoint(2717, 3303, 0), "Travel with Holgart to the fishing platform."); + travelWithHolgart.addDialogStep("Will you take me there?"); + climbLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER, new WorldPoint(2784, 3286, 0), "Climb the ladder in the north east corner of the platform."); + talkToKennith = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith from inside the cabin on the west side of the first floor."); + goDownLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER_TOP, new WorldPoint(2784, 3286, 1), "Go back down the ladder."); + goToIsland = new NpcStep(this, NpcID.HOLGARTPLATFORM, new WorldPoint(2781, 3274, 0), "Travel with Holgart to a nearby island."); + goToIslandFromMainland = new NpcStep(this, NpcID.HOLGARTLANDTRAVEL, new WorldPoint(2717, 3303, 0), "Travel with Holgart north of Witchaven to find Kent."); + goToIsland.addSubSteps(goToIslandFromMainland); + + talkToKent = new NpcStep(this, NpcID.KENT, new WorldPoint(2794, 3322, 0), "Talk to Kent on the island."); + returnFromIsland = new NpcStep(this, NpcID.HOLGARTSUNKBOAT, new WorldPoint(2801, 3320, 0), "Return to the platform with Holgart."); + travelWithHolgartFreeingKennith = new NpcStep(this, NpcID.HOLGARTSUNKBOAT, new WorldPoint(2717, 3303, 0), + "Travel with Holgart to the fishing platform."); + returnFromIsland.addSubSteps(travelWithHolgartFreeingKennith); + + talkToBaileyForTorch = new NpcStep(this, NpcID.BAILEY, new WorldPoint(2764, 3275, 0), "Talk to Bailey for an unlit torch."); + pickupGlass = new DetailedQuestStep(this, "Pick up the broken glass in the room.", glass); + pickupDampSticks = new DetailedQuestStep(this, new WorldPoint(2784, 3289, 0), "Pick up the damp sticks in the north east corner of the platform.", dampSticks); + useGlassOnDampSticks = new DetailedQuestStep(this, "Use the broken glass on damp sticks to dry them.", glass, dampSticks); + rubSticks = new DetailedQuestStep(this, "Rub the dry sticks to light the unlit torch.", drySticks.highlighted()); + goBackUpLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER, new WorldPoint(2784, 3286, 0), "Go up the ladder in the north east corner of the platform."); + talkToKennithAgain = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith to the west."); + kickWall = new ObjectStep(this, ObjectID.SLUG_BREAKABLE_PANEL, new WorldPoint(2768, 3289, 1), "Kick in the badly repaired wall east of Kennith."); + talkToKennithAfterKicking = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith again."); + activateCrane = new ObjectStep(this, ObjectID.SEASLUG_CRANE, new WorldPoint(2772, 3289, 1), "Rotate the crane east of Kennith's cabin."); + goDownLadderAgain = new ObjectStep(this, ObjectID.SEASLUG_LADDER_TOP, new WorldPoint(2784, 3286, 1), "Go back down the ladder."); + returnWithHolgart = new NpcStep(this, NpcID.HOLGARTPLATFORM, new WorldPoint(2781, 3274, 0), "Travel with Holgart back to the mainland."); + finishQuest = new NpcStep(this, NpcID.CAROLINE, new WorldPoint(2717, 3303, 0), "Talk to Caroline to complete the quest."); + } @Override public Map loadSteps() { initializeRequirements(); - setupConditions(); setupSteps(); - Map steps = new HashMap<>(); + + var steps = new HashMap(); steps.put(0, talkToCaroline); @@ -73,57 +179,57 @@ public Map loadSteps() steps.put(2, talkToHolgartWithSwampPaste); - ConditionalStep investigateThePlatform = new ConditionalStep(this, travelWithHolgart); + var investigateThePlatform = new ConditionalStep(this, travelWithHolgart); investigateThePlatform.addStep(onPlatformFirstFloor, talkToKennith); investigateThePlatform.addStep(onPlatformGroundFloor, climbLadder); steps.put(3, investigateThePlatform); - ConditionalStep goFindKent = new ConditionalStep(this, travelWithHolgart); + var goFindKent = new ConditionalStep(this, travelWithHolgart); goFindKent.addStep(onPlatformGroundFloor, goToIsland); goFindKent.addStep(onPlatformFirstFloor, goDownLadder); steps.put(4, goFindKent); - ConditionalStep talkWithKent = new ConditionalStep(this, goToIslandFromMainland); + var talkWithKent = new ConditionalStep(this, goToIslandFromMainland); talkWithKent.addStep(onIsland, talkToKent); steps.put(5, talkWithKent); - ConditionalStep goToFirstFloor = new ConditionalStep(this, travelWithHolgartFreeingKennith); - goToFirstFloor.addStep(new Conditions(litTorch), goBackUpLadder); - goToFirstFloor.addStep(new Conditions(torch, drySticks), rubSticks); - goToFirstFloor.addStep(new Conditions(torch, glass, dampSticks), useGlassOnDampSticks); - goToFirstFloor.addStep(new Conditions(torch, glass), pickupDampSticks); - goToFirstFloor.addStep(new Conditions(torch), pickupGlass); + var goToFirstFloor = new ConditionalStep(this, travelWithHolgartFreeingKennith); + goToFirstFloor.addStep(litTorch, goBackUpLadder); + goToFirstFloor.addStep(and(torch, drySticks), rubSticks); + goToFirstFloor.addStep(and(torch, glass, dampSticks), useGlassOnDampSticks); + goToFirstFloor.addStep(and(torch, glass), pickupDampSticks); + goToFirstFloor.addStep(torch, pickupGlass); goToFirstFloor.addStep(onPlatform, talkToBaileyForTorch); - ConditionalStep lightTheTorch = new ConditionalStep(this, goToFirstFloor); + var lightTheTorch = new ConditionalStep(this, goToFirstFloor); lightTheTorch.addStep(onIsland, returnFromIsland); steps.put(6, lightTheTorch); - ConditionalStep freeKennith = new ConditionalStep(this, goToFirstFloor); + var freeKennith = new ConditionalStep(this, goToFirstFloor); freeKennith.addStep(onPlatformFirstFloor, talkToKennithAgain); steps.put(7, freeKennith); - ConditionalStep breakWall = new ConditionalStep(this, goToFirstFloor); + var breakWall = new ConditionalStep(this, goToFirstFloor); breakWall.addStep(onPlatformFirstFloor, kickWall); steps.put(8, breakWall); - ConditionalStep tellKennethYouBrokeWall = new ConditionalStep(this, goToFirstFloor); + var tellKennethYouBrokeWall = new ConditionalStep(this, goToFirstFloor); tellKennethYouBrokeWall.addStep(onPlatformFirstFloor, talkToKennithAfterKicking); steps.put(9, tellKennethYouBrokeWall); - ConditionalStep turnTheCrane = new ConditionalStep(this, goToFirstFloor); + var turnTheCrane = new ConditionalStep(this, goToFirstFloor); turnTheCrane.addStep(onPlatformFirstFloor, activateCrane); steps.put(10, turnTheCrane); - ConditionalStep finishUp = new ConditionalStep(this, finishQuest); + var finishUp = new ConditionalStep(this, finishQuest); finishUp.addStep(onPlatformGroundFloor, returnWithHolgart); finishUp.addStep(onPlatformFirstFloor, goDownLadderAgain); @@ -133,85 +239,27 @@ public Map loadSteps() } @Override - protected void setupRequirements() - { - swampPaste = new ItemRequirement("Swamp paste", ItemID.SWAMPPASTE); - dampSticks = new ItemRequirement("Damp sticks", ItemID.DAMP_STICKS); - dampSticks.setHighlightInInventory(true); - drySticks = new ItemRequirement("Dry sticks", ItemID.DRY_STICKS); - drySticks.setHighlightInInventory(true); - torch = new ItemRequirement("Unlit torch", ItemID.TORCH_UNLIT); - litTorch = new ItemRequirement("Lit torch", ItemID.TORCH_LIT); - glass = new ItemRequirement("Broken glass", ItemID.BROKEN_GLASS); - glass.setHighlightInInventory(true); - - } - - @Override - protected void setupZones() - { - platformGroundFloor = new Zone(new WorldPoint(2760, 3271, 0), new WorldPoint(2795, 3293, 0)); - platformFirstFloor = new Zone(new WorldPoint(2760, 3271, 1), new WorldPoint(2795, 3293, 1)); - island = new Zone(new WorldPoint(2787, 3312, 0), new WorldPoint(2802, 3327, 0)); - } - - public void setupConditions() - { - onPlatformFirstFloor = new ZoneRequirement(platformFirstFloor); - onPlatformGroundFloor = new ZoneRequirement(platformGroundFloor); - onPlatform = new ZoneRequirement(platformFirstFloor, platformGroundFloor); - onIsland = new ZoneRequirement(island); - } - - public void setupSteps() + public List getGeneralRequirements() { - talkToCaroline = new NpcStep(this, NpcID.CAROLINE, new WorldPoint(2717, 3303, 0), "Talk to Caroline just north of Witchaven, east of East Ardougne."); - talkToCaroline.addDialogStep("I suppose so, how do I get there?"); - talkToHolgart = new NpcStep(this, NpcID.HOLGARTLANDNOTRAVEL, new WorldPoint(2717, 3303, 0), "Talk to Holgart nearby and give him some swamp paste.", swampPaste); - talkToHolgartWithSwampPaste = new NpcStep(this, NpcID.HOLGARTLANDNOTRAVEL, new WorldPoint(2717, 3303, 0), "Give Holgart some swamp paste.", swampPaste); - talkToHolgart.addSubSteps(talkToHolgartWithSwampPaste); - travelWithHolgart = new NpcStep(this, NpcID.HOLGARTLANDTRAVEL, new WorldPoint(2717, 3303, 0), "Travel with Holgart to the fishing platform."); - travelWithHolgart.addDialogStep("Will you take me there?"); - climbLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER, new WorldPoint(2784, 3286, 0), "Climb the ladder in the north east corner of the platform."); - talkToKennith = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith from inside the cabin on the west side of the first floor."); - goDownLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER_TOP, new WorldPoint(2784, 3286, 1), "Go back down the ladder."); - goToIsland = new NpcStep(this, NpcID.HOLGARTPLATFORM, new WorldPoint(2781, 3274, 0), "Travel with Holgart to a nearby island."); - goToIslandFromMainland = new NpcStep(this, NpcID.HOLGARTLANDTRAVEL, new WorldPoint(2717, 3303, 0), "Travel with Holgart north of Witchaven to find Kent."); - goToIsland.addSubSteps(goToIsland); - - talkToKent = new NpcStep(this, NpcID.KENT, new WorldPoint(2794, 3322, 0), "Talk to Kent on the island."); - returnFromIsland = new NpcStep(this, NpcID.HOLGARTSUNKBOAT, new WorldPoint(2801, 3320, 0), "Return to the platform with Holgart."); - travelWithHolgartFreeingKennith = new NpcStep(this, NpcID.HOLGARTSUNKBOAT, new WorldPoint(2717, 3303, 0), - "Travel with Holgart to the fishing platform."); - returnFromIsland.addSubSteps(travelWithHolgartFreeingKennith); - - talkToBaileyForTorch = new NpcStep(this, NpcID.BAILEY, new WorldPoint(2764, 3275, 0), "Talk to Bailey for an unlit torch."); - pickupGlass = new DetailedQuestStep(this, "Pick up the broken glass in the room.", glass); - pickupDampSticks = new DetailedQuestStep(this, new WorldPoint(2784, 3289, 0), "Pick up the damp sticks in the north east corner of the platform.", dampSticks); - useGlassOnDampSticks = new DetailedQuestStep(this, "Use the broken glass on damp sticks to dry them.", glass, dampSticks); - rubSticks = new DetailedQuestStep(this, "Rub the dry sticks to light the unlit torch."); - goBackUpLadder = new ObjectStep(this, ObjectID.SEASLUG_LADDER, new WorldPoint(2784, 3286, 0), "Go up the ladder in the north east corner of the platform."); - talkToKennithAgain = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith to the west."); - kickWall = new ObjectStep(this, ObjectID.SLUG_BREAKABLE_PANEL, new WorldPoint(2768, 3289, 1), "Kick in the badly repaired wall east of Kennith."); - talkToKennithAfterKicking = new NpcStep(this, NpcID.KENNITH_PLATFORM, new WorldPoint(2765, 3289, 1), "Talk to Kennith again."); - activateCrane = new ObjectStep(this, ObjectID.SEASLUG_CRANE, new WorldPoint(2772, 3289, 1), "Rotate the crane east of Kennith's cabin."); - goDownLadderAgain = new ObjectStep(this, ObjectID.SEASLUG_LADDER_TOP, new WorldPoint(2784, 3286, 1), "Go back down the ladder."); - returnWithHolgart = new NpcStep(this, NpcID.HOLGARTPLATFORM, new WorldPoint(2781, 3274, 0), "Travel with Holgart back to the mainland."); - finishQuest = new NpcStep(this, NpcID.CAROLINE, new WorldPoint(2717, 3303, 0), "Talk to Caroline to complete the quest."); + return List.of( + new SkillRequirement(Skill.FIREMAKING, 30, true) + ); } @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(swampPaste); - return reqs; + return List.of( + swampPaste + ); } @Override - public List getGeneralRequirements() + public List getNotes() { - return Collections.singletonList(new SkillRequirement(Skill.FIREMAKING, 30, true)); + return List.of( + "You can complete an Ardougne Medium Diary task by fishing from the fishing platform using a fishing rod or small fishing net (these can be bought from the fishing shop near quest start in Witchaven)." + ); } @Override @@ -223,35 +271,68 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.FISHING, 7125)); + return List.of( + new ExperienceReward(Skill.FISHING, 7175) + ); } @Override - public List getUnlockRewards() + public List getItemRewards() { - return Collections.singletonList(new UnlockReward("Access to the Fishing Platform")); + return List.of( + new ItemReward("Oyster pearls", ItemID.BIGOYSTERPEARLS, 1) + ); } - + @Override - public List getPanels() + public List getUnlockRewards() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Collections.singletonList(talkToCaroline), - swampPaste)); - allSteps.add(new PanelDetails("Investigation", Arrays.asList(talkToHolgart, travelWithHolgart, - climbLadder, talkToKennith, goDownLadder, goToIsland))); - allSteps.add(new PanelDetails("Talking with Kent", Arrays.asList(talkToKent, returnFromIsland))); - allSteps.add(new PanelDetails("Saving Kennith", - Arrays.asList(talkToBaileyForTorch, pickupGlass, pickupDampSticks, useGlassOnDampSticks, rubSticks, goBackUpLadder, - talkToKennithAgain, kickWall, talkToKennithAfterKicking, activateCrane, goDownLadderAgain, returnWithHolgart, - finishQuest))); - - return allSteps; + return List.of( + new UnlockReward("Access to the Fishing Platform") + ); } @Override - public List getNotes() + public List getPanels() { - return Collections.singletonList("You can complete an Ardougne Medium Diary task by fishing from the fishing platform using a fishing rod or small fishing net (these can be bought from the fishing shop near quest start in Witchaven)."); + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToCaroline + ), List.of( + swampPaste + ))); + + sections.add(new PanelDetails("Investigation", List.of( + talkToHolgart, + travelWithHolgart, + climbLadder, + talkToKennith, + goDownLadder, + goToIsland + ))); + + sections.add(new PanelDetails("Talking with Kent", List.of( + talkToKent, + returnFromIsland + ))); + + sections.add(new PanelDetails("Saving Kennith", List.of( + talkToBaileyForTorch, + pickupGlass, + pickupDampSticks, + useGlassOnDampSticks, + rubSticks, + goBackUpLadder, + talkToKennithAgain, + kickWall, + talkToKennithAfterKicking, + activateCrane, + goDownLadderAgain, + returnWithHolgart, + finishQuest + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/IncantationStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/IncantationStep.java index d181368198..5f98e76393 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/IncantationStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/IncantationStep.java @@ -31,13 +31,10 @@ import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.gameval.InterfaceID; -import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.VarbitID; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; -import java.util.Collections; - public class IncantationStep extends DetailedQuestStep { /** @@ -87,12 +84,9 @@ public class IncantationStep extends DetailedQuestStep private String[] incantationOrder; private int incantationPosition = 0; - public IncantationStep(QuestHelper questHelper, boolean reverse) + public IncantationStep(QuestHelper questHelper, boolean reverse, ItemRequirement sigilHighlighted) { - super(questHelper, "Click the demonic sigil and read the incantation."); - ItemRequirement sigilHighlighted = new ItemRequirement("Demonic sigil", ItemID.AGRITH_SIGIL); - sigilHighlighted.setHighlightInInventory(true); - this.addItemRequirements(Collections.singletonList(sigilHighlighted)); + super(questHelper, "Click the demonic sigil and read the incantation.", sigilHighlighted); this.reverse = reverse; } @@ -100,6 +94,7 @@ public IncantationStep(QuestHelper questHelper, boolean reverse) public void startUp() { super.startUp(); + incantationPosition = 0; updateHints(); } @@ -123,16 +118,17 @@ public void onMenuOptionClicked(MenuOptionClicked event) { var widget = event.getWidget(); - if (widget == null) { + if (widget == null) + { return; } - if (widget.getId() != InterfaceID.INVENTORY) + if (widget.getId() != InterfaceID.Inventory.ITEMS) { return; } - if ("Chant".equals(event.getMenuOption())) + if (event.getMenuOption().equals("Chant")) { incantationPosition = 0; } @@ -190,7 +186,8 @@ protected void updateHints() return; } - if (reverse) { + if (reverse) + { incantationOrder = new String[]{ WORDS[client.getVarbitValue(INCANTATION_WORD_5)], WORDS[client.getVarbitValue(INCANTATION_WORD_4)], @@ -198,7 +195,9 @@ protected void updateHints() WORDS[client.getVarbitValue(INCANTATION_WORD_2)], WORDS[client.getVarbitValue(INCANTATION_WORD_1)], }; - } else { + } + else + { incantationOrder = new String[]{ WORDS[client.getVarbitValue(INCANTATION_WORD_1)], WORDS[client.getVarbitValue(INCANTATION_WORD_2)], @@ -211,5 +210,6 @@ protected void updateHints() setText("Click the demonic sigil and read the incantation."); addText(incantString); + addText("If the highlight feels wrong, click the demonic sigil again."); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/SearchKilns.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/SearchKilns.java deleted file mode 100644 index 36faf85953..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/SearchKilns.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.helpers.quests.shadowofthestorm; - -import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; -import net.runelite.client.plugins.microbot.questhelper.steps.DetailedOwnerStep; -import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; -import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.GameTick; -import net.runelite.api.gameval.ObjectID; -import net.runelite.api.gameval.VarbitID; -import net.runelite.client.eventbus.Subscribe; - -import java.util.Arrays; -import java.util.Collection; - -public class SearchKilns extends DetailedOwnerStep -{ - ObjectStep searchKiln1, searchKiln2, searchKiln3, searchKiln4; - - public SearchKilns(QuestHelper questHelper) - { - super(questHelper, "Search the kilns in Uzer until you find a book."); - } - - @Subscribe - public void onGameTick(GameTick event) - { - updateSteps(); - } - - @Override - protected void updateSteps() - { - int correctKiln = client.getVarbitValue(VarbitID.AGRITH_KILN); - if (correctKiln == 0) - { - startUpStep(searchKiln1); - } - else if (correctKiln == 1) - { - startUpStep(searchKiln2); - } - else if (correctKiln == 2) - { - startUpStep(searchKiln3); - } - else if (correctKiln == 3) - { - startUpStep(searchKiln4); - } - } - - @Override - protected void setupSteps() - { - searchKiln1 = new ObjectStep(getQuestHelper(), ObjectID.AGRITH_KILN_1, new WorldPoint(3468, 3124, 0), "Search the kilns in Uzer until you find a book."); - searchKiln2 = new ObjectStep(getQuestHelper(), ObjectID.AGRITH_KILN_2, new WorldPoint(3479, 3083, 0), "Search the kilns in Uzer until you find a book."); - searchKiln3 = new ObjectStep(getQuestHelper(), ObjectID.AGRITH_KILN_3, new WorldPoint(3473, 3093, 0), "Search the kilns in Uzer until you find a book."); - searchKiln4 = new ObjectStep(getQuestHelper(), ObjectID.AGRITH_KILN_4, new WorldPoint(3501, 3085, 0), "Search the kilns in Uzer until you find a book."); - } - - @Override - public Collection getSteps() - { - return Arrays.asList(searchKiln1, searchKiln2, searchKiln3, searchKiln4); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/ShadowOfTheStorm.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/ShadowOfTheStorm.java index 8682b25778..621b8dd6f5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/ShadowOfTheStorm.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowofthestorm/ShadowOfTheStorm.java @@ -30,18 +30,31 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.PuzzleWrapperStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.runelite.client.plugins.microbot.questhelper.steps.TileStep; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -50,118 +63,105 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - public class ShadowOfTheStorm extends BasicQuestHelper { - //Items Required - ItemRequirement darkItems, silverlight, strangeImplement, blackMushroomInk, pestle, vial, silverBar, silverlightHighlighted, blackMushroomHighlighted, - silverlightDyedEquipped, sigilMould, silverlightDyed, strangeImplementHighlighted, sigil, book, bookHighlighted, - sigilHighlighted, sigil2; - - //Items Recommended - ItemRequirement combatGear, coinsForCarpet, alKharidTeleport; - - Requirement inRuin, inThroneRoom,talkedToGolem, talkedToMatthew, inCircleSpot, sigilNearby, evilDaveMoved, baddenMoved, - reenMoved, golemMoved, golemRejected, golemReprogrammed, - inSecondCircleSpot; - - DetailedQuestStep talkToReen, talkToBadden, pickMushroom, dyeSilverlight, goIntoRuin, pickUpStrangeImplement, talkToEvilDave, enterPortal, - talkToDenath, talkToJennifer, talkToMatthew, smeltSigil, talkToGolem, readBook, enterRuinAfterBook, enterPortalAfterBook, - talkToMatthewAfterBook, standInCircle, pickUpSigil, leavePortal, tellDaveToReturn, pickUpImplementAfterRitual, - goUpToBadden, talkToBaddenAfterRitual, talkToReenAfterRitual, talkToTheGolemAfterRitual, useImplementOnGolem, pickUpSigil2, - talkToGolemAfterReprogramming, enterRuinAfterRecruiting, enterPortalAfterRecruiting, talkToMatthewToStartFight, killDemon, - standInCircleAgain, enterRuinNoDark, enterRuinForRitual, enterPortalForRitual, enterRuinForDave, enterPortalForFight, - enterRuinForFight, unequipDarklight; - - DetailedOwnerStep searchKiln; - - IncantationStep readIncantation, incantRitual; - - //Zones - Zone ruin, throneRoom, circleSpot, secondCircleSpot; - - @Override - public Map loadSteps() - { - Map steps = new HashMap<>(); - initializeRequirements(); - setupConditions(); - setupSteps(); - - steps.put(0, talkToReen); - steps.put(10, talkToBadden); - - ConditionalStep infiltrateCult = new ConditionalStep(this, pickMushroom); - infiltrateCult.addStep(new Conditions(silverlightDyed, strangeImplement, inRuin), talkToEvilDave); - infiltrateCult.addStep(new Conditions(silverlightDyed, inRuin), pickUpStrangeImplement); - infiltrateCult.addStep(silverlightDyed, goIntoRuin); - infiltrateCult.addStep(blackMushroomHighlighted, dyeSilverlight); - steps.put(20, infiltrateCult); - - ConditionalStep goTalkToDenath = new ConditionalStep(this, enterRuinNoDark); - goTalkToDenath.addStep(inThroneRoom, talkToDenath); - goTalkToDenath.addStep(inRuin, enterPortal); - steps.put(30, goTalkToDenath); - - ConditionalStep completeSubTasks = new ConditionalStep(this, enterRuinNoDark); - completeSubTasks.addStep(new Conditions(book, sigil, inThroneRoom), talkToMatthewAfterBook); - completeSubTasks.addStep(new Conditions(book, sigil, inRuin), enterPortalAfterBook); - completeSubTasks.addStep(new Conditions(book, sigil), enterRuinAfterBook); - completeSubTasks.addStep(new Conditions(talkedToGolem, sigil), searchKiln); - completeSubTasks.addStep(new Conditions(talkedToMatthew, sigil), talkToGolem); - completeSubTasks.addStep(new Conditions(talkedToMatthew, sigilMould), smeltSigil); - completeSubTasks.addStep(new Conditions(inThroneRoom, sigilMould), talkToMatthew); - completeSubTasks.addStep(inThroneRoom, talkToJennifer); - completeSubTasks.addStep(inRuin, enterPortal); - steps.put(40, completeSubTasks); - steps.put(50, completeSubTasks); - steps.put(60, completeSubTasks); - - ConditionalStep startRitual = new ConditionalStep(this, enterRuinForRitual); - startRitual.addStep(inThroneRoom, talkToMatthewAfterBook); - startRitual.addStep(inRuin, enterPortalForRitual); - steps.put(70, startRitual); - - ConditionalStep performRitual = new ConditionalStep(this, enterRuinForRitual); - performRitual.addStep(inCircleSpot, readIncantation); - performRitual.addStep(inThroneRoom, standInCircle); - performRitual.addStep(inRuin, enterPortalForRitual); - steps.put(80, performRitual); - - ConditionalStep prepareForSecondRitual = new ConditionalStep(this, enterRuinForDave); - prepareForSecondRitual.addStep(sigilNearby, pickUpSigil); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved, golemMoved, inThroneRoom), talkToMatthewToStartFight); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved, golemMoved, inRuin), enterPortalAfterRecruiting); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved, golemMoved), enterRuinAfterRecruiting); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved, golemReprogrammed), talkToGolemAfterReprogramming); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved, golemRejected), useImplementOnGolem); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved, reenMoved), talkToTheGolemAfterRitual); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, baddenMoved), talkToReenAfterRitual); - prepareForSecondRitual.addStep(new Conditions(strangeImplement, evilDaveMoved, inRuin), goUpToBadden); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved, inRuin), pickUpImplementAfterRitual); - prepareForSecondRitual.addStep(new Conditions(evilDaveMoved), talkToBaddenAfterRitual); - prepareForSecondRitual.addStep(inRuin, tellDaveToReturn); - prepareForSecondRitual.addStep(inThroneRoom, leavePortal); - - steps.put(90, prepareForSecondRitual); - steps.put(100, prepareForSecondRitual); - - ConditionalStep summonAgrith = new ConditionalStep(this, enterRuinAfterRecruiting); - summonAgrith.addStep(inSecondCircleSpot, incantRitual); - summonAgrith.addStep(inThroneRoom, standInCircleAgain); - summonAgrith.addStep(inRuin, enterPortalAfterRecruiting); - steps.put(110, summonAgrith); - - ConditionalStep defeatAgrith = new ConditionalStep(this, enterRuinForFight); - defeatAgrith.addStep(inThroneRoom, killDemon); - defeatAgrith.addStep(inRuin, enterPortalForFight); - steps.put(120, defeatAgrith); - - steps.put(124, unequipDarklight); - - return steps; - } + // Required items + ItemRequirement silverlight; + ItemRequirement darkItems; + ItemRequirement silverBar; + + // Recommended items + ItemRequirement combatGear; + ItemRequirement coinsForCarpet; + ItemRequirement alKharidTeleport; + + // Mid-quest item requirements + ItemRequirement strangeImplement; + ItemRequirement blackMushroomInk; + ItemRequirement pestle; + ItemRequirement vial; + ItemRequirement silverlightHighlighted; + ItemRequirement blackMushroomHighlighted; + ItemRequirement silverlightDyedEquipped; + ItemRequirement sigilMould; + ItemRequirement silverlightDyed; + ItemRequirement strangeImplementHighlighted; + ItemRequirement sigil; + ItemRequirement book; + ItemRequirement bookHighlighted; + ItemRequirement sigilHighlighted; + ItemRequirement sigil2; + + // Zones + Zone ruin; + Zone throneRoom; + Zone circleSpot; + Zone secondCircleSpot; + + // Miscellaneous requirements + ZoneRequirement inRuin; + ZoneRequirement inThroneRoom; + VarbitRequirement talkedToGolem; + VarbitRequirement talkedToMatthew; + ZoneRequirement inCircleSpot; + ItemOnTileRequirement sigilNearby; + VarbitRequirement evilDaveMoved; + VarbitRequirement baddenMoved; + VarbitRequirement reenMoved; + VarbitRequirement golemMoved; + VarbitRequirement golemRejected; + VarbitRequirement golemReprogrammed; + ZoneRequirement inSecondCircleSpot; + FreeInventorySlotRequirement freeSlot1; + + // Steps + NpcStep talkToReen; + NpcStep talkToBadden; + ObjectStep pickMushroom; + DetailedQuestStep dyeSilverlight; + ObjectStep goIntoRuin; + DetailedQuestStep pickUpStrangeImplement; + NpcStep talkToEvilDave; + ObjectStep enterPortal; + NpcStep talkToDenath; + NpcStep talkToJennifer; + NpcStep talkToMatthew; + DetailedQuestStep smeltSigil; + NpcStep talkToGolem; + DetailedQuestStep readBook; + ObjectStep enterRuinAfterBook; + ObjectStep enterPortalAfterBook; + NpcStep talkToMatthewAfterBook; + TileStep standInCircle; + ItemStep pickUpSigil; + ObjectStep leavePortal; + NpcStep tellDaveToReturn; + DetailedQuestStep pickUpImplementAfterRitual; + ObjectStep goUpToBadden; + NpcStep talkToBaddenAfterRitual; + NpcStep talkToReenAfterRitual; + NpcStep talkToTheGolemAfterRitual; + NpcStep useImplementOnGolem; + ItemStep pickUpSigil2; + NpcStep talkToGolemAfterReprogramming; + ObjectStep enterRuinAfterRecruiting; + ObjectStep enterPortalAfterRecruiting; + NpcStep talkToMatthewToStartFight; + NpcStep killDemon; + TileStep standInCircleAgain; + ObjectStep enterRuinNoDark; + ObjectStep enterRuinForRitual; + ObjectStep enterPortalForRitual; + ObjectStep enterRuinForDave; + ObjectStep enterPortalForFight; + ObjectStep enterRuinForFight; + DetailedQuestStep unequipDarklight; + ConditionalStep searchKilns; + PuzzleWrapperStep pwSearchKilns; + IncantationStep readIncantation; + PuzzleWrapperStep pwReadIncantation; + IncantationStep incantRitual; + PuzzleWrapperStep pwIncantRitual; @Override protected void setupZones() @@ -215,10 +215,6 @@ protected void setupRequirements() // Recommended alKharidTeleport = new ItemRequirement("Al Kharid Teleport", ItemCollections.AMULET_OF_GLORIES); alKharidTeleport.addAlternates(ItemCollections.RING_OF_DUELINGS); - } - - private void setupConditions() - { inRuin = new ZoneRequirement(ruin); inThroneRoom = new ZoneRequirement(throneRoom); inCircleSpot = new ZoneRequirement(circleSpot); @@ -233,6 +229,8 @@ private void setupConditions() golemRejected = new VarbitRequirement(VarbitID.AGRITH_CONVINCED_GOLEM, 1, Operation.GREATER_EQUAL); golemReprogrammed = new VarbitRequirement(VarbitID.AGRITH_CONVINCED_GOLEM, 2, Operation.GREATER_EQUAL); golemMoved = new VarbitRequirement(VarbitID.AGRITH_CONVINCED_GOLEM, 3, Operation.GREATER_EQUAL); + + freeSlot1 = new FreeInventorySlotRequirement(1); } private void setupSteps() @@ -254,7 +252,7 @@ private void setupSteps() talkToDenath = new NpcStep(this, NpcID.AGRITH_DENATH, new WorldPoint(2720, 4912, 2), "Talk to Denath next to the throne."); talkToDenath.addDialogStep("What do I have to do?"); talkToDenath.addSubSteps(enterRuinNoDark, enterPortal); - talkToJennifer = new NpcStep(this, NpcID.AGRITH_JENNIFER, new WorldPoint(2723, 4901, 2), "Talk to Jennifer."); + talkToJennifer = new NpcStep(this, NpcID.AGRITH_JENNIFER, new WorldPoint(2723, 4901, 2), "Talk to Jennifer.", freeSlot1); talkToJennifer.addDialogStep("Do you have the demonic sigil mould?"); talkToMatthew = new NpcStep(this, NpcID.AGRITH_MATTHEW, new WorldPoint(2727, 4897, 2), "Talk to Matthew."); talkToMatthew.addDialogStep("Do you know what happened to Josef?"); @@ -263,7 +261,20 @@ private void setupSteps() talkToGolem = new NpcStep(this, NpcID.GOLEM_FIXED_GOLEM, new WorldPoint(3485, 3088, 0), "Talk to the Golem in Uzer.", silverlightDyed, sigil, combatGear); talkToGolem.addDialogStep("Uzer"); talkToGolem.addDialogStep("Did you see anything happen last night?"); - searchKiln = new SearchKilns(this); + + var searchKiln1 = new ObjectStep(this, ObjectID.AGRITH_KILN_1, new WorldPoint(3468, 3124, 0), ""); + var searchKiln2 = new ObjectStep(this, ObjectID.AGRITH_KILN_2, new WorldPoint(3479, 3083, 0), ""); + var searchKiln3 = new ObjectStep(this, ObjectID.AGRITH_KILN_3, new WorldPoint(3473, 3093, 0), ""); + var searchKiln4 = new ObjectStep(this, ObjectID.AGRITH_KILN_4, new WorldPoint(3501, 3085, 0), ""); + + var kilnBuilder = new VarbitBuilder(VarbitID.AGRITH_KILN); + searchKilns = new ConditionalStep(this, searchKiln1, "Search the kilns in Uzer until you find a book."); + searchKilns.addStep(kilnBuilder.eq(1), searchKiln2); + searchKilns.addStep(kilnBuilder.eq(2), searchKiln3); + searchKilns.addStep(kilnBuilder.eq(3), searchKiln4); + + pwSearchKilns = searchKilns.puzzleWrapStep("Search Uzer for a book."); + readBook = new DetailedQuestStep(this, "Read the book.", bookHighlighted); enterRuinAfterBook = new ObjectStep(this, ObjectID.GOLEM_INSIDESTAIRS_TOP, new WorldPoint(3493, 3090, 0), "Enter the Uzer ruins.", silverlightDyed, book, sigil); enterPortalAfterBook = new ObjectStep(this, ObjectID.GOLEM_PORTAL, new WorldPoint(2722, 4913, 0), "Enter the portal.", book, sigil); @@ -274,21 +285,23 @@ private void setupSteps() enterRuinForRitual = new ObjectStep(this, ObjectID.GOLEM_INSIDESTAIRS_TOP, new WorldPoint(3493, 3090, 0), "Enter the Uzer ruins.", sigil, silverlightDyed, combatGear); enterPortalForRitual = new ObjectStep(this, ObjectID.GOLEM_PORTAL, new WorldPoint(2722, 4913, 0), "Enter the portal."); - standInCircle = new DetailedQuestStep(this, new WorldPoint(2718, 4902, 2), "Stand in the correct spot in the circle.", sigil); - readIncantation = new IncantationStep(this, true); - pickUpSigil = new ItemStep(this, "Pick up the sigil.", sigil); + standInCircle = new TileStep(this, new WorldPoint(2718, 4902, 2), "Stand in the correct spot in the circle.", sigil); + standInCircle.addSubSteps(enterRuinForRitual, enterPortalForRitual); + readIncantation = new IncantationStep(this, true, sigilHighlighted); + pwReadIncantation = readIncantation.puzzleWrapStepWithDefaultText("Click the demonic sigil and read the incantation."); + pickUpSigil = new ItemStep(this, "Pick up the demonic sigil from the circle.", sigil); leavePortal = new ObjectStep(this, ObjectID.AGRITH_PORTAL_CLOSING, new WorldPoint(2720, 4883, 2), "Leave the throne room."); enterRuinForDave = new ObjectStep(this, ObjectID.GOLEM_INSIDESTAIRS_TOP, new WorldPoint(3493, 3090, 0), "Talk to Evil Dave in the Uzer ruins."); - tellDaveToReturn = new NpcStep(this, NpcID.AGRITH_DAVE, new WorldPoint(2721, 4900, 0), "Talk to Evil Dave."); + tellDaveToReturn = new NpcStep(this, NpcID.AGRITH_DAVE, new WorldPoint(2721, 4900, 0), "Talk to Evil Dave.", freeSlot1); tellDaveToReturn.addDialogStep("You've got to get back to the throne room!"); tellDaveToReturn.addSubSteps(enterRuinForDave); pickUpImplementAfterRitual = new DetailedQuestStep(this, new WorldPoint(2713, 4913, 0), "Pick up the strange implement in the north west corner of the ruin.", strangeImplement); - pickUpSigil2 = new ItemStep(this, "Pick up the sigil Tanya dropped.", sigil); + pickUpSigil2 = new ItemStep(this, "Pick up the demonic sigil Tanya dropped.", sigil); goUpToBadden = new ObjectStep(this, ObjectID.GOLEM_INSIDESTAIRS_BASE, new WorldPoint(2722, 4885, 0), "Leave the ruins."); talkToBaddenAfterRitual = new NpcStep(this, NpcID.AGRITH_BADDEN, new WorldPoint(3490, 3090, 0), "Talk to Father Badden in Uzer.", sigil2); - talkToBaddenAfterRitual.addSubSteps(goUpToBadden); + talkToBaddenAfterRitual.addSubSteps(goUpToBadden, pickUpImplementAfterRitual); talkToReenAfterRitual = new NpcStep(this, NpcID.AGRITH_REEN, new WorldPoint(3490, 3090, 0), "Talk to Father Reen in Uzer.", sigil2); talkToReenAfterRitual.addDialogStep("Oh, don't be so simple-minded!"); @@ -303,8 +316,9 @@ private void setupSteps() talkToMatthewToStartFight = new NpcStep(this, NpcID.AGRITH_MATTHEW, new WorldPoint(2727, 4897, 2), "Talk to Matthew in the throne room.", silverlightDyed, sigil, combatGear); talkToMatthewToStartFight.addSubSteps(enterRuinAfterRecruiting, enterPortalAfterRecruiting); talkToMatthewToStartFight.addDialogStep("Yes."); - standInCircleAgain = new DetailedQuestStep(this, new WorldPoint(2720, 4903, 2), "Stand in the correct spot in the circle.", sigil); - incantRitual = new IncantationStep(this, false); + standInCircleAgain = new TileStep(this, new WorldPoint(2720, 4903, 2), "Stand in the correct spot in the circle.", sigil); + incantRitual = new IncantationStep(this, false, sigilHighlighted); + pwIncantRitual = incantRitual.puzzleWrapStepWithDefaultText("Click the demonic sigil and read the incantation."); enterRuinForFight = new ObjectStep(this, ObjectID.GOLEM_INSIDESTAIRS_TOP, new WorldPoint(3493, 3090, 0), "Enter the Uzer ruins to finish fighting Agrith-Naar.", silverlightDyed, combatGear); enterPortalForFight = new ObjectStep(this, ObjectID.GOLEM_PORTAL, new WorldPoint(2722, 4913, 0), "Enter the portal to finish fighting Agrith-Naar.", silverlightDyed, combatGear); killDemon = new NpcStep(this, NpcID.AGRITH_NAAR, "Kill Agrith-Naar. You can hurt him with any weapon, BUT YOU MUST DEAL THE FINAL BLOW WITH SILVERLIGHT.", silverlightDyedEquipped, combatGear); @@ -314,39 +328,142 @@ private void setupSteps() } @Override - public List getNotes() + public Map loadSteps() { - return Arrays.asList("You will need 3 black items for a part of the quest. Potential items would be:", - "- Desert shirt/robe dyed with black mushroom ink", "- Black armour", "- Priest gown top/bottom", "- Black wizard hat", - "- Dark mystic", "- Ghostly robes", "- Shade robes", "- Black dragonhide", "- Black cape", "- One of the various black holiday event items", "- Graceful outfit (dyed black)"); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToReen); + steps.put(10, talkToBadden); + + var infiltrateCult = new ConditionalStep(this, pickMushroom); + infiltrateCult.addStep(and(silverlightDyed, strangeImplement, inRuin), talkToEvilDave); + infiltrateCult.addStep(and(silverlightDyed, inRuin), pickUpStrangeImplement); + infiltrateCult.addStep(silverlightDyed, goIntoRuin); + infiltrateCult.addStep(blackMushroomHighlighted, dyeSilverlight); + steps.put(20, infiltrateCult); + + var goTalkToDenath = new ConditionalStep(this, enterRuinNoDark); + goTalkToDenath.addStep(inThroneRoom, talkToDenath); + goTalkToDenath.addStep(inRuin, enterPortal); + steps.put(30, goTalkToDenath); + + var completeSubTasks = new ConditionalStep(this, enterRuinNoDark); + completeSubTasks.addStep(and(book, sigil, inThroneRoom), talkToMatthewAfterBook); + completeSubTasks.addStep(and(book, sigil, inRuin), enterPortalAfterBook); + completeSubTasks.addStep(and(book, sigil), enterRuinAfterBook); + completeSubTasks.addStep(and(talkedToGolem, sigil), pwSearchKilns); + completeSubTasks.addStep(and(talkedToMatthew, sigil), talkToGolem); + completeSubTasks.addStep(and(talkedToMatthew, sigilMould), smeltSigil); + completeSubTasks.addStep(and(inThroneRoom, sigilMould), talkToMatthew); + completeSubTasks.addStep(inThroneRoom, talkToJennifer); + completeSubTasks.addStep(inRuin, enterPortal); + steps.put(40, completeSubTasks); + steps.put(50, completeSubTasks); + steps.put(60, completeSubTasks); + + var startRitual = new ConditionalStep(this, enterRuinForRitual); + startRitual.addStep(inThroneRoom, talkToMatthewAfterBook); + startRitual.addStep(inRuin, enterPortalForRitual); + steps.put(70, startRitual); + + var performRitual = new ConditionalStep(this, enterRuinForRitual); + performRitual.addStep(inCircleSpot, pwReadIncantation); + performRitual.addStep(inThroneRoom, standInCircle); + performRitual.addStep(inRuin, enterPortalForRitual); + steps.put(80, performRitual); + + var prepareForSecondRitual = new ConditionalStep(this, enterRuinForDave); + prepareForSecondRitual.addStep(sigilNearby, pickUpSigil); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved, golemMoved, inThroneRoom), talkToMatthewToStartFight); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved, golemMoved, inRuin), enterPortalAfterRecruiting); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved, golemMoved), enterRuinAfterRecruiting); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved, golemReprogrammed), talkToGolemAfterReprogramming); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved, golemRejected), useImplementOnGolem); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved, reenMoved), talkToTheGolemAfterRitual); + prepareForSecondRitual.addStep(and(evilDaveMoved, baddenMoved), talkToReenAfterRitual); + prepareForSecondRitual.addStep(and(strangeImplement, evilDaveMoved, inRuin), goUpToBadden); + prepareForSecondRitual.addStep(and(evilDaveMoved, inRuin), pickUpImplementAfterRitual); + prepareForSecondRitual.addStep(and(evilDaveMoved), talkToBaddenAfterRitual); + prepareForSecondRitual.addStep(inRuin, tellDaveToReturn); + prepareForSecondRitual.addStep(inThroneRoom, leavePortal); + + steps.put(90, prepareForSecondRitual); + steps.put(100, prepareForSecondRitual); + + var summonAgrith = new ConditionalStep(this, enterRuinAfterRecruiting); + summonAgrith.addStep(inSecondCircleSpot, pwIncantRitual); + summonAgrith.addStep(inThroneRoom, standInCircleAgain); + summonAgrith.addStep(inRuin, enterPortalAfterRecruiting); + steps.put(110, summonAgrith); + + var defeatAgrith = new ConditionalStep(this, enterRuinForFight); + defeatAgrith.addStep(inThroneRoom, killDemon); + defeatAgrith.addStep(inRuin, enterPortalForFight); + steps.put(120, defeatAgrith); + + steps.put(124, unequipDarklight); + + return steps; } @Override - public List getCombatRequirements() + public List getGeneralRequirements() { - return Collections.singletonList("Agrith-Naar (level 100)"); + return List.of( + new QuestRequirement(QuestHelperQuest.THE_GOLEM, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.DEMON_SLAYER, QuestState.FINISHED), + new SkillRequirement(Skill.CRAFTING, 30, true) + ); } @Override public List getItemRequirements() { - return Arrays.asList(silverlight, darkItems, silverBar); + return List.of( + silverlight, + darkItems, + silverBar + ); } @Override public List getItemRecommended() { - return Arrays.asList(combatGear, coinsForCarpet, alKharidTeleport); + return List.of( + combatGear, + coinsForCarpet, + alKharidTeleport + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() + { + return List.of( + "Agrith-Naar (level 100)" + ); + } + + @Override + public List getNotes() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.THE_GOLEM, QuestState.FINISHED)); - req.add(new QuestRequirement(QuestHelperQuest.DEMON_SLAYER, QuestState.FINISHED)); - req.add(new SkillRequirement(Skill.CRAFTING, 30, true)); - return req; + return List.of( + "You will need 3 black items for a part of the quest. Potential items would be:", + "- Desert shirt/robe dyed with black mushroom ink", + "- Black armour", + "- Priest gown top/bottom", + "- Black wizard hat", + "- Dark mystic", + "- Ghostly robes", + "- Shade robes", + "- Black dragonhide", + "- Black cape", + "- One of the various black holiday event items", + "- Graceful outfit (dyed black)" + ); } @Override @@ -358,21 +475,70 @@ public QuestPointReward getQuestPointReward() @Override public List getItemRewards() { - return Arrays.asList( - new ItemReward("10,000 Experience Lamp (Any combat skill except Prayer)", ItemID.THOSF_REWARD_LAMP, 1), //4447 is placeholder for filter - new ItemReward("Darklight", ItemID.DARKLIGHT, 1)); + return List.of( + new ItemReward("10,000 Experience Lamp (Any combat skill except Prayer)", ItemID.THOSF_REWARD_LAMP, 1), //4447 is placeholder for filter + new ItemReward("Darklight", ItemID.DARKLIGHT, 1) + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - - allSteps.add(new PanelDetails("Starting off", Collections.singletonList(talkToReen))); - allSteps.add(new PanelDetails("Infiltrate the cult", Arrays.asList(talkToBadden, pickMushroom, dyeSilverlight, goIntoRuin, pickUpStrangeImplement, talkToEvilDave, talkToDenath, talkToJennifer, talkToMatthew), silverlight, darkItems)); - allSteps.add(new PanelDetails("Uncovering the truth", Arrays.asList(smeltSigil, talkToGolem, searchKiln, readBook, talkToMatthewAfterBook, standInCircle, readIncantation), silverBar, silverlightDyed, combatGear)); - allSteps.add(new PanelDetails("Defeating Agrith-Naar", Arrays.asList(pickUpSigil, leavePortal, pickUpSigil2, tellDaveToReturn, talkToBaddenAfterRitual, talkToReenAfterRitual, talkToTheGolemAfterRitual, useImplementOnGolem, talkToGolemAfterReprogramming, - talkToMatthewToStartFight, standInCircleAgain, incantRitual, killDemon, unequipDarklight), silverlightDyed, combatGear)); - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToReen + ))); + + sections.add(new PanelDetails("Infiltrate the cult", List.of( + talkToBadden, + pickMushroom, + dyeSilverlight, + goIntoRuin, + pickUpStrangeImplement, + talkToEvilDave, + talkToDenath, + talkToJennifer, + talkToMatthew + ), List.of( + silverlight, + darkItems + ))); + + sections.add(new PanelDetails("Uncovering the truth", List.of( + smeltSigil, + talkToGolem, + pwSearchKilns, + readBook, + talkToMatthewAfterBook, + standInCircle, + pwReadIncantation + ), List.of( + silverBar, + silverlightDyed, + combatGear + ))); + + sections.add(new PanelDetails("Defeating Agrith-Naar", List.of( + pickUpSigil, + leavePortal, + pickUpSigil2, + tellDaveToReturn, + talkToBaddenAfterRitual, + talkToReenAfterRitual, + talkToTheGolemAfterRitual, + useImplementOnGolem, + talkToGolemAfterReprogramming, + talkToMatthewToStartFight, + standInCircleAgain, + pwIncantRitual, + killDemon, + unequipDarklight + ), List.of( + silverlightDyed, + combatGear + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowsofcustodia/ShadowsOfCustodia.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowsofcustodia/ShadowsOfCustodia.java index 6ab1fd4999..e2ed47fd49 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowsofcustodia/ShadowsOfCustodia.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shadowsofcustodia/ShadowsOfCustodia.java @@ -36,6 +36,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -43,7 +44,15 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; @@ -52,13 +61,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; - /** * The quest guide for the "Shadows of Custodia" OSRS quest */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepherder/SheepHerder.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepherder/SheepHerder.java index 8530d771fc..9e1e565c21 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepherder/SheepHerder.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepherder/SheepHerder.java @@ -30,28 +30,30 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.tools.QuestTile; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class SheepHerder extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepshearer/SheepShearer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepshearer/SheepShearer.java index 1c57e98228..3f35bb5881 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepshearer/SheepShearer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sheepshearer/SheepShearer.java @@ -29,27 +29,35 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.ManualRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; import net.runelite.client.plugins.microbot.questhelper.util.QHObjectID; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ItemContainerChanged; -import net.runelite.api.gameval.*; -import net.runelite.client.eventbus.Subscribe; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.IntStream; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.gameval.InventoryID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarPlayerID; +import net.runelite.client.eventbus.Subscribe; public class SheepShearer extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shieldofarrav/ShieldOfArravBlackArmGang.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shieldofarrav/ShieldOfArravBlackArmGang.java index 8065d58655..afda63320e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shieldofarrav/ShieldOfArravBlackArmGang.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shieldofarrav/ShieldOfArravBlackArmGang.java @@ -41,7 +41,11 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shilovillage/ShiloVillage.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shilovillage/ShiloVillage.java index df86791175..c7ce80886c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shilovillage/ShiloVillage.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/shilovillage/ShiloVillage.java @@ -39,6 +39,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; @@ -49,109 +50,125 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - -import java.util.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarPlayerID; +import net.runelite.api.gameval.VarbitID; public class ShiloVillage extends BasicQuestHelper { - // Required - ItemRequirement spade, torchOrCandle, rope, bronzeWire, chisel, bones3; - - // Recommended - ItemRequirement combatGear, food, staminas, antipoison, prayerPotions, quickTeleport, papyrus, charcoal, - crumbleUndead; - - ItemRequirement belt, stonePlaque, tatteredScroll, crumpledScroll, zadimusCorpse, boneShard, beads, pommel, - beadsOfTheDead, boneKey, rashCorpse; - - Requirement emptySlot3, moundNearby, inCavern1, inCavern2, inCavern3, inCavern4, shownStone, shownCorpse, - hasReadTattered, hasReadCrumpled, revealedDoor, searchedDoor, doorOpened, nazNearby, corpseNearby; - - QuestStep talkToMosol, useBeltOnTrufitus, useSpadeOnGround, useTorchOnFissure, useRopeOnFissure, - lookAtMound, searchFissure, useChiselOnStone, enterDeeperCave, searchForTatteredScroll, searchForCrumpledScroll, - searchForCorpse, useCorpseOnTrufitus, useStonePlaqueOnTrufitus, readTattered, readCrumpled, buryCorpse; - - QuestStep searchRocksOnCairn, searchDolmen, useChiselOnPommel, useWireOnBeads; - - QuestStep searchPalms, searchDoors, makeKey, useKeyOnDoor, enterDoor, useBonesOnDoor, searchDolmenForFight, killNazastarool, - pickupCorpse; - - QuestStep enterCairnAgain, useCorpseOnDolmen; - - Zone cavern1, cavern2, cavern3, cavern4; + // Required items + ItemRequirement spade; + ItemRequirement torchOrCandle; + ItemRequirement rope; + ItemRequirement bronzeWire; + ItemRequirement chisel; + ItemRequirement bones3; + + // Recommended items + ItemRequirement combatGear; + ItemRequirement food; + ItemRequirement staminas; + ItemRequirement antipoison; + ItemRequirement prayerPotions; + ItemRequirement quickTeleport; + ItemRequirement papyrus; + ItemRequirement charcoal; + ItemRequirement crumbleUndead; + + // Mid-quest item requirements + ItemRequirement belt; + ItemRequirement stonePlaque; + ItemRequirement tatteredScroll; + ItemRequirement crumpledScroll; + ItemRequirement zadimusCorpse; + ItemRequirement boneShard; + ItemRequirement beads; + ItemRequirement pommel; + ItemRequirement beadsOfTheDead; + ItemRequirement boneKey; + ItemRequirement rashCorpse; + + // Zones + Zone cavern1; + Zone cavern2; + Zone cavern3; + Zone cavern4; + + // Miscellaneous requirements + FreeInventorySlotRequirement freeInvSlot1; + FreeInventorySlotRequirement freeInvSlot2; + ObjectCondition moundNearby; + ZoneRequirement inCavern1; + ZoneRequirement inCavern2; + ZoneRequirement inCavern3; + ZoneRequirement inCavern4; + Conditions shownStone; + Conditions shownCorpse; + Conditions hasReadTattered; + Conditions hasReadCrumpled; + VarbitRequirement revealedDoor; + Conditions searchedDoor; + VarbitRequirement doorOpened; + NpcInteractingRequirement nazNearby; + ItemOnTileRequirement corpseNearby; + + // Steps + NpcStep talkToMosol; + NpcStep showBeltToTrufitus; + ObjectStep useSpadeOnGround; + ObjectStep useTorchOnFissure; + ObjectStep useRopeOnFissure; + ObjectStep lookAtMound; + ObjectStep searchFissure; + ObjectStep useChiselOnStone; + ObjectStep enterDeeperCave; + ObjectStep searchForTatteredScroll; + ObjectStep searchForCrumpledScroll; + ObjectStep searchForCorpse; + NpcStep useCorpseOnTrufitus; + NpcStep useStonePlaqueOnTrufitus; + DetailedQuestStep readTattered; + DetailedQuestStep readCrumpled; + DetailedQuestStep buryCorpse; + ObjectStep searchRocksOnCairn; + ObjectStep searchDolmen; + DetailedQuestStep useChiselOnPommel; + DetailedQuestStep useWireOnBeads; + ObjectStep searchPalms; + ObjectStep searchDoors; + DetailedQuestStep makeKey; + ObjectStep useKeyOnDoor; + ObjectStep enterDoor; + ObjectStep useBonesOnDoor; + ObjectStep searchDolmenForFight; + NpcStep killNazastarool; + ItemStep pickupCorpse; + ObjectStep enterCairnAgain; + ObjectStep useCorpseOnDolmen; @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - ConditionalStep goStartQuest = new ConditionalStep(this, talkToMosol); - goStartQuest.addStep(belt.alsoCheckBank(), useBeltOnTrufitus); - steps.put(0, goStartQuest); - - steps.put(1, useSpadeOnGround); - steps.put(2, useSpadeOnGround); - steps.put(3, useSpadeOnGround); - - ConditionalStep lightUpFissure = new ConditionalStep(this, useTorchOnFissure); - lightUpFissure.addStep(moundNearby, lookAtMound); - steps.put(4, lightUpFissure); - - ConditionalStep goUseRope = new ConditionalStep(this, useRopeOnFissure); - goUseRope.addStep(moundNearby, lookAtMound); - steps.put(5, goUseRope); - - ConditionalStep goGetItems = new ConditionalStep(this, searchFissure); - goGetItems.addStep(new Conditions(beadsOfTheDead, boneKey), useKeyOnDoor); - goGetItems.addStep(new Conditions(beadsOfTheDead, searchedDoor), makeKey); - goGetItems.addStep(new Conditions(beadsOfTheDead, revealedDoor), searchDoors); - goGetItems.addStep(new Conditions(beadsOfTheDead), searchPalms); - goGetItems.addStep(new Conditions(beads), useWireOnBeads); - goGetItems.addStep(new Conditions(pommel), useChiselOnPommel); - goGetItems.addStep(new Conditions(inCavern3), searchDolmen); - // Stone-plaque may be useless? - // Don't need to show Trufitus bone shard - // Reading tattered unlocks access to the island cavern - // Reading crumpled lets you use bronze wire on beads - goGetItems.addStep(new Conditions(stonePlaque, hasReadTattered, hasReadCrumpled, boneShard), searchRocksOnCairn); - goGetItems.addStep(new Conditions(stonePlaque, hasReadTattered, crumpledScroll, boneShard), readCrumpled); - goGetItems.addStep(new Conditions(stonePlaque, tatteredScroll, crumpledScroll, boneShard), readTattered); - goGetItems.addStep(new Conditions(stonePlaque, tatteredScroll, crumpledScroll, zadimusCorpse), buryCorpse); - goGetItems.addStep(new Conditions(inCavern2, stonePlaque, tatteredScroll, crumpledScroll), searchForCorpse); - goGetItems.addStep(new Conditions(inCavern2, stonePlaque, tatteredScroll), searchForCrumpledScroll); - goGetItems.addStep(new Conditions(inCavern2, stonePlaque), searchForTatteredScroll); - goGetItems.addStep(new Conditions(inCavern1, stonePlaque), enterDeeperCave); - goGetItems.addStep(inCavern1, useChiselOnStone); - goGetItems.addStep(moundNearby, lookAtMound); - steps.put(6, goGetItems); - steps.put(7, goGetItems); - steps.put(8, goGetItems); - steps.put(9, goGetItems); - - ConditionalStep goToDolem = new ConditionalStep(this, enterDoor); - goToDolem.addStep(inCavern4, useBonesOnDoor); - steps.put(10, goToDolem); - steps.put(11, goToDolem); - - ConditionalStep goDoFight = new ConditionalStep(this, enterDoor); - goDoFight.addStep(new Conditions(rashCorpse, inCavern3), useCorpseOnDolmen); - goDoFight.addStep(rashCorpse, enterCairnAgain); - goDoFight.addStep(corpseNearby, pickupCorpse); - goDoFight.addStep(nazNearby, killNazastarool); - goDoFight.addStep(inCavern4, searchDolmenForFight); - steps.put(12, goDoFight); - steps.put(13, goDoFight); - steps.put(14, goDoFight); - - return steps; + cavern1 = new Zone(new WorldPoint(2870, 9330, 0), new WorldPoint(2950, 9407, 0)); + cavern2 = new Zone(new WorldPoint(2878, 9282, 0), new WorldPoint(2942, 9333, 0)); + cavern3 = new Zone(new WorldPoint(2751, 9353, 0), new WorldPoint(2770, 9397, 0)); + cavern4 = new Zone(new WorldPoint(2833, 9463, 0), new WorldPoint(2943, 9533, 0)); } @Override @@ -177,7 +194,8 @@ protected void setupRequirements() charcoal = new ItemRequirement("Charcoal", ItemID.CHARCOAL); crumbleUndead = new ItemRequirement("Crumble undead spell for final boss", -1, -1); - emptySlot3 = new FreeInventorySlotRequirement(3); + freeInvSlot1 = new FreeInventorySlotRequirement(1); + freeInvSlot2 = new FreeInventorySlotRequirement(2); belt = new ItemRequirement("Wampum belt", ItemID.MOSOL_WAMPUM_BELT); stonePlaque = new ItemRequirement("Stone-plaque", ItemID.ZQPLAQUE); @@ -192,20 +210,8 @@ protected void setupRequirements() pommel = new ItemRequirement("Sword pommel", ItemID.ZQBEVSWORD); beads = new ItemRequirement("Bone beads", ItemID.ZQBONEBEADS); beadsOfTheDead = new ItemRequirement("Beads of the dead", ItemID.ZQDEADBEADS); - rashCorpse = new ItemRequirement("Rashiliya corpse", ItemID.ZQCORPSE); - } - - @Override - protected void setupZones() - { - cavern1 = new Zone(new WorldPoint(2870, 9330, 0), new WorldPoint(2950, 9407, 0)); - cavern2 = new Zone(new WorldPoint(2878, 9282, 0), new WorldPoint(2942, 9333, 0)); - cavern3 = new Zone(new WorldPoint(2751, 9353, 0), new WorldPoint(2770, 9397, 0)); - cavern4 = new Zone(new WorldPoint(2833, 9463, 0), new WorldPoint(2943, 9533, 0)); - } + rashCorpse = new ItemRequirement("Rashiliyia corpse", ItemID.ZQCORPSE); - public void setupConditions() - { moundNearby = new ObjectCondition(ObjectID.AHZARHOON_ENTRANCE, new WorldPoint(2922, 3000, 0)); inCavern1 = new ZoneRequirement(cavern1); inCavern2 = new ZoneRequirement(cavern2); @@ -218,25 +224,25 @@ public void setupConditions() ); shownStone = new Conditions(true, LogicType.OR, - new DialogRequirement("If you have found anything else that you need " + - "help with, please just let me know."), + new DialogRequirement("If you have found anything else that you need help with, please just let me know."), new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Trufitus identified the plaque") ); hasReadTattered = new Conditions(true, LogicType.OR, - new WidgetTextRequirement(220, 3, "Bervirius, son of King Danthalas"), + new WidgetTextRequirement(InterfaceID.Messagescroll.MESSCROLL3, "Bervirius, son of King Danthalas"), new VarplayerRequirement(VarPlayerID.ZOMBIEQUEEN, 9, Operation.GREATER_EQUAL) ); hasReadCrumpled = new Conditions(true, LogicType.OR, - new WidgetTextRequirement(222, 3, "Rashiliyia's rage went unchecked."), + new WidgetTextRequirement(InterfaceID.MessagescrollHandwriting.MESSAGESCROLL3_HW, "Rashiliyia's rage went unchecked."), beadsOfTheDead ); revealedDoor = new VarbitRequirement(VarbitID.ZQDOOR_MULTI, 1, Operation.GREATER_EQUAL); doorOpened = new VarbitRequirement(VarbitID.ZQDOOR_MULTI, 2, Operation.GREATER_EQUAL); searchedDoor = new Conditions(true, LogicType.OR, - new WidgetTextRequirement(229, 1, "Examining the door,") + // TODO: This might be able to use varbit ZQDOOR_MULTI == 1 + WidgetTextRequirement.messageBox("Examining the door,") ); nazNearby = new NpcInteractingRequirement(NpcID.ZQ_MAINZOMBIE1, NpcID.ZQ_MAINZOMBIE2, NpcID.ZQ_MAINZOMBIE3); @@ -246,56 +252,44 @@ public void setupConditions() public void setupSteps() { - talkToMosol = new NpcStep(this, NpcID.MOSOL_REI, new WorldPoint(2884, 2951, 0), - "Talk to Mosol Rei east of Shilo Village in south Karamja."); - talkToMosol.addDialogSteps("Why do I need to run?", "Rashiliyia? Who is she?", - "I'll go to see the Shaman.", "Yes, I'm sure and I'll take the Wampum belt to Trufitus."); + talkToMosol = new NpcStep(this, NpcID.MOSOL_REI, new WorldPoint(2884, 2951, 0), "Talk to Mosol Rei east of Shilo Village in south Karamja to receive a wampum belt.", freeInvSlot1); + talkToMosol.addDialogSteps("Why do I need to run?", "Rashiliyia? Who is she?", "I'll go to see the Shaman.", "Yes, I'm sure and I'll take the Wampum belt to Trufitus."); talkToMosol.addDialogStep(1, "What can we do?"); - useBeltOnTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), - "Use the belt on to Trufitus.", belt.highlighted()); - useBeltOnTrufitus.addIcon(ItemID.MOSOL_WAMPUM_BELT); - useBeltOnTrufitus.addDialogSteps("Mosol Rei said something about a legend?", "Why was it called Ah Za Rhoon?", - "Tell me more.", "I am going to search for Ah Za Rhoon!", - "Yes, I will seriously look for Ah Za Rhoon and I'd appreciate your help.", "Yes."); - useSpadeOnGround = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE, new WorldPoint(2922, 3000, 0), - "Use a spade on the ground in south east Karamja.", spade.highlighted()); + + showBeltToTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), "Show the wampum belt to Trufitus in Tai Bwo Wannai village.", belt.highlighted()); + showBeltToTrufitus.addDialogStep("Mosol gave me something to show you."); + showBeltToTrufitus.addDialogStep("Mosol Rei said something about a legend?"); + showBeltToTrufitus.addDialogStep("Why was it called Ah Za Rhoon?"); + showBeltToTrufitus.addDialogStep("I am going to search for Ah Za Rhoon!"); + showBeltToTrufitus.addDialogStep("Yes."); + + useSpadeOnGround = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE, new WorldPoint(2922, 3000, 0), "Use a spade on the ground in south east Karamja.", spade.highlighted()); useSpadeOnGround.addIcon(ItemID.SPADE); - lookAtMound = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE, new WorldPoint(2922, 3000, 0), - "Look at the mound of earth in south east Karamja."); - useTorchOnFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE, new WorldPoint(2922, 3000, 0), - "Use a lit torch or candle on the fissure.", torchOrCandle.highlighted()); + lookAtMound = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE, new WorldPoint(2922, 3000, 0), "Look at the mound of earth in south east Karamja."); + useTorchOnFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE, new WorldPoint(2922, 3000, 0), "Use a lit torch or candle on the fissure.", torchOrCandle.highlighted()); useTorchOnFissure.addDialogStep("Yes"); useTorchOnFissure.addIcon(ItemID.LIT_CANDLE); useTorchOnFissure.addSubSteps(lookAtMound); - useRopeOnFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE, new WorldPoint(2922, 3000, 0), - "Use a rope on the fissure.", rope.highlighted()); + useRopeOnFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE, new WorldPoint(2922, 3000, 0), "Use a rope on the fissure.", rope.highlighted()); useRopeOnFissure.addIcon(ItemID.ROPE); - searchFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE_WITHROPE, new WorldPoint(2922, 3000, 0), - "Right-click search the fissure."); + searchFissure = new ObjectStep(this, ObjectID.AHZARHOON_ENTRANCE_FISSURE_WITHROPE, new WorldPoint(2922, 3000, 0), "Right-click search the fissure."); searchFissure.addDialogStep("Yes, I'll give it a go!"); - useChiselOnStone = new ObjectStep(this, ObjectID.ZQSECRETSTONE, new WorldPoint(2901, 9379, 0), - "Use a chisel on the strange looking stone to the south.", chisel.highlighted()); + useChiselOnStone = new ObjectStep(this, ObjectID.ZQSECRETSTONE, new WorldPoint(2901, 9379, 0), "Use a chisel on the strange looking stone to the south.", chisel.highlighted()); useChiselOnStone.addIcon(ItemID.CHISEL); - enterDeeperCave = new ObjectStep(this, ObjectID.SECRETRUBBLE, new WorldPoint(2888, 9373, 0), - "Search the cave in to go deeper in the caverns."); + enterDeeperCave = new ObjectStep(this, ObjectID.SECRETRUBBLE, new WorldPoint(2888, 9373, 0), "Search the nearby cave-in to go deeper in the caverns."); enterDeeperCave.addDialogStep("Yes, I'll wriggle through."); - searchForTatteredScroll = new ObjectStep(this, ObjectID.SECRETRUBBLEBOOK, new WorldPoint(2885, 9318, 0), - "Search the loose rocks to the north for a tattered scroll."); + searchForTatteredScroll = new ObjectStep(this, ObjectID.SECRETRUBBLEBOOK, new WorldPoint(2885, 9318, 0), "Search the loose rocks to the north for a tattered scroll."); searchForTatteredScroll.addDialogStep("Yes, I'll carefully move the rocks to see what's behind them."); - searchForCrumpledScroll = new ObjectStep(this, ObjectID.ZQSACKS, new WorldPoint(2939, 9285, 0), - "Search the old sacks to the east for a crumpled scroll."); - searchForCorpse = new ObjectStep(this, ObjectID.ZQGALLOWS, new WorldPoint(2935, 9326, 0), - "Right-click search the gallows in the north east corner for a corpse."); + searchForCrumpledScroll = new ObjectStep(this, ObjectID.ZQSACKS, new WorldPoint(2939, 9285, 0), "Search the old sacks to the east for a crumpled scroll."); + searchForCorpse = new ObjectStep(this, ObjectID.ZQGALLOWS, new WorldPoint(2935, 9326, 0), "Right-click search the gallows in the north east corner for a corpse."); searchForCorpse.addDialogStep("Yes, I may find something else on the corpse."); - useCorpseOnTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), - "Use Zadimus's corpse on Trufitus.", zadimusCorpse.highlighted()); + useCorpseOnTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), "Use Zadimus's corpse on Trufitus.", zadimusCorpse.highlighted()); useCorpseOnTrufitus.addDialogStep("Is there any sacred ground around here?"); useCorpseOnTrufitus.addIcon(ItemID.ZQZADIMUSBONES); - useStonePlaqueOnTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), - "Use the stone-plaque on Trufitus.", stonePlaque.highlighted()); + useStonePlaqueOnTrufitus = new NpcStep(this, NpcID.TRUFITUS, new WorldPoint(2809, 3085, 0), "Use the stone-plaque on Trufitus.", stonePlaque.highlighted()); useStonePlaqueOnTrufitus.addIcon(ItemID.ZQPLAQUE); readTattered = new DetailedQuestStep(this, "Read the tattered scroll.", tatteredScroll.highlighted()); @@ -304,86 +298,152 @@ public void setupSteps() readCrumpled = new DetailedQuestStep(this, "Read the crumpled scroll.", crumpledScroll.highlighted()); readCrumpled.addDialogSteps("Yes please."); - buryCorpse = new DetailedQuestStep(this, new WorldPoint(2795, 3089, 0), - "Bury Zadimus's corpse in the middle of Tai Bwo Wannai.", zadimusCorpse.highlighted()); + buryCorpse = new DetailedQuestStep(this, new WorldPoint(2795, 3089, 0), "Bury Zadimus's corpse in the middle of Tai Bwo Wannai.", zadimusCorpse.highlighted()); buryCorpse.addIcon(ItemID.ZQZADIMUSBONES); - searchRocksOnCairn = new ObjectStep(this, ObjectID.ZQROCKS, new WorldPoint(2762, 2990, 0), - "Right-click search the rocks on Cairn Isle."); + searchRocksOnCairn = new ObjectStep(this, ObjectID.ZQROCKS, new WorldPoint(2762, 2990, 0), "Right-click search the rocks on Cairn Isle."); searchRocksOnCairn.addDialogSteps("Yes please, I can think of nothing nicer!"); - searchDolmen = new ObjectStep(this, ObjectID.ZQDOLMEN, new WorldPoint(2767, 9365, 0), - "Right-click search the dolmen to the south."); - useChiselOnPommel = new DetailedQuestStep(this, "Use a chisel on the pommel.", chisel.highlighted(), - pommel.highlighted()); - useWireOnBeads = new DetailedQuestStep(this, "Use bronze wire on the beads.", bronzeWire.highlighted(), - beads.highlighted()); + searchDolmen = new ObjectStep(this, ObjectID.ZQDOLMEN, new WorldPoint(2767, 9365, 0), "Right-click search the tomb dolmen to the south."); + useChiselOnPommel = new DetailedQuestStep(this, "Use a chisel on the pommel.", chisel.highlighted(), pommel.highlighted()); + useWireOnBeads = new DetailedQuestStep(this, "Use bronze wire on the beads.", bronzeWire.highlighted(), beads.highlighted()); - searchPalms = new ObjectStep(this, ObjectID.ZQQUEST_HIDYTREE, new WorldPoint(2916, 3093, 0), - "Search the palm trees in the north east of Karamja. Come equipped for a boss fight.", - List.of(beadsOfTheDead.equipped(), boneShard, chisel, bones3, - combatGear), List.of(crumbleUndead, food)); + searchPalms = new ObjectStep(this, ObjectID.ZQQUEST_HIDYTREE, new WorldPoint(2916, 3093, 0), "Search the palm trees in the north east of Karamja. Come equipped for a boss fight.", List.of(beadsOfTheDead.equipped(), boneShard, chisel, bones3, combatGear), List.of(crumbleUndead, food)); - searchDoors = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), - "Right-click search the doors behind the palm trees.", combatGear); + searchDoors = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), "Right-click search the carved doors behind the palm trees.", combatGear); // 8180 opened? makeKey = new DetailedQuestStep(this, "Use a chisel on the bone shard.", chisel.highlighted(), boneShard.highlighted()); - useKeyOnDoor = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), - "Use the bone key on the doors behind the palm trees.", boneKey.highlighted()); + useKeyOnDoor = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), "Use the bone key on the doors behind the palm trees.", boneKey.highlighted()); useKeyOnDoor.addIcon(ItemID.ZQBONEKEY); - enterDoor = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), - "Enter the doors behind the palm trees.", beadsOfTheDead.equipped(), bones3, - combatGear); - useBonesOnDoor = new ObjectStep(this, ObjectID.THZQ_TOMBROOML1, new WorldPoint(2892, 9480, 0), - "Equip the beads of the dead, then make your way through the gate, down the rocks, then to the south west" + - " corner. Use bones on the door there.", - beadsOfTheDead.equipped(), bones3.highlighted()); + enterDoor = new ObjectStep(this, ObjectID.HILLSIDEDOORR_MULTI, new WorldPoint(2916, 3091, 0), "Enter the doors behind the palm trees.", beadsOfTheDead.equipped(), bones3, combatGear); + useBonesOnDoor = new ObjectStep(this, ObjectID.THZQ_TOMBROOML1, new WorldPoint(2892, 9480, 0), "Equip the beads of the dead, then make your way through the gate, down the rocks, then to the south west corner. Use bones on the door there.", beadsOfTheDead.equipped(), bones3.highlighted()); useBonesOnDoor.addIcon(ItemID.BONES); - searchDolmenForFight = new ObjectStep(this, ObjectID.ZQRASHDOLMEN, new WorldPoint(2893, 9488, 0), - "Search the dolmen, ready to fight."); - - killNazastarool = new NpcStep(this, NpcID.ZQ_MAINZOMBIE1, new WorldPoint(2892, 9488, 0), - "Defeat Nazastarool's 3 forms. You can safe spot them over the dolmen, and the Crumble Undead spell is very" + - " strong against them."); - ((NpcStep) killNazastarool).addAlternateNpcs(NpcID.ZQ_MAINZOMBIE2, NpcID.ZQ_MAINZOMBIE3); - ((NpcStep)killNazastarool).addSafeSpots(new WorldPoint(2894, 9486, 0), new WorldPoint(2891, 9486, 0)); + searchDolmenForFight = new ObjectStep(this, ObjectID.ZQRASHDOLMEN, new WorldPoint(2893, 9488, 0), "Search the tomb dolmen, ready to fight."); + + killNazastarool = new NpcStep(this, NpcID.ZQ_MAINZOMBIE1, new WorldPoint(2892, 9488, 0), "Defeat Nazastarool's 3 forms. You can safe spot them over the tomb dolmen. The Crumble Undead spell is very strong against them."); + killNazastarool.addAlternateNpcs(NpcID.ZQ_MAINZOMBIE2, NpcID.ZQ_MAINZOMBIE3); + killNazastarool.addSafeSpots(new WorldPoint(2894, 9486, 0), new WorldPoint(2891, 9486, 0)); pickupCorpse = new ItemStep(this, "Pickup Rashiliyia's corpse.", rashCorpse); - enterCairnAgain = new ObjectStep(this, ObjectID.ZQROCKS, new WorldPoint(2762, 2990, 0), - "Right-click search the rocks on Cairn Isle to enter the caverns again.", rashCorpse); + enterCairnAgain = new ObjectStep(this, ObjectID.ZQROCKS, new WorldPoint(2762, 2990, 0), "Right-click search the rocks on Cairn Isle to enter the caverns again.", rashCorpse); enterCairnAgain.addDialogSteps("Yes please, I can think of nothing nicer!"); - useCorpseOnDolmen = new ObjectStep(this, ObjectID.ZQDOLMEN, new WorldPoint(2767, 9365, 0), - "Use Rashiliyia's corpse on the dolmen to the south.", rashCorpse.highlighted()); + useCorpseOnDolmen = new ObjectStep(this, ObjectID.ZQDOLMEN, new WorldPoint(2767, 9365, 0), "Use Rashiliyia's corpse on the dolmen to the south.", rashCorpse.highlighted()); useCorpseOnDolmen.addIcon(ItemID.ZQCORPSE); } @Override - public List getItemRequirements() + public Map loadSteps() { - return Arrays.asList(spade, torchOrCandle, rope, bronzeWire, chisel, bones3); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + var goStartQuest = new ConditionalStep(this, talkToMosol); + goStartQuest.addStep(belt.alsoCheckBank(), showBeltToTrufitus); + steps.put(0, goStartQuest); + + steps.put(1, useSpadeOnGround); + steps.put(2, useSpadeOnGround); + steps.put(3, useSpadeOnGround); + + var lightUpFissure = new ConditionalStep(this, useTorchOnFissure); + lightUpFissure.addStep(moundNearby, lookAtMound); + steps.put(4, lightUpFissure); + + var goUseRope = new ConditionalStep(this, useRopeOnFissure); + goUseRope.addStep(moundNearby, lookAtMound); + steps.put(5, goUseRope); + + var goGetItems = new ConditionalStep(this, searchFissure); + goGetItems.addStep(and(beadsOfTheDead, boneKey), useKeyOnDoor); + goGetItems.addStep(and(beadsOfTheDead, searchedDoor), makeKey); + goGetItems.addStep(and(beadsOfTheDead, revealedDoor), searchDoors); + goGetItems.addStep(and(beadsOfTheDead), searchPalms); + goGetItems.addStep(beads, useWireOnBeads); + goGetItems.addStep(pommel, useChiselOnPommel); + goGetItems.addStep(inCavern3, searchDolmen); + // Stone-plaque may be useless? + // Don't need to show Trufitus bone shard + // Reading tattered unlocks access to the island cavern + // Reading crumpled lets you use bronze wire on beads + goGetItems.addStep(and(stonePlaque, hasReadTattered, hasReadCrumpled, boneShard), searchRocksOnCairn); + goGetItems.addStep(and(stonePlaque, hasReadTattered, crumpledScroll, boneShard), readCrumpled); + goGetItems.addStep(and(stonePlaque, tatteredScroll, crumpledScroll, boneShard), readTattered); + goGetItems.addStep(and(stonePlaque, tatteredScroll, crumpledScroll, zadimusCorpse), buryCorpse); + goGetItems.addStep(and(inCavern2, stonePlaque, tatteredScroll, crumpledScroll), searchForCorpse); + goGetItems.addStep(and(inCavern2, stonePlaque, tatteredScroll), searchForCrumpledScroll); + goGetItems.addStep(and(inCavern2, stonePlaque), searchForTatteredScroll); + goGetItems.addStep(and(inCavern1, stonePlaque), enterDeeperCave); + goGetItems.addStep(inCavern1, useChiselOnStone); + goGetItems.addStep(moundNearby, lookAtMound); + steps.put(6, goGetItems); + steps.put(7, goGetItems); + steps.put(8, goGetItems); + steps.put(9, goGetItems); + + var goToDolem = new ConditionalStep(this, enterDoor); + goToDolem.addStep(inCavern4, useBonesOnDoor); + steps.put(10, goToDolem); + steps.put(11, goToDolem); + + var goDoFight = new ConditionalStep(this, enterDoor); + goDoFight.addStep(and(rashCorpse, inCavern3), useCorpseOnDolmen); + goDoFight.addStep(rashCorpse, enterCairnAgain); + goDoFight.addStep(corpseNearby, pickupCorpse); + goDoFight.addStep(nazNearby, killNazastarool); + goDoFight.addStep(inCavern4, searchDolmenForFight); + steps.put(12, goDoFight); + steps.put(13, goDoFight); + steps.put(14, goDoFight); + + return steps; } @Override - public List getItemRecommended() + public List getGeneralRequirements() { - return Arrays.asList(combatGear, food, staminas, antipoison, prayerPotions, quickTeleport, - papyrus, charcoal, crumbleUndead); + return List.of( + new QuestRequirement(QuestHelperQuest.JUNGLE_POTION, QuestState.FINISHED), + new SkillRequirement(Skill.CRAFTING, 20), + new SkillRequirement(Skill.AGILITY, 32) + ); } + @Override + public List getItemRequirements() + { + return List.of( + spade, + torchOrCandle, + rope, + bronzeWire, + chisel, + bones3 + ); + } @Override - public List getCombatRequirements() + public List getItemRecommended() { - return Collections.singletonList("Nazastarool 3 times (levels 68, 91, 93) (safespottable)"); + return List.of( + combatGear, + food, + staminas, + antipoison, + prayerPotions, + quickTeleport, + papyrus, + charcoal, + crumbleUndead + ); } @Override - public List getGeneralRequirements() + public List getCombatRequirements() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.JUNGLE_POTION, QuestState.FINISHED)); - req.add(new SkillRequirement(Skill.CRAFTING, 20)); - req.add(new SkillRequirement(Skill.AGILITY, 32)); - return req; + return List.of( + "Nazastarool 3 times (levels 68, 91, 93) (safespottable)" + ); } @Override @@ -395,33 +455,77 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.CRAFTING, 3875)); + return List.of( + new ExperienceReward(Skill.CRAFTING, 3875) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("Access to Shilo Village"), - new UnlockReward("Ability to mine gem rocks in Shilo Village")); + return List.of( + new UnlockReward("Access to Shilo Village"), + new UnlockReward("Ability to mine gem rocks in Shilo Village") + ); } - @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Exploring", - Arrays.asList(talkToMosol, useBeltOnTrufitus, useSpadeOnGround, useTorchOnFissure, useRopeOnFissure, - searchFissure, useChiselOnStone, enterDeeperCave, searchForTatteredScroll, searchForCrumpledScroll, - searchForCorpse, buryCorpse, readTattered, readCrumpled), spade, torchOrCandle, rope, chisel)); - - allSteps.add(new PanelDetails("Free Raiysha", - Arrays.asList(searchRocksOnCairn, searchDolmen, useChiselOnPommel, useWireOnBeads, searchPalms, - searchDoors, makeKey, useKeyOnDoor, enterDoor, useBonesOnDoor, searchDolmenForFight, killNazastarool, - pickupCorpse, enterCairnAgain, useCorpseOnDolmen), List.of(chisel, bronzeWire, bones3), - List.of(combatGear, food, crumbleUndead, prayerPotions))); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Exploring", List.of( + talkToMosol, + showBeltToTrufitus, + useSpadeOnGround, + useTorchOnFissure, + useRopeOnFissure, + searchFissure, + useChiselOnStone, + enterDeeperCave, + searchForTatteredScroll, + searchForCrumpledScroll, + searchForCorpse, + buryCorpse, + readTattered, + readCrumpled + ), List.of( + spade, + torchOrCandle, + rope, + chisel + ), List.of( + freeInvSlot1 + ))); + + sections.add(new PanelDetails("Free Rashiliyia", List.of( + searchRocksOnCairn, + searchDolmen, + useChiselOnPommel, + useWireOnBeads, + searchPalms, + searchDoors, + makeKey, + useKeyOnDoor, + enterDoor, + useBonesOnDoor, + searchDolmenForFight, + killNazastarool, + pickupCorpse, + enterCairnAgain, + useCorpseOnDolmen + ), List.of( + chisel, + bronzeWire, + bones3 + ), List.of( + combatGear, + food, + crumbleUndead, + prayerPotions, + freeInvSlot2 + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sinsofthefather/DoorPuzzleStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sinsofthefather/DoorPuzzleStep.java index 5072ce38e9..8bf650269e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sinsofthefather/DoorPuzzleStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/sinsofthefather/DoorPuzzleStep.java @@ -40,9 +40,9 @@ import javax.inject.Inject; import java.awt.*; -import java.util.*; import java.util.List; import java.util.Queue; +import java.util.*; @Slf4j public class DoorPuzzleStep extends DetailedQuestStep @@ -60,7 +60,7 @@ public class DoorPuzzleStep extends DetailedQuestStep private boolean solving = false; - static class PuzzleLine + public static class PuzzleLine { public int[] cells; @@ -96,7 +96,11 @@ public DoorPuzzleStep(BasicQuestHelper questHelper) super(questHelper, "Solve the puzzle by marking the highlighted squares."); } - private PuzzleLine[] solve() + /** + * Entry point used in-game – reads the sums from the puzzle widgets + * and solves the Kakurasu grid. + */ + public PuzzleLine[] solve() { int[] rowSums = new int[SIZE]; int[] colSums = new int[SIZE]; @@ -114,32 +118,81 @@ private PuzzleLine[] solve() } PuzzleState solved = newSolveState(rowSums, colSums); - return solveGrid(solved); + return solveGrid(solved, rowSums, colSums); + } + + /** + * Intended for testing purposes, so we can easily feed in our own puzzles + */ + static PuzzleLine[] solveForSums(int[] rowSums, int[] colSums) + { + DoorPuzzleStep step = new DoorPuzzleStep(null); + PuzzleState solved = step.newSolveState(rowSums, colSums); + return step.solveGrid(solved, rowSums, colSums); + } + + private boolean gridSatisfiesSums(PuzzleLine[] grid, int[] rowSums, int[] colSums) + { + for (int r = 0; r < SIZE; r++) + { + int rowSum = 0; + for (int c = 0; c < SIZE; c++) + { + if (grid[r].cells[c] == FILLED) + { + rowSum += (c + 1); + } + } + if (rowSum != rowSums[r]) + { + return false; + } + } + for (int c = 0; c < SIZE; c++) + { + int colSum = 0; + for (int r = 0; r < SIZE; r++) + { + if (grid[r].cells[c] == FILLED) + { + colSum += (r + 1); + } + } + if (colSum != colSums[c]) + { + return false; + } + } + + return true; } - private PuzzleLine[] solveGrid(PuzzleState puzzleState) + private PuzzleLine[] solveGrid(PuzzleState puzzleState, int[] rowSums, int[] colSums) { int iterations = 0; Queue puzzleStates = new LinkedList<>(); puzzleStates.add(puzzleState); int MAX_ITERATIONS = 20; - while (iterations < MAX_ITERATIONS) + while (iterations < MAX_ITERATIONS && !puzzleStates.isEmpty()) { PuzzleState solution = checkSolutionOverlaps(puzzleStates.remove()); - if (solution == null && puzzleStates.isEmpty()) + if (solution == null) { - return null; + continue; } - else if (solution != null && solution.numberOfGray == 0) - { // If solved - return solution.grid; - } - /* If unable to find answer, assume a square if filled or empty and then try solving again */ - if (solution != null) + if (solution.numberOfGray == 0) { - puzzleStates.add(setFirstUnknownTo(solution, FILLED)); - puzzleStates.add(setFirstUnknownTo(solution, EMPTY)); + if (gridSatisfiesSums(solution.grid, rowSums, colSums)) + { + return solution.grid; + } + + iterations++; + continue; } + /* If unable to find answer, assume a square is filled or empty and then try solving again */ + puzzleStates.add(setFirstUnknownTo(solution, FILLED)); + puzzleStates.add(setFirstUnknownTo(solution, EMPTY)); iterations++; } return null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/swansong/FishMonkfish.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/swansong/FishMonkfish.java index bc9e2f210b..c81693fed2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/swansong/FishMonkfish.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/swansong/FishMonkfish.java @@ -31,7 +31,11 @@ import net.runelite.api.ItemContainer; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameTick; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.InventoryID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.eventbus.Subscribe; import java.util.Arrays; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/taibwowannaitrio/TaiBwoWannaiTrio.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/taibwowannaitrio/TaiBwoWannaiTrio.java index 381941bd11..d9594b25c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/taibwowannaitrio/TaiBwoWannaiTrio.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/taibwowannaitrio/TaiBwoWannaiTrio.java @@ -589,7 +589,7 @@ public ArrayList getPanels() smallFishingNet, pestleAndMortar, spear, agilityPotion4, rangedOrMagic, tinderbox, slicedBananaOrKnife, logsForFire)); allSteps.add(new PanelDetails("Gathering quest materials", Arrays.asList(fishKarambwaji, goToLubufu, getMoreVessel, fillVessel, getRum, sliceBanana, makeBananaRum), smallFishingNet, slicedBananaOrKnife)); - allSteps.add(new PanelDetails("Helping Tiadechel", talkToTiadeche1, giveVessel, askAboutResearch)); + allSteps.add(new PanelDetails("Helping Tiadeche", talkToTiadeche1, giveVessel, askAboutResearch)); allSteps.add(new PanelDetails("Collecting final items", Arrays.asList(pickupSeaweed, getJogreBones, burnBones, pickupBurntBones, makeKarambwanjiPaste, usePasteOnBones, getPoisonKarambwan, cookBones, cookKarambwan, usePestleOnKarambwan, usePasteOnSpear), tinderbox, karambwanji, pestleAndMortar)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/templeofikov/TempleOfIkov.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/templeofikov/TempleOfIkov.java index 60ac9eb2ff..04178d1a78 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/templeofikov/TempleOfIkov.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/templeofikov/TempleOfIkov.java @@ -56,13 +56,13 @@ public class TempleOfIkov extends BasicQuestHelper { //Items Required - ItemRequirement pendantOfLucien, bootsOfLightness, limpwurt20, yewOrBetterBow, knife, lightSource, lever, iceArrows20, iceArrows, shinyKey, + ItemRequirement pendantOfLucien, bootsOfLightness, limpwurt20, yewOrBetterBow, throwableWeapon, yewOrBetterBowOrThrowableWeapon, knife, lightSource, lever, iceArrows20, iceArrowsWithThrowableWeapon, enoughArrows, iceArrows, shinyKey, armadylPendant, staffOfArmadyl, pendantOfLucienEquipped, bootsOfLightnessEquipped, iceArrowsEquipped; Requirement emptyInventorySpot; Requirement belowMinus1Weight, below4Weight, inEntryRoom, inNorthRoom, inBootsRoom, dontHaveBoots, inMainOrNorthRoom, - leverNearby, pulledLever, inArrowRoom, hasEnoughArrows, lesNearby, inLesRoom, inWitchRoom, inDemonArea, + leverNearby, pulledLever, inArrowRoom, hasArrowsWithThrowableWeapon, hasEnoughArrows, lesNearby, inLesRoom, inWitchRoom, inDemonArea, inArmaRoom; QuestStep talkToLucien, prepare, prepareBelow0, enterDungeonForBoots, enterDungeon, goDownToBoots, getBoots, goUpFromBoots, pickUpLever, @@ -181,12 +181,18 @@ protected void setupRequirements() yewOrBetterBow = new ItemRequirement("Yew, magic, or dark bow", ItemID.YEW_SHORTBOW).isNotConsumed(); yewOrBetterBow.addAlternates(ItemID.YEW_LONGBOW, ItemID.TRAIL_COMPOSITE_BOW_YEW, ItemID.MAGIC_SHORTBOW, ItemID.MAGIC_SHORTBOW_I, ItemID.MAGIC_LONGBOW, ItemID.DARKBOW); + throwableWeapon = new ItemRequirement("Throwable Weapon", ItemCollections.THROWING_KNIVES); + throwableWeapon.addAlternates(ItemCollections.DARTS); + throwableWeapon.addAlternates(ItemCollections.THROWING_AXES); + yewOrBetterBowOrThrowableWeapon = new ItemRequirements(LogicType.OR, "Yew, magic, dark bow, or thrown ranged weapons (darts, knives, thrownaxes)", yewOrBetterBow, throwableWeapon); knife = new ItemRequirement("Knife to get the boots of lightness", ItemID.KNIFE).isNotConsumed(); lightSource = new ItemRequirement("A light source to get the boots of lightness", ItemCollections.LIGHT_SOURCES).isNotConsumed(); iceArrows20 = new ItemRequirement("Ice arrows", ItemID.ICE_ARROW, 20); iceArrows = new ItemRequirement("Ice arrows", ItemID.ICE_ARROW); + iceArrowsWithThrowableWeapon = new ItemRequirements(LogicType.AND, "Ice Arrow with Throwable Weapon", iceArrows, throwableWeapon); + enoughArrows = new ItemRequirements(LogicType.OR, "Sufficient Arrows", iceArrows20, iceArrowsWithThrowableWeapon); iceArrowsEquipped = new ItemRequirement("Ice arrows", ItemID.ICE_ARROW, 1, true); lever = new ItemRequirement("Lever", ItemID.IKOV_LEVER); lever.setHighlightInInventory(true); @@ -236,10 +242,11 @@ public void setupConditions() inBootsRoom = new ZoneRequirement(bootsRoom); inMainOrNorthRoom = new Conditions(LogicType.OR, inEntryRoom, inNorthRoom, inLesRoom); - pulledLever = new Conditions(true, LogicType.OR, new WidgetTextRequirement(229, 1, "You hear the clunking of some hidden machinery.")); + pulledLever = new Conditions(true, LogicType.OR, new WidgetTextRequirement(229, 3, "You hear the clunking of some hidden machinery.")); leverNearby = new ObjectCondition(ObjectID.IKOV_MENDEDLEVER, new WorldPoint(2671, 9804, 0)); inArrowRoom = new ZoneRequirement(arrowRoom1, arrowRoom2, arrowRoom3); - hasEnoughArrows = new Conditions(true, LogicType.OR, iceArrows20); + hasArrowsWithThrowableWeapon = new Conditions(true, LogicType.AND, iceArrows, throwableWeapon); + hasEnoughArrows = new Conditions(true, LogicType.OR, iceArrows20, hasArrowsWithThrowableWeapon); lesNearby = new NpcCondition(NpcID.IKOV_FIREWARRIOR); inWitchRoom = new ZoneRequirement(witchRoom); @@ -256,20 +263,20 @@ public void setupSteps() talkToLucien.addDialogSteps("I'm a mighty hero!", "That sounds like a laugh!"); prepare = new DetailedQuestStep(this, "Get your weight below 0kg. You can get boots of lightness from the Temple of Ikov north of East Ardougne for -4.5kg.", - pendantOfLucienEquipped, limpwurt20, yewOrBetterBow); + pendantOfLucienEquipped, limpwurt20, yewOrBetterBowOrThrowableWeapon); prepareBelow0 = new DetailedQuestStep(this, "Get your weight below 0kg.", - pendantOfLucienEquipped, limpwurt20, yewOrBetterBow); + pendantOfLucienEquipped, limpwurt20, yewOrBetterBowOrThrowableWeapon); prepare.addSubSteps(prepareBelow0); enterDungeonForBoots = new ObjectStep(this, ObjectID.LADDER_CELLAR, new WorldPoint(2677, 3405, 0), "Enter the Temple of Ikov. You can get Boots of Lightness inside to get -4.5kg.", - pendantOfLucienEquipped, knife, lightSource, limpwurt20, yewOrBetterBow); + pendantOfLucienEquipped, knife, lightSource, limpwurt20, yewOrBetterBowOrThrowableWeapon); enterDungeon = new ObjectStep(this, ObjectID.LADDER_CELLAR, new WorldPoint(2677, 3405, 0), - "Enter the Temple of Ikov north of East Ardougne.", pendantOfLucienEquipped, yewOrBetterBow, limpwurt20); + "Enter the Temple of Ikov north of East Ardougne.", pendantOfLucienEquipped, yewOrBetterBowOrThrowableWeapon, limpwurt20); enterDungeon.addSubSteps(enterDungeonForBoots); @@ -285,7 +292,7 @@ public void setupSteps() pullLever = new ObjectStep(this, ObjectID.IKOV_MENDEDLEVER, new WorldPoint(2671, 9804, 0), "Pull the lever."); enterArrowRoom = new ObjectStep(this, ObjectID.IKOV_MENDEDLEVERDOORL, new WorldPoint(2662, 9803, 0), "Enter the south gate."); - collectArrows = new ObjectStep(this, ObjectID.IKOV_CHESTCLOSED, "Search the chests in the ice area of this room until you have at least 20 Ice Arrows or more to be safe. A random chest has the arrows each time.", iceArrows20); + collectArrows = new ObjectStep(this, ObjectID.IKOV_CHESTCLOSED, "Search the chests in the ice area of this room until you have at least 20 Ice Arrows or more to be safe. If using a throwable weapon (darts, knives) a single Ice Arrow is sufficient. A random chest has the arrows each time.", enoughArrows); collectArrows.setHideWorldArrow(true); collectArrows.addAlternateObjects(ObjectID.IKOV_CHESTOPEN); @@ -300,10 +307,10 @@ public void setupSteps() goSearchThievingLever.addSubSteps(goPullThievingLever); tryToEnterWitchRoom = new ObjectStep(this, ObjectID.IKOV_FIREWARRIORDOOR, new WorldPoint(2646, 9870, 0), - "Try to enter the far north door. Be prepared to fight Lesarkus, who can only be hurt by ice arrows.", yewOrBetterBow, iceArrowsEquipped); + "Try to enter the far north door. Be prepared to fight Lesarkus, who can only be hurt by ice arrows.", yewOrBetterBowOrThrowableWeapon, iceArrowsEquipped); fightLes = new NpcStep(this, NpcID.IKOV_FIREWARRIOR, new WorldPoint(2646, 9866, 0), - "Kill the Fire Warrior of Lesarkus. He can only be hurt by the ice arrows.", yewOrBetterBow, iceArrowsEquipped); + "Kill the Fire Warrior of Lesarkus. He can only be hurt by the ice arrows.", yewOrBetterBowOrThrowableWeapon, iceArrowsEquipped); enterDungeonKilledLes = new ObjectStep(this, ObjectID.LADDER_CELLAR, new WorldPoint(2677, 3405, 0), "Enter the Temple of Ikov north of East Ardougne.", pendantOfLucienEquipped, limpwurt20); @@ -351,7 +358,7 @@ public void setupSteps() public List getItemRequirements() { ArrayList reqs = new ArrayList<>(); - reqs.add(yewOrBetterBow); + reqs.add(yewOrBetterBowOrThrowableWeapon); reqs.add(limpwurt20); reqs.add(knife); reqs.add(lightSource); @@ -405,7 +412,7 @@ public List getPanels() allSteps.add(new PanelDetails("Defeat Lesarkus", Arrays.asList(prepare, enterDungeon, goDownToBoots, getBoots, goUpFromBoots, pickUpLever, useLeverOnHole, pullLever, enterArrowRoom, collectArrows, returnToMainRoom, goSearchThievingLever, - tryToEnterWitchRoom, fightLes), pendantOfLucien, yewOrBetterBow, knife, lightSource, limpwurt20)); + tryToEnterWitchRoom, fightLes), pendantOfLucien, yewOrBetterBowOrThrowableWeapon, knife, lightSource, limpwurt20)); allSteps.add(new PanelDetails("Explore deeper", Arrays.asList(enterLesDoor, giveWineldaLimps, pickUpKey, pushWall, makeChoice, returnToLucien))); return allSteps; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thecurseofarrav/TheCurseOfArrav.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thecurseofarrav/TheCurseOfArrav.java index 2d193ec06a..072b4eceb6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thecurseofarrav/TheCurseOfArrav.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thecurseofarrav/TheCurseOfArrav.java @@ -50,6 +50,7 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.QuestState; import net.runelite.api.Skill; +import net.runelite.api.annotations.Varbit; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thedigsite/TheDigSite.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thedigsite/TheDigSite.java index 5bfbab6f2a..efe8d25fee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thedigsite/TheDigSite.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thedigsite/TheDigSite.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Zoinkwiz + * Copyright (c) 2026, pajlada * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +33,9 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; @@ -43,145 +47,188 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestSyncStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; - -import java.util.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarPlayerID; +import net.runelite.api.gameval.VarbitID; public class TheDigSite extends BasicQuestHelper { - //Items Required - ItemRequirement pestleAndMortar, vialHighlighted, tinderbox, tea, ropes2, rope, opal, charcoal, specimenBrush, specimenJar, panningTray, - panningTrayFull, trowel, varrock2, digsiteTeleports, sealedLetter, specialCup, teddybear, skull, nitro, nitrate, chemicalCompound, groundCharcoal, invitation, talisman, - mixedChemicals, mixedChemicals2, arcenia, powder, liquid, tablet, key, unstampedLetter, trowelHighlighted, tinderboxHighlighted, chemicalCompoundHighlighted; - - Requirement talkedToFemaleStudent, talkedToOrangeStudent, talkedToGreenStudent, talkedToGuide, letterStamped, hasTeddy, hasSkull, hasSpecialCup, - femaleStudentQ1Learnt, orangeStudentQ1Learnt, greenStudentQ1Learnt, femaleStudentQ2Learnt, orangeStudentQ2Learnt, greenStudentQ2Learnt, femaleStudentQ3Learnt, - femaleExtorting, orangeStudentQ3Learnt, greenStudentQ3Learnt, syncedUp, syncedUp2, syncedUp3, givenTalismanIn, rope1Added, rope2Added, - inUndergroundTemple1, inDougRoom,openedBarrel, searchedBricks, hasKeyOrPowderOrMixtures, openPowderChestNearby, inUndergroundTemple2, - knowStateAsJustStartedQuest, knowStateAsJustCompletedFirstExam, knowStateAsJustCompletedSecondExam; - - QuestStep talkToExaminer, talkToHaig, talkToExaminer2, searchBush, takeTray, talkToGuide, panWater, pickpocketWorkmen, talkToFemaleStudent, talkToFemaleStudent2, - talkToOrangeStudent, talkToOrangeStudent2, talkToGreenStudent, talkToGreenStudent2, takeTest1, talkToFemaleStudent3, talkToOrangeStudent3, talkToGreenStudent3, - takeTest2, talkToFemaleStudent4, takeTest3, getJar, getBrush, digForTalisman, talkToExpert, useInvitationOnWorkman, useRopeOnWinch, goDownWinch, pickUpRoot, - searchBricks, goUpRope, goDownToDoug, talkToDoug, goUpFromDoug, unlockChest, searchChest, useTrowelOnBarrel, useVialOnBarrel, usePowderOnExpert, useLiquidOnExpert, - mixNitroWithNitrate, grindCharcoal, addCharcoal, addRoot, goDownToExplode, useCompound, useTinderbox, takeTablet, useTabletOnExpert, syncStep, talkToFemaleStudent5, - talkToOrangeStudent4, talkToGreenStudent4, useRopeOnWinch2, goDownToExplode2, goDownForTablet, goUpWithTablet, searchPanningTray; - - //Zones - Zone undergroundTemple1, dougRoom, undergroundTemple2; + // Required items + ItemRequirement pestleAndMortar; + ItemRequirement vial; + ItemRequirement tinderbox; + ItemRequirement tea; + ItemRequirement ropes2; + ItemRequirement rope; + ItemRequirement opal; + ItemRequirement charcoal; + + // Recommended items + ItemRequirement varrock2; + ItemRequirement digsiteTeleports; + + // Mid-quest item requirements + ItemRequirement specimenBrush; + ItemRequirement specimenJar; + ItemRequirement panningTray; + ItemRequirement panningTrayFull; + ItemRequirement trowel; + ItemRequirement sealedLetter; + ItemRequirement specialCup; + ItemRequirement teddybear; + ItemRequirement skull; + ItemRequirement nitro; + ItemRequirement nitrate; + ItemRequirement chemicalCompound; + ItemRequirement groundCharcoal; + ItemRequirement invitation; + ItemRequirement talisman; + ItemRequirement mixedChemicals; + ItemRequirement mixedChemicals2; + ItemRequirement arcenia; + + ItemRequirement powder; + ItemRequirement liquid; + ItemRequirement tablet; + ItemRequirement key; + ItemRequirement unstampedLetter; + ItemRequirement trowelHighlighted; + ItemRequirement chemicalCompoundHighlighted; + + // Zones + Zone undergroundTemple1; + Zone undergroundTemple2; + Zone dougRoom; + + // Miscellaneous requirements + Conditions talkedToFemaleStudent; + Conditions talkedToOrangeStudent; + Conditions talkedToGreenStudent; + VarbitRequirement talkedToGuide; + VarbitRequirement letterStamped; + Conditions hasTeddy; + Conditions hasSkull; + Conditions hasSpecialCup; + Conditions femaleStudentQ1Learnt; + Conditions orangeStudentQ1Learnt; + Conditions greenStudentQ1Learnt; + Conditions femaleStudentQ2Learnt; + Conditions orangeStudentQ2Learnt; + Conditions greenStudentQ2Learnt; + Conditions femaleStudentQ3Learnt; + Conditions femaleExtorting; + Conditions orangeStudentQ3Learnt; + Conditions greenStudentQ3Learnt; + Conditions syncedUp; + Conditions syncedUp2; + Conditions syncedUp3; + VarbitRequirement givenTalismanIn; + VarbitRequirement rope1Added; + VarbitRequirement rope2Added; + ZoneRequirement inUndergroundTemple1; + ZoneRequirement inDougRoom; + VarbitRequirement openedBarrel; + VarbitRequirement searchedBricks; + Conditions hasKeyOrPowderOrMixtures; + ObjectCondition openPowderChestNearby; + ZoneRequirement inUndergroundTemple2; + Conditions knowStateAsJustStartedQuest; + Conditions knowStateAsJustCompletedFirstExam; + Conditions knowStateAsJustCompletedSecondExam; + + // Steps + NpcStep talkToExaminer; + NpcStep talkToHaig; + NpcStep talkToExaminer2; + + ObjectStep searchBush; + DetailedQuestStep takeTray; + NpcStep talkToGuide; + ObjectStep panWater; + DetailedQuestStep searchPanningTray; + + NpcStep pickpocketWorkmen; + NpcStep talkToFemaleStudent; + NpcStep talkToOrangeStudent; + NpcStep talkToGreenStudent; + NpcStep talkToFemaleStudent2; + NpcStep talkToOrangeStudent2; + NpcStep talkToGreenStudent2; + NpcStep takeTest1; + + NpcStep talkToFemaleStudent3; + NpcStep talkToOrangeStudent3; + NpcStep talkToGreenStudent3; + NpcStep takeTest2; + + NpcStep talkToFemaleStudent5; + NpcStep talkToOrangeStudent4; + NpcStep talkToGreenStudent4; + NpcStep talkToFemaleStudent4; + NpcStep takeTest3; + + ObjectStep getJar; + NpcStep getBrush; + ObjectStep digForTalisman; + NpcStep talkToExpert; + + NpcStep useInvitationOnWorkman; + ObjectStep useRopeOnWinch; + ObjectStep goDownWinch; + ItemStep pickUpRoot; + ObjectStep searchBricks; + + ObjectStep goUpRope; + ObjectStep useRopeOnWinch2; + ObjectStep goDownToDoug; + NpcStep talkToDoug; + ObjectStep goUpFromDoug; + ObjectStep unlockChest; + ObjectStep searchChest; + ObjectStep useTrowelOnBarrel; + ObjectStep useVialOnBarrel; + NpcStep usePowderOnExpert; + NpcStep useLiquidOnExpert; + DetailedQuestStep mixNitroWithNitrate; + DetailedQuestStep grindCharcoal; + DetailedQuestStep addCharcoal; + DetailedQuestStep addRoot; + ObjectStep goDownToExplode; + ObjectStep goDownToExplode2; + ObjectStep useCompound; + + ObjectStep useTinderbox; + DetailedQuestStep waitForBricksToBlowUp; + ObjectStep takeTablet; + ObjectStep goDownForTablet; + + ObjectStep goUpWithTablet; + NpcStep useTabletOnExpert; + + QuestSyncStep syncStep; @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); - - steps.put(0, talkToExaminer); - - ConditionalStep returnWithLetter = new ConditionalStep(this, talkToHaig); - // This is used to set knowStateAsJustStartedQuest to true - returnWithLetter.addStep(new Conditions(LogicType.NOR, knowStateAsJustStartedQuest), talkToExaminer); - returnWithLetter.addStep(letterStamped, talkToExaminer2); - steps.put(1, returnWithLetter); - - ConditionalStep goTakeTest1 = new ConditionalStep(this, syncStep); - // Sets the state of knowStateAsJustCompleted to true for ConditionalStep after this - goTakeTest1.addStep(new Conditions(LogicType.NOR, knowStateAsJustCompletedFirstExam), takeTest1); - - goTakeTest1.addStep(new Conditions(femaleStudentQ1Learnt, orangeStudentQ1Learnt, greenStudentQ1Learnt), takeTest1); - goTakeTest1.addStep(new Conditions(femaleStudentQ1Learnt, orangeStudentQ1Learnt, talkedToGreenStudent), talkToGreenStudent2); - goTakeTest1.addStep(new Conditions(femaleStudentQ1Learnt, orangeStudentQ1Learnt, hasSkull, specimenBrush), - talkToGreenStudent); - - goTakeTest1.addStep(new Conditions(femaleStudentQ1Learnt, talkedToOrangeStudent, hasSkull, specimenBrush), talkToOrangeStudent2); - goTakeTest1.addStep(new Conditions(femaleStudentQ1Learnt, hasSpecialCup, hasSkull, specimenBrush), talkToOrangeStudent); - - goTakeTest1.addStep(new Conditions(talkedToFemaleStudent, hasSpecialCup, hasSkull, specimenBrush), talkToFemaleStudent2); - goTakeTest1.addStep(new Conditions(hasTeddy, hasSpecialCup, hasSkull, specimenBrush), talkToFemaleStudent); - - goTakeTest1.addStep(new Conditions(syncedUp, hasTeddy, hasSpecialCup), pickpocketWorkmen); - goTakeTest1.addStep(new Conditions(syncedUp, hasTeddy, panningTrayFull, talkedToGuide), searchPanningTray); - goTakeTest1.addStep(new Conditions(syncedUp, hasTeddy, panningTray, talkedToGuide), panWater); - goTakeTest1.addStep(new Conditions(syncedUp, hasTeddy, panningTray), talkToGuide); - goTakeTest1.addStep(new Conditions(syncedUp, hasTeddy), takeTray); - goTakeTest1.addStep(syncedUp, searchBush); - steps.put(2, goTakeTest1); - - ConditionalStep goTakeTest2 = new ConditionalStep(this, syncStep); - // Sets the state of knowStateAsJustCompletedFirstExam to true for ConditionalStep after this - goTakeTest1.addStep(new Conditions(LogicType.NOR, knowStateAsJustCompletedSecondExam), takeTest2); - - goTakeTest2.addStep(new Conditions(syncedUp2, femaleStudentQ2Learnt, orangeStudentQ2Learnt, greenStudentQ2Learnt), takeTest2); - goTakeTest2.addStep(new Conditions(syncedUp2, femaleStudentQ2Learnt, orangeStudentQ2Learnt), talkToGreenStudent3); - goTakeTest2.addStep(new Conditions(syncedUp2, femaleStudentQ2Learnt), talkToOrangeStudent3); - goTakeTest2.addStep(syncedUp2, talkToFemaleStudent3); - steps.put(3, goTakeTest2); - - ConditionalStep goTakeTest3 = new ConditionalStep(this, syncStep); - goTakeTest3.addStep(new Conditions(femaleStudentQ3Learnt, orangeStudentQ3Learnt, greenStudentQ3Learnt), takeTest3); - goTakeTest3.addStep(new Conditions(syncedUp3, femaleStudentQ3Learnt, orangeStudentQ3Learnt), talkToGreenStudent4); - goTakeTest3.addStep(new Conditions(syncedUp3, femaleStudentQ3Learnt), talkToOrangeStudent4); - goTakeTest3.addStep(new Conditions(syncedUp3, femaleExtorting), talkToFemaleStudent5); - goTakeTest3.addStep(syncedUp3, talkToFemaleStudent4); - steps.put(4, goTakeTest3); - - ConditionalStep findTalisman = new ConditionalStep(this, getJar); - findTalisman.addStep(new Conditions(givenTalismanIn), useInvitationOnWorkman); - findTalisman.addStep(new Conditions(talisman), talkToExpert); - findTalisman.addStep(new Conditions(specimenJar, specimenBrush), digForTalisman); - findTalisman.addStep(new Conditions(specimenJar), getBrush); - steps.put(5, findTalisman); - - ConditionalStep learnHowToMakeExplosives = new ConditionalStep(this, useRopeOnWinch2); - learnHowToMakeExplosives.addStep(inDougRoom, talkToDoug); - learnHowToMakeExplosives.addStep(new Conditions(inUndergroundTemple1, arcenia), goUpRope); - learnHowToMakeExplosives.addStep(inUndergroundTemple1, pickUpRoot); - learnHowToMakeExplosives.addStep(new Conditions(rope2Added), goDownToDoug); - - ConditionalStep makeExplosives = new ConditionalStep(this, goDownWinch); - makeExplosives.addStep(new Conditions(chemicalCompound, inUndergroundTemple1), useCompound); - - makeExplosives.addStep(inDougRoom, goUpFromDoug); - makeExplosives.addStep(new Conditions(inUndergroundTemple1, arcenia), goUpRope); - makeExplosives.addStep(inUndergroundTemple1, pickUpRoot); - - makeExplosives.addStep(new Conditions(chemicalCompound), goDownToExplode); - makeExplosives.addStep(new Conditions(arcenia, mixedChemicals2), addRoot); - makeExplosives.addStep(new Conditions(arcenia, mixedChemicals, groundCharcoal), addCharcoal); - makeExplosives.addStep(new Conditions(arcenia, mixedChemicals), grindCharcoal); - makeExplosives.addStep(new Conditions(arcenia, nitrate, nitro), mixNitroWithNitrate); - makeExplosives.addStep(new Conditions(arcenia, powder, nitro), usePowderOnExpert); - makeExplosives.addStep(new Conditions(arcenia, powder, liquid), useLiquidOnExpert); - makeExplosives.addStep(new Conditions(arcenia, powder, liquid), useVialOnBarrel); - makeExplosives.addStep(new Conditions(arcenia, powder, openedBarrel), useVialOnBarrel); - makeExplosives.addStep(new Conditions(arcenia, powder), useTrowelOnBarrel); - makeExplosives.addStep(new Conditions(openPowderChestNearby, arcenia), searchChest); - makeExplosives.addStep(arcenia, unlockChest); - - ConditionalStep discovery = new ConditionalStep(this, useRopeOnWinch); - discovery.addStep(hasKeyOrPowderOrMixtures, makeExplosives); - discovery.addStep(searchedBricks, learnHowToMakeExplosives); - discovery.addStep(new Conditions(inUndergroundTemple1, arcenia), searchBricks); - discovery.addStep(inUndergroundTemple1, pickUpRoot); - discovery.addStep(rope1Added, goDownWinch); - steps.put(6, discovery); - - ConditionalStep explodeWall = new ConditionalStep(this, goDownToExplode2); - explodeWall.addStep(inUndergroundTemple1, useTinderbox); - steps.put(7, explodeWall); - - ConditionalStep completeQuest = new ConditionalStep(this, goDownForTablet); - completeQuest.addStep(new Conditions(tablet.alsoCheckBank(), inUndergroundTemple2), goUpWithTablet); - completeQuest.addStep(new Conditions(tablet.alsoCheckBank()), useTabletOnExpert); - completeQuest.addStep(inUndergroundTemple2, takeTablet); - steps.put(8, completeQuest); - - return steps; + undergroundTemple1 = new Zone(new WorldPoint(3359, 9800, 0), new WorldPoint(3393, 9855, 0)); + undergroundTemple2 = new Zone(new WorldPoint(3360, 9734, 0), new WorldPoint(3392, 9790, 0)); + dougRoom = new Zone(new WorldPoint(3340, 9809, 0), new WorldPoint(3357, 9826, 0)); } @Override @@ -189,10 +236,9 @@ protected void setupRequirements() { pestleAndMortar = new ItemRequirement("Pestle and mortar", ItemID.PESTLE_AND_MORTAR).isNotConsumed(); pestleAndMortar.setHighlightInInventory(true); - vialHighlighted = new ItemRequirement("Vial", ItemID.VIAL_EMPTY); - vialHighlighted.setHighlightInInventory(true); + vial = new ItemRequirement("Vial", ItemID.VIAL_EMPTY); + vial.setHighlightInInventory(true); tinderbox = new ItemRequirement("Tinderbox", ItemID.TINDERBOX).isNotConsumed(); - tinderboxHighlighted = tinderbox.highlighted(); tea = new ItemRequirement("Cup of tea", ItemID.CUP_OF_TEA); ropes2 = new ItemRequirement("Rope", ItemID.ROPE, 2); rope = new ItemRequirement("Rope", ItemID.ROPE); @@ -203,6 +249,10 @@ protected void setupRequirements() charcoal = new ItemRequirement("Charcoal", ItemID.CHARCOAL); charcoal.setTooltip("Obtainable during quest by searching specimen trays"); charcoal.setHighlightInInventory(true); + + varrock2 = new ItemRequirement("Varrock teleports", ItemID.POH_TABLET_VARROCKTELEPORT, 2); + digsiteTeleports = new ItemRequirement("Digsite teleports", ItemID.TELEPORTSCROLL_DIGSITE, 2); + specimenBrush = new ItemRequirement("Specimen brush", ItemID.SPECIMEN_BRUSH).isNotConsumed(); specimenJar = new ItemRequirement("Specimen jar", ItemID.SPECIMEN_JAR).isNotConsumed(); panningTray = new ItemRequirement("Panning tray", ItemID.TRAY_EMPTY).isNotConsumed(); @@ -213,8 +263,6 @@ protected void setupRequirements() trowelHighlighted = new ItemRequirement("Trowel", ItemID.TROWEL).isNotConsumed(); trowelHighlighted.setHighlightInInventory(true); trowelHighlighted.setTooltip("You can get another from one of the Examiners"); - varrock2 = new ItemRequirement("Varrock teleports", ItemID.POH_TABLET_VARROCKTELEPORT, 2); - digsiteTeleports = new ItemRequirement("Digsite teleports", ItemID.TELEPORTSCROLL_DIGSITE, 2); sealedLetter = new ItemRequirement("Sealed letter", ItemID.RECOMMENDEDLETTER); sealedLetter.setTooltip("You can get another from Curator Haig in the Varrock Museum"); specialCup = new ItemRequirement("Special cup", ItemID.ROCK_SAMPLE2); @@ -251,28 +299,15 @@ protected void setupRequirements() key.setHighlightInInventory(true); unstampedLetter = new ItemRequirement("Unstamped letter", ItemID.DIGPLAINLETTER); unstampedLetter.setTooltip("You can get another from the Exam Centre's examiners"); - } - @Override - protected void setupZones() - { - undergroundTemple1 = new Zone(new WorldPoint(3359, 9800, 0), new WorldPoint(3393, 9855, 0)); - undergroundTemple2 = new Zone(new WorldPoint(3360, 9734, 0), new WorldPoint(3392, 9790, 0)); - dougRoom = new Zone(new WorldPoint(3340, 9809, 0), new WorldPoint(3357, 9826, 0)); - } - - public void setupConditions() - { inUndergroundTemple1 = new ZoneRequirement(undergroundTemple1); inUndergroundTemple2 = new ZoneRequirement(undergroundTemple2); inDougRoom = new ZoneRequirement(dougRoom); - knowStateAsJustStartedQuest = new Conditions(true, new VarplayerRequirement(VarPlayerID.ITEXAMLEVEL, 1, Operation.LESS_EQUAL)); knowStateAsJustCompletedFirstExam = new Conditions(true, new VarplayerRequirement(VarPlayerID.ITEXAMLEVEL, 2, Operation.LESS_EQUAL)); knowStateAsJustCompletedSecondExam = new Conditions(true, new VarplayerRequirement(VarPlayerID.ITEXAMLEVEL, 3, Operation.LESS_EQUAL)); - syncedUp = new Conditions(true, LogicType.OR, knowStateAsJustStartedQuest, new WidgetTextRequirement(InterfaceID.Questjournal.TITLE, "The Dig Site")); @@ -282,14 +317,13 @@ public void setupConditions() new DialogRequirement("Hey! Excellent!")); syncedUp3 = new Conditions(true, LogicType.OR, knowStateAsJustCompletedSecondExam, - new WidgetTextRequirement(119, 2, "The Dig Site"), + new WidgetTextRequirement(InterfaceID.Questjournal.TITLE, "The Dig Site"), new DialogRequirement("You got all the questions correct, well done!"), new DialogRequirement("Great, I'm getting good at this.")); talkedToGuide = new VarbitRequirement(VarbitID.ITDIGSITETEA, 1); tea = tea.hideConditioned(talkedToGuide); - // Exam questions 1 talkedToFemaleStudent = new Conditions(true, LogicType.OR, new DialogRequirement("Hey! My lucky mascot!"), @@ -302,7 +336,7 @@ public void setupConditions() orangeGivenAnswer1Diary.addRange(20, 35); talkedToOrangeStudent = new Conditions(true, LogicType.OR, new DialogRequirement("Look what I found!"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "to find it and return it to him.")); + new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "He has lost his Special Cup")); orangeStudentQ1Learnt = new Conditions(true, LogicType.OR, new DialogRequirement("The people eligible to use the digsite are:"), orangeGivenAnswer1Diary); @@ -312,7 +346,7 @@ public void setupConditions() talkedToGreenStudent = new Conditions(true, LogicType.OR, new DialogRequirement("Oh wow! You've found it!"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "to him; maybe someone has picked it up?")); + new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "He has lost his Animal Skull")); greenStudentQ1Learnt = new Conditions(true, LogicType.OR, new DialogRequirement("The study of Earth Sciences is:"), greenGivenAnswer1Diary); @@ -341,7 +375,7 @@ public void setupConditions() new DialogRequirement("OK, I'll see what I can turn up for you."), new DialogRequirement("Well, I have seen people get them from panning"), new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I need to bring her an opal")); - WidgetTextRequirement femaleGivenAnswer3Diary = new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I need to speak to the student in the purple skirt about"); + WidgetTextRequirement femaleGivenAnswer3Diary = new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I need to bring her an opal"); femaleGivenAnswer3Diary.addRange(56, 63); femaleStudentQ3Learnt = new Conditions(true, LogicType.OR, new DialogRequirement("Sample preparation: Samples cleaned"), @@ -354,7 +388,7 @@ public void setupConditions() orangeGivenAnswer3Diary); WidgetTextRequirement greenGivenAnswer3Diary = new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I need to speak to the student in the green top about the"); - greenGivenAnswer3Diary.addRange(56, 63); + greenGivenAnswer3Diary.addRange(54, 63); greenStudentQ3Learnt = new Conditions(true, LogicType.OR, new DialogRequirement("Specimen brush use: Brush carefully"), greenGivenAnswer3Diary); @@ -366,25 +400,24 @@ public void setupConditions() rope2Added = new VarbitRequirement(VarbitID.ITDIGSITEWINCH2, 1); // 45 - 54 - hasTeddy = new Conditions(LogicType.OR, teddybear, talkedToFemaleStudent); - hasSkull = new Conditions(LogicType.OR, skull, talkedToGreenStudent); - hasSpecialCup = new Conditions(LogicType.OR, specialCup, talkedToOrangeStudent); + hasTeddy = or(teddybear, talkedToFemaleStudent); + hasSkull = or(skull, talkedToGreenStudent); + hasSpecialCup = or(specialCup, talkedToOrangeStudent); letterStamped = new VarbitRequirement(VarbitID.ITCURATORLETTER, 1); - searchedBricks = new VarbitRequirement(VarbitID.ITDIGSITEHINT, 1); openPowderChestNearby = new ObjectCondition(ObjectID.DIGCHESTOPEN); openedBarrel = new VarbitRequirement(VarbitID.ITDIGSITEBARREL, 1); - hasKeyOrPowderOrMixtures = new Conditions(LogicType.OR, - key, powder, nitrate, mixedChemicals, mixedChemicals2, chemicalCompound, openPowderChestNearby); + hasKeyOrPowderOrMixtures = or(key, powder, nitrate, mixedChemicals, mixedChemicals2, chemicalCompound, openPowderChestNearby); } public void setupSteps() { talkToExaminer = new NpcStep(this, NpcID.EXAMINER, new WorldPoint(3362, 3337, 0), "Talk to an Examiner in the Exam Centre south east of Varrock."); talkToExaminer.addDialogStep("Can I take an exam?"); - ((NpcStep) (talkToExaminer)).addAlternateNpcs(NpcID.QIP_DIGSITE_EXAMINER_02, NpcID.QIP_DIGSITE_EXAMINER_03); + talkToExaminer.addDialogStep("Yes."); + talkToExaminer.addAlternateNpcs(NpcID.QIP_DIGSITE_EXAMINER_02, NpcID.QIP_DIGSITE_EXAMINER_03); talkToHaig = new NpcStep(this, NpcID.CURATOR, new WorldPoint(3257, 3448, 0), "Talk to Curator Haig in the Varrock Museum.", unstampedLetter); talkToExaminer2 = new NpcStep(this, NpcID.EXAMINER, new WorldPoint(3362, 3337, 0), "Return to an Examiner in the Exam Centre south east of Varrock.", sealedLetter); @@ -397,8 +430,8 @@ public void setupSteps() panWater.addSubSteps(searchPanningTray); pickpocketWorkmen = new NpcStep(this, NpcID.DIGWORKMAN1, new WorldPoint(3372, 3390, 0), "Pickpocket workmen until you get an animal skull and a specimen brush.", true); - ((NpcStep) (pickpocketWorkmen)).addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); - ((NpcStep) (pickpocketWorkmen)).setMaxRoamRange(100); + pickpocketWorkmen.addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); + pickpocketWorkmen.setMaxRoamRange(100); talkToFemaleStudent = new NpcStep(this, NpcID.STUDENT2, new WorldPoint(3345, 3425, 0), "Talk to the female student in the north west of the Digsite twice.", teddybear); talkToOrangeStudent = new NpcStep(this, NpcID.STUDENT3, new WorldPoint(3369, 3419, 0), "Talk to the student in an orange shirt in the north east of the Digsite twice.", specialCup); talkToGreenStudent = new NpcStep(this, NpcID.STUDENT1, new WorldPoint(3362, 3398, 0), "Talk to the student in a green shirt in the south of the Digsite twice.", skull); @@ -429,21 +462,22 @@ public void setupSteps() "Brush carefully and slowly using short strokes.", "Handle bones very carefully and keep them away from other samples."); getJar = new ObjectStep(this, ObjectID.QIP_DIGSITE_CUPBOARDSHUT, new WorldPoint(3355, 3332, 0), "Search the cupboard on the south wall of the west room of the Exam Centre for a specimen jar."); - ((ObjectStep) (getJar)).addAlternateObjects(ObjectID.QIP_DIGSITE_CUPBOARDOPEN); + getJar.addAlternateObjects(ObjectID.QIP_DIGSITE_CUPBOARDOPEN); getBrush = new NpcStep(this, NpcID.DIGWORKMAN1, new WorldPoint(3372, 3390, 0), "Pickpocket workmen until you get a specimen brush.", true); - ((NpcStep) (getBrush)).addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); - ((NpcStep) (getBrush)).setMaxRoamRange(100); + getBrush.addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); + getBrush.setMaxRoamRange(100); // NOTE: May not need pick digForTalisman = new ObjectStep(this, ObjectID.DIGDUGUPSOIL2, new WorldPoint(3374, 3438, 0), "Dig in the north east dig spot in the Digsite until you get a talisman.", trowelHighlighted, specimenJar, specimenBrush); digForTalisman.addIcon(ItemID.TROWEL); + digForTalisman.addSubSteps(getBrush); talkToExpert = new NpcStep(this, NpcID.ARCHAEOLOGICAL_EXPERT, new WorldPoint(3357, 3334, 0), "Talk to the Archaeological expert in the Exam Centre.", talisman); useInvitationOnWorkman = new NpcStep(this, NpcID.DIGWORKMAN1, new WorldPoint(3360, 3415, 0), "Use the invitation on any workman.", true, invitation); useInvitationOnWorkman.addIcon(ItemID.DIGEXPERTSCROLL); useInvitationOnWorkman.addDialogStep("I lost the letter you gave me."); - ((NpcStep) (useInvitationOnWorkman)).addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); - ((NpcStep) (useInvitationOnWorkman)).setMaxRoamRange(100); + useInvitationOnWorkman.addAlternateNpcs(NpcID.QIP_DIGSITE_DIGWORKMAN_03, NpcID.QIP_DIGSITE_DIGWORKMAN_04); + useInvitationOnWorkman.setMaxRoamRange(100); useRopeOnWinch = new ObjectStep(this, ObjectID.DIGWINCH1, new WorldPoint(3353, 3417, 0), "Use a rope on the west winch.", rope); useRopeOnWinch.addIcon(ItemID.ROPE); goDownWinch = new ObjectStep(this, ObjectID.DIGWINCH1, new WorldPoint(3353, 3417, 0), "Climb down the west winch."); @@ -463,7 +497,7 @@ public void setupSteps() useTrowelOnBarrel = new ObjectStep(this, ObjectID.DIGBARRELCLOSED, new WorldPoint(3364, 3378, 0), "Use a trowel on the barrel west of the chest's tent.", trowelHighlighted); useTrowelOnBarrel.addIcon(ItemID.TROWEL); - useVialOnBarrel = new ObjectStep(this, ObjectID.DIGBARRELCLOSED, new WorldPoint(3364, 3378, 0), "Use a vial on the barrel west of the chest's tent.", vialHighlighted); + useVialOnBarrel = new ObjectStep(this, ObjectID.DIGBARRELCLOSED, new WorldPoint(3364, 3378, 0), "Use a vial on the barrel west of the chest's tent.", vial); useVialOnBarrel.addIcon(ItemID.VIAL_EMPTY); usePowderOnExpert = new NpcStep(this, NpcID.ARCHAEOLOGICAL_EXPERT, new WorldPoint(3357, 3334, 0), "Use the powder on the Archaeological expert in the Exam Centre.", powder); usePowderOnExpert.addIcon(ItemID.UNIDENTIFIED_POWDER); @@ -471,7 +505,7 @@ public void setupSteps() useLiquidOnExpert.addIcon(ItemID.UNIDENTIFIED_LIQUID); mixNitroWithNitrate = new DetailedQuestStep(this, "Mix the nitroglycerin and ammonium nitrate together.", nitro, nitrate); grindCharcoal = new DetailedQuestStep(this, "Grind charcoal with a pestle and mortar.", pestleAndMortar, charcoal); - addCharcoal = new DetailedQuestStep(this, "Add charcoal to the vial.", groundCharcoal, mixedChemicals); + addCharcoal = new DetailedQuestStep(this, "Add the ground charcoal to the vial.", groundCharcoal, mixedChemicals); addRoot = new DetailedQuestStep(this, "Add arcenia root to the vial.", arcenia, mixedChemicals2); goDownToExplode = new ObjectStep(this, ObjectID.DIGWINCH1, new WorldPoint(3353, 3417, 0), "Climb down the rope on the west winch.", chemicalCompound, tinderbox); goDownToExplode2 = new ObjectStep(this, ObjectID.DIGWINCH1, new WorldPoint(3353, 3417, 0), "Climb down the rope on the west winch.", tinderbox); @@ -479,8 +513,10 @@ public void setupSteps() useCompound = new ObjectStep(this, ObjectID.DIGBLASTBRICK, new WorldPoint(3378, 9824, 0), "Use the compound on the bricks to the south.", chemicalCompoundHighlighted); useCompound.addIcon(ItemID.DIGCOMPOUND); - useTinderbox = new ObjectStep(this, ObjectID.DIGBLASTBRICK, new WorldPoint(3378, 9824, 0), "Use a tinderbox on the bricks to the south.", tinderboxHighlighted); + useTinderbox = new ObjectStep(this, ObjectID.DIGBLASTBRICK, new WorldPoint(3378, 9824, 0), "Use a tinderbox on the bricks to the south.", tinderbox.highlighted()); useTinderbox.addIcon(ItemID.TINDERBOX); + waitForBricksToBlowUp = new DetailedQuestStep(this, new WorldPoint(3378, 9824, 0), "Use a tinderbox on the bricks to the south."); + useTinderbox.addSubSteps(waitForBricksToBlowUp); takeTablet = new ObjectStep(this, ObjectID.QIP_DIGSITE_ZAROS_STONE_TABLET_MULTILOC, new WorldPoint(3373, 9746, 0), "Take the stone tablet in the south room."); goDownForTablet = new ObjectStep(this, ObjectID.DIGWINCH1, new WorldPoint(3353, 3417, 0), "Climb down the rope on the west winch."); takeTablet.addSubSteps(goDownForTablet); @@ -490,35 +526,159 @@ public void setupSteps() useTabletOnExpert.addIcon(ItemID.ZAROSSTONETABLET); useTabletOnExpert.addSubSteps(goUpWithTablet); - syncStep = new DetailedQuestStep(this, "Open the quest's journal to sync your current quest state."); + syncStep = new QuestSyncStep(this, getQuest(), "Open the quest's journal to sync your current quest state."); } @Override - public List getNotes() + public Map loadSteps() { - return Collections.singletonList("This quest helper is susceptible to getting out of sync with the actual quest. If this happens to you, opening up the quest's journal should fix it."); + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToExaminer); + + var returnWithLetter = new ConditionalStep(this, talkToHaig); + // This is used to set knowStateAsJustStartedQuest to true + returnWithLetter.addStep(nor(knowStateAsJustStartedQuest), talkToExaminer); + returnWithLetter.addStep(letterStamped, talkToExaminer2); + steps.put(1, returnWithLetter); + + var goTakeTest1 = new ConditionalStep(this, syncStep); + // Sets the state of knowStateAsJustCompleted to true for ConditionalStep after this + goTakeTest1.addStep(nor(knowStateAsJustCompletedFirstExam), takeTest1); + + goTakeTest1.addStep(and(femaleStudentQ1Learnt, orangeStudentQ1Learnt, greenStudentQ1Learnt), takeTest1); + goTakeTest1.addStep(and(femaleStudentQ1Learnt, orangeStudentQ1Learnt, talkedToGreenStudent), talkToGreenStudent2); + goTakeTest1.addStep(and(femaleStudentQ1Learnt, orangeStudentQ1Learnt, hasSkull, specimenBrush), talkToGreenStudent); + + goTakeTest1.addStep(and(femaleStudentQ1Learnt, talkedToOrangeStudent, hasSkull, specimenBrush), talkToOrangeStudent2); + goTakeTest1.addStep(and(femaleStudentQ1Learnt, hasSpecialCup, hasSkull, specimenBrush), talkToOrangeStudent); + + goTakeTest1.addStep(and(talkedToFemaleStudent, hasSpecialCup, hasSkull, specimenBrush), talkToFemaleStudent2); + goTakeTest1.addStep(and(hasTeddy, hasSpecialCup, hasSkull, specimenBrush), talkToFemaleStudent); + + goTakeTest1.addStep(and(syncedUp, hasTeddy, hasSpecialCup), pickpocketWorkmen); + goTakeTest1.addStep(and(syncedUp, hasTeddy, panningTrayFull, talkedToGuide), searchPanningTray); + goTakeTest1.addStep(and(syncedUp, hasTeddy, panningTray, talkedToGuide), panWater); + goTakeTest1.addStep(and(syncedUp, hasTeddy, panningTray), talkToGuide); + goTakeTest1.addStep(and(syncedUp, hasTeddy), takeTray); + goTakeTest1.addStep(syncedUp, searchBush); + steps.put(2, goTakeTest1); + + var goTakeTest2 = new ConditionalStep(this, syncStep); + // Sets the state of knowStateAsJustCompletedFirstExam to true for ConditionalStep after this + goTakeTest1.addStep(nor(knowStateAsJustCompletedSecondExam), takeTest2); + + goTakeTest2.addStep(and(syncedUp2, femaleStudentQ2Learnt, orangeStudentQ2Learnt, greenStudentQ2Learnt), takeTest2); + goTakeTest2.addStep(and(syncedUp2, femaleStudentQ2Learnt, orangeStudentQ2Learnt), talkToGreenStudent3); + goTakeTest2.addStep(and(syncedUp2, femaleStudentQ2Learnt), talkToOrangeStudent3); + goTakeTest2.addStep(syncedUp2, talkToFemaleStudent3); + steps.put(3, goTakeTest2); + + var goTakeTest3 = new ConditionalStep(this, syncStep); + goTakeTest3.addStep(and(femaleStudentQ3Learnt, orangeStudentQ3Learnt, greenStudentQ3Learnt), takeTest3); + goTakeTest3.addStep(and(syncedUp3, femaleStudentQ3Learnt, orangeStudentQ3Learnt), talkToGreenStudent4); + goTakeTest3.addStep(and(syncedUp3, femaleStudentQ3Learnt), talkToOrangeStudent4); + goTakeTest3.addStep(and(syncedUp3, femaleExtorting), talkToFemaleStudent5); + goTakeTest3.addStep(syncedUp3, talkToFemaleStudent4); + steps.put(4, goTakeTest3); + + var findTalisman = new ConditionalStep(this, getJar); + findTalisman.addStep(and(givenTalismanIn), useInvitationOnWorkman); + findTalisman.addStep(and(talisman), talkToExpert); + findTalisman.addStep(and(specimenJar, specimenBrush), digForTalisman); + findTalisman.addStep(and(specimenJar), getBrush); + steps.put(5, findTalisman); + + var learnHowToMakeExplosives = new ConditionalStep(this, useRopeOnWinch2); + learnHowToMakeExplosives.addStep(inDougRoom, talkToDoug); + learnHowToMakeExplosives.addStep(and(inUndergroundTemple1, arcenia), goUpRope); + learnHowToMakeExplosives.addStep(inUndergroundTemple1, pickUpRoot); + learnHowToMakeExplosives.addStep(and(rope2Added), goDownToDoug); + + var makeExplosives = new ConditionalStep(this, goDownWinch); + makeExplosives.addStep(and(chemicalCompound, inUndergroundTemple1), useCompound); + + makeExplosives.addStep(inDougRoom, goUpFromDoug); + makeExplosives.addStep(and(inUndergroundTemple1, arcenia), goUpRope); + makeExplosives.addStep(inUndergroundTemple1, pickUpRoot); + + makeExplosives.addStep(chemicalCompound, goDownToExplode); + makeExplosives.addStep(and(arcenia, mixedChemicals2), addRoot); + makeExplosives.addStep(and(arcenia, mixedChemicals, groundCharcoal), addCharcoal); + makeExplosives.addStep(and(arcenia, mixedChemicals), grindCharcoal); + makeExplosives.addStep(and(arcenia, nitrate, nitro), mixNitroWithNitrate); + makeExplosives.addStep(and(arcenia, powder, nitro), usePowderOnExpert); + makeExplosives.addStep(and(arcenia, powder, liquid), useLiquidOnExpert); + makeExplosives.addStep(and(arcenia, powder, liquid), useVialOnBarrel); + makeExplosives.addStep(and(arcenia, powder, openedBarrel), useVialOnBarrel); + makeExplosives.addStep(and(arcenia, powder), useTrowelOnBarrel); + makeExplosives.addStep(and(openPowderChestNearby, arcenia), searchChest); + makeExplosives.addStep(arcenia, unlockChest); + + var discovery = new ConditionalStep(this, useRopeOnWinch); + discovery.addStep(hasKeyOrPowderOrMixtures, makeExplosives); + discovery.addStep(searchedBricks, learnHowToMakeExplosives); + discovery.addStep(and(inUndergroundTemple1, arcenia), searchBricks); + discovery.addStep(inUndergroundTemple1, pickUpRoot); + discovery.addStep(rope1Added, goDownWinch); + steps.put(6, discovery); + + var explodeWall = new ConditionalStep(this, goDownToExplode2); + explodeWall.addStep(inUndergroundTemple1, useTinderbox); + steps.put(7, explodeWall); + + var completeQuest = new ConditionalStep(this, goDownForTablet); + completeQuest.addStep(and(tablet.alsoCheckBank(), inUndergroundTemple2), goUpWithTablet); + completeQuest.addStep(and(tablet.alsoCheckBank()), useTabletOnExpert); + completeQuest.addStep(inUndergroundTemple2, takeTablet); + completeQuest.addStep(inUndergroundTemple1, waitForBricksToBlowUp); + steps.put(8, completeQuest); + + return steps; + } + + @Override + public List getGeneralRequirements() + { + return List.of( + new SkillRequirement(Skill.AGILITY, 10, true), + new SkillRequirement(Skill.HERBLORE, 10, true), + new SkillRequirement(Skill.THIEVING, 25) + ); } @Override public List getItemRequirements() { - return Arrays.asList(pestleAndMortar, vialHighlighted, tinderbox, tea, ropes2, opal, charcoal); + return List.of( + pestleAndMortar, + vial, + tinderbox, + tea, + ropes2, + opal, + charcoal + ); } @Override public List getItemRecommended() { - return Arrays.asList(digsiteTeleports, varrock2); + return List.of( + digsiteTeleports, + varrock2 + ); } @Override - public List getGeneralRequirements() + public List getNotes() { - ArrayList req = new ArrayList<>(); - req.add(new SkillRequirement(Skill.AGILITY, 10, true)); - req.add(new SkillRequirement(Skill.HERBLORE, 10, true)); - req.add(new SkillRequirement(Skill.THIEVING, 25)); - return req; + return List.of( + "This quest helper is susceptible to getting out of sync with the actual quest. If this happens to you, opening up the quest's journal should fix it." + ); } @Override @@ -530,38 +690,114 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Arrays.asList( - new ExperienceReward(Skill.MINING, 15300), - new ExperienceReward(Skill.HERBLORE, 2000)); + return List.of( + new ExperienceReward(Skill.MINING, 15300), + new ExperienceReward(Skill.HERBLORE, 2000) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("Gold Bars", ItemID.GOLD_BAR, 2)); + return List.of( + new ItemReward("Gold Bars", ItemID.GOLD_BAR, 2) + ); } @Override public List getUnlockRewards() { - return Collections.singletonList(new UnlockReward("Ability to clean specimens in the Varrock Museum")); + return List.of( + new UnlockReward("Ability to clean specimens in the Varrock Museum") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Arrays.asList(talkToExaminer, talkToHaig, talkToExaminer2, searchBush, takeTray, talkToGuide, panWater, pickpocketWorkmen, talkToFemaleStudent, talkToFemaleStudent2, - talkToOrangeStudent, talkToOrangeStudent2, talkToGreenStudent, talkToGreenStudent2, takeTest1), tea)); - - allSteps.add(new PanelDetails("Exam 2", Arrays.asList(talkToFemaleStudent3, talkToOrangeStudent3, talkToGreenStudent3, takeTest2))); - allSteps.add(new PanelDetails("Exam 3", Arrays.asList(talkToFemaleStudent4, talkToFemaleStudent5, talkToOrangeStudent4, - talkToGreenStudent4, takeTest3), opal)); - allSteps.add(new PanelDetails("Discovery", Arrays.asList(getJar, digForTalisman, talkToExpert, useInvitationOnWorkman), trowel, specimenBrush)); - allSteps.add(new PanelDetails("Digging deeper", Arrays.asList(useRopeOnWinch, goDownWinch, pickUpRoot, searchBricks, goUpRope, useRopeOnWinch2, goDownToDoug, - talkToDoug, goUpFromDoug, unlockChest, searchChest, useTrowelOnBarrel, useVialOnBarrel, useLiquidOnExpert, usePowderOnExpert, mixNitroWithNitrate, grindCharcoal, addCharcoal, addRoot, goDownToExplode, - useCompound, useTinderbox, takeTablet, useTabletOnExpert), ropes2, trowelHighlighted, pestleAndMortar, vialHighlighted, tinderboxHighlighted, charcoal)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToExaminer, + talkToHaig, + talkToExaminer2, + searchBush, + takeTray, + talkToGuide, + panWater, + pickpocketWorkmen, + talkToFemaleStudent, + talkToFemaleStudent2, + talkToOrangeStudent, + talkToOrangeStudent2, + talkToGreenStudent, + talkToGreenStudent2, + takeTest1 + ), List.of( + tea + ))); + + sections.add(new PanelDetails("Exam 2", List.of( + talkToFemaleStudent3, + talkToOrangeStudent3, + talkToGreenStudent3, + takeTest2 + ))); + + sections.add(new PanelDetails("Exam 3", List.of( + talkToFemaleStudent4, + talkToFemaleStudent5, + talkToOrangeStudent4, + talkToGreenStudent4, + takeTest3 + ), List.of( + opal + ))); + + sections.add(new PanelDetails("Discovery", List.of( + getJar, + digForTalisman, + talkToExpert, + useInvitationOnWorkman + ), List.of( + trowel, + specimenBrush + ))); + + sections.add(new PanelDetails("Digging deeper", List.of( + useRopeOnWinch, + goDownWinch, + pickUpRoot, + searchBricks, + goUpRope, + useRopeOnWinch2, + goDownToDoug, + talkToDoug, + goUpFromDoug, + unlockChest, + searchChest, + useTrowelOnBarrel, + useVialOnBarrel, + useLiquidOnExpert, + usePowderOnExpert, + mixNitroWithNitrate, + grindCharcoal, + addCharcoal, + addRoot, + goDownToExplode, + useCompound, + useTinderbox, + takeTablet, + useTabletOnExpert + ), List.of( + ropes2, + trowelHighlighted, + pestleAndMortar, + vial, + tinderbox, + charcoal + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefinaldawn/TheFinalDawn.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefinaldawn/TheFinalDawn.java index 4c3b5719ac..df73c851db 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefinaldawn/TheFinalDawn.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefinaldawn/TheFinalDawn.java @@ -50,6 +50,9 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; import net.runelite.client.plugins.microbot.questhelper.steps.*; + +import java.util.*; + import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetHighlight; import net.runelite.api.QuestState; @@ -61,8 +64,6 @@ import net.runelite.api.gameval.*; import net.runelite.client.eventbus.Subscribe; -import java.util.*; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; /** @@ -509,7 +510,6 @@ private int getSumOfLitBraziers() new WorldPoint(1286, 9438, 1), new WorldPoint(1289, 9435, 1), new WorldPoint(1296, 9435, 1) - ); int total = 0; @@ -612,9 +612,12 @@ protected void setupRequirements() combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); + // Technically only applies for the cultist fight to have these foods available, but as they're recommended last + // It shouldn't impact any existing suggestions for players + food.addAlternates(ItemID.COOKED_LIZARD, ItemID.BREAM_FISH_COOKED); food.setUrlSuffix("Food"); - prayerPotions = new ItemRequirement("Prayer potions", ItemCollections.PRAYER_POTIONS, 3); + prayerPotions.addAlternates(ItemID._4DOSEMOONLIGHTPOTION, ItemID._3DOSEMOONLIGHTPOTION, ItemID._2DOSEMOONLIGHTPOTION, ItemID._1DOSEMOONLIGHTPOTION); whistle = new ItemRequirement("Quetzal whistle", ItemID.HG_QUETZALWHISTLE_BASIC); whistle.addAlternates(ItemID.HG_QUETZALWHISTLE_ENHANCED, ItemID.HG_QUETZALWHISTLE_PERFECTED); @@ -825,7 +828,7 @@ public void setupSteps() enterPassage.addDialogSteps("Enter the passage."); pickBlueChest = new ObjectStep(this, ObjectID.TWILIGHT_TEMPLE_METZLI_CHAMBER_CHEST_CLOSED, new WorldPoint(1723, 9709, 0), "Picklock the chest in the " + "hidden room. Be ready for a fight afterwards."); - fightEnforcer = new NpcStep(this, NpcID.VMQ4_TEMPLE_GUARD_BOSS_FIGHT, new WorldPoint(1712, 9706, 0), "Defeat the enforcer. You cannot use prayers" + + fightEnforcer = new NpcStep(this, NpcID.VMQ4_TEMPLE_GUARD_BOSS_FIGHT, new WorldPoint(1712, 9706, 0), "Defeat the enforcer. You cannot use prayers, or teleport out" + ". Step away each time he goes to attack, and step behind him or sideways if he says 'Traitor!' or 'Thief!'."); pickUpEmissaryScroll = new ItemStep(this, "Pick up the emissary scroll.", emissaryScroll); readEmissaryScroll = new DetailedQuestStep(this, "Read the emissary scroll.", emissaryScroll.highlighted()); @@ -884,7 +887,7 @@ public void setupSteps() showSackToVibia = showSackToVibiaNotPuzzleWrapped.puzzleWrapStep(true); showSackToVibiaNotPuzzleWrapped.addSubSteps(goF2ToF1HideoutEnd, goToF0HideoutEnd); - takePotato.addSubSteps(removePotatoesFromSack, takeKnife, takeCoinPurse, goToF1Hideout, goDownFromF2Hideout, goF1ToF2Hideout, useKnifeOnPottedFan, + takePotato.addSubSteps(takeKnife, takeCoinPurse, goToF1Hideout, goDownFromF2Hideout, goF1ToF2Hideout, useKnifeOnPottedFan, fillCoinPurse, emptyCoinPurse, useBranchOnCoinPurse, goToF0Hideout, goToF0HideoutEnd, goF2ToF1HideoutEnd, showSackToVibia); searchBodyForKey = new NpcStep(this, NpcID.VMQ4_JANUS_HOUSE_JANUS_UNCONSCIOUS, new WorldPoint(1647, 3093, 0), "Search Janus."); @@ -1242,7 +1245,7 @@ public List getPanels() civitasTeleport ))); panels.add(new PanelDetails("The hideout", List.of(talkToQueen, talkToCaptainVibia, inspectWindow, giveBonesOrMeatToDog, enterDoorCode, takePotato, - takeKnife, goToF1Hideout, takeCoinPurse, goF1ToF2Hideout, useKnifeOnPottedFan, fillCoinPurse, useBranchOnCoinPurse, showSackToVibia, + removePotatoesFromSack, takeKnife, goToF1Hideout, takeCoinPurse, goF1ToF2Hideout, useKnifeOnPottedFan, fillCoinPurse, useBranchOnCoinPurse, showSackToVibia, searchBodyForKey, enterTrapdoor, talkToQueenToGoCamTorum), List.of(bone), List.of())); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theforsakentower/JugPuzzle.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theforsakentower/JugPuzzle.java index 88a68fe21a..d2142ed6bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theforsakentower/JugPuzzle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theforsakentower/JugPuzzle.java @@ -48,7 +48,6 @@ import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.microbot.util.text.Rs2TextSanitizer; import java.util.*; import java.util.regex.Matcher; @@ -98,7 +97,7 @@ protected void updateSteps() if (widget != null) { - String text = Rs2TextSanitizer.sanitizeWidgetMultilineText(widget.getText()); + String text = widget.getText().replace("
", " "); Matcher jugOnJugMatcher = JUG_VALUES_MATCHER.matcher(text); Matcher jugEmptiedMatcher = JUG_EMPTIED.matcher(text); Matcher jugFilledMatcher = JUG_FILLED.matcher(text); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremennikisles/TheFremennikIsles.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremennikisles/TheFremennikIsles.java index 9eeb50b5f3..28db2ffcf3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremennikisles/TheFremennikIsles.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremennikisles/TheFremennikIsles.java @@ -632,7 +632,7 @@ public List getPanels() allSteps.add(new PanelDetails("Collecting beard tax", Arrays.asList(collectFromHringAgain, collectFromRaum, collectFromSkuliAgain, collectFromKeepaAgain, collectFromFlosi, talkToGjukiAfterCollection2))); allSteps.add(new PanelDetails("Spy on Mawnis again", Arrays.asList(talkToSlugToSpyAgain, goSpyOnMawnisAgain, reportBackToSlugAgain, talkToGjukiAfterSpy2, talkToMawnisWithDecree))); allSteps.add(prepareForCombatPanel); - allSteps.add(new PanelDetails("Killing the king", Arrays.asList(enterCave, killTrolls, enterKingRoom, killKing, decapitateKing, finishQuest), yakBottom, yakTop, roundShield, meleeWeapon, food)); + allSteps.add(new PanelDetails("Killing the king", Arrays.asList(enterCave, killTrolls, enterKingRoom, killKing, decapitateKing, finishQuest), roundShield, meleeWeapon, food)); return allSteps; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremenniktrials/TheFremennikTrials.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremenniktrials/TheFremennikTrials.java index 1dca85d6b7..6ff93e4e06 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremenniktrials/TheFremennikTrials.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thefremenniktrials/TheFremennikTrials.java @@ -49,7 +49,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; import java.util.*; @@ -298,7 +302,7 @@ protected void setupRequirements() petRock = new ItemRequirement("Pet rock", ItemID.VT_USELESS_ROCK).isNotConsumed(); petRock.setTooltip("You can get another from Askeladden"); - emptySlot4 = new ItemRequirement("4 empty inventory slots", -1, 4); + emptySlot4 = new ItemRequirement("Empty inventory slots for vegetables and a pet rock", -1, 4); goldenWool = new ItemRequirement("Golden wool", ItemID.VIKING_GOLDEN_WOOL); goldenFleece = new ItemRequirement("Golden fleece", ItemID.VIKING_GOLDEN_FLEECE); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thegolem/TheGolem.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thegolem/TheGolem.java index e3d178d04c..9c5d0faa82 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thegolem/TheGolem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thegolem/TheGolem.java @@ -32,6 +32,8 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.TeleportItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitBuilder; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; @@ -40,7 +42,15 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -48,14 +58,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; - public class TheGolem extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theheartofdarkness/TheHeartOfDarkness.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theheartofdarkness/TheHeartOfDarkness.java index 74be88eb58..af474f4d6d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theheartofdarkness/TheHeartOfDarkness.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theheartofdarkness/TheHeartOfDarkness.java @@ -27,6 +27,7 @@ import com.google.common.collect.Lists; import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; +import net.runelite.client.plugins.microbot.questhelper.domain.QuetzalDestination; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.secretsofthenorth.ArrowChestPuzzleStep; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; @@ -37,6 +38,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NoFollowerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.InInstanceRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; @@ -93,6 +95,8 @@ public class TheHeartOfDarkness extends BasicQuestHelper ItemRequirement towerKey, book, poem, scrapOfPaper1, scrapOfPaper2, scrapOfPaper3, completedNote, emissaryHood, emissaryTop, emissaryBottom, emissaryBoots, emissaryRobesEquipped, emissaryRobes, airIcon, waterIcon, earthIcon, fireIcon; + NoFollowerRequirement noFollower; + Requirement atTeomat, builtLandingInOverlook, talkedToSergius, talkedToCaritta, talkedToFelius, princeIsFollowing, inFirstTrialRoom, inSecondTrialRoom, southEastGateUnlocked, southWestChestOpened, hasReadPoem, knowAboutDirections, inArrowPuzzle, combatStarted, startedInvestigation, freeInvSlots4; @@ -406,6 +410,7 @@ protected void setupRequirements() fireIcon = new ItemRequirement("Fire icon", ItemID.VMQ3_RUINS_FIRE_STATUE_REPAIR); + noFollower = new NoFollowerRequirement("No pet following you"); } private void setupConditions() @@ -542,15 +547,11 @@ private void setupSteps() { talkToItzlaAtTeomat = new NpcStep(this, NpcID.VMQ2_ITZLA_VIS, new WorldPoint(1454, 3173, 0), "Talk to Prince Itzla Arkan at the Teomat. You" + " can travel here using Renu the quetzal."); - WidgetHighlight teomatWidget = new WidgetHighlight(874, 15, true); - teomatWidget.setModelIdRequirement(51205); - talkToItzlaAtTeomat.addWidgetHighlight(teomatWidget); + talkToItzlaAtTeomat.addWidgetHighlight(WidgetHighlight.createQuetzalHighlight(QuetzalDestination.THE_TEOMAT)); talkToItzlaAtTeomat.addDialogStep("Yes."); travelToGorge = new NpcStep(this, NpcID.QUETZAL_CHILD_GREEN_NOOP, new WorldPoint(1437, 3169, 0), "Travel on Renu to the Quetzacalli Gorge."); ((NpcStep) travelToGorge).addAlternateNpcs(NpcID.QUETZAL_CHILD_GREEN_FEED, NpcID.QUETZAL_CHILD_GREEN, NpcID.QUETZAL_CHILD_ORANGE, NpcID.QUETZAL_CHILD_BLUE, NpcID.QUETZAL_CHILD_CYAN, NpcID.QUETZAL_CHILD_GREEN_ORANGE); - WidgetHighlight gorgeWidget = new WidgetHighlight(874, 15, true); - gorgeWidget.setModelIdRequirement(54539); - travelToGorge.addWidgetHighlight(gorgeWidget); + travelToGorge.addWidgetHighlight(WidgetHighlight.createQuetzalHighlight(QuetzalDestination.QUETZACALLI_GORGE)); talkToBartender = new NpcStep(this, NpcID.QUETZACALLI_BARTENDER, new WorldPoint(1499, 3224, 0), "Talk to the Bartender in the pub in the Gorge.", coins.quantity(30)); // Told about ground room, 11123 1->0 @@ -635,7 +636,7 @@ private void setupSteps() talkToFelius = new NpcStep(this, NpcID.VMQ3_RECRUIT_1_VIS, new WorldPoint(1659, 3224, 0), "Talk to Felius outside the tower."); talkToCaritta = new NpcStep(this, NpcID.VMQ3_RECRUIT_2_VIS, new WorldPoint(1659, 3224, 0), "Talk to Caritta outside the tower."); talkToPrinceAfterRecruits = new NpcStep(this, NpcID.VMQ3_ITZLA_VIS_CITIZEN, new WorldPoint(1656, 3219, 0), "Talk to the prince at the Tower " + - "of Ascension to the south-east of the salvager overlook again."); + "of Ascension to the south-east of the salvager overlook again.", noFollower); talkToPrinceAfterRecruits.addDialogStep("Could you remind me what Ximoua is?"); talkToJanus = new NpcStep(this, NpcID.VMQ3_FOREBEARER_JANUS_VIS, new WorldPoint(1638, 3224, 0), "Talk to Forebearer Janus inside the tower."); @@ -966,6 +967,7 @@ private void setupSteps() talkToServius = new NpcStep(this, NpcID.VMQ3_SERVIUS_VIS, new WorldPoint(1681, 3168, 0), "Talk to Servius, Teokan of Ralos in the palace" + " in Civitas illa Fortis to complete the quest."); + talkToServius.addWidgetHighlight(WidgetHighlight.createQuetzalHighlight(QuetzalDestination.CIVITAS_ILLA_FORTIS)); talkToServius.addTeleport(civitasIllaFortisTeleport); } @@ -1154,7 +1156,7 @@ public List getPanels() allSteps.add(new PanelDetails("Final Trial", List.of(fightPrinceSidebar, talkToJanusAfterPrinceFight))); allSteps.add(new PanelDetails("Cult", List.of(talkToJanusAfterAllTrials, searchChestForEmissaryRobes, talkToItzlaToFollow, enterTemple, talkToItzlaAfterSermon, talkToFides))); allSteps.add(new PanelDetails("The Old Ones", List.of(enterRuins, takePickaxe, mineRocks, pullFirstLever, climbDownLedge, slideAlongIceLedge, pullSecondLever, jumpOverFrozenPlatforms, pullThirdLever, - pullFourthLever, pullChain, inspectAirMarkings, inspectEarthMarkings, searchAirUrn, searchEarthUrn, inspectWaterMarkings, inspectFireMarkings, + pullFourthLever, pullChain, climbDownIceShortcut, inspectAirMarkings, inspectEarthMarkings, searchAirUrn, searchEarthUrn, inspectWaterMarkings, inspectFireMarkings, searchFireUrn, searchWaterUrn, fixWaterStatue, fixFireStatue, fixEarthStatue, fixAirStatue, activateFirstStatue, activateSecondStatue, activateThirdStatue, activateFourthStatue, enterFinalBossRoom, defeatAmoxliatlSidebar, talkToServius), List.of(combatGear, freeInvSlots4), List.of(food, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theidesofmilk/TheIdesOfMilk.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theidesofmilk/TheIdesOfMilk.java new file mode 100644 index 0000000000..8df4efc5d0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theidesofmilk/TheIdesOfMilk.java @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2026, adamsbytes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.helpers.quests.theidesofmilk; + +import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; +import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; +import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.CombatLevelRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; +import net.runelite.client.plugins.microbot.questhelper.util.QHObjectID; +import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; + +public class TheIdesOfMilk extends BasicQuestHelper +{ + // Recommended items + ItemRequirement combatGear; + ItemRequirement food; + + // Mid-quest item requirements + ItemRequirement husbandryBook; + ItemRequirement milkSample1; + ItemRequirement milkSample2; + + // Zones + Zone lumbridgeCastleF1; + + // Miscellaneous requirements + VarbitRequirement gillieInformed; + ZoneRequirement inLumbridgeCastleF1; + NpcCondition brutusNearby; + + // Steps + NpcStep talkToCassius; + NpcStep talkToGillie; + NpcStep talkToSeth; + ObjectStep searchShelves; + NpcStep returnToCassiusWithBook; + NpcStep talkToCassiusAboutBook; + DetailedQuestStep drinkMilkSample1; + NpcStep talkToCassiusAfterDrink; + ObjectStep goUpToLumbridgeCastleF1; + NpcStep talkToDuke; + NpcStep talkToGillieAgain; + DetailedQuestStep drinkMilkSample2; + NpcStep talkToGillieAfterDrink; + ObjectStep openBullPen; + NpcStep killBrutus; + NpcStep talkToGillieAfterFight; + NpcStep finishQuest; + + @Override + protected void setupZones() + { + lumbridgeCastleF1 = new Zone(new WorldPoint(3203, 3206, 1), new WorldPoint(3218, 3231, 1)); + } + + @Override + protected void setupRequirements() + { + husbandryBook = new ItemRequirement("The groats principles", ItemID.COWQUEST_HUSBANDRY_BOOK); + husbandryBook.canBeObtainedDuringQuest(); + + milkSample1 = new ItemRequirement("Milk sample", ItemID.COWQUEST_MILK_SAMPLE_1); + milkSample1.canBeObtainedDuringQuest(); + milkSample1.setTooltip("You can get another from Cassius"); + + milkSample2 = new ItemRequirement("Milk sample", ItemID.COWQUEST_MILK_SAMPLE_2); + milkSample2.canBeObtainedDuringQuest(); + milkSample2.setTooltip("You can get another from Cassius"); + + gillieInformed = new VarbitRequirement(VarbitID.COWQUEST_GILLIE_INFORMATION, 1); + inLumbridgeCastleF1 = new ZoneRequirement(lumbridgeCastleF1); + + combatGear = new ItemRequirement("Combat gear", -1, -1).isNotConsumed(); + combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); + + food = new ItemRequirement("Food", -1, -1); + food.setDisplayItemId(BankSlotIcons.getFood()); + } + + public void setupSteps() + { + talkToCassius = new NpcStep(this, NpcID.COWBOSS_FARMER, + new WorldPoint(3171, 3277, 0), + "Speak to Cassius by the pond north-west of Lumbridge to start the quest.", true); + talkToCassius.addDialogStep("Yes."); + + talkToGillie = new NpcStep(this, NpcID.GILLIE_THE_MILKMAID, + new WorldPoint(3253, 3270, 0), + "Speak to Gillie Groats at the cow field east of Lumbridge."); + talkToGillie.addDialogStep("Can you share what makes your cows so productive?"); + + talkToSeth = new NpcStep(this, NpcID.FAVOUR_SETH_GROATS, + new WorldPoint(3228, 3291, 0), + "Speak to Seth Groats at his farmhouse east of the River Lum."); + + searchShelves = new ObjectStep(this, ObjectID.COWQUEST_SETH_SHELF, + new WorldPoint(3227, 3287, 0), + "Search the shelves in Seth's farmhouse for 'The groats principles'."); + + returnToCassiusWithBook = new NpcStep(this, NpcID.COWBOSS_FARMER, + new WorldPoint(3171, 3277, 0), + "Return to Cassius with the book.", true, husbandryBook); + + talkToCassiusAboutBook = new NpcStep(this, NpcID.COWBOSS_FARMER, + new WorldPoint(3171, 3277, 0), + "Talk to Cassius.", true); + returnToCassiusWithBook.addSubSteps(talkToCassiusAboutBook); + + drinkMilkSample1 = new DetailedQuestStep(this, + "Drink the milk sample near Cassius.", milkSample1.highlighted()); + + talkToCassiusAfterDrink = new NpcStep(this, NpcID.COWBOSS_FARMER, + new WorldPoint(3171, 3277, 0), + "Talk to Cassius after drinking the milk sample.", true); + + goUpToLumbridgeCastleF1 = new ObjectStep(this, QHObjectID.LUMBRIDGE_CASTLE_F0_SOUTH_STAIRCASE, + new WorldPoint(3205, 3208, 0), + "Speak to Duke Horacio on the first floor of Lumbridge Castle.", milkSample2); + + talkToDuke = new NpcStep(this, NpcID.DUKE_OF_LUMBRIDGE, + new WorldPoint(3210, 3220, 1), + "Speak to Duke Horacio on the first floor of Lumbridge Castle.", milkSample2); + talkToDuke.addSubSteps(goUpToLumbridgeCastleF1); + + talkToGillieAgain = new NpcStep(this, NpcID.GILLIE_THE_MILKMAID, + new WorldPoint(3253, 3270, 0), + "Speak to Gillie Groats at the cow field."); + + drinkMilkSample2 = new DetailedQuestStep(this, + "Drink the milk sample near Gillie.", milkSample2.highlighted()); + + talkToGillieAfterDrink = new NpcStep(this, NpcID.GILLIE_THE_MILKMAID, + new WorldPoint(3253, 3270, 0), + "Talk to Gillie Groats after drinking the milk sample."); + + brutusNearby = new NpcCondition(NpcID.COWBOSS); + + openBullPen = new ObjectStep(this, ObjectID.FENCEGATE_L_COWBOSS_START, + new WorldPoint(3262, 3294, 0), + "Open the bull pen gate in the north-east corner of the cow field to fight the Bull (level 30).", + combatGear, food); + openBullPen.addDialogStep("Yes."); + + killBrutus = new NpcStep(this, NpcID.COWBOSS, + new WorldPoint(3262, 3294, 0), + "Kill the Bull (level 30). Protect from Melee blocks his basic attacks (max hit 3). Dodge his ground slam ('snorts') and charge ('growls') by walking through him. Special attacks can hit over 15.", + combatGear, food); + openBullPen.addSubSteps(killBrutus); + + talkToGillieAfterFight = new NpcStep(this, NpcID.GILLIE_THE_MILKMAID, + new WorldPoint(3253, 3270, 0), + "Speak to Gillie Groats after defeating the Bull."); + + finishQuest = new NpcStep(this, NpcID.COWBOSS_FARMER, + new WorldPoint(3171, 3277, 0), + "Return to Cassius to complete the quest. You can then speak to Gillie Groats for a cow bell amulet and magic lamp (1,000 XP combat/Prayer).", true); + } + + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToCassius); + steps.put(1, talkToCassius); + steps.put(2, talkToCassius); + + var cInvestigate = new ConditionalStep(this, talkToGillie); + cInvestigate.addStep(gillieInformed, talkToSeth); + steps.put(3, cInvestigate); + + var cGetBook = new ConditionalStep(this, searchShelves); + cGetBook.addStep(husbandryBook, returnToCassiusWithBook); + steps.put(4, cGetBook); + var cReturnBook = new ConditionalStep(this, talkToCassiusAboutBook); + cReturnBook.addStep(husbandryBook, returnToCassiusWithBook); + steps.put(5, cReturnBook); + + steps.put(6, drinkMilkSample1); + steps.put(8, talkToCassiusAfterDrink); + var cTalkToDuke = new ConditionalStep(this, goUpToLumbridgeCastleF1); + cTalkToDuke.addStep(inLumbridgeCastleF1, talkToDuke); + steps.put(10, cTalkToDuke); + steps.put(12, talkToGillieAgain); + steps.put(14, drinkMilkSample2); + steps.put(16, talkToGillieAfterDrink); + var cFightBrutus = new ConditionalStep(this, openBullPen); + cFightBrutus.addStep(brutusNearby, killBrutus); + steps.put(18, cFightBrutus); + steps.put(20, talkToGillieAfterFight); + steps.put(21, finishQuest); + + return steps; + } + + @Override + public List getGeneralRecommended() + { + return List.of( + new CombatLevelRequirement(15) + ); + } + + @Override + public List getItemRecommended() + { + return List.of(combatGear, food); + } + + @Override + public List getCombatRequirements() + { + return List.of("Bull (level 30)"); + } + + @Override + public QuestPointReward getQuestPointReward() + { + return new QuestPointReward(1); + } + + @Override + public List getUnlockRewards() + { + return List.of( + new UnlockReward("Access to the cow boss"), + new UnlockReward("Cow bell amulet and magic lamp (1,000 XP combat/Prayer) from Gillie Groats") + ); + } + + @Override + public List getPanels() + { + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToCassius + ))); + + sections.add(new PanelDetails("Investigation", List.of( + talkToGillie, + talkToSeth, + searchShelves + ))); + + sections.add(new PanelDetails("Milk tasting", List.of( + returnToCassiusWithBook, + drinkMilkSample1, + talkToCassiusAfterDrink + ))); + + sections.add(new PanelDetails("The Duke's opinion", List.of( + talkToDuke, + talkToGillieAgain, + drinkMilkSample2, + talkToGillieAfterDrink + ))); + + sections.add(new PanelDetails("The bull fight", List.of( + openBullPen, + talkToGillieAfterFight + ), combatGear, food)); + + sections.add(new PanelDetails("Finishing up", List.of( + finishQuest + ))); + + return sections; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theknightssword/TheKnightsSword.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theknightssword/TheKnightsSword.java index 905025d564..74cf09c84d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theknightssword/TheKnightsSword.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theknightssword/TheKnightsSword.java @@ -27,13 +27,10 @@ import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.requirements.ComplexRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; @@ -43,97 +40,99 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - +// TODO: fix typo in Sir Vyvin's name public class TheKnightsSword extends BasicQuestHelper { - //Items Required - ItemRequirement pickaxe, redberryPie, ironBars, bluriteOre, bluriteSword, portrait; + // Required items + ItemRequirement redberryPie; + ItemRequirement ironBars; + ItemRequirement bluriteOre; + ItemRequirement pickaxe; - //Items Recommended - ItemRequirement varrockTeleport, faladorTeleports, homeTele; - ComplexRequirement searchCupboardReq; + // Recommended items + ItemRequirement varrockTeleport; + ItemRequirement faladorTeleports; + ItemRequirement homeTele; - Requirement inDungeon, inFaladorCastle1, inFaladorCastle2, inFaladorCastle2Bedroom, sirVyinNotInRoom; + // Mid-quest item requirements + ItemRequirement bluriteSword; + ItemRequirement portrait; - QuestStep talkToSquire, talkToReldo, talkToThurgo, talkToThurgoAgain, talkToSquire2, goUpCastle1, goUpCastle2, searchCupboard, enterDungeon, - mineBlurite, givePortraitToThurgo, bringThurgoOre, finishQuest; + // Zones + Zone dungeon; + Zone faladorCastle1; + Zone faladorCastle2; + Zone faladorCastle2Bedroom; - //Zones - Zone dungeon, faladorCastle1, faladorCastle2, faladorCastle2Bedroom; + // Miscellaneous requirements + NpcRequirement sirVyvinNotInRoom; + ZoneRequirement inDungeon; + ZoneRequirement inFaladorCastle1; + ZoneRequirement inFaladorCastle2; + ZoneRequirement inFaladorCastle2Bedroom; - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); + // Steps + NpcStep talkToSquire; - steps.put(0, talkToSquire); - steps.put(1, talkToReldo); - steps.put(2, talkToThurgo); - steps.put(3, talkToThurgoAgain); - steps.put(4, talkToSquire2); + NpcStep talkToReldo; - ConditionalStep getPortrait = new ConditionalStep(this, goUpCastle1); - getPortrait.addStep(portrait.alsoCheckBank(), givePortraitToThurgo); - getPortrait.addStep(inFaladorCastle2, searchCupboard); - getPortrait.addStep(inFaladorCastle1, goUpCastle2); + NpcStep talkToThurgo; - steps.put(5, getPortrait); + NpcStep talkToThurgoAgain; - ConditionalStep returnSwordToSquire = new ConditionalStep(this, enterDungeon); - returnSwordToSquire.addStep(bluriteSword.alsoCheckBank(), finishQuest); - returnSwordToSquire.addStep(bluriteOre.alsoCheckBank(), bringThurgoOre); - returnSwordToSquire.addStep(inDungeon, mineBlurite); + NpcStep talkToSquire2; - steps.put(6, returnSwordToSquire); + ObjectStep goUpCastle1; + ObjectStep goUpCastle2; + ObjectStep searchCupboard; + NpcStep givePortraitToThurgo; - return steps; + ObjectStep enterDungeon; + ObjectStep mineBlurite; + NpcStep bringThurgoOre; + NpcStep finishQuest; + + @Override + protected void setupZones() + { + dungeon = new Zone(new WorldPoint(2979, 9538, 0), new WorldPoint(3069, 9602, 0)); + faladorCastle1 = new Zone(new WorldPoint(2954, 3328, 1), new WorldPoint(2997, 3353, 1)); + faladorCastle2 = new Zone(new WorldPoint(2980, 3331, 2), new WorldPoint(2986, 3346, 2)); + faladorCastle2Bedroom = new Zone(new WorldPoint(2981, 3336, 2), new WorldPoint(2986, 3331, 2)); } @Override protected void setupRequirements() { redberryPie = new ItemRequirement("Redberry pie", ItemID.REDBERRY_PIE); + redberryPie.setTooltip("Purchasable from the grand exchange, or for ironmen: 10 cooking to cook one, or 32 cooking and a chef's hat to buy one from the Cooks' Guild."); ironBars = new ItemRequirement("Iron bar", ItemID.IRON_BAR, 2); bluriteOre = new ItemRequirement("Blurite ore", ItemID.BLURITE_ORE); - bluriteSword = new ItemRequirement("Blurite sword", ItemID.FALADIAN_SWORD); pickaxe = new ItemRequirement("Any pickaxe", ItemCollections.PICKAXES).isNotConsumed(); + varrockTeleport = new ItemRequirement("A teleport to Varrock", ItemID.POH_TABLET_VARROCKTELEPORT); - faladorTeleports = new ItemRequirement("Teleports to Falador", ItemID.POH_TABLET_FALADORTELEPORT, 4); - homeTele = new ItemRequirement("A teleport near Mudskipper Point, such as POH teleport or Fairy Ring to AIQ", - ItemID.NZONE_TELETAB_RIMMINGTON, 2); + faladorTeleports = new ItemRequirement("Teleports to Falador", ItemID.POH_TABLET_FALADORTELEPORT, 3); + homeTele = new ItemRequirement("A teleport near Mudskipper Point, such as POH teleport or Fairy Ring to AIQ", ItemID.NZONE_TELETAB_RIMMINGTON, 2); + + bluriteSword = new ItemRequirement("Blurite sword", ItemID.FALADIAN_SWORD); portrait = new ItemRequirement("Portrait", ItemID.KNIGHTS_PORTRAIT); - } - public void setupConditions() - { inDungeon = new ZoneRequirement(dungeon); inFaladorCastle1 = new ZoneRequirement(faladorCastle1); inFaladorCastle2 = new ZoneRequirement(faladorCastle2); inFaladorCastle2Bedroom = new ZoneRequirement(faladorCastle2Bedroom); - sirVyinNotInRoom = new NpcCondition(NpcID.SIR_VYVIN, faladorCastle2Bedroom); - NpcRequirement sirVyinNotInRoom = new NpcRequirement("Sir Vyin not in the bedroom.", NpcID.SIR_VYVIN, true, faladorCastle2Bedroom); - ZoneRequirement playerIsUpstairs = new ZoneRequirement("Upstairs", faladorCastle2); - searchCupboardReq = new ComplexRequirement(LogicType.AND, "Sir Vyin not in the bedroom.", playerIsUpstairs, sirVyinNotInRoom); - } - - @Override - protected void setupZones() - { - dungeon = new Zone(new WorldPoint(2979, 9538, 0), new WorldPoint(3069, 9602, 0)); - faladorCastle1 = new Zone(new WorldPoint(2954, 3328, 1), new WorldPoint(2997, 3353, 1)); - faladorCastle2 = new Zone(new WorldPoint(2980, 3331, 2), new WorldPoint(2986, 3346, 2)); - faladorCastle2Bedroom = new Zone(new WorldPoint(2981, 3336, 2), new WorldPoint(2986, 3331, 2)); + sirVyvinNotInRoom = new NpcRequirement("Sir Vyvin not in the bedroom.", NpcID.SIR_VYVIN, true, faladorCastle2Bedroom); } public void setupSteps() @@ -142,60 +141,118 @@ public void setupSteps() talkToSquire.addDialogStep("And how is life as a squire?"); talkToSquire.addDialogStep("I can make a new sword if you like..."); talkToSquire.addDialogStep("So would these dwarves make another one?"); - talkToSquire.addDialogStep("Ok, I'll give it a go."); talkToSquire.addDialogStep("Yes."); + talkToSquire.addTeleport(faladorTeleports.quantity(1)); + talkToReldo = new NpcStep(this, NpcID.RELDO_NORMAL, new WorldPoint(3211, 3494, 0), "Talk to Reldo in Varrock Castle's library."); talkToReldo.addDialogStep("What do you know about the Imcando dwarves?"); + talkToReldo.addTeleport(varrockTeleport.quantity(1)); + talkToThurgo = new NpcStep(this, NpcID.THURGO, new WorldPoint(3000, 3145, 0), "Talk to Thurgo south of Port Sarim and give him a redberry pie.", redberryPie); talkToThurgo.addDialogStep("Would you like a redberry pie?"); + talkToThurgo.addTeleport(homeTele.quantity(1)); + talkToThurgoAgain = new NpcStep(this, NpcID.THURGO, new WorldPoint(3000, 3145, 0), "Talk to Thurgo again."); talkToThurgoAgain.addDialogStep("Can you make a special sword for me?"); + talkToSquire2 = new NpcStep(this, NpcID.SQUIRE, new WorldPoint(2978, 3341, 0), "Talk to the Squire in Falador Castle's courtyard."); + talkToSquire2.addTeleport(faladorTeleports.quantity(1)); + goUpCastle1 = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_LADDER_UP, new WorldPoint(2994, 3341, 0), "Climb up the east ladder in Falador Castle."); + goUpCastle2 = new ObjectStep(this, ObjectID.FAI_FALADOR_CASTLE_STAIRS, new WorldPoint(2985, 3338, 1), "Go up the staircase west of the ladder on the 1st floor."); - searchCupboard = new ObjectStep(this, ObjectID.VYVINCUPBOARDOPEN, new WorldPoint(2985, 3336, 2), "Search the cupboard in the room south of the staircase. You'll need Sir Vyvin to be in the other room.", searchCupboardReq); - ((ObjectStep)searchCupboard).addAlternateObjects(ObjectID.VYVINCUPBOARDSHUT); // 2271 is the closed cupboard - givePortraitToThurgo = new NpcStep(this, NpcID.THURGO, new WorldPoint(3000, 3145, 0), "Bring Thurgo the portrait.", ironBars, portrait); + + searchCupboard = new ObjectStep(this, ObjectID.VYVINCUPBOARDOPEN, new WorldPoint(2985, 3336, 2), "Search the cupboard in the room south of the staircase. You'll need Sir Vyvin to be in the other room.", sirVyvinNotInRoom); + searchCupboard.addAlternateObjects(ObjectID.VYVINCUPBOARDSHUT); + + givePortraitToThurgo = new NpcStep(this, NpcID.THURGO, new WorldPoint(3000, 3145, 0), "Bring Thurgo the portrait.", pickaxe, ironBars, portrait); givePortraitToThurgo.addDialogStep("About that sword..."); + givePortraitToThurgo.addTeleport(homeTele.quantity(1)); + enterDungeon = new ObjectStep(this, ObjectID.FAI_TRAPDOOR, new WorldPoint(3008, 3150, 0), "Go down the ladder south of Port Sarim. Be prepared for ice giants and ice warriors to attack you.", pickaxe, ironBars); + mineBlurite = new ObjectStep(this, ObjectID.BLURITE_ROCK_1, new WorldPoint(3049, 9566, 0), "Mine a blurite ore in the eastern cavern.", pickaxe); + bringThurgoOre = new NpcStep(this, NpcID.THURGO, new WorldPoint(3000, 3145, 0), "Return to Thurgo with a blurite ore and two iron bars.", bluriteOre, ironBars); bringThurgoOre.addDialogStep("Can you make that replacement sword now?"); + finishQuest = new NpcStep(this, NpcID.SQUIRE, new WorldPoint(2978, 3341, 0), "Return to the Squire with the sword to finish the quest.", bluriteSword); + finishQuest.addTeleport(faladorTeleports.quantity(1)); + } + + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToSquire); + steps.put(1, talkToReldo); + steps.put(2, talkToThurgo); + steps.put(3, talkToThurgoAgain); + steps.put(4, talkToSquire2); + + var getPortrait = new ConditionalStep(this, goUpCastle1); + getPortrait.addStep(portrait.alsoCheckBank(), givePortraitToThurgo); + getPortrait.addStep(inFaladorCastle2, searchCupboard); + getPortrait.addStep(inFaladorCastle1, goUpCastle2); + + steps.put(5, getPortrait); + + var returnSwordToSquire = new ConditionalStep(this, enterDungeon); + returnSwordToSquire.addStep(bluriteSword.alsoCheckBank(), finishQuest); + returnSwordToSquire.addStep(bluriteOre.alsoCheckBank(), bringThurgoOre); + returnSwordToSquire.addStep(inDungeon, mineBlurite); + + steps.put(6, returnSwordToSquire); + + return steps; + } + + @Override + public List getGeneralRequirements() + { + return List.of( + new SkillRequirement(Skill.MINING, 10, true) + ); } @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(redberryPie); - reqs.add(ironBars); - reqs.add(pickaxe); - return reqs; + return List.of( + redberryPie, + ironBars, + pickaxe + ); } @Override public List getItemRecommended() { - ArrayList reqs = new ArrayList<>(); - reqs.add(varrockTeleport); - reqs.add(faladorTeleports); - reqs.add(homeTele); - return reqs; + return List.of( + varrockTeleport, + faladorTeleports, + homeTele + ); } @Override public List getCombatRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add("Able to survive attacks from Ice Warriors (level 57) and Ice Giants (level 53)"); - return reqs; + return List.of( + "Able to survive attacks from Ice Warriors (level 57) and Ice Giants (level 53)" + ); } @Override - public List getGeneralRequirements() + public List getNotes() { - return Collections.singletonList(new SkillRequirement(Skill.MINING, 10, true)); + return List.of( + "You can make progress towards the Falador Easy Diary task by mining an additional Blurite ore and smelting another Blurite bar, it will be required for smithing Blurite limbs." + ); } @Override @@ -207,33 +264,57 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.SMITHING, 12725)); + return List.of( + new ExperienceReward(Skill.SMITHING, 12725) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("The ability to smelt Blurite ore."), - new UnlockReward("The ability to smith Blurite bars.")); + return List.of( + new UnlockReward("The ability to smelt Blurite ore."), + new UnlockReward("The ability to smith Blurite bars.") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - - allSteps.add(new PanelDetails("Starting off", Arrays.asList(talkToSquire, talkToReldo))); - allSteps.add(new PanelDetails("Finding an Imcando", Arrays.asList(talkToThurgo, talkToThurgoAgain), redberryPie)); - allSteps.add(new PanelDetails("Find the portrait", Arrays.asList(talkToSquire2, goUpCastle1, goUpCastle2, searchCupboard, givePortraitToThurgo))); - allSteps.add(new PanelDetails("Making the sword", Arrays.asList(enterDungeon, mineBlurite, bringThurgoOre), pickaxe, ironBars)); - allSteps.add(new PanelDetails("Return the sword", Collections.singletonList(finishQuest))); - return allSteps; - } + var sections = new ArrayList(); - @Override - public List getNotes() - { - return Collections.singletonList("You can make progress towards the Falador Easy Diary task by mining an additional Blurite ore and smelting another Blurite bar, it will be required for smithing Blurite limbs."); + sections.add(new PanelDetails("Starting off", List.of( + talkToSquire, + talkToReldo + ))); + + sections.add(new PanelDetails("Finding an Imcando", List.of( + talkToThurgo, + talkToThurgoAgain + ), List.of( + redberryPie + ))); + + sections.add(new PanelDetails("Find the portrait", List.of( + talkToSquire2, + goUpCastle1, + goUpCastle2, + searchCupboard, + givePortraitToThurgo + ))); + + sections.add(new PanelDetails("Making the sword", List.of(enterDungeon, + mineBlurite, + bringThurgoOre + ), List.of( + pickaxe, + ironBars + ))); + + sections.add(new PanelDetails("Return the sword", List.of( + finishQuest + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thelosttribe/TheLostTribe.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thelosttribe/TheLostTribe.java index 2ea3c3713e..fe6427589f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thelosttribe/TheLostTribe.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thelosttribe/TheLostTribe.java @@ -40,82 +40,131 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcEmoteStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.client.plugins.microbot.questhelper.steps.emote.QuestEmote; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - public class TheLostTribe extends BasicQuestHelper { - //Items Required - ItemRequirement pickaxe, lightSource, brooch, book, key, silverware, treaty; - - //Items Recommended - ItemRequirement varrockTeleport, faladorTeleport, lumbridgeTeleports; - - Requirement inBasement, inLumbridgeF0, inLumbridgeF1, inLumbridgeF2, inTunnels, inMines, - foundRobes, inHamBase, foundSilverwareOrToldOnSigmund, bobKnows, hansKnows; - - DetailedQuestStep goDownFromF2, talkToSigmund, talkToDuke, goDownFromF1, talkToHans, goUpToF1, - goDownIntoBasement, usePickaxeOnRubble, climbThroughHole, grabBrooch, climbOutThroughHole, goUpFromBasement, - showBroochToDuke, searchBookcase, readBook, talkToGenerals, walkToMistag, emoteAtMistag, pickpocketSigmund, - unlockChest, enterHamLair, searchHamCrates, talkToKazgar, talkToMistagForEnd, talkToBob, talkToAllAboutCellar; - - ConditionalStep goToF1Steps, goDownToBasement, goTalkToSigmundToStart, findGoblinWitnessSteps, goTalkToDukeAfterHans, - goMineRubble, enterTunnels, goShowBroochToDuke, goTalkToDukeAfterEmote, goTravelToMistag, goGetKey, goOpenRobeChest, - goIntoHamLair, goToDukeWithSilverware, travelToMakePeace; - - //Zones - Zone basement, lumbridgeF0, lumbridgeF1, lumbridgeF2, tunnels, mines, hamBase; + // Required items + ItemRequirement pickaxe; + ItemRequirement lightSource; + + // Recommended item + ItemRequirement varrockTeleport; + ItemRequirement faladorTeleport; + ItemRequirement lumbridgeTeleports; + + // Mid-quest item requirements + ItemRequirement brooch; + ItemRequirement book; + ItemRequirement key; + ItemRequirement silverware; + ItemRequirement treaty; + + // Zones + Zone basement; + Zone lumbridgeF0; + Zone lumbridgeF1; + Zone lumbridgeF2; + Zone tunnels; + Zone mines; + Zone hamBase; + + // Miscellaneous requirements + ZoneRequirement inBasement; + ZoneRequirement inLumbridgeF0; + ZoneRequirement inLumbridgeF1; + ZoneRequirement inLumbridgeF2; + ZoneRequirement inTunnels; + ZoneRequirement inMines; + VarbitRequirement foundRobes; + ZoneRequirement inHamBase; + VarbitRequirement foundSilverwareOrToldOnSigmund; + VarbitRequirement bobKnows; + VarbitRequirement hansKnows; + + // Steps + ObjectStep goDownIntoBasement; + ObjectStep goDownFromF1; + ObjectStep goUpToF1; + ObjectStep goUpFromBasement; + ObjectStep goDownFromF2; + ObjectStep climbOutThroughHole; + ConditionalStep goToF1Steps; + + NpcStep talkToSigmund; + ConditionalStep goTalkToSigmundToStart; + + NpcStep talkToHans; + NpcStep talkToBob; + NpcStep talkToAllAboutCellar; + ConditionalStep findGoblinWitnessSteps; + + NpcStep talkToDuke; + ConditionalStep goTalkToDukeAfterHans; + + ConditionalStep goDownToBasement; + ObjectStep usePickaxeOnRubble; + ConditionalStep goMineRubble; + + ObjectStep climbThroughHole; + ConditionalStep enterTunnels; + DetailedQuestStep grabBrooch; + NpcStep showBroochToDuke; + ConditionalStep goShowBroochToDuke; + + ObjectStep searchBookcase; + DetailedQuestStep readBook; + + NpcStep talkToGenerals; + + NpcEmoteStep walkToMistag; + NpcEmoteStep emoteAtMistag; + ConditionalStep goTravelToMistag; + + ConditionalStep goTalkToDukeAfterEmote; + + NpcStep pickpocketSigmund; + ConditionalStep goGetKey; + ObjectStep unlockChest; + ConditionalStep goOpenRobeChest; + ObjectStep enterHamLair; + ObjectStep searchHamCrates; + ConditionalStep goIntoHamLair; + ConditionalStep goToDukeWithSilverware; + + NpcStep talkToKazgar; + NpcStep talkToMistagForEnd; + ConditionalStep travelToMakePeace; @Override - public Map loadSteps() + protected void setupZones() { - initializeRequirements(); - setupConditions(); - setupSteps(); - setupConditionalSteps(); - Map steps = new HashMap<>(); - - steps.put(0, goTalkToSigmundToStart); - steps.put(1, findGoblinWitnessSteps); - steps.put(2, goTalkToDukeAfterHans); - steps.put(3, goMineRubble); - - ConditionalStep goGrabBrooch = new ConditionalStep(this, enterTunnels); - goGrabBrooch.addStep(brooch, goShowBroochToDuke); - goGrabBrooch.addStep(inTunnels, grabBrooch); - steps.put(4, goGrabBrooch); - - ConditionalStep getBook = new ConditionalStep(this, searchBookcase); - getBook.addStep(book, readBook); - steps.put(5, getBook); - - steps.put(6, talkToGenerals); - - ConditionalStep makeContactSteps = new ConditionalStep(this, goTravelToMistag); - makeContactSteps.addStep(inMines, emoteAtMistag); - makeContactSteps.addStep(inTunnels, walkToMistag); - - steps.put(7, makeContactSteps); - steps.put(8, goTalkToDukeAfterEmote); - - ConditionalStep revealSigmund = new ConditionalStep(this, goGetKey); - revealSigmund.addStep(silverware.alsoCheckBank(), goToDukeWithSilverware); - revealSigmund.addStep(foundRobes, goIntoHamLair); - revealSigmund.addStep(key, goOpenRobeChest); - steps.put(9, revealSigmund); - - steps.put(10, travelToMakePeace); - - return steps; + basement = new Zone(new WorldPoint(3208, 9614, 0), new WorldPoint(3219, 9625, 0)); + lumbridgeF0 = new Zone(new WorldPoint(3136, 3136, 0), new WorldPoint(3328, 3328, 0)); + lumbridgeF1 = new Zone(new WorldPoint(3203, 3206, 1), new WorldPoint(3217, 3231, 1)); + lumbridgeF2 = new Zone(new WorldPoint(3203, 3206, 2), new WorldPoint(3217, 3231, 2)); + tunnels = new Zone(new WorldPoint(3221, 9602, 0), new WorldPoint(3308, 9661, 0)); + mines = new Zone(new WorldPoint(3309, 9600, 0), new WorldPoint(3327, 9655, 0)); + hamBase = new Zone(new WorldPoint(3140, 9600, 0), new WorldPoint(3190, 9655, 0)); } @Override @@ -136,22 +185,7 @@ protected void setupRequirements() varrockTeleport = new ItemRequirement("Varrock teleport", ItemID.POH_TABLET_VARROCKTELEPORT); lumbridgeTeleports = new ItemRequirement("Lumbridge teleports", ItemID.POH_TABLET_LUMBRIDGETELEPORT, 3); faladorTeleport = new ItemRequirement("Falador teleport", ItemID.POH_TABLET_FALADORTELEPORT); - } - @Override - protected void setupZones() - { - basement = new Zone(new WorldPoint(3208, 9614, 0), new WorldPoint(3219, 9625, 0)); - lumbridgeF0 = new Zone(new WorldPoint(3136, 3136, 0), new WorldPoint(3328, 3328, 0)); - lumbridgeF1 = new Zone(new WorldPoint(3203, 3206, 1), new WorldPoint(3217, 3231, 1)); - lumbridgeF2 = new Zone(new WorldPoint(3203, 3206, 2), new WorldPoint(3217, 3231, 2)); - tunnels = new Zone(new WorldPoint(3221, 9602, 0), new WorldPoint(3308, 9661, 0)); - mines = new Zone(new WorldPoint(3309, 9600, 0), new WorldPoint(3327, 9655, 0)); - hamBase = new Zone(new WorldPoint(3140, 9600, 0), new WorldPoint(3190, 9655, 0)); - } - - public void setupConditions() - { inBasement = new ZoneRequirement(basement); inLumbridgeF0 = new ZoneRequirement(lumbridgeF0); inLumbridgeF1 = new ZoneRequirement(lumbridgeF1); @@ -176,46 +210,82 @@ public void setupSteps() goDownFromF1 = new ObjectStep(this, ObjectID.SPIRALSTAIRSMIDDLE, new WorldPoint(3205, 3208, 1), "Go down the staircase."); goDownFromF1.addDialogStep("Climb down the stairs."); goUpToF1 = new ObjectStep(this, ObjectID.SPIRALSTAIRSBOTTOM_3, new WorldPoint(3205, 3208, 0), "Go up to the first floor of Lumbridge Castle."); + goUpToF1.addDialogStep("Can you show me the way out of the mines?"); goUpFromBasement = new ObjectStep(this, ObjectID.LADDER_FROM_CELLAR, new WorldPoint(3209, 9616, 0), "Go up to the surface."); goDownFromF2 = new ObjectStep(this, ObjectID.SPIRALSTAIRSTOP_3, new WorldPoint(3205, 3208, 2), "Go downstairs."); + climbOutThroughHole = new ObjectStep(this, ObjectID.LOST_TRIBE_CAVEWALL_HOLE_WALLDECOR, new WorldPoint(3221, 9618, 0), ""); + climbOutThroughHole.setForceClickboxHighlight(true); + + goToF1Steps = new ConditionalStep(this, goUpToF1); + goToF1Steps.addStep(inLumbridgeF2, goDownFromF2); + goToF1Steps.addStep(inBasement, goUpFromBasement); + goToF1Steps.addStep(inTunnels, climbOutThroughHole); + talkToSigmund = new NpcStep(this, NpcID.LOST_TRIBE_SIGMUND_THERE, new WorldPoint(3210, 3222, 1), ""); talkToSigmund.addDialogSteps("Do you have any quests for me?", "Yes."); + goTalkToSigmundToStart = new ConditionalStep(this, goToF1Steps, "Talk to Sigmund in Lumbridge Castle."); + goTalkToSigmundToStart.addStep(inLumbridgeF1, talkToSigmund); + // This isn't just talk to Hans, it's a random one of the NPCs to chat to talkToHans = new NpcStep(this, NpcID.HANS, new WorldPoint(3222, 3218, 0), "Talk to Hans who is roaming around the castle."); talkToHans.addDialogStep("Do you know what happened in the cellar?"); - talkToBob = new NpcStep(this, NpcID.TWOCATS_BOB_CUTSCENE, new WorldPoint(3231, 3203, 0), "Talk to Bob in the south of Lumbridge."); + talkToBob = new NpcStep(this, NpcID.BOB, new WorldPoint(3231, 3203, 0), "Talk to Bob in the south of Lumbridge."); talkToBob.addDialogStep("Do you know what happened in the castle cellar?"); - talkToAllAboutCellar = new NpcStep(this, NpcID.COOK, "Talk to the Cook, Hans, Father Aereck, and Bob in Lumbridge until one tells you about seeing a goblin."); - ((NpcStep)(talkToAllAboutCellar)).addAlternateNpcs(NpcID.FATHER_AERECK); + talkToAllAboutCellar = new NpcStep(this, NpcID.COOK, ""); + talkToAllAboutCellar.addAlternateNpcs(NpcID.FATHER_AERECK); talkToAllAboutCellar.addDialogSteps("Do you know what happened in the castle cellar?"); talkToAllAboutCellar.addSubSteps(talkToHans, talkToBob); + findGoblinWitnessSteps = new ConditionalStep(this, talkToAllAboutCellar, "Talk to the Cook, Hans, Father Aereck, and Bob in Lumbridge until one tells you about seeing a goblin."); + findGoblinWitnessSteps.addStep(inLumbridgeF2, goDownFromF2); + findGoblinWitnessSteps.addStep(inLumbridgeF1, goDownFromF1); + findGoblinWitnessSteps.addStep(inBasement, goUpFromBasement); + findGoblinWitnessSteps.addStep(hansKnows, talkToHans); + findGoblinWitnessSteps.addStep(bobKnows, talkToBob); + talkToDuke = new NpcStep(this, NpcID.DUKE_OF_LUMBRIDGE, new WorldPoint(3210, 3222, 1), ""); + + goTalkToDukeAfterHans = new ConditionalStep(this, goToF1Steps, "Talk to Duke Horacio in Lumbridge Castle."); + goTalkToDukeAfterHans.addDialogSteps("Hans says he saw something in the cellar", "Bob says he saw something in the cellar", "Father Aereck says he saw something in the cellar", "The cook says he saw something in the cellar"); + goTalkToDukeAfterHans.addStep(inLumbridgeF1, talkToDuke); + + goDownToBasement = new ConditionalStep(this, goDownIntoBasement); + goDownToBasement.addStep(inLumbridgeF2, goDownFromF2); + goDownToBasement.addStep(inLumbridgeF1, goDownFromF1); + // Name of person who said they saw something changes usePickaxeOnRubble = new ObjectStep(this, ObjectID.LOST_TRIBE_CELLAR_WALL, new WorldPoint(3219, 9618, 0), ""); usePickaxeOnRubble.addIcon(ItemID.BRONZE_PICKAXE); + goMineRubble = new ConditionalStep(this, goDownToBasement, "Use a pickaxe on the rubble in the Lumbridge Castle basement.", pickaxe.highlighted(), lightSource); + goMineRubble.addStep(inBasement, usePickaxeOnRubble); + climbThroughHole = new ObjectStep(this, ObjectID.LOST_TRIBE_CELLAR_WALL, new WorldPoint(3219, 9618, 0), ""); + climbThroughHole.setForceClickboxHighlight(true); - grabBrooch = new DetailedQuestStep(this, new WorldPoint(3230, 9610, 0), "Pick up the brooch on the floor.", brooch); + enterTunnels = new ConditionalStep(this, goDownToBasement, "Enter the hole in Lumbridge Castle's basement.", lightSource); + enterTunnels.addStep(inBasement, climbThroughHole); - climbOutThroughHole = new ObjectStep(this, ObjectID.LOST_TRIBE_CAVEWALL_HOLE_WALLDECOR, new WorldPoint(3221, 9618, 0), ""); + grabBrooch = new DetailedQuestStep(this, new WorldPoint(3230, 9610, 0), "Pick up the brooch on the floor.", brooch); showBroochToDuke = new NpcStep(this, NpcID.DUKE_OF_LUMBRIDGE, new WorldPoint(3210, 3222, 1), ""); showBroochToDuke.addDialogStep("I dug through the rubble..."); + goShowBroochToDuke = new ConditionalStep(this, goToF1Steps, "Show the brooch to Duke Horacio in Lumbridge Castle.", brooch); + goShowBroochToDuke.addStep(inLumbridgeF1, showBroochToDuke); + searchBookcase = new ObjectStep(this, ObjectID.LOST_TRIBE_BOOKCASE, new WorldPoint(3207, 3496, 0), "Search the north west bookcase in the Varrock Castle Library."); searchBookcase.addTeleport(varrockTeleport); + readBook = new DetailedQuestStep(this, "Read the entire goblin symbol book.", book); - readBook.addWidgetHighlight(183, 16); + readBook.addWidgetHighlight(InterfaceID.LostTribeSymbolBook.LOST_TRIBE_RIGHT_ARROW); talkToGenerals = new NpcStep(this, NpcID.GENERAL_WARTFACE_GREEN, new WorldPoint(2957, 3512, 0), "Talk to the Goblin Generals in the Goblin Village."); talkToGenerals.addTeleport(faladorTeleport); - talkToGenerals.addDialogSteps("Have you ever heard of the Dorgeshuun?", "It doesn't really matter", - "Well either way they refused to fight", "Well I found a brooch underground...", "Well why not show me both greetings?"); + talkToGenerals.addDialogSteps("Have you ever heard of the Dorgeshuun?", "It doesn't really matter", "Well either way they refused to fight", "Well I found a brooch underground...", "Well why not show me both greetings?"); List travelLine = Arrays.asList( new WorldPoint(3222, 9618, 0), @@ -261,52 +331,6 @@ public void setupSteps() emoteAtMistag = new NpcEmoteStep(this, NpcID.LOST_TRIBE_MISTAG_1OP, QuestEmote.GOBLIN_BOW, new WorldPoint(3319, 9615, 0), "Perform the Goblin Bow emote next to Mistag and talk to him.", lightSource); - pickpocketSigmund = new NpcStep(this, NpcID.LOST_TRIBE_SIGMUND_THERE, new WorldPoint(3210, 3222, 1), ""); - unlockChest = new ObjectStep(this, ObjectID.LOST_TRIBE_CHEST, new WorldPoint(3209, 3217, 1), ""); - - enterHamLair = new ObjectStep(this, ObjectID.HAM_MULTI_TRAPDOOR, new WorldPoint(3166, 3252, 0), ""); - - searchHamCrates = new ObjectStep(this, ObjectID.LOST_TRIBE_CRATE, new WorldPoint(3152, 9645, 0), ""); - - talkToKazgar = new NpcStep(this, NpcID.LOST_TRIBE_GUIDE_2OPS, new WorldPoint(3230, 9610, 0), "Travel with Kazgar to shortcut to Mistag."); - talkToMistagForEnd = new NpcStep(this, NpcID.LOST_TRIBE_MISTAG_2OPS, new WorldPoint(3319, 9615, 0), ""); - } - - private void setupConditionalSteps() - { - goToF1Steps = new ConditionalStep(this, goUpToF1); - goToF1Steps.addStep(inLumbridgeF2, goDownFromF2); - goToF1Steps.addStep(inBasement, goUpFromBasement); - goToF1Steps.addStep(inTunnels, climbOutThroughHole); - - goDownToBasement = new ConditionalStep(this, goDownIntoBasement); - goDownToBasement.addStep(inLumbridgeF2, goDownFromF2); - goDownToBasement.addStep(inLumbridgeF1, goDownFromF1); - - goTalkToSigmundToStart = new ConditionalStep(this, goToF1Steps, "Talk to Sigmund in Lumbridge Castle."); - goTalkToSigmundToStart.addStep(inLumbridgeF1, talkToSigmund); - - findGoblinWitnessSteps = new ConditionalStep(this, talkToAllAboutCellar); - findGoblinWitnessSteps.addStep(inLumbridgeF2, goDownFromF2); - findGoblinWitnessSteps.addStep(inLumbridgeF1, goDownFromF1); - findGoblinWitnessSteps.addStep(inBasement, goUpFromBasement); - findGoblinWitnessSteps.addStep(hansKnows, talkToHans); - findGoblinWitnessSteps.addStep(bobKnows, talkToBob); - - goTalkToDukeAfterHans = new ConditionalStep(this, goToF1Steps, "Talk to Duke Horacio in Lumbridge Castle."); - goTalkToDukeAfterHans.addDialogSteps("Hans says he saw something in the cellar", "Bob says he saw something in the cellar", - "Father Aereck says he saw something in the cellar", "The cook says he saw something in the cellar"); - goTalkToDukeAfterHans.addStep(inLumbridgeF1, talkToDuke); - - goMineRubble = new ConditionalStep(this, goDownToBasement, "Go use a pickaxe on the rubble in the Lumbridge Castle basement.", pickaxe.highlighted(), lightSource); - goMineRubble.addStep(inBasement, usePickaxeOnRubble); - - enterTunnels = new ConditionalStep(this, goDownToBasement, "Enter the hole in Lumbridge Castle's basement.", lightSource); - enterTunnels.addStep(inBasement, climbThroughHole); - - goShowBroochToDuke = new ConditionalStep(this, goToF1Steps, "Show the brooch to Duke Horacio in Lumbridge Castle.", brooch); - goShowBroochToDuke.addStep(inLumbridgeF1, showBroochToDuke); - goTravelToMistag = new ConditionalStep(this, goDownToBasement, "Travel through the tunnels under Lumbridge until you reach Mistag.", lightSource); goTravelToMistag.addStep(inBasement, climbThroughHole); goTravelToMistag.addSubSteps(walkToMistag); @@ -315,12 +339,20 @@ private void setupConditionalSteps() goTalkToDukeAfterEmote.addDialogSteps("I've made contact with the cave goblins..."); goTalkToDukeAfterEmote.addStep(inLumbridgeF1, talkToDuke); + pickpocketSigmund = new NpcStep(this, NpcID.LOST_TRIBE_SIGMUND_THERE, new WorldPoint(3210, 3222, 1), ""); + goGetKey = new ConditionalStep(this, goToF1Steps, "Pickpocket Sigmund for a key."); goGetKey.addStep(inLumbridgeF1, pickpocketSigmund); + unlockChest = new ObjectStep(this, ObjectID.LOST_TRIBE_CHEST, new WorldPoint(3209, 3217, 1), ""); + goOpenRobeChest = new ConditionalStep(this, goToF1Steps, "Open the chest in the room next to the Duke's room.", key); goOpenRobeChest.addStep(inLumbridgeF1, unlockChest); + enterHamLair = new ObjectStep(this, ObjectID.HAM_MULTI_TRAPDOOR, new WorldPoint(3166, 3252, 0), ""); + + searchHamCrates = new ObjectStep(this, ObjectID.LOST_TRIBE_CRATE, new WorldPoint(3152, 9645, 0), ""); + goIntoHamLair = new ConditionalStep(this, enterHamLair, "Enter the H.A.M lair west of Lumbridge and search a crate in its entrance for the silverware."); goIntoHamLair.addStep(inHamBase, searchHamCrates); goIntoHamLair.addStep(inLumbridgeF2, goDownFromF2); @@ -331,34 +363,91 @@ private void setupConditionalSteps() goToDukeWithSilverware.addDialogStep("I found the missing silverware in the HAM cave!"); goToDukeWithSilverware.addStep(inLumbridgeF1, talkToDuke); + talkToKazgar = new NpcStep(this, NpcID.LOST_TRIBE_GUIDE_2OPS, new WorldPoint(3230, 9610, 0), "Travel with Kazgar to shortcut to Mistag."); + talkToKazgar.addDialogStep("Can you show me the way to the mines?"); + talkToMistagForEnd = new NpcStep(this, NpcID.LOST_TRIBE_MISTAG_2OPS, new WorldPoint(3319, 9615, 0), ""); + travelToMakePeace = new ConditionalStep(this, goDownToBasement, "Travel through the tunnels until you reach Mistag, and give him the treaty.", lightSource, treaty); + travelToMakePeace.addDialogStep("What was I doing again?"); travelToMakePeace.addStep(inMines, talkToMistagForEnd); travelToMakePeace.addStep(inTunnels, talkToKazgar); travelToMakePeace.addStep(inBasement, climbThroughHole); } + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, goTalkToSigmundToStart); + + steps.put(1, findGoblinWitnessSteps); + + steps.put(2, goTalkToDukeAfterHans); + + steps.put(3, goMineRubble); + + var goGrabBrooch = new ConditionalStep(this, enterTunnels); + goGrabBrooch.addStep(brooch, goShowBroochToDuke); + goGrabBrooch.addStep(inTunnels, grabBrooch); + steps.put(4, goGrabBrooch); + + var getBook = new ConditionalStep(this, searchBookcase); + getBook.addStep(book, readBook); + steps.put(5, getBook); + + steps.put(6, talkToGenerals); + + var makeContactSteps = new ConditionalStep(this, goTravelToMistag); + makeContactSteps.addStep(inMines, emoteAtMistag); + makeContactSteps.addStep(inTunnels, walkToMistag); + steps.put(7, makeContactSteps); + + steps.put(8, goTalkToDukeAfterEmote); + + var revealSigmund = new ConditionalStep(this, goGetKey); + revealSigmund.addStep(silverware.alsoCheckBank(), goToDukeWithSilverware); + revealSigmund.addStep(foundRobes, goIntoHamLair); + revealSigmund.addStep(key, goOpenRobeChest); + steps.put(9, revealSigmund); + + steps.put(10, travelToMakePeace); + + return steps; + } + @Override public List getItemRequirements() { - return Arrays.asList(pickaxe, lightSource); + return List.of( + pickaxe, + lightSource + ); } @Override public List getItemRecommended() { - return Arrays.asList(lumbridgeTeleports, varrockTeleport, faladorTeleport); + return List.of( + lumbridgeTeleports, + varrockTeleport, + faladorTeleport + ); } @Override public List getGeneralRequirements() { - ArrayList req = new ArrayList<>(); - req.add(new QuestRequirement(QuestHelperQuest.GOBLIN_DIPLOMACY, QuestState.FINISHED)); - req.add(new QuestRequirement(QuestHelperQuest.RUNE_MYSTERIES, QuestState.FINISHED)); - req.add(new SkillRequirement(Skill.AGILITY, 13, true)); - req.add(new SkillRequirement(Skill.THIEVING, 13, true)); - req.add(new SkillRequirement(Skill.MINING, 17, true)); - return req; + return List.of( + new QuestRequirement(QuestHelperQuest.GOBLIN_DIPLOMACY, QuestState.FINISHED), + new QuestRequirement(QuestHelperQuest.RUNE_MYSTERIES, QuestState.FINISHED), + new SkillRequirement(Skill.AGILITY, 13, true), + new SkillRequirement(Skill.THIEVING, 13, true), + new SkillRequirement(Skill.MINING, 17, true) + ); } @Override @@ -370,34 +459,74 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.MINING, 3000)); + return List.of( + new ExperienceReward(Skill.MINING, 3000) + ); } @Override public List getItemRewards() { - return Collections.singletonList(new ItemReward("Ring of Life", ItemID.RING_OF_LIFE, 1)); + return List.of( + new ItemReward("Ring of Life", ItemID.RING_OF_LIFE, 1) + ); } @Override public List getUnlockRewards() { - return Arrays.asList( - new UnlockReward("Access to the Dorgesh-Kann mine."), - new UnlockReward("Access to Nardok's Bone Weapon Store"), - new UnlockReward("2 new goblin emotes.")); + return List.of( + new UnlockReward("Access to the Dorgesh-Kaan mine."), + new UnlockReward("Access to Nardok's Bone Weapon Store"), + new UnlockReward("2 new goblin emotes.") + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); - allSteps.add(new PanelDetails("Starting off", Arrays.asList(goTalkToSigmundToStart, talkToAllAboutCellar, goTalkToDukeAfterHans))); - allSteps.add(new PanelDetails("Investigating", Arrays.asList(goMineRubble, enterTunnels, grabBrooch, goShowBroochToDuke), pickaxe, lightSource)); - allSteps.add(new PanelDetails("Learning about goblins", Arrays.asList(searchBookcase, readBook, talkToGenerals))); - allSteps.add(new PanelDetails("Making contact", Arrays.asList(goTravelToMistag, emoteAtMistag, goTalkToDukeAfterEmote), lightSource)); - allSteps.add(new PanelDetails("Resolving tensions", Arrays.asList(goGetKey, goOpenRobeChest, goIntoHamLair, goToDukeWithSilverware, travelToMakePeace), lightSource)); - - return allSteps; + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + goTalkToSigmundToStart, + findGoblinWitnessSteps, + goTalkToDukeAfterHans + ))); + + sections.add(new PanelDetails("Investigating", List.of( + goMineRubble, + enterTunnels, + grabBrooch, + goShowBroochToDuke + ), List.of( + pickaxe, + lightSource + ))); + + sections.add(new PanelDetails("Learning about goblins", List.of( + searchBookcase, + readBook, + talkToGenerals + ))); + + sections.add(new PanelDetails("Making contact", List.of( + goTravelToMistag, + emoteAtMistag, + goTalkToDukeAfterEmote + ), List.of( + lightSource + ))); + + sections.add(new PanelDetails("Resolving tensions", List.of( + goGetKey, + goOpenRobeChest, + goIntoHamLair, + goToDukeWithSilverware, + travelToMakePeace + ), List.of( + lightSource + ))); + + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/ThePathOfGlouphrie.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/ThePathOfGlouphrie.java index 5ba87899d0..f277847582 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/ThePathOfGlouphrie.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/ThePathOfGlouphrie.java @@ -53,6 +53,7 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; @@ -232,7 +233,6 @@ private void setupConditions() learnedAboutChapter1 = new VarbitRequirement(VarbitID.POG_BOLRIE_DIARY_1, 1); learnedAboutChapter2 = new VarbitRequirement(VarbitID.POG_BOLRIE_DIARY_2, 1); - // learnedAboutChapter3 = new VarbitRequirement(VarbitID.POG_BOLRIE_DIARY_3, 1); inSewer1 = new ZoneRequirement(sewer1); inSewer2 = new ZoneRequirement(sewer2); @@ -242,7 +242,7 @@ private void setupConditions() inSewer6 = new Conditions(LogicType.OR, new ZoneRequirement(sewer6Section1), new ZoneRequirement(sewer6Section2)); inBossRoom = new ZoneRequirement(bossRoom); - lecternWidgetActive = new WidgetTextRequirement(854, 5, "Chapter 1. Bad advice"); + lecternWidgetActive = new WidgetTextRequirement(InterfaceID.PogBolriesDiary.CHAPTER1, "Chapter 1. Bad advice"); protectMissiles = new PrayerRequirement("Protect from Missiles to reduce damage taken by the Terrorbirds", Prayer.PROTECT_FROM_MISSILES); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/YewnocksPuzzle.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/YewnocksPuzzle.java index 3d2db996f8..8094f802a2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/YewnocksPuzzle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/YewnocksPuzzle.java @@ -35,6 +35,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.InventoryID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.ObjectID; @@ -374,11 +375,11 @@ protected void setupSteps() getMoreDiscs = new ObjectStep(getQuestHelper(), ObjectID.POG_CHEST_CLOSED, regionPoint(34, 31), "Get more discs from the chests outside. You can drop discs before you get more. You can also use the exchanger next to Yewnock's machine.", true); useExchanger = new ObjectStep(getQuestHelper(), ObjectID.POG_GNOME_MACHINE_03, regionPoint(22, 33), "A solution has been calculated, exit the machine interface & click Yewnock's exchanger."); - useExchanger.addWidgetHighlight(848, 27); // TODO: Verify that this is the "exit" button in the Machine widget + useExchanger.addWidgetHighlight(InterfaceID.PogCoinMachine.CLOSE); clickMachine = new ObjectStep(getQuestHelper(), ObjectID.POG_GNOME_MACHINE_02, regionPoint(22, 32), "A solution has been found, click Yewnock's machine and insert the discs as prompted."); - clickMachine.addWidgetHighlight(849, 41); + clickMachine.addWidgetHighlight(InterfaceID.PogCoinExchanger.CLOSE); clickMachineOnce = new ObjectStep(getQuestHelper(), ObjectID.POG_GNOME_MACHINE_02, regionPoint(22, 32), "Operate Yewnock's machine to calculate a solution."); @@ -391,14 +392,14 @@ protected void setupSteps() 848, 26); exchangerInsertDisc = new DiscInsertionStep(getQuestHelper(), "Insert the highlighted disc into the highlighted slot."); - exchangerExchange = new WidgetStep(getQuestHelper(), "", 849, 40); + exchangerExchange = new WidgetStep(getQuestHelper(), "", InterfaceID.PogCoinExchanger.EXCHANGE); exchangerConfirm = new DetailedQuestStep(getQuestHelper(), "Click the confirm button."); - exchangerConfirm.addWidgetHighlight(849, 36); + exchangerConfirm.addWidgetHighlight(InterfaceID.PogCoinExchanger.SUBMIT); exchangerReset = new WidgetStep(getQuestHelper(), "Found unexpected disc(s) in the exchange input, reset & follow the instructions."); - exchangerReset.addWidgetHighlight(849, 34); + exchangerReset.addWidgetHighlight(InterfaceID.PogCoinExchanger.RESET); - machineOpen = new WidgetPresenceRequirement(848, 0); - exchangerOpen = new WidgetPresenceRequirement(849, 0); + machineOpen = new WidgetPresenceRequirement(InterfaceID.PogCoinMachine.UNIVERSE); + exchangerOpen = new WidgetPresenceRequirement(InterfaceID.PogCoinExchanger.UNIVERSE); } @Override @@ -453,9 +454,9 @@ public void shutDown() solution.reset(); } - private int getWidgetItemId(int groupId, int childId) + private int getWidgetItemId(int widgetId) { - var widget = client.getWidget(groupId, childId); + var widget = client.getWidget(widgetId); if (widget == null) { return -1; @@ -467,32 +468,32 @@ private int getWidgetItemId(int groupId, int childId) /** * This function will add a widget highlight to the slot where it finds a good exchange, if any * - * @return a pair of widget group + child IDs if there is an exchange we're looking for in one of the slots + * @return a widget ID if there is an exchange we're looking for in one of the slots */ - private Optional> findGoodExchange() + private Optional findGoodExchange() { - var exchangeResultTL = getWidgetItemId(849, 21); - var exchangeResultTR = getWidgetItemId(849, 24); - var exchangeResultBL = getWidgetItemId(849, 27); - var exchangeResultBR = getWidgetItemId(849, 30); + var exchangeResultTL = getWidgetItemId(InterfaceID.PogCoinExchanger.OUTPUT_1_MODEL); + var exchangeResultTR = getWidgetItemId(InterfaceID.PogCoinExchanger.OUTPUT_2_MODEL); + var exchangeResultBL = getWidgetItemId(InterfaceID.PogCoinExchanger.OUTPUT_3_MODEL); + var exchangeResultBR = getWidgetItemId(InterfaceID.PogCoinExchanger.OUTPUT_4_MODEL); for (var puzzleNeed : solution.puzzleNeeds) { if (puzzleNeed.getAllIds().contains(exchangeResultTL)) { - return Optional.of(Pair.of(849, 21)); + return Optional.of(InterfaceID.PogCoinExchanger.OUTPUT_1_MODEL); } if (puzzleNeed.getAllIds().contains(exchangeResultTR)) { - return Optional.of(Pair.of(849, 24)); + return Optional.of(InterfaceID.PogCoinExchanger.OUTPUT_2_MODEL); } if (puzzleNeed.getAllIds().contains(exchangeResultBL)) { - return Optional.of(Pair.of(849, 27)); + return Optional.of(InterfaceID.PogCoinExchanger.OUTPUT_3_MODEL); } if (puzzleNeed.getAllIds().contains(exchangeResultBR)) { - return Optional.of(Pair.of(849, 30)); + return Optional.of(InterfaceID.PogCoinExchanger.OUTPUT_4_MODEL); } } @@ -689,9 +690,9 @@ protected void updateSteps() exchangerConfirm.clearWidgetHighlights(); // Highlight the confirm button - exchangerConfirm.addWidgetHighlight(849, 36); + exchangerConfirm.addWidgetHighlight(InterfaceID.PogCoinExchanger.SUBMIT); // Highlight the widget with the good exchange - exchangerConfirm.addWidgetHighlight(goodExchangeWidget.getLeft(), goodExchangeWidget.getRight()); + exchangerConfirm.addWidgetHighlight(goodExchangeWidget); startUpStep(exchangerConfirm); return; } @@ -699,9 +700,9 @@ protected void updateSteps() exchangerInsertDisc.setRequirements(solution.toExchange); // Exchanger widget is open - var exchangeInput1 = getWidgetItemId(849, 8); - var exchangeInput2 = getWidgetItemId(849, 13); - var exchangeInput3 = getWidgetItemId(849, 18); + var exchangeInput1 = getWidgetItemId(InterfaceID.PogCoinExchanger.INPUT_1_MODEL); + var exchangeInput2 = getWidgetItemId(InterfaceID.PogCoinExchanger.INPUT_2_MODEL); + var exchangeInput3 = getWidgetItemId(InterfaceID.PogCoinExchanger.INPUT_3_MODEL); List exchangeInputs = Stream.of(exchangeInput1, exchangeInput2, exchangeInput3).filter(itemId -> itemId > 0).collect(Collectors.toUnmodifiableList()); // TODO: Validate that the correct disc is in one of the 3 exchange slots (need their widget IDs or varbits) @@ -713,7 +714,7 @@ protected void updateSteps() // Highlight the first exchanger input exchangerInsertDisc.clearWidgetHighlights(); - exchangerInsertDisc.addWidgetHighlight(849, 8); + exchangerInsertDisc.addWidgetHighlight(InterfaceID.PogCoinExchanger.INPUT_1_MODEL); startUpStep(exchangerInsertDisc); return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/sections/TheWarpedDepths.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/sections/TheWarpedDepths.java index 1c9e04dbf0..97cbbe87f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/sections/TheWarpedDepths.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thepathofglouphrie/sections/TheWarpedDepths.java @@ -59,6 +59,7 @@ public void setup(ThePathOfGlouphrie quest) sewer1Ladder.addRecommended(quest.earmuffsOrSlayerHelmet); sewer2Ladder = new ObjectStep(quest, ObjectID.POG_SEWER_LADDER_TOP, new WorldPoint(1529, 4236, 1), "Climb down the ladder to the east."); + sewer2Ladder.setForceClickboxHighlight(true); sewer2Ladder.addRecommended(quest.protectMissiles); sewer2Ladder.addRecommended(quest.earmuffsOrSlayerHelmetEquipped); sewer3Ladder = new ObjectStep(quest, ObjectID.POG_SEWER_PIPE_SIDE_LADDER, new WorldPoint(1529, 4253, 0), @@ -67,6 +68,7 @@ public void setup(ThePathOfGlouphrie quest) sewer3Ladder.addRecommended(quest.earmuffsOrSlayerHelmetEquipped); sewer4Ladder = new ObjectStep(quest, ObjectID.POG_SEWER_LADDER_TOP, new WorldPoint(1486, 4282, 1), "Climb down the ladder to the north-west. Re-activate your run if you step in any puddles."); + sewer4Ladder.setForceClickboxHighlight(true); sewer4Ladder.addRecommended(quest.protectMissiles); sewer4Ladder.addRecommended(quest.earmuffsOrSlayerHelmetEquipped); sewer4Ladder.setLinePoints(List.of( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theredreef/TheRedReef.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theredreef/TheRedReef.java new file mode 100644 index 0000000000..3dac4184e5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theredreef/TheRedReef.java @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2026, pajlada + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.helpers.quests.theredreef; + +import net.runelite.client.plugins.microbot.questhelper.bank.banktab.BankSlotIcons; +import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; +import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; +import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; +import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NoFollowerRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.CombatLevelRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.PolyZone; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; +import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; +import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.runelite.client.plugins.microbot.questhelper.steps.WorldEntityStep; +import net.runelite.api.QuestState; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; + +public class TheRedReef extends BasicQuestHelper +{ + // Required items + ItemRequirement rangedCombatGearOrShipWithCannons; + ItemRequirement combatGear; + ItemRequirement combatGearBethel; + ItemRequirement combatGearLobster; + + // Recommended items + ItemRequirement food; + ItemRequirement prayerPotions; + ItemRequirement repairKits; + + // Mid-quest item requirements + ItemRequirement divingHelmet; + ItemRequirement divingHelmetEquipped; + ItemRequirement divingApparatus; + ItemRequirement divingApparatusEquipped; + + // Zones + Zone redRock; + Zone lastLightF0; + + // Miscellaneous requirements + ZoneRequirement onRedRock; + ZoneRequirement onLastLightF0; + ZoneRequirement onLastLightF1; + ZoneRequirement onLastLightF2; + NpcRequirement onZenith; + VarbitRequirement diving; + NpcRequirement giantLobsterAround; + VarbitRequirement onBoat; + FreeInventorySlotRequirement freeInv2; + NoFollowerRequirement noFollower; + + // Steps + // 0 + 2 + NpcStep talkToRaleyToStartQuest; + + // 4 + NpcStep talkToFinn; + + // 6 + NpcStep talkToElderKatt; + + // 8 + NpcStep talkToFloopa; + + // 10 + DetailedQuestStep sailToRedRock; + + // 12 + NpcStep talkToRedRockReceptionist; + + // 14 + ConditionalStep cInspectCases; + + // 16 + NpcStep talkToTheodorePaxton; + + // 18 + NpcStep sinkBlackEyeBethelBoats; + + // 20 + ObjectStep disembarkAtLastLight; + + // 22 + NpcStep killPiratesAtLastLight; + + // 24 + ObjectStep climbUpToF1; + ObjectStep climbUpToF2; + NpcStep killBlackEyeBethel; + + // 26 + ObjectStep climbDownToF1; + ObjectStep climbDownToF0; + ObjectStep sailToRedRock2; + ObjectStep boardYourShip; + NpcStep talkToTheodorePaxtonAgain; + ConditionalStep cReturnToTheodorePaxton; + + // 28 + WorldEntityStep sailToZenith; + + // 30 + NpcStep talkToSpencerBrentwood; + DetailedQuestStep equipDivingGearAndDive; + NpcStep dive; + DetailedQuestStep listenToSpencer; + + // 32 + ObjectStep repairCoralDredger; + NpcStep fightTheGiantLobster; + + // 34 + ObjectStep repairCoralDredger2; + + // 36 + NpcStep talkToSpencerNearEastCoralDredger; + + // 38 + NpcStep talkToSpencerAboutFuturePlans; + + // 40 + ConditionalStep cReturnToFloopa; + + @Override + protected void setupZones() + { + redRock = new PolyZone(List.of( + new WorldPoint(2809, 2508, 0), + new WorldPoint(2804, 2511, 0) + )); + + lastLightF0 = new Zone( + new WorldPoint(2867, 2319, 0), + new WorldPoint(2849, 2335, 0) + ); + } + + @Override + protected void setupRequirements() + { + rangedCombatGearOrShipWithCannons = new ItemRequirement("Ranged/Mage combat gear to skip boat combat, or a boat with cannons to deal with pirates", -1, -1).isNotConsumed(); + rangedCombatGearOrShipWithCannons.setDisplayItemId(BankSlotIcons.getRangedCombatGear()); + combatGear = new ItemRequirement("Combat gear", -1, -1).isNotConsumed(); + combatGear.setDisplayItemId(BankSlotIcons.getRangedCombatGear()); + combatGearBethel = new ItemRequirement("Combat gear to fight Black Eye Bethel", -1, -1).isNotConsumed(); + combatGearBethel.setDisplayItemId(BankSlotIcons.getRangedCombatGear()); + combatGearLobster = new ItemRequirement("Any combat gear to fight a giant lobster", -1, -1).isNotConsumed(); + combatGearLobster.setDisplayItemId(BankSlotIcons.getRangedCombatGear()); + + food = new ItemRequirement("Food", ItemCollections.GOOD_EATING_FOOD, -1); + prayerPotions = new ItemRequirement("Prayer potions", ItemCollections.PRAYER_POTIONS, -1); + repairKits = new ItemRequirement("Boat repair kits", ItemCollections.BOAT_REPAIR_KITS, 5); + + divingHelmet = new ItemRequirement("Deep sea helmet", ItemID.TRR_DIVING_HELMET); + divingHelmetEquipped = divingHelmet.equipped(); + divingHelmetEquipped.setHighlightInInventory(true); + divingApparatus = new ItemRequirement("Deep sea apparatus", ItemID.TRR_DIVING_BACKPACK); + divingApparatusEquipped = divingApparatus.equipped(); + divingApparatusEquipped.setHighlightInInventory(true); + + var rr1 = new Zone( + new WorldPoint(2805, 2500, 0), + new WorldPoint(2790, 2527, 0) + ); + var rr2 = new Zone( + new WorldPoint(2808, 2521, 0), + new WorldPoint(2806, 2522, 0) + ); + var rr3 = new Zone( + new WorldPoint(2806, 2510, 0), + new WorldPoint(2808, 2509, 0) + ); + var rr4 = new Zone( + new WorldPoint(2789, 2515, 0), + new WorldPoint(2785, 2529, 0) + ); + onRedRock = new ZoneRequirement(rr1, rr2, rr3, rr4); + + onLastLightF0 = new ZoneRequirement(lastLightF0); + onLastLightF1 = new ZoneRequirement(new Zone(11300, 1)); + onLastLightF2 = new ZoneRequirement(new Zone(11300, 2)); + + onZenith = new NpcRequirement(NpcID.TRR_SPENCER_BRENTWOOD_VIS); + + diving = new VarbitRequirement(VarbitID.PLAYER_DIVING, 1); + giantLobsterAround = new NpcRequirement(NpcID.TRR_GIANT_LOBSTER); + onBoat = new VarbitRequirement(VarbitID.SAILING_BOARDED_BOAT, 1); + freeInv2 = new FreeInventorySlotRequirement(2); + noFollower = new NoFollowerRequirement("No pet following you"); + } + + void setupSteps() + { + talkToRaleyToStartQuest = new NpcStep(this, NpcID.TT_RALEY_CONCH, new WorldPoint(3186, 2405, 0), "Talk to Elder Raley at his home in The Great Conch to start the quest."); + talkToRaleyToStartQuest.addDialogStep("Yes."); + + talkToFinn = new NpcStep(this, NpcID.TORTUGAN_FINN, new WorldPoint(3197, 2401, 0), "Talk to Finn, south-east of Elder Raley's house, about Floopa's whereabouts."); + + talkToElderKatt = new NpcStep(this, NpcID.TORTUGAN_GROVE_GUARDIAN, new WorldPoint(3196, 2466, 0), "Head to The Sacred Grove and talk to Elder Katt."); + + talkToFloopa = new NpcStep(this, NpcID.TRR_FLOOPA_VIS, new WorldPoint(3194, 2490, 0), "Enter The Sacred Grove and talk to Floopa."); + + sailToRedRock = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_DISEMBARK, new WorldPoint(2809, 2509, 0), "Sail to Red Rock, north-west of The Great Conch."); + + talkToRedRockReceptionist = new NpcStep(this, NpcID.TRR_RED_ROCK_RECEPTIONIST, new WorldPoint(2792, 2522, 0), "Talk to the receptionist on Red Rock."); + + var needToInspectCase1 = new VarbitRequirement(VarbitID.TRR_DISPLAY_CASE_1, 0); + var inspectCase1 = new ObjectStep(this, ObjectID.TRR_DISPLAY_CASE_1, new WorldPoint(2796, 2522, 0), ""); + + var needToInspectCase2 = new VarbitRequirement(VarbitID.TRR_DISPLAY_CASE_2, 0); + var inspectCase2 = new ObjectStep(this, ObjectID.TRR_DISPLAY_CASE_2, new WorldPoint(2794, 2524, 0), ""); + + var needToInspectCase3 = new VarbitRequirement(VarbitID.TRR_DISPLAY_CASE_3, 0); + var inspectCase3 = new ObjectStep(this, ObjectID.TRR_DISPLAY_CASE_3, new WorldPoint(2789, 2523, 0), ""); + + var inspectCase4 = new ObjectStep(this, ObjectID.TRR_DISPLAY_CASE_4, new WorldPoint(2789, 2519, 0), ""); + + cInspectCases = new ConditionalStep(this, inspectCase4, "Familiarize yourself with the history of the Red Reef Trading Company by inspecting the display cases around the building."); + cInspectCases.addStep(needToInspectCase1, inspectCase1); + cInspectCases.addStep(needToInspectCase2, inspectCase2); + cInspectCases.addStep(needToInspectCase3, inspectCase3); + + talkToTheodorePaxton = new NpcStep(this, NpcID.TRR_THEODORE_PAXTON, new WorldPoint(2795, 2517, 0), "Talk to Theodore Paxton."); + + // TODO: add all pirate npc ids + sinkBlackEyeBethelBoats = new NpcStep(this, new int[]{NpcID.TRR_PIRATE_1, NpcID.TRR_PIRATE_2, NpcID.TRR_PIRATE_3, NpcID.TRR_PIRATE_4}, new WorldPoint(2834, 2357, 0), + "Get ready for boat combat, then sail south towards Last Light and deal with Black Eye Bethel. Protect from Missiles to avoid most damage. Repair your ship. " + + "Combat is over when all boats are sunk or all pirates are killed.", rangedCombatGearOrShipWithCannons, combatGearBethel); + sinkBlackEyeBethelBoats.setRecommended(List.of(food, prayerPotions, repairKits)); + + disembarkAtLastLight = new ObjectStep(this, ObjectID.SAILING_MOORING_DISEMBARK, new WorldPoint(2849, 2327, 0), "Disembark at Last Light."); + + killPiratesAtLastLight = new NpcStep(this, new int[]{NpcID.TRR_PIRATE_1, NpcID.TRR_PIRATE_2, NpcID.TRR_PIRATE_3, NpcID.TRR_PIRATE_4}, new WorldPoint(2855, 2325, 0), "Kill all six pirates at Last Light.", true); + + var blackEyeBethelText = "Kill Black Eye Bethel. Use Protect from Melee to avoid some damage. Avoid her charge attack. Re-enable your prayers if she disables them."; + climbUpToF1 = new ObjectStep(this, ObjectID.LAST_LIGHT_SPIRALSTAIRS_BASE, new WorldPoint(2863, 2326, 0), blackEyeBethelText, combatGearBethel); + climbUpToF2 = new ObjectStep(this, ObjectID.LAST_LIGHT_SPIRALSTAIRS_MIDDLE, new WorldPoint(2863, 2326, 1), blackEyeBethelText, combatGearBethel); + climbUpToF2.addDialogStep("Climb up."); + killBlackEyeBethel = new NpcStep(this, NpcID.TRR_PIRATE_CAPTAIN, new WorldPoint(2862, 2323, 2), blackEyeBethelText, combatGearBethel); + killBlackEyeBethel.addSubSteps(climbUpToF1, climbUpToF2); + + sailToRedRock2 = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_DISEMBARK, new WorldPoint(2809, 2509, 0), "Sail to Red Rock, north of Last Light."); + climbDownToF1 = new ObjectStep(this, ObjectID.LAST_LIGHT_SPIRALSTAIRS_TOP, new WorldPoint(2863, 2326, 2), "Climb down the tower."); + climbDownToF0 = new ObjectStep(this, ObjectID.LAST_LIGHT_SPIRALSTAIRS_MIDDLE, new WorldPoint(2862, 2326, 1), "Climb down the tower."); + climbDownToF0.addDialogStep("Climb down."); + boardYourShip = new ObjectStep(this, ObjectID.SAILING_MOORING_EMBARK, new WorldPoint(2849, 2327, 0), "Board your boat."); + talkToTheodorePaxtonAgain = new NpcStep(this, NpcID.TRR_THEODORE_PAXTON, new WorldPoint(2795, 2517, 0), "Talk to Theodore Paxton."); + cReturnToTheodorePaxton = new ConditionalStep(this, sailToRedRock2, "Return to Theodore Paxton on Red Rock with the good news."); + cReturnToTheodorePaxton.addStep(onRedRock, talkToTheodorePaxtonAgain); + cReturnToTheodorePaxton.addStep(onLastLightF2, climbDownToF1); + cReturnToTheodorePaxton.addStep(onLastLightF1, climbDownToF0); + cReturnToTheodorePaxton.addStep(onLastLightF0, boardYourShip); + + sailToZenith = new WorldEntityStep(this, 9, new WorldPoint(2874, 2506, 0), + "Sail to and board the Zenith, east of Red Rock. If you don't see the Zenith there, try hopping to a different world.", combatGearLobster); + talkToSpencerBrentwood = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_VIS, new WorldPoint(2878, 2505, 0), "Talk to Spencer Brentwood aboard the Zenith.", combatGearLobster); + equipDivingGearAndDive = new DetailedQuestStep(this, "Equip the deep sea diving gear and dive down to the bottom of the sea.", combatGearLobster, divingHelmetEquipped, divingApparatusEquipped); + dive = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_VIS, "Talk to Spencer Brentwood again with the deep sea diving gear equipped to dive down to the bottom of the sea.", combatGearLobster, divingHelmetEquipped, divingApparatusEquipped, noFollower); + dive.addDialogStep("Let's go."); + dive.addSubSteps(equipDivingGearAndDive); + listenToSpencer = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_DIVING_A, new WorldPoint(2836, 8922, 1), "Listen to Spencer Brentwood's instructions."); + + repairCoralDredger = new ObjectStep(this, ObjectID.TRR_CORAL_DREDGER_BROKEN_OP, new WorldPoint(2844, 8942, 1), "Head north and repair the Coral dredger, ready to fight a Giant lobster.", combatGearLobster); + fightTheGiantLobster = new NpcStep(this, NpcID.TRR_GIANT_LOBSTER, "Kill the Giant lobster. Avoid the blue particles on the floor."); + + repairCoralDredger2 = new ObjectStep(this, ObjectID.TRR_CORAL_DREDGER_BROKEN_OP, new WorldPoint(2844, 8942, 1), "Repair the Coral dredger."); + + talkToSpencerNearEastCoralDredger = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_DIVING_VIS, new WorldPoint(2857, 8915, 1), "Talk to Spencer Brentwood near the eastern coral dredger."); + + talkToSpencerAboutFuturePlans = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_VIS, new WorldPoint(2878, 2505, 0), "Talk to Spencer Brentwood aboard the Zenith after repairing the coral dredgers."); + + var talkToSpencerBrentwoodAgain = new NpcStep(this, NpcID.TRR_SPENCER_BRENTWOOD_VIS, new WorldPoint(2878, 2505, 0), "Return to Spencer Brentwood to disembark onto your boat."); + talkToSpencerBrentwoodAgain.addDialogStep("Actually, I'd like to disembark."); + + var sailToGreatConch = new ObjectStep(this, ObjectID.SAILING_GANGPLANK_DISEMBARK, new WorldPoint(3174, 2367, 0), "Sail to The Great Conch."); + var talkToFloopaAtElderRaleysHouse = new NpcStep(this, NpcID.TT_FLOOPA_VIS, new WorldPoint(3185, 2405, 0), ""); + + cReturnToFloopa = new ConditionalStep(this, talkToFloopaAtElderRaleysHouse, "Return to Floopa at Elder Raley's house at The Great Conch."); + cReturnToFloopa.addStep(onZenith, talkToSpencerBrentwoodAgain); + cReturnToFloopa.addStep(onBoat, sailToGreatConch); + } + + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToRaleyToStartQuest); + steps.put(2, talkToRaleyToStartQuest); + + steps.put(4, talkToFinn); + + steps.put(6, talkToElderKatt); + + steps.put(8, talkToFloopa); + + steps.put(10, sailToRedRock); + + var cTalkToReceptionist = new ConditionalStep(this, sailToRedRock); + cTalkToReceptionist.addStep(onRedRock, talkToRedRockReceptionist); + steps.put(12, cTalkToReceptionist); + + var cInspectCases = new ConditionalStep(this, sailToRedRock); + cInspectCases.addStep(onRedRock, this.cInspectCases); + steps.put(14, cInspectCases); + + var cTalkToMrPaxton = new ConditionalStep(this, sailToRedRock); + cTalkToMrPaxton.addStep(onRedRock, talkToTheodorePaxton); + steps.put(16, cTalkToMrPaxton); + + steps.put(18, sinkBlackEyeBethelBoats); + + steps.put(20, disembarkAtLastLight); + + var cKillPiratesAtLastLight = new ConditionalStep(this, disembarkAtLastLight); + cKillPiratesAtLastLight.addStep(onLastLightF0, killPiratesAtLastLight); + steps.put(22, cKillPiratesAtLastLight); + + var cKillBlackEyeBethel = new ConditionalStep(this, disembarkAtLastLight); + cKillBlackEyeBethel.addStep(onLastLightF0, climbUpToF1); + cKillBlackEyeBethel.addStep(onLastLightF1, climbUpToF2); + cKillBlackEyeBethel.addStep(onLastLightF2, killBlackEyeBethel); + steps.put(24, cKillBlackEyeBethel); + + steps.put(26, cReturnToTheodorePaxton); + + var cInitialDive = new ConditionalStep(this, sailToZenith); + cInitialDive.addStep(diving, listenToSpencer); + cInitialDive.addStep(and(onZenith, divingApparatusEquipped, divingHelmetEquipped), dive); + cInitialDive.addStep(and(onZenith, divingApparatus, divingHelmet), equipDivingGearAndDive); + cInitialDive.addStep(onZenith, talkToSpencerBrentwood); + steps.put(28, cInitialDive); + steps.put(30, cInitialDive); + + var cFightLobster = new ConditionalStep(this, sailToZenith); + cFightLobster.addStep(and(diving, giantLobsterAround), fightTheGiantLobster); + cFightLobster.addStep(diving, repairCoralDredger); + cFightLobster.addStep(and(onZenith, divingApparatusEquipped, divingHelmetEquipped), dive); + cFightLobster.addStep(and(onZenith, divingApparatus, divingHelmet), equipDivingGearAndDive); + cFightLobster.addStep(onZenith, talkToSpencerBrentwood); + + steps.put(32, cFightLobster); + + var cRepairNorthernCoralDredger = new ConditionalStep(this, sailToZenith); + cRepairNorthernCoralDredger.addStep(diving, repairCoralDredger2); + cRepairNorthernCoralDredger.addStep(and(onZenith, divingApparatusEquipped, divingHelmetEquipped), dive); + cRepairNorthernCoralDredger.addStep(and(onZenith, divingApparatus, divingHelmet), equipDivingGearAndDive); + cRepairNorthernCoralDredger.addStep(onZenith, talkToSpencerBrentwood); + steps.put(34, cRepairNorthernCoralDredger); + + var cRepairEasternCoralDredgerWithSpencer = new ConditionalStep(this, sailToZenith); + cRepairEasternCoralDredgerWithSpencer.addStep(diving, talkToSpencerNearEastCoralDredger); + cRepairEasternCoralDredgerWithSpencer.addStep(and(onZenith, divingApparatusEquipped, divingHelmetEquipped), dive); + cRepairEasternCoralDredgerWithSpencer.addStep(and(onZenith, divingApparatus, divingHelmet), equipDivingGearAndDive); + cRepairEasternCoralDredgerWithSpencer.addStep(onZenith, talkToSpencerBrentwood); + + steps.put(36, cRepairEasternCoralDredgerWithSpencer); + + var cTalkToSpencerAboutFuturePlans = new ConditionalStep(this, sailToZenith); + cTalkToSpencerAboutFuturePlans.addStep(onZenith, talkToSpencerAboutFuturePlans); + + steps.put(38, cTalkToSpencerAboutFuturePlans); + + steps.put(40, cReturnToFloopa); + + return steps; + } + + @Override + public List getGeneralRequirements() + { + return List.of( + new QuestRequirement(QuestHelperQuest.TROUBLED_TORTUGANS, QuestState.FINISHED), + new SkillRequirement(Skill.SAILING, 52, false), + new SkillRequirement(Skill.SMITHING, 48, false) + ); + } + + @Override + public List getGeneralRecommended() + { + return List.of( + new SkillRequirement(Skill.PRAYER, 40, false, "43 prayer for Protect from Missiles & Melee"), + new CombatLevelRequirement(65) + ); + } + + @Override + public List getItemRequirements() + { + return List.of( + rangedCombatGearOrShipWithCannons, + combatGear + ); + } + + @Override + public List getItemRecommended() + { + return List.of( + food, + prayerPotions, + repairKits + ); + } + + @Override + public List getCombatRequirements() + { + return List.of( + "2 pirate ships, or the crew on the ship with ranged combat gear", + "6 pirates (lvl 52)", + "Black Eye Bethel (lvl 191)", + "Giant lobster (lvl 112)" + ); + } + + @Override + public QuestPointReward getQuestPointReward() + { + return new QuestPointReward(2); + } + + @Override + public List getExperienceRewards() + { + return List.of( + new ExperienceReward(Skill.SAILING, 15000), + new ExperienceReward(Skill.SMITHING, 5000) + ); + } + + @Override + public List getItemRewards() + { + return List.of( + new ItemReward("Bosun's Workbench Schematic", /*ItemID.LOST_SCHEMATIC_BOSUNS_WORKBENCH*/ -1) // NOTE: The gameval for this item is not in the latest RuneLite release + ); + } + + @Override + public List getUnlockRewards() + { + return List.of( + new UnlockReward("Access to the Great Conch sacred grove") + ); + } + + @Override + public List getPanels() + { + var sections = new ArrayList(); + + sections.add(new PanelDetails("Finding Floopa", List.of( + talkToRaleyToStartQuest, + talkToFinn, + talkToElderKatt, + talkToFloopa + ))); + + sections.add(new PanelDetails("Infiltrating the Red Reef", List.of( + sailToRedRock, + talkToRedRockReceptionist, + cInspectCases, + talkToTheodorePaxton + ))); + + sections.add(new PanelDetails("Dealing with Black Eye Bethel", List.of( + sinkBlackEyeBethelBoats, + disembarkAtLastLight, + killPiratesAtLastLight, + killBlackEyeBethel, + cReturnToTheodorePaxton + ), List.of( + rangedCombatGearOrShipWithCannons, + combatGearBethel + ), List.of( + food, + prayerPotions, + repairKits + ))); + + sections.add(new PanelDetails("Helping the Zenith", List.of( + sailToZenith, + talkToSpencerBrentwood, + dive, + listenToSpencer, + repairCoralDredger, + fightTheGiantLobster, + repairCoralDredger2, + talkToSpencerNearEastCoralDredger, + talkToSpencerAboutFuturePlans + ), List.of( + combatGearLobster, + freeInv2 + ), List.of( + food + ))); + + sections.add(new PanelDetails("Return to Floopa", List.of( + cReturnToFloopa + ))); + + return sections; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/therestlessghost/TheRestlessGhost.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/therestlessghost/TheRestlessGhost.java index aa5fa847ba..534620bed0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/therestlessghost/TheRestlessGhost.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/therestlessghost/TheRestlessGhost.java @@ -30,6 +30,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ObjectCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -40,6 +41,10 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -47,13 +52,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class TheRestlessGhost extends BasicQuestHelper { // Recommended items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theslugmenace/PuzzleStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theslugmenace/PuzzleStep.java index 02a15095ca..f692f5bf4e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theslugmenace/PuzzleStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/theslugmenace/PuzzleStep.java @@ -5,8 +5,8 @@ import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.events.VarbitChanged; import net.runelite.api.gameval.InterfaceID; -import net.runelite.api.gameval.VarPlayerID; import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thetouristtrap/TheTouristTrap.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thetouristtrap/TheTouristTrap.java index ee1bfac569..64b0ec34b7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thetouristtrap/TheTouristTrap.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/thetouristtrap/TheTouristTrap.java @@ -191,7 +191,7 @@ protected void setupRequirements() bronzeBar3 = new ItemRequirement("Bronze bars", ItemID.BRONZE_BAR, 3); hammer = new ItemRequirement("Hammer", ItemCollections.HAMMER).isNotConsumed(); - metalKey = new KeyringRequirement("Metal key", configManager, KeyringCollection.METAL_KEY); + metalKey = new KeyringRequirement("Metal key", KeyringCollection.METAL_KEY); metalKey.setTooltip("You can get another by killing the Mercenary Guard outside the Desert Mining Camp"); slaveTop = new ItemRequirement("Slave shirt", ItemID.SLAVE_SHIRT); slaveTop.setTooltip("You can trade in a desert robe set for slave clothes with the Male Slave"); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/throneofmiscellania/ThroneOfMiscellania.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/throneofmiscellania/ThroneOfMiscellania.java index 100a526c8f..25371badb2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/throneofmiscellania/ThroneOfMiscellania.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/throneofmiscellania/ThroneOfMiscellania.java @@ -45,7 +45,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; @@ -476,15 +480,6 @@ public List getItemRequirements() return reqs; } - @Override - public List getNotes() - { - ArrayList reqs = new ArrayList<>(); - reqs.add("Currently this helper only shows you how to marry Astrid. If you'd like to be friends with her or choose to be with Brand, " + - "you can either follow an external guide for now, or simply talk to King Vargas after the quest to change."); - return reqs; - } - @Override public List getItemRecommended() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/toweroflife/PuzzleSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/toweroflife/PuzzleSolver.java index 0a50496100..98e697d07b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/toweroflife/PuzzleSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/toweroflife/PuzzleSolver.java @@ -246,7 +246,6 @@ private class PipeSolverSolution { private final WidgetDetails pieceInfo; - private final Widget piece; private final int correctOrientation, selectedVBit, targetX, targetY; public PipeSolverSolution(WidgetDetails piece, int targetX, int targetY, int correctOrientation, int selectedVBit) @@ -257,15 +256,20 @@ public PipeSolverSolution(WidgetDetails piece, int targetX, int targetY, int cor public PipeSolverSolution(WidgetDetails pieceDetails, int targetX, int targetY, int correctOrientation, int selectedVBit, Function getPieceX, Function getPieceY) { this.pieceInfo = pieceDetails; - this.piece = PuzzleSolver.this.getWidget(pieceInfo); - if (this.piece == null) - throw new WidgetNotFoundException(); this.targetX = targetX; this.targetY = targetY; this.correctOrientation = correctOrientation; this.selectedVBit = selectedVBit; } + private Widget getPiece() + { + Widget widget = PuzzleSolver.this.getWidget(pieceInfo); + if (widget == null) + throw new WidgetNotFoundException(); + return widget; + } + public boolean isSolved() { return !isSelected(); @@ -278,27 +282,27 @@ public boolean isSelected() public boolean isLeft() { - return piece.getOriginalX() < targetX - 4; + return getPiece().getOriginalX() < targetX - 4; } public boolean isRight() { - return piece.getOriginalX() > targetX + 4; + return getPiece().getOriginalX() > targetX + 4; } public boolean isAbove() { - return piece.getOriginalY() < targetY - 4; + return getPiece().getOriginalY() < targetY - 4; } public boolean isBelow() { - return piece.getOriginalY() > targetY + 4; + return getPiece().getOriginalY() > targetY + 4; } public boolean isOriented() { - return piece.getModelId() == correctOrientation; + return getPiece().getModelId() == correctOrientation; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/treegnomevillage/TreeGnomeVillage.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/treegnomevillage/TreeGnomeVillage.java index a195487284..9beea13352 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/treegnomevillage/TreeGnomeVillage.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/treegnomevillage/TreeGnomeVillage.java @@ -33,6 +33,7 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.NpcHintArrowRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; @@ -42,7 +43,16 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -50,13 +60,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class TreeGnomeVillage extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/PuzzleStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/PuzzleStep.java index cf26b3e11f..d40f4b6171 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/PuzzleStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/PuzzleStep.java @@ -30,6 +30,7 @@ import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.events.GameTick; import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.VarbitID; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.ui.FontManager; @@ -40,26 +41,21 @@ public class PuzzleStep extends QuestStep { - private final Character ENTRY_ONE = 'K'; - private final Character ENTRY_TWO = 'U'; - private final Character ENTRY_THREE = 'R'; - private final Character ENTRY_FOUR = 'T'; - - private final int SLOT_ONE = 42; - private final int SLOT_TWO = 43; - private final int SLOT_THREE = 44; - private final int SLOT_FOUR = 45; - - private final int ARROW_ONE_LEFT = 46; - private final int ARROW_ONE_RIGHT = 47; - private final int ARROW_TWO_LEFT = 48; - private final int ARROW_TWO_RIGHT = 49; - private final int ARROW_THREE_LEFT = 50; - private final int ARROW_THREE_RIGHT = 51; - private final int ARROW_FOUR_LEFT = 52; - private final int ARROW_FOUR_RIGHT = 53; - - private final int COMPLETE = 55; + private final int ENTRY_ONE = 11; // K + private final int ENTRY_TWO = 21; // U + private final int ENTRY_THREE = 18; // R + private final int ENTRY_FOUR = 20; // T + + private final int ARROW_ONE_LEFT = InterfaceID.TribalDoor.TRIBALA_LEFT; + private final int ARROW_ONE_RIGHT = InterfaceID.TribalDoor.TRIBALA_RIGHT; + private final int ARROW_TWO_LEFT = InterfaceID.TribalDoor.TRIBALB_LEFT; + private final int ARROW_TWO_RIGHT = InterfaceID.TribalDoor.TRIBALB_RIGHT; + private final int ARROW_THREE_LEFT = InterfaceID.TribalDoor.TRIBALC_LEFT; + private final int ARROW_THREE_RIGHT = InterfaceID.TribalDoor.TRIBALC_RIGHT; + private final int ARROW_FOUR_LEFT = InterfaceID.TribalDoor.TRIBALD_LEFT; + private final int ARROW_FOUR_RIGHT = InterfaceID.TribalDoor.TRIBALD_RIGHT; + + private final int COMPLETE = InterfaceID.TribalDoor.TRIBALENTER; private final HashMap highlightButtons = new HashMap<>(); private final HashMap distance = new HashMap<>(); @@ -86,15 +82,15 @@ public void onGameTick(GameTick gameTick) private void updateSolvedPositionState() { - highlightButtons.replace(1, matchStateToSolution(SLOT_ONE, ENTRY_ONE, ARROW_ONE_RIGHT, ARROW_ONE_LEFT)); - highlightButtons.replace(2, matchStateToSolution(SLOT_TWO, ENTRY_TWO, ARROW_TWO_RIGHT, ARROW_TWO_LEFT)); - highlightButtons.replace(3, matchStateToSolution(SLOT_THREE, ENTRY_THREE, ARROW_THREE_RIGHT, ARROW_THREE_LEFT)); - highlightButtons.replace(4, matchStateToSolution(SLOT_FOUR, ENTRY_FOUR, ARROW_FOUR_RIGHT, ARROW_FOUR_LEFT)); + highlightButtons.replace(1, matchStateToSolution(VarbitID.TOTEMQUEST_COMBODOOR_CODE1, ENTRY_ONE, ARROW_ONE_RIGHT, ARROW_ONE_LEFT)); + highlightButtons.replace(2, matchStateToSolution(VarbitID.TOTEMQUEST_COMBODOOR_CODE2, ENTRY_TWO, ARROW_TWO_RIGHT, ARROW_TWO_LEFT)); + highlightButtons.replace(3, matchStateToSolution(VarbitID.TOTEMQUEST_COMBODOOR_CODE3, ENTRY_THREE, ARROW_THREE_RIGHT, ARROW_THREE_LEFT)); + highlightButtons.replace(4, matchStateToSolution(VarbitID.TOTEMQUEST_COMBODOOR_CODE4, ENTRY_FOUR, ARROW_FOUR_RIGHT, ARROW_FOUR_LEFT)); - distance.replace(1, matchStateToDistance(SLOT_ONE, ENTRY_ONE)); - distance.replace(2, matchStateToDistance(SLOT_TWO, ENTRY_TWO)); - distance.replace(3, matchStateToDistance(SLOT_THREE, ENTRY_THREE)); - distance.replace(4, matchStateToDistance(SLOT_FOUR, ENTRY_FOUR)); + distance.replace(1, matchStateToDistance(VarbitID.TOTEMQUEST_COMBODOOR_CODE1, ENTRY_ONE)); + distance.replace(2, matchStateToDistance(VarbitID.TOTEMQUEST_COMBODOOR_CODE2, ENTRY_TWO)); + distance.replace(3, matchStateToDistance(VarbitID.TOTEMQUEST_COMBODOOR_CODE3, ENTRY_THREE)); + distance.replace(4, matchStateToDistance(VarbitID.TOTEMQUEST_COMBODOOR_CODE4, ENTRY_FOUR)); if (highlightButtons.get(1) + highlightButtons.get(2) + highlightButtons.get(3) + highlightButtons.get(4) == 0) @@ -107,22 +103,17 @@ private void updateSolvedPositionState() } } - private int matchStateToSolution(int slot, Character target, int arrowRightId, int arrowLeftId) + private int matchStateToSolution(int varbitID, int target, int arrowRightId, int arrowLeftId) { - Widget widget = client.getWidget(InterfaceID.TRIBAL_DOOR, slot); - if (widget == null) return 0; - char current = widget.getText().charAt(0); - int currentPos = (int) current - (int) 'A'; - int id = Math.floorMod(currentPos - target, 26) < Math.floorMod(target - currentPos, 26) ? arrowRightId : arrowLeftId; - if (current != target) return id; + int currentPos = client.getVarbitValue(varbitID); + int id = Math.floorMod(currentPos - target, 26) < Math.floorMod(target - currentPos, 26) ? arrowLeftId : arrowRightId; + if (currentPos != target) return id; return 0; } - private int matchStateToDistance(int slot, Character target) + private int matchStateToDistance(int varbitID, int target) { - Widget widget = client.getWidget(InterfaceID.TRIBAL_DOOR, slot); - if (widget == null) return 0; - char current = widget.getText().charAt(0); + int current = client.getVarbitValue(varbitID); return Math.min(Math.floorMod(current - target, 26), Math.floorMod(target - current, 26)); } @@ -137,7 +128,7 @@ public void makeWidgetOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) continue; } - Widget widget = client.getWidget(InterfaceID.TRIBAL_DOOR, entry.getValue()); + Widget widget = client.getWidget(entry.getValue()); if (widget != null) { graphics.setColor(new Color(questHelper.getConfig().targetOverlayColor().getRed(), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/TribalTotem.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/TribalTotem.java index c0d3ea0310..187a5a8396 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/TribalTotem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/tribaltotem/TribalTotem.java @@ -43,6 +43,7 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; @@ -127,7 +128,7 @@ public void setupConditions() { inEntrance = new ZoneRequirement(houseGroundFloorEntrance); inMiddleRoom = new ZoneRequirement(houseGroundFloorMiddleRoom); - openedLockWidget = new WidgetTextRequirement(369, 54,"Combination Lock Door"); + openedLockWidget = new WidgetTextRequirement(InterfaceID.TribalDoor.TITLE_TEXT, "Combination Lock Door"); inStairway = new ZoneRequirement(houseGroundFloor); investigatedStairs = new WidgetTextRequirement(229, 1, "Your trained senses as a thief enable you to see that there is a trap
in these stairs. You make a note of its location for future reference
when using these stairs."); isUpstairs = new ZoneRequirement(houseFirstFloor); @@ -137,7 +138,7 @@ public void setupConditions() public void setupSteps() { talkToKangaiMau = new NpcStep(this, NpcID.KANGAI_MAU, new WorldPoint(2794, 3182, 0), "Talk to Kangai Mau in the Brimhaven food store."); - talkToKangaiMau.addDialogSteps("I'm in search of adventure!", "Ok, I will get it back."); + talkToKangaiMau.addDialogSteps("I'm in search of adventure!", "Ok, I will get it back.", "Yes."); investigateCrate = new ObjectStep(this, ObjectID.HORNCRATE, new WorldPoint(2650, 3273, 0), "Travel to the GPDT depot in Ardougne and investigate the most northeastern crate for a label."); useLabel = new ObjectStep(this, ObjectID.TELEPORTCRATE, new WorldPoint(2650, 3271, 0), "Use the label on the highlighted crate.", addressLabel); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/trollstronghold/TrollStronghold.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/trollstronghold/TrollStronghold.java index 234599667f..c1c125ca56 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/trollstronghold/TrollStronghold.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/trollstronghold/TrollStronghold.java @@ -49,7 +49,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/RepairTown.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/RepairTown.java index 6fa67c894e..91cb6ce6b8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/RepairTown.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/RepairTown.java @@ -33,6 +33,7 @@ import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.List; import net.runelite.api.ItemContainer; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameTick; @@ -42,8 +43,6 @@ import net.runelite.api.gameval.VarbitID; import net.runelite.client.eventbus.Subscribe; -import java.util.List; - public class RepairTown extends DetailedOwnerStep { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/TroubledTortugans.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/TroubledTortugans.java index c7f7035eaf..cbaf94cd40 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/TroubledTortugans.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/troubledtortugans/TroubledTortugans.java @@ -33,6 +33,9 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemOnTileRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.nor; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; @@ -40,7 +43,16 @@ import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -48,13 +60,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class TroubledTortugans extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/vampyreslayer/VampyreSlayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/vampyreslayer/VampyreSlayer.java index 186f7c2675..119ef3a54b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/vampyreslayer/VampyreSlayer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/vampyreslayer/VampyreSlayer.java @@ -29,62 +29,83 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; +import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; +import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.*; - public class VampyreSlayer extends BasicQuestHelper { - //Items Required - ItemRequirement hammer, beer, garlic, garlicObtainable, stake, combatGear; - - //Items Recommended - ItemRequirement varrockTeleport, draynorManorTeleport; - - Requirement inManor, inBasement, isUpstairsInMorgans, draynorNearby; - - QuestStep talkToMorgan, goUpstairsMorgan, getGarlic, ifNeedGarlic, talkToHarlow, talkToHarlowAgain, enterDraynorManor, goDownToBasement, openCoffin, killDraynor; + // Required items + ItemRequirement hammer; + ItemRequirement beer; + ItemRequirement twoCoins; + ItemRequirements beerOrTwoCoins; + ItemRequirement combatGear; - //Zones - Zone manor, basement, upstairsInMorgans; - - @Override - public Map loadSteps() - { - initializeRequirements(); - setupConditions(); - setupSteps(); - Map steps = new HashMap<>(); + // Recommended items + ItemRequirement varrockTeleport; + ItemRequirement draynorManorTeleport; + ItemRequirement garlic; + ItemRequirement garlicObtainable; - steps.put(0, talkToMorgan); + // Mid-quest item requirements + ItemRequirement stake; - ConditionalStep getGarlicAndStake = new ConditionalStep(this, goUpstairsMorgan); - getGarlicAndStake.addStep(garlic, talkToHarlow); - getGarlicAndStake.addStep(isUpstairsInMorgans, getGarlic); + // Zones + Zone manor; + Zone basement; + Zone upstairsInMorgans; - steps.put(1, getGarlicAndStake); + // Miscellaneous requirements + ZoneRequirement inManor; + ZoneRequirement inBasement; + ZoneRequirement isUpstairsInMorgans; + NpcCondition draynorNearby; + Conditions givenBeerToHarlow; - ConditionalStep prepareAndKillDraynor = new ConditionalStep(this, getGarlicAndStake); - prepareAndKillDraynor.addStep(draynorNearby, killDraynor); - prepareAndKillDraynor.addStep(inBasement, openCoffin); - prepareAndKillDraynor.addStep(inManor, goDownToBasement); - prepareAndKillDraynor.addStep(stake, enterDraynorManor); + // Steps + NpcStep talkToMorgan; - steps.put(2, prepareAndKillDraynor); + ObjectStep goUpstairsMorgan; + ObjectStep getGarlic; + ConditionalStep cGetGarlic; + NpcStep talkToHarlow; + NpcStep buyBeer; + NpcStep talkToHarlowAgain; + ObjectStep enterDraynorManor; + ObjectStep goDownToBasement; + ObjectStep openCoffin; + NpcStep killDraynor; - return steps; + @Override + protected void setupZones() + { + basement = new Zone(new WorldPoint(3074, 9767, 0), new WorldPoint(3081, 9779, 0)); + manor = new Zone(new WorldPoint(3097, 3354, 0), new WorldPoint(3119, 3373, 0)); + upstairsInMorgans = new Zone(new WorldPoint(3096, 3266, 1), new WorldPoint(3102, 3270, 1)); } @Override @@ -96,77 +117,109 @@ protected void setupRequirements() stake.setTooltip("You can get another from Dr. Harlow in the Blue Moon Inn in Varrock."); hammer = new ItemRequirement("Hammer", ItemCollections.HAMMER).isNotConsumed(); garlic = new ItemRequirement("Garlic", ItemID.GARLIC); - garlic.setTooltip("Optional, makes Count Draynor weaker"); - beer = new ItemRequirement("A beer, or 2 coins to buy one", ItemID.BEER); + garlic.setTooltip("Weakens Count Draynor"); + beer = new ItemRequirement("Beer", ItemID.BEER); + twoCoins = new ItemRequirement("Coins", ItemID.COINS, 2); + beerOrTwoCoins = new ItemRequirements(LogicType.OR, "A beer, or 2 coins to buy one", beer, twoCoins); combatGear = new ItemRequirement("Combat gear + food to defeat Count Draynor", -1, -1).isNotConsumed(); combatGear.setDisplayItemId(BankSlotIcons.getCombatGear()); - garlicObtainable = new ItemRequirement("Garlic", ItemID.GARLIC); + garlicObtainable = garlic.copy(); garlicObtainable.canBeObtainedDuringQuest(); - } - public void setupConditions() - { inBasement = new ZoneRequirement(basement); inManor = new ZoneRequirement(manor); isUpstairsInMorgans = new ZoneRequirement(upstairsInMorgans); draynorNearby = new NpcCondition(NpcID.COUNT_DRAYNOR); - } - @Override - protected void setupZones() - { - basement = new Zone(new WorldPoint(3074, 9767, 0), new WorldPoint(3081, 9779, 0)); - manor = new Zone(new WorldPoint(3097, 3354, 0), new WorldPoint(3119, 3373, 0)); - upstairsInMorgans = new Zone(new WorldPoint(3096, 3266, 1), new WorldPoint(3102, 3270, 1)); + var givenBeerToHarlow1 = new DialogRequirement("You give a beer to Dr Harlow."); + givenBeerToHarlow1.setMustBeActive(true); + givenBeerToHarlow1.setAllowMesbox(true); + var givenBeerToHarlow2 = new DialogRequirement("Cheersh matey...", "So tell me how to kill vampyres then.", "Yesh, yesh vampyres, I was very good at killing em once", "Well, you're going to need a stake"); + givenBeerToHarlow2.setMustBeActive(true); + givenBeerToHarlow = or(givenBeerToHarlow1, givenBeerToHarlow2); } public void setupSteps() { talkToMorgan = new NpcStep(this, NpcID.MORGAN, new WorldPoint(3098, 3268, 0), "Talk to Morgan in the north of Draynor Village."); - talkToMorgan.addDialogStep("Ok, I'm up for an adventure."); - talkToMorgan.addDialogStep("Accept quest"); - goUpstairsMorgan = new ObjectStep(this, ObjectID.STAIRS, new WorldPoint(3100, 3267, 0), "Go upstairs in Morgan's house and search the cupboard for some garlic."); - getGarlic = new ObjectStep(this, ObjectID.GARLICCUPBOARDOPEN, new WorldPoint(3096, 3270, 1), "Search the cupboard upstairs in Morgan's house."); - ((ObjectStep) getGarlic).addAlternateObjects(ObjectID.GARLICCUPBOARDSHUT); - ifNeedGarlic = new DetailedQuestStep(this, "If you need garlic, you can get some from the cupboard upstairs in Morgan's house."); - ifNeedGarlic.addSubSteps(goUpstairsMorgan, getGarlic); - - talkToHarlow = new NpcStep(this, NpcID.DR_HARLOW, new WorldPoint(3222, 3399, 0), "Talk to Dr. Harlow in the Blue Moon Inn in Varrock.", beer); + talkToMorgan.addDialogStep("Yes."); + + goUpstairsMorgan = new ObjectStep(this, ObjectID.STAIRS, new WorldPoint(3100, 3267, 0), "Climb the stairs."); + getGarlic = new ObjectStep(this, ObjectID.GARLICCUPBOARDOPEN, new WorldPoint(3096, 3270, 1), "Search the cupboard."); + getGarlic.addAlternateObjects(ObjectID.GARLICCUPBOARDSHUT); + cGetGarlic = new ConditionalStep(this, goUpstairsMorgan, "Get garlic from the cupboard upstairs in Morgan's house.\n\nYou can tick off this section in the sidebar to skip the garlic acquisition."); + cGetGarlic.addStep(isUpstairsInMorgans, getGarlic); + + talkToHarlow = new NpcStep(this, NpcID.DR_HARLOW, new WorldPoint(3222, 3399, 0), "Talk to Dr. Harlow in the Blue Moon Inn in Varrock.", beerOrTwoCoins); talkToHarlow.addDialogStep("Morgan needs your help!"); - talkToHarlowAgain = new NpcStep(this, NpcID.DR_HARLOW, new WorldPoint(3222, 3399, 0), "Talk to Dr. Harlow again with a beer. You can buy one for 2gp in the Blue Moon Inn.", beer); - enterDraynorManor = new ObjectStep(this, ObjectID.HAUNTEDDOORL, new WorldPoint(3108, 3353, 0), "Prepare to fight Count Draynor (level 34), and enter Draynor Manor.", combatGear, stake, hammer, garlic); - goDownToBasement = new ObjectStep(this, ObjectID.CRYPTSTAIRSDOWN, new WorldPoint(3116, 3358, 0), "Enter Draynor Manor's basement.", combatGear, stake, hammer, garlic); - openCoffin = new ObjectStep(this, ObjectID.VAMPCOFFIN, new WorldPoint(3078, 9776, 0), "Open the coffin and kill Count Draynor.", combatGear, stake, hammer, garlic); - killDraynor = new NpcStep(this, NpcID.COUNT_DRAYNOR, new WorldPoint(3077, 9769, 0), "Kill Count Draynor.", combatGear, stake, hammer, garlic); + buyBeer = new NpcStep(this, NpcID.BLUEMOON_BARTENDER, "Buy a beer from the bartender in the Blue Moon Inn in Varrock.", twoCoins); + buyBeer.addDialogStep("A glass of your finest ale please."); + talkToHarlowAgain = new NpcStep(this, NpcID.DR_HARLOW, new WorldPoint(3222, 3399, 0), "Talk to Dr. Harlow again with a beer.", beer); + talkToHarlowAgain.addDialogStep("Yes. Here you go."); + + List countDraynorReqs = List.of(hammer, stake, combatGear); + List countDraynorRecommended = List.of(garlic); + enterDraynorManor = new ObjectStep(this, ObjectID.HAUNTEDDOORL, new WorldPoint(3108, 3353, 0), "Prepare to fight Count Draynor (level 34), and enter Draynor Manor.", countDraynorReqs, countDraynorRecommended); + goDownToBasement = new ObjectStep(this, ObjectID.CRYPTSTAIRSDOWN, new WorldPoint(3116, 3358, 0), "Enter Draynor Manor's basement.", countDraynorReqs, countDraynorRecommended); + openCoffin = new ObjectStep(this, ObjectID.VAMPCOFFIN, new WorldPoint(3078, 9776, 0), "Open the coffin and kill Count Draynor.", countDraynorReqs, countDraynorRecommended); + killDraynor = new NpcStep(this, NpcID.COUNT_DRAYNOR, new WorldPoint(3077, 9769, 0), "Kill Count Draynor.", countDraynorReqs, countDraynorRecommended); openCoffin.addSubSteps(killDraynor); } + @Override + public Map loadSteps() + { + initializeRequirements(); + setupSteps(); + + var steps = new HashMap(); + + steps.put(0, talkToMorgan); + + var getGarlicAndStake = new ConditionalStep(this, cGetGarlic); + getGarlicAndStake.addStep(garlic, talkToHarlow); + steps.put(1, getGarlicAndStake); + + var getStake = new ConditionalStep(this, talkToHarlowAgain); + getStake.addStep(givenBeerToHarlow, talkToHarlowAgain); + getStake.addStep(not(beer), buyBeer); + var prepareAndKillDraynor = new ConditionalStep(this, getStake); + prepareAndKillDraynor.addStep(draynorNearby, killDraynor); + prepareAndKillDraynor.addStep(inBasement, openCoffin); + prepareAndKillDraynor.addStep(inManor, goDownToBasement); + prepareAndKillDraynor.addStep(stake, enterDraynorManor); + + steps.put(2, prepareAndKillDraynor); + + return steps; + } + @Override public List getItemRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add(hammer); - reqs.add(beer); - reqs.add(combatGear); - return reqs; + return List.of( + hammer, + beerOrTwoCoins, + combatGear + ); } @Override public List getItemRecommended() { - ArrayList reqs = new ArrayList<>(); - reqs.add(varrockTeleport); - reqs.add(draynorManorTeleport); - reqs.add(garlicObtainable); - return reqs; + return List.of( + varrockTeleport, + draynorManorTeleport, + garlicObtainable + ); } @Override public List getCombatRequirements() { - ArrayList reqs = new ArrayList<>(); - reqs.add("Count Draynor (level 34)"); - return reqs; + return List.of( + "Count Draynor (level 34)" + ); } @Override @@ -178,17 +231,46 @@ public QuestPointReward getQuestPointReward() @Override public List getExperienceRewards() { - return Collections.singletonList(new ExperienceReward(Skill.ATTACK, 4825)); + return List.of( + new ExperienceReward(Skill.ATTACK, 4825) + ); } @Override public List getPanels() { - List allSteps = new ArrayList<>(); + var sections = new ArrayList(); + + sections.add(new PanelDetails("Starting off", List.of( + talkToMorgan + ))); + + var garlicSection = new PanelDetails("Get garlic", List.of( + cGetGarlic + )); + garlicSection.setLockingStep(cGetGarlic); + sections.add(garlicSection); + + sections.add(new PanelDetails("Get a stake", List.of( + talkToHarlow, + buyBeer, + talkToHarlowAgain + ), List.of( + beerOrTwoCoins + ))); + + sections.add(new PanelDetails("Kill Count Draynor", List.of( + enterDraynorManor, + goDownToBasement, + openCoffin + ), List.of( + hammer, + stake, + combatGear + ), List.of( + garlic + ))); - allSteps.add(new PanelDetails("Starting off", Arrays.asList(talkToMorgan, ifNeedGarlic))); - allSteps.add(new PanelDetails("Get a stake", Arrays.asList(talkToHarlow, talkToHarlowAgain), beer)); - allSteps.add(new PanelDetails("Kill Count Draynor", Arrays.asList(enterDraynorManor, goDownToBasement, openCoffin), hammer, stake, garlic, combatGear)); - return allSteps; + return sections; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/wanted/Wanted.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/wanted/Wanted.java index 6d70f71b89..c24aa9b27e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/wanted/Wanted.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/wanted/Wanted.java @@ -52,7 +52,11 @@ import net.runelite.api.QuestState; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.VarPlayerID; import java.util.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/watchtower/Watchtower.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/watchtower/Watchtower.java index 7e2e1bcda4..a815e6d73c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/watchtower/Watchtower.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/watchtower/Watchtower.java @@ -45,7 +45,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.*; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; +import net.runelite.api.gameval.VarbitID; import java.util.*; @@ -467,7 +471,7 @@ public void setupSteps() stealRockCake = new ObjectStep(this, ObjectID.ROCKCOUNTER_WITHCAKES, new WorldPoint(2514, 3036, 0), "Steal a rock cake from Gu'Tanoth's market."); - talkToGuardBattlement = new NpcStep(this, NpcID.OGRE_GUARD3, new WorldPoint(2503, 3012, 0), "Talk to an Ogre Guard next to the battelement."); + talkToGuardBattlement = new NpcStep(this, NpcID.OGRE_GUARD3, new WorldPoint(2503, 3012, 0), "Talk to an Ogre Guard next to the battlement."); talkToGuardBattlement.addDialogStep("But I am a friend to ogres..."); talkToGuardWithRockCake = new ObjectStep(this, NpcID.OGRE_GUARD3, new WorldPoint(2507, 3012, 0), "Attempt to cross the battlement again with a rock cake.", rockCake); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/waterfallquest/WaterfallQuest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/waterfallquest/WaterfallQuest.java index 53a9e9909e..dbc6f03668 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/waterfallquest/WaterfallQuest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/waterfallquest/WaterfallQuest.java @@ -29,13 +29,23 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarbitRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -43,10 +53,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; -import java.util.*; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; - public class WaterfallQuest extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whatliesbelow/WhatLiesBelow.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whatliesbelow/WhatLiesBelow.java index cd5151d3ea..755a965577 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whatliesbelow/WhatLiesBelow.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whatliesbelow/WhatLiesBelow.java @@ -185,6 +185,7 @@ public void setupSteps() talkToSurok = new NpcStep(this, NpcID.SUROK_SUROK, new WorldPoint(3211, 3493, 0), "Talk to Surok Magis in the Varrock Library.", letterToSurok); talkToSurokNoLetter = new NpcStep(this, NpcID.WGS_SUROK_TRANSITION, new WorldPoint(3211, 3493, 0), "Talk to Surok Magis in the Varrock Library."); + ((NpcStep) talkToSurokNoLetter).addAlternateNpcs(NpcID.SUROK_SUROK_TYPE1); talkToSurokNoLetter.addDialogSteps("Go on, then!", "Go on then!"); talkToSurok.addSubSteps(talkToSurokNoLetter); @@ -278,7 +279,7 @@ public List getPanels() List allSteps = new ArrayList<>(); allSteps.add(new PanelDetails("Starting off", Collections.singletonList(talkToRat))); allSteps.add(new PanelDetails("Help Rat", Arrays.asList(killOutlaws, bringFolderToRat))); - allSteps.add(new PanelDetails("Help Surok", Arrays.asList(talkToSurok, enterChaosAltar, useWandOnAltar, bringWandToSurok), chaosRunes15, chaosTalismanOrAbyss, bowl)); + allSteps.add(new PanelDetails("Help Surok", Arrays.asList(talkToSurok, enterChaosAltar, useWandOnAltar, bringWandToSurok), chaosRunes15, chaosTalismanOrAbyss, bowl, wand)); allSteps.add(new PanelDetails("Defeat Surok", Arrays.asList(talkToRatAfterSurok, talkToZaff, talkToSurokToFight, fightRoald, talkToRatToFinish))); return allSteps; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whileguthixsleeps/WhileGuthixSleeps.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whileguthixsleeps/WhileGuthixSleeps.java index 777c1b452d..f72bf89f64 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whileguthixsleeps/WhileGuthixSleeps.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/whileguthixsleeps/WhileGuthixSleeps.java @@ -984,7 +984,7 @@ protected void setupRequirements() placedEarthBlock = new VarbitRequirement(VarbitID.WGS_EARTH_KEY_USED, 1); notPlacedFireBlock = new VarbitRequirement(VarbitID.WGS_FIRE_KEY_USED, 0); - noWeaponOrShieldEquipped = new ComplexRequirement("No weapon or shield equipped", new NoItemRequirement("", ItemSlots.WEAPON), new NoItemRequirement("", ItemSlots.SHIELD)); + noWeaponOrShieldEquipped = new NoItemRequirement("Nothing equipped in your hands", ItemSlots.EMPTY_HANDS); airCavity = new Zone(new WorldPoint(4107, 5095, 0), new WorldPoint(4119, 5116, 0)); inAirCavity = new ZoneRequirement(airCavity); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchshouse/WitchsHouse.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchshouse/WitchsHouse.java index e88fb2908a..44fd46da66 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchshouse/WitchsHouse.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchshouse/WitchsHouse.java @@ -32,13 +32,25 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ObjectCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.FreeInventorySlotRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; import net.runelite.client.plugins.microbot.questhelper.requirements.var.VarplayerRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.rewards.ExperienceReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; -import net.runelite.client.plugins.microbot.questhelper.steps.*; +import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; +import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ItemStep; +import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; +import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; +import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; @@ -46,13 +58,6 @@ import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarPlayerID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.*; - public class WitchsHouse extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchspotion/WitchsPotion.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchspotion/WitchsPotion.java index e33a50f6de..6dff4d5a39 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchspotion/WitchsPotion.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/witchspotion/WitchsPotion.java @@ -33,17 +33,16 @@ import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.ObjectStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; import net.runelite.api.gameval.ObjectID; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class WitchsPotion extends BasicQuestHelper { // Required items diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/xmarksthespot/XMarksTheSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/xmarksthespot/XMarksTheSpot.java index cc33e64f75..5768cf0b31 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/xmarksthespot/XMarksTheSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/helpers/quests/xmarksthespot/XMarksTheSpot.java @@ -29,22 +29,20 @@ import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; import net.runelite.client.plugins.microbot.questhelper.rewards.ItemReward; import net.runelite.client.plugins.microbot.questhelper.rewards.QuestPointReward; import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; import net.runelite.client.plugins.microbot.questhelper.steps.DigStep; import net.runelite.client.plugins.microbot.questhelper.steps.NpcStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.not; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; public class XMarksTheSpot extends BasicQuestHelper { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/ItemAndLastUpdated.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/ItemAndLastUpdated.java index c1a357b171..d84dffe7cc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/ItemAndLastUpdated.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/ItemAndLastUpdated.java @@ -31,6 +31,9 @@ import net.runelite.api.Item; import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.Callable; @Slf4j @@ -52,12 +55,36 @@ public ItemAndLastUpdated(TrackedContainers containerType) this.containerType = containerType; } + /// Updates the full list of items in this container public void update(int updateTick, Item[] items) { this.lastUpdated = updateTick; this.items = items; } + /// Helper function to add a single item into the container. + /// + /// Prefer using the update method if possible. + public void add(int updateTick, int itemID, int itemQuantity) + { + this.lastUpdated = updateTick; + + var newItems = new ArrayList<>(List.of(this.items)); + newItems.add(new Item(itemID, itemQuantity)); + + this.items = newItems.toArray(new Item[0]); + } + + /// Helper function to remove items with a given item ID from the container. + /// + /// Prefer using the update method if possible. + public void removeByItemID(int updateTick, int itemID) + { + this.lastUpdated = updateTick; + + this.items = Arrays.stream(this.items).filter((item) -> item.getId() != itemID).toArray(Item[]::new); + } + /** * Get the Items contained within the Tracked Container. * If this instance of ItemAndLastUpdated has a method in specialMethodToObtainItems to obtain the current state of the Container other than diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/NewVersionManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/NewVersionManager.java index 7b42362739..625ea5f6a7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/NewVersionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/NewVersionManager.java @@ -44,7 +44,7 @@ public class NewVersionManager private final String LAST_VERSION_SEEN_CONFIG_KEY = "lastversionchecked"; - private final String UPDATE_CHAT_TEXT = "Quest Helper has been updated to 4.12.1! This improves the default order for Sea Charting, and adds a proximity mode you can toggle at the top of it!"; + private final String UPDATE_CHAT_TEXT = "Quest Helper has been updated to 4.15.1! You can now filter by leagues regions, and the League's Helper is improved."; public void updateChatWithNotificationIfNewVersion() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestContainerManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestContainerManager.java index 03a1bac8dc..9ad173886d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestContainerManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestContainerManager.java @@ -56,8 +56,11 @@ public class QuestContainerManager @Getter private final static ItemAndLastUpdated runePouchData = new ItemAndLastUpdated(TrackedContainers.RUNE_POUCH); + @Getter + private final static ItemAndLastUpdated keyRingData = new ItemAndLastUpdated(TrackedContainers.KEY_RING); + @Getter - private final static List orderedListOfContainers = List.of(equippedData, inventoryData, bankData, runePouchData, potionData, groupStorageData); + private final static List orderedListOfContainers = List.of(equippedData, inventoryData, bankData, runePouchData, potionData, groupStorageData, keyRingData); static Set RUNE_POUCHES = Set.of(ItemID.BH_RUNE_POUCH, ItemID.BH_RUNE_POUCH_TROUVER, ItemID.DIVINE_RUNE_POUCH, ItemID.DIVINE_RUNE_POUCH_TROUVER); private static final int NUM_SLOTS = 6; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestManager.java index 85864b9f0f..a94bbb3682 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestManager.java @@ -27,6 +27,7 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; +import net.runelite.client.plugins.microbot.questhelper.config.LeagueFiltering; import net.runelite.client.plugins.microbot.questhelper.config.SkillFiltering; import net.runelite.client.plugins.microbot.questhelper.panel.QuestHelperPanel; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestDetails; @@ -229,6 +230,7 @@ public void updateQuestList() .filter(config.difficulty()) .filter(QuestDetails::showCompletedQuests) .filter(SkillFiltering::passesSkillFilter) + .filter(LeagueFiltering::passesLeagueFilter) .sorted(config.orderListBy()) .collect(Collectors.toList()); Map completedQuests = QuestHelperQuest.getQuestHelpers(isDeveloperMode()) @@ -476,6 +478,7 @@ private void getAllItemRequirements() .stream() .filter(pred) .filter(QuestDetails::isNotCompleted) + .filter(LeagueFiltering::passesLeagueFilter) .sorted(config.orderListBy()) .collect(Collectors.toList()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestMenuHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestMenuHandler.java index d05de52e61..4a411b70fb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestMenuHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/managers/QuestMenuHandler.java @@ -33,7 +33,6 @@ import net.runelite.api.*; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.InterfaceID; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.util.Text; import javax.inject.Inject; @@ -131,7 +130,7 @@ private void handleShieldOfArrav() return; } - WorldPoint location = Rs2Player.getWorldLocation(); + WorldPoint location = player.getWorldLocation(); QuestHelperQuest questToStart = PHOENIX_START_ZONE.contains(location) ? QuestHelperQuest.SHIELD_OF_ARRAV_PHOENIX_GANG : QuestHelperQuest.SHIELD_OF_ARRAV_BLACK_ARM_GANG; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperMinimapOverlay.java index 6d16420abf..c4d05be991 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperMinimapOverlay.java @@ -26,6 +26,11 @@ public QuestHelperMinimapOverlay(QuestHelperPlugin plugin) @Override public Dimension render(Graphics2D graphics) { + if (plugin.isInCutscene()) + { + return null; + } + QuestHelper quest = plugin.getSelectedQuest(); if (quest != null && quest.getCurrentStep() != null && quest.getCurrentStep().getActiveStep() != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperOverlay.java index 9be7416147..c37ee6b597 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperOverlay.java @@ -31,6 +31,7 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPanel; +import net.runelite.client.ui.overlay.OverlayPriority; import javax.inject.Inject; import java.awt.*; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldArrowOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldArrowOverlay.java index 7960babaf2..1f3ee50951 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldArrowOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldArrowOverlay.java @@ -49,6 +49,11 @@ public QuestHelperWorldArrowOverlay(QuestHelperPlugin plugin) @Override public Dimension render(Graphics2D graphics) { + if (plugin.isInCutscene()) + { + return null; + } + QuestHelper quest = plugin.getSelectedQuest(); if (quest != null && quest.getCurrentStep() != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldLineOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldLineOverlay.java index feac0cba6f..51988c55b8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldLineOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldLineOverlay.java @@ -54,6 +54,11 @@ public Dimension render(Graphics2D graphics) return null; } + if (plugin.isInCutscene()) + { + return null; + } + QuestHelper quest = plugin.getSelectedQuest(); if (quest != null && quest.getCurrentStep() != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldOverlay.java index 002db5eb04..911c32400f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/overlays/QuestHelperWorldOverlay.java @@ -63,15 +63,24 @@ public Dimension render(Graphics2D graphics) QuestHelper quest = plugin.getSelectedQuest(); - if (quest != null && quest.getCurrentStep() != null) + if (quest != null) { - quest.makeWorldOverlayHint(graphics, plugin); - quest.getCurrentStep().makeWorldOverlayHint(graphics, plugin); + var currentStep = quest.getCurrentStep(); + if (currentStep != null) + { + if (!plugin.isInCutscene() || currentStep.getActiveStep().isAllowInCutscene()) + { + currentStep.makeWorldOverlayHint(graphics, plugin); + } + } } - plugin.getBackgroundHelpers().forEach((name, questHelper) -> questHelper.getCurrentStep().makeWorldOverlayHint(graphics, plugin)); + if (!plugin.isInCutscene()) + { + plugin.getBackgroundHelpers().forEach((name, questHelper) -> questHelper.getCurrentStep().makeWorldOverlayHint(graphics, plugin)); - plugin.getRuneliteObjectManager().makeWorldOverlayHint(graphics); + plugin.getRuneliteObjectManager().makeWorldOverlayHint(graphics); + } return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/JGenerator.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/JGenerator.java index f79c75fb30..53a0f7f66a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/JGenerator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/JGenerator.java @@ -72,7 +72,7 @@ public static JTextArea makeJTextArea() jTextArea.setOpaque(false); jTextArea.setEditable(false); jTextArea.setFocusable(false); - jTextArea.setBackground(UIManager.getColor("Label.background")); + jTextArea.setBackground(javax.swing.UIManager.getColor("Label.background")); jTextArea.setBorder(new EmptyBorder(0, 0, 0, 0)); return jTextArea; @@ -86,7 +86,7 @@ public static JTextArea makeJTextArea(String text) jTextArea.setOpaque(false); jTextArea.setEditable(false); jTextArea.setFocusable(false); - jTextArea.setBackground(UIManager.getColor("Label.background")); + jTextArea.setBackground(javax.swing.UIManager.getColor("Label.background")); jTextArea.setBorder(new EmptyBorder(0, 0, 0, 0)); return jTextArea; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/ManualStepSkipStore.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/ManualStepSkipStore.java new file mode 100644 index 0000000000..528815a9d8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/ManualStepSkipStore.java @@ -0,0 +1,112 @@ +package net.runelite.client.plugins.microbot.questhelper.panel; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import net.runelite.client.config.ConfigManager; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +/** + * Persists per-RuneScape-profile manual step skips under {@link QuestHelperConfig#QUEST_HELPER_GROUP}, + * one JSON map key per displayed helper name (same grouping as sidebar order). + */ +public final class ManualStepSkipStore +{ + private static final Type MAP_TYPE = new TypeToken>() + { + }.getType(); + + private ManualStepSkipStore() + { + } + + public static String configKeyForQuest(String displayedQuestName) + { + return QuestHelperConfig.QUEST_HELPER_MANUAL_SKIPS_KEY_PREFIX + slug(displayedQuestName); + } + + private static String slug(String name) + { + if (name == null) + { + return "helper"; + } + String s = name.trim().replaceAll("[^a-zA-Z0-9_-]+", "_"); + if (s.length() > 96) + { + s = s.substring(0, 96); + } + return s.isEmpty() ? "helper" : s; + } + + public static Map load(ConfigManager cm, Gson gson, String displayedQuestName) + { + if (cm == null || cm.getRSProfileKey() == null) + { + return new HashMap<>(); + } + String ck = configKeyForQuest(displayedQuestName); + String raw = cm.getRSProfileConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck); + if ((raw == null || raw.isBlank()) && cm.getRSProfileKey() != null) + { + String legacy = cm.getConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck); + if (legacy != null && !legacy.isBlank()) + { + cm.setRSProfileConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck, legacy); + cm.unsetConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck); + raw = legacy; + } + } + if (raw == null || raw.isBlank()) + { + return new HashMap<>(); + } + try + { + Map m = gson.fromJson(raw, MAP_TYPE); + return m != null ? new HashMap<>(m) : new HashMap<>(); + } + catch (RuntimeException e) + { + return new HashMap<>(); + } + } + + public static void put(ConfigManager cm, Gson gson, String displayedQuestName, String slotKey, boolean skipped) + { + if (cm == null || cm.getRSProfileKey() == null || slotKey == null || slotKey.isBlank()) + { + return; + } + String ck = configKeyForQuest(displayedQuestName); + Map map = load(cm, gson, displayedQuestName); + if (skipped) + { + map.put(slotKey, true); + } + else + { + map.remove(slotKey); + } + if (map.isEmpty()) + { + cm.unsetRSProfileConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck); + } + else + { + cm.setRSProfileConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, ck, gson.toJson(map)); + } + } + + public static void clearAll(ConfigManager cm, String displayedQuestName) + { + if (cm == null || cm.getRSProfileKey() == null) + { + return; + } + cm.unsetRSProfileConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, configKeyForQuest(displayedQuestName)); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/PanelDetails.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/PanelDetails.java index b1bfcc9590..5830295f1b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/PanelDetails.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/PanelDetails.java @@ -37,7 +37,7 @@ public class PanelDetails { @Getter - int id = -1; + int id = Integer.MIN_VALUE; @Getter String header; @@ -139,6 +139,11 @@ public void addSteps(QuestStep... steps) this.steps.addAll(Arrays.asList(steps)); } + public void addSteps(Collection steps) + { + this.steps.addAll(steps); + } + public boolean contains(QuestStep currentStep) { if (getSteps().contains(currentStep)) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestHelperPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestHelperPanel.java index 2c840fa1f7..a8893857ee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestHelperPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestHelperPanel.java @@ -27,6 +27,7 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.managers.QuestManager; +import net.runelite.client.plugins.microbot.questhelper.panel.regionfiltering.RegionFilterPanel; import net.runelite.client.plugins.microbot.questhelper.panel.skillfiltering.SkillFilterPanel; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestDetails; @@ -39,6 +40,9 @@ import net.runelite.api.GameState; import net.runelite.api.QuestState; import net.runelite.api.Skill; +import net.runelite.api.WorldType; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.config.ConfigManager; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.PluginPanel; @@ -54,12 +58,13 @@ import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicButtonUI; import java.awt.*; +import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.*; import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -74,17 +79,37 @@ public class QuestHelperPanel extends PluginPanel private final JPanel searchQuestsPanel; private final JPanel allDropdownSections = new JPanel(); + private final JPanel filterStackPanel = new JPanel(); private final JComboBox filterDropdown, difficultyDropdown, orderDropdown; private final JComboBox stateDropdown = new JComboBox<>(); private JPanel statePanel; private final JButton skillExpandButton = new JButton(); + private JPanel regionsFilterSection; + private RegionFilterPanel regionFilterPanel; private final IconTextField searchBar = new IconTextField(); private final FixedWidthPanel questListPanel = new FixedWidthPanel(); private final FixedWidthPanel questListWrapper = new FixedWidthPanel(); private final JScrollPane scrollableContainer; + private final CardLayout viewportLayout = new CardLayout(); + private final JPanel viewportContent = new JPanel(viewportLayout) + { + @Override + public Dimension getPreferredSize() + { + for (Component component : getComponents()) + { + if (component.isVisible()) + { + return component.getPreferredSize(); + } + } + return super.getPreferredSize(); + } + }; public static final int DROPDOWN_HEIGHT = 26; public boolean questActive = false; + private String activeView = VIEW_QUEST_LIST; private final ArrayList questSelectPanels = new ArrayList<>(); @@ -98,6 +123,9 @@ public class QuestHelperPanel extends PluginPanel private static final ImageIcon SETTINGS_ICON; private static final ImageIcon COLLAPSED_ICON; private static final ImageIcon EXPANDED_ICON; + private static final String VIEW_QUEST_LIST = "quest_list"; + private static final String VIEW_QUEST_OVERVIEW = "quest_overview"; + private static final String VIEW_SETTINGS = "settings"; private int nextDesiredScrollValue = 0; @@ -160,14 +188,14 @@ public QuestHelperPanel(QuestHelperPlugin questHelperPlugin, QuestManager questM onSearchBarChanged(); }); - settingsBtn.addMouseListener(new MouseAdapter() + settingsBtn.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(MouseEvent evt) + public void mouseEntered(java.awt.event.MouseEvent evt) { settingsBtn.setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); } - public void mouseExited(MouseEvent evt) + public void mouseExited(java.awt.event.MouseEvent evt) { if (settingsPanelActive()) { @@ -189,14 +217,14 @@ public void mouseExited(MouseEvent evt) discordBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); discordBtn.setUI(new BasicButtonUI()); discordBtn.addActionListener((ev) -> LinkBrowser.browse("https://discord.gg/XCfwNnz6RB")); - discordBtn.addMouseListener(new MouseAdapter() + discordBtn.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(MouseEvent evt) + public void mouseEntered(java.awt.event.MouseEvent evt) { discordBtn.setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); } - public void mouseExited(MouseEvent evt) + public void mouseExited(java.awt.event.MouseEvent evt) { discordBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); } @@ -211,14 +239,14 @@ public void mouseExited(MouseEvent evt) githubBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); githubBtn.setUI(new BasicButtonUI()); githubBtn.addActionListener((ev) -> LinkBrowser.browse("https://github.com/Zoinkwiz/quest-helper")); - githubBtn.addMouseListener(new MouseAdapter() + githubBtn.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(MouseEvent evt) + public void mouseEntered(java.awt.event.MouseEvent evt) { githubBtn.setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); } - public void mouseExited(MouseEvent evt) + public void mouseExited(java.awt.event.MouseEvent evt) { githubBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); } @@ -233,14 +261,14 @@ public void mouseExited(MouseEvent evt) patreonBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); patreonBtn.setUI(new BasicButtonUI()); patreonBtn.addActionListener((ev) -> LinkBrowser.browse("https://www.patreon.com/zoinkwiz")); - patreonBtn.addMouseListener(new MouseAdapter() + patreonBtn.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(MouseEvent evt) + public void mouseEntered(java.awt.event.MouseEvent evt) { patreonBtn.setBackground(ColorScheme.DARK_GRAY_HOVER_COLOR); } - public void mouseExited(MouseEvent evt) + public void mouseExited(java.awt.event.MouseEvent evt) { patreonBtn.setBackground(ColorScheme.DARK_GRAY_COLOR); } @@ -318,21 +346,21 @@ public void changedUpdate(DocumentEvent e) skillExpandButton.setHorizontalTextPosition(SwingConstants.LEFT); skillExpandButton.setIconTextGap(10); skillExpandButton.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) { - skillFilterPanel.setVisible(!skillFilterPanel.isVisible()); - if (skillFilterPanel.isVisible()) - { - skillExpandButton.setIcon(EXPANDED_ICON); - } - else + @Override + public void mousePressed(MouseEvent mouseEvent) { - skillExpandButton.setIcon(COLLAPSED_ICON); + skillFilterPanel.setVisible(!skillFilterPanel.isVisible()); + if (skillFilterPanel.isVisible()) + { + skillExpandButton.setIcon(EXPANDED_ICON); + } + else + { + skillExpandButton.setIcon(COLLAPSED_ICON); + } } - } - }); + }); JPanel skillExpandBar = new JPanel(); skillExpandBar.setLayout(new BorderLayout()); @@ -362,6 +390,53 @@ public void mousePressed(MouseEvent mouseEvent) } }); + // Region filtering + JButton regionExpandButton = new JButton(); + regionExpandButton.setForeground(Color.GRAY); + regionExpandButton.setIcon(COLLAPSED_ICON); + regionExpandButton.setHorizontalTextPosition(SwingConstants.LEFT); + regionExpandButton.setIconTextGap(10); + + regionFilterPanel = new RegionFilterPanel(questHelperPlugin.spriteManager, () -> { + questHelperPlugin.getClientThread().invokeLater(questManager::updateQuestList); + int count = regionFilterPanel.getSelectedCount(); + regionExpandButton.setText(count > 0 ? String.format("%d active", count) : ""); + }); + regionFilterPanel.setVisible(false); + + JLabel regionFilterName = JGenerator.makeJLabel("Region filtering"); + regionFilterName.setForeground(Color.WHITE); + questHelperPlugin.spriteManager.getSpriteAsync(2214, 0, sprite -> { + if (sprite != null) + { + SwingUtilities.invokeLater(() -> regionFilterName.setIcon(new ImageIcon(sprite))); + } + }); + + JPanel regionExpandBar = new JPanel(); + regionExpandBar.setLayout(new BorderLayout()); + regionExpandBar.setToolTipText("Choose league regions to filter quests by"); + regionExpandBar.add(regionFilterName, BorderLayout.CENTER); + regionExpandBar.add(regionExpandButton, BorderLayout.EAST); + + MouseAdapter regionExpandListener = new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + regionFilterPanel.setVisible(!regionFilterPanel.isVisible()); + regionExpandButton.setIcon(regionFilterPanel.isVisible() ? EXPANDED_ICON : COLLAPSED_ICON); + } + }; + regionExpandButton.addMouseListener(regionExpandListener); + regionExpandBar.addMouseListener(regionExpandListener); + + regionsFilterSection = new JPanel(); + regionsFilterSection.setLayout(new BorderLayout()); + regionsFilterSection.setMinimumSize(new Dimension(PANEL_WIDTH, 0)); + regionsFilterSection.add(regionExpandBar, BorderLayout.CENTER); + regionsFilterSection.add(regionFilterPanel, BorderLayout.SOUTH); + // Filter dropdown + search allDropdownSections.setLayout(new BoxLayout(allDropdownSections, BoxLayout.Y_AXIS)); allDropdownSections.setBorder(new EmptyBorder(0, 0, 10, 0)); @@ -369,14 +444,23 @@ public void mousePressed(MouseEvent mouseEvent) allDropdownSections.add(difficultyPanel); allDropdownSections.add(orderPanel); allDropdownSections.add(skillsFilterPanel); + allDropdownSections.add(regionsFilterSection); - searchQuestsPanel.add(allDropdownSections, BorderLayout.NORTH); + // Set initial visibility based on config and current world type + updateRegionFilterVisibility(questHelperPlugin.getClient().getWorldType().contains(WorldType.SEASONAL)); + + filterStackPanel.setLayout(new BoxLayout(filterStackPanel, BoxLayout.Y_AXIS)); + filterStackPanel.setOpaque(false); + filterStackPanel.add(Box.createVerticalStrut(8)); + filterStackPanel.add(allDropdownSections); + + searchQuestsPanel.add(filterStackPanel, BorderLayout.NORTH); // Wrapper questListWrapper.setLayout(new BorderLayout()); questListWrapper.add(questListPanel, BorderLayout.NORTH); - scrollableContainer = new JScrollPane(questListWrapper); + scrollableContainer = new JScrollPane(viewportContent); scrollableContainer.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); @@ -394,6 +478,9 @@ public void mousePressed(MouseEvent mouseEvent) questOverviewWrapper.setLayout(new BorderLayout()); questOverviewWrapper.add(questOverviewPanel, BorderLayout.NORTH); + viewportContent.add(questListWrapper, VIEW_QUEST_LIST); + viewportContent.add(questOverviewWrapper, VIEW_QUEST_OVERVIEW); + viewportContent.add(assistLevelPanel, VIEW_SETTINGS); if (questHelperPlugin.isDeveloperMode()) { @@ -404,8 +491,56 @@ public void mousePressed(MouseEvent mouseEvent) var devModePanel = new JPanel(); devModePanel.setLayout(new BorderLayout()); + var togglePuzzleHelper = new JMenuItem(new AbstractAction("toggle puzzle helper") + { + @Override + public void actionPerformed(ActionEvent actionEvent) + { + var v = questHelperPlugin.getConfig().solvePuzzles(); + configManager.setConfiguration(QuestHelperConfig.QUEST_HELPER_GROUP, "solvePuzzles", !v); + } + }); + + var toggleCutsceneStatus = new JMenuItem(new AbstractAction("toggle cutscene status") + { + @Override + public void actionPerformed(ActionEvent actionEvent) + { + questHelperPlugin.getClientThread().invoke(() -> { + // from RuneLite core's devtools ::setvarb + var varbit = VarbitID.CUTSCENE_STATUS; + var client = questHelperPlugin.getClient(); + + var currentStatus = client.getVarbitValue(VarbitID.CUTSCENE_STATUS); + var varbitComposition = client.getVarbit(varbit); + var value = currentStatus == 0 ? 1 : 0; + + client.setVarbitValue(client.getVarps(), varbit, value); + client.queueChangedVarp(varbitComposition.getIndex()); + var varbitChanged = new VarbitChanged(); + varbitChanged.setVarbitId(varbit); + varbitChanged.setValue(value); + questHelperPlugin.getEventBus().post(varbitChanged); // fake event + }); + } + }); + + var menu = new JPopupMenu("Menu"); + menu.add(togglePuzzleHelper); + menu.add(toggleCutsceneStatus); var reloadQuest = new JButton("reload quest"); + reloadQuest.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (SwingUtilities.isRightMouseButton(e) && e.getClickCount() == 1) + { + menu.show(reloadQuest, e.getX(), e.getY()); + } + } + }); reloadQuest.addActionListener((ev) -> { nextDesiredScrollValue = scrollableContainer.getVerticalScrollBar().getValue(); var currentQuest = questHelperPlugin.getSelectedQuest(); @@ -417,6 +552,10 @@ public void mousePressed(MouseEvent mouseEvent) }); devModePanel.add(reloadQuest, BorderLayout.SOUTH); + JPanel previewNavPanel = new JPanel(new GridLayout(2, 1, 0, 4)); + previewNavPanel.setBackground(ColorScheme.DARK_GRAY_COLOR); + devModePanel.add(previewNavPanel, BorderLayout.CENTER); + // State dropdown for BasicQuestHelper stateDropdown.setFocusable(false); stateDropdown.addItemListener((ev) -> { @@ -443,7 +582,7 @@ else if (selectedItem != null) } } }); - + // Create a panel with label for the state dropdown statePanel = makeDropdownPanel(stateDropdown, "Quest State"); statePanel.setPreferredSize(new Dimension(PANEL_WIDTH, DROPDOWN_HEIGHT)); @@ -468,12 +607,11 @@ private void onSearchBarChanged() if ((questOverviewPanel.currentQuest == null || !text.isEmpty())) { activateQuestList(); - questSelectPanels.forEach(questListPanel::remove); showMatchingQuests(text); } else { - scrollableContainer.setViewportView(questOverviewWrapper); + showView(VIEW_QUEST_OVERVIEW); } revalidate(); } @@ -515,21 +653,25 @@ private JPanel makeDropdownPanel(JComboBox dropdown, String name) private void showMatchingQuests(String text) { - if (text.isEmpty()) + questSelectPanels.forEach(questListPanel::remove); + + if (text == null || text.isEmpty()) { questSelectPanels.forEach(questListPanel::add); - return; } - - final String[] searchTerms = text.toLowerCase().split(" "); - - questSelectPanels.forEach(listItem -> + else { - if (Text.matchesSearchTerms(Arrays.asList(searchTerms), listItem.getKeywords())) + final String[] searchTerms = text.toLowerCase().split(" "); + questSelectPanels.forEach(listItem -> { - questListPanel.add(listItem); - } - }); + if (Text.matchesSearchTerms(Arrays.asList(searchTerms), listItem.getKeywords())) + { + questListPanel.add(listItem); + } + }); + } + revalidate(); + repaint(); } public void refresh(List questHelpers, boolean loggedOut, @@ -590,10 +732,11 @@ public void refresh(List questHelpers, boolean loggedOut, showMatchingQuests(searchBar.getText() != null ? searchBar.getText() : ""); } + public void addQuest(QuestHelper quest, boolean isActive) { allDropdownSections.setVisible(false); - scrollableContainer.setViewportView(questOverviewWrapper); + showView(VIEW_QUEST_OVERVIEW); questOverviewPanel.addQuest(quest, isActive); updateStateDropdown(quest); @@ -631,7 +774,9 @@ public void removeQuest() questActive = false; questOverviewPanel.removeQuest(); activateQuestList(); + showMatchingQuests(searchBar.getText() != null ? searchBar.getText() : ""); updateStateDropdown(null); + scrollableContainer.getVerticalScrollBar().setValue(0); repaint(); revalidate(); @@ -639,12 +784,12 @@ public void removeQuest() private boolean settingsPanelActive() { - return scrollableContainer.getViewport().getView() == assistLevelPanel; + return VIEW_SETTINGS.equals(activeView); } private void activateSettings() { - scrollableContainer.setViewportView(assistLevelPanel); + showView(VIEW_SETTINGS); searchQuestsPanel.setVisible(false); repaint(); @@ -655,7 +800,7 @@ private void deactivateSettings() { if (questActive && searchBar.getText().isEmpty()) { - scrollableContainer.setViewportView(questOverviewWrapper); + showView(VIEW_QUEST_OVERVIEW); } else { @@ -669,7 +814,7 @@ private void deactivateSettings() private void activateQuestList() { - scrollableContainer.setViewportView(questListWrapper); + showView(VIEW_QUEST_LIST); searchQuestsPanel.setVisible(true); allDropdownSections.setVisible(true); @@ -677,6 +822,17 @@ private void activateQuestList() revalidate(); } + private void showView(String viewName) + { + if (viewName.equals(activeView)) + { + return; + } + + viewportLayout.show(viewportContent, viewName); + activeView = viewName; + } + private void updateStateDropdown(QuestHelper questHelper) { if (!questHelperPlugin.isDeveloperMode()) return; @@ -746,7 +902,7 @@ public void setSelectedQuest(QuestHelper questHelper) else { assistLevelPanel.rebuild(questHelper, configManager, this); - scrollableContainer.setViewportView(assistLevelPanel); + showView(VIEW_SETTINGS); searchQuestsPanel.setVisible(false); } } @@ -785,4 +941,31 @@ public void refreshSkillFiltering() skillExpandButton.setText(String.format("%d active", numFilteredSkills)); } } + + /** + * Updates visibility of the region filter section based on config and world type. + */ + public void updateRegionFilterVisibility(boolean isLeagueWorld) + { + QuestHelperConfig.RegionFilterVisibility visibility = questHelperPlugin.getConfig().regionFilterVisibility(); + boolean shouldShow; + switch (visibility) + { + case SHOW: + shouldShow = true; + break; + case HIDE: + shouldShow = false; + break; + case AUTO: + default: + shouldShow = isLeagueWorld; + break; + } + regionsFilterSection.setVisible(shouldShow); + if (!shouldShow) + { + regionFilterPanel.clearSelection(); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestOverviewPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestOverviewPanel.java index d2d63233d3..ba751a8ea0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestOverviewPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestOverviewPanel.java @@ -56,8 +56,8 @@ import java.awt.event.ItemEvent; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.*; import java.util.List; +import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; @@ -81,7 +81,10 @@ public class QuestOverviewPanel extends JPanel private final QuestRewardsPanel questRewardsPanel; private final JPanel questExternalResourcesList; - private final JPanel questStepsContainer = new JPanel(); + private JPanel questStepsContainer; + private final CardLayout questStepsLayout = new CardLayout(); + private final JPanel questStepsHost = new JPanel(questStepsLayout); + private final JPanel activeStepsCard = new JPanel(new BorderLayout()); private final JPanel actionsContainer = new JPanel(); private final JPanel configContainer = new JPanel(); @@ -90,6 +93,8 @@ public class QuestOverviewPanel extends JPanel private final JLabel questNameLabel = JGenerator.makeJLabel(); private static final ImageIcon CLOSE_ICON = Icon.CLOSE.getIcon(); + private static final String ACTIVE_STEPS_CARD = "active"; + private static final String EMPTY_STEPS_CARD = "empty"; private final List allQuestStepPanelList = new CopyOnWriteArrayList<>(); public QuestOverviewPanel(QuestHelperPlugin questHelperPlugin, QuestManager questManager) @@ -109,7 +114,7 @@ public QuestOverviewPanel(QuestHelperPlugin questHelperPlugin, QuestManager ques actionsContainer.setBorder(new EmptyBorder(5, 5, 5, 10)); actionsContainer.setVisible(false); - final JPanel viewControls = new JPanel(new GridLayout(1, 3, 10, 0)); + final JPanel viewControls = new JPanel(new GridLayout(1, 1, 6, 0)); viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR); JButton closeBtn = new JButton(); @@ -197,11 +202,15 @@ public QuestOverviewPanel(QuestHelperPlugin questHelperPlugin, QuestManager ques introPanel.add(overviewPanel, BorderLayout.NORTH); /* Container for quest steps */ - questStepsContainer.setLayout(new BoxLayout(questStepsContainer, BoxLayout.Y_AXIS)); + questStepsContainer = createQuestStepsContainer(); + activeStepsCard.add(questStepsContainer, BorderLayout.CENTER); + questStepsHost.add(new JPanel(), EMPTY_STEPS_CARD); + questStepsHost.add(activeStepsCard, ACTIVE_STEPS_CARD); + questStepsLayout.show(questStepsHost, EMPTY_STEPS_CARD); add(actionsContainer); add(configContainer); add(introPanel); - add(questStepsContainer); + add(questStepsHost); } private JComboBox makeNewDropdown(Enum[] values, String key) @@ -251,6 +260,10 @@ public void addQuest(QuestHelper quest, boolean isActive) { currentQuest = quest; allQuestStepPanelList.clear(); + questStepsContainer = createQuestStepsContainer(); + activeStepsCard.removeAll(); + activeStepsCard.add(questStepsContainer, BorderLayout.CENTER); + questStepsLayout.show(questStepsHost, ACTIVE_STEPS_CARD); List steps = quest.getPanels(); QuestStep currentStep; @@ -324,7 +337,8 @@ public void removeQuest() introPanel.setVisible(false); configContainer.setVisible(false); configContainer.removeAll(); - questStepsContainer.removeAll(); + questStepsLayout.show(questStepsHost, EMPTY_STEPS_CARD); + allQuestStepPanelList.clear(); questGeneralRequirementsPanel.setRequirements(null); questGeneralRecommendedPanel.setRequirements(null); questItemRequirementsPanel.setRequirements(null); @@ -337,6 +351,13 @@ public void removeQuest() revalidate(); } + private JPanel createQuestStepsContainer() + { + JPanel container = new JPanel(); + container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS)); + return container; + } + /// The quest helper's X is clicked private void closeHelper() { @@ -415,6 +436,10 @@ public void setupQuestRequirements(QuestHelper quest) private static void collectRequirements(QuestHelper quest, List allRequirements, Set processedQuestIds) { + if (quest.getQuest() == null) + { + return; + } if (quest.getQuest().getQuestHelper().getGeneralRequirements() == null) return; List generalRequirements = quest.getQuest().getQuestHelper().getGeneralRequirements(); @@ -524,6 +549,11 @@ private void updateCombatRequirementsPanels(List combatRequirementList) private void updateExternalResourcesPanel(QuestHelper quest) { List externalResourcesList; + if (quest.getQuest() == null) + { + questExternalResourcesList.removeAll(); + return; + } try { externalResourcesList = Collections.singletonList(ExternalQuestResources.valueOf(quest.getQuest().name().toUpperCase()).getWikiURL()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRequirementsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRequirementsPanel.java index 27e547a170..1782997e9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRequirementsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRequirementsPanel.java @@ -50,8 +50,11 @@ import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class QuestRequirementsPanel extends JPanel { @@ -92,7 +95,7 @@ public static JPanel createHeader(@NonNull String header) var headerPanel = new JPanel(); headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); headerPanel.setLayout(new BorderLayout()); - headerPanel.setBorder(new EmptyBorder(5, 5, 5, 10)); + headerPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); var headerLabel = JGenerator.makeJTextArea(header); headerLabel.setForeground(Color.WHITE); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRewardsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRewardsPanel.java index 42f5beab26..dbef8c712a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRewardsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestRewardsPanel.java @@ -58,7 +58,7 @@ public QuestRewardsPanel() rewardsText.setOpaque(false); rewardsText.setEditable(false); rewardsText.setFocusable(false); - rewardsText.setBackground(UIManager.getColor("Label.background")); + rewardsText.setBackground(javax.swing.UIManager.getColor("Label.background")); rewardsText.setFont(Fonts.getOriginalFont()); rewardsText.setBorder(new EmptyBorder(0, 0, 0, 0)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestStepPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestStepPanel.java deleted file mode 100644 index 290e67db96..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/QuestStepPanel.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2020, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.panel; - -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; -import net.runelite.client.plugins.microbot.questhelper.managers.QuestManager; -import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; -import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.FontManager; -import net.runelite.client.util.SwingUtil; - -import javax.annotation.Nullable; -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; - -public class QuestStepPanel extends JPanel implements MouseListener -{ - private static final int TITLE_PADDING = 5; - - @Getter - private final PanelDetails panelDetails; - private final QuestHelperPlugin questHelperPlugin; - - private final JPanel headerPanel = new JPanel(); - private final JTextPane headerLabel = JGenerator.makeJTextPane(); - private final JPanel bodyPanel = new JPanel(); - private final JCheckBox lockStep = new JCheckBox(); - @Getter - private final JPanel leftTitleContainer; - private final JPanel viewControls; - private final HashMap steps = new HashMap<>(); - private final @Nullable QuestRequirementsPanel requiredItemsPanel; - private final @Nullable QuestRequirementsPanel recommendedItemsPanel; - private boolean stepAutoLocked; - private final QuestHelper questHelper; - private QuestStep lastHighlightedStep = null; - - public QuestStepPanel(PanelDetails panelDetails, QuestStep currentStep, QuestManager questManager, QuestHelperPlugin questHelperPlugin) - { - this.panelDetails = panelDetails; - this.questHelperPlugin = questHelperPlugin; - this.questHelper = questManager.getSelectedQuest(); - - setLayout(new BorderLayout(0, 1)); - setBorder(new EmptyBorder(5, 0, 0, 0)); - - leftTitleContainer = new JPanel(new BorderLayout(5, 0)); - - headerLabel.addMouseListener(this); - addMouseListener(this); - - headerLabel.setText(panelDetails.getHeader()); - headerLabel.setFont(FontManager.getRunescapeBoldFont()); - - headerLabel.setMinimumSize(new Dimension(1, headerLabel.getPreferredSize().height)); - - headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.X_AXIS)); - headerPanel.setBorder(new EmptyBorder(7, 7, 3, 7)); - - headerPanel.add(Box.createRigidArea(new Dimension(TITLE_PADDING, 0))); - leftTitleContainer.add(headerLabel, BorderLayout.CENTER); - headerPanel.add(leftTitleContainer, BorderLayout.WEST); - - viewControls = new JPanel(new GridLayout(1, 3, 10, 0)); - - SwingUtil.addModalTooltip(lockStep, "Mark section as incomplete", "Mark section as complete"); - lockStep.setBackground(ColorScheme.DARKER_GRAY_COLOR); - lockStep.addActionListener(ev -> lockSection(lockStep.isSelected())); - lockStep.setVisible(false); - headerPanel.add(lockStep, BorderLayout.EAST); - - viewControls.add(lockStep); - - headerPanel.add(viewControls, BorderLayout.EAST); - - if (panelDetails.contains(currentStep)) - { - headerLabel.setForeground(Color.BLACK); - headerPanel.setBackground(ColorScheme.BRAND_ORANGE); - viewControls.setBackground(ColorScheme.BRAND_ORANGE); - leftTitleContainer.setBackground(ColorScheme.BRAND_ORANGE); - } - else - { - headerLabel.setForeground(Color.WHITE); - headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - } - - /* Body */ - bodyPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - bodyPanel.setLayout(new BorderLayout()); - bodyPanel.setBorder(new EmptyBorder(10, 5, 10, 5)); - - if (panelDetails.getRequirements() != null) - { - requiredItemsPanel = new QuestRequirementsPanel("Bring the following items:", panelDetails.getRequirements(), questManager, false); - bodyPanel.add(requiredItemsPanel, BorderLayout.NORTH); - } - else - { - requiredItemsPanel = null; - } - - if (panelDetails.getRecommended() != null) - { - recommendedItemsPanel = new QuestRequirementsPanel("Optionally bring the following items:", panelDetails.getRecommended(), questManager, - false); - bodyPanel.add(recommendedItemsPanel, BorderLayout.CENTER); - } - else - { - recommendedItemsPanel = null; - } - - JPanel questStepsPanel = new JPanel(); - questStepsPanel.setLayout(new BoxLayout(questStepsPanel, BoxLayout.Y_AXIS)); - questStepsPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - for (QuestStep step : panelDetails.getSteps()) - { - JTextPane questStepLabel = JGenerator.makeJTextPane(); - questStepLabel.setLayout(new BorderLayout()); - questStepLabel.setAlignmentX(SwingConstants.LEFT); - questStepLabel.setAlignmentY(SwingConstants.TOP); - questStepLabel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - questStepLabel.setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createMatteBorder(1, 0, 1, 0, ColorScheme.DARK_GRAY_COLOR.brighter()), - BorderFactory.createEmptyBorder(5, 5, 10, 0) - )); - questStepLabel.setText(generateText(step)); - questStepLabel.setOpaque(true); - questStepLabel.setVisible(step.isShowInSidebar()); - - steps.put(step, questStepLabel); - questStepsPanel.add(questStepLabel); - - } - - bodyPanel.add(questStepsPanel, BorderLayout.SOUTH); - - add(headerPanel, BorderLayout.NORTH); - add(bodyPanel, BorderLayout.CENTER); - - if (!panelDetails.getSteps().contains(currentStep)) - { - collapse(); - } - } - - public String generateText(QuestStep step) - { - StringBuilder text = new StringBuilder(); - - if (step.getText() != null) - { - var first = true; - for (var line : step.getText()) - { - if (!first) - { - text.append("\n\n"); - } - text.append(line); - first = false; - } - } - - return text.toString(); - } - - public List getSteps() - { - return new ArrayList<>(steps.keySet()); - } - - public HashMap getStepsLabels() - { - return steps; - } - - public void setLockable(boolean canLock) - { - lockStep.setVisible(canLock); - } - - public void updateHighlightCheck(Client client, QuestStep newStep, QuestHelper currentQuest) - { - if (panelDetails.getHideCondition() == null || !panelDetails.getHideCondition().check(client)) - { - setVisible(true); - boolean highlighted = false; - setLockable(panelDetails.getLockingQuestSteps() != null && - (panelDetails.getVars() == null || panelDetails.getVars().contains(currentQuest.getVar()))); - - for (QuestStep sidebarStep : getSteps()) - { - if (sidebarStep.getConditionToHide() != null && sidebarStep.getConditionToHide().check(client)) continue; - if (sidebarStep.containsSteps(newStep, new HashSet<>())) - { - highlighted = true; - updateHighlight(sidebarStep); - break; - } - } - - if (!highlighted) - { - removeHighlight(); - } - } - else - { - setVisible(false); - } - } - - - public void updateHighlight(QuestStep currentStep) - { - expand(); - - if (steps.get(lastHighlightedStep) != null) - { - steps.get(lastHighlightedStep).setForeground(Color.LIGHT_GRAY); - } - else - { - headerLabel.setForeground(Color.BLACK); - headerPanel.setBackground(ColorScheme.BRAND_ORANGE); - viewControls.setBackground(ColorScheme.BRAND_ORANGE); - leftTitleContainer.setBackground(ColorScheme.BRAND_ORANGE); - } - - if (steps.get(currentStep) != null) - { - steps.get(currentStep).setForeground(ColorScheme.BRAND_ORANGE); - } - - lastHighlightedStep = currentStep; - } - - public void removeHighlight() - { - headerLabel.setForeground(Color.WHITE); - if (isCollapsed()) - { - applyDimmer(false, headerPanel); - } - headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - if (steps.get(currentlyActiveQuestSidebarStep()) != null) - { - steps.get(currentlyActiveQuestSidebarStep()).setForeground(Color.LIGHT_GRAY); - } - - collapse(); - } - - public void updateLock() - { - if (panelDetails.getLockingQuestSteps() == null) - { - return; - } - - if (panelDetails.getLockingQuestSteps().isUnlockable()) - { - stepAutoLocked = false; - lockStep.setEnabled(true); - } - else - { - if (!stepAutoLocked) - { - collapse(); - } - stepAutoLocked = true; - lockStep.setEnabled(false); - } - - if (panelDetails.getLockingQuestSteps().isLocked()) - { - lockStep.setSelected(true); - } - } - - private void lockSection(boolean locked) - { - if (locked) - { - panelDetails.getLockingQuestSteps().setLockedManually(true); - if (!isCollapsed()) - { - collapse(); - } - } - else - { - panelDetails.getLockingQuestSteps().setLockedManually(false); - if (isCollapsed()) - { - expand(); - } - } - } - - private void collapse() - { - if (!isCollapsed()) - { - bodyPanel.setVisible(false); - applyDimmer(false, headerPanel); - } - } - - private void expand() - { - if (isCollapsed()) - { - bodyPanel.setVisible(true); - applyDimmer(true, headerPanel); - } - } - - boolean isCollapsed() - { - return !bodyPanel.isVisible(); - } - - private void applyDimmer(boolean brighten, JPanel panel) - { - for (Component component : panel.getComponents()) - { - Color color = component.getForeground(); - component.setForeground(brighten ? color.brighter() : color.darker()); - } - } - - public void updateRequirements(Client client) - { - if (requiredItemsPanel != null) - { - requiredItemsPanel.update(client, questHelperPlugin); - } - - if (recommendedItemsPanel != null) - { - recommendedItemsPanel.update(client, questHelperPlugin); - } - - updateStepVisibility(client); - } - - public void updateStepVisibility(Client client) - { - boolean stepVisibilityChanged = false; - for (QuestStep step : steps.keySet()) - { - boolean oldVisibility = step.isShowInSidebar(); - boolean newVisibility = step.getConditionToHide() == null || !step.getConditionToHide().check(client); - stepVisibilityChanged = stepVisibilityChanged || (oldVisibility != newVisibility); - - step.setShowInSidebar(newVisibility); - steps.get(step).setVisible(newVisibility); - } - - if (stepVisibilityChanged) - { - updateHighlightCheck(client, currentlyActiveQuestSidebarStep(), questHelper); - } - } - - private QuestStep currentlyActiveQuestSidebarStep() - { - return questHelperPlugin.getSelectedQuest().getCurrentStep().getActiveStep(); - } - - @Override - public void mouseClicked(MouseEvent e) - { - if (e.getButton() == MouseEvent.BUTTON1) - { - if (isCollapsed()) - { - expand(); - } - else - { - collapse(); - } - } - } - - @Override - public void mousePressed(MouseEvent mouseEvent) - { - } - - @Override - public void mouseReleased(MouseEvent mouseEvent) - { - } - - @Override - public void mouseEntered(MouseEvent mouseEvent) - { - } - - @Override - public void mouseExited(MouseEvent mouseEvent) - { - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/TopLevelPanelDetails.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/TopLevelPanelDetails.java index 6945285280..1522e462e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/TopLevelPanelDetails.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/TopLevelPanelDetails.java @@ -26,7 +26,6 @@ import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import lombok.Getter; - import java.util.ArrayList; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/IronmanOptimalQuestGuide.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/IronmanOptimalQuestGuide.java index b24beed088..dfd06d9c33 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/IronmanOptimalQuestGuide.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/IronmanOptimalQuestGuide.java @@ -27,9 +27,8 @@ import com.google.common.collect.ImmutableList; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; -import lombok.Getter; - import java.util.List; +import lombok.Getter; /** * The order of these quests are parsed using data from the OSRS Wiki @@ -261,6 +260,8 @@ public class IronmanOptimalQuestGuide QuestHelperQuest.THE_CORSAIR_CURSE, QuestHelperQuest.IN_SEARCH_OF_KNOWLEDGE, QuestHelperQuest.HOPESPEARS_WILL, + QuestHelperQuest.THE_IDES_OF_MILK, + QuestHelperQuest.THE_RED_REEF, // Quests & mini quests that are not part of the OSRS Wiki's Optimal Ironman Quest Guide QuestHelperQuest.VALE_TOTEMS, QuestHelperQuest.BALLOON_TRANSPORT_GRAND_TREE, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/OptimalQuestGuide.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/OptimalQuestGuide.java index 1e2a0ce647..84d9ed1ece 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/OptimalQuestGuide.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/OptimalQuestGuide.java @@ -27,9 +27,8 @@ import com.google.common.collect.ImmutableList; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; -import lombok.Getter; - import java.util.List; +import lombok.Getter; /** * The order of these quests are parsed using data from the OSRS Wiki @@ -266,6 +265,8 @@ public class OptimalQuestGuide QuestHelperQuest.SONG_OF_THE_ELVES, QuestHelperQuest.CLOCK_TOWER, QuestHelperQuest.THE_CORSAIR_CURSE, + QuestHelperQuest.THE_IDES_OF_MILK, + QuestHelperQuest.THE_RED_REEF, // Quests & mini quests that are not part of the OSRS Wiki's Optimal Quest Guide QuestHelperQuest.VALE_TOTEMS, QuestHelperQuest.BARBARIAN_TRAINING, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/ReleaseDate.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/ReleaseDate.java index 45dac69e04..221ef4d55f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/ReleaseDate.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/questorders/ReleaseDate.java @@ -27,9 +27,8 @@ import com.google.common.collect.ImmutableList; import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; -import lombok.Getter; - import java.util.List; +import lombok.Getter; /** * The order of these quests are parsed using data from the OSRS Wiki @@ -226,6 +225,8 @@ public class ReleaseDate QuestHelperQuest.PRYING_TIMES, QuestHelperQuest.CURRENT_AFFAIRS, QuestHelperQuest.TROUBLED_TORTUGANS, + QuestHelperQuest.THE_IDES_OF_MILK, + QuestHelperQuest.THE_RED_REEF, // Miniquests QuestHelperQuest.ALFRED_GRIMHANDS_BARCRAWL, QuestHelperQuest.THE_MAGE_ARENA, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/AbstractQuestSection.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/AbstractQuestSection.java index 85251329c0..c623ec6c75 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/AbstractQuestSection.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/AbstractQuestSection.java @@ -29,8 +29,8 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.Client; - import javax.swing.*; +import java.util.HashMap; import java.util.List; public abstract class AbstractQuestSection extends JPanel diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestSectionSection.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestSectionSection.java index af26014f44..c86c481c79 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestSectionSection.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestSectionSection.java @@ -36,7 +36,6 @@ import net.runelite.client.ui.FontManager; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.SwingUtil; - import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; @@ -44,15 +43,20 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class QuestSectionSection extends AbstractQuestSection implements MouseListener { // Idea is to contain multiple sections or queststeppanel private static final int TITLE_PADDING = 5; - private static final ImageIcon DRAG_ICON = new ImageIcon(ImageUtil.loadImageResource(QuestHelperPlugin.class, "/hamburger.png")); + private static final ImageIcon DRAG_ICON = new ImageIcon(ImageUtil.loadImageResource(QuestHelperPlugin.class, "hamburger.png")); private final QuestOverviewPanel questOverviewPanel; private final QuestHelperPlugin questHelperPlugin; @@ -125,7 +129,7 @@ public QuestSectionSection(QuestOverviewPanel questOverviewPanel, TopLevelPanelD stepsPanel.setBorder(new EmptyBorder(10, 5, 10, 5)); // Dragging functionality - this.draggable = panelDetails.getPanelDetails().stream().anyMatch((pDetails -> pDetails.getId() != -1)); + this.draggable = panelDetails.getPanelDetails().stream().anyMatch((pDetails -> pDetails.getId() != Integer.MIN_VALUE)); List order = questHelperPlugin.loadSidebarOrder(questManager.getSelectedQuest()); List panelDetailsList = panelDetails.getPanelDetails(); @@ -476,7 +480,7 @@ private void swapPanels(AbstractQuestSection a, AbstractQuestSection b) public List getIds() { List allIds = new ArrayList<>(); - if (panelDetails.getId() != -1) allIds.add(panelDetails.getId()); + if (panelDetails.getId() != Integer.MIN_VALUE) allIds.add(panelDetails.getId()); allIds.addAll(subPanels.stream() .map(AbstractQuestSection::getIds) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestStepPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestStepPanel.java index 5665aca9ee..dcbefe6f8c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestStepPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/queststepsection/QuestStepPanel.java @@ -27,9 +27,12 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.managers.QuestManager; import net.runelite.client.plugins.microbot.questhelper.panel.JGenerator; +import net.runelite.client.plugins.microbot.questhelper.panel.ManualStepSkipStore; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.panel.QuestRequirementsPanel; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; +import net.runelite.client.plugins.microbot.questhelper.requirements.ManualRequirement; +import net.runelite.client.plugins.microbot.questhelper.steps.BoardShipStep; import net.runelite.client.plugins.microbot.questhelper.steps.PortTaskStep; import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; import net.runelite.api.Client; @@ -41,19 +44,26 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; public class QuestStepPanel extends AbstractQuestSection implements MouseListener { private static final int TITLE_PADDING = 5; private final QuestHelperPlugin questHelperPlugin; - private final HashMap steps = new HashMap<>(); + private final Map stepTextPanes = new HashMap<>(); + private final Map stepRowPanels = new HashMap<>(); + private final Map manualSkipBoxes = new HashMap<>(); + private final Map persistedManualSkips; + private final List orderedSidebarSteps = new ArrayList<>(); + private boolean suppressManualSkipEvents; private final @Nullable QuestRequirementsPanel requiredItemsPanel; private final @Nullable QuestRequirementsPanel recommendedItemsPanel; private boolean stepAutoLocked; @@ -65,6 +75,18 @@ public QuestStepPanel(PanelDetails panelDetails, QuestStep currentStep, QuestMan this.panelDetails = panelDetails; this.questHelperPlugin = questHelperPlugin; this.questHelper = questManager.getSelectedQuest(); + if (this.questHelper != null) + { + this.persistedManualSkips = ManualStepSkipStore.load( + this.questHelper.getConfigManager(), + this.questHelper.gson, + this.questHelper.getDisplayedQuestName() + ); + } + else + { + this.persistedManualSkips = new HashMap<>(); + } setLayout(new BorderLayout(0, 1)); setBorder(new EmptyBorder(5, 0, 0, 0)); @@ -131,7 +153,7 @@ public QuestStepPanel(PanelDetails panelDetails, QuestStep currentStep, QuestMan if (panelDetails.getRecommended() != null) { recommendedItemsPanel = new QuestRequirementsPanel("Optionally bring the following items:", panelDetails.getRecommended(), questManager, - false); + false); bodyPanel.add(recommendedItemsPanel, BorderLayout.CENTER); } else @@ -145,18 +167,16 @@ public QuestStepPanel(PanelDetails panelDetails, QuestStep currentStep, QuestMan for (QuestStep step : panelDetails.getSteps()) { - if(step instanceof PortTaskStep) + if (step instanceof PortTaskStep) { for (QuestStep step2 : ((PortTaskStep) step).getStepsList()) { - JTextPane questStepLabel = createQuestStepLabel(step2); - steps.put(step2, questStepLabel); - questStepsPanel.add(questStepLabel); + addStepRow(questStepsPanel, step2); } - }else{ - JTextPane questStepLabel = createQuestStepLabel(step); - steps.put(step, questStepLabel); - questStepsPanel.add(questStepLabel); + } + else + { + addStepRow(questStepsPanel, step); } } @@ -171,7 +191,179 @@ public QuestStepPanel(PanelDetails panelDetails, QuestStep currentStep, QuestMan } } - private JTextPane createQuestStepLabel(QuestStep step){ + private void addStepRow(JPanel questStepsPanel, QuestStep step) + { + orderedSidebarSteps.add(step); + JPanel row = buildStepRow(step); + stepRowPanels.put(step, row); + questStepsPanel.add(row); + } + + private JPanel buildStepRow(QuestStep step) + { + JPanel row = new JPanel(new BorderLayout()); + row.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + JTextPane questStepLabel = createQuestStepTextPane(step); + stepTextPanes.put(step, questStepLabel); + row.add(questStepLabel, BorderLayout.CENTER); + + ManualRequirement m = step.getSidebarManualSkipRequirement(); + String pk = step.getSidebarManualSkipPersistenceKey(); + if (m != null && pk != null && !pk.isBlank()) + { + boolean persistedSkipped = Boolean.TRUE.equals(persistedManualSkips.get(pk)); + if (persistedSkipped) + { + m.setShouldPass(true); + } + + JCheckBox skip = new JCheckBox(); + skip.setToolTipText("Skip step"); + skip.setOpaque(true); + Client c = questHelperPlugin.getClient(); + skip.setSelected(c != null && m.check(c)); + manualSkipBoxes.put(step, skip); + skip.addActionListener(e -> { + if (suppressManualSkipEvents) + { + return; + } + boolean sel = skip.isSelected(); + m.setShouldPass(sel); + if (sel) + { + persistedManualSkips.put(pk, true); + } + else + { + persistedManualSkips.remove(pk); + } + if (questHelper != null) + { + questHelper.notifyManualSidebarSkipChanged(pk, sel); + } + }); + skip.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent e) + { + maybeShowManualSkipContextMenu(step, skip, e); + } + + @Override + public void mouseReleased(MouseEvent e) + { + maybeShowManualSkipContextMenu(step, skip, e); + } + }); + row.add(skip, BorderLayout.EAST); + } + + row.setVisible(step.isShowInSidebar()); + return row; + } + + private void maybeShowManualSkipContextMenu(QuestStep clickedStep, JCheckBox source, MouseEvent e) + { + if (!e.isPopupTrigger()) + { + return; + } + JPopupMenu menu = new JPopupMenu(); + JMenuItem tickUpTo = new JMenuItem("Tick all up to this step"); + tickUpTo.addActionListener(ev -> tickManualSkipCheckboxesUpTo(clickedStep)); + menu.add(tickUpTo); + JMenuItem resetAll = new JMenuItem("Reset all tick boxes"); + resetAll.addActionListener(ev -> resetAllManualSkipCheckboxes()); + menu.add(resetAll); + menu.show(source, e.getX(), e.getY()); + } + + private void tickManualSkipCheckboxesUpTo(QuestStep clickedStep) + { + if (clickedStep == null || orderedSidebarSteps.isEmpty()) + { + return; + } + int endIndex = orderedSidebarSteps.indexOf(clickedStep); + if (endIndex < 0) + { + return; + } + suppressManualSkipEvents = true; + try + { + for (int i = 0; i <= endIndex; i++) + { + QuestStep step = orderedSidebarSteps.get(i); + ManualRequirement m = step.getSidebarManualSkipRequirement(); + String pk = step.getSidebarManualSkipPersistenceKey(); + if (m == null || pk == null || pk.isBlank()) + { + continue; + } + m.setShouldPass(true); + persistedManualSkips.put(pk, true); + JCheckBox box = manualSkipBoxes.get(step); + if (box != null) + { + box.setSelected(true); + } + if (questHelper != null) + { + questHelper.notifyManualSidebarSkipChanged(pk, true); + } + } + } + finally + { + suppressManualSkipEvents = false; + } + } + + private void resetAllManualSkipCheckboxes() + { + if (questHelper != null) + { + questHelper.resetAllManualSidebarSkips(); + } + if (manualSkipBoxes.isEmpty()) + { + return; + } + suppressManualSkipEvents = true; + try + { + for (Map.Entry e : manualSkipBoxes.entrySet()) + { + QuestStep step = e.getKey(); + JCheckBox box = e.getValue(); + ManualRequirement m = step.getSidebarManualSkipRequirement(); + String pk = step.getSidebarManualSkipPersistenceKey(); + if (m != null) + { + m.setShouldPass(false); + } + if (pk != null && !pk.isBlank()) + { + persistedManualSkips.remove(pk); + } + if (box != null) + { + box.setSelected(false); + } + } + } + finally + { + suppressManualSkipEvents = false; + } + } + + private JTextPane createQuestStepTextPane(QuestStep step) + { JTextPane questStepLabel = JGenerator.makeJTextPane(); questStepLabel.setLayout(new BorderLayout()); questStepLabel.setAlignmentX(SwingConstants.LEFT); @@ -183,13 +375,37 @@ private JTextPane createQuestStepLabel(QuestStep step){ )); questStepLabel.setText(generateText(step)); questStepLabel.setOpaque(true); - questStepLabel.setVisible(step.isShowInSidebar()); + questStepLabel.setVisible(true); return questStepLabel; } + private void syncManualSkipCheckboxesFromRequirements(Client client) + { + if (manualSkipBoxes.isEmpty()) + { + return; + } + suppressManualSkipEvents = true; + try + { + for (Map.Entry e : manualSkipBoxes.entrySet()) + { + ManualRequirement m = e.getKey().getSidebarManualSkipRequirement(); + if (m != null) + { + e.getValue().setSelected(client != null && m.check(client)); + } + } + } + finally + { + suppressManualSkipEvents = false; + } + } + public void updateAllText() { - steps.forEach((questStep, textPane) -> { + stepTextPanes.forEach((questStep, textPane) -> { if (textPane != null) { String newText = generateText(questStep); @@ -226,7 +442,7 @@ public String generateText(QuestStep step) public List getSteps() { - return new ArrayList<>(steps.keySet()); + return new ArrayList<>(stepTextPanes.keySet()); } public void setLockable(boolean canLock) @@ -282,19 +498,19 @@ public boolean updateHighlightCheck(Client client, QuestStep newStep, QuestHelpe public void updateTextToFaded(QuestStep questStep) { - if (steps.get(questStep) != null) + if (stepTextPanes.get(questStep) != null) { - steps.get(questStep).setForeground(Color.DARK_GRAY); - steps.get(questStep).setToolTipText(questStep.getFadeCondition().getDisplayText()); + stepTextPanes.get(questStep).setForeground(Color.DARK_GRAY); + stepTextPanes.get(questStep).setToolTipText(questStep.getFadeCondition().getDisplayText()); } } public void updateTextToUnfaded(QuestStep questStep) { - if (steps.get(questStep) != null) + if (stepTextPanes.get(questStep) != null) { - steps.get(questStep).setForeground(Color.LIGHT_GRAY); - steps.get(questStep).setToolTipText(null); + stepTextPanes.get(questStep).setForeground(Color.LIGHT_GRAY); + stepTextPanes.get(questStep).setToolTipText(null); } } @@ -302,14 +518,14 @@ public void updateHighlight(QuestStep currentStep) { expand(); - if (steps.get(lastHighlightedStep) != null) + if (stepTextPanes.get(lastHighlightedStep) != null) { - steps.get(lastHighlightedStep).setForeground(Color.LIGHT_GRAY); + stepTextPanes.get(lastHighlightedStep).setForeground(Color.LIGHT_GRAY); } - if (steps.get(currentStep) != null) + if (stepTextPanes.get(currentStep) != null) { - steps.get(currentStep).setForeground(ColorScheme.BRAND_ORANGE); + stepTextPanes.get(currentStep).setForeground(ColorScheme.BRAND_ORANGE); headerLabel.setForeground(Color.BLACK); headerPanel.setBackground(ColorScheme.BRAND_ORANGE); viewControls.setBackground(ColorScheme.BRAND_ORANGE); @@ -329,9 +545,9 @@ public void removeHighlight() headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - if (steps.get(currentlyActiveQuestSidebarStep()) != null) + if (stepTextPanes.get(currentlyActiveQuestSidebarStep()) != null) { - steps.get(currentlyActiveQuestSidebarStep()).setForeground(Color.LIGHT_GRAY); + stepTextPanes.get(currentlyActiveQuestSidebarStep()).setForeground(Color.LIGHT_GRAY); } collapse(); @@ -430,19 +646,24 @@ public void updateRequirements(Client client) } updateStepVisibility(client); + syncManualSkipCheckboxesFromRequirements(client); } public boolean updateStepVisibility(Client client) { boolean stepVisibilityChanged = false; - for (QuestStep step : steps.keySet()) + for (QuestStep step : stepTextPanes.keySet()) { boolean oldVisibility = step.isShowInSidebar(); boolean newVisibility = step.getConditionToHide() == null || !step.getConditionToHide().check(client); stepVisibilityChanged = stepVisibilityChanged || (oldVisibility != newVisibility); step.setShowInSidebar(newVisibility); - steps.get(step).setVisible(newVisibility); + JPanel row = stepRowPanels.get(step); + if (row != null) + { + row.setVisible(newVisibility); + } } if (stepVisibilityChanged) @@ -463,7 +684,7 @@ protected QuestStep currentlyActiveQuestSidebarStep() public List getIds() { - if (panelDetails.getId() == -1) return List.of(); + if (panelDetails.getId() == Integer.MIN_VALUE) return List.of(); return List.of(panelDetails.getId()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/regionfiltering/RegionFilterPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/regionfiltering/RegionFilterPanel.java new file mode 100644 index 0000000000..2d3a4a1d57 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/panel/regionfiltering/RegionFilterPanel.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2026, Syrif + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.panel.regionfiltering; + +import net.runelite.client.plugins.microbot.questhelper.config.LeagueFiltering; +import net.runelite.client.plugins.microbot.questhelper.questinfo.LeagueRegion; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.util.ImageUtil; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.EnumSet; + +public class RegionFilterPanel extends JPanel +{ + private final EnumSet selectedRegions = EnumSet.noneOf(LeagueRegion.class); + private final Runnable onChanged; + private final SpriteManager spriteManager; + public RegionFilterPanel(SpriteManager spriteManager, Runnable onChanged) + { + super(); + this.spriteManager = spriteManager; + this.onChanged = onChanged; + + setBorder(new EmptyBorder(10, 10, 10, 10)); + setLayout(new GridLayout(0, 3, 7, 7)); + + for (LeagueRegion region : LeagueRegion.values()) + { + add(createRegionButton(region)); + } + } + + private JButton createRegionButton(LeagueRegion region) + { + JButton button = new JButton(); + button.setOpaque(true); + button.setFocusPainted(false); + button.setBackground(ColorScheme.DARKER_GRAY_COLOR); + button.setToolTipText(region.getDisplayName()); + button.setText(region.getDisplayName()); + button.setFont(button.getFont().deriveFont(Font.PLAIN, 9f)); + button.setForeground(Color.GRAY); + button.setMargin(new Insets(4, 2, 4, 2)); + + // Load sprite async on client thread, replace text with icon when ready + spriteManager.getSpriteAsync(region.getSpriteId(), 0, sprite -> { + if (sprite != null) + { + ImageIcon selectedIcon = new ImageIcon(sprite); + ImageIcon deselectedIcon = new ImageIcon(ImageUtil.alphaOffset(sprite, -180)); + button.putClientProperty("selectedIcon", selectedIcon); + button.putClientProperty("deselectedIcon", deselectedIcon); + SwingUtilities.invokeLater(() -> { + button.setText(null); + if (selectedRegions.contains(region)) + { + button.setIcon(selectedIcon); + } + else + { + button.setIcon(deselectedIcon); + } + button.setPreferredSize(new Dimension(sprite.getWidth() + 10, sprite.getHeight() + 10)); + button.revalidate(); + }); + } + }); + + button.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent e) + { + if (selectedRegions.contains(region)) + { + selectedRegions.remove(region); + updateButtonState(button, false); + } + else + { + selectedRegions.add(region); + updateButtonState(button, true); + } + LeagueFiltering.setSelectedRegions(selectedRegions.isEmpty() ? null : EnumSet.copyOf(selectedRegions)); + onChanged.run(); + } + + @Override + public void mouseEntered(MouseEvent e) + { + button.setBackground(button.getBackground().brighter()); + } + + @Override + public void mouseExited(MouseEvent e) + { + if (selectedRegions.contains(region)) + { + button.setBackground(ColorScheme.BRAND_ORANGE); + } + else + { + button.setBackground(ColorScheme.DARKER_GRAY_COLOR); + } + } + }); + + return button; + } + + private void updateButtonState(JButton button, boolean selected) + { + if (selected) + { + button.setBackground(ColorScheme.BRAND_ORANGE); + ImageIcon selectedIcon = (ImageIcon) button.getClientProperty("selectedIcon"); + if (selectedIcon != null) + { + button.setIcon(selectedIcon); + } + else + { + button.setForeground(Color.WHITE); + } + } + else + { + button.setBackground(ColorScheme.DARKER_GRAY_COLOR); + ImageIcon deselectedIcon = (ImageIcon) button.getClientProperty("deselectedIcon"); + if (deselectedIcon != null) + { + button.setIcon(deselectedIcon); + } + else + { + button.setForeground(Color.GRAY); + } + } + } + + public int getSelectedCount() + { + return selectedRegions.size(); + } + + /** + * Clears all selected regions and resets button states. + */ + public void clearSelection() + { + if (selectedRegions.isEmpty()) + { + return; + } + selectedRegions.clear(); + LeagueFiltering.setSelectedRegions(null); + for (Component comp : getComponents()) + { + if (comp instanceof JButton) + { + updateButtonState((JButton) comp, false); + } + } + onChanged.run(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/bikeshedder/BikeShedder.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/bikeshedder/BikeShedder.java index 552e6bcaad..ecd46990f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/bikeshedder/BikeShedder.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/bikeshedder/BikeShedder.java @@ -25,18 +25,14 @@ package net.runelite.client.plugins.microbot.questhelper.playerquests.bikeshedder; import com.google.common.collect.ImmutableMap; -import net.runelite.api.Skill; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.InterfaceID; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; import net.runelite.client.plugins.microbot.questhelper.collections.ItemCollections; +import net.runelite.client.plugins.microbot.questhelper.collections.KeyringCollection; import net.runelite.client.plugins.microbot.questhelper.collections.TeleportCollections; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questhelpers.BasicQuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirements; +import net.runelite.client.plugins.microbot.questhelper.requirements.item.KeyringRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SkillRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.player.SpellbookRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; @@ -46,6 +42,12 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.*; import net.runelite.client.plugins.microbot.questhelper.steps.widget.NormalSpells; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.ItemID; +import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.ObjectID; import java.util.ArrayList; import java.util.Arrays; @@ -91,13 +93,95 @@ public class BikeShedder extends BasicQuestHelper private ItemRequirement anyCoins; private ItemStep getCoins; + // Sailing + private NpcStep talkToNpcOnBoat; + private NpcStep talkToKlarenceFromShip; + private ObjectStep useSalvagingHook; + private ObjectStep useObjectOffBoat; + private ZoneRequirement onBoat1; + private ZoneRequirement onBoat2; + private ZoneRequirement onBoat3; + private ZoneRequirement onBoat4; + + // Keyring + private ItemRequirement dustyKeyItem; + private KeyringRequirement dustyKeyKeyRing; + private DetailedQuestStep keyringStep; + @Override public Map loadSteps() { + setupRequirements(); + var lumbridge = new Zone(new WorldPoint(3217, 3210, 0), new WorldPoint(3226, 3228, 0)); var outsideLumbridge = new ZoneRequirement(false, lumbridge); moveToLumbridge.setHighlightZone(lumbridge); var steps = new ConditionalStep(this, confuseHans); + + // aldarin bank + var plankNoBank = new ItemRequirement("Plank (no bank)", ItemID.WOODPLANK); + { + // Do not check bank for plank + var plankStep = new DetailedQuestStep(this, "Plank requirement will not check bank", plankNoBank); + var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will not check bank (Requirement used as conditional step passed)", plankNoBank); + var cPlankStep = new ConditionalStep(this, plankStep); + cPlankStep.addStep(plankNoBank, plankStepPassed); + steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2926, 0)), cPlankStep); + } + + { + // Check bank for plank using alsoCheckBank + var plank = plankNoBank.alsoCheckBank(); + plank.setName("Plank (check bank 1)"); + var plankStep = new DetailedQuestStep(this, "Plank requirement will check bank 1", plank); + var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will check bank 1 (Requirement used as conditional step passed)", plank); + var cPlankStep = new ConditionalStep(this, plankStep); + cPlankStep.addStep(plank, plankStepPassed); + steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2925, 0)), cPlankStep); + } + + { + // Check bank for plank using setShouldCheckBank + var plank = new ItemRequirement("Plank (no bank)", ItemID.WOODPLANK); + plank.setShouldCheckBank(true); + plank.setName("Plank (check bank 2)"); + var plankStep = new DetailedQuestStep(this, "Plank requirement will check bank 2", plank); + var plankStepPassed = new DetailedQuestStep(this, "Plank requirement will check bank 2 (Requirement used as conditional step passed)", plank); + var cPlankStep = new ConditionalStep(this, plankStep); + cPlankStep.addStep(plank, plankStepPassed); + steps.addStep(new ZoneRequirement(new WorldPoint(1399, 2924, 0)), cPlankStep); + } + + // mistrock bank + { + // does not need to be equipped + var blueWizardHat = new ItemRequirement("Blue wizard hat", ItemID.BLUEWIZHAT); + var step = new DetailedQuestStep(this, "Blue wizard hat, does not have to be equipped", blueWizardHat); + var stepPassed = new DetailedQuestStep(this, "Blue wizard hat, does not have to be equipped (Requirement used as conditional step passed)", blueWizardHat); + var cStep = new ConditionalStep(this, step); + cStep.addStep(blueWizardHat, stepPassed); + steps.addStep(new ZoneRequirement(new WorldPoint(1383, 2866, 0)), cStep); + } + + { + // must be equipped + var blueWizardHat = new ItemRequirement("Blue wizard hat", ItemID.BLUEWIZHAT); + blueWizardHat.setMustBeEquipped(true); + var step = new DetailedQuestStep(this, "Blue wizard hat, must be equipped", blueWizardHat); + var stepPassed = new DetailedQuestStep(this, "Blue wizard hat, must be equipped (Requirement used as conditional step passed)", blueWizardHat); + var cStep = new ConditionalStep(this, step); + cStep.addStep(blueWizardHat, stepPassed); + steps.addStep(new ZoneRequirement(new WorldPoint(1382, 2866, 0)), cStep); + } + + // Boat + steps.addStep(onBoat1, talkToNpcOnBoat); + steps.addStep(onBoat2, talkToKlarenceFromShip); + steps.addStep(onBoat3, useSalvagingHook); + steps.addStep(onBoat4, useObjectOffBoat); + + steps.addStep(new ZoneRequirement(new WorldPoint(2655, 3286, 0)), keyringStep); + steps.addStep(byStaircaseInSunrisePalace, goDownstairsInSunrisePalace); steps.addStep(outsideLumbridge, moveToLumbridge); steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3218, 0)), haveRunes); @@ -108,6 +192,7 @@ public Map loadSteps() steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3216, 0)), getCoins); steps.addStep(conditionalRequirementZoneRequirement, conditionalRequirementLookAtCoins); steps.addStep(new ZoneRequirement(new WorldPoint(3224, 3221, 0)), lookAtCooksAssistant); + return new ImmutableMap.Builder() .put(-1, steps) .build(); @@ -174,22 +259,86 @@ protected void setupRequirements() var fire30 = new ItemRequirement("Fire runes", ItemID.FIRERUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 63)); + .showConditioned(new SkillRequirement(Skill.MAGIC, 63)); var air30 = new ItemRequirement("Air runes", ItemID.AIRRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 66)); + .showConditioned(new SkillRequirement(Skill.MAGIC, 66)); var water30 = new ItemRequirement("Water runes", ItemID.WATERRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 56)); + .showConditioned(new SkillRequirement(Skill.MAGIC, 56)); var earth30 = new ItemRequirement("Earth runes", ItemID.EARTHRUNE, 30) - .showConditioned(new SkillRequirement(Skill.MAGIC, 60)); + .showConditioned(new SkillRequirement(Skill.MAGIC, 60)); elemental30Unique = new ItemRequirements(LogicType.OR, "Elemental runes as ItemRequirements OR", air30, water30, earth30, fire30); elemental30Unique.addAlternates(ItemID.FIRERUNE, ItemID.EARTHRUNE, ItemID.AIRRUNE); elemental30 = new ItemRequirement("Elemental rune as ItemRequirement", List.of(ItemID.AIRRUNE, ItemID.EARTHRUNE, ItemID.WATERRUNE, - ItemID.FIRERUNE), 30); + ItemID.FIRERUNE), 30); elemental30.setTooltip("You have potato"); haveRunes = new DetailedQuestStep(this, "Compare rune checks for ItemRequirement and ItemRequirements with OR.", elemental30, elemental30Unique); anyCoins = new ItemRequirement("Coins", ItemCollections.COINS); getCoins = new ItemStep(this, new WorldPoint(3224, 3215, 0), "Get coins", anyCoins); + + // Sailing + + var zones1 = new Zone[] { + new Zone(new WorldPoint(3843, 6402, 1), new WorldPoint(3844, 6402, 1)), // Tutorial + new Zone(new WorldPoint(3842, 6389, 1), new WorldPoint(3876, 6389, 1)), + new Zone(new WorldPoint(3842, 6365, 1), new WorldPoint(3860, 6365, 1)), + new Zone(new WorldPoint(3843, 6354, 1), new WorldPoint(3884, 6354, 1)) + }; + onBoat1 = new ZoneRequirement(zones1); + + var zones2 = new Zone[] { + new Zone(new WorldPoint(3843, 6403, 1), new WorldPoint(3844, 6403, 1)), // Tutorial + new Zone(new WorldPoint(3842, 6390, 1), new WorldPoint(3876, 6390, 1)), + new Zone(new WorldPoint(3842, 6366, 1), new WorldPoint(3860, 6366, 1)), + new Zone(new WorldPoint(3843, 6355, 1), new WorldPoint(3884, 6355, 1)) + }; + onBoat2 = new ZoneRequirement(zones2); + + var zones3 = new Zone[] { + new Zone(new WorldPoint(3843, 6404, 1), new WorldPoint(3844, 6404, 1)), // Tutorial + new Zone(new WorldPoint(3842, 6391, 1), new WorldPoint(3876, 6391, 1)), + new Zone(new WorldPoint(3842, 6367, 1), new WorldPoint(3860, 6367, 1)), + new Zone(new WorldPoint(3843, 6356, 1), new WorldPoint(3884, 6356, 1)) + }; + onBoat3 = new ZoneRequirement(zones3); + + var zones4 = new Zone[] { + new Zone(new WorldPoint(3843, 6405, 1), new WorldPoint(3844, 6405, 1)), // Tutorial + new Zone(new WorldPoint(3842, 6312, 1), new WorldPoint(3876, 6392, 1)), + new Zone(new WorldPoint(3842, 6368, 1), new WorldPoint(3860, 6368, 1)), + new Zone(new WorldPoint(3843, 6357, 1), new WorldPoint(3884, 6357, 1)) + }; + onBoat4 = new ZoneRequirement(zones4); + + talkToNpcOnBoat = new NpcStep(this, NpcID.SAILING_INTRO_ANNE_BOAT, "Talk to a ship NPC."); + List shipNpcs = new ArrayList<>(); + for (int i = NpcID.SAILING_CREW_GENERIC_1_WORLD; i <= NpcID.SAILING_CREW_GHOST_JENKINS_CARGO_3; i++) + { + shipNpcs.add(i); + } + talkToNpcOnBoat.addHighlightZones(zones1); + talkToNpcOnBoat.addAlternateNpcs(shipNpcs.toArray(new Integer[0])); + + talkToKlarenceFromShip = new NpcStep(this, NpcID.KLARENSE, new WorldPoint(3046, 3205, 0), "Klarence off the ship."); + talkToKlarenceFromShip.setHighlightZone(new Zone(new WorldPoint(3044, 3202, 0), new WorldPoint(3050, 3205, 0))); + talkToKlarenceFromShip.addHighlightZones(zones2); + List salvagingHookIds = new ArrayList<>(); + for (int i = ObjectID.SAILING_INTRO_SALVAGING_HOOK; i <= ObjectID.SALVAGING_HOOK_LARGE_DRAGON_B; i++) + { + salvagingHookIds.add(i); + } + + useSalvagingHook = new ObjectStep(this, ObjectID.SAILING_INTRO_SALVAGING_HOOK, "Use the salvaging hook."); + useSalvagingHook.addAlternateObjects(salvagingHookIds.toArray(new Integer[0])); + useSalvagingHook.addHighlightZones(zones3); + + useObjectOffBoat = new ObjectStep(this, ObjectID.DRAGONSHIPGANGPLANK_ON, new WorldPoint(3047, 3205, 0), "Click Klarense's gangplank."); + useObjectOffBoat.setHighlightZone(new Zone(new WorldPoint(3044, 3202, 0), new WorldPoint(3050, 3205, 0))); + useObjectOffBoat.addHighlightZones(zones4); + + dustyKeyItem = new ItemRequirement("Dusty key (ItemReq)", ItemID.DUSTY_KEY); + dustyKeyKeyRing = new KeyringRequirement("Dusty key (KeyRingReq)", KeyringCollection.DUSTY_KEY); + keyringStep = new DetailedQuestStep(this, "We need the dusty key", dustyKeyItem, dustyKeyKeyRing); } @Override @@ -211,6 +360,8 @@ public List getPanels() panels.add(new PanelDetails("Item step", List.of(getCoins), List.of(anyCoins))); panels.add(new PanelDetails("Quest state", List.of(lookAtCooksAssistant), List.of(lookAtCooksAssistantRequirement, lookAtCooksAssistantTextRequirement))); panels.add(new PanelDetails("Ensure staircase upstairs in Sunrise Palace is highlighted", List.of(goDownstairsInSunrisePalace), List.of())); + panels.add(new PanelDetails("Sailing", List.of(talkToNpcOnBoat, talkToKlarenceFromShip, useSalvagingHook, useObjectOffBoat), List.of())); + panels.add(new PanelDetails("Key ring", List.of(keyringStep), List.of(dustyKeyItem, dustyKeyKeyRing))); return panels; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/cookshelper/CooksHelper.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/cookshelper/CooksHelper.java deleted file mode 100644 index 50bc5a9b56..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/playerquests/cookshelper/CooksHelper.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2023, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.playerquests.cookshelper; - -import net.runelite.api.QuestState; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.gameval.ItemID; -import net.runelite.api.gameval.NpcID; -import net.runelite.api.gameval.ObjectID; -import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; -import net.runelite.client.plugins.microbot.questhelper.questhelpers.PlayerMadeQuestHelper; -import net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest; -import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; -import net.runelite.client.plugins.microbot.questhelper.requirements.quest.QuestRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.PlayerQuestStateRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.ZoneRequirement; -import net.runelite.client.plugins.microbot.questhelper.rewards.UnlockReward; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.RuneliteConfigSetter; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.dialog.RuneliteDialogStep; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.dialog.RuneliteObjectDialogStep; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.dialog.RunelitePlayerDialogStep; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.FaceAnimationIDs; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.FakeItem; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.FakeNpc; -import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.ReplacedObject; -import net.runelite.client.plugins.microbot.questhelper.steps.ConditionalStep; -import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; -import net.runelite.client.plugins.microbot.questhelper.steps.QuestStep; -import net.runelite.client.plugins.microbot.questhelper.steps.TileStep; -import net.runelite.client.plugins.microbot.questhelper.steps.playermadesteps.RuneliteObjectStep; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class CooksHelper extends PlayerMadeQuestHelper -{ - private RuneliteObjectStep talkToCook, talkToHopleez, grabCabbage, returnToHopleez; - - private DetailedQuestStep standNextToCook, standNextToHopleez, standNextToHopleez2; - - private Requirement nearCook, nearHopleez; - - private FakeNpc cooksCousin, hopleez; - - private FakeItem cabbage; - - private PlayerQuestStateRequirement talkedToCooksCousin, talkedToHopleez, displayCabbage, pickedCabbage; - - @Override - public QuestStep loadStep() - { - itemWidget = ItemID.TOP_HAT; - rotationX = 100; - zoom = 200; - - setupRequirements(); - createRuneliteObjects(); - setupSteps(); - - PlayerQuestStateRequirement req = new PlayerQuestStateRequirement(configManager, getQuest().getPlayerQuests(), 0); - - ConditionalStep questSteps = new ConditionalStep(this, standNextToCook); - questSteps.addStep(req.getNewState(4), new DetailedQuestStep(this, "Quest completed!")); - questSteps.addStep(new Conditions(req.getNewState(3), nearHopleez), returnToHopleez); - questSteps.addStep(req.getNewState(3), standNextToHopleez2); - questSteps.addStep(req.getNewState(2), grabCabbage); - questSteps.addStep(new Conditions(req.getNewState(1), nearHopleez), talkToHopleez); - questSteps.addStep(req.getNewState(1), standNextToHopleez); - questSteps.addStep(nearCook, talkToCook); - - // We want something which can be added to a requirement, which - - // Don't save to config until helper closes/client closing? - - return questSteps; - } - - @Override - protected void setupRequirements() - { - // NPCs should persist through quest steps unless actively removed? Dialog should be conditional on step (sometimes) - // Hide/show NPCs/the runelite character when NPCs go on it/you go over it - // Handle cancelling dialog boxes (even just moving a tile away should remove for example) - // Properly handle removing NPC from screen when changing floors and such - // Work out how to do proper priority on the npcs being clicked - // Wandering NPCs? - // Objects + items (basically same as NPCs) - talkedToCooksCousin = new PlayerQuestStateRequirement(configManager, getQuest().getPlayerQuests(), 1, Operation.GREATER_EQUAL); - talkedToHopleez = new PlayerQuestStateRequirement(configManager, getQuest().getPlayerQuests(), 2, Operation.GREATER_EQUAL); - pickedCabbage = new PlayerQuestStateRequirement(configManager, getQuest().getPlayerQuests(), 3, Operation.GREATER_EQUAL); - displayCabbage = new PlayerQuestStateRequirement(configManager, getQuest().getPlayerQuests(), 2); - nearCook = new ZoneRequirement(new Zone(new WorldPoint(3206, 3212, 0), new WorldPoint(3212, 3218, 0))); - nearHopleez = new ZoneRequirement(new Zone(new WorldPoint(3232, 3212, 0), new WorldPoint(3238, 3218, 0))); - } - - public void setupSteps() - { - // TODO: Need a way to define the groupID of a runelite object to be a quest step without it being stuck - // Add each step's groupID as a sub-group - - talkToCook = new RuneliteObjectStep(this, cooksCousin, "Talk to the Lumbridge Cook's Cousin."); - standNextToCook = new TileStep(this, new WorldPoint(3210, 3215, 0), "Talk to the Lumbridge Cook's Cousin."); - talkToCook.addSubSteps(standNextToCook); - - talkToHopleez = new RuneliteObjectStep(this, hopleez, "Talk to Hopleez east of Lumbridge Castle."); - standNextToHopleez = new TileStep(this, new WorldPoint(3236, 3215, 0), "Talk to Hopleez east of Lumbridge Castle."); - talkToHopleez.addSubSteps(standNextToHopleez); - - grabCabbage = new RuneliteObjectStep(this, cabbage, "Get the cabbage to the north of Hopleez, outside the Sheared Ram."); - - returnToHopleez = new RuneliteObjectStep(this, hopleez, "Return to Hopleez east of Lumbridge Castle."); - standNextToHopleez2 = new DetailedQuestStep(this, new WorldPoint(3235, 3216, 0), "Return to Hopleez east of Lumbridge Castle."); - returnToHopleez.addSubSteps(standNextToHopleez2); - } - - private void setupCooksCousin() - { - // Cook's Cousin - cooksCousin = runeliteObjectManager.createFakeNpc(this.toString(), client.getNpcDefinition(NpcID.POH_SERVANT_COOK_WOMAN).getModels(), new WorldPoint(3209, 3215, 0), 808); - cooksCousin.setName("Cook's Cousin"); - cooksCousin.setFace(4626); - cooksCousin.setExamine("The Cook's cousin."); - cooksCousin.addTalkAction(runeliteObjectManager); - cooksCousin.addExamineAction(runeliteObjectManager); - - QuestRequirement hasDoneCooksAssistant = new QuestRequirement(QuestHelperQuest.COOKS_ASSISTANT, QuestState.FINISHED); - - RuneliteObjectDialogStep dontMeetReqDialog = cooksCousin.createDialogStepForNpc("Come talk to me once you've helped my cousin out."); - cooksCousin.addDialogTree(null, dontMeetReqDialog); - - RuneliteDialogStep dialog = cooksCousin.createDialogStepForNpc("Hey, you there! You helped out my cousin before right?"); - dialog.addContinueDialog(new RunelitePlayerDialogStep(client, "I have yeah, what's wrong? Does he need some more eggs? Maybe I can just get him a chicken instead?")) - .addContinueDialog(cooksCousin.createDialogStepForNpc("No no, nothing like that. Have you seen that terribly dressed person outside the courtyard?", FaceAnimationIDs.FRIENDLY_QUESTIONING)) - .addContinueDialog(cooksCousin.createDialogStepForNpc("I don't know who they are, but can you please get them to move along please?", FaceAnimationIDs.FRIENDLY_QUESTIONING)) - .addContinueDialog(cooksCousin.createDialogStepForNpc("They seem to be attracting more troublemakers....")) - .addContinueDialog(new RunelitePlayerDialogStep(client, "You mean Hatius? If so it'd be my pleasure.").setStateProgression(talkedToCooksCousin.getSetter())); - cooksCousin.addDialogTree(hasDoneCooksAssistant, dialog); - - RuneliteObjectDialogStep dialogV2 = cooksCousin.createDialogStepForNpc("That terribly dressed person is still outside the castle, go talk to them!"); - cooksCousin.addDialogTree(talkedToCooksCousin, dialogV2); - } - - private void setupHopleez() - { - // Hopleez - hopleez = runeliteObjectManager.createFakeNpc(this.toString(), client.getNpcDefinition(NpcID.ZEAH_DEFENCE_PURE).getModels(), new WorldPoint(3235, 3215, 0), 808); - hopleez.setName("Hopleez"); - hopleez.setFace(7481); - hopleez.setExamine("He was here first."); - hopleez.addTalkAction(runeliteObjectManager); - hopleez.addExamineAction(runeliteObjectManager); - - // Dialog - RuneliteDialogStep hopleezDialogPreQuest = hopleez.createDialogStepForNpc("Hop noob."); - hopleezDialogPreQuest.addContinueDialog(new RunelitePlayerDialogStep(client, "What? Also, what are you wearing?")) - .addContinueDialog(hopleez.createDialogStepForNpc("Hop NOOB.")); - hopleez.addDialogTree(null, hopleezDialogPreQuest); - - RuneliteDialogStep hopleezDialog1 = hopleez.createDialogStepForNpc("Hop noob.", FaceAnimationIDs.ANNOYED); - hopleezDialog1.addContinueDialog(new RunelitePlayerDialogStep(client, "What? The Cook's Cousin sent me to see what you were doing here.", FaceAnimationIDs.QUIZZICAL)) - .addContinueDialog(hopleez.createDialogStepForNpc("One moment I was relaxing in Zeah killing some crabs. I closed my eyes for a second, and suddenly I'm here.")) - .addContinueDialog(hopleez.createDialogStepForNpc("People would always try to steal my spot in Zeah, and it seems it's no different here!", FaceAnimationIDs.ANNOYED)) - .addContinueDialog(hopleez.createDialogStepForNpc("Not only is this guy crashing me, but he's trying to outdress me too!", FaceAnimationIDs.ANNOYED_2)) - .addContinueDialog(new RunelitePlayerDialogStep(client, "Hatius? I'm pretty sure he's been here much longer than you....", FaceAnimationIDs.QUESTIONING)) - .addContinueDialog(hopleez.createDialogStepForNpc("I swear he wasn't here when I first arrived, I went away for a second and suddenly he's here!", FaceAnimationIDs.ANNOYED_2)) - .addContinueDialog(hopleez.createDialogStepForNpc("Help me teach him a lesson, get me that old cabbage from outside the The Sheared Ram.")) - .addContinueDialog(new RunelitePlayerDialogStep(client, "Umm, sure....", talkedToHopleez.getSetter())); - hopleez.addDialogTree(talkedToCooksCousin, hopleezDialog1); - - - RuneliteDialogStep hopleezWaitingForCabbageDialog = hopleez.createDialogStepForNpc("Get me that cabbage!"); - hopleez.addDialogTree(talkedToHopleez, hopleezWaitingForCabbageDialog); - - RuneliteConfigSetter endQuest = new RuneliteConfigSetter(configManager, getQuest().getPlayerQuests().getConfigValue(), "4"); - RuneliteDialogStep hopleezGiveCabbageDialog = hopleez.createDialogStepForNpc("Have you got the cabbage?"); - hopleezGiveCabbageDialog - .addContinueDialog(new RunelitePlayerDialogStep(client, "I have! Here you go, why do you need it?")) - .addContinueDialog(hopleez.createDialogStepForNpc("Nice! Now let's sort out this crasher...")) - .addContinueDialog(hopleez.createDialogStepForNpc("Oi noob, take this!")) - .addContinueDialog(new RuneliteObjectDialogStep("Hatius Cosaintus", "What on earth?", NpcID.HATIUS_LUMBRIDGE_DIARY).setStateProgression(endQuest)); - hopleez.addDialogTree(pickedCabbage, hopleezGiveCabbageDialog); - } - - private void setupCabbage() - { - // Old cabbage - cabbage = runeliteObjectManager.createFakeItem(this.toString(), new int[]{ 8196 }, new WorldPoint(3231, 3235, 0), -1); - cabbage.setName("Old cabbage"); - cabbage.setExamine("A mouldy looking cabbage."); - cabbage.addExamineAction(runeliteObjectManager); - cabbage.setDisplayRequirement(displayCabbage); - cabbage.addTakeAction(runeliteObjectManager, new RuneliteConfigSetter(configManager, getQuest().getPlayerQuests().getConfigValue(), "3"), - "You pick up the old cabbage."); - - cabbage.setObjectToRemove(new ReplacedObject(ObjectID.AP_INDICATOR, new WorldPoint(3231, 3235, 0))); - } - - private void createRuneliteObjects() - { - setupCooksCousin(); - setupHopleez(); - setupCabbage(); - } - - @Override - public List getGeneralRequirements() - { - return Collections.singletonList(new QuestRequirement(QuestHelperQuest.COOKS_ASSISTANT, QuestState.FINISHED)); - } - - @Override - public List getUnlockRewards() - { - return Collections.singletonList( - new UnlockReward("A replacement for Hatius Cosaintus") - ); - } - - @Override - public List getPanels() - { - List allSteps = new ArrayList<>(); - PanelDetails helpingTheCousinSteps = new PanelDetails("Helping the Cook's Cousin", Arrays.asList(talkToCook, talkToHopleez, grabCabbage, returnToHopleez)); - allSteps.add(helpingTheCousinSteps); - - return allSteps; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questhelpers/QuestHelper.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questhelpers/QuestHelper.java index 18a590d939..37e5a9a687 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questhelpers/QuestHelper.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questhelpers/QuestHelper.java @@ -24,12 +24,14 @@ */ package net.runelite.client.plugins.microbot.questhelper.questhelpers; +import com.google.gson.Gson; import com.google.inject.Binder; import com.google.inject.CreationException; import com.google.inject.Injector; import com.google.inject.Module; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; +import net.runelite.client.plugins.microbot.questhelper.panel.ManualStepSkipStore; import net.runelite.client.plugins.microbot.questhelper.panel.PanelDetails; import net.runelite.client.plugins.microbot.questhelper.questinfo.ExternalQuestResources; import net.runelite.client.plugins.microbot.questhelper.questinfo.HelperConfig; @@ -77,6 +79,9 @@ public abstract class QuestHelper implements Module, QuestDebugRenderer @Inject private EventBus eventBus; + @Inject + public Gson gson; + @Getter private QuestStep currentStep; @@ -84,6 +89,14 @@ public abstract class QuestHelper implements Module, QuestDebugRenderer @Setter private QuestHelperQuest quest; + /** + * When set (e.g. construct preview / imported player guides), used for sidebar and step overlays + * instead of {@link QuestHelperQuest#getName()} from {@link #quest}. + */ + @Getter + @Setter + private String playerFacingQuestName; + @Setter private Injector injector; @@ -118,6 +131,49 @@ public void removeRuneliteObjects() runeliteObjectManager.removeGroupAndSubgroups(toString()); } + /** + * Human-readable quest title for UI (sidebar, overlays). Uses {@link #playerFacingQuestName} when set, + * otherwise the linked {@link QuestHelperQuest} name, otherwise a generic label. + */ + public String getDisplayedQuestName() + { + if (playerFacingQuestName != null && !playerFacingQuestName.isBlank()) + { + return playerFacingQuestName.trim(); + } + if (quest != null) + { + return quest.getName(); + } + return "Quest Helper"; + } + + /** + * Persists a manual skip flag for one step (sidebar checkbox) and notifies the helper to refresh branch logic. + */ + public void notifyManualSidebarSkipChanged(String persistenceKey, boolean skipped) + { + if (persistenceKey == null || persistenceKey.isBlank()) + { + return; + } + ManualStepSkipStore.put(configManager, gson, getDisplayedQuestName(), persistenceKey, skipped); + onManualSidebarSkipsPersistedChanged(); + } + + public void resetAllManualSidebarSkips() + { + ManualStepSkipStore.clearAll(configManager, getDisplayedQuestName()); + onManualSidebarSkipsPersistedChanged(); + } + + /** + * Hook for helpers that merge persisted skips with runtime state (e.g. maker preview). + */ + protected void onManualSidebarSkipsPersistedChanged() + { + } + public abstract boolean updateQuest(); public void debugStartup(QuestHelperConfig config) @@ -218,9 +274,9 @@ public void renderDebugOverlay(Graphics graphics, QuestHelperPlugin plugin, Pane .build() ); panelComponent.getChildren().add(LineComponent.builder() - .left(getQuest().getName()) + .left(getDisplayedQuestName()) .leftColor(getConfig().debugColor()) - .right(getVar() + "") + .right(getQuest() != null ? String.valueOf(getVar()) : "—") .rightColor(getConfig().debugColor()) .build() ); @@ -228,6 +284,10 @@ public void renderDebugOverlay(Graphics graphics, QuestHelperPlugin plugin, Pane public int getVar() { + if (quest == null) + { + return 0; + } return quest.getVar(client); } @@ -240,11 +300,6 @@ public boolean hasQuestStateBecomeFinished() return questStateEnteredFinished; } - public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) - { - - } - protected void setupZones() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/ExternalQuestResources.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/ExternalQuestResources.java index 17b6e15564..e20412742e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/ExternalQuestResources.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/ExternalQuestResources.java @@ -28,6 +28,7 @@ public enum ExternalQuestResources SHEEP_SHEARER("https://oldschool.runescape.wiki/w/Sheep_Shearer"), SHIELD_OF_ARRAV_PHOENIX_GANG("https://oldschool.runescape.wiki/w/Shield_of_Arrav"), SHIELD_OF_ARRAV_BLACK_ARM_GANG("https://oldschool.runescape.wiki/w/Shield_of_Arrav"), + THE_IDES_OF_MILK("https://oldschool.runescape.wiki/w/The_Ides_of_Milk"), VAMPYRE_SLAYER("https://oldschool.runescape.wiki/w/Vampyre_Slayer"), WITCHS_POTION("https://oldschool.runescape.wiki/w/Witch%27s_Potion"), X_MARKS_THE_SPOT("https://oldschool.runescape.wiki/w/X_Marks_the_Spot"), @@ -192,6 +193,7 @@ public enum ExternalQuestResources PRYING_TIMES("https://oldschool.runescape.wiki/w/Prying_Times"), CURRENT_AFFAIRS("https://oldschool.runescape.wiki/w/Current_Affairs"), TROUBLED_TORTUGANS("https://oldschool.runescape.wiki/w/Troubled_Tortugans"), + THE_RED_REEF("https://oldschool.runescape.wiki/w/The_Red_Reef"), //Miniquests ENTER_THE_ABYSS("https://oldschool.runescape.wiki/w/Enter_the_Abyss"), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueQuestRegions.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueQuestRegions.java new file mode 100644 index 0000000000..44243f9b90 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueQuestRegions.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2026, Syrif + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.questinfo; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; + +import static net.runelite.client.plugins.microbot.questhelper.questinfo.LeagueRegion.*; +import static net.runelite.client.plugins.microbot.questhelper.questinfo.QuestHelperQuest.*; + +/** + * Maps quests to the league regions required to complete them. + * TODO: Quests with no mapping require manual curation. + * Unmapped quests always pass the league filter. + * Update this class per league season. + */ +public class LeagueQuestRegions +{ + private static final Map> QUEST_REGIONS = new EnumMap<>(QuestHelperQuest.class); + + static + { + // F2P quests + put(X_MARKS_THE_SPOT, ASGARNIA); + put(THE_CORSAIR_CURSE, ASGARNIA, KANDARIN); + put(MISTHALIN_MYSTERY, MISTHALIN); + put(PIRATES_TREASURE, ASGARNIA); + put(GOBLIN_DIPLOMACY, ASGARNIA); + put(THE_KNIGHTS_SWORD, ASGARNIA); + put(WITCHS_POTION, ASGARNIA); + put(BLACK_KNIGHTS_FORTRESS, ASGARNIA); + put(DORICS_QUEST, ASGARNIA); + put(PRINCE_ALI_RESCUE, DESERT); + put(IMP_CATCHER, MISTHALIN); + put(VAMPYRE_SLAYER, MISTHALIN); + put(ERNEST_THE_CHICKEN, MISTHALIN); + put(THE_RESTLESS_GHOST, MISTHALIN); + put(SHEEP_SHEARER, MISTHALIN); + put(SHIELD_OF_ARRAV_PHOENIX_GANG, MISTHALIN); + put(SHIELD_OF_ARRAV_BLACK_ARM_GANG, MISTHALIN); + put(DEMON_SLAYER, MISTHALIN); + put(ROMEO__JULIET, MISTHALIN); + put(COOKS_ASSISTANT, MISTHALIN); + + // Members quests + put(WITCHS_HOUSE, ASGARNIA); + put(HEROES_QUEST, ASGARNIA); + put(SCORPION_CATCHER, ASGARNIA, KANDARIN, MISTHALIN); + put(FISHING_CONTEST, KANDARIN); + put(TRIBAL_TOTEM, KARAMJA, KANDARIN); + put(MONKS_FRIEND, KANDARIN); + put(TEMPLE_OF_IKOV, KANDARIN, MISTHALIN); + put(CLOCK_TOWER, KANDARIN); + put(FIGHT_ARENA, KANDARIN); + put(HAZEEL_CULT, KANDARIN); + put(SHEEP_HERDER, KANDARIN); + put(PLAGUE_CITY, KANDARIN); + put(SEA_SLUG, KANDARIN); + put(WATERFALL_QUEST, KANDARIN); + put(OBSERVATORY_QUEST, KANDARIN); + put(DWARF_CANNON, ASGARNIA, KANDARIN); + put(GERTRUDES_CAT, MISTHALIN); + put(BIG_CHOMPY_BIRD_HUNTING, KANDARIN); + put(TAI_BWO_WANNAI_TRIO, KARAMJA); + put(SHADES_OF_MORTTON, MORYTANIA); + put(THRONE_OF_MISCELLANIA, FREMENNIK); + put(HAUNTED_MINE, MORYTANIA); + put(TROLL_ROMANCE, ASGARNIA, KANDARIN); + put(GHOSTS_AHOY, MORYTANIA); + put(BETWEEN_A_ROCK, ASGARNIA, FREMENNIK, KANDARIN); + put(THE_GOLEM, DESERT); + put(THE_GIANT_DWARF, ASGARNIA, FREMENNIK); + put(RECRUITMENT_DRIVE, ASGARNIA); + put(FORGETTABLE_TALE, ASGARNIA, FREMENNIK, KANDARIN); + put(A_TAIL_OF_TWO_CATS, ASGARNIA, DESERT); + put(WANTED, ASGARNIA, MORYTANIA, WILDERNESS); + put(SHADOW_OF_THE_STORM, DESERT); + put(MAKING_HISTORY, FREMENNIK, KANDARIN, MORYTANIA); + put(SPIRITS_OF_THE_ELID, DESERT); + put(DEVIOUS_MINDS, ASGARNIA, MORYTANIA, WILDERNESS); + put(THE_HAND_IN_THE_SAND, ASGARNIA, KANDARIN); + put(THE_SLUG_MENACE, ASGARNIA, KANDARIN); // also needs Misthalin OR Desert OR Wilderness for altars + put(ELEMENTAL_WORKSHOP_II, MISTHALIN, KANDARIN); + put(ENLIGHTENED_JOURNEY, ASGARNIA); + put(EAGLES_PEAK, KANDARIN); + put(ANIMAL_MAGNETISM, ASGARNIA, MORYTANIA); + put(CONTACT, DESERT); + put(THE_FREMENNIK_ISLES, FREMENNIK); + put(WHAT_LIES_BELOW, DESERT, WILDERNESS); + put(OLAFS_QUEST, FREMENNIK); + put(ANOTHER_SLICE_OF_HAM, ASGARNIA, FREMENNIK); + put(GRIM_TALES, ASGARNIA); + put(BIOHAZARD, ASGARNIA, KANDARIN); + put(TOWER_OF_LIFE, KANDARIN); + put(LAND_OF_THE_GOBLINS, ASGARNIA, FREMENNIK, KANDARIN); + put(ZOGRE_FLESH_EATERS, KANDARIN); + put(CLIENT_OF_KOUREND, KOUREND); + put(THE_QUEEN_OF_THIEVES, KOUREND); + put(THE_DEPTHS_OF_DESPAIR, KOUREND); + put(A_TASTE_OF_HOPE, MORYTANIA); + put(TALE_OF_THE_RIGHTEOUS, KOUREND); + put(THE_ASCENT_OF_ARCEUUS, KOUREND); + put(THE_FORSAKEN_TOWER, KOUREND); + put(THE_FREMENNIK_EXILES, FREMENNIK); + put(SINS_OF_THE_FATHER, MORYTANIA); + put(A_PORCINE_OF_INTEREST, ASGARNIA); + put(GETTING_AHEAD, KOUREND); + put(A_NIGHT_AT_THE_THEATRE, MORYTANIA); + put(A_KINGDOM_DIVIDED, KOUREND); + put(BENEATH_CURSED_SANDS, DESERT); + put(SLEEPING_GIANTS, DESERT); + put(THE_GARDEN_OF_DEATH, KOUREND); + put(THE_PATH_OF_GLOUPHRIE, KANDARIN); + put(CHILDREN_OF_THE_SUN, MISTHALIN); + put(AT_FIRST_LIGHT, VARLAMORE); + put(PERILOUS_MOON, VARLAMORE); + put(THE_RIBBITING_TALE_OF_A_LILY_PAD_LABOUR_DISPUTE, VARLAMORE); + put(THE_HEART_OF_DARKNESS, VARLAMORE); + put(DEATH_ON_THE_ISLE, VARLAMORE); + put(MEAT_AND_GREET, VARLAMORE); + put(ETHICALLY_ACQUIRED_ANTIQUITIES, ASGARNIA, VARLAMORE); + put(THE_FINAL_DAWN, VARLAMORE); + put(SHADOWS_OF_CUSTODIA, VARLAMORE); + put(SCRAMBLED, VARLAMORE); + put(A_SOULS_BANE, MISTHALIN); + put(RAG_AND_BONE_MAN_I, MISTHALIN, KARAMJA); + put(ROYAL_TROUBLE, FREMENNIK); + put(DEATH_TO_THE_DORGESHUUN, MISTHALIN); + + put(BELOW_ICE_MOUNTAIN, ASGARNIA, MISTHALIN); + put(BIG_CHOMPY_BIRD_HUNTING, KANDARIN); + put(CABIN_FEVER, MORYTANIA); + put(COLD_WAR, KANDARIN, FREMENNIK); + put(THE_CURSE_OF_ARRAV, DESERT, MISTHALIN, ASGARNIA); + put(DARKNESS_OF_HALLOWVALE, MISTHALIN, MORYTANIA); + put(DEFENDER_OF_VARROCK, MISTHALIN); + put(DESERT_TREASURE, DESERT, MISTHALIN, KANDARIN, ASGARNIA, MORYTANIA); + put(ENAKHRAS_LAMENT, DESERT); + put(THE_FEUD, DESERT); + put(THE_GREAT_BRAIN_ROBBERY, MORYTANIA, ASGARNIA); + put(HORROR_FROM_THE_DEEP, FREMENNIK, KANDARIN); + put(THE_IDES_OF_MILK, MISTHALIN); + put(IN_AID_OF_THE_MYREQUE, MISTHALIN, MORYTANIA); + put(IN_SEARCH_OF_THE_MYREQUE, MORYTANIA); + put(THE_LOST_TRIBE, MISTHALIN, ASGARNIA); + put(MAKING_FRIENDS_WITH_MY_ARM, MISTHALIN, FREMENNIK); + put(MOUNTAIN_DAUGHTER, FREMENNIK, KANDARIN); + put(MOURNINGS_END_PART_I, KANDARIN, TIRANNWN, ASGARNIA); + put(MOURNINGS_END_PART_II, KANDARIN, TIRANNWN); + put(MY_ARMS_BIG_ADVENTURE, ASGARNIA, KARAMJA); + put(RAG_AND_BONE_MAN_II, MISTHALIN, KARAMJA, KANDARIN, ASGARNIA, MORYTANIA, DESERT); + put(RATCATCHERS, MISTHALIN, KANDARIN, FREMENNIK, ASGARNIA, DESERT); + put(REGICIDE, KANDARIN, TIRANNWN, ASGARNIA); + put(ROVING_ELVES, KANDARIN, TIRANNWN); + put(RUM_DEAL, MORYTANIA); + put(SECRETS_OF_THE_NORTH, KANDARIN, FREMENNIK); + put(SONG_OF_THE_ELVES, TIRANNWN, KANDARIN); + put(TEARS_OF_GUTHIX, MISTHALIN); + // Possibly Wilderness, but only if the abyss rcing area when tele'd there counts as wildy? + put(TEMPLE_OF_THE_EYE, DESERT, MISTHALIN); + put(THE_TOURIST_TRAP, DESERT); + put(WHILE_GUTHIX_SLEEPS, MISTHALIN, ASGARNIA, KANDARIN); + + // put(TROUBLED_TORTUGANS, SEA); + // put(PRYING_TIMES, SEA); + // put(PANDEMONIUM, ASGARNIA, SEA); + // put(CURRENT_AFFAIRS, KANDARIN, SEA); + + // RFD subquests + put(RECIPE_FOR_DISASTER_START, MISTHALIN, FREMENNIK, VARLAMORE); + put(RECIPE_FOR_DISASTER_WARTFACE_AND_BENTNOZE, MISTHALIN, ASGARNIA); + put(RECIPE_FOR_DISASTER_DWARF, MISTHALIN, ASGARNIA, KANDARIN); + put(RECIPE_FOR_DISASTER_EVIL_DAVE, MISTHALIN, DESERT); + put(RECIPE_FOR_DISASTER_PIRATE_PETE, MISTHALIN, KANDARIN); + put(RECIPE_FOR_DISASTER_LUMBRIDGE_GUIDE, MISTHALIN, ASGARNIA, KANDARIN); + put(RECIPE_FOR_DISASTER_SIR_AMIK_VARZE, MISTHALIN, ASGARNIA, FREMENNIK); + put(RECIPE_FOR_DISASTER_MONKEY_AMBASSADOR, MISTHALIN, KANDARIN); + put(RECIPE_FOR_DISASTER_SKRACH_UGLOGWEE, MISTHALIN, KANDARIN); + + // Miniquests + put(ALFRED_GRIMHANDS_BARCRAWL, KANDARIN); + put(BARBARIAN_TRAINING, KARAMJA, KANDARIN); + put(SKIPPY_AND_THE_MOGRES, ASGARNIA); + put(LAIR_OF_TARN_RAZORLOR, MORYTANIA); + put(BEAR_YOUR_SOUL, ASGARNIA, KOUREND); + put(THE_MAGE_ARENA, WILDERNESS); + put(FAMILY_PEST, DESERT, FREMENNIK, KANDARIN); + put(THE_MAGE_ARENA_II, WILDERNESS); + put(IN_SEARCH_OF_KNOWLEDGE, KOUREND); + put(DADDYS_HOME, MISTHALIN); + // THE_FROZEN_DOOR and INTO_THE_TOMBS don't have QuestHelperQuest entries yet + put(HIS_FAITHFUL_SERVANTS, MORYTANIA); + put(VALE_TOTEMS, VARLAMORE); + + // Diaries + put(DESERT_EASY, DESERT); + put(DESERT_MEDIUM, DESERT); + put(DESERT_HARD, DESERT); + put(DESERT_ELITE, DESERT); + + put(FALADOR_EASY, ASGARNIA); + put(FALADOR_MEDIUM, ASGARNIA); + put(FALADOR_HARD, ASGARNIA); + put(FALADOR_ELITE, ASGARNIA); + + put(FREMENNIK_EASY, FREMENNIK); + put(FREMENNIK_MEDIUM, FREMENNIK); + put(FREMENNIK_HARD, FREMENNIK); + put(FREMENNIK_ELITE, FREMENNIK); + + put(ARDOUGNE_EASY, KANDARIN); + put(ARDOUGNE_MEDIUM, KANDARIN); + put(ARDOUGNE_HARD, KANDARIN); + put(ARDOUGNE_ELITE, KANDARIN); + + put(KANDARIN_EASY, KANDARIN); + put(KANDARIN_MEDIUM, KANDARIN); + put(KANDARIN_HARD, KANDARIN); + put(KANDARIN_ELITE, KANDARIN); + + put(KARAMJA_EASY, KARAMJA); + put(KARAMJA_MEDIUM, KARAMJA); + put(KARAMJA_HARD, KARAMJA); + put(KARAMJA_ELITE, KARAMJA); + + put(KOUREND_EASY, KOUREND); + put(KOUREND_MEDIUM, KOUREND); + put(KOUREND_HARD, KOUREND); + put(KOUREND_ELITE, KOUREND); + + put(LUMBRIDGE_EASY, MISTHALIN); + put(LUMBRIDGE_MEDIUM, MISTHALIN); + put(LUMBRIDGE_HARD, MISTHALIN); + put(LUMBRIDGE_ELITE, MISTHALIN); + + put(MORYTANIA_EASY, MORYTANIA); + put(MORYTANIA_MEDIUM, MORYTANIA); + put(MORYTANIA_HARD, MORYTANIA); + put(MORYTANIA_ELITE, MORYTANIA); + + put(VARROCK_EASY, MISTHALIN); + put(VARROCK_MEDIUM, MISTHALIN); + put(VARROCK_HARD, MISTHALIN); + put(VARROCK_ELITE, MISTHALIN); + + put(WESTERN_EASY, KANDARIN, TIRANNWN); + put(WESTERN_MEDIUM, KANDARIN, TIRANNWN); + put(WESTERN_HARD, KANDARIN, TIRANNWN); + put(WESTERN_ELITE, KANDARIN, TIRANNWN); + + put(WILDERNESS_EASY, WILDERNESS); + put(WILDERNESS_MEDIUM, WILDERNESS); + put(WILDERNESS_HARD, WILDERNESS); + put(WILDERNESS_ELITE, WILDERNESS); + } + + private static void put(QuestHelperQuest quest, LeagueRegion... regions) + { + QUEST_REGIONS.put(quest, EnumSet.of(regions[0], regions)); + } + + public static boolean isCompletableWith(QuestHelperQuest quest, EnumSet playerRegions) + { + EnumSet required = QUEST_REGIONS.get(quest); + if (required == null) + { + return false; + } + return playerRegions.containsAll(required); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueRegion.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueRegion.java new file mode 100644 index 0000000000..c010941725 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/LeagueRegion.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Syrif + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.questinfo; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.gameval.SpriteID; + +/** + * Regions available in OSRS leagues. Area codes match param 1017 values from the game cache. + */ +@AllArgsConstructor +@Getter +public enum LeagueRegion +{ + MISTHALIN("Misthalin", 1, SpriteID.TrailblazerMapShields._0), + KARAMJA("Karamja", 2, SpriteID.TrailblazerMapShields._1), + ASGARNIA("Asgarnia", 3, SpriteID.TrailblazerMapShields._2), + KANDARIN("Kandarin", 4, SpriteID.TrailblazerMapShields._6), + MORYTANIA("Morytania", 5, SpriteID.TrailblazerMapShields._4), + DESERT("Desert", 6, SpriteID.TrailblazerMapShields._3), + TIRANNWN("Tirannwn", 7, SpriteID.TrailblazerMapShields._8), + FREMENNIK("Fremennik Province", 8, SpriteID.TrailblazerMapShields._7), + KOUREND("Kourend & Kebos", 10, SpriteID.League4MapShields01._9), + WILDERNESS("Wilderness", 11, SpriteID.TrailblazerMapShields._5), + VARLAMORE("Varlamore", 21, SpriteID.League5MapShields01._10); + + private final String displayName; + private final int areaCode; + private final int spriteId; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestHelperQuest.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestHelperQuest.java index 6c18daca5b..597ab3a83b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestHelperQuest.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestHelperQuest.java @@ -25,6 +25,7 @@ package net.runelite.client.plugins.microbot.questhelper.questinfo; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.ChartingHelper; import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.ardougne.ArdougneEasy; import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.ardougne.ArdougneElite; import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.ardougne.ArdougneHard; @@ -70,7 +71,6 @@ import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.wilderness.WildernessElite; import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.wilderness.WildernessHard; import net.runelite.client.plugins.microbot.questhelper.helpers.achievementdiaries.wilderness.WildernessMedium; -import net.runelite.client.plugins.microbot.questhelper.helpers.activities.charting.ChartingHelper; import net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.alfredgrimhandsbarcrawl.AlfredGrimhandsBarcrawl; import net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.barbariantraining.BarbarianTraining; import net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.curseoftheemptylord.CurseOfTheEmptyLord; @@ -88,10 +88,10 @@ import net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.themagearenaii.TheMageArenaII; import net.runelite.client.plugins.microbot.questhelper.helpers.miniquests.valetotems.ValeTotems; import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.allneededitems.AllNeededItems; -import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.HerbRun; -import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.TreeRun; import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.knightswaves.KnightWaves; import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.strongholdofsecurity.StrongholdOfSecurity; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.HerbRun; +import net.runelite.client.plugins.microbot.questhelper.helpers.mischelpers.farmruns.TreeRun; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.akingdomdivided.AKingdomDivided; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.anightatthetheatre.ANightAtTheTheatre; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.animalmagnetism.AnimalMagnetism; @@ -246,10 +246,12 @@ import net.runelite.client.plugins.microbot.questhelper.helpers.quests.thegreatbrainrobbery.TheGreatBrainRobbery; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.thehandinthesand.TheHandInTheSand; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theheartofdarkness.TheHeartOfDarkness; +import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theidesofmilk.TheIdesOfMilk; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theknightssword.TheKnightsSword; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.thelosttribe.TheLostTribe; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.thepathofglouphrie.ThePathOfGlouphrie; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.thequeenofthieves.TheQueenOfThieves; +import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theredreef.TheRedReef; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.therestlessghost.TheRestlessGhost; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theribbitingtaleofalilypadlabourdispute.TheRibbitingTaleOfALilyPadLabourDispute; import net.runelite.client.plugins.microbot.questhelper.helpers.quests.theslugmenace.TheSlugMenace; @@ -303,6 +305,7 @@ public enum QuestHelperQuest ERNEST_THE_CHICKEN(new ErnestTheChicken(), Quest.ERNEST_THE_CHICKEN, QuestVarPlayer.QUEST_ERNEST_THE_CHICKEN, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), GOBLIN_DIPLOMACY(new GoblinDiplomacy(), Quest.GOBLIN_DIPLOMACY, QuestVarbits.QUEST_GOBLIN_DIPLOMACY, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), IMP_CATCHER(new ImpCatcher(), Quest.IMP_CATCHER, QuestVarPlayer.QUEST_IMP_CATCHER, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), + THE_IDES_OF_MILK(new TheIdesOfMilk(), Quest.THE_IDES_OF_MILK, QuestVarbits.QUEST_THE_IDES_OF_MILK, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), THE_KNIGHTS_SWORD(new TheKnightsSword(), Quest.THE_KNIGHTS_SWORD, QuestVarPlayer.QUEST_THE_KNIGHTS_SWORD, QuestDetails.Type.F2P, QuestDetails.Difficulty.INTERMEDIATE), MISTHALIN_MYSTERY(new MisthalinMystery(), Quest.MISTHALIN_MYSTERY, QuestVarbits.QUEST_MISTHALIN_MYSTERY, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), PIRATES_TREASURE(new PiratesTreasure(), Quest.PIRATES_TREASURE, QuestVarPlayer.QUEST_PIRATES_TREASURE, QuestDetails.Type.F2P, QuestDetails.Difficulty.NOVICE), @@ -482,6 +485,7 @@ public enum QuestHelperQuest PRYING_TIMES(new PryingTimes(), Quest.PRYING_TIMES, QuestVarbits.QUEST_PRYING_TIMES, QuestDetails.Type.P2P, QuestDetails.Difficulty.INTERMEDIATE), CURRENT_AFFAIRS(new CurrentAffairs(), Quest.CURRENT_AFFAIRS, QuestVarbits.QUEST_CURRENT_AFFAIRS, QuestDetails.Type.P2P, QuestDetails.Difficulty.NOVICE), TROUBLED_TORTUGANS(new TroubledTortugans(), Quest.TROUBLED_TORTUGANS, QuestVarbits.QUEST_TROUBLED_TORTUGANS, QuestDetails.Type.P2P, QuestDetails.Difficulty.EXPERIENCED), + THE_RED_REEF(new TheRedReef(), Quest.THE_RED_REEF, QuestVarbits.QUEST_THE_RED_REEF, QuestDetails.Type.P2P, QuestDetails.Difficulty.EXPERIENCED), //Miniquests ENTER_THE_ABYSS(new EnterTheAbyss(), Quest.ENTER_THE_ABYSS, QuestVarPlayer.QUEST_ENTER_THE_ABYSS, QuestDetails.Type.MINIQUEST, QuestDetails.Difficulty.MINIQUEST), BEAR_YOUR_SOUL(new BearYourSoul(), Quest.BEAR_YOUR_SOUL, QuestVarbits.QUEST_BEAR_YOUR_SOUL, QuestDetails.Type.MINIQUEST, QuestDetails.Difficulty.MINIQUEST), @@ -657,7 +661,6 @@ public enum QuestHelperQuest WOODCUTTING(new Woodcutting(), "Woodcutting", Skill.WOODCUTTING, 99, QuestDetails.Type.SKILL_F2P, QuestDetails.Difficulty.SKILL), MINING(new Mining(), "Mining", Skill.MINING, 99, QuestDetails.Type.SKILL_F2P, QuestDetails.Difficulty.SKILL), - // Player Quests BIKE_SHEDDER(new BikeShedder(), "Bike Shedder", PlayerQuests.BIKE_SHEDDER, 4, true); @@ -675,9 +678,11 @@ public enum QuestHelperQuest @Getter private final QuestDetails.Difficulty difficulty; + @Getter private final QuestVarbits varbit; + @Getter private final QuestVarPlayer varPlayer; private Skill skill; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestVarbits.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestVarbits.java index d6ce0c9536..e87cfd4340 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestVarbits.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/questinfo/QuestVarbits.java @@ -18,6 +18,7 @@ public enum QuestVarbits QUEST_GOBLIN_DIPLOMACY(VarbitID.GOBDIP_MAIN), QUEST_MISTHALIN_MYSTERY(VarbitID.MISTMYST_PROGRESS), QUEST_THE_CORSAIR_CURSE(VarbitID.CORSCURS_PROGRESS), + QUEST_THE_IDES_OF_MILK(VarbitID.COWQUEST), QUEST_X_MARKS_THE_SPOT(VarbitID.CLUEQUEST), /** @@ -127,7 +128,8 @@ public enum QuestVarbits QUEST_PANDEMONIUM(VarbitID.SAILING_INTRO), QUEST_PRYING_TIMES(VarbitID.QUEST_PRY), QUEST_CURRENT_AFFAIRS(VarbitID.CURRENT_AFFAIRS), - QUEST_TROUBLED_TORTUGANS(VarbitID.TT), + QUEST_TROUBLED_TORTUGANS(VarbitID.TT), + QUEST_THE_RED_REEF(VarbitID.TRR), /** * mini-quest varbits, these don't hold the completion value. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/AbstractRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/AbstractRequirement.java index b1f02da01f..e4480df65e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/AbstractRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/AbstractRequirement.java @@ -24,8 +24,8 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements; -import net.runelite.api.Client; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import net.runelite.api.Client; import net.runelite.client.ui.overlay.components.LineComponent; import javax.annotation.Nonnull; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/ChatMessageRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/ChatMessageRequirement.java index 7bef5083ec..1f15f19c2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/ChatMessageRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/ChatMessageRequirement.java @@ -26,11 +26,11 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ConditionForStep; import lombok.Setter; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.events.ChatMessage; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.ConditionForStep; import java.util.Arrays; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/Requirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/Requirement.java index 343a8b16c8..0384ec8631 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/Requirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/Requirement.java @@ -26,9 +26,9 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements; +import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.api.Client; import net.runelite.client.config.ConfigManager; -import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.ui.overlay.components.LineComponent; import javax.annotation.Nonnull; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/StepIsActiveRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/StepIsActiveRequirement.java index a8d6dbc232..cea3370279 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/StepIsActiveRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/StepIsActiveRequirement.java @@ -26,7 +26,7 @@ import net.runelite.client.plugins.microbot.questhelper.steps.DetailedQuestStep; import net.runelite.api.Client; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; public class StepIsActiveRequirement extends AbstractRequirement { @@ -43,7 +43,7 @@ public boolean check(Client client) return questStep.isStarted(); } - @NotNull + @Nonnull @Override public String getDisplayText() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ConditionForStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ConditionForStep.java index cb767e0181..ac054d69b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ConditionForStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ConditionForStep.java @@ -40,6 +40,7 @@ public abstract class ConditionForStep implements InitializableRequirement @Getter protected boolean hasPassed; protected boolean onlyNeedToPassOnce; + @Getter protected LogicType logicType; @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/Conditions.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/Conditions.java index 2931517683..9faf5edac8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/Conditions.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/Conditions.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Set; public class Conditions extends ConditionForStep { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ObjectCondition.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ObjectCondition.java index 2117c649a1..edf7ff1d66 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ObjectCondition.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/conditional/ObjectCondition.java @@ -24,13 +24,13 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements.conditional; +import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import lombok.Setter; import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.Tile; import net.runelite.api.TileObject; import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; import java.util.Objects; import java.util.Set; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirement.java index 0c6e999b09..4885ee8542 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirement.java @@ -43,13 +43,13 @@ import net.runelite.api.Item; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.util.Text; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nullable; import javax.annotation.CheckReturnValue; import javax.annotation.Nonnull; import java.awt.*; -import java.util.*; import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -93,7 +93,6 @@ public class ItemRequirement extends AbstractRequirement * Indicates whether the item must be equipped. */ @Setter - @Getter protected boolean mustBeEquipped; public boolean mustBeEquipped() { @@ -647,11 +646,11 @@ public void setAdditionalOptions(Requirement additionalOptions) public String getWikiUrl() { if (getUrlSuffix() != null) { - return "https://oldschool.runescape.wiki/w/" + getUrlSuffix(); + return "https://oldschool.runescape.wiki/w/" + getUrlSuffix() + "#Item_sources"; } if (getId() != -1) { - return "https://oldschool.runescape.wiki/w/Special:Lookup?type=item&id=" + getId(); + return "https://oldschool.runescape.wiki/w/Special:Lookup?type=item&id=" + getId() + "#Item_sources"; } return null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirements.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirements.java index 6b7c039a10..8ff3696cfe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirements.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/ItemRequirements.java @@ -36,8 +36,8 @@ import net.runelite.api.Item; import java.awt.*; -import java.util.*; import java.util.List; +import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/KeyringRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/KeyringRequirement.java index 0326f47b07..7b0567b28d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/KeyringRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/KeyringRequirement.java @@ -24,115 +24,26 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements.item; -import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.collections.KeyringCollection; -import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.gameval.ItemID; -import net.runelite.client.config.ConfigManager; -import java.awt.*; -import java.util.Set; - -// TODO: Convert this to be a TrackedContainer instead? +/// A requirement of a key that can be found on a key ring. +/// +/// This requirement helps the bank tag service show the keyring if the key can be found in the player's key ring. public class KeyringRequirement extends ItemRequirement { - RuneliteRequirement runeliteRequirement; - @Getter KeyringCollection keyringCollection; - ConfigManager configManager; - - ItemRequirement keyring; - - public KeyringRequirement(String name, ConfigManager configManager, KeyringCollection key) + public KeyringRequirement(String name, KeyringCollection key) { super(name, key.getItemID()); - keyring = new ItemRequirement("Steel key ring", ItemID.FAVOUR_KEY_RING); - runeliteRequirement = new RuneliteRequirement(configManager, key.runeliteName(), - "true", key.toChatText()); this.keyringCollection = key; - this.configManager = configManager; - } - - public KeyringRequirement(ConfigManager configManager, KeyringCollection key) - { - super(key.toChatText(), key.getItemID()); - keyring = new ItemRequirement("Steel key ring", ItemID.FAVOUR_KEY_RING); - runeliteRequirement = new RuneliteRequirement(configManager, key.runeliteName(), - "true", key.toChatText()); - this.keyringCollection = key; - this.configManager = configManager; - } - - public String chatboxText() - { - return keyringCollection.toChatText(); - } - - public void setConfigValue(String value) - { - runeliteRequirement.setConfigValue(value); - } - - @Override - public ItemRequirement copy() - { - KeyringRequirement newItem = new KeyringRequirement(getName(), configManager, keyringCollection); - newItem.addAlternates(alternateItems); - newItem.setDisplayItemId(getDisplayItemId()); - newItem.setHighlightInInventory(highlightInInventory); - newItem.setDisplayMatchedItemName(isDisplayMatchedItemName()); - newItem.setConditionToHide(getConditionToHide()); - newItem.setShouldCheckBank(isShouldCheckBank()); - newItem.setTooltip(getTooltip()); - newItem.setUrlSuffix(getUrlSuffix()); - - return newItem; - } - - @Override - public boolean check(Client client) - {; - if (hasKeyOnKeyRing() && keyring.check(client)) - { - return true; - } - - return super.check(client); - } - - public boolean hasKeyOnKeyRing() - { - return runeliteRequirement.check(); - } - - @Override - public Color getColor(Client client, QuestHelperConfig config) - { - if (hasKeyOnKeyRing()) - { - return keyring.getColor(client, config); - } - - return this.check(client) ? config.passColour() : config.failColour(); - } - - protected String getTooltipFromEnumSet(Set containers) - { - String basicTooltip = super.getTooltipFromEnumSet(containers); - if (hasKeyOnKeyRing()) - { - return basicTooltip + " on your key ring."; - } - return basicTooltip; } @Override protected KeyringRequirement copyOfClass() { - return new KeyringRequirement(getName(), configManager, keyringCollection); + return new KeyringRequirement(getName(), keyringCollection); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/TrackedContainers.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/TrackedContainers.java index aefce2c64b..21abbb41d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/TrackedContainers.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/item/TrackedContainers.java @@ -32,5 +32,6 @@ public enum TrackedContainers POTION_STORAGE, GROUP_STORAGE, RUNE_POUCH, + KEY_RING, UNDEFINED } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/DialogRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/DialogRequirement.java index 97f66bb017..d27e7602f7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/DialogRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/DialogRequirement.java @@ -29,6 +29,7 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.events.ChatMessage; +import net.runelite.api.gameval.InterfaceID; import net.runelite.client.util.Text; import java.util.ArrayList; @@ -40,16 +41,23 @@ public class DialogRequirement extends SimpleRequirement @Setter String talkerName; final List text = new ArrayList<>(); - final boolean mustBeActive; + + @Setter + boolean mustBeActive; boolean hasSeenDialog = false; + /// Also allow the dialog message to check MESBOX messages + @Setter + boolean allowMesbox = false; + public DialogRequirement(String... text) { this.talkerName = null; this.text.addAll(Arrays.asList(text)); this.mustBeActive = false; } + public DialogRequirement(String talkerName, String text, boolean mustBeActive) { this.talkerName = talkerName; @@ -75,9 +83,35 @@ public boolean check(Client client) return hasSeenDialog; } + public void validateActiveWidget(Client client) + { + if (!mustBeActive) return; + + var chatModal = client.getWidget(InterfaceID.Chatbox.CHATMODAL); + + if (chatModal == null || chatModal.isHidden()) + { + hasSeenDialog = false; + } + } + public void validateCondition(ChatMessage chatMessage) { - if (chatMessage.getType() != ChatMessageType.DIALOG) return; + if (chatMessage.getType() != ChatMessageType.DIALOG) + { + if (allowMesbox) + { + // This requirement also allows validating the condition against MESBOX entries + if (chatMessage.getType() != ChatMessageType.MESBOX) + { + return; + } + } + else + { + return; + } + } String dialogMessage = chatMessage.getMessage(); if (!hasSeenDialog) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NoFollowerRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NoFollowerRequirement.java index 5538b4c324..c1dace149c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NoFollowerRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NoFollowerRequirement.java @@ -27,11 +27,10 @@ package net.runelite.client.plugins.microbot.questhelper.requirements.npc; import net.runelite.client.plugins.microbot.questhelper.requirements.AbstractRequirement; +import javax.annotation.Nonnull; import net.runelite.api.Client; import net.runelite.api.gameval.VarPlayerID; -import javax.annotation.Nonnull; - public class NoFollowerRequirement extends AbstractRequirement { String text; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NpcRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NpcRequirement.java index 8ccdf7e21b..1e6efe0a98 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NpcRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/npc/NpcRequirement.java @@ -131,7 +131,13 @@ public NpcRequirement(int npcID, String npcName) @Override public boolean check(Client client) { - List found = client.getTopLevelWorldView().npcs().stream() + var localPlayer = client.getLocalPlayer(); + if (localPlayer == null) + { + return false; + } + + List found = localPlayer.getWorldView().npcs().stream() .filter(npc -> npc.getId() == npcID || npc.getComposition().getId() == npcID) .filter(npc -> npcName == null || (npc.getName() != null && npc.getName().equals(npcName))) .collect(Collectors.toList()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/Boosts.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/Boosts.java index f4f56b6e00..1eff7f8781 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/Boosts.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/Boosts.java @@ -38,11 +38,11 @@ public enum Boosts DEFENCE("Defence",21), FARMING("Farming",3), FIREMAKING("Firemaking",1), - FISHING("Fishing",5), + FISHING("Fishing",6), FLETCHING("Fletching",4), HERBLORE("Herblore",4), HITPOINTS("Hitpoints",22), - HUNTER("Hunter",3), + HUNTER("Hunter",6), MAGIC("Magic",19), MINING("Mining",3), PRAYER("Prayer",0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreeInventorySlotRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreeInventorySlotRequirement.java index 79d1b132f3..f5dc54956a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreeInventorySlotRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreeInventorySlotRequirement.java @@ -36,6 +36,7 @@ import net.runelite.api.gameval.InventoryID; import javax.annotation.Nonnull; +import java.util.Locale; /** * Requirement that checks if a player has a required number of slots free in a given diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreePortTaskSlotsRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreePortTaskSlotsRequirement.java index 9340e324b9..4fa1229998 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreePortTaskSlotsRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/FreePortTaskSlotsRequirement.java @@ -27,12 +27,13 @@ package net.runelite.client.plugins.microbot.questhelper.requirements.player; import net.runelite.client.plugins.microbot.questhelper.requirements.AbstractRequirement; -import lombok.Getter; import net.runelite.api.Client; -import net.runelite.api.gameval.VarbitID; import javax.annotation.Nonnull; +import lombok.Getter; +import net.runelite.api.gameval.VarbitID; + /** * Requirement that checks if a player has a required number of Port Task slots free. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/ShipInPortRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/ShipInPortRequirement.java index 3fd9c19176..5853612f55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/ShipInPortRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/player/ShipInPortRequirement.java @@ -28,11 +28,12 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.AbstractRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.util.Port; -import lombok.Getter; import net.runelite.api.Client; -import net.runelite.api.gameval.VarbitID; import javax.annotation.Nonnull; + +import lombok.Getter; +import net.runelite.api.gameval.VarbitID; import java.util.stream.IntStream; /** diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/sailing/HasBoatResistanceRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/sailing/HasBoatResistanceRequirement.java index 5ec4ff4261..c12783702f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/sailing/HasBoatResistanceRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/sailing/HasBoatResistanceRequirement.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements.sailing; +import net.runelite.client.plugins.microbot.questhelper.requirements.AbstractRequirement; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.gameval.VarbitID; -import net.runelite.client.plugins.microbot.questhelper.requirements.AbstractRequirement; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/InventorySlots.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/InventorySlots.java index 3de13dd104..a83d855c33 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/InventorySlots.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/InventorySlots.java @@ -27,9 +27,9 @@ package net.runelite.client.plugins.microbot.questhelper.requirements.util; import net.runelite.api.Client; +import net.runelite.api.gameval.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; -import net.runelite.api.gameval.InventoryID; import java.util.Arrays; import java.util.Objects; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/ItemSlots.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/ItemSlots.java index e693900f06..f6fc9481bf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/ItemSlots.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/ItemSlots.java @@ -26,6 +26,8 @@ */ package net.runelite.client.plugins.microbot.questhelper.requirements.util; +import java.util.ArrayList; +import java.util.List; import lombok.Getter; import net.runelite.api.Client; import net.runelite.api.Item; @@ -38,34 +40,38 @@ @Getter public enum ItemSlots { - ANY_EQUIPPED_AND_INVENTORY(-3, "inventory or equipped", InventorySlots.EQUIPMENT_AND_INVENTORY_SLOTS), - ANY_INVENTORY(-2, "inventory slots", InventorySlots.INVENTORY_SLOTS), - ANY_EQUIPPED(-1, "equipped slots", InventorySlots.EQUIPMENT_SLOTS), - HEAD(0, "head slot"), - CAPE(1, "cape slot"), - AMULET(2, "amulet slot"), - WEAPON(3, "weapon slot"), - BODY(4, "body slot"), - SHIELD(5, "shield slot"), - LEGS(7, "legs slot"), - GLOVES(9, "gloves slot"), - BOOTS(10, "boots slot"), - RING(12, "ring slot"), - AMMO(13, "ammo slot"); + ANY_EQUIPPED_AND_INVENTORY("inventory or equipped", InventorySlots.EQUIPMENT_AND_INVENTORY_SLOTS, -3), + ANY_INVENTORY("inventory slots", InventorySlots.INVENTORY_SLOTS, -2), + ANY_EQUIPPED("equipped slots", InventorySlots.EQUIPMENT_SLOTS, -1), - private final int slotIdx; + EMPTY_HANDS("weapons and shield slot", 3, 5), + BARE_HANDS("weapon, shield and gloves slot", 3, 5, 9), + + HEAD("head slot", 0), + CAPE("cape slot", 1), + AMULET("amulet slot", 2), + WEAPON("weapon slot", 3), + BODY("body slot", 4), + SHIELD("shield slot", 5), + LEGS("legs slot", 7), + GLOVES("gloves slot", 9), + BOOTS("boots slot", 10), + RING("ring slot", 12), + AMMO("ammo slot", 13); + + private final int[] slotIdxs; private final String name; private final InventorySlots inventorySlots; - ItemSlots(int slotIdx, String name) + ItemSlots(String name, int... slotIdx) { - this.slotIdx = slotIdx; + this.slotIdxs = slotIdx; this.name = name; this.inventorySlots = null; } - ItemSlots(int slotIdx, String name, InventorySlots slots) + ItemSlots(String name, InventorySlots slots, int... slotIdx) { - this.slotIdx = slotIdx; + this.slotIdxs = slotIdx; this.name = name; this.inventorySlots = slots; } @@ -90,14 +96,7 @@ public boolean checkInventory(Client client, Predicate predicate) { return false; } - ItemContainer equipment = client.getItemContainer(InventoryID.WORN); - if (equipment == null || getSlotIdx() < 0) // unknown slot - { - return false; - } - Item item = equipment.getItem(getSlotIdx()); - - return predicate.test(item); + return getItems(client).allMatch(predicate); } /** @@ -120,17 +119,21 @@ public boolean contains(Client client, Predicate predicate) { return false; } + return getItems(client).anyMatch(predicate); + } + + private Stream getItems(Client client){ ItemContainer equipment = client.getItemContainer(InventoryID.WORN); - if (equipment == null || getSlotIdx() < 0) // unknown slot - { - return false; - } - Item item = equipment.getItem(getSlotIdx()); - if (item == null) + + List items = new ArrayList<>(); + for(int slotIdx: getSlotIdxs()) { - return false; + if (equipment == null || slotIdx < 0) // unknown slot + { + continue; + } + items.add(equipment.getItem(slotIdx)); } - - return predicate.test(item); + return items.stream(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/Port.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/Port.java index b6ec18cdea..6284c137c2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/Port.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/util/Port.java @@ -36,37 +36,37 @@ @Getter public enum Port { - PORT_SARIM(0, "Port Sarim", ObjectID.SAILING_DOCKING_BUOY_PORT_SARIM, new WorldPoint(3048, 3186, 0), new Zone(new WorldPoint(3045, 3183, 0), new WorldPoint(3061, 3208, 0)), new WorldPoint(3051, 3193, 0), new WorldPoint(3028, 3194, 0), ObjectID.PORT_TASK_BOARD_PORT_SARIM, new WorldPoint(3030, 3197, 0)) - , PANDEMONIUM(1, "the Pandemonium", ObjectID.SAILING_DOCKING_BUOY_THE_PANDEMONIUM, new WorldPoint(3069, 2981, 0), new Zone(new WorldPoint(3065, 2974, 0), new WorldPoint(3084, 2998, 0)), new WorldPoint(3070, 2987, 0), new WorldPoint(3061,2985, 0), ObjectID.PORT_TASK_BOARD_PANDEMONIUM, new WorldPoint(3058, 2958, 0)) -// , LANDS_END(2, "Land's End", ObjectID.SAILING_DOCKING_BUOY_LANDS_END, null, null, null, null, ObjectID.PORT_TASK_BOARD_LANDS_END, null) - , MUSA_POINT(3, "Musa Point", ObjectID.SAILING_DOCKING_BUOY_MUSA_POINT, new WorldPoint(2961, 3152, 0), new Zone(new WorldPoint(2974, 3156, 0), new WorldPoint(2956, 3144, 0)), new WorldPoint(2961, 3146, 0), new WorldPoint(2952, 3150, 0), ObjectID.PORT_TASK_BOARD_MUSA_POINT, new WorldPoint(2956, 3144, 0)) -// , HOSIDIUS(4, "Hosidius", ObjectID.SAILING_DOCKING_BUOY_HOSIDIUS, null, null, null, null, -1, null) -// , PORT_PISCARILIUS(-1, "Port Piscarilius", ObjectID.SAILING_DOCKING_BUOY_PORT_PISCARILIUS, null, null, null, null, ObjectID.PORT_TASK_BOARD_PORT_PISCARILIUS, null) -// , RIMMINGTON(-1, "Rimmington", ObjectID.SAILING_DOCKING_BUOY_RIMMINGTON, null, null, null, null, -1, null) - , CATHERBY(6, "Catherby", ObjectID.SAILING_DOCKING_BUOY_CATHERBY, new WorldPoint(2788, 3409, 0), new Zone(new WorldPoint(2804, 3401, 0), new WorldPoint(2786, 3413, 0)), new WorldPoint(2796, 3412, 0), new WorldPoint(2799, 3413, 0), ObjectID.PORT_TASK_BOARD_CATHERBY, new WorldPoint(2803, 3418, 0)) -// , BRIMHAVEN(-1, "Brimhaven", ObjectID.SAILING_DOCKING_BUOY_BRIMHAVEN, null, null, null, null, ObjectID.PORT_TASK_BOARD_BRIMHAVEN, null) -// , ARDOUGNE(-1, "Ardougne", ObjectID.SAILING_DOCKING_BUOY_ARDOUGNE, null, null, null, null, ObjectID.PORT_TASK_BOARD_ARDOUGNE, null) -// , PORT_KHAZARD(-1, "Port Khazard", ObjectID.SAILING_DOCKING_BUOY_PORT_KHAZARD, null, null, null, null, ObjectID.PORT_TASK_BOARD_PORT_KHAZARD, null) -// , WITCHAVEN(-1, "Witchaven", ObjectID.SAILING_DOCKING_BUOY_WITCHAVEN, null, null, null, null, -1, null) -// , ENTRANA(-1, "Entrana", ObjectID.SAILING_DOCKING_BUOY_ENTRANA, null, null, null, null, -1, null) -// , CIVITAS_ILLA_FORTIS(-1, "Civitas illa Fortis", ObjectID.SAILING_DOCKING_BUOY_CIVITAS_ILLA_FORTIS, null, null, null, null, ObjectID.PORT_TASK_BOARD_CIVITAS_ILLA_FORTIS, null) -// , CORSAIR_COVE(-1, "Corsair Cove", ObjectID.SAILING_DOCKING_BUOY_CORSAIR_COVE, null, null, null, null, ObjectID.PORT_TASK_BOARD_CORSAIR_COVE, null) -// , CAIRN_ISLE(-1, "Cairn Isle", ObjectID.SAILING_DOCKING_BUOY_CAIRN_ISLE, null, null, null, null, -1, null) -// , THE_SUMMER_SHORE(-1, "the Summer Shore", ObjectID.SAILING_DOCKING_BUOY_THE_SUMMER_SHORE, null, null, null, null, ObjectID.PORT_TASK_BOARD_THE_SUMMER_SHORE, null) -// , ALDARIN(-1, "Aldarin", ObjectID.SAILING_DOCKING_BUOY_ALDARIN, null, null, null, null, ObjectID.PORT_TASK_BOARD_ALDARIN, null) -// , RUINS_OF_UNKAH(-1, "Ruins of Unkah", ObjectID.SAILING_DOCKING_BUOY_RUINS_OF_UNKAH, null, null, null, null, ObjectID.PORT_TASK_BOARD_RUINS_OF_UNKAH, null) -// , VOID_KNIGHTS_OUTPOST(-1, "Void Knights Outpost", ObjectID.SAILING_DOCKING_BUOY_VOID_KNIGHTS_OUTPOST, null, null, null, null, ObjectID.PORT_TASK_BOARD_VOID_KNIGHTS_OUTPOST, null) -// , PORT_ROBERTS(-1, "Port Roberts", ObjectID.SAILING_DOCKING_BUOY_PORT_ROBERTS, null, null, null, null, ObjectID.PORT_TASK_BOARD_PORT_ROBERTS, null) -// , RELLEKKA(-1, "Rellekka", ObjectID.SAILING_DOCKING_BUOY_RELLEKKA, null, null, null, null, ObjectID.PORT_TASK_BOARD_RELLEKKA, null) -// , ETCETERIA(-1, "Etceteria", ObjectID.SAILING_DOCKING_BUOY_ETCETERIA, null, null, null, null, ObjectID.PORT_TASK_BOARD_ETCETERIA, null) -// , PORT_TYRAS(-1, "Port Tyras", ObjectID.SAILING_DOCKING_BUOY_PORT_TYRAS, null, null, null, null, ObjectID.PORT_TASK_BOARD_PORT_TYRAS, null) -// , DEEPFIN_POINT(-1, "Deepfin Point", ObjectID.SAILING_DOCKING_BUOY_DEEPFIN_POINT, null, null, null, null, ObjectID.PORT_TASK_BOARD_DEEPFIN_POINT, null) -// , JATIZSO(-1, "Jatizso", ObjectID.SAILING_DOCKING_BUOY_JATIZSO, null, null, null, null, -1, null) -// , NEITIZNOT(-1, "Neitiznot", ObjectID.SAILING_DOCKING_BUOY_NEITIZNOT, null, null, null, null, -1, null) -// , PRIFDDINAS(-1, "Prifddinas", ObjectID.SAILING_DOCKING_BUOY_PRIFDDINAS, null, null, null, null, ObjectID.PORT_TASK_BOARD_PRIFDDINAS, null) -// , PISCATORIS(-1, "Piscatoris", ObjectID.SAILING_DOCKING_BUOY_PISCATORIS, null, null, null, null, -1, null) -// , LUNAR_ISLE(-1, "Lunar Isle", ObjectID.SAILING_DOCKING_BUOY_LUNAR_ISLE, null, null, null, null, ObjectID.PORT_TASK_BOARD_LUNAR_ISLE, null) - ; + PORT_SARIM(0, "Port Sarim", ObjectID.SAILING_DOCKING_BUOY_PORT_SARIM, new WorldPoint(3048, 3186, 0), new Zone(new WorldPoint(3045, 3183, 0), new WorldPoint(3061, 3208, 0)), new WorldPoint(3051, 3193, 0), new WorldPoint(3028, 3194, 0), ObjectID.PORT_TASK_BOARD_PORT_SARIM, new WorldPoint(3030, 3197, 0)), + PANDEMONIUM(1, "the Pandemonium", ObjectID.SAILING_DOCKING_BUOY_THE_PANDEMONIUM, new WorldPoint(3069, 2981, 0), new Zone(new WorldPoint(3065, 2974, 0), new WorldPoint(3084, 2998, 0)), new WorldPoint(3070, 2987, 0), new WorldPoint(3061,2985, 0), ObjectID.PORT_TASK_BOARD_PANDEMONIUM, new WorldPoint(3058, 2958, 0)), + LANDS_END(2, "Land's End", ObjectID.SAILING_DOCKING_BUOY_LANDS_END, new WorldPoint(1515, 3405, 0), new Zone( new WorldPoint(1520, 3408, 0), new WorldPoint(1507, 3393, 0)), new WorldPoint(1507, 3403, 0), new WorldPoint(1506, 3407, 0), ObjectID.PORT_TASK_BOARD_LANDS_END, new WorldPoint(1502, 3407, 0)), + MUSA_POINT(3, "Musa Point", ObjectID.SAILING_DOCKING_BUOY_MUSA_POINT, new WorldPoint(2961, 3152, 0), new Zone(new WorldPoint(2974, 3156, 0), new WorldPoint(2956, 3144, 0)), new WorldPoint(2961, 3146, 0), new WorldPoint(2952, 3150, 0), ObjectID.PORT_TASK_BOARD_MUSA_POINT, new WorldPoint(2956, 3144, 0)), + HOSIDIUS(4, "Hosidius", ObjectID.SAILING_DOCKING_BUOY_HOSIDIUS, new WorldPoint(1719, 3450, 0), null, new WorldPoint(1726, 3452, 0), new WorldPoint(1725, 3460, 0), -1, null), + PORT_PISCARILIUS(-1, "Port Piscarilius", ObjectID.SAILING_DOCKING_BUOY_PORT_PISCARILIUS, new WorldPoint(1840, 3681, 0), new Zone( new WorldPoint(1854, 3686, 0), new WorldPoint(1836, 3674, 0)), new WorldPoint(1845, 3687, 0), new WorldPoint(1837, 3691, 0), ObjectID.PORT_TASK_BOARD_PORT_PISCARILIUS, new WorldPoint(1839, 3691, 0)), + RIMMINGTON(-1, "Rimmington", ObjectID.SAILING_DOCKING_BUOY_RIMMINGTON, new WorldPoint(2908, 3216, 0), null, new WorldPoint(3906, 3225, 0), null, -1, null), + CATHERBY(6, "Catherby", ObjectID.SAILING_DOCKING_BUOY_CATHERBY, new WorldPoint(2788, 3409, 0), new Zone(new WorldPoint(2804, 3401, 0), new WorldPoint(2786, 3413, 0)), new WorldPoint(2796, 3412, 0), new WorldPoint(2799, 3413, 0), ObjectID.PORT_TASK_BOARD_CATHERBY, new WorldPoint(2803, 3418, 0)), + BRIMHAVEN(-1, "Brimhaven", ObjectID.SAILING_DOCKING_BUOY_BRIMHAVEN, new WorldPoint(2755, 3223, 0), new Zone( new WorldPoint(2746, 3219, 0), new WorldPoint(2758, 3239, 0)), new WorldPoint(2758, 3230, 0), new WorldPoint(2769, 3225, 0), ObjectID.PORT_TASK_BOARD_BRIMHAVEN, new WorldPoint(2764, 3227, 0)), + ARDOUGNE(-1, "Ardougne", ObjectID.SAILING_DOCKING_BUOY_ARDOUGNE, new WorldPoint(2663, 3261, 0), null, new WorldPoint(2671, 3265, 0), new WorldPoint(2674, 3269, 0), ObjectID.PORT_TASK_BOARD_ARDOUGNE, new WorldPoint(2676, 3276, 0)), + PORT_KHAZARD(-1, "Port Khazard", ObjectID.SAILING_DOCKING_BUOY_PORT_KHAZARD, new WorldPoint(2663, 3261, 0), new Zone( new WorldPoint(2694, 3171, 0), new WorldPoint(2682, 3153, 0)), new WorldPoint(2686, 3162, 0), new WorldPoint(2684, 3164, 0), ObjectID.PORT_TASK_BOARD_PORT_KHAZARD, new WorldPoint(2678, 3162, 0)), + WITCHAVEN(-1, "Witchaven", ObjectID.SAILING_DOCKING_BUOY_WITCHAVEN, new WorldPoint(2746, 3297, 0), new Zone( new WorldPoint(2759, 3312, 0), new WorldPoint(2741, 3294, 0)), new WorldPoint(2747, 3305, 0), null, -1, null), + ENTRANA(-1, "Entrana", ObjectID.SAILING_DOCKING_BUOY_ENTRANA, new WorldPoint(2880, 3330, 0), new Zone( new WorldPoint(2874, 3322, 0), new WorldPoint(2892, 3340, 0)), new WorldPoint(2879, 3336, 0), new WorldPoint(2874, 3339, 0), -1, null), + CIVITAS_ILLA_FORTIS(-1, "Civitas illa Fortis", ObjectID.SAILING_DOCKING_BUOY_CIVITAS_ILLA_FORTIS, new WorldPoint(1768, 3147, 0), new Zone( new WorldPoint(1764, 3129, 0), new WorldPoint(1774, 3149, 0)), new WorldPoint(1775, 3142, 0), new WorldPoint(1781, 3147, 0), ObjectID.PORT_TASK_BOARD_CIVITAS_ILLA_FORTIS, new WorldPoint(1782, 3142, 0)), + CORSAIR_COVE(-1, "Corsair Cove", ObjectID.SAILING_DOCKING_BUOY_CORSAIR_COVE, new WorldPoint(2585, 3847, 0), new Zone( new WorldPoint(2581, 2834, 0), new WorldPoint(2593, 2847, 0)), new WorldPoint(2580, 2844, 0), new WorldPoint(2581, 2848, 0), ObjectID.PORT_TASK_BOARD_CORSAIR_COVE, new WorldPoint(2579, 2853, 0)), + CAIRN_ISLE(-1, "Cairn Isle", ObjectID.SAILING_DOCKING_BUOY_CAIRN_ISLE, new WorldPoint(2748, 2944, 0), null, new WorldPoint(2750, 2952, 0), new WorldPoint(2756, 2949, 0), -1, null), + SUNSET_COAST(-1, "the Sunset Coast", ObjectID.SAILING_DOCKING_BUOY_SUNSET_COAST, new WorldPoint(1505, 2977, 0), new Zone( new WorldPoint(1500, 2958, 0), new WorldPoint(1511, 2979, 0)), new WorldPoint(1512, 2974, 0), new WorldPoint(1515, 2977, 0), -1, null), + THE_SUMMER_SHORE(-1, "the Summer Shore", ObjectID.SAILING_DOCKING_BUOY_THE_SUMMER_SHORE, new WorldPoint(3168, 2364, 0), new Zone( new WorldPoint(3200, 2353, 0), new WorldPoint(3160, 2372, 0)), new WorldPoint(3174, 2367, 0), new WorldPoint(3173, 2370, 0), ObjectID.PORT_TASK_BOARD_THE_SUMMER_SHORE, new WorldPoint(3183, 2368, 0)), + ALDARIN(-1, "Aldarin", ObjectID.SAILING_DOCKING_BUOY_ALDARIN, new WorldPoint(1457, 2975, 0), new Zone( new WorldPoint(1444, 2970, 0), new WorldPoint(1461, 2984, 0)), new WorldPoint(1452, 2970, 0), new WorldPoint(1449, 2969, 0), ObjectID.PORT_TASK_BOARD_ALDARIN, new WorldPoint(1438, 2939, 0)), + RUINS_OF_UNKAH(-1, "Ruins of Unkah", ObjectID.SAILING_DOCKING_BUOY_RUINS_OF_UNKAH, new WorldPoint(3144, 2818, 0), new Zone( new WorldPoint(3136, 2813, 0), new WorldPoint(3146, 2831, 0)), new WorldPoint(3144, 2825, 0), new WorldPoint(3148, 2826, 0), ObjectID.PORT_TASK_BOARD_RUINS_OF_UNKAH, new WorldPoint(3146, 2828, 0)), + VOID_KNIGHTS_OUTPOST(-1, "Void Knights Outpost", ObjectID.SAILING_DOCKING_BUOY_VOID_KNIGHTS_OUTPOST, new WorldPoint(2643, 2678, 0), new Zone( new WorldPoint(2641, 2675, 0), new WorldPoint(2659, 2687, 0)), new WorldPoint(2651, 2678, 0), new WorldPoint(2652, 2673, 0), ObjectID.PORT_TASK_BOARD_VOID_KNIGHTS_OUTPOST, new WorldPoint(2659, 2672, 0)), + PORT_ROBERTS(-1, "Port Roberts", ObjectID.SAILING_DOCKING_BUOY_PORT_ROBERTS, new WorldPoint(1859, 3302, 0), new Zone( new WorldPoint(1850, 3297, 0), new WorldPoint(1862, 3317, 0)), new WorldPoint(1861, 3307, 0), new WorldPoint(1867, 3306, 0), ObjectID.PORT_TASK_BOARD_PORT_ROBERTS, new WorldPoint(1872, 3303, 0)), + RELLEKKA(-1, "Rellekka", ObjectID.SAILING_DOCKING_BUOY_RELLEKKA, new WorldPoint(2633, 3711, 0), new Zone( new WorldPoint(2624, 3704, 0), new WorldPoint(2636, 3716, 0)), new WorldPoint(2630, 3705, 0), new WorldPoint(2629, 3699, 0), ObjectID.PORT_TASK_BOARD_RELLEKKA, new WorldPoint(2629, 3685, 0)), + ETCETERIA(-1, "Etceteria", ObjectID.SAILING_DOCKING_BUOY_ETCETERIA, new WorldPoint(2618, 3836, 0), new Zone( new WorldPoint(2607, 3833, 0), new WorldPoint(2619, 3839, 0)), new WorldPoint(2613, 2840, 0), new WorldPoint(2612, 3846, 0), ObjectID.PORT_TASK_BOARD_ETCETERIA, new WorldPoint(2617, 3849, 0)), + PORT_TYRAS(-1, "Port Tyras", ObjectID.SAILING_DOCKING_BUOY_PORT_TYRAS, new WorldPoint(2149, 3117, 0), new Zone( new WorldPoint(2132, 3109, 0), new WorldPoint(2152, 3120, 0)), new WorldPoint(2144, 3120, 0), new WorldPoint(2151, 3123, 0), ObjectID.PORT_TASK_BOARD_PORT_TYRAS, new WorldPoint(2146, 3123, 0)), + DEEPFIN_POINT(-1, "Deepfin Point", ObjectID.SAILING_DOCKING_BUOY_DEEPFIN_POINT, new WorldPoint(1930, 2755, 0), new Zone( new WorldPoint(1935, 2743, 0), new WorldPoint(1914, 2759, 0)), new WorldPoint(1923, 2758, 0), new WorldPoint(1928, 2761, 0), ObjectID.PORT_TASK_BOARD_DEEPFIN_POINT, new WorldPoint(1931, 2761, 0)), + JATIZSO(-1, "Jatizso", ObjectID.SAILING_DOCKING_BUOY_JATIZSO, new WorldPoint(2405, 3776, 0), new Zone( new WorldPoint(2404, 3770, 0), new WorldPoint(2422, 3779, 0)), new WorldPoint(2412, 3780, 0), new WorldPoint(2401, 3788, 0), -1, null), + NEITIZNOT(-1, "Neitiznot", ObjectID.SAILING_DOCKING_BUOY_NEITIZNOT, new WorldPoint(2304, 3786, 0), new Zone( new WorldPoint(2298, 3771, 0), new WorldPoint(2307, 3789, 0)), new WorldPoint(2309, 3782, 0), new WorldPoint(2308, 3775, 0), -1, null), + PRIFDDINAS(-1, "Prifddinas", ObjectID.SAILING_DOCKING_BUOY_PRIFDDINAS, new WorldPoint(2165, 3321, 0), new Zone( new WorldPoint(2165, 3307, 0), new WorldPoint(2141, 3325, 0)), new WorldPoint(2158, 3324, 0), new WorldPoint(2170, 3328, 0), ObjectID.PORT_TASK_BOARD_PRIFDDINAS, new WorldPoint(2163, 3326, 0)), + PISCATORIS(-1, "Piscatoris", ObjectID.SAILING_DOCKING_BUOY_PISCATORIS, new WorldPoint(2304, 3696, 0), new Zone( new WorldPoint(2293, 3682, 0), new WorldPoint(2306, 3700, 0)), new WorldPoint(2304, 3689, 0), new WorldPoint(2313, 3693, 0), -1, null), + LUNAR_ISLE(-1, "Lunar Isle", ObjectID.SAILING_DOCKING_BUOY_LUNAR_ISLE, new WorldPoint(2154, 3886, 0), new Zone( new WorldPoint(2151, 3875, 0), new WorldPoint(2163, 3887, 0)), new WorldPoint(2152, 3881, 0), new WorldPoint(2146, 3879, 0), ObjectID.PORT_TASK_BOARD_LUNAR_ISLE, new WorldPoint(2139, 3884, 0));; private final int id; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/var/VarbitRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/var/VarbitRequirement.java index 77aeda7457..ae6267d773 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/var/VarbitRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/var/VarbitRequirement.java @@ -53,7 +53,8 @@ public class VarbitRequirement extends AbstractRequirement @Setter private int requiredValue; private final Operation operation; - private final String displayText; + @Setter + private String displayText; // bit positions private boolean bitIsSet = false; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/zone/ZoneRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/zone/ZoneRequirement.java index c0e6e8fc09..bcd7013b59 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/zone/ZoneRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/requirements/zone/ZoneRequirement.java @@ -33,6 +33,8 @@ import lombok.Getter; import net.runelite.api.Client; import net.runelite.api.Player; +import net.runelite.api.WorldEntity; +import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import javax.annotation.Nonnull; @@ -46,6 +48,13 @@ public class ZoneRequirement extends AbstractRequirement private final boolean checkInZone; private String displayText; + /// Contains the value of the most recent successful zone check. + /// null = no check has succeeded + /// true = the last check was deemed a success (check returned true) + /// false = the last check was deemed a failure (check returned false) + @Getter + private Boolean matchedZoneLastCheck = null; + /** * Check if the player is either in the specified zone. * @@ -107,7 +116,8 @@ public boolean check(Client client) if (player != null && zones != null) { boolean inZone = zones.stream().anyMatch(z -> z.contains(client, player.getLocalLocation())); - return inZone == checkInZone; + matchedZoneLastCheck = inZone == checkInZone; + return matchedZoneLastCheck; } return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/Cheerer.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/Cheerer.java index b1a1726aaa..a16a67e1fe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/Cheerer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/Cheerer.java @@ -45,19 +45,16 @@ public class Cheerer public static void createCheerers(RuneliteObjectManager runeliteObjectManager, Client client, ConfigManager configManager) { cheerers.clear(); - if (client.getLocalPlayer() == null) - { - return; - } createWOM(runeliteObjectManager, client); createZoinkwiz(runeliteObjectManager, client); } private static void createWOM(RuneliteObjectManager runeliteObjectManager, Client client) { - WorldPoint playerPos = client.getLocalPlayer().getWorldLocation(); - WorldPoint pointAbovePlayer = new WorldPoint(playerPos.getX(), playerPos.getY() + 1, playerPos.getPlane()); - FakeNpc wiseOldMan = runeliteObjectManager.createFakeNpc("global", wiseOldManOutfit(client), pointAbovePlayer, 862); + // Spawn the initial NPC in lumbridge. + // When the NPC is activated from the player completing a quest, we will always update the position anyway. + var spawnPos = new WorldPoint(3223, 3218, 0); + FakeNpc wiseOldMan = runeliteObjectManager.createFakeNpc("global", wiseOldManOutfit(client), spawnPos, 862); wiseOldMan.setName("Wise Old Man"); wiseOldMan.setExamine("Loves questing."); wiseOldMan.addExamineAction(runeliteObjectManager); @@ -86,9 +83,10 @@ private static Model wiseOldManOutfit(Client client) private static void createZoinkwiz(RuneliteObjectManager runeliteObjectManager, Client client) { - WorldPoint playerPos = client.getLocalPlayer().getWorldLocation(); - WorldPoint pointAbovePlayer = new WorldPoint(playerPos.getX(), playerPos.getY() + 1, playerPos.getPlane()); - FakeNpc zoinkwiz = runeliteObjectManager.createFakeNpc("global", zoinkwizOutfit(client), pointAbovePlayer, 862); + // Spawn the initial NPC in lumbridge. + // When the NPC is activated from the player completing a quest, we will always update the position anyway. + var spawnPos = new WorldPoint(3223, 3218, 0); + FakeNpc zoinkwiz = runeliteObjectManager.createFakeNpc("global", zoinkwizOutfit(client), spawnPos, 862); zoinkwiz.setName("Zoinkwiz"); zoinkwiz.setExamine("Loves questing."); zoinkwiz.addExamineAction(runeliteObjectManager); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/GlobalFakeObjects.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/GlobalFakeObjects.java index ef91ce9c5c..ed1ffbdc2d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/GlobalFakeObjects.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/GlobalFakeObjects.java @@ -25,9 +25,18 @@ package net.runelite.client.plugins.microbot.questhelper.runeliteobjects; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import net.runelite.client.plugins.microbot.questhelper.questinfo.PlayerQuests; +import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.PlayerQuestStateRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.util.Operation; +import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.ReplacedNpc; import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.RuneliteObjectManager; +import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.WidgetReplacement; +import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetDetails; import lombok.Setter; import net.runelite.api.Client; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InterfaceID; +import net.runelite.api.gameval.NpcID; import net.runelite.client.config.ConfigManager; public class GlobalFakeObjects diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/ExtendedRuneliteObject.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/ExtendedRuneliteObject.java index 0e315b7445..2f940912e6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/ExtendedRuneliteObject.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/ExtendedRuneliteObject.java @@ -45,8 +45,8 @@ import net.runelite.client.game.chatbox.ChatboxPanelManager; import java.awt.*; -import java.util.*; import java.util.List; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Supplier; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/RuneliteObjectManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/RuneliteObjectManager.java index 68e1af5f9f..e9d2200bdf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/RuneliteObjectManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/runeliteobjects/extendedruneliteobjects/RuneliteObjectManager.java @@ -29,15 +29,15 @@ import com.google.inject.Singleton; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetDetails; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.*; import net.runelite.api.Menu; import net.runelite.api.Point; +import net.runelite.api.*; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.*; import net.runelite.api.gameval.InterfaceID; -import net.runelite.api.gameval.SpriteID; import net.runelite.api.widgets.Widget; +import net.runelite.api.gameval.SpriteID; import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.Hooks; import net.runelite.client.chat.ChatColorType; @@ -54,8 +54,8 @@ import java.awt.*; import java.awt.image.BufferedImage; -import java.util.*; import java.util.List; +import java.util.*; import java.util.function.Consumer; // This will hold all RuneliteObjects @@ -817,15 +817,18 @@ public void onGameTick(GameTick event) @Subscribe public void onClientTick(ClientTick event) { + var localPlayer = client.getLocalPlayer(); + + if (localPlayer == null) + { + return; + } + bufferRedClickAnimation = Math.floorMod(bufferRedClickAnimation + 1, ANIMATION_PERIOD); if (bufferRedClickAnimation == 0) { redClickAnimationFrame++; } - if (client.getLocalPlayer() == null) - { - return; - } WorldPoint playerPosition = WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation()); runeliteObjectGroups.forEach((groupID, extendedRuneliteObjectGroup) -> { for (ExtendedRuneliteObject extendedRuneliteObject : extendedRuneliteObjectGroup.extendedRuneliteObjects) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/AchievementDiaryStepManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/AchievementDiaryStepManager.java index f14f066e13..588eb47c9c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/AchievementDiaryStepManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/AchievementDiaryStepManager.java @@ -36,6 +36,7 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.NpcLootReceived; +import net.runelite.client.events.ServerNpcLoot; import javax.inject.Singleton; @@ -46,7 +47,7 @@ public class AchievementDiaryStepManager static Zone workshop; @Getter - static Requirement inWorkshop; + static ZoneRequirement inWorkshop; @Getter static RuneliteRequirement killedFire, killedEarth, killedWater, killedAir; @@ -68,7 +69,7 @@ private static void setupKandarin(ConfigManager configManager) public static void check(Client client) { - if (!inWorkshop.check(client)) + if (!Boolean.FALSE.equals(inWorkshop.getMatchedZoneLastCheck()) && !inWorkshop.check(client)) { killedFire.setConfigValue("false"); killedEarth.setConfigValue("false"); @@ -78,14 +79,27 @@ public static void check(Client client) } @Subscribe - public void onNpcLootReceived(final NpcLootReceived npcLootReceived) + public static void onServerNpcLoot(final ServerNpcLoot npcLootReceived) { - final NPC npc = npcLootReceived.getNpc(); + final var npc = npcLootReceived.getComposition(); - final int id = npc.getId(); - if (id == NpcID.ELEMENTAL_FIRE) killedFire.setConfigValue("true"); - if (id == NpcID.ELEMENTAL_EARTH) killedEarth.setConfigValue("true"); - if (id == NpcID.ELEMENTAL_WATER) killedWater.setConfigValue("true"); - if (id == NpcID.ELEMENTAL_AIR) killedAir.setConfigValue("true"); + switch (npc.getId()) + { + case NpcID.ELEMENTAL_FIRE: + killedFire.setConfigValue("true"); + break; + + case NpcID.ELEMENTAL_EARTH: + killedEarth.setConfigValue("true"); + break; + + case NpcID.ELEMENTAL_WATER: + killedWater.setConfigValue("true"); + break; + + case NpcID.ELEMENTAL_AIR: + killedAir.setConfigValue("true"); + break; + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/BarbarianTrainingStateTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/BarbarianTrainingStateTracker.java deleted file mode 100644 index f8820c6761..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/BarbarianTrainingStateTracker.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2024, Zoinkwiz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.microbot.questhelper.statemanagement; - -import net.runelite.client.plugins.microbot.questhelper.config.ConfigKeys; -import net.runelite.client.plugins.microbot.questhelper.requirements.*; -import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; -import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.runelite.RuneliteRequirement; -import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; -import net.runelite.client.plugins.microbot.questhelper.requirements.widget.WidgetTextRequirement; -import net.runelite.api.Client; -import net.runelite.api.gameval.InterfaceID; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.EventBus; - -import javax.inject.Inject; -import javax.inject.Singleton; - -@Singleton -public class BarbarianTrainingStateTracker -{ - @Inject - Client client; - - Requirement taskedWithFishing, taskedWithHarpooning, taskedWithFarming, taskedWithBowFiremaking, taskedWithPyre, taskedWithPotSmashing, - taskedWithSpears, taskedWithHastae, taskedWithHerblore, plantedSeed, smashedPot, litFireWithBow, sacrificedRemains, caughtBarbarianFish, - caughtFishWithoutHarpoon, madePotion, madeSpear, madeHasta, finishedFishing, finishedHarpoon, finishedSeedPlanting, finishedPotSmashing, - finishedFiremaking, finishedPyre, finishedSpear, finishedHasta, finishedHerblore; - - RequirementValidator reqs; - - - public void startUp(ConfigManager configManager, EventBus eventBus) - { - taskedWithFishing = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_FISHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Certainly. Take the rod from under my bed and fish in the lake. When you have caught a few fish, I am sure you will be ready to talk more with me."), - new DialogRequirement("Alas, I do not sense that you have been successful in your fishing yet. The look in your eyes is not that of the osprey."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "fish with a new") - ) - ); - - taskedWithHarpooning = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_HARPOON.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("... and I thought fishing was a safe way to pass the time."), - new DialogRequirement("I see you need encouragement in learning the ways of fishing without a harpoon."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "fish with my") - ) - ); - - taskedWithFarming = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_SEED_PLANTING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Remember to be calm, and good luck."), - new DialogRequirement("I see you have yet to be successful in planting a seed with your fists."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "plant a seed with") - ) - ); - - taskedWithPotSmashing = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_POT_SMASHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("May the spirits guide you into success."), - new DialogRequirement("You have not yet attempted to plant a tree. Why not?"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to smash pots after") - ) - ); - - taskedWithBowFiremaking = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_FIREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("The spirits will aid you. The power they supply will guide your hands. Go and benefit from their guidance upon oak logs."), - new DialogRequirement("By now you know my response."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "light a fire with") - ) - ); - - taskedWithPyre = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_PYREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Dive into the whirlpool in the lake to the east. The spirits will use their abilities to ensure you arrive in the correct location. Be warned, their influence fades, so you must find y"), - new DialogRequirement("I will repeat myself fully, since this is quite complex. Listen well."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to create pyre ships") - ) - ); - - taskedWithHerblore = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_HERBLORE.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Have I become so predictable? But yes, I do indeed require a potion. It is of the highest importance that you bring me a lesser attack potion combined with fish roe."), - new DialogRequirement("Do you have my potion?"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to make a new type") - ) - ); - - taskedWithSpears = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Note well that you will require wood for the spear shafts. The quality of wood must be similar to that of the metal involved."), - new DialogRequirement("You do not exude the presence of one who has poured his soul into manufacturing spears."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "Otto has tasked me with learning how to smith spears") - ) - ); - - taskedWithHastae = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_STARTED_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Indeed. You may use our special anvil for this spear type too. The ways of black and dragon hastae are beyond our knowledge, however."), - new DialogRequirement("Take some wood and metal and make a spear upon the
nearby anvil, then you may return to me. As an
example, you may use bronze bars with normal logs or
iron bars with oak logs."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, " has tasked me with learning how to smith a hasta") - ) - ); - - // Finished tasks - finishedFishing = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_FISHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Patience young one. These are fish which are fat with eggs rather than fat of flesh. It is these eggs that are the thing to make use of."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to catch a fish with the new rod!") - ), - "Finished Barbarian Fishing" - ); - - finishedHarpoon = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_HARPOON.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("I mean that when you eventually die and find peace, at least the spirits you encounter will be your friends. Alas for you adventurous sort, the natural ways of passing are close to imp"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to fish with my hands!") - ), - "Finished Barbarian Harpooning" - ); - - finishedSeedPlanting = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_SEED_PLANTING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("No child, but we all have potential to improve our strength."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to plant a seed with my fists!") - ), - "Finished Barbarian Seed Planting" - ); - - finishedPotSmashing = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_POT_SMASHING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("It will become more natural with practice."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to smash a plant pot without littering!") - ), - "Finished Barbarian Pot Smashing" - ); - - finishedFiremaking = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_FIREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("Fine news indeed!"), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to light a fire with a bow!") - ), - "Finished Barbarian Firemaking" - ); - - finishedPyre = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_PYREMAKING.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("On this great day you have my eternal thanks. May you find riches while rescuing my spiritual ancestors in the caverns for many moons to come."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a pyre ship!") - ), - "Finished Barbarian Pyremaking" - ); - - finishedSpear = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("The manufacture of spears is now yours as a speciality. Use your skill well."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to smith a spear!") - ), - "Finished Barbarian Spear Smithing" - ); - - finishedHasta = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("To live life to it's fullest of course - that you may be a peaceful spirit when your time ends."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a hasta!") - ), - "Finished Barbarian Hasta Smithing" - ); - - finishedHerblore = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_FINISHED_HERBLORE.getKey(), - new Conditions(true, LogicType.OR, - new DialogRequirement("I will take that off your hands now. I will say no more than that I am eternally grateful."), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I managed to create a new potion!") - ), - "Finished Barbarian Herblore" - ); - - // Mid-conditions - plantedSeed = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_PLANTED_SEED.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You plant "), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to plant a seed with my fists!") - ) - ); - - smashedPot = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_SMASHED_POT.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You plant "), - new ChatMessageRequirement(" sapling"), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smash a pot without littering!") - ) - ); - - litFireWithBow = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_BOW_FIRE.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("The fire catches and the logs begin to burn."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to light a fire with a bow!") - ) - ); - - sacrificedRemains = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_PYRE_MADE.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("The ancient barbarian is laid to rest."), - new ChatMessageRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to create a pyre ship! I should let") - ) - ); - - caughtBarbarianFish = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_BARBFISHED.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You catch a leaping trout.", "You catch a leaping salmon.", "You catch a leaping sturgeon."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to catch a fish with the new rod! I should let") - ) - ); - - caughtFishWithoutHarpoon = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_HARPOONED_FISH.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You catch a raw tuna.", "You catch a swordfish.", "You catch a shark.", "You catch a shark!"), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to fish with my hands! I should let Otto know") - ) - ); - - madePotion = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_MADE_POTION.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You combine your potion with the fish eggs."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to make a new type of potion! I should let") - ) - ); - - madeSpear = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_MADE_SPEAR.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You make a "), - new ChatMessageRequirement(" spear."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smith a spear!") - ) - ); - - madeHasta = new RuneliteRequirement( - configManager, ConfigKeys.BARBARIAN_TRAINING_MADE_HASTA.getKey(), - new Conditions(true, LogicType.OR, - new MultiChatMessageRequirement( - new ChatMessageRequirement("You make a "), - new ChatMessageRequirement(" hasta."), - new MesBoxRequirement("You feel you have learned more of barbarian ways. Otto might wish to talk to you more.") - ), - new WidgetTextRequirement(InterfaceID.Questjournal.TEXTLAYER, true, "I've managed to smith a hasta!") - ) - ); - - - reqs = new RequirementValidator(client, eventBus, - taskedWithFishing, taskedWithHarpooning, taskedWithFarming, taskedWithBowFiremaking, taskedWithPyre, taskedWithPotSmashing, - taskedWithSpears, taskedWithHastae, taskedWithHerblore, plantedSeed, smashedPot, litFireWithBow, sacrificedRemains, caughtBarbarianFish, - caughtFishWithoutHarpoon, madePotion, madeSpear, madeHasta, finishedFishing, finishedHarpoon, finishedSeedPlanting, finishedPotSmashing, - finishedFiremaking, finishedPyre, finishedSpear, finishedHasta, finishedHerblore - ); - - eventBus.register(reqs); - reqs.startUp(); - } - - - public void shutDown(EventBus eventBus) - { - eventBus.unregister(reqs); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/PlayerStateManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/PlayerStateManager.java index de991b8078..4844da0f1c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/PlayerStateManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/statemanagement/PlayerStateManager.java @@ -26,12 +26,13 @@ import net.runelite.client.plugins.microbot.questhelper.collections.KeyringCollection; import net.runelite.client.plugins.microbot.questhelper.domain.AccountType; -import net.runelite.client.plugins.microbot.questhelper.requirements.item.KeyringRequirement; +import net.runelite.client.plugins.microbot.questhelper.managers.QuestContainerManager; import net.runelite.client.plugins.microbot.questhelper.runeliteobjects.extendedruneliteobjects.QuestCompletedWidget; import lombok.Getter; import lombok.NonNull; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; +import net.runelite.api.Item; import net.runelite.api.Player; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; @@ -39,36 +40,33 @@ import net.runelite.api.events.VarbitChanged; import net.runelite.api.gameval.VarbitID; import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.EventBus; +import net.runelite.client.config.RuneScapeProfileType; import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.microbot.util.player.Rs2Player; +import net.runelite.client.events.ServerNpcLoot; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; +import java.util.ArrayList; @Singleton public class PlayerStateManager { + private final KeyringCollection[] keyringKeys = KeyringCollection.values(); + @Inject Client client; @Inject ConfigManager configManager; - @Inject - EventBus eventBus; - @Inject QuestCompletedWidget playerQuestCompleteWidget; - @Inject - BarbarianTrainingStateTracker barbarianTrainingStateTracker; - - List keyringKeys; - WorldPoint lastPlayerPos = null; + private boolean loggedInStateKnown = false; + private RuneScapeProfileType worldType; + /** * The type of the logged in account (e.g. ironman, hardcore ironman) * Quest helpers should use this value when building their requirements instead of fetching the value themselves. @@ -78,42 +76,44 @@ public class PlayerStateManager public void startUp() { - keyringKeys = KeyringCollection.allKeyRequirements(configManager); AchievementDiaryStepManager.setup(configManager); - barbarianTrainingStateTracker.startUp(configManager, eventBus); } public void shutDown() { - barbarianTrainingStateTracker.shutDown(eventBus); } @Subscribe public void onChatMessage(ChatMessage chatMessage) { - if (keyringKeys == null || chatMessage.getType() != ChatMessageType.GAMEMESSAGE) return; + if (chatMessage.getType() != ChatMessageType.GAMEMESSAGE) return; if (chatMessage.getMessage().contains("to your key ring.")) { - for (KeyringRequirement keyringKey : keyringKeys) + for (var keyringKey : keyringKeys) { if (chatMessage.getMessage().contains("You add the " + keyringKey.chatboxText())) { - keyringKey.setConfigValue("true"); + keyringKey.setHasKeyOnKeyRing(configManager, true); + + QuestContainerManager.getKeyRingData().add(client.getTickCount(), keyringKey.getItemID(), 1); + break; } } } - if (chatMessage.getMessage().contains("from your key ring.")) + else if (chatMessage.getMessage().contains("from your key ring.")) { - for (KeyringRequirement keyringKey : keyringKeys) + for (var keyringKey : keyringKeys) { if (chatMessage.getMessage().contains("You remove the " + keyringKey.chatboxText())) { - keyringKey.setConfigValue("false"); + keyringKey.setHasKeyOnKeyRing(configManager, false); + + QuestContainerManager.getKeyRingData().removeByItemID(client.getTickCount(), keyringKey.getItemID()); + break; } } } - - if (chatMessage.getMessage().contains("Achievement Diary Stage Task - ")) + else if (chatMessage.getMessage().contains("Achievement Diary Stage Task - ")) { AchievementDiaryStepManager.check(client); } @@ -125,7 +125,7 @@ public void onGameTick(GameTick gameTick) Player player = client.getLocalPlayer(); if (player != null) { - WorldPoint newPos = Rs2Player.getWorldLocation(); + WorldPoint newPos = player.getWorldLocation(); if (newPos != null && lastPlayerPos != null) { if (newPos.distanceTo(lastPlayerPos) != 0) @@ -134,6 +134,8 @@ public void onGameTick(GameTick gameTick) } } lastPlayerPos = newPos; + + AchievementDiaryStepManager.check(client); } } @@ -160,4 +162,60 @@ public String getPlayerName() } return client.getLocalPlayer().getName(); } + + public void loadInitialStateFromConfig() + { + if (loggedInStateKnown) + { + return; + } + + var localPlayer = client.getLocalPlayer(); + if (localPlayer != null && localPlayer.getName() != null) + { + loggedInStateKnown = true; + loadState(); + } + } + + private void loadState() + { + // Only re-load from config if loading from a new profile + if (!RuneScapeProfileType.getCurrent(client).equals(worldType)) + { + // Load key ring state from config + loadKeyRingFromConfig(); + } + } + + private void loadKeyRingFromConfig() + { + var keys = new ArrayList(); + + for (var keyringKey : keyringKeys) + { + if (keyringKey.hasKeyOnKeyRing(configManager)) + { + keys.add(new Item(keyringKey.getItemID(), 1)); + } + } + + QuestContainerManager.getKeyRingData().update(client.getTickCount(), keys.toArray(new Item[0])); + } + + public void emptyState() + { + worldType = null; + } + + public void setUnknownInitialState() + { + loggedInStateKnown = false; + } + + @Subscribe + public void onServerNpcLoot(ServerNpcLoot event) + { + AchievementDiaryStepManager.onServerNpcLoot(event); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/BoardShipStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/BoardShipStep.java index ef3e894728..c3b19d18ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/BoardShipStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/BoardShipStep.java @@ -8,7 +8,6 @@ import lombok.NonNull; import net.runelite.api.gameval.ObjectID; import net.runelite.client.ui.overlay.components.PanelComponent; - import java.util.ArrayList; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ConditionalStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ConditionalStep.java index 9802adc2c3..e4033952d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ConditionalStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ConditionalStep.java @@ -30,7 +30,9 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.ChatMessageRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.MultiChatMessageRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.InitializableRequirement; +import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.NpcCondition; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.npc.DialogRequirement; @@ -41,13 +43,14 @@ import lombok.Setter; import net.runelite.api.GameState; import net.runelite.api.events.*; +import net.runelite.api.gameval.InterfaceID; import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.ui.overlay.components.PanelComponent; import java.awt.*; -import java.util.*; import java.util.List; +import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -107,9 +110,16 @@ public ConditionalStep(QuestHelper questHelper, Integer id, QuestStep step, Stri this.id = id; } + public void addStep(ConditionalStep step) + { + var newSet = new HashSet<>(step.steps.keySet()); + newSet.remove(null); + addStep(passOnceCompleted(new Conditions(LogicType.OR, new ArrayList<>(newSet)), step), step, false); + } + public void addStep(Requirement requirement, QuestStep step) { - addStep(requirement, step, false); + addStep(passOnceCompleted(requirement, step), step, false); } // Each addStep can have an ID. When you add an ID, it keeps a separate ID to Steps OrderedHashSet. @@ -119,11 +129,49 @@ public void addStep(Requirement requirement, QuestStep step) public void addStep(Requirement requirement, QuestStep step, boolean isLockable) { step.setLockable(isLockable); - this.steps.put(requirement, step); + this.steps.put(passOnceCompleted(requirement, step), step); checkForConditions(requirement); } + private Requirement passOnceCompleted(Requirement completion, QuestStep step) + { + return completion; +// var manualOverride = step.getSidebarManualSkipRequirement(); +// if (completion == null || manualOverride == null) +// { +// return completion; +// } +// // Only auto-tick the sidebar when completion becomes true (rising edge). If we setShouldPass every +// // tick while the game still reports the step complete, an explicit untick is overwritten immediately. +// final boolean[] completionWasPassingLastCheck = { false }; +// return not(new Requirement() +// { +// @Override +// public boolean check(Client client) +// { +// if (manualOverride.check(client)) +// { +// completionWasPassingLastCheck[0] = true; +// return true; +// } +// boolean passed = completion.check(client); +// if (passed && !completionWasPassingLastCheck[0]) +// { +// manualOverride.setShouldPass(true); +// } +// completionWasPassingLastCheck[0] = passed; +// return passed; +// } +// +// @Override +// public @NotNull String getDisplayText() +// { +// return completion.getDisplayText(); +// } +// }); + } + private void checkForConditions(Requirement requirement) { checkForChatConditions(requirement); @@ -269,6 +317,17 @@ public void handleChatMessage(ChatMessage chatMessage, boolean parentDefinedRecu handleChildRequirementValidation(step -> step.handleChatMessage(chatMessage, parentDefinedRecursion), parentDefinedRecursion); } + @Subscribe + public void onWidgetClosed(WidgetClosed event) + { + final var DIALOG_GROUP_IDS = List.of(InterfaceID.CHAT_LEFT, InterfaceID.CHAT_RIGHT, InterfaceID.OBJECTBOX); + if (!DIALOG_GROUP_IDS.contains(event.getGroupId())) return; + + clientThread.invokeAtTickEnd(() -> { + dialogConditions.forEach(requirement -> requirement.validateActiveWidget(client)); + }); + } + @Subscribe public void onNpcSpawned(NpcSpawned event) { @@ -428,6 +487,7 @@ public void makeWidgetOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) .map(ItemRequirement.class::cast) .collect(Collectors.toList()); renderInventory(graphics, activeDp, itemRequirements, false); + renderBank(graphics, requirements); for (AbstractWidgetHighlight widgetHighlights : widgetsToHighlight) { widgetHighlights.highlightChoices(graphics, client, plugin); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DetailedQuestStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DetailedQuestStep.java index 106aaf186e..ee85486802 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DetailedQuestStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DetailedQuestStep.java @@ -43,17 +43,17 @@ import lombok.Getter; import lombok.NonNull; import lombok.Setter; -import net.runelite.api.*; import net.runelite.api.Menu; import net.runelite.api.Point; +import net.runelite.api.*; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.ItemDespawned; import net.runelite.api.events.ItemSpawned; -import net.runelite.api.gameval.SpriteID; import net.runelite.api.widgets.Widget; +import net.runelite.api.gameval.SpriteID; import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.PluginMessage; @@ -65,8 +65,8 @@ import java.awt.*; import java.awt.image.BufferedImage; -import java.util.*; import java.util.List; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -304,11 +304,6 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) return; } - if (inCutscene) - { - return; - } - if (!markedTiles.isEmpty()) { for (QuestTile location : markedTiles) @@ -359,11 +354,6 @@ public void makeWorldArrowOverlayHint(Graphics2D graphics, QuestHelperPlugin plu return; } - if (inCutscene) - { - return; - } - if (currentRender < (MAX_RENDER_SIZE / 2)) { renderArrow(graphics); @@ -378,11 +368,6 @@ public void makeWorldLineOverlayHint(Graphics2D graphics, QuestHelperPlugin plug return; } - if (inCutscene) - { - return; - } - if (linePoints != null && linePoints.size() > 1) { WorldLines.drawLinesOnWorld(graphics, client, linePoints, getQuestHelper().getConfig().targetOverlayColor()); @@ -468,6 +453,13 @@ public void makeWidgetOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) .collect(Collectors.toList()); renderInventory(graphics, definedPoint, itemRequirements, false); renderInventory(graphics, definedPoint, teleportRequirements, true); + + // TODO: Add a config to turn off as well? + if (!questHelper.getQuestHelperPlugin().isBankTabOpen()) + { + renderBank(graphics, requirements); + } + for (AbstractWidgetHighlight widgetHighlights : widgetsToHighlight) { widgetHighlights.highlightChoices(graphics, client, plugin); @@ -494,11 +486,6 @@ public void renderMapArrows(Graphics2D graphics) return; } - if (inCutscene) - { - return; - } - WorldPoint point = mapPoint.getWorldPoint(); if (currentRender < MAX_RENDER_SIZE / 2 || !getQuestHelper().getConfig().haveMinimapArrowFlash()) @@ -559,7 +546,7 @@ public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plu { super.makeOverlayHint(panelComponent, plugin, additionalText, new ArrayList<>()); - if (inCutscene || hideRequirements) + if (hideRequirements) { return; } @@ -688,10 +675,6 @@ private boolean requirementContainsID(ItemRequirement requirement, Collection ids, Graphics2D graphics) { - if (inCutscene) - { - return; - } Player player = client.getLocalPlayer(); if (player == null) @@ -812,7 +795,7 @@ protected void renderHoveredMenuEntryPanel(PanelComponent panelComponent, String if (currentMenuEntries != null) { - Point mousePosition = client.getMouseCanvasPosition(); + net.runelite.api.Point mousePosition = client.getMouseCanvasPosition(); int menuX = menu.getMenuX(); int menuY = menu.getMenuY(); int menuWidth = menu.getMenuWidth(); @@ -881,7 +864,14 @@ public void setShortestPath() { return; } - var playerWp = client.getLocalPlayer().getWorldLocation(); + + var localPlayer = client.getLocalPlayer(); + if (localPlayer == null) + { + return; + } + + var playerWp = localPlayer.getWorldLocation(); if (playerWp == null) { return; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DigStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DigStep.java index 26e40a7638..048f6aec1f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DigStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/DigStep.java @@ -29,6 +29,8 @@ import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; +import java.awt.*; +import java.awt.image.BufferedImage; import lombok.Setter; import net.runelite.api.Player; import net.runelite.api.coords.LocalPoint; @@ -38,9 +40,6 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.ui.overlay.OverlayUtil; -import java.awt.*; -import java.awt.image.BufferedImage; - public class DigStep extends DetailedQuestStep { private final ItemRequirement spade; @@ -97,11 +96,6 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) { super.makeWorldOverlayHint(graphics, plugin); - if (inCutscene) - { - return; - } - LocalPoint localLocation = definedPoint.resolveLocalPoint(client); if (localLocation == null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/EmoteStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/EmoteStep.java index 8eecf548ee..367ad426a6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/EmoteStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/EmoteStep.java @@ -98,24 +98,30 @@ public void makeWidgetOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) void scrollToWidget(Widget widget) { - final Widget parent = client.getWidget(InterfaceID.Emote.CONTENTS); + final Widget parent = client.getWidget(InterfaceID.Emote.SCROLLABLE); if (widget == null || parent == null) { return; } + int averageCentralY = 0; + int nonnullCount = 0; + averageCentralY += widget.getRelativeY() + widget.getHeight() / 2; + nonnullCount += 1; + averageCentralY /= nonnullCount; final int newScroll = Math.max(0, Math.min(parent.getScrollHeight(), - (widget.getRelativeY() + widget.getHeight() / 2) - parent.getHeight() / 2)); + averageCentralY - parent.getHeight() / 2)); client.runScript( ScriptID.UPDATE_SCROLLBAR, - InterfaceID.Emote.SCROLLBAR, - InterfaceID.Emote.CONTENTS, + InterfaceID.Emote.SCROLLBAR, + InterfaceID.Emote.SCROLLABLE, newScroll ); } + @Override protected void setupIcon() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcEmoteStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcEmoteStep.java index 8c32b29a11..ed3219f6ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcEmoteStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcEmoteStep.java @@ -24,12 +24,12 @@ */ package net.runelite.client.plugins.microbot.questhelper.steps; -import lombok.Getter; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.steps.emote.QuestEmote; import net.runelite.client.plugins.microbot.questhelper.steps.overlay.IconOverlay; +import lombok.Getter; import net.runelite.api.ScriptID; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.InterfaceID; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcStep.java index f68d90fd5e..10610b0ed3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/NpcStep.java @@ -25,7 +25,6 @@ */ package net.runelite.client.plugins.microbot.questhelper.steps; -import lombok.Getter; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; @@ -33,9 +32,10 @@ import net.runelite.client.plugins.microbot.questhelper.steps.overlay.DirectionArrow; import net.runelite.client.plugins.microbot.questhelper.steps.tools.DefinedPoint; import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; +import lombok.Getter; import lombok.Setter; -import net.runelite.api.*; import net.runelite.api.Point; +import net.runelite.api.*; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.NpcChanged; @@ -63,8 +63,8 @@ public class NpcStep extends DetailedQuestStep protected final int npcID; protected final List alternateNpcIDs = new ArrayList<>(); - @Setter @Getter + @Setter protected boolean allowMultipleHighlights; @Getter @@ -210,6 +210,19 @@ public void scanForNpcs() { addNpcToListGivenMatchingID(npc, this::npcPassesChecks, npcs); } + + /* TODO: Configurable boolean per NpcStep for whether to consider all world views + This is as you're likely to want to only highlight stuff on your own ship, not on others' + */ + for (WorldView worldView : client.getTopLevelWorldView().worldViews()) + { + if (worldView == playerWorldView) continue; + + for (NPC npc : worldView.npcs()) + { + addNpcToListGivenMatchingID(npc, this::npcPassesChecks, npcs); + } + } } public NpcStep addAlternateNpcs(Integer... alternateNpcIDs) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ObjectStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ObjectStep.java index 9cf33dfdd9..36e74b7800 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ObjectStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/ObjectStep.java @@ -24,7 +24,6 @@ */ package net.runelite.client.plugins.microbot.questhelper.steps; -import lombok.Getter; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; @@ -33,9 +32,11 @@ import net.runelite.client.plugins.microbot.questhelper.steps.overlay.DirectionArrow; import net.runelite.client.plugins.microbot.questhelper.steps.tools.DefinedPoint; import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; +import lombok.Getter; +import lombok.NonNull; import lombok.Setter; -import net.runelite.api.*; import net.runelite.api.Point; +import net.runelite.api.*; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.*; @@ -67,6 +68,11 @@ public class ObjectStep extends DetailedQuestStep @Setter private boolean revalidateObjects; + /// Force the highlight to use the clickbox highlight, regardless of the user's setting. + /// This is useful if the object you're trying to highlight is technically visible but cannot feasibly be outline-highlighted. + @Setter + private boolean forceClickboxHighlight = false; + public ObjectStep(QuestHelper questHelper, int objectID, WorldPoint worldPoint, String text, Requirement... requirements) { super(questHelper, worldPoint, text, requirements); @@ -147,11 +153,9 @@ protected void loadObjects() { // TODO: This needs to be tested in Shadow of the Storm's Demon Room objects.clear(); - loadObjectsInWorldView(client.getTopLevelWorldView()); - var playerWorldView = client.getLocalPlayer().getWorldView(); - if (playerWorldView != client.getTopLevelWorldView()) + for (WorldView worldView : client.getTopLevelWorldView().worldViews()) { - loadObjectsInWorldView(client.getLocalPlayer().getWorldView()); + loadObjectsInWorldView(worldView); } } @@ -308,11 +312,6 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) return; } - if (inCutscene) - { - return; - } - Point mousePosition = client.getMouseCanvasPosition(); if (client.getLocalPlayer() == null) @@ -352,10 +351,15 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) Color configColor = getQuestHelper().getConfig().targetOverlayColor(); - QuestHelperConfig.ObjectHighlightStyle highlightStyle = visibilityHelper.isObjectVisible(tileObject) + var isObjectVisible = visibilityHelper.isObjectVisible(tileObject); + var highlightStyle = isObjectVisible ? questHelper.getConfig().highlightStyleObjects() : CLICK_BOX; + if (highlightStyle == QuestHelperConfig.ObjectHighlightStyle.OUTLINE && forceClickboxHighlight) { + highlightStyle = QuestHelperConfig.ObjectHighlightStyle.CLICK_BOX; + } + switch (highlightStyle) { case CLICK_BOX: @@ -385,7 +389,7 @@ public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) if (iconItemID != -1 && closestObject != null && questHelper.getConfig().showSymbolOverlay()) { Shape clickbox = closestObject.getClickbox(); - if (clickbox != null && !inCutscene) + if (clickbox != null) { Rectangle2D boundingBox = clickbox.getBounds2D(); graphics.drawImage(icon, (int) boundingBox.getCenterX() - 15, (int) boundingBox.getCenterY() - 10, @@ -465,12 +469,6 @@ protected void handleObjects(TileObject object) return; } - var worldViewsToConsider = List.of(client.getTopLevelWorldView(), client.getLocalPlayer().getWorldView()); - if (!worldViewsToConsider.contains(object.getWorldView())) - { - return; - } - if (object.getId() == objectID || alternateObjectIDs.contains(object.getId())) { setObjects(object); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PortTaskStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PortTaskStep.java index cadd9f9aa3..c1b4f4c0e7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PortTaskStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PortTaskStep.java @@ -9,12 +9,10 @@ import lombok.Getter; import net.runelite.api.gameval.ObjectID; import net.runelite.api.gameval.VarbitID; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; - import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.and; import static net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicHelper.or; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleStep.java index 61a81e980a..8ae37997ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleStep.java @@ -1,6 +1,5 @@ package net.runelite.client.plugins.microbot.questhelper.steps; -import lombok.Getter; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; @@ -8,6 +7,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.Subscribe; +import lombok.Getter; import java.awt.*; import java.util.HashSet; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleWrapperStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleWrapperStep.java index b2f10303d9..3b42bf606c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleWrapperStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/PuzzleWrapperStep.java @@ -32,11 +32,12 @@ import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.conditional.Conditions; import net.runelite.client.plugins.microbot.questhelper.requirements.util.LogicType; -import net.runelite.client.plugins.microbot.questhelper.steps.choice.DialogChoiceStep; import lombok.Getter; +import net.runelite.client.plugins.microbot.questhelper.steps.choice.DialogChoiceStep; import lombok.NonNull; import net.runelite.client.ui.overlay.components.PanelComponent; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/QuestStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/QuestStep.java index c5f9068481..7102a40628 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/QuestStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/QuestStep.java @@ -30,6 +30,7 @@ import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestUtil; +import net.runelite.client.plugins.microbot.questhelper.requirements.ManualRequirement; import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; import net.runelite.client.plugins.microbot.questhelper.requirements.item.ItemRequirement; import net.runelite.client.plugins.microbot.questhelper.steps.choice.*; @@ -65,10 +66,11 @@ import net.runelite.client.util.ColorUtil; import net.runelite.client.util.ImageUtil; +import javax.annotation.Nullable; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.*; import java.util.List; +import java.util.*; import java.util.regex.Pattern; import static net.runelite.client.plugins.microbot.questhelper.overlays.QuestHelperOverlay.TITLED_CONTENT_COLOR; @@ -126,9 +128,7 @@ public abstract class QuestStep implements Module @Setter private Requirement lockingCondition; - private int currentCutsceneStatus = 0; - protected boolean inCutscene; - + @Getter @Setter protected boolean allowInCutscene = false; @@ -161,6 +161,24 @@ public abstract class QuestStep implements Module @Setter private boolean showInSidebar = true; + /** + * When set, the Quest Helper sidebar can show a small skip control that toggles this requirement and persists per helper. + */ + @Nullable + @Getter + @Setter + private ManualRequirement sidebarManualSkipRequirement; + + /** + * Stable id for {@link #sidebarManualSkipRequirement} persistence (e.g. maker order slot id). + */ + @Nullable + @Getter + @Setter + private String sidebarManualSkipPersistenceKey; + + + protected String lastDialogSeen = ""; @Setter @@ -248,19 +266,6 @@ public void addSubSteps(Collection substeps) @Subscribe public void onVarbitChanged(VarbitChanged event) { - if (!allowInCutscene) - { - int newCutsceneStatus = client.getVarbitValue(VarbitID.CUTSCENE_STATUS); - if (currentCutsceneStatus == 0 && newCutsceneStatus == 1) - { - enteredCutscene(); - } - else if (currentCutsceneStatus == 1 && newCutsceneStatus == 0) - { - leftCutscene(); - } - currentCutsceneStatus = newCutsceneStatus; - } } @Subscribe @@ -290,16 +295,6 @@ public void addText(String newLine) text.add(newLine); } - public void enteredCutscene() - { - inCutscene = true; - } - - public void leftCutscene() - { - inCutscene = false; - } - public void highlightChoice() { choices.checkChoices(client, lastDialogSeen); @@ -623,6 +618,45 @@ protected Widget getInventoryWidget() return client.getWidget(InterfaceID.Inventory.ITEMS); } + protected Widget getBankWidget() + { + return client.getWidget(InterfaceID.Bankmain.ITEMS); + } + + protected void renderBank(Graphics2D graphics, List passedRequirements) + { + Widget bankWidget = getBankWidget(); + if (bankWidget == null || bankWidget.isHidden()) + { + return; + } + Color baseColor = questHelper.getConfig().targetOverlayColor(); + + if (bankWidget.getDynamicChildren() == null) return; + + + for (Widget item : bankWidget.getDynamicChildren()) + { + for (Requirement requirement : passedRequirements) + { + if (isValidRequirementForRenderInBank(requirement, item)) + { + highlightItem(item, baseColor, graphics); + } + } + } + } + + private boolean isValidRequirementForRenderInBank(Requirement requirement, Widget item) + { + return requirement instanceof ItemRequirement && isValidRenderRequirementInBank((ItemRequirement) requirement, item); + } + + protected boolean isValidRenderRequirementInBank(ItemRequirement requirement, Widget item) + { + return (item.getItemId() > 0 && !item.isHidden() && requirement.getAllIds().contains(item.getItemId())); + } + protected void renderInventory(Graphics2D graphics, DefinedPoint definedPoint, List passedRequirements, boolean distanceLimit) { Widget inventoryWidget = getInventoryWidget(); @@ -649,13 +683,13 @@ protected void renderInventory(Graphics2D graphics, DefinedPoint definedPoint, L if (isValidRequirementForRenderInInventory(requirement, item)) { - highlightInventoryItem(item, baseColor, graphics); + highlightItem(item, baseColor, graphics); } } } } - private void highlightInventoryItem(Widget item, Color color, Graphics2D graphics) + private void highlightItem(Widget item, Color color, Graphics2D graphics) { Rectangle slotBounds = item.getBounds(); switch (questHelper.getConfig().highlightStyleInventoryItems()) @@ -740,4 +774,14 @@ public PuzzleWrapperStep puzzleWrapStep(boolean hiddenInSidebar) { return new PuzzleWrapperStep(getQuestHelper(), this).withNoHelpHiddenInSidebar(hiddenInSidebar); } + + public void withPersistedManualSkip(String persistenceKey) { + setSidebarManualSkipWithPersistenceKey(new ManualRequirement(), persistenceKey); + } + + public void setSidebarManualSkipWithPersistenceKey(ManualRequirement requirement, String persistenceKey) + { + setSidebarManualSkipRequirement(requirement); + setSidebarManualSkipPersistenceKey(persistenceKey); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WidgetStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WidgetStep.java index bb9179ff23..23c03336cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WidgetStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WidgetStep.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.microbot.questhelper.steps; -import lombok.Getter; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; import net.runelite.client.plugins.microbot.questhelper.steps.widget.WidgetDetails; +import lombok.Getter; import lombok.Setter; import net.runelite.api.widgets.Widget; @@ -39,8 +39,8 @@ public class WidgetStep extends DetailedQuestStep { - @Setter @Getter + @Setter protected List widgetDetails = new ArrayList<>(); protected List> extraWidgetOverlayHintFunctions = new ArrayList<>(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WorldEntityStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WorldEntityStep.java new file mode 100644 index 0000000000..158ea87c3d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/WorldEntityStep.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2026, Zoinkwiz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.microbot.questhelper.steps; + +import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; +import net.runelite.client.plugins.microbot.questhelper.questhelpers.QuestHelper; +import net.runelite.client.plugins.microbot.questhelper.requirements.Requirement; +import net.runelite.client.plugins.microbot.questhelper.steps.overlay.DirectionArrow; +import net.runelite.client.plugins.microbot.questhelper.steps.tools.DefinedPoint; +import net.runelite.client.plugins.microbot.questhelper.steps.tools.QuestPerspective; +import net.runelite.api.WorldEntity; +import net.runelite.api.WorldEntityConfig; +import net.runelite.api.WorldView; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.NpcID; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.util.ColorUtil; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.Arrays; + +public class WorldEntityStep extends DetailedQuestStep +{ + public final int worldEntityConfigID; + + // Used to know where to put the hint arrow + private Shape lastFrameStructure; + + public WorldEntityStep(QuestHelper questHelper, int worldEntityConfigID, DefinedPoint definedPoint, String text, Requirement... requirements) + { + super(questHelper, definedPoint, text, requirements); + this.worldEntityConfigID = worldEntityConfigID; + } + + public WorldEntityStep(QuestHelper questHelper, int worldEntityConfigID, WorldPoint worldPoint, String text, Requirement... requirements) + { + this(questHelper, worldEntityConfigID, DefinedPoint.of(worldPoint), text, requirements); + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) + { + super.makeWorldOverlayHint(graphics, plugin); + + lastFrameStructure = null; + + WorldEntity worldEntity = findWorldEntity(); + if (worldEntity == null) return; + + // Currently fine as only one boat per world view. Perhaps in the future an issue where multiple things exist in a world view? + Shape structure = QuestPerspective.getAreaFromWorldView(client, worldEntity.getWorldView()); + if (structure == null) return; + + lastFrameStructure = structure; + + Color configColor = getQuestHelper().getConfig().targetOverlayColor(); + OverlayUtil.renderHoverableArea( + graphics, + structure, + client.getMouseCanvasPosition(), + ColorUtil.colorWithAlpha(configColor, 20), + configColor.darker(), + configColor + ); + } + + + @Override + public void renderArrow(Graphics2D graphics) + { + if (hideWorldArrow || !questHelper.getConfig().showMiniMapArrow()) + { + return; + } + + Shape structure = lastFrameStructure; + if (structure == null) + { + super.renderArrow(graphics); + return; + } + + Rectangle bounds = structure.getBounds(); + if (bounds.width <= 0 || bounds.height <= 0) + { + super.renderArrow(graphics); + return; + } + + int tipX = bounds.x + bounds.width / 2; + int tipY = bounds.y; + DirectionArrow.drawWorldArrow(graphics, getQuestHelper().getConfig().targetOverlayColor(), tipX, tipY); + } + + + private WorldEntity findWorldEntity() + { + WorldEntity worldEntity = findWorldEntityInWorldView(client.getTopLevelWorldView(), worldEntityConfigID); + if (worldEntity != null) + { + return worldEntity; + } + + for (WorldView worldView : client.getTopLevelWorldView().worldViews()) + { + worldEntity = findWorldEntityInWorldView(worldView, worldEntityConfigID); + if (worldEntity != null) + { + return worldEntity; + } + } + + return null; + } + + public static WorldEntity findWorldEntityInWorldView(WorldView worldView, int configId) + { + if (worldView == null) + { + return null; + } + + for (WorldEntity worldEntity : worldView.worldEntities()) + { + WorldEntityConfig config = worldEntity.getConfig(); + if (config != null && config.getId() == configId) + { + return worldEntity; + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/DialogChoiceStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/DialogChoiceStep.java index 4d291340f8..61a259381e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/DialogChoiceStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/DialogChoiceStep.java @@ -1,10 +1,10 @@ package net.runelite.client.plugins.microbot.questhelper.steps.choice; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import java.util.Map; import lombok.Getter; import lombok.Setter; -import java.util.Map; import java.util.regex.Pattern; public class DialogChoiceStep extends WidgetChoiceStep diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/WidgetChoiceStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/WidgetChoiceStep.java index 35f3018419..2ed8a0c4f8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/WidgetChoiceStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/choice/WidgetChoiceStep.java @@ -25,6 +25,7 @@ package net.runelite.client.plugins.microbot.questhelper.steps.choice; import net.runelite.client.plugins.microbot.questhelper.QuestHelperConfig; +import java.util.Map; import lombok.Getter; import lombok.Setter; import net.runelite.api.Client; @@ -34,7 +35,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.regex.Pattern; public class WidgetChoiceStep @@ -54,6 +54,7 @@ public class WidgetChoiceStep protected int excludedGroupId; protected int excludedChildId; + @Getter private final int choiceById; @Getter @@ -64,6 +65,7 @@ public class WidgetChoiceStep protected int varbitValue = -1; protected final Map varbitValueToAnswer; + @Getter protected boolean shouldNumber = false; @Setter diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/emote/QuestEmote.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/emote/QuestEmote.java index 67cd6f540f..b7f64b0a27 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/emote/QuestEmote.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/emote/QuestEmote.java @@ -44,7 +44,9 @@ public enum QuestEmote STAMP("Stamp", SpriteID.Emotes.STAMP), FLAP("Flap", SpriteID.Emotes.FLAP), SLAP_HEAD("Slap Head", SpriteID.Emotes.SLAP_HEAD), - SPIN("Spin", SpriteID.Emotes.SPIN); + SALUTE("Salute", SpriteID.Emotes.SALUTE), + SPIN("Spin", SpriteID.Emotes.SPIN), + SIT("Sit", 5248); private String name; private int spriteId; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/overlay/DirectionArrow.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/overlay/DirectionArrow.java index c76e78aa95..19b56fbad7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/overlay/DirectionArrow.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/overlay/DirectionArrow.java @@ -33,8 +33,8 @@ import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; @@ -193,7 +193,7 @@ protected static void createMinimapDirectionArrow(Graphics2D graphics, Client cl drawMinimapArrow(graphics, line, color); } - @NotNull + @Nonnull private static Line2D.Double getLine(Point playerPosOnMinimap, Point destinationPosOnMinimap) { double xDiff = playerPosOnMinimap.getX() - destinationPosOnMinimap.getX(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/DefinedPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/DefinedPoint.java index 158e0f611e..7794b12f2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/DefinedPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/DefinedPoint.java @@ -32,7 +32,6 @@ import net.runelite.api.WorldView; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; - import javax.annotation.Nullable; import java.util.List; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/QuestPerspective.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/QuestPerspective.java index d758cfce97..a140ee668e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/QuestPerspective.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/tools/QuestPerspective.java @@ -25,8 +25,16 @@ package net.runelite.client.plugins.microbot.questhelper.steps.tools; import net.runelite.client.plugins.microbot.questhelper.requirements.zone.Zone; -import net.runelite.api.*; +import net.runelite.api.Client; +import net.runelite.api.DecorativeObject; +import net.runelite.api.GameObject; +import net.runelite.api.GroundObject; +import net.runelite.api.Perspective; import net.runelite.api.Point; +import net.runelite.api.Tile; +import net.runelite.api.WallObject; +import net.runelite.api.WorldView; +import net.runelite.api.Player; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.InterfaceID; @@ -34,8 +42,8 @@ import net.runelite.api.widgets.Widget; import java.awt.*; -import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.awt.geom.Area; +import java.util.*; import java.util.List; public class QuestPerspective @@ -77,8 +85,7 @@ public static WorldPoint getWorldPointConsideringWorldView(Client client, LocalP } var mainLocal = worldEntity.transformToMainWorld(localPoint); - return WorldPoint.fromLocal(client.getTopLevelWorldView(), - mainLocal.getX(), mainLocal.getY(), client.getTopLevelWorldView().getPlane()); + return WorldPoint.fromLocalInstance(client, mainLocal, client.getTopLevelWorldView().getPlane()); } else { @@ -123,8 +130,7 @@ public static WorldPoint getWorldPointConsideringWorldView(Client client, WorldV } var mainLocal = worldEntity.transformToMainWorld(localPoint); - return WorldPoint.fromLocal(client.getTopLevelWorldView(), - mainLocal.getX(), mainLocal.getY(), client.getTopLevelWorldView().getPlane()); + return WorldPoint.fromLocalInstance(client, mainLocal, client.getTopLevelWorldView().getPlane()); } else { @@ -266,10 +272,10 @@ public static Point getMinimapPoint(Client client, WorldPoint start, WorldPoint return null; } - final int angle = client.getCameraYawTarget() & 0x7FF; + final int angle = client.getCameraYawTarget() & 0x3FFF; - final int sin = Perspective.SINE[angle]; - final int cos = Perspective.COSINE[angle]; + final int sin = Perspective.SINE14[angle]; + final int cos = Perspective.COSINE14[angle]; final int xx = y * sin + cos * x >> 16; final int yy = sin * x - y * cos >> 16; @@ -359,6 +365,73 @@ private static void addToPoly(Client client, Polygon areaPoly, LocalPoint localP } } + public static Shape getAreaFromWorldView(Client client, WorldView view) + { + if (view == null || view.getScene() == null) + { + return null; + } + + Tile[][][] tiles = view.getScene().getTiles(); + + Area area = new Area(); + for (Tile[][] planeTiles : tiles) + { + if (planeTiles == null) continue; + for (Tile[] column : planeTiles) + { + if (column == null) continue; + for (Tile tile : column) + { + if (tile == null) continue; + addTileHulls(area, client, tile); + } + } + } + + return area.isEmpty() ? null : area; + } + + private static void addTileHulls(Area area, Client client, Tile tile) + { + GameObject[] gameObjects = tile.getGameObjects(); + if (gameObjects != null) + { + for (GameObject go : gameObjects) + { + if (go == null || !isUnnamedScenery(client, go.getId())) continue; + addHull(area, go.getConvexHull()); + } + } + + WallObject wall = tile.getWallObject(); + if (wall != null && isUnnamedScenery(client, wall.getId())) + { + addHull(area, wall.getConvexHull()); + addHull(area, wall.getConvexHull2()); + } + + GroundObject ground = tile.getGroundObject(); + if (ground != null && isUnnamedScenery(client, ground.getId())) + { + addHull(area, ground.getConvexHull()); + } + } + + private static void addHull(Area target, Shape hull) + { + if (hull != null) + { + target.add(new Area(hull)); + } + } + + private static boolean isUnnamedScenery(Client client, int objectId) + { + var def = client.getObjectDefinition(objectId); + return def != null && Objects.equals(def.getName(), "null"); + } + /** * Compares a quest-defined {@link WorldPoint} with a runtime {@link LocalPoint}, normalizing * both into the top-level world space so they can be compared safely across WorldViews. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/widget/WidgetHighlight.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/widget/WidgetHighlight.java index 90e9ad5b2f..2229e47193 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/widget/WidgetHighlight.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/steps/widget/WidgetHighlight.java @@ -25,6 +25,7 @@ package net.runelite.client.plugins.microbot.questhelper.steps.widget; import net.runelite.client.plugins.microbot.questhelper.QuestHelperPlugin; +import net.runelite.client.plugins.microbot.questhelper.domain.QuetzalDestination; import lombok.Getter; import lombok.Setter; import net.runelite.api.Client; @@ -38,6 +39,7 @@ public class WidgetHighlight extends AbstractWidgetHighlight { @Getter protected final int interfaceID; + @Getter protected final int childChildId; @@ -138,6 +140,18 @@ public static WidgetHighlight createShopItemHighlight(int itemIdRequirement) return w; } + /** + * Create a widget highlight that highlights the given destination in the quetzal interface + * @param quetzalDestination The quetzal destination to highlight + * @return a fully built WidgetHighlight + */ + public static WidgetHighlight createQuetzalHighlight(QuetzalDestination quetzalDestination) + { + var w = new WidgetHighlight(InterfaceID.QuetzalMenu.ICONS, true); + w.modelIdRequirement = quetzalDestination.modelID; + return w; + } + @Override public void highlightChoices(Graphics2D graphics, Client client, QuestHelperPlugin questHelper) { @@ -154,6 +168,7 @@ private void highlightChoices(Widget parentWidget, Graphics2D graphics, QuestHel Widget[] widgets = parentWidget.getChildren(); Widget[] staticWidgets = parentWidget.getStaticChildren(); + var dynamicWidgets = parentWidget.getDynamicChildren(); if (childChildId != -1 && widgets != null) { @@ -171,6 +186,10 @@ private void highlightChoices(Widget parentWidget, Graphics2D graphics, QuestHel { highlightChoices(widget, graphics, questHelper); } + for (var widget : dynamicWidgets) + { + highlightChoices(widget, graphics, questHelper); + } } highlightWidget(graphics, questHelper, parentWidget); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/util/Utils.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/util/Utils.java index 11b5140149..5dfacb00f8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/util/Utils.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/questhelper/util/Utils.java @@ -36,7 +36,6 @@ import net.runelite.api.gameval.VarbitID; import net.runelite.client.util.ColorUtil; import org.apache.commons.lang3.tuple.Pair; -import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import java.awt.*; @@ -52,7 +51,7 @@ public class Utils * @return {@link AccountType} * @apiNote This function should only be called from the client thread. */ - public AccountType getAccountType(@NotNull Client client) + public AccountType getAccountType(@Nonnull Client client) { if (client.getGameState() != GameState.LOGGED_IN) { From fe771870a1255bbee0e008d4f4635d837e312f0b Mon Sep 17 00:00:00 2001 From: infuse21 Date: Sun, 19 Jul 2026 17:26:34 +0100 Subject: [PATCH 5/5] regen client-thread-guardrail-baseline.txt removed toll-gate helper pattern to avoid guardrail violation --- .../microbot/util/walker/Rs2Walker.java | 8 +--- .../client-thread-guardrail-baseline.txt | 48 +++++++++---------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java index 9afa31c64c..6bf2a33f90 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/walker/Rs2Walker.java @@ -8585,12 +8585,6 @@ private static int transportHandlingPreference(Transport transport) { return 0; } - private static boolean isAlKharidTollGateTransport(Transport transport, TileObject tileObject) { - return isAlKharidTollGateTransport(transport) - && tileObject != null - && isAlKharidTollGateObjectId(tileObject.getId()); - } - private static boolean isAlKharidTollGateTransport(Transport transport) { return transport != null && isAlKharidTollGateObjectId(transport.getObjectId()) @@ -8664,7 +8658,7 @@ private static boolean handleObjectExceptions(Transport transport, TileObject ti } } - if (isAlKharidTollGateTransport(transport, tileObject) && isPayTollAction(transport.getAction())) { + if (isAlKharidTollGateTransport(transport) && isPayTollAction(transport.getAction())) { return handleAlKharidTollGate(transport); } diff --git a/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt b/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt index a2605ab88d..dab8036f3b 100644 --- a/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt +++ b/runelite-client/src/test/resources/threadsafety/client-thread-guardrail-baseline.txt @@ -783,6 +783,7 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#invokeCharterDestinat net.runelite.client.plugins.microbot.util.walker.Rs2Walker#invokeCharterDestinationWidget(Widget, String): boolean -> net.runelite.api.widgets.Widget#getIndex(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCatalogTransportObject(TileObject): boolean -> net.runelite.api.TileObject#getId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCatalogTransportObject(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isClientThread(): boolean -> net.runelite.api.Client#isClientThread(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCloseToRegion(int, int, int): boolean -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isCloseToRegion(int, int, int): boolean -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isDoorComposition(ObjectComposition, List): boolean -> net.runelite.api.ObjectComposition#getImpostorIds(): int[] @@ -797,32 +798,32 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isPendingRouteDoorObj net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isPendingRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isUnresolvedRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.ObjectComposition#getName(): String net.runelite.client.plugins.microbot.util.walker.Rs2Walker#isUnresolvedRouteDoorObject(TileObject, WorldPoint, WorldPoint, WorldPoint, int): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$40(WorldPoint, WorldPoint, WorldPoint, List, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$41(WorldPoint, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$38(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$41(WorldPoint, WorldPoint, WorldPoint, List, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$findDoorNearSegment$42(WorldPoint, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$39(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleFairyRing$185(Transport, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$154(Widget, Object[]): boolean -> net.runelite.api.widgets.Widget#getOnOpListener(): Object[] -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$156(String): boolean -> net.runelite.api.widgets.Widget#getText(): String -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$132(int, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$138(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$138(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$139(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$139(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleRockfall$21(WorldPoint, Tile): boolean -> net.runelite.api.Tile#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$112(int, boolean, TileObject): boolean -> net.runelite.api.ObjectComposition#getName(): String -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$112(int, boolean, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$114(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$115(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$116(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleDoors$40(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleFairyRing$187(Transport, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$156(Widget, Object[]): boolean -> net.runelite.api.widgets.Widget#getOnOpListener(): Object[] +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleMinigameTeleport$158(String): boolean -> net.runelite.api.widgets.Widget#getText(): String +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$134(int, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$140(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$140(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$141(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleObjectExceptions$141(WorldPoint, TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleRockfall$22(WorldPoint, Tile): boolean -> net.runelite.api.Tile#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$113(int, boolean, boolean, TileObject): boolean -> net.runelite.api.ObjectComposition#getName(): String +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$113(int, boolean, boolean, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$115(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$116(TileObject): boolean -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$117(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$119(int, List, TileObject): boolean -> net.runelite.api.TileObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$120(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$146(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$147(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$118(Transport, Object): Integer -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$120(int, List, TileObject): boolean -> net.runelite.api.TileObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleTransports$121(Transport, TileObject): int -> net.runelite.api.TileObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$148(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$handleWildernessObelisk$149(Transport, GameObject): boolean -> net.runelite.api.GameObject#getId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$processWalk$2(): boolean -> net.runelite.api.widgets.Widget#getSpriteId(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$processWalk$3(): boolean -> net.runelite.api.widgets.Widget#getSpriteId(): int -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$tryHandleBlockingPathObjectsWithTimeout$68(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint +net.runelite.client.plugins.microbot.util.walker.Rs2Walker#lambda$tryHandleBlockingPathObjectsWithTimeout$69(WorldPoint, GameObject): boolean -> net.runelite.api.GameObject#getWorldLocation(): WorldPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.WorldView#isInstance(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#localPointForWorld(WorldPoint): LocalPoint -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint @@ -838,7 +839,6 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#processWalk(WorldPoin net.runelite.client.plugins.microbot.util.walker.Rs2Walker#resolveDoorSegment(List, int): WorldPoint[] -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#resolveDoorSegment(List, int): WorldPoint[] -> net.runelite.api.Scene#isInstance(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#resolveDoorSegment(List, int): WorldPoint[] -> net.runelite.api.WorldView#getScene(): Scene -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#setStart(WorldPoint): void -> net.runelite.api.Client#isClientThread(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#setTarget(WorldPoint, String): void -> net.runelite.api.Client#getLocalPlayer(): Player net.runelite.client.plugins.microbot.util.walker.Rs2Walker#staminaThreshold(): int -> net.runelite.api.Client#getLocalPlayer(): Player net.runelite.client.plugins.microbot.util.walker.Rs2Walker#staminaThreshold(): int -> net.runelite.api.Player#getName(): String @@ -865,11 +865,9 @@ net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastLocal(LocalPo net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkFastLocal(LocalPoint): void -> net.runelite.api.WorldView#getPlane(): int net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkNextToInstance(GameObject): void -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkNextToInstance(GameObject): void -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithBankedTransportsAndState(WorldPoint, int, boolean): WalkerState -> net.runelite.api.Client#isClientThread(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithBankedTransportsAndStateLocked(WorldPoint, int, boolean): WalkerState -> net.runelite.api.Client#getTopLevelWorldView(): WorldView net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithBankedTransportsAndStateLocked(WorldPoint, int, boolean): WalkerState -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithStateInternal(WorldPoint, int): WalkerState -> net.runelite.api.Client#getTopLevelWorldView(): WorldView -net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithStateInternal(WorldPoint, int): WalkerState -> net.runelite.api.Client#isClientThread(): boolean net.runelite.client.plugins.microbot.util.walker.Rs2Walker#walkWithStateInternal(WorldPoint, int): WalkerState -> net.runelite.api.coords.LocalPoint#fromWorld(WorldView, WorldPoint): LocalPoint net.runelite.client.plugins.microbot.util.widget.Rs2Widget#checkBoundsOverlapWidgetInMainModal(Rectangle, int, int): boolean -> net.runelite.api.widgets.Widget#isHidden(): boolean net.runelite.client.plugins.microbot.util.widget.Rs2Widget#checkWidgetAndDescendantsForOverlapCanvas(Widget, Rectangle, int, int): boolean -> net.runelite.api.widgets.Widget#getBounds(): Rectangle