SRL Archive - Archive

Camel - SRL Member Application


Camel

2014-10-11 21:47:17

How Long have You Played Runescape?
9 Year(s)


Are you affilated in anyway with Jagex LTD?
No

Were you Referred to SRL?



What is your general programming knowledge?
I am moderately experienced with C# and Java.


Are you a member of any other communities?
No


Tell us about yourself…
From: Camel
My name is Jack. I'm a student at Oklahoma State University majoring in chemical engineering. My interests are computer programming, and writing and recording music.

Computer programming has been a "sleeping" hobby of mine since I took AP computer science in high school. This class went over Java. To be honest, I don't actually remember what I learned in that class but according to the test results I was decent. After the class I didn't really do any programming for 3 years.

Then one day last summer I decided that I wanted to bot runescape again. (I had done it earlier using various other bots). One way or another I ended up here. I lurked around the forums for a few days and decided that I wanted to give scripting for runescape a shot. So I read through The Mayors tutorial and I felt like I picked up everything pretty quickly as I've seen most of it before and made a very bad Air rune crafter. Over the past 3 months I've been here, I've been consistently updating this script to the best of my ability and I think it may finally be complete (maybe). This is the script I will be submitting.



Please show us one (or multiple) of your scripts.
// application stuff

// Link Tutorial I made.

