Because this script was my first script and it is not flexible I will release it for opensource because I believe the readability will be very valuable to beginning scripters.
i'm much much better now and this script is cancer, I only spent like 5minutes adding comments and i hope some people can learn whatever from this
gl
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.util.Arrays;
import org.osbot.rs07.api.map.Area;
import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.api.model.Entity;
import org.osbot.rs07.api.model.GroundItem;
import org.osbot.rs07.api.model.NPC;
import org.osbot.rs07.api.model.RS2Object;
import org.osbot.rs07.api.ui.EquipmentSlot;
import org.osbot.rs07.api.ui.Skill;
import org.osbot.rs07.script.Script;
import org.osbot.rs07.script.ScriptManifest;
import org.osbot.rs07.utility.ConditionalSleep;
@ScriptManifest(author = "justanotherkid", info = "", name = "Unicows", version = 1.0, logo = "")
public class main extends Script {
Area area = new Area( new Position(3010,4412,0), new Position(3042,4373,0));
Area bankarea = new Area( new Position(2443,3082,0), new Position(2438,3096,0));
Area kandarinarea = new Area( new Position(2611,3219,0), new Position(2601,3228,0));
Position[] toarea1 = new Position[] { new Position(2606,3222,0), new Position(2616,3222,0), new Position(2628,3222,0), new Position(2636,3223,0), new Position(2649,3225,0),};
String state;
Area position = new Area( new Position(3017,4409,0), new Position(3021,4408,0));
Position ladder = new Position (2648,3213,0);
GroundItem horn;
NPC unicow;
long startTime;
long count1;
long totalcount;
Entity door;
RS2Object towerdoor;
Entity bank;
Entity trapdoor;
@Override
public void onStart() {
startTime = System.currentTimeMillis(); // start a timer in ms
for(Skill skill : new Skill[]{Skill.HITPOINTS, Skill.ATTACK, Skill.STRENGTH, Skill.DEFENCE}) {
getExperienceTracker().start(skill); } // start exp trackers, you can add more skill trackers by just adding onto the list
}
private enum State {
SUMMON,IDLE,LOOT,FIGHT,TRAVEL2BANK,BANK,TRAVEL2AREA,DROP,WORLDHOP // enum of states
}
private State getState() // below are conditions to required to execute each state, i believe the conditions are straight forward so i will not explain them
{
if(area.contains(myPlayer()) && getPlayers().getAll().size() > 1 && !myPlayer().isUnderAttack())
{
return State.WORLDHOP;
}
if(horn != null && area.contains(myPlayer()) && !myPlayer().isUnderAttack() && getInventory().getAmount("Unicorn horn") < 28)
{
unicow = npcs.closest("Unicow");
return State.LOOT;
}
if(area.contains(myPlayer()) && getInventory().contains("Cowhide") && getInventory().contains("Unicorn horn") && unicow == null)
{
unicow = npcs.closest("Unicow");
return State.SUMMON;
}
if(getInventory().contains("Green satchel") || getInventory().contains("Tea flask") || getInventory().contains("Bones"))
{
return State.DROP;
}
if(!getInventory().contains("Cowhide") && bankarea.contains(myPlayer()))
{
return State.BANK;
}
if(!getInventory().contains("Cowhide") && !bankarea.contains(myPlayer()))
{
unicow = npcs.closest("Unicow");
return State.TRAVEL2BANK;
}
if(unicow != null && area.contains(myPlayer()) || myPlayer().isUnderAttack())
{
unicow = npcs.closest("Unicow");
return State.FIGHT;
}
if(getInventory().contains("Unicorn horn") && getInventory().contains("Unicorn horn") && !area.contains(myPlayer()))
{
return State.TRAVEL2AREA;
}
return State.IDLE;
}
@Override
public int onLoop() throws InterruptedException // the 2 lines below here are always on loop regardless of what state is executed
{
unicow = npcs.closest("Unicow"); // constantly refreshing unicow to mean the closest unicow; if no unicow exists then it will return null
horn = getGroundItems().closest("Unicorn horn"); // same as the unicow line
switch(getState()) // under here is the part where we define what each state does
{
case WORLDHOP:
state = "WORLDHOPPING"; // this changes the string state to display a different word, this is helpful to debug where exactly a script error is occuring
getWorlds().hopToP2PWorld(); //hop to a random p2p world
break; // always add a break; after each case
case DROP:
state = "DROPPING";
getInventory().dropAllExcept("Cowhide","Unicorn horn"); // drop all except these items
break;
case TRAVEL2AREA:
state = "TRAVELING";
getEquipment().interact(EquipmentSlot.CAPE, "Kandarin Monastery"); // interact with this cape
sleep(random(2300,2800)); //sleep for the loading screen (you can use a conditional sleep)
if(!kandarinarea.contains(myPlayer()))
{
door = objects.closest("Door");
if(door.hasAction("Open")) // it will only open a door if it has the action "Open" so if the door is already open it will not execute this
{
door.interact("Open");
sleep(random(800,1400));
getWalking().walkPath(Arrays.asList(toarea1)); //this walks a predefined path, most people prefer using the webwalker
RS2Object towerdoor = getObjects().closest("Tower door"); // defining a new RS2Object, this is bad practice, make sure you define your variable globally way up in the script to prevent junk buildup (everytime it executes this line it makes a new variable)
if(towerdoor.hasAction("Open"))
{
towerdoor.interact("Open");
sleep(random(800,1000));
}
}
else
{
getWalking().walkPath(Arrays.asList(toarea1));
towerdoor = getObjects().closest("Tower door");
if(towerdoor.hasAction("Open"))
{
towerdoor.interact("Open");
sleep(random(800,1000));
}
}
}
getWalking().webWalk(new Position[] {ladder}); // webwalking to a certain position called ladder which was globally defined above
trapdoor = objects.closest("Trapdoor");
if(trapdoor.hasAction("Open")) // if the trapdoor is closed then execute the first portion, else just execute the second portion (aka else statement)
{
trapdoor.interact("Open");
sleep(random(600,1000));
trapdoor.interact("Climb-down");
}
else
{
trapdoor.interact("Climb-down");
}
sleep(random(1600,2000));
getWalking().webWalk(position);
while(myPlayer().isMoving()){ // this is really bad practice, use a WalkingEvent, never use a while loop like this
sleep(300);
}
break;
case BANK:
state = "BANKING";
count1 = getInventory().getAmount("Unicorn horn"); // the amount of unicorn horns in the inventory
bank = objects.closest("Bank chest");
if(bank != null)
{
bank.interact("Use");
sleep(400);
while(myPlayer().isMoving())
{
sleep(300);
}
} // this is bad practice, what should have been done is if(bank is open) { execute banking portion } else { execute getting to bank and opening portion }
if(getBank().isOpen())
{
if(!getEquipment().isWearingItemThatContains(EquipmentSlot.RING, "Ring of dueling"))
{
getBank().depositAll();
totalcount += count1; // add the amount of unicorn horns banked to the total amount banked
getBank().withdraw("Cowhide", 16);
sleep(random(100,200));
getBank().withdraw("Unicorn horn", 1);
sleep(random(100,200));
getBank().withdraw("Ring of dueling(8)", 1);
getBank().close();
sleep(random(100,200));
getEquipment().equip(EquipmentSlot.RING, "Ring of dueling(8)");
}
else
{
getBank().depositAll();
totalcount += count1;
sleep(random(100,200));
getBank().withdraw("Cowhide", 14);
sleep(random(100,200));
getBank().withdraw("Unicorn horn", 1);
sleep(random(100,200));
getBank().close();
}
if(getSkills().getDynamic(Skill.HITPOINTS) < 40) // if HP is below 40
{
bank.interact("Use");
sleep(600);
getBank().withdraw("Salmon", 4);
getBank().close();
sleep(300);
while(getInventory().contains("Salmon")) // while inventory contains salmon, eat them
{
getInventory().interact("Eat","Salmon");
sleep(600);
}
}
}
break;
case TRAVEL2BANK:
state = "TRAVELING";
if(!bankarea.contains(myPlayer()))
{
getEquipment().interact(EquipmentSlot.RING, "Castle Wars");
new ConditionalSleep(3000) // this is the conditional sleep snippet that should have been used more often, make sure you save this snippet
{ // the number 3000 in the line above is the timeout number (the conditional sleep will end in that time)
@Override
public boolean condition() throws InterruptedException
{
return bankarea.contains(myPlayer()); // the condition that needs to be met to end the conditional sleep earlier
}
}.sleep();
}
break;
case IDLE:
break;
case SUMMON:
state = "SUMMONING";
if(!position.contains(myPlayer()))
{
getWalking().webWalk(position); // if you choose to use a webwalker this way you should always add a sleep after the getWalking() to prevent spam clicking
}
Entity fountain = getObjects().closest("Symbol of Life"); // needs to be defined globally to prevent junk buildup
if(fountain != null)
{
getInventory().interact("Use", "Unicorn horn");;
fountain.interact();
sleep(1250);
getInventory().interact("Use", "Cowhide");
fountain.interact();
sleep(500);
fountain.interact("Activate");
sleep(400);
if(getDialogues().inDialogue())
{
getDialogues().completeDialogue("Click here to continue");
}
}
sleep(1000);
break;
case FIGHT:
state = "FIGHTING";
if (unicow != null && unicow.exists() && unicow.isAttackable())
{
getInventory().deselectItem(); // failsafe since occasionally an item will be selected from the SUMMON state that will prevent combat
unicow.interact("Attack");
sleep(random(400));
while(myPlayer().isUnderAttack()) // this should be a conditional sleep that returns true if the player is under attack
{
sleep(random(300));
}
}
sleep(500);
break;
case LOOT:
state = "LOOTING";
if(horn != null)
{
if(getInventory().isFull() && getInventory().contains("Cowhide"))
{
getInventory().drop("Cowhide");
horn.interact("Take");
}
else
{
horn.interact("Take");
}
}
break;
}
return random(200) + 200;
}
@Override
public void onExit() { //place things that you want to happen during the exiting of the script; you can add the client to type the amount of unicow horns collected in the log
}
@Override
public void onPaint(Graphics2D g)
{
long ss = (System.currentTimeMillis() - startTime) / 1000; // long ss, long mm, and long hh are used to format the timer we started way above
long mm = ss / 60;
long hh = mm / 60;
long gainedexp = getExperienceTracker().getGainedXP(Skill.HITPOINTS) +
getExperienceTracker().getGainedXP(Skill.ATTACK) +
getExperienceTracker().getGainedXP(Skill.STRENGTH) +
getExperienceTracker().getGainedXP(Skill.DEFENCE); // adding all the exp gained so far
long gainedexphr = getExperienceTracker().getGainedXPPerHour(Skill.HITPOINTS) +
getExperienceTracker().getGainedXPPerHour(Skill.ATTACK) +
getExperienceTracker().getGainedXPPerHour(Skill.STRENGTH) +
getExperienceTracker().getGainedXPPerHour(Skill.DEFENCE); // adding the exp/hr calculations
Font font = new Font("Sans-Serif", Font.BOLD, 14); //defining a font of Sans-Serif that is bold and size 14
g.setColor(Color.WHITE); // setting the font color
g.setFont(font); // setting the font equal to what was defined 2 lines above
g.drawString("Status: " + state, 8, 303); // drawing these strings for this line and those below
g.drawString("Exp : " + gainedexp + " (" + gainedexphr + ")", 8, 318);
g.drawString("Run time: " + hh + ":" + mm%60 + ":" + ss%60 , 8, 333);
g.drawString("Amount Banked: " + totalcount, 230, 333);
}
}