Bank Browsing- BlackLists
Level: Intermediate
Follow up tutorial (read this first) BlackLists with color
About B4 and this series of tutorials-
I am developing a system called B4 (Bank Browser By Boreas) made up of functions for finding, withdrawing, and depositing bank items. It will be fast and efficient, using techniques especially designed for using minimal resources and still getting the job done. One of the features will be only searching for something once, and then remembering where it is. It will also be easy to use, with high level functions like MakeInventory('18 coal, 9 iron'); that will take care of everything. It will also make DTM/bitmap/color creation easier, so you can spend more time scripting. As well as the high level functions like MakeInventory, it will contain many lower level functions that you can combine to make your own personalized higher level functions. This series of tutorials will teach you how to use the functions, and how they work. It is partly a user manual for the B4 system, but it is also a series of scripting tutorial, teaching problem solving, scripting techniques, and ways of thinking. The more you know about how something works, the better you can use it. All of these tutorials will be labeled intermediate or advanced. The material will not be too tricky, but I do expect you to be comfortable with arrays etc. Also, B4 will make banking very easy, but I still want beginner scripters to learn the old fashioned way of doing it. Therefore, these tutorials are for intermediate-advanced scripters who want to spend less time writing banking routines and more time on interesting things, although you may also learn some scripting techniques too.
About this tutorial-
BlackLists are lists of black dots, duh. Let me explain. A great way of finding items in the bank and inventory is by making a DTM containing points on the black(65536) outline of the item, because it never changes. (Note a DTM like this will work the same for gold bars and steel bars, because they have the same outline. To make it only work for gold, you will need a point on the gold color, with some tolerance, because it does change. See a DTM tut for more info, as BlackLists don't worry about this.) Ok, so every (type of) item has a black outline which can be used to identify it. This outline is a bunch of points, which have the color 65536. Basically (<<keyword), these points are the BlackList for that item.
When you look in a bank, and scroll to the top (FixBank) there are 48 visible BankSlots, 6 rows of 8. In B4 these 48 are numbered like in the inventory, reading left to right, top to bottom, 1 to 48. The corners of these BankSlots can be found with a formula, for BlackLists we just need the top left. Each BankSlot is 31 by 31 pixels, 961 pixels. Now, we want to look at the pixels for black(65536), but we don't need all of them. So the question is, which pixels do we look at? For that we need a TPointArray. A TPointArray is an array of TPoints. Each TPoint contains 2 values, the x and y. In this case, they x and y are the distances between the pixel we want to look at, and the top left corner of the box (BankSlot) we are looking in. First we declare a variable to hold our list of points to check.
Next we need a function that creates the TPointArray of the points relative to the top left of bankslots we want to look at. The following creates an array with about 385 points, which is 40% of all the points in a bankslot. All the numbers are from 0 to 31, because its relative to the top left corner of the bankslot.
SCAR Code:
{*******************************************************************************
function Create40PercentTPA:TPointArray;
By: Boreas
Note: Purely an internal function, used in setup.
Description: Returns a TPointArray containing the relative (to x1,y1 of a BSlot)
for 385 points (out of 31*31, hence 40%). Only needs to be done once, to create
the list of points to check for 65536. Only takes like 15ms, and I didn't
feel like typing them all out.
*******************************************************************************}
function Create40PercentTPA:TPointArray;
var Counter,hx,hy:integer;
var TPointsToCheck:array [0..384] of TPoint;
begin
repeat
hy:=15;
hx:=hx+1;
repeat
hy:=hy+1;
if (((hx mod 4)=0) or ((hy mod 4)=0)) then
begin
TPointsToCheck[Counter].x:=hx;
TPointsToCheck[Counter].y:=hy;
Counter:=Counter+1;
end;
until hy=31;
until hx=31;
result:=TPointsToCheck;
end;
Oops. It's not 40% or 385 points. It's more like 208 points, 22%. This is because I added the hy:=15;, so that it ignores the part where the yellow amount number is. I will change the name when B4 comes out.
You can create you own function (see pwnaz0r's max accuracy one on page 2), just make sure to skip the top 15 pixels where the number is. The one above looks like a net, with 7 lines across and 7 lines down, like how a tic-tac-toe(naughts and crosses for UK) board has 2. You can make it slower but more accurate by changing the mod 4 to mode 2, which will give it 15 lines both way. You can do the opposite by changing to 8, giving 3. You could also do something with circles. I chose the net pattern because you can't draw a line (more than 3 pixels long) without catching the net. You don't even need a formula, but doing it by hand can take a while. Basically, you just need a TPointArray containing the points in the BankSlot you want to look at, with the top left being 0,0. More points is more accurate but slower.
SCAR Code:
MyList:=Create40PercentTPA;
Here's how to get the coords of the top left corner of a bankslot. I won't go into how it works, this is just how I do it for B4.
SCAR Code:
Tmpx1:=79+((((WhichBankSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichBankSlot-1)/8))*38);
So we have a list a points in a BankSlot we want to look at. The next step is to go through the list for an item and check which are black(65536). This is fairly simple, go through the list you created, adding the coords in the TPoints to the top left corner, and check if the color there is black. If it is, add the index of the list to another list, an array of integers. This is faster and simpler than making another TPoint array, because we will need to output the list somehow later.
SCAR Code:
{*******************************************************************************
function CreateItemBlackList(WhichBankSlot:integer;WhichList:TPointArray):array of integer;
By: Boreas
Description: Looks at the points in the list for an item, and returns an array
contatining the indexes of the points that are black.
Usage: WhichBankSlot-just what it sounds like. WhichList-the TPointArray
containing positions relative to the x1,y1 of a bankslot which you want to check
*******************************************************************************}
function CreateItemBlackList(WhichBankSlot:integer;WhichList:TPointArray):array of integer;
var Counter,Counter2,Tmpx1,Tmpy1,ListLength:integer;
var TmpArray:array of integer;
begin
Tmpx1:=79+((((WhichBankSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichBankSlot-1)/8))*38);
ListLength:=getarraylength(WhichList)-1;
setarraylength(tmparray,1);
for Counter:= 0 to ListLength do
begin
if GetColor(Tmpx1+WhichList[Counter].x,Tmpy1+WhichList[Counter].y)=65536 then
begin
TmpArray[Counter2]:=Counter;
Counter2:=Counter2+1;
setarraylength(TmpArray,Counter2+1);
end;
end;
result:=TmpArray;
end;
Now, to make a BlackList for an item, just declare an array of integers....
SCAR Code:
var tmpList:array of integer;
put the item in a bankslot (45 for example), and make the TPointArray as discussed before.
SCAR Code:
tmplist:=CreateItemBlackList(45,MyList);
Now tmplist is the BlackList used to identify that type of item. If you create the list during runtime, just use that array of integer. If you want to make it when writing a script, like traditional DTMs, you need to convert it into something you can transfer. For that, you can use
SCAR Code:
writeln(intarraytostr(tmplist2));
IntArrayToStr by Moparisthebest is in SRL/Misc/ArrayLoaders.scar
This will display a bunch of numbers with spaces between them. To put them back into the usable array, use StrToIntArray. This is like DTMFromString. Once you have the string, remember what item it goes to, and what TPointArray was used to create it (in this case, it was MyList made with Create40PercentTPA), it will only work later if you use the same TPointArray. B4 will make this process easier.
So now you have the BlackList for an item type, the next step is using that to identify that item type again. You could use the following:
SCAR Code:
{*******************************************************************************
function CheckItemBlackList(WhichBankSlot:integer;WhichBlackList:array of integer;WhichList:TPointArray):boolean;
By: Boreas
Description: Returns true if an items blacklist matches the one in the parameters
*******************************************************************************}
function CheckItemBlackList(WhichBankSlot:integer;WhichBlackList:array of integer;WhichList:TPointArray):boolean;
var Counter,Tmpx1,Tmpy1,ListLength:integer;
var TheBoolean:boolean;
begin
Tmpx1:=79+((((WhichBankSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichBankSlot-1)/8))*38);
ListLength:=getarraylength(WhichBlackList)-1;
TheBoolean:=true;
repeat
if not(getcolor(Tmpx1+Whichlist[WhichBlacklist[Counter]].x,
Tmpy1+Whichlist[WhichBlacklist[Counter]].y)=65536) then
TheBoolean:=false;
Counter:=Counter+1;
until ((not(TheBoolean)) or (Counter=(ListLength+1)));
result:=TheBoolean;
end;
This will look at the integers in the BlackList, match them up to the indexs of the TPoint in the WhichList, look at the corresponding TPoints, and then add those values to the top left of the bankslot you are looking at, and check if the color at those pixels are black.
That works, however there is another way shown below, that may take a little more time, but is still very fast. The above method runs into the same problem as DTMs, whereas the method below does not. The problem is, if you make a DTM of a unstrung bow, it will be found in a strung bow. The method below creates a BlackList of an item in question, and compares it to the one you made before. Since you are using the exact same method to make the list, they will be exactly the same if they are the same type of item.
Let's assume tmplist is a BlackList for cut gems you made by looking at diamond. Also assume that there is another cut gem (lets say a sapphire) in spot 46. The script below will make a BlackList for the item in spot 46, in the same way tmplist was made. It will see that they are both cut gems and say yes.
SCAR Code:
tmplist2:=CreateItemBlackList(46,MyList);
if CompareIntArrays(tmplist,tmplist2) then writeln('yes')
For this you need CompareIntArrays which simply looks at each integer in an array, and if they all match up, returns true.
SCAR Code:
{*******************************************************************************
function CompareIntArrays(FirstIntArray,SecondIntArray:array of integer):boolean;
By: Boreas
Description: Returns true both arrays are the same
******************************************************************************}
function CompareIntArrays(FirstIntArray,SecondIntArray:array of integer):boolean;
var Counter:integer;
begin
if not(getarraylength(FirstIntArray)=getarraylength(SecondIntArray)) then
result:=false;
if (getarraylength(FirstIntArray)=getarraylength(SecondIntArray)) then
begin
result:=true;
repeat
if not(FirstIntArray[Counter]=SecondIntArray[Counter]) then
result:=false;
Counter:=Counter+1;
until ((Counter=getarraylength(FirstIntArray)) or (result=false));
end;
end;
Run the following script on the picture below to see it in action.
SCAR Code:
program New;
{.include SRL/SRL.scar}
var MyList:TPointArray;
var tmpList,tmpList2:array of integer;
var t:integer;
{*******************************************************************************
function Create40PercentTPA:TPointArray;
By: Boreas
Note: Purely an internal function, used in setup.
Description: Returns a TPointArray containing the relative (to x1,y1 of a BSlot)
for 385 points (out of 31*31, hence 40%). Only needs to be done once, to create
the list of points to check for 65536. Only takes like 15ms, and I didn't
feel like typing them all out.
*******************************************************************************}
function Create40PercentTPA:TPointArray;
var Counter,hx,hy:integer;
var TPointsToCheck:array [0..384] of TPoint;
begin
repeat
hy:=15;
hx:=hx+1;
repeat
hy:=hy+1;
if (((hx mod 4)=0) or ((hy mod 4)=0)) then
begin
TPointsToCheck[Counter].x:=hx;
TPointsToCheck[Counter].y:=hy;
Counter:=Counter+1;
end;
until hy=31;
until hx=31;
result:=TPointsToCheck;
end;
{*******************************************************************************
function CreateItemBlackList(WhichBankSlot:integer;WhichList:TPointArray):array of integer;
By: Boreas
Description: Looks at the points in the list for an item, and returns an array
contatining the indexes of the points that are black.
Usage: WhichBankSlot-just what it sounds like. WhichList-the TPointArray
containing positions relative to the x1,y1 of a bankslot which you want to check
*******************************************************************************}
function CreateItemBlackList(WhichBankSlot:integer;WhichList:TPointArray):array of integer;
var Counter,Counter2,Tmpx1,Tmpy1,ListLength:integer;
var TmpArray:array of integer;
begin
Tmpx1:=79+((((WhichBankSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichBankSlot-1)/8))*38);
ListLength:=getarraylength(WhichList)-1;
setarraylength(tmparray,1);
for Counter:= 0 to ListLength do
begin
if GetColor(Tmpx1+WhichList[Counter].x,Tmpy1+WhichList[Counter].y)=65536 then
begin
TmpArray[Counter2]:=Counter;
Counter2:=Counter2+1;
setarraylength(TmpArray,Counter2+1);
end;
end;
result:=TmpArray;
end;
{*******************************************************************************
function CheckItemBlackList(WhichBankSlot:integer;WhichBlackList:array of integer;WhichList:TPointArray):boolean;
By: Boreas
Description: Returns true if an items blacklist matches the one in the parameters
*******************************************************************************}
function CheckItemBlackList(WhichBankSlot:integer;WhichBlackList:array of integer;WhichList:TPointArray):boolean;
var Counter,Tmpx1,Tmpy1,ListLength:integer;
var TheBoolean:boolean;
begin
Tmpx1:=79+((((WhichBankSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichBankSlot-1)/8))*38);
ListLength:=getarraylength(WhichBlackList)-1;
TheBoolean:=true;
repeat
if not(getcolor(Tmpx1+Whichlist[WhichBlacklist[Counter]].x,
Tmpy1+Whichlist[WhichBlacklist[Counter]].y)=65536) then
TheBoolean:=false;
Counter:=Counter+1;
until ((not(TheBoolean)) or (Counter=(ListLength+1)));
result:=TheBoolean;
end;
{*******************************************************************************
function CompareIntArrays(FirstIntArray,SecondIntArray:array of integer):boolean;
By: Boreas
Description: Returns true both arrays are the same
******************************************************************************}
function CompareIntArrays(FirstIntArray,SecondIntArray:array of integer):boolean;
var Counter:integer;
begin
if not(getarraylength(FirstIntArray)=getarraylength(SecondIntArray)) then
result:=false;
if (getarraylength(FirstIntArray)=getarraylength(SecondIntArray)) then
begin
result:=true;
repeat
if not(FirstIntArray[Counter]=SecondIntArray[Counter]) then
result:=false;
Counter:=Counter+1;
until ((Counter=getarraylength(FirstIntArray)) or (result=false));
end;
end;
function intArrayToStr(intArray: array of Integer): string;
var
i, arrayLength: Integer;
begin
arrayLength := GetArrayLength(intArray);
repeat
Result := Result + IntToStr(intArray[i]);
if (not (i = (arrayLength - 1))) then
Result := Result + ' ';
i := i + 1;
until (i = arrayLength)
end;
function strToIntArray(intArray: string): array of Integer;
var
i, spacePos: Integer;
begin
repeat
SetArrayLength(Result, i + 1);
spacePos := Pos(' ', intArray);
if (not (spacePos = 0)) then
begin
Result[i] := StrToInt(Copy(intArray, 1, spacePos - 1));
end
else
begin
Result[i] := StrToInt(Copy(intArray, 1, Length(intArray)));
break;
end;
Delete(intArray, 1, spacePos);
i := i + 1;
until (False)
end;
begin
setupsrl;
t:=getsystemtime;
MyList:=Create40PercentTPA;
tmplist:=CreateItemBlackList(45,MyList);
tmplist2:=CreateItemBlackList(46,MyList);
//writeln(inttostr(getarraylength(tmplist2)));
//writeln(intarraytostr(tmplist2));
if CompareIntArrays(tmplist,tmplist2) then writeln('yes')
//if (tmplist=tmplist2) then writeln('yes');
//writeln(inttostr(getsystemtime-t)+'ms');
{
if CheckItemBlackList(46,tmplist,mylist) then
writeln('yes');
writeln(inttostr(getsystemtime-t));
}end.

Please note that is a small technique, to be combined with others. It is a very small part of B4, and doesn't do that much without the rest. But I thought I would post it here now so you can use it if you want. Plus, unlike most of B4, this doesn't require any edits to SRL, or lower level supporting functions (because it is one) besides the ones I posted above.
Please note this tutorial is very rough. If anyone is interested and needs me to clean it up a bit, I will. Any questions, feel free to ask. Since I created it, it's hard for me to explain it, as I was never taught it, so I may have left out important parts lol.
Hehe I had 3 tuts out and none were about actual scripting, so I had to fix that lol