Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

Sign up now!

Suggestion Discussion - How should randoms be handled

First Bot Author
Joined
Aug 7, 2013
Messages
262
In this thread I will group random events into several categories based on their signature.

Group A: Talk and Done: These require the user to click on the anti-random, perhaps click continue a few times and nothing more. Examples: Drunken Dwarf, Strange plant

Group B: Talk and Puzzle: These require the user to click on the anti-random and solve a puzzle on the spot. Examples: Rick Turpentin, Sandwich Lady

Group C: Teleport: These teleport the user into a safe area to complete a puzzle. Examples: Evil Twin, Beekeeper

Group D: Fight or Run: These requires the user to either fight off, or run from. Examples: Evil Chicken, Shade, Zombie

Now Imagine the client would handle all random events by default, and the script is paused while it's solving a random event. This means the script has no means to interfere. How would each group be handled?

Starting with C: This seems the easiest group to handle, as when the player is teleported, the script has no desire to do anything anymore, nor is the player in danger: the random solver can start right away!

But then A and B, which often require the player to be out of combat before talking. Now, if the random solver activates instantly and simply waits for the user to become idle: that might never happen and the player might die. You'd need the script to tell the client when it is safe to solve the random event!

The same goes for D: How would the client decide whether to fight or to run? Imagine Ultra Bandits: which protects melee at all times as the player is under attack by a large amount of bandits. Fighting an evil chicken would be stupid, as it uses magic. However, fighting a melee-based random event wouldn't be an issue as it wouldn't hit anything. I would want the script to be able to tell the client which it's going to fight, and which it is not! If I am a level 3 player woodcutting some yew logs and get any combat-based event: I'd run! But this also poses a problem, as the client wouldn't know where to run to, especially if you're inside a closed-off compound: such as a house, or a cow pen! The script would at least require the option to walk manually!

I've therefore come up with a clean way of dealing with randoms, which I will illustrate by implementing it.
Code:
import com.runemate.game.api.hybrid.region.Players;
import com.runemate.game.api.script.annotations.Manifest;
import com.runemate.game.api.script.data.Category;
import com.runemate.game.api.script.data.GameType;
import com.runemate.game.api.script.framework.LoopingScript;

@Manifest(
        categories = Category.OTHER,
        compatibility = GameType.OSRS,
        name = "Example Script",
        version = "1.0.00",
        description = "Example Description.")
public final class ExampleScript extends LoopingScript implements RandomListener {

    private RandomEvent randomEvent;

    @Override
    public void onLoop() {
        if (randomEvent != null) {
            //get to safety
        }
    }

    @Override
    public boolean safeToTalk(final RandomEvent event) {
        randomEvent = event;
        return Players.getLocal().getHealthGauge() == null;
    }

    @Override
    public void onRandomEvent(final RandomEvent event) {
        if (event.getGroup() == RandomEvent.Group.FIGHT_OR_RUN) {
            if (event == RandomEvent.EVIL_CHICKEN) {
                event.setSolveMode(RandomEvent.Mode.RUN); //Let the client decide a location to run to and do everything itself
                //or
                event.setSolver(new EvilChickenRunner());
            } else {
                event.setSolveMode(RandomEvent.Mode.FIGHT); //Let the client do the fighting
                //or
                event.setSolver(new RandomFighter());
            }
        }
    }

    @Override
    public void onRandomEventComplete(final RandomEvent event) {
        randomEvent = null;
    }

    private final class EvilChickenRunner implements Runnable {

        @Override
        public void run() {
            //my own running method
        }
    }

    private final class RandomFighter implements Runnable {

        @Override
        public void run() {
            //my own way of fighting a random
        }
    }
}

It isn't perfect, but it illustrates the idea. What do you guys think about the handling of randoms?
 
Mod Automation
Joined
Jul 26, 2013
Messages
3,053
Correct me if I'm wrong but I do believe you can only get randoms when you are out of combat, in which case the trying to talk while in combat argument is moot.

On a more general note, I'm torn on this. I like the traditional structure in which random handling is abstracted out of the control of an individual bot/author as not everyone can develop code to the quality you can and any shortcomings would reflect on the client instead of the bot. That being said, I do see the use case (as you suggested being stuck in a pen when needing to run) to allow devs some level of control. I would, however, emphasize the need for the anti-random to have default behaviors with optional methods in the API to over-ride certain behaviors. For example, an attack or run anti-random would run by default, but allow the author to over-ride that and attack if he so wishes.
 
First Bot Author
Joined
Aug 7, 2013
Messages
262
Correct me if I'm wrong but I do believe you can only get randoms when you are out of combat, in which case the trying to talk while in combat argument is moot.

On a more general note, I'm torn on this. I like the traditional structure in which random handling is abstracted out of the control of an individual bot/author as not everyone can develop code to the quality you can and any shortcomings would reflect on the client instead of the bot. That being said, I do see the use case (as you suggested being stuck in a pen when needing to run) to allow devs some level of control. I would, however, emphasize the need for the anti-random to have default behaviors with optional methods in the API to over-ride certain behaviors. For example, an attack or run anti-random would run by default, but allow the author to over-ride that and attack if he so wishes.
I believe Jagex has indeed made randoms not appear while in combat (although this wasn't the case back in the days), but aggressive creatures can still attack if it's a random event of group A or B.
 
Author of MaxiBots
Joined
Dec 3, 2013
Messages
7,032
Good idea however perhaps we should consider a system similar to osbots where the client handles the randoms by default, however scripts also has access to methods that help in this situation, those being one that executes before the random handler does its thing, one that executes after the random has completed and one that completely replaces the default random handler if i remember correctly. This sort of system would allow the script to exit for example the chicken pen before allowing the solver to take over and upon completing the solver, reenter the pen.

This is something what it looks like in osbot
Code:
import org.osbot.script.Script;
import org.osbot.script.rs2.model.NPC;
import org.osbot.script.rs2.randoms.RandomBehaviourHook;
import org.osbot.script.rs2.randoms.RandomManager;


public class Example extends Script{
    @Override
    public void onStart() {

        randomManager.registerHook(
                new RandomBehaviourHook(RandomManager.STRANGE_PLANT) {

                    @Override
                    public boolean shouldActivatePreLoop() {
                        return false;
                    }

                    @Override
                    public int preLoop() {
                        return 100;
                    }

                    @Override
                    public int onLoop() throws InterruptedException {
                        NPC plant = closestNPCForName("Strange Plant");
                     
                        if (plant != null) {
                            if (plant.isFacing(client.getMyPlayer()))
                                plant.interact("Pick");
                        }
                        return super.onLoop();
                    }

                    @Override
                    public boolean shouldActivatePostLoop() {
                        return false;
                    }

                    @Override
                    public int postLoop() {
                        return 100;
                    }

                }
        );
    }
}

I wouldn't consider this copying but rather using the most sensible and logical approach.
And after reading the code you posted i realized this is practically the same idea, lol
 
Last edited:
Top