{ It isn't a script but I think it shows that I have some ability }

// https://villavu.com/forum/showthread.php?t=110546



{ Air Rune Crafter }

program AirCrafter;
{$DEFINE SMART}
{$I SRL-6/SRL.simba}
{$I SPS/lib/SPS-RS3.Simba}
{$i srl-6/lib/misc/srlplayerform.simba}

const

{------------------------------------------------------------------------------)
*Colors To Be Used*
If the script is not finding the desired object you can easily update the
colors by using ACA to find new colors and changing the values below.
(------------------------------------------------------------------------------}

{ Bankers in Varrock West Bank }
BANKER_COLOUR = 5582399;
BANKER_TOL = 9;
BANKER_HUE = 0.32;
BANKER_SAT = 0.83;

{ Air Altar Entrance - Use the blue color in the cracks }
ALTAR_RUIN_COLOUR = 12691328;
ALTAR_RUIN_TOL = 9;
ALTAR_RUIN_HUE = 0.33;
ALTAR_RUIN_SAT = 1.74;

{ Air Altar oval Bounds, this script uses a hard-coded oval to very quickly }
{ click the Altar, these are the ovals Bounds }
{ DISREGARD THIS IF NOT USING SMART }
ALTAR_X = 368;
ALTAR_Y = 102;
ALTAR_RADIUS_X = 40;
ALTAR_RADIUS_Y = 33;

{ Air Altar Colors - the gray colors on the altar in making the waves }
{ similar to the waves on an air rune }
ALTAR_COLOUR = 9140353;
ALTAR_TOL = 11;
ALTAR_HUE = 0.39;
ALTAR_SAT = 0.30;

{ Exit Portal - You will have to gather colors of the portal in multiple }
{ states of its glowing pattern }
{ DISREGARD THIS IF USING THE TELE TO VARROCK OPTION }
PORTAL_COLOUR = 6727080;
PORTAL_TOL = 24;
PORTAL_HUE = 0.04;
PORTAL_SAT = 0.47;


{==============================================================================)
| Global variable declaration |
(==============================================================================}

var
{ Player Form Variables }
TakeBreaks, Debug, Preset, Antiban, UseTele : Boolean;
World, runsToDo, PresetNumber : Integer;

{ Progress Report Variables }
RunsDone, RunesMade, EssPrice, RunePrice,x,y, Recoveries, LawRunePrice: Integer;
proggyBmp:integer;
BreakTime : Integer;

{ DTMs }
EssDTM, AltarDTM, StaffShopDTM : Integer;

{ SPS areas, arrays, and location check boxes }
spsMain, spsRecovery: TSPSArea;
PathToAltarA,PathToAltarB,PathToBankA,PathToBankB, PathToBankC, PathToBankD, RecoverPath : TPointArray;
BankBox,AltarBox : TBox;

{ A general procedure for leaving the altar, this will point to either }
{ TeleToVarrock() or LeaveAltarPortal() depending on what the }
{ user opts for in the form. }
LeaveAltar: procedure();

{==============================================================================)
| Stop Script |
|------------------------------------------------------------------------------|
| PURPOSE: Logs the player out and frees DTMs and the progress report bitmap. |
(==============================================================================}
procedure stopScript(reason : String);
begin
writeLn('Stopping script');
writeLn(reason);
if isLoggedIn() then
writeLn('Logging out');
players[currentPlayer].logout();
if not Preset then
freeDTM(EssDTM);
freeDtm(AltarDTM);
freeDtm(StaffShopDTM);
freeBitmap(proggyBmp);
writeLn('Done');
end;

{==============================================================================)
| LoadProggie |
|------------------------------------------------------------------------------|
| PURPOSE: Loads the progress report paint. |
(==============================================================================}
procedure LoadProggie();
begin
// Very long bitmapfromstring call
end;

{==============================================================================)
| Jagex Retardation |
|------------------------------------------------------------------------------|
| PURPOSE: Exits tresure hunter and claims any spin tickets found. |
(==============================================================================}
procedure JagexRetardation;
begin
exitTreasure;
claimTicket;
end;

{==============================================================================)
| Anti Pattern |
|------------------------------------------------------------------------------|
| PURPOSE: Various activities the script will occasionly partake in to |
| emulate human behavior. |
(==============================================================================}
procedure Antipattern;
var
i: integer;
begin
if not Antiban then
exit;

i := random(3000);
if i < 60 then
begin
writeLn('Doing antiban');
case i of
1..4: begin
writeLn('Taking Mini-break');
wait(gaussRangeInt(300000,420000));
if not isLoggedIn() then
begin
players[currentPlayer].login();
wait(gaussRangeInt(300,2000));
minimap.clickCompass();
mainscreen.setAngle(MS_ANGLE_HIGH);
JagexRetardation;
end;
end;
5..18: begin
hoverSkill(SKILL_RUNECRAFTING);
wait(gaussRangeInt(1500,5000));
gameTabs.openTab(TAB_BACKPACK);
end;
19..21: mouseMovingObject();
22..34: sleepAndMoveMouse(randomRange(100,6000));
35..45: begin
mouseOffClient(Random(4));
Wait(gaussRangeInt(10000,15000));
end;
46..53: Wait(gaussRangeInt(1000,1500));
54..60: pickUpMouse();
end;
writeLn('Antiban done');
end;
end;

{==============================================================================)
| Recover |
|------------------------------------------------------------------------------|
| PURPOSE: Teleports the player to the lodestone and walks to the front of the |
| bank. This is called if the player has failed to walk to the |
| desired destination for too long, or fails to accomplish an |
| activity in a timely manner. |
(==============================================================================}
procedure Recover;
begin
lodestoneScreen.teleportTo(LOCATION_VARROCK);
SmallRandomMouse(40);
wait(gaussRangeInt(15500,17500));
minimap.clickCompass();
mainscreen.setAngle(MS_ANGLE_HIGH);
spsRecovery.WalkPath(RecoverPath);
Recoveries := Recoveries + 1;
end;

{==============================================================================)
| Get Break Time |
|------------------------------------------------------------------------------|
| PURPOSE: Determines how long the player will play before taking a break |
(==============================================================================}
procedure GetBreakTime();
begin
// 60000 = 1 min
BreakTime := getSystemTime()
+ gaussRangeInt(gaussRangeInt(45,160) * 60000, gaussRangeInt(161,350) * 60000);
end;

{==============================================================================)
| Take Break |
|------------------------------------------------------------------------------|
| PURPOSE: Takes a break for 25 to 100 minutes |
| CREDITS: This method was taken from The Mayor's VEB Miner. |
(==============================================================================}
procedure takeBreak();
var
H, M, S, HH, MM, SS, breakFor, timeLeft: integer;
breakStartTimer: TTimeMarker;

begin
if not TakeBreaks then
exit;
if (getSystemTime() >= BreakTime) then
begin
if random(2) = 0 then
players[currentPlayer].logout()
else
players[currentPlayer].exitToLobby();
breakFor := gaussRangeInt(25 * 60000, 100 * 60000);
convertTime(breakFor, H, M, S);
writeLn('You are breaking for: ' + toStr(H)+ 'h ' + toStr(M)+ 'm ' + toStr(S)+ 's');
breakStartTimer.start();
repeat
timeLeft := breakFor - breakStartTimer.getTime();
convertTime(timeLeft, HH, MM, SS);
writeLn('Ending break in: ' + toStr(HH)+ 'h ' + toStr(MM)+ 'm ' + toStr(SS)+ 's');
wait(25000 + random(4000));
until breakFor < breakStartTimer.getTime();
GetBreakTime();
players[currentPlayer].login();
wait(gaussRangeInt(1500, 3500));
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
mainscreen.setZoom(true);
JagexRetardation;
end;
end;

{==============================================================================)
| Get GE Price |
|------------------------------------------------------------------------------|
| PURPOSE: Finds the GE price of an item and returns its value as an integer |
| CREDITS: This method was taken from The Mayor's VEB Miner. |
(==============================================================================}
function getGEPrice(itemString: string): integer;
var
wikiaPage, priceString: string;
begin
wikiaPage := getPage('http://runescape.wikia.com/wiki/Exchange:' +itemString);
priceString := between('GEPrice">', '</span>', wikiaPage);
result := strToIntDef(priceString, -1);
writeLn('-- ' + itemString + ' price: '+ toStr(result) + ' gp');
end;

{==============================================================================)
| Search ATPA for Object and click |
|------------------------------------------------------------------------------|
| PURPOSE: Given a ATPA, this function mouses over each element in the array |
| and clicks the an object if desired mousetext is found |
(==============================================================================}
procedure SearchForAndClickOnObject( ATPA : T2DPointArray; MouseOverText, ChooseOptions : array of string);
var
i : Integer;
begin
smartImage.debugATPA(ATPA);
for i := 0 to high(ATPA) do
begin
// Mouse the middle of the first TPA in the ATPA
mouse(middleTPA(ATPA[i]), MOUSE_MOVE);
// Check mouseOver
if isMouseOverText(MouseOverText, 500) then
begin
// Decide if its a right or left click.
if gaussRangeInt(0,8) = 4 then
begin
fastClick(MOUSE_RIGHT);
chooseOption.select(ChooseOptions);
end else
begin
fastClick(MOUSE_LEFT);
end;

// Sometimes move the mouse after clicking
if (gaussRangeInt(0,5) = 3) then
smallRandomMouse(50 + random(100));

//Clear the debug
smartImage.clearArea(mainScreen.getBounds);
Exit;
end;
end;
smartImage.clearArea(mainScreen.getBounds);
end;

{==============================================================================)
| Slot Of Air Runes |
|------------------------------------------------------------------------------|
| PURPOSE: Goes through each slot in the inventory looking for the white color |
| found on air runes. Once found, it returns the slot number as an |
| integer. |
(==============================================================================}
function SlotOfAirRunes() : integer;
var
i,x,y : integer;
boxes : TBoxArray;
begin
boxes := tabBackpack.getSlotBoxes();
for i:=0 to high(boxes) do
begin
if(findColorTolerance(x,y,13816539,boxes[i],15,colorSetting(1, 0.00, 0.00))) then
begin
result := i+1;
exit;
end;
end;
// defaults to one because its probably there
result := 1;
end;

{==============================================================================)
| Sort ATPA by change in Y |
|------------------------------------------------------------------------------|
| PURPOSE: Sorts an ATPA by the differnce in Y values of each TPA compared to |
| the Y value of the playerpoint. |
| NOTE: This is done with bubble sort. |
| There won't be more then 12 elements, so no reason to do bother |
| using a O(nLog(n)) algorithm. |
(==============================================================================}
procedure SortByChangeInY(var ATPA : T2DPointArray);
var
j, i : Integer;
Sorted : Boolean;
temp : TPointArray;
iteration : Integer;
begin
Sorted := False;
iteration := 0;

while (Sorted = False) do
begin
//Assume its sorted
Sorted := True;

// The highest element will always end up at the end of the array
// the "- iteration" makes the overall sort do less comparisons
for j := 1 to (high(ATPA) - iteration) do
begin

if((Abs(middleTPA(ATPA[j-1]).y - mainscreen.playerPoint.y)) >
(Abs(middleTPA(ATPA[j]).y - mainscreen.playerPoint.y))) then
begin
// Swap the values
Temp := ATPA[j];
ATPA[j] := ATPA[j-1];
ATPA[j-1] := Temp;

// This if block will be accessed unless the array IS sorted, so if this line runs
// the array is not yet sorted
Sorted := False;
end;
end;
iteration := iteration + 1;
end;
end;

function timeUntilBreak(): string;
var
breakFromNow, H, M, S: integer;
begin
breakFromNow := BreakTime - getSystemTime();
convertTime(breakFromNow, H, M, S);
result := (toStr(H)+ 'h ' + toStr(M)+ 'm ' + toStr(S)+ 's');
end;

{==============================================================================)
| IS In Altar |
|------------------------------------------------------------------------------|
| PURPOSE: This function looks for a DTM in the minimap that determines if the |
| player is in the altar or not. |
| NOTE: The DTM follows the shape of the brown surronding mound that altar |
| sits on. The waitTime input determines how long the function | |
| will continue looking before returning false. |
(==============================================================================}
function IsInAltar(waitTime: integer = 0) : Boolean;
var
t: TTimeMarker;
x,y: Integer;
begin
result := false;

if not isLoggedIn() then
exit;

t.start();
repeat
if(findDTM(AltarDTM,x,y,minimap.getBounds())) then
result := true;

wait(gaussRangeInt(30,120));
until (t.getTime() > waitTime) or (result);
end;

{==============================================================================)
| Tele To Varrock |
|------------------------------------------------------------------------------|
| PURPOSE: This procedure teleports the player to Varrock by clicking the |
| first slot on the action bar. |
| NOTE: It checks to see if the teleport was |
| successful by first waiting until it leaves the altar, then looking |
| for the StaffShop symbol on the minimap |
(==============================================================================}
Procedure TeleToVarrock;
var
x,y :Integer;
timer : TTimeMarker;
timer2 : TTimeMarker;
Begin
timer.start()
repeat
if Actionbar.clickSlot(1) then
RunesMade := RunesMade - 3;

if(gaussRangeInt(2,5)= 3) then
SmallRandomMouse(40);

timer2.Start();
repeat
wait(gaussRangeInt(40,200));
until(not IsInAltar(100)) or (timer2.getTime() > 5000);

wait(gaussRangeInt(400,1100));
until (FindDTM(StaffShopDTM,x,y,minimap.getBounds()) = true) or (timer.getTime > 30000);
end;

{==============================================================================)
| Craft Runes |
|------------------------------------------------------------------------------|
| PURPOSE: This procedure will click on the altar to make the runes. |
| NOTE: When entering the altar, the player will end up in the same spot |
| everytime, so on the first iteration the script mouses a hard |
| coded oval. If this fails for whatever reason, the script will |
| use color to search for the altar instead. |
(==============================================================================}
procedure CraftRunes();
var
x,y,i : Integer;
TPA : TPointArray;
ATPA : T2DPointArray;
timer : TTimeMarker;
firstRun: Boolean;
begin
smartImage.DrawEllipse(Point(ALTAR_X,ALTAR_Y),ALTAR_RADIUS_X,ALTAR_RADIUS_Y,false,5);
timer.start();
firstRun := True;

repeat
// Try Oval finding
if(firstRun) then
begin
mouseOval(ALTAR_X,ALTAR_Y,ALTAR_RADIUS_X,ALTAR_RADIUS_Y);
if isMouseOverText(['Craft', 'raft', '-rune'], 500) then
begin
if gaussRangeInt(0,8) = 4 then
begin
fastClick(MOUSE_RIGHT);
chooseOption.select(['raft','-rune','Altar']);
end else
begin
fastClick(MOUSE_LEFT);
end;

if (gaussRangeInt(0,5) = 3) then
smallRandomMouse(50 + random(100));
end;
end else
//Else color finding
begin
findColorsSpiralTolerance(x, y, TPA, ALTAR_COLOUR, mainScreen.getBounds(), ALTAR_TOL, colorSetting(2, ALTAR_HUE, ALTAR_SAT));
if (Length(TPA) < 1) then
begin
Exit;
end;
ATPA := TPA.toATPA(45, 45);
// Sort by size to click on the main altar and not one of the stones with
// small inscriptions of the same color
ATPA.sortBysize(true);
SearchForAndClickOnObject(ATPA,['Craft','raft','-runes'],['Craft','raft']);
end;

tabBackpack.waitForShift(randomRange(3000,4500));
wait(gaussRangeInt(700,1000));

// in case pack.count messes up or somehow the altar is clicked with no ess
if Conversationbox.isOpen then
begin
Conversationbox.continue(false,false);
exit;
end;

firstRun:= False;
until (tabBackpack.count < 3) or (timer.getTime > 20000) or (not isLoggedIn());
if timer.getTime < 20000 then
begin
JagexRetardation;
RunsDone := RunsDone + 1;
RunesMade := RunesMade + getItemAmount(tabBackpack.getSlotBox(SlotOfAirRunes()));
Exit;
end;
Recover;
end;

{==============================================================================)
| is In Bank |
|------------------------------------------------------------------------------|
| PURPOSE: This accurately determines if the player is in the bank. |
(==============================================================================}
Function isInBank() : Boolean
var
pos: TPoint;
begin
pos := spsMain.getPlayerPos();
result := pointInBox(pos, BankBox);
end;

{==============================================================================)
| Walk To Bank |
|------------------------------------------------------------------------------|
| PURPOSE: Walks the player to the bank, from either the altar or varrock |
| fountain. |
| NOTE: This function will repeat for up to 6 minutes, it will break out |
| early if the player is in the bank, after 1.5 minutes the function |
| will use the Recover procedure. |
(==============================================================================}
procedure WalkToBank();
var
walkTimer: TTimeMarker;
WalkPath : TPointArray;
begin
walkTimer.start();

if not minimap.isRunEnabled() then
minimap.toggleRun(true);

repeat
if not isLoggedIn() then
exit;

if isInBank() then
exit;

// 1.5 minutes
if walkTimer.getTime() > 90000 then
begin
Recover;
end;

if not UseTele then
begin
if(random(2) = 0 ) then
WalkPath := pathToBankA
else
WalkPath := pathToBankB;

end else
begin
if(random(2) = 0 ) then
WalkPath := pathToBankC
else
WalkPath := pathToBankD;
end;

if not UseTele then
begin
if not spsMain.walkPath(WalkPath) then
begin
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
end;
end else
begin
// walks player right outside of bank
// spsMain is used to walk inside the bank
if not spsRecovery.walkPath(WalkPath) then
begin
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
end;
// sps main is more accurate, puts the player somewhere in the bank
spsMain.walkToPos(Point(356+gaussRangeInt(-3,3), 149-random(5)));
end;
until walkTimer.getTime() > 300000;

StopScript('Failed to walk to the bank');
end;

{==============================================================================)
| is next to Altar |
|------------------------------------------------------------------------------|
| PURPOSE: This accurately determines if the player is next to the altar. |
(==============================================================================}
function IsNextToAltar() : Boolean
var
pos: TPoint;
begin
pos := spsMain.getPlayerPos();
result := pointInBox(pos, AltarBox);
end;

{==============================================================================)
| Walk To Altar |
|------------------------------------------------------------------------------|
| PURPOSE: Walks the player to the altar from the bank. |
| NOTE: This function will repeat for up to 6 minutes, it will break out |
| early if the player is next to the altar, after 1.5 minutes |
| the function will use the Recover procedure. After 6, |
| the script will terminate. |
(==============================================================================}
procedure WalkToAltar();
var
walkTimer: TTimeMarker;
WalkPath : TPointArray;
begin
walkTimer.start();

if not minimap.isRunEnabled() then
minimap.toggleRun(true);

repeat
if not isLoggedIn() then
exit;

if isNextToAltar() then
exit;

// 1.5 minutes
if walkTimer.getTime() > 90000 then
begin
Recover;
end;

if(random(2) = 0 ) then
WalkPath := pathToAltarA
else
WalkPath := pathToAltarB;

if not spsMain.walkPath(WalkPath) then
begin
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
end;

until walkTimer.getTime() > 300000;

StopScript('Failed to walk to the Altar');
end;

{==============================================================================)
| Open Bank |
|------------------------------------------------------------------------------|
| PURPOSE: Finds and clicks on the banker to open the bankscreen in VWB. |
| NOTE: This procedure uses the SortByChangeInY procedure to |
| avoid the player getting stuck behind the ropes walling each booth. |
(==============================================================================}
procedure OpenBank;
var
x, y : integer;
TPA : TPointArray;
ATPA: T2DPointArray;
timer : TTimeMarker;
begin
if not isLoggedIn() then
exit;

timer.start();
repeat

findColorsSpiralTolerance(x, y, TPA, BANKER_COLOUR, mainScreen.getBounds(), BANKER_TOL, colorSetting(2, BANKER_HUE, BANKER_SAT));
if (Length(TPA) < 1) then
begin
Exit;
end;

mainScreen.filterPointsPlayer(TPA);
ATPA := TPA.toATPA(15, 15);
FilterTPAsBetween(ATPA,1,25);
SortByChangeInY(ATPA);

SearchForAndClickOnObject(ATPA,['Bank','ank','nk B'],['Bank','anl']);

until (Bankscreen.isOpen(5000)) or (Pinscreen.isOpen(5000)) or (not isLoggedIn()) or (timer.getTime() > 20000);
end;

{==============================================================================)
| Enter altar |
|------------------------------------------------------------------------------|
| PURPOSE: Finds and clicks the air altar ruins to enter the air altar |
(==============================================================================}
procedure EnterAltar();
var
x, y : integer;
TPA: TPointArray;
ATPA: T2DPointArray;
timer : TTimeMarker;

begin
if not isLoggedIn() then
exit;

timer.start();
repeat
findColorsSpiralTolerance(x, y, TPA, ALTAR_RUIN_COLOUR, mainScreen.getBounds(), ALTAR_RUIN_TOL, colorSetting(2, ALTAR_RUIN_HUE, ALTAR_RUIN_SAT));
if (Length(TPA) < 1) then
begin
Exit;
end;

mainScreen.filterPointsPlayer(TPA);
ATPA := TPA.Cluster(30, 30);
FilterTPAsBetween(ATPA,1,40);
ATPA.sortBysize(true);

SearchForAndClickOnObject(ATPA,['Enter Myster','nter My','yster','ster'],['Enter','nter']);

until (IsInAltar(5000)) or (not isLoggedIn()) or (timer.getTime() > 20000);
end;

{==============================================================================)
| Leave Altar Portal |
|------------------------------------------------------------------------------|
| PURPOSE: Finds and clicks the portal in the air altar to leave the altar |
(==============================================================================}
procedure LeaveAltarPortal();
var
x, y : integer;
TPA: TPointArray;
ATPA: T2DPointArray;
timer : TTimeMarker;
timer2 : TTimeMarker;
begin
if not isLoggedIn() then
exit;
timer.start();
repeat
findColorsSpiralTolerance(x, y,TPA ,PORTAL_COLOUR, mainScreen.getBounds(), PORTAL_TOL, colorSetting(2, PORTAL_HUE, PORTAL_SAT));
if (Length(TPA) < 1) then
begin
exit;
end;

mainScreen.filterPointsPlayer(TPA);
ATPA := TPA.toATPA(25, 25);
// Cuts TPAs that have less then 31 points (colors) in them
FilterTPAsBetween(ATPA,1,30);
ATPA.sortFromMidPoint(mainscreen.playerPoint);

SearchForAndClickOnObject(ATPA,['Enter Portal','nter P','ortal','tal'],['Enter','nter']);;

//Waits about 6 seconds for the player to walk to and go through the portal
//this makes it so the bot doesn't spam click the portal
timer2.Start();
repeat
wait(gaussRangeInt(40,200));
until(not IsInAltar(100)) or (timer2.getTime() > 6000);

until (not IsInAltar(100)) or (not isLoggedIn()) or (timer.getTime() > 30000);

//Failing to leave the altar in 30 seconds would suggest something
//is going wrong. So it will loadstone
if (timer.getTime() > 30000) then
Recover;
end;


{==============================================================================)
| Deposit Runes |
|------------------------------------------------------------------------------|
| PURPOSE: Clicks the deposit inventory button in the bankscreen and exits. |
(==============================================================================}
procedure DepositRunes();
var
bankTimer: TTimeMarker;
begin
if bankScreen.isOpen() then
begin
bankTimer.start();
repeat

if (bankscreen.getPackCount() > 0) then
begin
bankScreen.quickDeposit(QUICK_DEPOSIT_INVENTORY);
wait(gaussRangeInt(1100, 1750));
end;

if(bankscreen.getPackCount() = 0) then
exit;

until (bankTImer.getTime() > 45000);
end;
end;

{==============================================================================)
| Withdraw ess |
|------------------------------------------------------------------------------|
| PURPOSE: Searches for a DTM of essense and withdraws them. |
(==============================================================================}
procedure WithdrawEss();
var
i: Integer;
begin
if(bankScreen.isOpen()) then
begin
repeat
if(bankscreen.withdraw(EssDTM,-1)) then
begin
wait(gaussRangeInt(500,1000));

if(bankscreen.getPackCount() > 0) then
begin
wait(gaussRangeInt(200,400));
bankscreen.close();
exit();
end;
end;
inc(i);
until i > 15
if (i> 15) then
StopScript('Failed to withdraw ess');
end;
end;

{==============================================================================)
| Use Bank |
|------------------------------------------------------------------------------|
| PURPOSE: Enters the bank pin, if open. Then either calls DepositRunes() and |
| Withdraw ess, or clicks the preset button depending on the users |
| choice |
(==============================================================================}
procedure UseBank();
var
timer : TTimeMarker;
begin
if Bankscreen.isOpen(3000) or Pinscreen.isOpen(2999) then
begin

if pinScreen.isOpen() then
pinScreen.enter(Players[currentPlayer].bankPin);

timer.start();
repeat
if Preset then
begin

// Presets exit the bankscreen
bankscreen.ClickButton(PresetNumber + 2);
wait(gaussRangeInt(100,300));
end else
begin
DepositRunes();

// Has bankscreen.close in it
WithdrawEss();
end;

until (not Bankscreen.isOpen) or (not isLoggedIn()) or (timer.getTime >30000);
end;
end;

{==============================================================================)
| Check for images |
|------------------------------------------------------------------------------|
| PURPOSE: Looks for the SPS images in the folder or downloads them if they |
| are not found. |
| CREDITS: I took this procedure from The Mayor's VEB miner |
(==============================================================================}
procedure checkForImages(path, link, item: string);
var
progFile: longInt;
picName: string;
begin
picName := AppPath + path;

try
if not fileExists(picName) then
begin
writeLn('NOTIFICATION: ' + item + ' does not exist - Downloading it now!');
progFile := createFile(picName);
end else
begin
writeLn('NOTIFICATION: ' + item + ' already exists!');
exit;
end;
closeFile(progFile);
progFile := rewriteFile(picName, false);
writeFileString(progFile, getPage(link));
writeLn('NOTIFICATION: ' + item + ' has been download to Simba folder!');
writeLn('');
finally
if (progFile > 0) then
closeFile(progFile);
end;
end;


procedure initPlayerForm();
begin
with playerForm do
begin
name := 'Buttdestroyr''s Aircrafter V3';

editBoxLabels := ['World','Runs To Do'];
editBoxDefaults := [ '0', '100'];

checkBoxLabels := ['Take Breaks', 'Debug','Use Preset','Antiban','Use Tele to Varrock (Preset Only)'];
checkBoxDefaults := ['True','False','False','True','False'];

comboBoxLabels := ['Preset Number'];
comboBoxDefaults := ['1'];

setLength(comboBoxItems, length(comboBoxLabels));
comboBoxItems[0] := ['1', '2'];
end;
end;


procedure setup();
var
i : Integer;
begin
smartEnableDrawing := true;

PresetNumber := -1;
Recoveries := 0;

initPlayerForm();
runPlayerForm();

// Stops the script if the user exits the form
if (not playerForm.isScriptReady) then
terminatescript;

// Sets global variables from the playerform
players.Setup(playerForm.playerNames, playerForm.playerFile);
currentPlayer := 0;
for i := 0 to high(players) do
with players[i] do
begin
World := strToInt(playerForm.players[i].settings[0]);
players[currentPlayer].world := World;
RunsToDo := strToInt(playerForm.players[i].settings[1]);
Debug := strToBool(playerForm.players[i].settings[3]);
TakeBreaks := strToBool(playerForm.players[i].settings[2]);
Preset := strToBool(playerForm.players[i].settings[4]);
Antiban := strToBool(playerForm.players[i].settings[5]);
UseTele := strToBool(playerForm.players[i].settings[6]);
if Preset then
PresetNumber := strToInt(playerForm.players[i].settings[7]);
end;

smartPlugins := ['d3d9.dll'];

setupSRL();
disableSRLDebug := not Debug;

checkForImages('Includes/SPS/img/runescape_surface/recovery_path.png', 'http://i.imgur.com/kmeBd97.png', 'Recovery map');
checkForImages('Includes/SPS/img/runescape_surface/air_altar_path.png', 'http://i.imgur.com/eFDFsbD.png', 'Main map');

spsMain.setup('air_altar_path', RUNESCAPE_SURFACE);
spsRecovery.setup('recovery_path',RUNESCAPE_SURFACE);

//Check boxes used in isInBank and isNextToAltar
BankBox := intToBox(330,119,380,162);
AltarBox := intToBox(98,258,140,297);

//Paths used in this script
RecoverPath := [Point(171, 292), Point(171, 272), Point(171, 247), Point(171, 224),
Point(169, 197), Point(168, 159), Point(163, 136), Point(156, 110),
Point(124, 110), Point(91, 104), Point(75, 105)];

pathToAltarA := [Point(355, 148), Point(354, 164), Point(351, 182), Point(338, 187),
Point(315, 190), Point(284, 195), Point(271, 205), Point(262, 215),
Point(255, 224), Point(239, 230), Point(222, 239), Point(203, 239),
Point(175, 237), Point(156, 237), Point(136, 245), Point(135, 255),
Point(123, 287)];

pathToAltarB := [Point(353, 185), Point(333, 184), Point(311, 189), Point(286, 194),
Point(271, 202), Point(261, 217), Point(234, 218), Point(218, 227),
Point(195, 237), Point(156, 237), Point(136, 241), Point(126, 267),
Point(127, 277)];

pathToBankA := [Point(134, 259), Point(137, 243), Point(155, 236), Point(179, 237),
Point(218, 236), Point(236, 231), Point(252, 223), Point(269, 209),
Point(289, 191), Point(304, 188), Point(330, 188), Point(353, 184),
Point(356, 149)];

pathToBankB := [Point(130, 243), Point(152, 237), Point(193, 245), Point(217, 238),
Point(244, 226), Point(267, 216), Point(274, 200), Point(301, 191),
Point(327, 189), Point(327, 189), Point(346, 186), Point(352, 155)];
// Tele To Varrock Paths
pathToBankC := [Point(155, 107), Point(121, 107), Point(102, 101), Point(69, 101)];
pathToBankD := [Point(157, 117), Point(145, 107), Point(121, 107), Point(93, 105), Point(67, 101)];

if UseTele then
begin
//Point LeaveAltar at TeleToVarrock
LeaveAltar := @TeleToVarrock;

//Load law rune price for progress report
LawRunePrice := getGEPrice('Law_rune');
end else
begin
//Point LeaveAltar at LeaveAltar Portal
LeaveAltar := @LeaveAltarPortal;
end;

// Load the DTMs
AltarDTM := DTMFromString('m6wAAAHic42ZgYChnZmDYB8Q7gXg7EM8C4mogLgTiLCCuhLJBco6MDAy2QCwNxP+Bej8A8XMgZgXyhYDYC4i9gdgAiGMCjIjGckAziMWMJGAkAAAbhRWV');

if UseTele then
StaffShopDTM := DTMFromString('mbQAAAHicY2VgYAhjYWAIAeIAII5lgfDbgOL1QNwCxK1A3A/EC1siGTaf+cawZN8bhvm7XjGU9x9lYAWKo2NGLBgMALg7DtE=');

if not Preset then
EssDTM := DTMFromString('mWAAAAHicY2FgYMhmhuAYIK4AYm1GBgZLRgitC8QuTo5AVUxwzMWAChjRMAgAAN/AA1Y=');

RunesMade :=0;

//Calls the monster bitmapfromString
//LoadProggie;

// Get the prices
RunePrice := getGEPrice('Air_rune');
EssPrice := getGEPrice('Rune_essence');

// When the script is stopped it will run the StopScript() function
addOnTerminate('stopScript');
end;


procedure PaintProgress();
var
RunesPerHour : Integer;
RunsPerHour : Integer;
ExperienceGained : Integer;
ExperiencePerHour : Integer;
ProfitGained : Integer;
ProfitPerHour : Integer;
begin
RunesPerHour := round((RunesMade) * (3600.0 / (GetTimeRunning / 1000.0)));
RunsPerHour := round((RunsDone) * (3600.0 / (GetTimeRunning / 1000.0)));
ExperienceGained := RunsDone * 140;
ProfitGained := ( (RunesMade*RunePrice) - ((RunsDone*28) * EssPrice) );

if UseTele then
begin
// compensate statistics for the law rune and all
ProfitGained := (ProfitGained - (RunsDone * LawRunePrice));
ProfitGained := ProfitGained - (EssPrice * RunsDone);
ExperienceGained := ExperienceGained - (RunsDone * 5);
end;

ExperiencePerHour := round((ExperienceGained) * (3600.0 / (GetTimeRunning / 1000.0)));
ProfitPerHour := round((ProfitGained) * (3600.0 / (GetTimeRunning / 1000.0)));

// Draw the lettering
smartImage.clearArea(chatbox.getBounds);
//smartImage.drawBitmap(proggyBmp, point(2, 462));
smartImage.drawClippedText('Time Ran: ' + msToTime(getTimeRunning(), TIME_SHORT) + '', point(90, 520), 'UpChars07', true, clWhite);
smartImage.drawClippedText('XP Gained: ' + toStr(ExperienceGained) + '', point(90, 540), 'UpChars07', true, clWhite);
smartImage.drawClippedText('XP per Hour: ' + toStr(round(ExperiencePerHour)) + '', point(90, 560), 'UpChars07', true, clWhite);
smartImage.drawClippedText(': ' + toStr(ProfitGained) + ' ('+toStr(ProfitPerHour)+' PH)', point(350, 525), 'UpChars07', true, clYellow);
smartImage.drawClippedText(': ' + toStr(RunesMade) + ' ('+toStr(RunesPerHour)+' PH)', point(350, 555), 'UpChars07', true, clWhite);
end;


{==============================================================================)
| Main Loop |
|------------------------------------------------------------------------------|
| PURPOSE: Yes. |
| Note: Through various if statements, the mainloop can determine at what |
| stage in the cycle it is at. Also, for the script to go through an |
| entire air-rune-crafting-iteration this procedure will be called |
| four times. |
(==============================================================================}
procedure MainLoop();
begin
// > 2 for the possible law rune
if tabBackpack.count > 2 then
begin

if IsInAltar(400) then
begin
craftRunes();
end else
begin
WalkToAltar();
EnterAltar();
end;

end else
begin

if IsInAltar(400) then
begin
LeaveAltar();
end else
begin
WalkToBank();
OpenBank();
UseBank();
end;
end;

PaintProgress;
Antipattern;
TakeBreak;

if TakeBreaks Then
writeln('Next Break: ' + timeUntilBreak());
end;


begin
clearDebug();
setup();
GetBreakTime();

// IF the script is started when the user is already logged in
if isLoggedIn() then
begin
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
mainscreen.setZoom(true);
JagexRetardation;
end;

repeat

if not isLoggedIn() then
begin
players[currentPlayer].login();
wait(randomRange(1500, 3000));
minimap.clickCompass();
mainScreen.setAngle(MS_ANGLE_HIGH);
mainscreen.setZoom(true);
JagexRetardation;
end;

mainLoop;

until RunsDone > RunsToDo;
end.

NKN

2014-10-11 21:51:06

Yes.

Kyle

2014-10-11 21:54:30

Was wondering when you were going to apply. This one is quite obviously a yes!

PS: Hands down the cleanest looking procedure/function commenting I have ever seen.

riwu

2014-10-11 22:00:36

Yes. You have demonstrated well use of arrays in the script.
Though things like:
SearchForAndClickOnObject(ATPA,['Craft','raft','-runes'],['Craft','raft']); 
'raft' is a substring of 'Craft' so it would be redundant. Pretty minor though but good to get rid of for a cleaner script :)

