Hey Jingle!
First of all, it means a lot to me that you've mentioned me as an inspiration for scripting! I guess I'll keep the tradition going, cause I've got A LOT of feedback for you on this :) I'll get right into it (be sure to check the comments in the code, as I've left quite a bit in there as well):
1) With..do is your friend. Use it as much as possible! It can cut down on a bunch of unnecessary typing and it leaves you with a much cleaner look. I've included it in another part of my edits, but I'll get to that in a bit.
Procedure DeclarePlayers;
Begin
HowManyPlayers := 1;
NumberOfPlayers(HowManyPlayers);
CurrentPlayer := 0;
With Players[0] Do
Begin
Name := RS_Username; // Player username
Pass := RS_Password; // Player password
Active := True;
Pin := RS_Pin;
If DefineWorld Then
WorldInfo := [True, OurWorld]
//Else
// ^ Players[0].Member would not be given a value if DefineWorld is true.
Member := True;
BoxRewards := ['XP', 'xp', 'lamp'];
LampSkill := Skill_Runecrafting;
End;
End;
2) I've got a solution to your food problems. It's known as a type and they are super useful for this kind of stuff.
Type FoodData = Record
Raw, Burn, Cook, Tol, XP: Integer;
Uptext: String;
End;
Var
FoodInfo: FoodData;
^ Both should be declared globally. This will allow you to store data in FoodInfo.Raw, FoodInfo.Burn, and so on. This is very helpful when used in conjunction with cases as you can set dynamic values for FoodInfo depending on user input. Like this:
Const
FoodToCook = 'rocktail'; // Valid arguments: rocktail, shark, ...
HowManyToCook = 100;
Once you've got a const set for what raw food you're going to be cooking, you can use a case statement to setup all of the vars you're going to use later in the script:
procedure SetupVars;
begin
Currently('Setting up food data...');
FoodInfo.XP := 0;
if (FoodToCook = '') then
//TerminateScript;
case Lowercase(FoodToCook) of
'rocktail':
begin
with FoodInfo do
begin
XP := 1;
Raw := 1; // Unique raw color
Burn := 1; // Unique burned color
Cook := 1; // Etc.
Tol := 5; // Tolerance for above colors
Uptext := 'ckt';
end;
end;
'shark':
begin
with FoodInfo do
begin
XP := 1;
Raw := 1;
Burn := 1;
Cook := 1;
Tol := 5;
Uptext := 'har';
end;
end;
end;
if (FoodInfo.XP = 0) then
//TerminateScript;
end;
^ Using the case statement will allow you to find all of the colors for each food and store them so all you have to do is change the FoodToCook const to change all of the vars.
3) In your Declare procedure, You've got a whole lot of similar colors you're using with FindTPACluster. I suggest you cut that down since your tolerance is high. For example, there won't be a difference between 10397350 and 10331300 at a tolerance higher than 10, so there is no point adding both of those. This is my suggestion:
Procedure Declare;
begin
// Red 1st, then light grey
Colors := [1911500, 2241005, 1845704, 10726315, 10331300];
Tol := 30; // Tolerance on each color
4) In your LoadVars procedure, you have a SetAngle func and a Version var. I suggest adding in a second SetAngle since it's very crucial that it be at highest for the best results. It's as simple as:
SetAngle(SRL_ANGLE_HIGH);
SetAngle(SRL_ANGLE_HIGH); // In case of lag
Version:= '1.0'; // Well this is wrong :P
5) Your SlotUrn function can be cleaned up a little by using MouseTBox instead of MouseBox (You're going to be seeing
plenty of MouseTBox for a bit :p). Using this in conjunction with InvBox will make everything easier:
Function SlotUrn(LeNumber: Integer): Boolean;
Begin
Result:= False;
If (LeNumber = 1) Then
Begin
MouseTBox(InvBox(LeNumber), Mouse_Left); // InvBox(1) returns the coords of slot 1 in a box allowing
// for use of MouseTBox. Just a good way to clean up code.
ScriptDebug('We Teleported a Urn from Slot 1!');
Result := True;
Exit;
End;
If (LeNumber = 2) Then
Begin
MouseTBox(InvBox(LeNumber), Mouse_Left);
ScriptDebug('We Teleported a Urn from Slot 1!');
Result := True;
Exit;
End;
End;
6) I saw that you were using alot of FindColorsXXX throughout your script with multiple occurences and the same variables etc. So I whipped up this baby to make all that much more simple:
function WaitColorBox(WaitTime: Integer; Color, Min, Tol: TIntegerArray; Box: TBoxArray; Strict: Boolean): Boolean;
var
c: T2DIntegerArray;
TPA: TPointArray;
Temp: TIntegerArray;
hMax, hTemp, Count, h, hh, t, i: Integer;
hColor, hMin, hTol, hBox: Integer;
begin
if not LoggedIn then Exit;
Result := False;
hColor := High(Color); // All of this hXXX bullshiz is just to allow for a special feature that
hMin := High(Min); // I've added into this. You can enter 2 search boxes and 1 of everything else
hTol := High(Tol); // and the function will search for the specified color, with the min and tol
hBox := High(Box); // values in both search boxes. It can be done vice versa as well.
Temp := [hColor, hMin, hTol, hBox];
hTemp := High(Temp);
hMax := MaxA(Temp);
SetLength(c, hMax + 1);
for h := 0 to hTemp do
begin
for hh := 0 to hMax do
begin
if (Temp[h] < 1) then
c[hh][h] := 0
else
c[hh][h] := hh;
end;
end;
MarkTime(t);
repeat
Count := 0;
for i := 0 to hMax do
begin
FindColorsTolerance(TPA, Color[c[i][0]], Box[c[i][3]].x1, Box[c[i][3]].y1, Box[c[i][3]].x2, Box[c[i][3]].y2, Tol[c[i][2]]);
if (Length(TPA) > Min[c[i][1]]) then
Inc(Count);
end;
if Strict then
begin
if (Count >= (hColor + 1)) then
begin
Result := True;
Exit;
end;
end else
begin
if (Count > 0) then
begin
Result := True;
Exit;
end;
end;
Wait(100+Random(50));
until(TimeFromMark(t) > WaitTime);
end;
^ You're going to see this function in conjunction with all of those MouseTBox's :)
7) The new FindUrnToTele, UrnsInOurInventory and ClickChatToCook functions boasting the WaitColorBox and MouseTBox I keep talking about:
Function FindUrnToTele: Boolean;
Var
UrnBox, TeleBox: TBoxArray;
x, y, dx, dy, fx, fy : Integer;
Begin
Result:= False;
If Not LoggedIn Then Exit;
SetLength(UrnBox, 2);
SetLength(TeleBox, 2);
UrnBox[0] := IntToBox(555, 210, 600, 245);
UrnBox[1] := IntToBox(600, 210, 640, 245);
TeleBox[0] := IntToBox(150, 420, 174, 444);
TeleBox[1] := IntToBox(205, 405, 315, 455);
{If FindColoredAreaTolerance(x, y, 5137749, 555, 210, 600, 245, 9, 27) And
FindColoredAreaTolerance(dx, dy, 1907518, 555, 210, 600, 245, 16, 15) Then}
If WaitColorBox(1000, [5137749, 1907518], [9, 16], [27, 15], [UrnBox[0]], True) Then
Begin // ^ Searches UrnBox[0] for both colors with their specified min and tol values
SlotUrn(1);
Wait(RandomRange(1500, 2500));
//If FindColoredAreaTolerance(fx, fy, 1710098, 150, 420, 174, 444, 25, 5) Then
If WaitColorBox(1000, [1710098], [25], [5], [TeleBox[0]], True) Then
Begin MouseTBox(TeleBox[1], Mouse_Left); IncEx(UrnT, 1); End; // More MouseTBox here
End Else
ScriptDebug('No teleport-able urns found in Slot 1.');
{If FindColoredAreaTolerance(x, y, 5137749, 600, 210, 640, 245, 9, 27) And
FindColoredAreaTolerance(dx, dy, 1907518, 600, 210, 640, 245, 16, 15) Then}
If WaitColorBox(1000, [5137749, 1907518], [9, 16], [27, 15], [UrnBox[1]], True) Then
Begin
SlotUrn(2);
Wait(RandomRange(1500, 2500));
//If FindColoredAreaTolerance(fx, fy, 1710098, 150, 420, 174, 444, 25, 5) Then
If WaitColorBox(1000, [1710098], [25], [5], [TeleBox[0]], True) Then
Begin MouseTBox(TeleBox[1], Mouse_Left); IncEx(UrnT, 1); End;
End Else
ScriptDebug('No teleport-able urns found in Slot 2.');
Result:= True;
End;
Function UrnsInOurInventory: Integer;
Var
fx, fy, dx, dy: Integer;
//TPA1, TPA2: TPointArray;
aBox: TBoxArray;
Begin
SetLength(aBox, 2);
aBox[0] := IntToBox(563, 215, 592, 243);
aBox[1] := IntToBox(605, 215, 634, 242);
{If FindColorsSpiralTolerance(fx, fy, TPA1, 4151499, 563, 215, 592, 243, 15)
And FindColorsSpiralTolerance(dx, dy, TPA2, 4151499, 605, 215, 634, 242, 15) Then}
If WaitColorBox(1000, [4151499], [1], [15], [aBox[0], aBox[1]], True) Then
// ^ Searched aBox[0] and aBox[1] for the color with specified min and tol values
Result := 2
Else
Result := 1;
End;
Function ClickChatToCook: Boolean;
Var
x, y: Integer;
aBox: TBoxArray;
Begin
Result := False;
SetLength(aBox, 2);
aBox[0] := IntToBox(150, 420, 174, 444);
aBox[1] := IntToBox(230, 408, 290, 453);
{Wait(RandomRange(2000, 3000));
If FindColoredAreaTolerance(x, y, 1710098, 150, 420, 174, 444, 25, 15) Then}
If WaitColorBox(3000, [1710098], [25], [15], [aBox[0]], True) Then
Begin
MouseTBox(aBox[1], Mouse_Left);
Result := True;
Wait(RandomRange(20, 200));
Exit;
End;
End;
8) DoWork procedure. I don't have much explaining to do for this one, so just take a look through the code. I moved things around and added a repeat..until to provide more failsafe-age.
Function DoWork(MaxTries: Integer): Boolean; // Would be better if this was a function
Var
Tries: Integer;
Box: TBox;
Begin
Declare;
Box := IntToBox(44, 345, 52, 357);
Tries := 0;
Repeat
Arr := FindTPACluster(Colors, Tol, SortFrom, FilterArr, TrimArr, 0, MaxDist, True, Area[0], Area[1], Area[2], Area[3]);
MarkTime(RangeT);
For a := 0 To High(Arr) Do
Begin
x := MiddleTPA(Arr[a]).x;
y := MiddleTPA(Arr[a]).y;
Mouse(x, y, 3, 3, Mouse_Move);
If WaitUptextMulti(['ang', 'nge'], 500) Then // Uptext check is a great failsafe
ClickMouse2(Mouse_Left)
Else
Continue;
If DidClick(False, 500) Then // Should probably increase the max wait range to a static one here
Begin
Result := True;
Wait(RandomRange(1500, 2500));
Exit;
End;
//If FindColorTolerance(x, y, 16777215, 44, 345, 52, 357, 15) Then
If WaitColorBox(1000, [16777215], [1], [15], [Box], True) Then
Begin
Result := True; // I'm not sure what this is searching for :S
Exit;
End;
If (a >= 2) Then // Breaks from the current set of clusters since the greater a gets, the less
Break; // likely the cluster you're checking is the one you're searching for.
End;
If (TimeFromMark(RangeT)>=30000) Then
Begin
ScriptDebug('Fail: Either 1. Cannot Locate Range ' + 'or ' +
'2. Cannot find the chatbox to cook food.');
TerminateScript;
End;
Inc(Tries);
Until(Tries > MaxTries);
End;
9) This one is very minor. Just some slight fixes to the banking code to account for the multiple types of food:
ScriptDebug('Time to get more food.');
FoodStack := IntToStr(GetBankItemAmount(9, 0));
ScriptDebug('We have: ' + FoodStack + ' raw ' + FoodToCook +' left in our bank. We are stable.');
If (GetBankItemAmount(9, 0) > 25) Then
Withdraw(9, 0, 10000)
Else TerminateScript;
Wait(RandomRange(1, 1000));
CloseBank;
IncEx(Stats_RawTails, 26);
// ^ Can edit to be something like: Stats_RawFood
IncEx(Stats_CookXP, 7029);
10) Last one! This one is just a suggestion. I saw that you were using bitmaps to identify how many fish were raw/cooked in the inventory. This is just a nifty function I wrote up to do the same thing using the colors that would be set in the SetupVars procedure I mentioned before (using the FoodInfo):
function CheckInv(Slot: Integer; Color: TIntegerArray): Boolean;
var
tSlot: TBox;
begin
if not LoggedIn then Exit;
Result := False;
tSlot := InvBox(Slot);
if ExistsItem(Slot) then
Result := WaitColorBox(100, Color, [5], [FoodInfo.Tol], [tSlot], False);
end;
end;
Function CheckFood: TBooleanArray; // Checks the inventory and returns a boolean array of what do next
Var
Color: TIntegerArray;
hColor, Raw, Burnt, Cooked, CaB, i, ii: Integer;
Begin
If Not LoggedIn Then Exit;
If Not BankScreen Then
Begin
SetLength(Result, 2);
Result[0] := False;
Result[1] := False;
Color := [FoodInfo.Raw, FoodInfo.Burn, FoodInfo.Cook];
hColor := High(Color);
Raw := 0;
Burnt := 0;
Cooked := 0;
for i := 3 to 28 do
begin
for ii := 0 to hColor do
begin
if CheckInv(i, [Color[ii]]) then
begin
if (ii = 0) then
Inc(Raw);
if (ii = 1) then
Inc(Burnt);
if (ii = 2) then
Inc(Cooked);
Break;
end;
end;
end;
CaB := Cooked + Burnt;
If (Raw = 26) Then
Begin
//Writeln('Need to cook food!');
Result[0] := True;
End;
If ((Cooked = 26) or (CaB = 26)) Then
Begin
//Writeln('Need to bank food!');
Result[1] := True;
End;
If (Raw < 26) and (CaB < 26) then
Begin
//Writeln('Cooking food!');
Exit;
End;
End;
if Result[0] then
CookTime := True; // Global var that you can use to tell you to find the range and wait, etc.
if Result[1] then
BankTime := True; // Global var that is only set true when you're inventory has no raw food
// Using the two global vars above, you can do if CookTime then (as well as BankTime) checks during
// your main loop to increase effeciency, timing, and it's a great failsafe. You can call CheckFood
// after banking, before going to the range, while waiting at the range, after cooking, etc. to keep
// tabs on exactly what point in the loop you are.
End;
^ This would take about 3 seconds to go through the whole inventory and return a result, but it uses the FoodInfo color vars which makes your life easier for adding new food :p
Well, that's it. This is amazing for a first script! This is like 10x better than my first
few scripts, so keep up the good work!