Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package net.runelite.client.plugins.microbot.farmingcontract;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.client.config.*;

@ConfigInformation("Automates Farming Guild contracts end-to-end.<br/><br/>" +
"<b>Start:</b> anywhere — the plugin walks to the guild.<br/>" +
"Have seeds, compost, rake, spade, and seed dibber banked.<br/><br/>" +
"<b>Cycle:</b> get contract → bank → compost & plant → harvest → turn in → repeat.<br/>" +
"Auto tier picks the highest contract your level supports.")
@ConfigGroup("farmingcontract")
public interface FarmingContractConfig extends Config {

@ConfigSection(
name = "Contract",
description = "Contract preferences",
position = 0
)
String contractSection = "contract";

@ConfigItem(
keyName = "contractTier",
name = "Contract Tier",
description = "Which contract tier to request from Jane",
position = 1,
section = contractSection
)
default ContractTier contractTier() {
return ContractTier.AUTO;
}

@ConfigItem(
keyName = "autoDowngrade",
name = "Auto Downgrade",
description = "Request an easier contract if seeds are unavailable",
position = 2,
section = contractSection
)
default boolean autoDowngrade() {
return true;
}

@ConfigItem(
keyName = "downgradeTree",
name = "Downgrade Trees",
description = "Automatically downgrade tree contracts (slow to grow)",
position = 3,
section = contractSection
)
default boolean downgradeTree() {
return false;
}

@ConfigItem(
keyName = "downgradeFruitTree",
name = "Downgrade Fruit Trees",
description = "Automatically downgrade fruit tree contracts (slow to grow)",
position = 4,
section = contractSection
)
default boolean downgradeFruitTree() {
return false;
}

@ConfigSection(
name = "Farming",
description = "Farming preferences",
position = 10
)
String farmingSection = "farming";

@ConfigItem(
keyName = "compostType",
name = "Compost Type",
description = "Type of compost to apply before planting",
position = 11,
section = farmingSection
)
default CompostType compostType() {
return CompostType.ULTRACOMPOST;
}

@ConfigItem(
keyName = "enableComposting",
name = "Compost Bin",
description = "Fill big compost bin with pineapples and collect ultracompost before doing contracts",
position = 12,
section = farmingSection
)
default boolean enableComposting() {
return false;
}

@ConfigItem(
keyName = "protectTrees",
name = "Protect Trees",
description = "Pay the gardener to protect tree and fruit tree contracts while they grow",
position = 13,
section = farmingSection
)
default boolean protectTrees() {
return false;
}

@Getter
@RequiredArgsConstructor
enum ContractTier {
AUTO("Auto"),
EASY("Easy"),
MEDIUM("Medium"),
HARD("Hard");

private final String label;

@Override
public String toString() {
return label;
}
}

@Getter
@RequiredArgsConstructor
enum CompostType {
NONE("None", -1),
COMPOST("Compost", 6032),
SUPERCOMPOST("Supercompost", 6034),
ULTRACOMPOST("Ultracompost", 21483);

private final String name;
private final int itemId;

@Override
public String toString() {
return name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package net.runelite.client.plugins.microbot.farmingcontract;

import com.google.common.collect.ImmutableMap;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.gameval.ItemID;
import net.runelite.client.plugins.timetracking.farming.PatchImplementation;
import net.runelite.client.plugins.timetracking.farming.Produce;

import java.util.Map;

public final class FarmingContractData {

static final WorldPoint JANE_LOCATION = new WorldPoint(1248, 3727, 0);
static final WorldPoint BIN_LOCATION = new WorldPoint(1272, 3729, 0);
static final int PINEAPPLE = ItemID.PINEAPPLE;
static final int VOLCANIC_ASH = ItemID.FOSSIL_VOLCANIC_ASH;
static final int BUCKET_EMPTY = ItemID.BUCKET_EMPTY;
static final int BUCKET_ULTRACOMPOST = ItemID.BUCKET_ULTRACOMPOST;
static final int MAGIC_SECATEURS = ItemID.FAIRY_ENCHANTED_SECATEURS;
static final int VOLCANIC_ASH_PER_BIN = 50;
static final int BIN_CAPACITY = 30;

static final Map<PatchImplementation, String> PATCH_NAMES = ImmutableMap.<PatchImplementation, String>builder()
.put(PatchImplementation.HERB, "Herb patch")
.put(PatchImplementation.ALLOTMENT, "Allotment")
.put(PatchImplementation.FLOWER, "Flower Patch")
.put(PatchImplementation.BUSH, "Bush Patch")
.put(PatchImplementation.TREE, "Tree patch")
.put(PatchImplementation.FRUIT_TREE, "Fruit Tree Patch")
.put(PatchImplementation.CACTUS, "Cactus patch")
.build();

static final Map<PatchImplementation, WorldPoint> PATCH_LOCATIONS = ImmutableMap.<PatchImplementation, WorldPoint>builder()
.put(PatchImplementation.HERB, new WorldPoint(1238, 3726, 0))
.put(PatchImplementation.ALLOTMENT, new WorldPoint(1267, 3727, 0))
.put(PatchImplementation.FLOWER, new WorldPoint(1260, 3725, 0))
.put(PatchImplementation.BUSH, new WorldPoint(1260, 3733, 0))
.put(PatchImplementation.TREE, new WorldPoint(1231, 3735, 0))
.put(PatchImplementation.FRUIT_TREE, new WorldPoint(1242, 3758, 0))
.put(PatchImplementation.CACTUS, new WorldPoint(1264, 3747, 0))
.build();

static final Map<Produce, Integer> SEED_MAPPINGS = ImmutableMap.<Produce, Integer>builder()
// Allotments
.put(Produce.POTATO, ItemID.POTATO_SEED)
.put(Produce.ONION, ItemID.ONION_SEED)
.put(Produce.CABBAGE, ItemID.CABBAGE_SEED)
.put(Produce.TOMATO, ItemID.TOMATO_SEED)
.put(Produce.SWEETCORN, ItemID.SWEETCORN_SEED)
.put(Produce.STRAWBERRY, ItemID.STRAWBERRY_SEED)
.put(Produce.WATERMELON, ItemID.WATERMELON_SEED)
.put(Produce.SNAPE_GRASS, ItemID.SNAPE_GRASS_SEED)
// Flowers
.put(Produce.MARIGOLD, ItemID.MARIGOLD_SEED)
.put(Produce.ROSEMARY, ItemID.ROSEMARY_SEED)
.put(Produce.NASTURTIUM, ItemID.NASTURTIUM_SEED)
.put(Produce.WOAD, ItemID.WOAD_SEED)
.put(Produce.LIMPWURT, ItemID.LIMPWURT_SEED)
.put(Produce.WHITE_LILY, ItemID.WHITE_LILY_SEED)
// Herbs
.put(Produce.GUAM, ItemID.GUAM_SEED)
.put(Produce.MARRENTILL, ItemID.MARRENTILL_SEED)
.put(Produce.TARROMIN, ItemID.TARROMIN_SEED)
.put(Produce.HARRALANDER, ItemID.HARRALANDER_SEED)
.put(Produce.RANARR, ItemID.RANARR_SEED)
.put(Produce.TOADFLAX, ItemID.TOADFLAX_SEED)
.put(Produce.IRIT, ItemID.IRIT_SEED)
.put(Produce.AVANTOE, ItemID.AVANTOE_SEED)
.put(Produce.KWUARM, ItemID.KWUARM_SEED)
.put(Produce.SNAPDRAGON, ItemID.SNAPDRAGON_SEED)
.put(Produce.CADANTINE, ItemID.CADANTINE_SEED)
.put(Produce.LANTADYME, ItemID.LANTADYME_SEED)
.put(Produce.DWARF_WEED, ItemID.DWARF_WEED_SEED)
.put(Produce.TORSTOL, ItemID.TORSTOL_SEED)
// Trees (saplings)
.put(Produce.OAK, ItemID.PLANTPOT_OAK_SAPLING)
.put(Produce.WILLOW, ItemID.PLANTPOT_WILLOW_SAPLING)
.put(Produce.MAPLE, ItemID.PLANTPOT_MAPLE_SAPLING)
.put(Produce.YEW, ItemID.PLANTPOT_YEW_SAPLING)
.put(Produce.MAGIC, ItemID.PLANTPOT_MAGIC_TREE_SAPLING)
// Fruit trees (saplings)
.put(Produce.APPLE, ItemID.PLANTPOT_APPLE_SAPLING)
.put(Produce.BANANA, ItemID.PLANTPOT_BANANA_SAPLING)
.put(Produce.ORANGE, ItemID.PLANTPOT_ORANGE_SAPLING)
.put(Produce.CURRY, ItemID.PLANTPOT_CURRY_SAPLING)
.put(Produce.PINEAPPLE, ItemID.PLANTPOT_PINEAPPLE_SAPLING)
.put(Produce.PAPAYA, ItemID.PLANTPOT_PAPAYA_SAPLING)
.put(Produce.PALM, ItemID.PLANTPOT_PALM_SAPLING)
.put(Produce.DRAGONFRUIT, ItemID.PLANTPOT_DRAGONFRUIT_SAPLING)
// Bushes
.put(Produce.REDBERRIES, ItemID.REDBERRY_BUSH_SEED)
.put(Produce.CADAVABERRIES, ItemID.CADAVABERRY_BUSH_SEED)
.put(Produce.DWELLBERRIES, ItemID.DWELLBERRY_BUSH_SEED)
.put(Produce.JANGERBERRIES, ItemID.JANGERBERRY_BUSH_SEED)
.put(Produce.WHITEBERRIES, ItemID.WHITEBERRY_BUSH_SEED)
.put(Produce.POISON_IVY, ItemID.POISONIVY_BUSH_SEED)
// Cactus
.put(Produce.CACTUS, ItemID.CACTUS_SEED)
.put(Produce.POTATO_CACTUS, ItemID.POTATO_CACTUS_SEED)
.build();

static final Map<Produce, int[]> PROTECTION_PAYMENTS = ImmutableMap.<Produce, int[]>builder()
// Trees
.put(Produce.OAK, new int[]{ItemID.BASKET_TOMATO_5, 1})
.put(Produce.WILLOW, new int[]{ItemID.BASKET_APPLE_5, 1})
.put(Produce.MAPLE, new int[]{ItemID.BASKET_ORANGE_5, 1})
.put(Produce.YEW, new int[]{ItemID.CACTUS_SPINE, 10})
.put(Produce.MAGIC, new int[]{ItemID.COCONUT, 25})
// Fruit trees
.put(Produce.APPLE, new int[]{ItemID.SWEETCORN, 9})
.put(Produce.BANANA, new int[]{ItemID.BASKET_APPLE_5, 4})
.put(Produce.ORANGE, new int[]{ItemID.BASKET_STRAWBERRY_5, 3})
.put(Produce.CURRY, new int[]{ItemID.BASKET_BANANA_5, 5})
.put(Produce.PINEAPPLE, new int[]{ItemID.WATERMELON, 10})
.put(Produce.PAPAYA, new int[]{ItemID.PINEAPPLE, 10})
.put(Produce.PALM, new int[]{ItemID.PAPAYA, 15})
.put(Produce.DRAGONFRUIT, new int[]{ItemID.COCONUT, 15})
.build();

static int getProtectionItemId(Produce produce) {
int[] payment = PROTECTION_PAYMENTS.get(produce);
return payment != null ? payment[0] : -1;
}

static int getProtectionItemQty(Produce produce) {
int[] payment = PROTECTION_PAYMENTS.get(produce);
return payment != null ? payment[1] : 0;
}

static boolean hasProtectionData(Produce produce) {
return PROTECTION_PAYMENTS.containsKey(produce);
}

static int getSeedId(Produce produce) {
return SEED_MAPPINGS.getOrDefault(produce, -1);
}

static int getSeedsRequired(Produce produce) {
return produce.getPatchImplementation() == PatchImplementation.ALLOTMENT ? 3 : 1;
}

static boolean needsCoins(Produce produce) {
PatchImplementation type = produce.getPatchImplementation();
return type == PatchImplementation.TREE || type == PatchImplementation.FRUIT_TREE;
}

static boolean usesSecateurs(PatchImplementation type) {
return type == PatchImplementation.ALLOTMENT
|| type == PatchImplementation.HERB
|| type == PatchImplementation.FLOWER
|| type == PatchImplementation.BUSH;
}

static boolean needsClearAfterHarvest(PatchImplementation type) {
return type == PatchImplementation.BUSH
|| type == PatchImplementation.CACTUS;
}

static boolean needsCheckHealth(PatchImplementation type) {
return type == PatchImplementation.TREE
|| type == PatchImplementation.FRUIT_TREE
|| type == PatchImplementation.BUSH
|| type == PatchImplementation.CACTUS;
}

private FarmingContractData() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package net.runelite.client.plugins.microbot.farmingcontract;

import net.runelite.api.Skill;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;

import lombok.extern.slf4j.Slf4j;

import javax.inject.Inject;
import java.awt.*;

@Slf4j
public class FarmingContractOverlay extends OverlayPanel {

@Inject
FarmingContractOverlay(FarmingContractPlugin plugin) {
super(plugin);
setPosition(OverlayPosition.TOP_LEFT);
setNaughty();
}

@Override
public Dimension render(Graphics2D graphics) {
try {
panelComponent.setPreferredSize(new Dimension(200, 0));
panelComponent.getChildren().add(TitleComponent.builder()
.text("Farming Contract")
.color(Color.GREEN)
.build());

panelComponent.getChildren().add(LineComponent.builder()
.left("Status:")
.right(FarmingContractPlugin.getStatus())
.build());

String contractName = FarmingContractScript.getContractName();
panelComponent.getChildren().add(LineComponent.builder()
.left("Contract:")
.right(contractName != null ? contractName : "None")
.build());

if (Microbot.isLoggedIn()) {
int level = Microbot.getClient().getRealSkillLevel(Skill.FARMING);
String tier = level >= 85 ? "Hard" : level >= 65 ? "Medium" : level >= 45 ? "Easy" : "N/A";
panelComponent.getChildren().add(LineComponent.builder()
.left("Farming:")
.right(level + " (" + tier + ")")
.build());
}
} catch (Exception ex) {
log.error("Overlay render error", ex);
}
return super.render(graphics);
}
}
Loading
Loading