Ian

2014-10-11 22:25:11

You appear to have listened to many of the suggestions in your previous app, that's good.

I'm sure there is a name that would be more accurate to describe what this procedure does. Something like 'fixJagexRetardation' or even 'removeTHThings'.

procedure JagexRetardation;
begin
exitTreasure;
claimTicket;
end;

Yes from me :)

Hoodz

2014-10-12 06:49:15

From: BMWxi
You appear to have listened to many of the suggestions in your previous app, that's good.

I'm sure there is a name that would be more accurate to describe what this procedure does. Something like 'fixJagexRetardation' or even 'removeTHThings'.

procedure JagexRetardation;
begin
exitTreasure;
claimTicket;
end;

Yes from me :)


meh treasure thingy is retarded so its well described ;)


—
yes from me

Sjoe

2014-10-12 07:22:37

yes, just for that tutorial alone :p

Ross

2014-10-12 14:30:32

Glad you applied again, still abstaining for now, but my vote would be a yes.

A+ on that tutorial, would love to see some more scripts from you! See if you can find a way to incorporate that bitmapFromString without clogging up 900 lines in your main script!

Hoodz

2014-10-12 14:32:22

From: Ross
Glad you applied again, still abstaining for now, but my vote would be a yes.

A+ on that tutorial, would love to see some more scripts from you! See if you can find a way to incorporate that bitmapFromString without clogging up 900 lines in your main script!


