SRL Archive - OSR Help

How can I make this shorter/neater?


Wardancer

2012-09-07 10:23:23

So I'm rewriting a few functions of grandexchange.simba (quite the educating process) and I came upon what I would call an aesthetic issue. First, I should say what the code does. It basically lets you pick which slot you want to buy from the GE ('any' or 1 to 6). I built in a failsafe that returns a message if the slot isn't free, but in the process I ended up writing a "begin end" with nothing in middle since I didn't want to repeat the same action for the 7 options and make this look even more atrocious. In case that wasn't clear, the action I want it to do if the value is true is the same for the 7 options. Let me show you the code (which works flawlessly as far as I can tell):

function BuyGE(spot : String): Boolean;
var
x, y : Integer;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
'any':
if (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
end else
begin
Writeln('No slot is free');
Exit;
end;
'1':
if (FindObject(x,y,BuyButton,35,85,173,190)) then
begin
end else
begin
Writeln('This slot is not free');
Exit;
end;
'2':
if (FindObject(x,y,BuyButton,190,85,328,190)) then
begin
end else
begin
Writeln('This slot is not free');
Exit;
end;
'3':
if (FindObject(x,y,BuyButton,346,85,485,190)) then
begin;
end else
begin
Writeln('This slot is not free');
Exit;
end;
'4':
if (FindObject(x,y,BuyButton,35,200,170,310)) then
begin
end else
begin
Writeln('This slot is not free');
Exit;
end;
'5':
if (FindObject(x,y,BuyButton,190,200,330,310)) then
begin
end else
begin
Writeln('This slot is not free');
Exit;
end;
'6':
if (FindObject(x,y,BuyButton,345,200,480,300)) then
begin
end else
begin
Writeln('This slot is not free');
Exit;
end;
end;
begin;
ClickMouse2(true);
WaitOption('Buy O',500);
WaitFunc(@GEEBuyMenu,10,6000);
end;
end;

I considered coding a separate function which would be the failsafe itself (I really dislike the way I'm repeating many times the same Writeln message), but I was curious about other people's opinions. I'll more than likely be coding that other function which will act as the failsafe by the time someone replies (wondering if I can code this a simple way without using "spot" as a global variable at the moment), but I'd like to know how other people would tackle this issue.

Any suggestion regarding how I coded this is more than welcome. Also, if you have any question, feel free to ask me.

riwu

2012-09-07 10:33:55

Since you are not doing any action if condition is false, you can just do:
if not condition then blabla.

eg:
if not (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
Writeln('No slot is free');
Exit;
end;

Also you dont need the begin and end after ur case statement.

litoris

2012-09-07 10:45:45

function BuyGE(spot : String): Boolean;
var
x, y, XS, YS, XE, YE : Integer;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
'any':
begin
XS := MSX1;
YS := MSY1;
XE := MSX2;
YE := MSY2;
end;
'1':
begin
XS := 35;
YS := 85;
XE := 173;
YE := 190;
end;
//go on like this...
end;
if not (FindObject(x,y,BuyButton,345,200,480,300)) then //pointless to do an empty begin-end staetement
begin //using not instead
Writeln('This slot is not free');
Exit;
end;
ClickMouse2(true);
WaitOption('Buy O',500);
WaitFunc(@GEEBuyMenu,10,6000);
end;
Fixed the standards too.

Wardancer

2012-09-07 10:59:51

Thank you very much. I was actually wondering if the "if not" could be used that way. For some reason, I wasn't able to fully grasp it.

I really love the way you wrote it down, litoris. I really dread repetition, yet I don't have the knowledge or experience to deal with it appropriately yet. I hadn't considered this way of fixing it and I'm sure it'll be extremely useful in the future even though it's a basic use of variables. I can already think of a few other functions I'll be using it with.

litoris

2012-09-07 11:01:09

From: Wardancer
Thank you very much. I was actually wondering if the "if not" could be used that way. For some reason, I wasn't able to fully grasp it.

I really love the way you wrote it down, litoris. I really dread repetition, yet I don't have the knowledge or experience to deal with it appropriately yet. I hadn't considered this way of fixing it and I'm sure it'll be extremely useful in the future even though it's a basic use of variables. I can already think of a few other functions I'll be using it with.


No problem. The best way to learn handy stuff like this is to read through people's scripts. I learned 90% of the things I know that way, and the rest from tutorials.

masterBB

2012-09-07 11:05:06

function BuyGE(spot : String): Boolean;
var
x, y: Integer;
searchBox: TBox;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
'any':
searchBox := IntToBox(MMX1, MMY1, MMX2, MMY2);
'1':
searchBox := IntToBox(35, 85, 173, 190);
//go on like this...
end;
if not (FindObject(x,y,BuyButton, searchBox.x1, searchBox.y1, searchBox.x2, searchBox.y2)) then //pointless to do an empty begin-end staetement
begin //using not instead
Writeln('This slot is not free');
Exit;
end;
ClickMouse2(true);
WaitOption('Buy O',500);
WaitFunc(@GEEBuyMenu,10,6000);
end;

litoris

2012-09-07 12:02:49

^I think my version is better when it comes to editing, but yours looks nicer if it's going to be in the include.

masterBB

2012-09-07 12:10:44

procedure BuyGE(spot : String);
var
x, y: Integer;
searchBox: TBox;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
'any':
searchBox := IntToBox(MMX1, MMY1, MMX2, MMY2);
'1':
searchBox := IntToBox(35, 85, 173, 190);
//go on like this...
end;
if (FindObject(x,y,BuyButton, searchBox.x1, searchBox.y1, searchBox.x2, searchBox.y2)) then //pointless to do an empty begin-end staetement
begin
ClickMouse2(true);
WaitOption('Buy O', 500);
WaitFunc(@GEEBuyMenu, 10, 6000);
end else
Writeln('This slot is not free');
end;

This is how I would do it. I think boxes should be used when possible over 4 integers.

Runaway

2012-09-07 12:37:41

Building on Bart's version:


function BuyGE(spot: String): Boolean;
var
s, x, y: Integer;
searchBox: TBox;
begin
Result := False;
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
if (spot = 'any') then
searchBox := IntToBox(MMX1, MMY1, MMX2, MMY2)
else
begin
s := StrToInt(spot);
if not InRange(s, 1, 6) then
begin
Writeln('Invalid slot value!');
Exit;
end;
searchBox := IntToBox(35 + ((s - 1) mod 3 * 155), 85 + (Floor(s / 4.0) * 115), 170 + ((s - 1) mod 3 * 155), 190 + (Floor(s / 4.0) * 115));
end;
if not (FindObject(x, y, BuyButton, searchBox.x1, searchBox.y1, searchBox.x2, searchBox.y2)) then
begin
if (spot = 'any') then
Writeln('No slots are free!')
else
Writeln('Slot '+ spot +' is not free!');
Exit;
end;
ClickMouse2(true);
if WaitOption('Buy O', 500) then
Result := WaitFunc(@GEEBuyMenu, 10, 6000);
end;

Perfect scenario for some mods & floors ;)

Wardancer

2012-09-07 12:55:50

Thank you for this other example, masterBB. Makes me realize there are so many ways to code the same thing.

What is your (everyone) opinion on records? In this particular case, I think it would be superfluous, but I'm wondering if it's actively used by people. I only know one script (from NKN) that uses it in his custom find object function.

EDIT: Thank you Runaway for this. I was actually scratching my head wondering how to do -exactly- this yesterday (assuming I'm understanding what you wrote). I don't fully understand "mod" and "floor". Got to look it up… okay the search was a bit of a waste as I didn't find anything regarding mod and floor, but it led me to opening the math include which has a great function that would let me do exactly that (I think) (GridBox). I'll try to come up with my own version to see if it works.

masterBB

2012-09-07 13:03:26

I kind off accidentally swapped MM with MS, but there are indeed a lot of options to solve the same problem. Runaway his version is the best, but personally I try to keep the amount of formulas a bit low. It will make your code harder to read.

Records are cool. There are no pros and cons in the way they work opposed to multiple variables.

Runaway

2012-09-07 16:21:19

From: Wardancer
EDIT: Thank you Runaway for this. I was actually scratching my head wondering how to do -exactly- this yesterday (assuming I'm understanding what you wrote). I don't fully understand "mod" and "floor". Got to look it up… okay the search was a bit of a waste as I didn't find anything regarding mod and floor, but it led me to opening the math include which has a great function that would let me do exactly that (I think) (GridBox). I'll try to come up with my own version to see if it works.


I'll give you a small overview of both of them :)

Mod is a special divisor operator that returns the remainder rather than the answer. Example:


0 mod 2 = 0
1 mod 2 = 1
2 mod 2 = 0
3 mod 2 = 1
etc...

It's very useful for a continuous pattern. If i is any real number, then:


if (i mod 2 = 0) then
Writeln('i is an even number.');

You can effectively check whether i is even or odd. In the BuyGE code I posted above, I used i mod 3 to determine what the x1 value would be since the difference pattern was:


x1: 35, 190, 345, 35, 190, 345
or
x1: 35 + (155*0), 35 + (155*1), 35 + (155*2), etc.

Since the pattern i mod 3 creates follows the same routine (0, 1, 2, 0, 1, 2):


0 mod 3 = 0
1 mod 3 = 1
2 mod 3 = 2
3 mod 3 = 0
4 mod 3 = 1
etc...

I knew that the following equation could be used to determine the value of x1 relative to the value of i:


for i := 1 to 6 do
begin
x1 := 35 + ((i - 1) mod 3 * 155);
Writeln(x1);
end;

Hopefully that will cover the basic usage of mod! As for floor, I use it as a version of mod with a 'greater interval'. Since the difference pattern of y1 was:


y1: 85, 85, 85, 200, 200, 200
or
x1: 85 + (115*0), 85 + (115*0), 85 + (115*0), 85 + (115*1), 85 + (115*1), 85 + (115*1)

A simple mod approach would not work. Floor rounds down the value to the nearest whole number, so it can be used to measure patterns that stick to the same number for more than 1 repetition. Since:


Floor(1 / 4.0) = 0
Floor(2 / 4.0) = 0
Floor(3 / 4.0) = 0
Floor(4 / 4.0) = 1
Floor(5 / 4.0) = 1
etc...

I used that method to produce the pattern we observed for y1 above, making the equation to determine the value of y1 relative to the value of i:


for i := 1 to 6 do
begin
y1 := 85 + (Floor(i / 4.0) * 115);
Writeln(y1);
end;

So, it all relates back to observing a pattern and finding an equation to replicate the pattern based upon differences. The best way to learn more complex uses of this would be to jump right into it and try to solve complex patterns with these (and other) functions :)

Here's the code I used to quickly determine the equations for the code you posted:


program new;
{$I SRL/SRL.simba}
var
Box: TBox;
i: Integer;
x1, y1, x2, y2: Integer;
begin
// x1: 35, 190, 345, 35, 190, 345 (155)
// y1: 85, 85, 85, 200, 200, 200 (115)
// x2: 170, 325, 480, 170, 325, 480 (155)
// y2: 190, 190, 190, 305, 305, 305 (115)
for i := 1 to 6 do
begin
x1 := 35 + ((i - 1) mod 3 * 155);
y1 := 85 + (Floor(i / 4.0) * 115);
x2 := 170 + ((i - 1) mod 3 * 155);
y2 := 190 + (Floor(i / 4.0) * 115);
Box := IntToBox(x1, y1, x2, y2);
Writeln(Box);
end;
end.

Once you pinpoint a pattern, it's actually quite simple to work out the code to replicate it!

litoris

2012-09-07 16:53:45

From: Runaway
I'll give you a small overview of both of them :)

Mod is a special divisor operator that returns the remainder rather than the answer. Example:


0 mod 2 = 0
1 mod 2 = 1
2 mod 2 = 0
3 mod 2 = 1
etc...

It's very useful for a continuous pattern. If i is any real number, then:


if (i mod 2 = 0) then
Writeln('i is an even number.');

You can effectively check whether i is even or odd. In the BuyGE code I posted above, I used i mod 3 to determine what the x1 value would be since the difference pattern was:


x1: 35, 190, 345, 35, 190, 345
or
x1: 35 + (155*0), 35 + (155*1), 35 + (155*2), etc.

Since the pattern i mod 3 creates follows the same routine (0, 1, 2, 0, 1, 2):


0 mod 3 = 0
1 mod 3 = 1
2 mod 3 = 2
3 mod 3 = 0
4 mod 3 = 1
etc...

-snip-
Once you pinpoint a pattern, it's actually quite simple to work out the code to replicate it!


This was a great read, thanks!

Wardancer

2012-09-07 17:33:50

Thank you for the explanation. Here is the code I came up with by myself using GridBox. I'm having an issue with standards though…

function BuyGE(spot : integer): Boolean;
var
x, y : Integer;
a : TBox;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
0:
if not (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
writeln('No spot is free')
Exit;
end;
1..6:
begin;
a:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,BuyButton,a.x1,a.y1,a.x2,a.y2) then
begin
writeln('This spot is not free')
Exit;
end;
begin;
ClickMouse2(true);
WaitOption('Buy O',500);
WaitFunc(@GEEBuyMenu,10,6000);
end;
end;
end;
end;

First, I have to say that I -know- that all those begin and end look atrocious but that was the only way I could get the script to work. Removing a single begin or end (even trying to just place it somewhere else) ends up giving me an error message. As you can read in the code, the part of the clicking only works for 1 to 6 which isn't what I want. Trying to place one of the four ends at the end before the begin of the clicking also doesn't work. I also can't take off the begin before the GridBox function. Basically, I'd like to understand what goes wrong there.

Thank you for your time.

Runaway

2012-09-07 17:42:13

Try this out:


function BuyGE(spot : integer): Boolean;
var
x, y : Integer;
b : TBox;
begin
Result := False; // need a result for a function
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
0:
begin
if not (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
writeln('No spot is free')
Exit;
end;
end;
1..6:
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,BuyButton,b.x1,b.y1,b.x2,b.y2) then
begin
writeln('This spot is not free')
Exit;
end;
end;
else // if spot is none of the above
begin
writeln('Invalid spot entered');
Exit;
end;
end;
ClickMouse2(true);
if WaitOption('Buy O',500) then // no point checking for the menu if you didn't choose an option
Result := WaitFunc(@GEEBuyMenu,10,6000);
end;

Wardancer

2012-09-07 18:02:41

Thank you Runaway. That solved the issue.

I finally understand the problem I had too. A case statement has to finish with an end. By adding only one end before my clicking action, it was like I tried to use my "begin" as a case statement.

At first, you mention that the function needs a result. I thought that it automatically gave the result "true" if it could do what it did. Now, I'm starting to think I coded some procedures as functions. Yeah, that part was really a procedure… yet it still does what I intend it to. The temptation to code absolutely everything in functions is very high now. I have to go back to the theory and get to really understand the limitations of both.

I appreciate the "end else" you added too. I was searching to find what "infinity" would be. Didn't want to paste my code with a case being 7..99999999999999999999999999999, haha.

litoris

2012-09-07 18:08:18

You should make sure you always Do Result := True/false before the function exits. A good way is to set it to false at the very beginning, and set to true when something is finished.

masterBB

2012-09-07 18:16:58

Yeah, functions are cool. They make it much easier to create a reliable script. Remember they can return more then just a Boolean type. With the exception of procedures like init and proggy, most procedures could be rewritten to a function. Using a 'Boolean' function is advised if it can 'fail'.


function BuyGE(spot : integer): Boolean;
var
x, y : Integer;
b : TBox;
begin
Result := False; // need a result for a function
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
0:
if not (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
writeln('No spot is free')
Exit;
end;
1..6:
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,BuyButton,b.x1,b.y1,b.x2,b.y2) then
begin
writeln('This spot is not free')
Exit;
end;
end;
else // if spot is none of the above
begin
writeln('Invalid spot entered');
Exit;
end;
end;
ClickMouse2(true);
if WaitOption('Buy O',500) then // no point checking for the menu if you didn't choose an option
Result := WaitFunc(@GEEBuyMenu,10,6000);
end;

I personally liked his case statements standards a bit more. Makes the default, else, look more inline with the other cases. Also removed a begin and end at the first case. Also awesome comment explaining mod and floor.

e:

function BuyGE(spot: integer): Boolean;
var
x, y, i: Integer;
b: TBox;
begin
Result := False; // need a result for a function
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
0:
begin
for i := 1 to 6 do
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if FindObject(x,y,BuyButton,b.x1,b.y1,b.x2,b.y2) then
begin
Writeln('Found in spot: ' + IntToStr(i));
break;
end;
end;
Writeln('No free slot found');
Exit;
end;
1..6:
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,BuyButton,b.x1,b.y1,b.x2,b.y2) then
begin
writeln('This spot is not free')
Exit;
end;
end;
else // if spot is none of the above
begin
writeln('Invalid spot entered');
Exit;
end;
end;
ClickMouse2(true);
if WaitOption('Buy O',500) then // no point checking for the menu if you didn't choose an option
Result := WaitFunc(@GEEBuyMenu,10,6000);
end;

Wardancer

2012-09-07 18:26:02

Well, that was definitely a procedure so I'm not sure I understand the practical aspect of what you're trying to say. For my "real" functions, it is quite obvious that I'm making them to receive a value. Do you mean a function that does something AND tells me if it did it? Some kind of half breed between a procedure and a function. I understand the theory behind it, but I didn't get to a point where that's actually needed or useful.

EDIT: I really can't see the practical aspect of turning procedures into functions. Do you use it as an extra layer of failsafe? My first reflex would be to reach the same result using a different path (i.e exit, if..then..etc), but I can see how a different scripting style can go around the problem differently.

Runaway

2012-09-07 19:05:29

From: Wardancer
Well, that was definitely a procedure so I'm not sure I understand the practical aspect of what you're trying to say. For my "real" functions, it is quite obvious that I'm making them to receive a value. Do you mean a function that does something AND tells me if it did it? Some kind of half breed between a procedure and a function. I understand the theory behind it, but I didn't get to a point where that's actually needed or useful.

EDIT: I really can't see the practical aspect of turning procedures into functions. Do you use it as an extra layer of failsafe? My first reflex would be to reach the same result using a different path (i.e exit, if..then..etc), but I can see how a different scripting style can go around the problem differently.


Yes. It can be used as a failsafe to improve speed, accuracy and efficiency. For example, you originally had this in your code:


ClickMouse2(true);
WaitOption('Buy O',500);
WaitFunc(@GEEBuyMenu,10,6000);

It does what it's supposed to. But if the script cannot find the specified option, it will waste time and resources searching for the buy menu when there's a 100% chance it's not there! Utilizing the functional properties of WaitOption not only allows you to skip the unnecessary menu check, but you can execute code designed specifically to act when WaitOption fails. Like so:


ClickMouse2(true);
if WaitOption('Buy O',500) then
WaitFunc(@GEEBuyMenu,10,6000)
else
begin
Writeln('Could not locate option');
//DoFailsafe;
end;

Although, not everything benefits from a result.

Wardancer

2012-09-07 19:25:47

What I meant is that instead of using a function, we can use a if..then and end up with the same result (in the case that we're dealing with a procedure). It might come to preference too. I have a procedure for opening the grand exchange and another to make sure that it really is open. I could've made the procedure as a function and put both together I guess. I might end up hated with my one line functions, haha.

EDIT: I might as well share all I have so far. Some people might want to play a bit with the functions and procedures I came up with and I have 2-3 questions. I won't be able to stress it enough, but the general frame of the script (like Declareplayers, Antiban and such) was made by NKN and should be entirely credited to him. I also removed the LoadObjects function as it isn't mine and while I have permission to use it, I didn't ask if I could publicly release it. I put a few notes in the script which I'll explain after.

program new;
{$DEFINE SMART}
{$i srl/srl.simba}
{$i srl/srl/misc/SmartGraphics.simba}

procedure DeclarePlayers;
begin
HowManyPlayers := 1; // This is set to the total amount of players (more on multiplayer later ;)), for now, just keep it set as 1
NumberOfPlayers(HowManyPlayers); // This is a procedure in SRL which sets up player arrays (also, more on that later), this will always be the same
CurrentPlayer := 0; // This is the player to start with; the first player will always be 0 (you'll find out when you learn all about arrays)

Players[0].Name := 'Uqam'; // Username
Players[0].Pass := ''; // Password
Players[0].Nick := ''; // 3-4 lowercase letters from username; used for random event detection
Players[0].Active := True; // Set to true if you want to use Player 0
Players[0].Pin := ''; // Leave blank if the player doesn't have a bank pin
Players[0].BoxRewards := ['Xp', 'mote', 'ostume', 'oins', 'aphire', 'ssence'];
end;
procedure Antiban;
begin
FindNormalRandoms;
case Random(80) of
0: RandomRClick;
2: PickUpMouse;
3: RandomMovement;
4: BoredHuman;
5: ExamineInv;
7: SetAngle(SRL_ANGLE_HIGH);
8: Wait(5000)
end;
end;
type //Credit goes to NKN for the custom object finding functions. I only put the values in there. The frame is all his.
MSObject = record
Col, Tol, TPADist, MinCount: Integer;
Hue, Sat: Extended;
Uptext: String;
MMDot: String;
end;
var
GE, BuyButton, SellButton, ExitGEMenuButton : MSObject;
procedure LoadObjects;
var
i:integer;
begin
with GE do
begin
Col := 2891040;
Tol := 20;
Hue := 0.18;
Sat := 0.30;
UpText := 'Exch'
end;
with BuyButton do
begin
Col := 247218;
Tol := 4;
Hue := 0.25;
Sat := 1.29;
UpText := 'Buy O'
end;
with SellButton do
begin
Col := 224454;
Tol := 4;
Hue := 0.34;
Sat := 0.03;
UpText := 'Sell O'
end;
with ExitGEMenuButton do
begin
Col := 11975110;
Tol := 10;
Hue := 0.80;
Sat := 0.31;
UpText := 'ack'
end;
for i := 1 to 28 do
Boxes[i] := InvBox(i)
end;
function FindObject(var x,y : Integer; Obj: MSObject; X1,Y1,X2,Y2:integer) : Boolean;
//Censored =)
function InGEE: Boolean;
begin;
result := findTextTPA(39116, 20, 204, 27, 248, 49, 'Grand', upCharsEx, nothing);
end;
function GEESellMenu: Boolean;
begin;
result := findTextTPA(39116, 20, 87, 68, 155, 86, 'Sell O', upCharsEx, nothing);
end;
function GEEBuyMenu: Boolean;
begin;
result := findTextTPA(39116, 20, 87, 68, 155, 86, 'Buy O', upCharsEx, nothing);
end;
function GEECanTypeAmount: Boolean;
begin;
result := findTextTPA(0, 150, 125, 387, 166, 412, 'nter', upCharsEx, nothing);
end;
function GEECanTypePrice: Boolean;
begin;
result := findTextTPA(0, 150, 140, 392, 182, 411, 'nter', upCharsEx, nothing);
end;
function GEECanTypeItem: Boolean;
begin;
result := findTextTPA(23200, 50, 196, 355, 228, 373, 'rand', upCharsEx, nothing);
end;
function OpenGE: Boolean;
var
x,y:integer;
begin
if InGEE or GEESellMenu or GEEBuyMenu then
Exit;
if(FindObject(x,y,GE,MSX1,MSY1,MSX2,MSY2)) then
begin
Clickmouse2(false);
WaitOption('Exchange G',500);
WaitFunc(@InGEE,10,6000);
end else
Exit;
end;
function GEEMenuExit: Boolean;
var
x, y : Integer;
begin
if not InGEE then
Exit;
if not GEESellMenu and not GEEBuyMenu then
Exit;
if(FindObject(x,y,ExitGEMenuButton,MSX1,MSY1,MSX2,MSY2)) then
begin
ClickMouse2(true);
WaitOption('ack',500);
WaitFunc(@InGEE,10,6000);
end else
Exit;
end;
function GEEBuyAt(spot: integer): Boolean;
var
x, y, i: Integer;
b: TBox;
begin
Result := False;
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
Exit;
case spot of
0:
if not (FindObject(x,y,BuyButton,MSX1,MSY1,MSX2,MSY2)) then
begin
writeln('No spot is free')
Exit;
end;
1..6:
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,BuyButton,b.x1,b.y1,b.x2,b.y2) then
begin
writeln('This spot is not free')
Exit;
end;
end;
else
begin
writeln('Invalid spot entered');
Exit;
end;
end;
ClickMouse2(true);
WaitOption('Buy O',500);
Wait(500+Random(250));
WaitFunc(@GEEBuyMenu,10,6000);
end;
function GEESellAt(spot: integer): Boolean;
var
x, y, i: Integer;
b: TBox;
begin
Result := False;
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
case spot of
0:
if not (FindObject(x,y,SellButton,MSX1,MSY1,MSX2,MSY2)) then
begin
writeln('No spot is free')
Exit;
end;
1..6:
begin
b:= GridBox(spot, 3, 2, 155, 120, 155, 120, point(100,136));
if not FindObject(x,y,SellButton,b.x1,b.y1,b.x2,b.y2) then
begin
writeln('This spot is not free')
Exit;
end;
end;
else
begin
writeln('Invalid spot entered');
Exit;
end;
end;
ClickMouse2(true);
if WaitOption('Sell O',500) then
WaitFunc(@GEEBuyMenu,10,6000);
Wait(1250+Random(250));
end;
procedure GEESetQuantity(Q : String);
var
x, y, numberOfFailures : integer;
searchBox: TBox;
begin
for numberofFailures := 0 to 5 do
if not InGEE then
Exit;
if not GEESellMenu and not GEEBuyMenu then
Exit;
case lowercase(Q) of
'1':
searchBox := IntToBox(56, 211, 87, 231);
'10':
searchBox := IntToBox(97, 211, 129, 231);
'100':
searchBox := IntToBox(138, 211, 170, 231);
'all':
if not GEESellMenu then
begin
writeln('Invalid parameter');
Exit;
end else
searchBox := IntToBox(220, 211, 253, 231);
else
begin
if (FindColorTolerance(x, y, 39116, 222, 211, 252, 231, 100)) then
begin
MMouse(x, y, 4, 4);
ClickMouse2(true);
WaitFunc(@GEECanTypeAmount, 10, 16000);
TypeSendEx(Q, true);
Wait(1500 + Random(250));
end;
end;
end;
case lowercase(Q) of
'1', '10', '100', 'all':
if (FindColorTolerance(x, y, 39116, searchBox.x1, searchBox.y1, searchBox.x2, searchBox.y2, 100)) then
begin
MMouse(x, y, 4, 4);
ClickMouse2(true);
Wait(1000 + Random(500));
end;
end;
if (ExtractFromStr(GetTextAtExWrap(86, 184, 227, 198, 0, 10, 1, 6400255, 50, UpCharsEx), Numbers)) = Q then
Exit;
begin
writeln('Something went wrong!')
Inc(numberOfFailures);
if numberofFailures = 5 then
begin
writeln('Failed too many times. Terminating script.');
TerminateScript;
end;
end;
end;
procedure GEESetPrice(Value : String; numberOfClicks : Integer);
var
x, y, numberOfFailures, numberOfClickz : integer;
searchBox: TBox;
begin
for numberOfFailures := 0 to 5 do
if not InGEE then
Exit;
if not GEESellMenu and not GEEBuyMenu then
Exit;
case lowercase(Value) of
'min':
searchBox := IntToBox(274, 211, 304, 231);
'mid':
Exit;
'max':
searchBox := IntToBox(427, 211, 460, 231);
else
begin
if (FindColorTolerance(x, y, 39167, 371, 211, 403, 231, 100)) then
begin
MMouse(x, y, 4, 4);
ClickMouse2(true);
WaitFunc(@GEECanTypePrice, 10, 6000);
TypeSendEx(Value, true);
Wait(1500 + Random(250));
if (ExtractFromStr(GetTextAtExWrap(296, 184, 438, 198, 0, 10, 1, 6400255, 50, UpCharsEx), Numbers)) = Value then
Exit;
begin
writeln('Something went wrong!')
Inc(numberOfFailures);
if numberOfFailures = 5 then
begin
writeln('Failed too many times. Terminating script.');
TerminateScript;
end;
end;
end;
end;
end;
case lowercase(Value) of
'min', 'max':
if (FindColorTolerance(x, y, 39167, searchBox.x1, searchBox.y1, searchBox.x2, searchBox.y2, 100)) then
begin
repeat
MMouse(x, y, 4, 4);
ClickMouse2(true);
Inc(numberOfClickz);
Wait(200 + Random(50));
until (numberOfClickz = numberOfClicks);
Wait(500 + Random(200));
end;
end;
end;
procedure GEEConfirmOffer;
begin
MouseBoxEx(215, 286, 310, 325, 10, 1);
Wait(1500 + Random(500));
end;
procedure GEEBuy(What, Quantity, Value: String; numberOfClicks, spot : Integer);
var
x, y : Integer;
begin
if not InGEE then
Exit;
if GEESellMenu or GEEBuyMenu then
GEEMenuExit;
GEEBuyAt(spot);
WaitFunc(@GEECanTypeItem, 10, 6000);
TypeSendEx(What, true);
WaitFindColor(x, y, 23200, 67, 343, 119, 359, 30, 6000);
MouseBoxEx(200, 350, 228, 368, 5, 1);
WaitColorGone(39372, 394, 81, 40, 6000);
//if not findTextTPA(39372, 20, 210, 75, 380, 95, What, StatChars, nothing) = true then //Look at the note below
//Writeln('A problem occurred. Trying again.');
//GEEBuy(What, Quantity, Value, numberOfClicks, spot);
GEESetQuantity(Quantity);
GEESetPrice(value, numberOfClicks);
GEEConfirmOffer;
end;




procedure BuyRanarr;
var
Price, x, y : Integer;
begin
OpenGE;
//GEEBuyAt(6);
//GEESetQuantity('12354');
//GEESetPrice('852', 4)
//GEEMenuExit;
GEEBuy('lean ranarr', '2', 'max', 1, 0);

writeln('See if any malicious loop is going on');
end;



procedure Mainloop;
begin
//OpenGE;
BuyRanarr;



end;

begin
{$IFDEF SMART}
SRL_SIXHOURFIX := TRUE;
SMART_FIXSPEED := TRUE;
{$ENDIF}

ClearDebug;
SetupSRL;
DeclarePlayers; // Calls the procedure, you can't forget this!
LoginPlayer;
ClickNorth(SRL_ANGLE_HIGH);
LoadObjects;
repeat
Mainloop;
until(allPlayersInactive);
end.

Note: I'm trying to use this as a failsafe to make sure that the item the person is trying to purchase is really the one he wants. However, for some reason beyond me, the text reading doesn't work at this spot. I'll figure out the issue eventually, but I wanted to post what I have done so far for people to comment/insult/make use of.

Once again, what I'm looking for are methods to make this look neater. Everything works and I'll add more failsafes as I figure out holes, but I'm always looking for ways to optimize things.

If someone has any question about what a particular function does or would like details, feel free to ask.