|
7 | 7 | import net.runelite.client.plugins.microbot.api.player.models.Rs2PlayerModel; |
8 | 8 | import net.runelite.client.plugins.microbot.api.tileobject.Rs2TileObjectCache; |
9 | 9 | import net.runelite.client.plugins.microbot.api.tileobject.models.Rs2TileObjectModel; |
| 10 | +import net.runelite.client.plugins.microbot.sailing.AlchOrder; |
10 | 11 | import net.runelite.client.plugins.microbot.sailing.SailingConfig; |
11 | 12 | import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; |
| 13 | +import net.runelite.client.plugins.microbot.util.inventory.Rs2ItemModel; |
12 | 14 | import net.runelite.client.plugins.microbot.util.magic.Rs2Magic; |
13 | 15 | import net.runelite.client.plugins.microbot.util.math.Rs2Random; |
14 | 16 | import net.runelite.client.plugins.microbot.util.player.Rs2Player; |
|
17 | 19 | import java.util.Arrays; |
18 | 20 | import java.util.Comparator; |
19 | 21 | import java.util.List; |
| 22 | +import java.util.stream.Collectors; |
20 | 23 |
|
21 | 24 | import static net.runelite.client.plugins.microbot.util.Global.sleep; |
22 | 25 | import static net.runelite.client.plugins.microbot.util.Global.sleepUntil; |
@@ -63,19 +66,22 @@ public void run(SailingConfig config) { |
63 | 66 | return; |
64 | 67 | } |
65 | 68 |
|
| 69 | + // Check inventory FIRST before deciding whether to salvage |
| 70 | + if (isInventoryFull()) { |
| 71 | + log.info("Inventory full, handling before salvaging"); |
| 72 | + handleFullInventory(config, player); |
| 73 | + return; |
| 74 | + } |
| 75 | + |
| 76 | + // Inventory has space — go find a wreck and salvage |
66 | 77 | var nearbyWreck = findNearestWreck(player.getWorldLocation()); |
67 | 78 | if (nearbyWreck == null) { |
68 | 79 | log.info("No shipwreck found nearby"); |
69 | 80 | sleep(WAIT_TIME); |
70 | | - dropJunk(config); |
71 | 81 | return; |
72 | 82 | } |
73 | 83 |
|
74 | | - if (isInventoryFull()) { |
75 | | - handleFullInventory(config, player); |
76 | | - } else { |
77 | | - deploySalvagingHook(player); |
78 | | - } |
| 84 | + deploySalvagingHook(player); |
79 | 85 |
|
80 | 86 | } catch (Exception ex) { |
81 | 87 | log.error("Error in salvaging script", ex); |
@@ -117,9 +123,17 @@ private void handleFullInventory(SailingConfig config, Rs2PlayerModel player) { |
117 | 123 | if (hasSalvageItems() && !isPlayerAnimating(player)) { |
118 | 124 | depositSalvageOrDrop(config); |
119 | 125 | } else { |
| 126 | + // 1. Drop junk first to make room for casket loot |
| 127 | + dropJunk(config); |
| 128 | + // 2. Open caskets — now there's space for the loot to land |
| 129 | + if (config.openCaskets()) { |
| 130 | + openCaskets(); |
| 131 | + } |
| 132 | + // 3. Alch anything on the alch list (including new loot from caskets) |
120 | 133 | if (config.enableAlching()) { |
121 | 134 | alchItems(config); |
122 | 135 | } |
| 136 | + // 4. Drop anything leftover from casket loot that's also on the drop list |
123 | 137 | dropJunk(config); |
124 | 138 | } |
125 | 139 | } |
@@ -162,30 +176,88 @@ private void deploySalvagingHook(Rs2PlayerModel player) { |
162 | 176 | } |
163 | 177 | } |
164 | 178 |
|
| 179 | + private void openCaskets() { |
| 180 | + while (Rs2Inventory.hasItem("casket")) { |
| 181 | + int slotsBefore = Rs2Inventory.emptySlotCount(); |
| 182 | + log.info("Opening casket ({} casket(s) remaining)", Rs2Inventory.count("casket")); |
| 183 | + Rs2Inventory.interact("casket", "Open"); |
| 184 | + sleepUntil(() -> !Rs2Inventory.hasItem("casket") || |
| 185 | + Rs2Inventory.emptySlotCount() != slotsBefore, 5000); |
| 186 | + if (Rs2Inventory.hasItem("casket") && Rs2Inventory.emptySlotCount() == slotsBefore) { |
| 187 | + log.warn("Casket open had no effect, stopping casket loop"); |
| 188 | + break; |
| 189 | + } |
| 190 | + sleep(300, 600); |
| 191 | + } |
| 192 | + log.info("All caskets opened"); |
| 193 | + } |
| 194 | + |
165 | 195 | private void alchItems(SailingConfig config) { |
166 | 196 | var alchItems = config.alchItems(); |
167 | | - if (alchItems == null || alchItems.isBlank()) { |
168 | | - return; |
169 | | - } |
| 197 | + if (alchItems == null || alchItems.isBlank()) return; |
170 | 198 |
|
171 | | - var itemsToAlch = Arrays.stream(alchItems.split(",")) |
| 199 | + var itemNamesToAlch = Arrays.stream(alchItems.split(",")) |
172 | 200 | .map(String::trim) |
| 201 | + .map(String::toLowerCase) |
173 | 202 | .filter(item -> !item.isEmpty()) |
174 | | - .toArray(String[]::new); |
| 203 | + .collect(Collectors.toList()); |
175 | 204 |
|
176 | | - for (String itemName : itemsToAlch) { |
177 | | - if (Rs2Inventory.hasItem(itemName)) { |
178 | | - Rs2Magic.alch(itemName); |
179 | | - Rs2Player.waitForXpDrop(Skill.MAGIC, 10000, false); |
| 205 | + AlchOrder order = config.alchOrder(); |
| 206 | + |
| 207 | + if (order == AlchOrder.LIST_ORDER) { |
| 208 | + for (String itemName : itemNamesToAlch) { |
| 209 | + while (Rs2Inventory.hasItem(itemName)) { |
| 210 | + log.info("Alching (list order): {}", itemName); |
| 211 | + Rs2Magic.alch(itemName); |
| 212 | + Rs2Player.waitForXpDrop(Skill.MAGIC, 10000, false); |
| 213 | + } |
| 214 | + } |
| 215 | + } else { |
| 216 | + final int COLUMNS = 4; |
| 217 | + Comparator<Rs2ItemModel> slotOrder; |
| 218 | + switch (order) { |
| 219 | + case RIGHT_TO_LEFT: |
| 220 | + slotOrder = Comparator |
| 221 | + .comparingInt((Rs2ItemModel i) -> i.getSlot() / COLUMNS) |
| 222 | + .thenComparingInt(i -> -(i.getSlot() % COLUMNS)); |
| 223 | + break; |
| 224 | + case TOP_TO_BOTTOM: |
| 225 | + slotOrder = Comparator |
| 226 | + .comparingInt((Rs2ItemModel i) -> i.getSlot() % COLUMNS) |
| 227 | + .thenComparingInt(i -> i.getSlot() / COLUMNS); |
| 228 | + break; |
| 229 | + case BOTTOM_TO_TOP: |
| 230 | + slotOrder = Comparator |
| 231 | + .comparingInt((Rs2ItemModel i) -> i.getSlot() % COLUMNS) |
| 232 | + .thenComparingInt(i -> -(i.getSlot() / COLUMNS)); |
| 233 | + break; |
| 234 | + default: // LEFT_TO_RIGHT |
| 235 | + slotOrder = Comparator.comparingInt(Rs2ItemModel::getSlot); |
| 236 | + break; |
180 | 237 | } |
| 238 | + |
| 239 | + boolean alched; |
| 240 | + do { |
| 241 | + alched = false; |
| 242 | + List<Rs2ItemModel> candidates = Rs2Inventory.all().stream() |
| 243 | + .filter(item -> itemNamesToAlch.stream() |
| 244 | + .anyMatch(name -> item.getName().toLowerCase().contains(name))) |
| 245 | + .sorted(slotOrder) |
| 246 | + .collect(Collectors.toList()); |
| 247 | + if (!candidates.isEmpty()) { |
| 248 | + Rs2ItemModel next = candidates.get(0); |
| 249 | + log.info("Alching ({}) slot {}: {}", order, next.getSlot(), next.getName()); |
| 250 | + Rs2Magic.alch(next); |
| 251 | + Rs2Player.waitForXpDrop(Skill.MAGIC, 10000, false); |
| 252 | + alched = true; |
| 253 | + } |
| 254 | + } while (alched); |
181 | 255 | } |
182 | 256 | } |
183 | 257 |
|
184 | 258 | private void dropJunk(SailingConfig config) { |
185 | 259 | var dropItems = config.dropItems(); |
186 | | - if (dropItems == null || dropItems.isBlank()) { |
187 | | - return; |
188 | | - } |
| 260 | + if (dropItems == null || dropItems.isBlank()) return; |
189 | 261 |
|
190 | 262 | var junkItems = Arrays.stream(dropItems.split(",")) |
191 | 263 | .map(String::trim) |
|
0 commit comments