i believe loadBitmap would work

Brandon

2014-10-12 15:29:05

I rarely ever vote. I actually have no idea what anyone else is talking about. I've never seen or heard of "Camel" before. However, that has to be one of the best comment formats I've ever seen in an app or anywhere on this site. The code is legible, nice and clean!

Now for what I dislike. StrToBool or StrToInt. My personal preference is StrToBoolDef or StrToIntDef. I'm not a big fan of having exceptions being thrown in scripts for something like converting a string to bool or int. However, that's just minor preferences and takes nothing away from your script. If anything, it just serves as a warning and tells the user they're doing something wrong by throwing an exception rather than running with defaults.

But again, yes from me.

The Mayor

2014-10-12 16:47:58

Yes.

Ashaman88

2014-10-12 17:51:23

From: Brandon
I rarely ever vote. I actually have no idea what anyone else is talking about. I've never seen or heard of "Camel" before. However, that has to be one of the best comment formats I've ever seen in an app or anywhere on this site. The code is legible, nice and clean!

Now for what I dislike. StrToBool or StrToInt. My personal preference is StrToBoolDef or StrToIntDef. I'm not a big fan of having exceptions being thrown in scripts for something like converting a string to bool or int. However, that's just minor preferences and takes nothing away from your script. If anything, it just serves as a warning and tells the user they're doing something wrong by throwing an exception rather than running with defaults.

