schepa 0 Share Posted April 1, 2022 Hi! I'm a mid level web developer and after years of wondering I finally wrote my first script. It's a script for the Cook's Assistant quest. I thought about starting with Behavior Tree, but it seemed too complex to start with, so I did it using TaskScript. I would appreciate any feedback. org.dreambot.taskscript Main Spoiler @ScriptManifest(name = "Cook's Assistant", author = "schepa", category = Category.QUEST, version = 1.0) public class Main extends TaskScript implements ChatListener { public List<String> necessaryItems = new LinkedList<>(Arrays.asList("Bucket of milk", "Pot of flour", "Egg")); public boolean isHopperOperated = false; public final Area LUMBRIDGE_CASTLE_KITCHEN = new Area(3206, 3212, 3211, 3216); public final Area LUMBRIDGE_CASTLE_CELLAR = new Area(3219, 9620, 3208, 9625); public final Area LUMBRIDGE_EAST_FARM = new Area(3252, 3273, 3260, 3280); public final Area LUMBRIDGE_WHEAT_FIELD = new Area(3162, 3292, 3160, 3295); public final Area MILL_LANE_MILL_SECOND_FLOOR = new Area(3164, 3307, 3169, 3306, 2); public final Area MILL_LANE_MILL_GROUND_FLOOR = new Area(3164, 3307, 3169, 3306); public final Area FARMER_FRED_HOUSE = new Area(3185, 3276, 3191, 3278); @Override public void onStart() { openQuestWidget(); getNeededItems(); closeQuestWidget(); addNodes( new StartQuestNode(this), new GetPotNode(this), new GetBucketNode(this), new FillBucketOfMilkNode(this), new FillPotOfFlourNode(this), new GetEggNode(this), new EndQuestNode(this) ); } @Override public void onMessage(Message message) { if (message.getMessage().contains("You operate the hopper.")) { isHopperOperated = true; } } private void openQuestWidget() { while (Tabs.getOpen() != Tab.QUEST) { Tabs.openWithMouse(Tab.QUEST); sleep(1500, 2000); } while (Widgets.getWidget(119) == null) { WidgetChild widgetChild = Widgets.getWidget(399).getChild(7).getChild(1); if (widgetChild.isVisible()) { widgetChild.interact(); sleep(1500, 2000); } } } private void closeQuestWidget() { while (Widgets.getWidget(119) != null) { Widgets.getWidget(119).getChild(205).interact(); sleep(2000, 3000); } } private void getNeededItems() { Widgets.getWidget(119).getChildren().forEach((children) -> { String lineText = children.getText(); if (lineText.contains("I have given the cook a bucket of milk.")) { necessaryItems.remove("Bucket of milk"); } else if (lineText.contains("I have given the cook a pot of flour.")) { necessaryItems.remove("Pot of flour"); } else if (lineText.contains("I have given the cook an egg.")) { necessaryItems.remove("Egg"); } }); if (necessaryItems.isEmpty()) { return; } } } org.dreambot.tasknodes StartQuestNode Spoiler public class StartQuestNode extends TaskNode { private final Main main; public StartQuestNode(Main main) { this.main = main; } @Override public int priority() { return 6; } @Override public boolean accept() { return !Quests.isStarted(FreeQuest.COOKS_ASSISTANT); } @Override public int execute() { if (Quests.isFinished(FreeQuest.COOKS_ASSISTANT)) { return -1; } if (Utils.walkToArea(main.LUMBRIDGE_CASTLE_KITCHEN)) { Utils.interactWithNPC("Talk-to", "Cook"); Utils.handleDialog("What's wrong?", "Yes."); } return Calculations.random(250, 500); } } GetPotNode Spoiler public class GetPotNode extends TaskNode { private final Main main; public GetPotNode(Main main) { this.main = main; } @Override public int priority() { return 5; } @Override public boolean accept() { boolean isNecessary = main.necessaryItems.contains("Pot of flour"); boolean hasPotOfFlour = Inventory.contains("Pot of flour"); boolean hasPot = Inventory.contains("Pot"); return isNecessary && !hasPotOfFlour && !hasPot; } @Override public int execute() { if (Utils.walkToArea(main.LUMBRIDGE_CASTLE_KITCHEN)) { Utils.takeGroundItem("Pot"); } return Calculations.random(250, 500); } } GetBucketNode Spoiler public class GetBucketNode extends TaskNode { private final Main main; public GetBucketNode(Main main) { this.main = main; } @Override public int priority() { return 4; } @Override public boolean accept() { boolean isNecessary = main.necessaryItems.contains("Bucket of milk"); boolean hasBucketOfMilk = Inventory.contains("Bucket of milk"); boolean hasBucket = Inventory.contains("Bucket"); return isNecessary && !hasBucketOfMilk && !hasBucket; } @Override public int execute() { if (Utils.walkToArea(main.LUMBRIDGE_CASTLE_CELLAR)) { Utils.takeGroundItem("Bucket"); } return Calculations.random(250, 500); } } FillBucketOfMilkNode Spoiler public class FillBucketOfMilkNode extends TaskNode { private final Main main; public FillBucketOfMilkNode(Main main) { this.main = main; } @Override public int priority() { return 3; } @Override public boolean accept() { boolean isNecessary = main.necessaryItems.contains("Bucket of milk"); boolean hasBucketOfMilk = Inventory.contains("Bucket of milk"); return isNecessary && !hasBucketOfMilk; } @Override public int execute() { if (Utils.walkToArea(main.LUMBRIDGE_EAST_FARM)) { Utils.interactWithGameObject("Milk", "Dairy cow"); } return Calculations.random(250, 500); } } FillPotOfFlourNode Spoiler public class FillPotOfFlourNode extends TaskNode { private final Main main; public FillPotOfFlourNode(Main main) { this.main = main; } @Override public int priority() { return 3; } @Override public boolean accept() { boolean isNecessary = main.necessaryItems.contains("Pot of flour"); boolean hasPotOfFlour = Inventory.contains("Pot of flour"); return isNecessary && !hasPotOfFlour; } @Override public int execute() { if (!Inventory.contains("Grain")) { if (main.isHopperOperated) { Utils.walkToArea(main.MILL_LANE_MILL_GROUND_FLOOR); Utils.interactWithGameObject("Empty", "Flour bin", 5000, 6000); } else if (Utils.walkToArea(main.LUMBRIDGE_WHEAT_FIELD)) { Utils.interactWithGameObject("Pick", "Wheat"); } } else { if (Utils.walkToArea(main.MILL_LANE_MILL_SECOND_FLOOR)) { Utils.interactWithGameObject("Fill", "Hopper", 5000, 6000); Utils.interactWithGameObject("Operate", "Hopper controls", 5000, 6000); } } return Calculations.random(250, 500); } } GetEggNode Spoiler public class GetEggNode extends TaskNode { private final Main main; public GetEggNode(Main main) { this.main = main; } @Override public int priority() { return 1; } @Override public boolean accept() { boolean isNecessary = main.necessaryItems.contains("Egg"); boolean hasEgg = Inventory.contains("Egg"); return isNecessary && !hasEgg; } @Override public int execute() { if (Utils.walkToArea(main.FARMER_FRED_HOUSE)) { Utils.takeGroundItem("Egg"); } return Calculations.random(250, 500); } } EndQuestNode Spoiler public class EndQuestNode extends TaskNode { private final Main main; public EndQuestNode(Main main) { this.main = main; } @Override public int priority() { return 0; } @Override public boolean accept() { return true; } @Override public int execute() { if (Utils.walkToArea(main.LUMBRIDGE_CASTLE_KITCHEN)) { Utils.interactWithNPC("Talk-to", "Cook"); Utils.handleDialog(); } return Calculations.random(250, 500); } } CooksAssistant.zip Link to comment Share on other sites More sharing options...
SubCZ 280 Share Posted April 1, 2022 Utils.interactWithNPC("Talk-to", "Cook"); Utils.handleDialog("What's wrong?", "Yes."); 1) You're often not checking if the interaction was successful. Any misclick, lag, etc could throw it off. 2) You're also using a lot of while loops that could loop infinitely, where a simple sleepUntil would be better to allow to recover from unexpected situations (and just for clarity). 3) Looks like the majority of your member variables are public? This is usually not a good idea, see here: https://stackoverflow.com/questions/48820066/why-do-we-declare-private-variables-in-java#:~:text=Making a variable private "protects,classes which use the class. 4) I'd also separate the logic a bit more instead of using state variables and a bunch of areas in your Main class. 5) I'm not sure what Utils#interactWithGameObject does, but every GameObject already has an interact method. Didn't look at the details too much but this is what I noticed. Otherwise good job, and good luck in the future Hans Zimmer 1 Link to comment Share on other sites More sharing options...
BeepBoopBop 9 Share Posted April 2, 2022 Your Utils object is doing a LOT of heavy lifting. A danger of having a generic "Utils" class is that it very quickly becomes unwieldy, and you start losing a lot of the organization that OOP brings to the table. I personally like having separate utility classes that wrap around core functions, like a "Walker", a "Talker", a "Banker", etc. That way, everything stays self-contained. I'll mimic SubCZ's recommendations of removing a lot of the "While" statements. Most of the time they're not necessary, and the more while loops, the more likely your bot can end up in a very obviously-botlike state (ie, missing random events, or repeatedly clicking on a game object over and over and over again). I'd rather the script fail and crash than get stuck in one of those states. Finally, it seems like you're waiting between 5-6 seconds whenever interacting with an object you may need to walk to. You can use a sleepUntil statement with a condition of "player not moving, player not animating, and player distance to object is 1" to make this much less botlike. Good start! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now