package net.scapeemulator.game.task; import net.scapeemulator.game.model.Position; import net.scapeemulator.game.model.area.Area; import net.scapeemulator.game.model.area.PositionArea; import net.scapeemulator.game.model.mob.Mob; /** * An @{link Action} which fires when a distance requirement is met. * * @author Blake * @author Graham */ public abstract class DistancedAction<T extends Mob> extends Action<T> { /** * The position to distance check with. */ protected final Area bounds; /** * The minimum distance before the action fires. */ private final int distance; /** * The delay once the threshold is reached. */ private final int delay; /** * A flag indicating if this action fires immediately after the threshold is reached. */ private final boolean immediate; /** * A flag indicating if this action should wait until the mob has stopped moving completely before firing. */ private boolean waitForNotWalking; /** * A flag indicating if the distance has been reached yet. */ private boolean reached = false; public DistancedAction(int delay, boolean immediate, T character, Position position, int distance) { this(delay, immediate, character, new PositionArea(position), distance, false); } public DistancedAction(int delay, boolean immediate, T character, Position position, int distance, boolean waitForStop) { this(delay, immediate, character, new PositionArea(position), distance, waitForStop); } /** * Creates a new DistancedAction. * * @param delay The delay between executions once the distance threshold is reached. * @param immediate Whether or not this action fires immediately after the distance threshold is reached. * @param character The character. * @param position The position. * @param distance The distance. */ public DistancedAction(int delay, boolean immediate, T character, Area bounds, int distance) { this(delay, immediate, character, bounds, distance, false); } /** * Creates a new DistancedAction. * * @param delay The delay between executions once the distance threshold is reached. * @param immediate Whether or not this action fires immediately after the distance threshold is reached. * @param character The character. * @param position The position. * @param distance The distance. * @param waitForStop If true, executeAction() will not be called until the mob has completely stopped moving */ public DistancedAction(int delay, boolean immediate, T character, Area bounds, int distance, boolean waitForStop) { super(character, 1, true); this.bounds = bounds; this.distance = distance; this.delay = delay; this.immediate = immediate; } @Override public void execute() { if (reached) { // some actions (e.g. agility) will cause the player to move away again // so we don't check once the player got close enough once executeAction(); } else if (bounds.withinArea(mob.getPosition().getX(), mob.getPosition().getY(), distance, false)) { if (waitForNotWalking && !mob.notWalking()) { return; } reached = true; setDelay(delay); if (immediate) { executeAction(); } } else if (mob.getWalkingQueue().isEmpty()) { cantReach(); stop(); } } public void waitForEmptyQueue() { waitForNotWalking = true; } /** * Executes the actual action. Called when the distance requirement is met. */ public abstract void executeAction(); /** * Called when the mobs walking queue is empty if they haven't yet reached the destination. */ public abstract void cantReach(); }