- Joined
- Dec 3, 2013
- Messages
- 7,032
- Thread Author
- #1
Hey guys, just posting the source for my old alcher here as it was originally open source and fully commented. I'm moving it to my new framework and didn't want that to be public too 
This isn't quite a tutorial in the normal sense of the word but it's so heavily commented that it may as well be
I've only included the main script here as the other classes are really just helpers. Enjoy!
And here's the manifest. If you don't write a manifest for your script it won't show in the script selector. Save it as a .xml file anywhere in your script folder
This isn't quite a tutorial in the normal sense of the word but it's so heavily commented that it may as well be
I've only included the main script here as the other classes are really just helpers. Enjoy!
Code:
package com.runemate.maxiscripts.looping.alchemy;
//Imports are all the classes that we are going to use methods from
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import com.runemate.api.Calculations;
import com.runemate.api.actionbar;
import com.runemate.game.api.client.paint.PaintListener;
import com.runemate.game.api.hybrid.Environment;
import com.runemate.game.api.hybrid.RuneScape;
import com.runemate.game.api.hybrid.entities.definitions.ItemDefinition;
import com.runemate.game.api.hybrid.local.Skill;
import com.runemate.game.api.hybrid.local.hud.interfaces.InterfaceWindows;
import com.runemate.game.api.hybrid.local.hud.interfaces.Inventory;
import com.runemate.game.api.hybrid.local.hud.interfaces.SpriteItem;
import com.runemate.game.api.hybrid.util.StopWatch;
import com.runemate.game.api.osrs.local.hud.interfaces.Magic;
import com.runemate.game.api.rs3.local.CombatMode;
import com.runemate.game.api.rs3.local.hud.Powers;
import com.runemate.game.api.rs3.local.hud.interfaces.eoc.ActionBar;
import com.runemate.game.api.rs3.local.hud.interfaces.eoc.ActionWindow;
import com.runemate.game.api.rs3.local.hud.interfaces.eoc.SlotAction;
import com.runemate.game.api.script.Execution;
import com.runemate.game.api.script.framework.LoopingScript;
/* LoopingScript is the script framework we're going to use. Extending it forces us to have the onLoop method.
* It also gives us access to a heap of methods like onStart, getEventDispatcher and setLoopDelay to name a few.
* By extending it, our class is now of that type. For a full list of methods we inherit from LoopingScript look in
* the api or type 'this.' to list all methods we have direct access to.
* Implementing PaintListener gives us access to the onPaint method which is what draws things on the screen.
* For it to actually draw on the screen though you need to add this class to the event dispatcher as we do in onStart.
*/
public class MaxiAlcher extends LoopingScript implements PaintListener, MouseListener{
private boolean cast = false; //This will store whether the alchemy spell is currently selected
private String status = "Loading..."; //this will be used to store and print out the status
private final StopWatch runtime = new StopWatch(); //This will be used to show how long the script has been running
private int casts = 0; //stores how many times we've cast a spell and will be displayed to the user
private int startXp = -1; //this will store how much magic experience the user had when the script started.
private int startLvl = -1; //this will store what the users magic level was when the script started
private int xpGained = 0; //this will store how much magic experience the user has gained while running the script
private int lvlsGained = 0; //this will store how many magic levels the user has gained while running the script
private GUI gui; //this is an object of the gui that pops up when the script starts. without it the gui wouldn't show up
private Rectangle showGUI = new Rectangle(445, 300, 60, 25);
/* This method gets called automatically when the script first starts.
* args is a parameter parsed to the script
* String... is called a varargs and basically just means it can either be a single String, multiple Strings separated by a comma or a String array(String[])
* @Override means that you've inherited this method from one of the classes you've extended or implemented and that you want to call this version of the method
* instead of the one in the class it's inherited from
*/
@Override
public void onStart(String... args) {
getEventDispatcher().addListener(this); //This tells the client that this class has events that need to be listened for. In this case it's for the PaintListener to draw on the screen.
setLoopDelay(100, 200); //Sets the length of time in milliseconds to wait before calling onLoop again
System.out.println(getMetaData().getName() + " V" + getMetaData().getVersion() + " started!"); //This just prints to the console and consequentially the log file saying 'Thanks for using MaxiAlcher!'
gui = new GUI(); //This is where we actually instantiate the gui object.
}
//This is called when the script gets paused via the pause button on the client
@Override
public void onPause() {
runtime.stop(); //Stops the runtime timer so that the runtime doesn't keep counting time while the script is paused
}
//This is called when the script is unpaused via the resume button on the client
@Override
public void onResume() {
runtime.start(); //Resumes the runtime timer
}
//This is called just before the script stops
@Override
public void onStop() {
//All of the println's below print the session stats to the console/log before the script stops
System.out.println("---"+getMetaData().getName()+"---");
System.out.println("Runtime: " + runtime.getRuntimeAsString());
System.out.println("Last status: "+status);
System.out.println("Level: " + Skill.MAGIC.getCurrentLevel() + "(+" + lvlsGained + ")");
System.out.println("Xp gained: " + xpGained);
System.out.println("Casts: " + casts);
System.out.println("---Thanks for using " + getMetaData().getName() + "!---");
if (gui != null) {
gui.setVisible(false); //Makes sure the gui isn't visible
gui.dispose(); //Tells the garbage collector that the gui's memory can be freed for use elsewhere
}
}
//This gets called over and over and is the main body of your script.
@Override
public void onLoop() {
if (RuneScape.isLoggedIn() && !gui.isVisible()) { //If we're logged in to the game and the gui isn't visible continue inside this set of {}
/* If the startXp is still -1 (the initial value) and the players constitution experience is greater than 0 continue inside this set of {}
* We check the constitution to make sure the user is fully logged in as to avoid false startXp values
*/
if (startXp == -1 && Skill.CONSTITUTION.getExperience() > 0) {
runtime.start(); //Start the runtime timer
startXp = Skill.MAGIC.getExperience(); //Set the startXp to the players current magic experience
startLvl = Skill.MAGIC.getBaseLevel(); //Set the startLvl to the players current magic level
}
if (Inventory.containsAllOf("Nature rune") && Inventory.containsAnyOf(gui.getItems())) { //If the Inventory contains at least one Nature rune and one of the item the user has said to alch continue inside this set of {}
if (Environment.isOSRS() || CombatMode.LEGACY.isCurrent()) { //If we're playing osrs or the CombatMode is set to legacy continue inside this set of {}
if (InterfaceWindows.getMagic().isOpen()) { //If the magic interface is open continue inside this set of {}
/*
* This will set the status to 'Activating High Alchemy' if gui.highAlchemy() returns true
* If it returns false it will set the status to 'Activating Low Alchemy'.
* (gui.highAlchemy() ? "High Alchemy" : "Low Alchemy") is called a ternary statement
* and tells the script whether to say "High Alchemy" or "Low Alchemy"
* It's the same as writing the following:
* if (gui.highAlchemy() {
* return "High Alchemy";
* }
* else {
* return "Low Alchemy";
* }
*/
status = "Activating " + (gui.highAlchemy() ? "High Alchemy" : "Low Alchemy");
/*
* This time we've got a ternary statement as the return type of the first ternary statement
* This single line is the same as writing the following 16 lines:
* if (Environment.isOSRS()) {
* if (gui.highAlchemy()) {
* Magic.HIGH_LEVEL_ALCHEMY.activate();
* }
* else {
* Magic.LOW_LEVEL_ALCHEMY.activate();
* }
* }
* else {
* if (gui.highAlchemy()) {
* Powers.Magic.HIGH_LEVEL_ALCHEMY.activate();
* }
* else {
* Powers.Magic.HIGH_LEVEL_ALCHEMY.activate();
* }
* }
*/
if (Environment.isOSRS() ? (gui.highAlchemy() ? Magic.HIGH_LEVEL_ALCHEMY.activate() : Magic.LOW_LEVEL_ALCHEMY.activate()) : (gui.highAlchemy() ? Powers.Magic.HIGH_LEVEL_ALCHEMY.activate() : Powers.Magic.LOW_LEVEL_ALCHEMY.activate())) {
cast = true; //Set cast to true so the script knows the alchemy spell has been selected
Execution.delay(100, 200); //Wait a random amount of time between 100ms and 200ms before continuing
}
}//If the magic window wasn't open, check if the alchemy spell is selected. If not call openMagic()
else if (!cast) {
openMagic();
}
else {//If the magic window wasn't open and the alchemy spell is selected continue in here
if (InterfaceWindows.getInventory().isOpen()) {//if the inventory is open call castOn()
castOn();
}
else { //if the inventory isn't open, open it
if (InterfaceWindows.getInventory().open()) {
/*
* Here we wait for either the inventory to open or for 1 second to have passed.
* () -> is a new feature in java 8 and is called a lambda
* If i wasn't to use a lambda here this is what the code would have looked like:
* Execution.delayUntil(new Callable<Boolean>() {
*
* @Override
* public Boolean call() throws Exception {
* return InterfaceWindows.getInventory().open();
* }
* }, 1000);
*
* Lambdas strip away all that extra junk and leaves you with the functional line you actually wanted to write.
* () represents the call method and if it needed to take parameters we put the parameters like this (param1, param2, etc...) -> doSomething
*/
Execution.delayUntil(() -> InterfaceWindows.getInventory().open(), 1000);
}
}
}
}
else if (cast){ //If we're in RS3 and the CombatMode isn't Legacy and we have selected the alchemy spell call castOn()
castOn();
}
else { //If we're in RS3 and the CombatMode isn't Legacy and we haven't selected the alchemy spell call alchEoC()
alchEoC();
}
}
}
}
private void castOn() {
final SpriteItem item = Inventory.getItems(gui.getItems()).first(); //Get the first item in the inventory with the name that the user specified in the gui
if (item != null) { //If the item exists
String name = "item";
final ItemDefinition def = item.getDefinition();
if (def != null) {
final String temp = def.getName();
if (temp != null && !temp.isEmpty()) {
name = temp;
}
}
status = "Casting alchemy on " + name;
if (item.interact("Cast")) { //Try to interact with the item and if successful
cast = false; //Set cast to false as the spell is no longer selected
casts++; //Increase our spell cast counter
Execution.delayUntil(() -> InterfaceWindows.getMagic().isOpen(), 2000); //Wait until the magic window has opened again or until 2000 ms (2 seconds) has passed
}
else {
cast = false;
}
}
}
private void alchEoC() {
if (!ActionBar.isExpanded()) { //If the actionbar isn't expanded call expandActionbar()
expandActionbar();
}
else { //If it is expanded
final SlotAction action = actionbar.getSlot(gui.highAlchemy() ? "High Level Alch" : "Low Level Alch"); //Get the slot in the actionbar that contains the selected alchemy spell
if (action != null) { //If there actually is a slot with the spell on it call activateAlchemy() and parse the actionbar slot as a parameter
activateAlchemy(action);
}
else { //If there isn't a slot with the spell on it
if (InterfaceWindows.getMagic().isOpen()) { //If the magic interface is open
final Powers.Magic spell = (gui.highAlchemy() ? Powers.Magic.HIGH_LEVEL_ALCHEMY : Powers.Magic.LOW_LEVEL_ALCHEMY); //Get the spell
status = "Adding "+(gui.highAlchemy() ? "High Level Alchemy" : "Low Level Alchemy")+" to the action bar";
if (spell != null) { //if the spell exists
ActionBar.Slot empty = actionbar.getEmptySlot(); //Get the first empty actionbar slot
if (empty != null) { //if there was an empty slot
if (actionbar.addToActionbar(spell.getComponent().getBounds(), empty)) { //Add the spell to the actionbar in the empty slot
if (ActionWindow.MAGIC_ABILITIES.close()) { //close the magic window as we no longer need it (the spell is now on the actionbar)
Execution.delay(100, 200);
}
}
}
}
}
else { //If the magic interface isn't open call openMagic()
openMagic();
}
}
}
}
private void expandActionbar() {
status = "Expanding the action bar";
if (ActionBar.toggleExpansion()) { //Attempt to toggle the actionbars expansion, if successful wait until it has expanded or until 1 second has passed
Execution.delayUntil(() -> ActionBar.isExpanded(), 1000);
}
}
private void activateAlchemy(SlotAction action) {
final ActionBar.Slot slot = action.getSlot(); //Get the slot that contains the action
if (slot != null) { //If the slot exists
status = "Activating "+(gui.highAlchemy() ? "High Level Alchemy" : "Low Level Alchemy");
if (slot.getAction().activate()) { //Activate the slot (cast the spell)
cast = true;
Execution.delay(100, 200);
}
}
}
private void openMagic() {
status = "Opening spellbook";
if (InterfaceWindows.getMagic().open()) { //Attempt to open the magic book and is successful
Execution.delayUntil(() -> InterfaceWindows.getMagic().isOpen(), 1000);
}
}
/*
* This is where we put everything that we want to draw to the screen
* Graphics2D is the class that contains all the paint methods
*/
@Override
public void onPaint(final Graphics2D g) {
int x=50,y=50; //Set the initial drawing coordinates to 50 px to the right and down from the top left of the applet
g.setColor(Color.black);
g.fillRect(445, 300, 60, 25);
g.setColor(Color.white);
g.drawString("Settings", 450, 315);
xpGained = startXp == -1 ? 0 : Skill.MAGIC.getExperience() - startXp; //Set the xpGained to 0 if we haven't set the startXp yet, otherwise set it to the currentXp - startXp
final int lvl = Skill.MAGIC.getCurrentLevel(); //this will store the current magic level
lvlsGained = (startLvl == -1 ? 0 : lvl - startLvl); //Same deal as with xpGained
g.drawString("Version " + getMetaData().getVersion(), x, y+=15); //This will draw a string at the current x value and the current y value and then add 15 to the y value
g.drawString("Runtime: " + runtime.getRuntimeAsString(), x, y+=15);
g.drawString("Status: " + status, x, y+=15);
if (gui != null) g.drawString("Type: " + (gui.highAlchemy() ? "High Alchemy" : "Low Alchemy"), x, y+=15); //If the gui exists draw the spell that the user selected
g.drawString("Level: " + lvl + "(+" + lvlsGained + ")" , x, y+=15);
g.drawString("Xp Gained(/hr): " + xpGained + "(/" + Calculations.getHourly(xpGained, runtime.getRuntime()) + ")", x, y+=15); //Draw the xpGained as well as the amount of Xp they're gaining every hour at the current rate
g.drawString("Xp to next level: "+Skill.MAGIC.getExperienceToNextLevel(), x, y+=15);
g.drawString("Casts(/hr): " + casts + "(/" + Calculations.getHourly(casts, runtime.getRuntime()) + ")", x, y+=15);
}
@Override
public void mouseClicked(MouseEvent m) {
if (showGUI.contains(m.getPoint())) {
if (gui != null && !gui.isVisible())
gui.setVisible(true);
}
}
@Override
public void mouseEntered(MouseEvent arg0) {}
@Override
public void mouseExited(MouseEvent arg0) {}
@Override
public void mousePressed(MouseEvent arg0) {}
@Override
public void mouseReleased(MouseEvent arg0) {}
}
And here's the manifest. If you don't write a manifest for your script it won't show in the script selector. Save it as a .xml file anywhere in your script folder
Code:
<manifest>
<main-class>com.runemate.maxiscripts.looping.alchemy.MaxiAlcher</main-class>
<name>MaxiAlcher</name>
<description>Casts Low/High Alchemy</description>
<version>1.0.5</version>
<open-source>false</open-source>
<hidden>false</hidden>
<compatibility>
<game-type>OSRS</game-type>
<game-type>RS3</game-type>
</compatibility>
<categories>
<category>MAGIC</category>
<category>MONEYMAKING</category>
</categories>
<tags>
<tag>alchemy</tag>
<tag>money</tag>
</tags>
<tag>magic</tag><!--Required to publish on the bot store--><internal-id>alcher</internal-id>
</manifest>
Last edited: