diff --git a/.idea/artifacts/CAgility_jar.xml b/.idea/artifacts/CAgility_jar.xml
new file mode 100644
index 0000000..787a589
--- /dev/null
+++ b/.idea/artifacts/CAgility_jar.xml
@@ -0,0 +1,9 @@
+
+
+ $USER_HOME$/DreamBot/Scripts
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index c11ccb6..262b23c 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,6 +2,7 @@
+
diff --git a/CAgility/CAgility.iml b/CAgility/CAgility.iml
new file mode 100644
index 0000000..ac9e1f0
--- /dev/null
+++ b/CAgility/CAgility.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CAgility/src/io/reisub/dreambot/cagility/CAgility.java b/CAgility/src/io/reisub/dreambot/cagility/CAgility.java
new file mode 100644
index 0000000..99170d4
--- /dev/null
+++ b/CAgility/src/io/reisub/dreambot/cagility/CAgility.java
@@ -0,0 +1,24 @@
+package io.reisub.dreambot.cagility;
+
+import io.reisub.dreambot.cagility.tasks.HandleObstacle;
+import io.reisub.dreambot.cagility.tasks.PickupMark;
+import io.reisub.dreambot.util.Constants;
+import io.reisub.dreambot.util.tasks.Eat;
+import io.reisub.dreambot.util.tasks.kitten.KittenTask;
+import org.dreambot.api.script.Category;
+import org.dreambot.api.script.ScriptManifest;
+import org.dreambot.api.script.impl.TaskScript;
+
+@SuppressWarnings("unused")
+@ScriptManifest(category = Category.AGILITY, name = "CAgility", description = "Runs laps for days", author = Constants.AUTHOR, version = 1.0)
+public class CAgility extends TaskScript {
+ @Override
+ public void onStart() {
+ addNodes(
+ new Eat(),
+ KittenTask.createKittenTask(),
+ new HandleObstacle(HandleObstacle.Course.CANIFIS),
+ new PickupMark()
+ );
+ }
+}
diff --git a/CAgility/src/io/reisub/dreambot/cagility/Obstacle.java b/CAgility/src/io/reisub/dreambot/cagility/Obstacle.java
new file mode 100644
index 0000000..712af03
--- /dev/null
+++ b/CAgility/src/io/reisub/dreambot/cagility/Obstacle.java
@@ -0,0 +1,39 @@
+package io.reisub.dreambot.cagility;
+
+import org.dreambot.api.methods.interactive.GameObjects;
+import org.dreambot.api.wrappers.interactive.GameObject;
+
+public class Obstacle {
+ private final int id;
+ private final boolean retry;
+ private Obstacle next;
+
+ public Obstacle(int id, boolean canRetry) {
+ this.id = id;
+ this.retry = canRetry;
+ }
+
+ public Obstacle(int id) {
+ this(id, false);
+ }
+
+ public int getID() {
+ return this.id;
+ }
+
+ public boolean canRetry() {
+ return this.retry;
+ }
+
+ public GameObject getGameObject() {
+ return GameObjects.closest(getID());
+ }
+
+ public Obstacle getNext() {
+ return this.next;
+ }
+
+ public void setNext(Obstacle next) {
+ this.next = next;
+ }
+}
diff --git a/CAgility/src/io/reisub/dreambot/cagility/tasks/HandleObstacle.java b/CAgility/src/io/reisub/dreambot/cagility/tasks/HandleObstacle.java
new file mode 100644
index 0000000..864e4fa
--- /dev/null
+++ b/CAgility/src/io/reisub/dreambot/cagility/tasks/HandleObstacle.java
@@ -0,0 +1,133 @@
+package io.reisub.dreambot.cagility.tasks;
+
+import io.reisub.dreambot.cagility.Obstacle;
+import io.reisub.dreambot.util.Constants;
+import io.reisub.dreambot.util.Util;
+import io.reisub.dreambot.util.event.ListenerManager;
+import io.reisub.dreambot.util.event.health.HealthListener;
+import org.dreambot.api.input.Mouse;
+import org.dreambot.api.methods.Calculations;
+import org.dreambot.api.methods.MethodContext;
+import org.dreambot.api.methods.interactive.Players;
+import org.dreambot.api.methods.item.GroundItems;
+import org.dreambot.api.methods.skills.Skill;
+import org.dreambot.api.methods.walking.impl.Walking;
+import org.dreambot.api.script.ScriptManager;
+import org.dreambot.api.script.TaskNode;
+import org.dreambot.api.script.event.impl.ExperienceEvent;
+import org.dreambot.api.script.listener.ExperienceListener;
+import org.dreambot.api.wrappers.interactive.GameObject;
+import org.dreambot.api.wrappers.items.GroundItem;
+
+import java.awt.*;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HandleObstacle extends TaskNode {
+ public enum Course {
+ CANIFIS(
+ new Obstacle(14843),
+ new Obstacle(14844),
+ new Obstacle(14845),
+ new Obstacle(14848),
+ new Obstacle(14846),
+ new Obstacle(14894),
+ new Obstacle(14847),
+ new Obstacle(14897)
+ );
+
+ private final Obstacle firstObstacle;
+
+ Course(Obstacle... obstacles) {
+ this.firstObstacle = obstacles[0];
+
+ for (int i = 0; i < obstacles.length; i++) {
+ if (i + 1 == obstacles.length) {
+ obstacles[i].setNext(obstacles[0]);
+ } else {
+ obstacles[i].setNext(obstacles[i+1]);
+ }
+ }
+ }
+ }
+
+ private final Course course;
+ private final Map hoverMap;
+ private Obstacle lastObstacle = null;
+ private boolean failed, obstacleCompleted = false;
+
+ public HandleObstacle(Course course) {
+ this.course = course;
+ this.hoverMap = new HashMap<>();
+
+ ListenerManager.getInstance().addListener(new HealthListener() {
+ @Override
+ public void onHealthDecreased(int oldValue, int newValue) {
+ failed = true;
+ }
+ });
+
+ ScriptManager.getScriptManager().addListener(new ExperienceListener() {
+ @Override
+ public void onGained(ExperienceEvent event) {
+ if (event.getSkill().equals(Skill.AGILITY)) {
+ obstacleCompleted = true;
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean accept() {
+ GroundItem mark = GroundItems.closest(Constants.MARK_OF_GRACE);
+
+ return Util.playerIsIdle() && (mark == null || !mark.canReach());
+ }
+
+ @Override
+ public int execute() {
+ Obstacle current;
+
+ if (lastObstacle == null) {
+ current = course.firstObstacle;
+ } else {
+ if (failed) {
+ if (lastObstacle.canRetry()) {
+ current = lastObstacle;
+ } else {
+ current = course.firstObstacle;
+ }
+ failed = false;
+ } else {
+ current = lastObstacle.getNext();
+ }
+ }
+
+ final GameObject currentObject = current.getGameObject();
+ if (currentObject == null) return Calculations.random(300, 500);
+
+ if (!currentObject.isOnScreen()) {
+ Walking.clickTileOnMinimap(currentObject.getTile());
+ MethodContext.sleepUntil(() -> Players.localPlayer().distance(currentObject) < 3, Calculations.random(5000, 5500));
+ }
+
+ if (hoverMap.get(current.getID()) == null) {
+ hoverMap.put(current.getID(), currentObject.getBoundingBox());
+ }
+
+ currentObject.interact();
+
+ lastObstacle = current;
+
+ Rectangle hoverRect = hoverMap.get(current.getNext().getID());
+ if (hoverRect != null) {
+ Mouse.move(hoverRect);
+ }
+
+ MethodContext.sleepUntil(() -> failed || obstacleCompleted, Calculations.random(9000, 10000));
+
+ obstacleCompleted = false;
+
+ return Calculations.random(180, 350);
+ }
+}
diff --git a/CAgility/src/io/reisub/dreambot/cagility/tasks/PickupMark.java b/CAgility/src/io/reisub/dreambot/cagility/tasks/PickupMark.java
new file mode 100644
index 0000000..f8b7741
--- /dev/null
+++ b/CAgility/src/io/reisub/dreambot/cagility/tasks/PickupMark.java
@@ -0,0 +1,38 @@
+package io.reisub.dreambot.cagility.tasks;
+
+import io.reisub.dreambot.util.Constants;
+import org.dreambot.api.methods.Calculations;
+import org.dreambot.api.methods.MethodContext;
+import org.dreambot.api.methods.container.impl.Inventory;
+import org.dreambot.api.methods.item.GroundItems;
+import org.dreambot.api.script.TaskNode;
+import org.dreambot.api.wrappers.items.GroundItem;
+import org.dreambot.api.wrappers.items.Item;
+
+public class PickupMark extends TaskNode {
+ @Override
+ public boolean accept() {
+ GroundItem mark = GroundItems.closest(Constants.MARK_OF_GRACE);
+
+ return mark != null && mark.canReach();
+ }
+
+ @Override
+ public int execute() {
+ GroundItem mark = GroundItems.closest(Constants.MARK_OF_GRACE);
+
+ if (mark == null || !mark.canReach()) return 0;
+
+ Item marks = Inventory.get(Constants.MARK_OF_GRACE);
+ final int count = marks == null ? 0 : marks.getAmount();
+
+ mark.interact();
+
+ MethodContext.sleepUntil(() -> {
+ Item currentMarks = Inventory.get(Constants.MARK_OF_GRACE);
+ return currentMarks != null && currentMarks.getAmount() > count;
+ }, Calculations.random(5000, 5500));
+
+ return Calculations.random(250, 400);
+ }
+}
diff --git a/Util/src/io/reisub/dreambot/util/Constants.java b/Util/src/io/reisub/dreambot/util/Constants.java
index 57a3c63..d665cd6 100644
--- a/Util/src/io/reisub/dreambot/util/Constants.java
+++ b/Util/src/io/reisub/dreambot/util/Constants.java
@@ -47,6 +47,7 @@ public class Constants {
public static final String BRUMA_ROOTS = "Bruma roots";
public static final String BRAZIER = "Brazier";
public static final String BURNING_BRAZIER = "Burning brazier";
+ public static final String MARK_OF_GRACE = "Mark of grace";
// Actions
public static final String USE = "Use";