But again, yes from me.


Previously known as Buttdestroyr.

But I also vote yes

CynicRus

2014-10-12 23:07:45

Yes from me.

Kevin

2014-10-13 08:43:45

Part of me wanted to say no to ruin that beautiful streak you have going, but it would be wrong. ;) You obviously deserve the position, you took tons of advice from the last app, you became more active, and you released a damn beautiful tutorial on a subject that is rarely covered and actually useful - that should also help lots of people.

After having noticed your improved community involvement, and reading the tutorial (and the code therein), I don't even have to read this application to truthfully and confidently say yes.

Clarity

2014-10-13 13:08:07

Your drive after the last app is impressive, I look forward to seeing more from you after you get that golden name!

I am also a big fan of JagexRetardation;

Benny

2014-10-14 19:12:35

No….. GL son








YES

Kyle

2014-10-14 20:48:08

Why does someone always have to vote no on a perfect app?

Ross

2014-10-14 23:20:33

From: elfyyy
Why does someone always have to vote no on a perfect app?


So I can maintain highest app ratio.

The Mayor

2014-10-15 00:09:37

From: Ross
So I can maintain highest app ratio.

@Benny; is known for his perfect score without anyone swinging the votes ;)


E: Looks like you're no longer gonna be eligible for the comp! :(

Benny

2014-10-17 22:30:52

From: Ross
So I can maintain highest app ratio.

Nah boss I'm one of the few with dat 100% record.
Haha but no I did vote yes. He deserved it this time.
From: The Mayor
@Benny; is known for his perfect score without anyone swinging the votes ;)


E: Looks like you're no longer gonna be eligible for the comp! :(

Daniel

2014-10-17 23:02:10

In.

Congratulations. :)