PDA

View Full Version : Bank Browsing- BlackLists with Color



Boreas
02-24-2007, 05:57 AM
NOTE: I have found a situation where this technique doesn't work. I have developed a new technique that will work all the time, but is a little more complicated (but in some ways easier). This method is still best for somethings (staffs), so both methods will be available. See post 10 for more details.


Bank Browsing- BlackLists w/ FindColorTolerance

Level: Intermediate but you must read this first LINK TO BLACKLIST TUT (http://www.villavu.com/forum/showthread.php?t=6229?t=7151)

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-
If you have read the BlackList tutorial (if not, do that first) you that a BlackList for a steel bar will be the same for a gold bar. This tutorial will go over how to tell the difference, once the BlackLists have narrowed it down.

How do we tell the difference? There are multiple ways; DTMs/Bitmaps/Colors (uptext moves the mouse, we will do that later) but they all come down to one thing, color. Since the color isn't static like the black (65536) we also need tolerance. Now we don't need anything fancy, FindColorTolerance will do. The way we use it is where it gets fancy.

FindColorTolerance looks for multiple colors (tolerance) in multiple pixels (in a specified box). This won't bring your computer to a grinding halt, but if we can minimize the effect, then why not? First off the tolerance, make this as small as you can get away with. You can use various utilities to help with this, I'll leave it to you to figure out because it's different for different items. The second part is the area to search in, that's where we can really improve. Before I talk more about that, let's start at the beginning.

Ok let's say we are looking for a fire rune, and we have other runes such as air, and one BlackList would work for both. The BlackList tutorial shows how to check whether a specific item fits a BlackList. Let's expand on this by finding an item that fits, in fact all items that fit.

Check this out:
{************************************************* ******************************
function InIntArray(TheInt:integer;TheArray:array of integer):boolean;
By: Boreas
Description: Returns true if TheInt is a member of TheArray
************************************************** ****************************}
function InIntArray(TheInt:integer;TheArray:array of integer):boolean;
var i:integer;
begin
repeat
if TheArray[i]=TheInt then
result:=true;
i:=i+1;
until ((i=getarraylength(TheArray)) or (result));
end;

{************************************************* ******************************
function FindAllSlotsBlackListSkip(BlackList:array of integer; PointList:TPointArray; SkipEm:array of integer):array of integer;
By: Boreas
Description: Returns the BankSlots containing the BlackList found with the
PointList. Skips the slots in SkipEm. Use [0] to skip none.
************************************************** ****************************}
function FindAllSlotsBlackListSkip(BlackList:array of integer; PointList:TPointArray; SkipEm:array of integer):array of integer;
var slot,counter:integer;
tmpBlackList, tmpresult:array of integer;

begin
for slot:=1 to 48 do
begin
if not(InIntArray(slot,SkipEm)) then //is there a better way?
begin
tmpBlackList:=CreateItemBlackList(slot,PointList);
if CompareIntArrays(BlackList,tmpBlackList) then
begin
setarraylength(tmpresult,counter+1);
tmpresult[counter]:=slot;
counter:=counter+1;
end;
end;
end;
result:=tmpresult;
end;

It returns a integer array of all the spots that have the same BlackList as the one specified.

Notice it can also skip an array of spots. If you know it's not somewhere, then why bother looking there? B4 will make more use of this feature with chains of functions that accept spots check/skip and return spots for the next one to look at, until there is 1. For now, just put [0].

Here it is in action
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;WhichLis t: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;WhichLis t: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 CompareIntArrays(FirstIntArray,SecondIntArray:arra y of integer):boolean;
By: Boreas
Description: Returns true both arrays are the same
************************************************** ****************************}
function CompareIntArrays(FirstIntArray,SecondIntArray:arra y of integer):boolean;
var Counter:integer;
begin
if not(getarraylength(FirstIntArray)=getarraylength(S econdIntArray)) then
result:=false;


if (getarraylength(FirstIntArray)=getarraylength(Seco ndIntArray)) 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;

//in misc/arrayloader.scar by moparisthebest
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;

//in misc/arrayloader.scar by moparisthebest
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;

{************************************************* ******************************
function InIntArray(TheInt:integer;TheArray:array of integer):boolean;
By: Boreas
Description: Returns true if TheInt is a member of TheArray
************************************************** ****************************}
function InIntArray(TheInt:integer;TheArray:array of integer):boolean;
var i:integer;
begin
repeat
if TheArray[i]=TheInt then
result:=true;
i:=i+1;
until ((i=getarraylength(TheArray)) or (result));
end;

{************************************************* ******************************
function FindAllSlotsBlackListSkip(BlackList:array of integer; PointList:TPointArray; SkipEm:array of integer):array of integer;
By: Boreas
Description: Returns the BankSlots containing the BlackList found with the
PointList. Skips the slots in SkipEm. Use [0] to skip none.
************************************************** ****************************}
function FindAllSlotsBlackListSkip(BlackList:array of integer; PointList:TPointArray; SkipEm:array of integer):array of integer;
var slot,counter:integer;
tmpBlackList, tmpresult:array of integer;

begin
for slot:=1 to 48 do
begin
if not(InIntArray(slot,SkipEm)) then //is there a better way?
begin
tmpBlackList:=CreateItemBlackList(slot,PointList);
if CompareIntArrays(BlackList,tmpBlackList) then
begin
setarraylength(tmpresult,counter+1);
tmpresult[counter]:=slot;
counter:=counter+1;
end;
end;
end;
result:=tmpresult;
end;

begin
t:=getsystemtime;
MyList:=Create40PercentTPA;
tmplist:=CreateItemBlackList(6,MyList);
tmplist2:=findallslotsblacklistskip(tmplist,MyList ,[0]);
writeln(intarraytostr(tmplist2));

writeln(inttostr(getsystemtime-t));
end.

http://img180.imageshack.us/img180/7964/bankcq0.th.png (http://img180.imageshack.us/my.php?image=bankcq0.png)



So now we have 4 slots in which the fire rune could be. Each slot is 31 by 31 pixels, making 3844 pixels all together. But we can do better than that. Items do not move around in their BankSlots. This means the middle of the rune is always the same distance away from the top left corner of the BankSlot, no matter which slot it is in. Remember this fact. Another fact is, the color that distinguishes the fire rune from the rest (red) is not all over the rune, or the slot. It is in the middle. So lets have the FindColorTolerance just look there. So lets get the coordinates of the area you want to look in. Not so fast. We want it to work in any slot, so we want coordinates of the box to be relative to the top left corner of the slot. Lucky for you, I have something for that.

program New;

procedure CreateBoxRelativeToBankSlot;
var x1,y1,x2,y2,slot1,slot2,tmpx,tmpy:integer;
begin
writeln('Put the mouse at the top left of the box');
writeln('Then press F12');
repeat
wait(30);
until isfkeydown(12);
GetMousePos(x1,y1);
slot1:=(((((y1-62) div 38)+1)-1)*8)+(((x1-79) div 47)+1);
tmpx:=79+((((Slot1+7)mod 8))*47);
tmpy:=62+((((Slot1-1)/8))*38);
x1:=x1-tmpx;
y1:=y1-tmpy;

writeln('Put the mouse at the bottom right of the box');
writeln('Then press F11');
repeat
wait(30);
until isfkeydown(11);
GetMousePos(x2,y2);
slot2:=(((((y2-62) div 38)+1)-1)*8)+(((x2-79) div 47)+1);
tmpx:=79+((((Slot2+7)mod 8))*47);
tmpy:=62+((((Slot2-1)/8))*38);
x2:=x2-tmpx;
y2:=y2-tmpy;

if not(slot1=slot2) then writeln('Error try again');
writeln('x1= '+inttostr(x1));
writeln('y1= '+inttostr(y1));
writeln('x2= '+inttostr(x2));
writeln('y2= '+inttostr(y2));
end;

begin
CreateBoxRelativeToBankSlot;
end.

Should be pretty self explanatory, but I'll do it anyway. Run the script on the pic. Move your mouse to top left corner of the box you want look in (around the red). Press F12. Do the same for the bottom right and press F11. Lemme know if I need to make pics of me doing this.

You should get something like
x1= 14
y1= 23
x2= 17
y2= 25

So thanks to the find all BlackList function, we know which slots to look in. Thanks to the box creator, we know where in each slot to look. You figure out the color and tolerance. Now we have everything for this

{************************************************* ******************************
function FindColorTolBanksSlots(color,tolerance,x1,y1,x2,y2 :integer; Slots:array of integer):array of integer;
By: Boreas
Description: Returns array of BankSlots which contain the color with tol in the
box relative to top left of bank slots.
************************************************** ****************************}
function FindColorTolBanksSlots(color,tolerance,x1,y1,x2,y2 :integer; Slots:array of integer):array of integer;
var tmpx,tmpy,Counter, ResultCounter:integer;
tmpresult:array of integer;
begin
for Counter:=0 to getarraylength(Slots)-1 do
begin
tmpx:=79+((((Slots[Counter]+7)mod 8))*47);
tmpy:=62+((((Slots[Counter]-1)/8))*38);
if FindColorTolerance(tmpx,tmpy,color,Slotx1+x1,Sloty 1+y1,Slotx1+x2,Sloty1+y2,tolerance) then
begin
setarraylength(tmpresult,ResultCounter+1);
tmpresult[ResultCounter]:=Counter;
ResultCounter:=ResultCounter+1;
end;
end;
result:=tmpresult;
end;

Similar to the other function, it looks at some spots, and returns which one(s) it narrowed down to. If for some reason this returns more than 1 result, you can narrow it down in the same fashion with another method (probably uptext). You can figure out how to write that from this, I may add it later if you really want.

I think that about covers it, I feel like I'm forgetting something though.

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 and in the BlackList tutorial.

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.

WT-Fakawi
02-24-2007, 02:21 PM
This really needs to be placed in /core!

Boreas
02-24-2007, 04:21 PM
You ain't seen nothin yet :p

BTW, most of the rest of B4 will need something like

type
BSlot=record
row,column,
x1,x2,y1,y2,
ItemNumber:integer;
ItemName:string;
end;

BankSlot: array [1..48] of Bslot;

added to Tuser. Although I may put most of it a global array of 48, because they don't change per player, and just have the itemname and number in the player array, because they do.

YoHoJo
02-24-2007, 08:17 PM
CONGRATULATIONS ON DEV BOREAS
You really deserve it =).

Boreas
02-24-2007, 09:24 PM
Thanks :)

You still think DTMs are the best thing ever? hehehe

WhiteShadow
02-25-2007, 05:33 AM
I r jelous of joo. y u much be so ownagensmart?! rawful.

you are new cool scripter in my book :}

and i never ever would think of taking advantage of the black color and using it to make a tpointarray. and match tpoint coords to find things. i mean wtf. wowza pleas?

Boreas
02-25-2007, 05:36 AM
Hehe thanks. Btw BlackLists are actually simple integer arrays, not TPoint arrays. They just reference to a TPointArray.

pwnaz0r
02-25-2007, 10:09 PM
:p Thats A Nice little idea you've thought of Boreas. + rep bro and grats on dev rank. Could there be an easier way to find the box to search for the color for in tho? I'll try to see if I can think of anything. Doubt I can but none the less :p

Boreas
02-25-2007, 10:14 PM
You mean the CreateBoxRelativeToBankSlot thing? Just as long as it gets coords of the box inside the bankslot, as opposed to client, anything is fine.

If you mean to find which bankslots to look for the color in, you could use Dtms, bitmaps, anything. But then there would be no point, because they can use color too, whereas BlackLists are designed to be quick and ignore color.

Boreas
05-25-2007, 02:57 PM
NOTE: I have found a situation where this technique doesn't work. I have developed a new technique that will work all the time, but is a little more complicated (but in some ways easier). So you can use this for now if you really can't wait.

I was looking at runes, and found that the colors don't change much from world to world. So I was using a generic color and 20 tolerance,which is more than enough to find 2 water colors similar, but not laws. That's the good news. Bad news is deaths and waters use the same color. So I thought, that's annoying, but at least the color is in different places. So I made a box (using tool above) on a death rune, where there is no white color, but the same box on an air rune would have color. I ran my test script, it listed all the spots with runes, and then only listed the spot with airs. That's the other good news. The other bad news is that making a box on air rune that doesn't contain white, but does on death, is reallllly annoying.

The solution: BlackLists, that aren't black ;). The technology was already there, I just changed 65536 to a parameter color in CreateItemBlackList. Then instead of getcolor=color, I did SimilarColors with a tol from parameter (so far 15 always works). I was using the custom net function (see other BlackList tut) and using 2 for the net made it take over a second. 2 is needed to get runes but not rune ess. I experimented with different net values for the initial BlackList search and the narrowing down ColorList search. I found that 8 made the BlackList search not as accurate, but that didn't matter when combined with the ColorList search also at 8. So it's taking less than half a second to do both searches. And remember, when looking for multiple runes (always, because there isn't a spell that uses 1 type of rune afaik), it will save time by doing the BlackList search only once, and then 1 ColorList search for each type of rune.

Another thing is metal bars and the like, which don't have colors and symbols like runes, but just colors. I have a feeling that you can use the same list for each, and just change the color. Edit: nvm

This makes things a little more complicated having 2 lists, but it also makes it simpler with uniformity. So yea, I'll change B4 for this.


EDIT: ahh colorlists don't work for staffs because they don't look high where the numbers are, so both methods will be available.

wired16
05-25-2007, 04:38 PM
boreas=god? lol

WT-Fakawi
05-25-2007, 04:56 PM
As a last resort, you could always hover or RightClick in order to get the right Objectname....

Should we add a record Bankslot to the Player array?

Boreas
05-25-2007, 05:26 PM
Yes, that is why I am working with
Slots: array of integer;
which gets shorter as it's narrowed down. Hopefully, it will get to 1, and then the uptext check will be built into the right clicking. If it's more than 1, then it will move to each one in the list. I really want it to be perfect without uptext though, because I hate FindObj type stuff.

Yea, I'll add that later, for Inv and Bank. Each player will have item Name, ID, and Amount for each slot, and then there will be a separate array out of the playerarray that contains coord info for each slot.

ShowerThoughts
08-25-2007, 08:46 PM
your really cool but is very confiusing

alach11
08-25-2007, 09:07 PM
Holy shit... this really does need to be added to core. Great work, hard to imagine something as awsome as "MakeInventory".

Distort
08-26-2007, 11:19 AM
I'm a bit confused about where you start talkingabout "top left of the box", I'm assuming you mean a imaginary box around a object or is it something i've missed completly.

Boreas
08-26-2007, 02:26 PM
Yes. Move your mouse over an item, move it up until the uptext goes away, then move down 1 pixel. Then move left until uptext goes away, then move right 1 pixel. That is what I call the x1,y1 of that slot.


This script outputs a formula for finding the x1y1's of the inventory. To use, get a player straight from tut island, or just make sure you have an axe in spot 1 (top left) of inventory, tinderbox in spot 2 (to the right of axe) and bucket in spot 5 (below axe), which is what you have after tut island.

program New;
{.include srl/srl.scar}

const
InvSlot1X1= 563;
const
InvSlot1Y1= 213;
const
InvSlot2X1= 605;
const
InvSlot5Y1= 249;
{************************************************* ******************************
function CreateItemBlackList(WhichBankSlot:integer;WhichLis t: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(WhichSlot: integer; WhichList: TPointArray):array of integer;
var Counter,Counter2,Tmpx1,Tmpy1,ListLength:integer;
var TmpArray:array of integer;
begin
Tmpx1:=79+((((WhichSlot+7)mod 8))*47);
Tmpy1:=62+((((WhichSlot-1)/8))*38);
if WhichSlot > 48 then //inv
begin
Tmpx1:=InvSlot1X1+(((((WhichSlot-48)+3)mod 4))*(InvSlot2X1-InvSlot1X1));
Tmpy1:=InvSlot1Y1+(((((WhichSlot-48)-1)/4))*(InvSlot5Y1-InvSlot1Y1));
end;
if WhichSlot>(48+28) then //shop
begin
Tmpx1:=80+(((((WhichSlot-(48+28))+7)mod 8))*47);
Tmpy1:=69+(((((WhichSlot-(48+28))-1)/8))*47);
end;
if WhichSlot>(48+28+40) then //left trade
begin
Tmpx1:=36+(((((WhichSlot-(48+28+40))+3)mod 4))*42);
Tmpy1:=75+(((((WhichSlot-(48+28+40))-1)/4))*33);
end;
if WhichSlot>(48+28+40+28) then //right trade
begin
Tmpx1:=325+(((((WhichSlot-(48+28+40+28))+3)mod 4))*42);
Tmpy1:=73+(((((WhichSlot-(48+28+40+28))-1)/4))*33);
end;

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;
setarraylength(TmpArray,Counter2-1);
result:=TmpArray;
end;





var Axe:integer;
procedure LoadDTM;
begin

Axe := DTMFromString('78DA63B4676260B8C58006189148206D035 4F' +
'398801A0BA09A7704D4D801D5BCC4AD8609443B02C9FB04D4 3803' +
'C9BB04D47801C98704D4F800C93B04D4B802C91BF8D500002 0D60' +
'A6F');
end;
procedure CalibrateInv;
var x,y,w,h,yadd,xadd,x1,y1,x2,y2:integer;
begin
LoadDTM;
GetClientDimensions(w,h);
FindDTM(Axe,x,y,0,0,w,h);

xadd:=x;
MMouse(x,y,0,0);
repeat
xadd:=xadd-1;
MMouse(xadd,y,0,0);
wait(400+random(50));
until not(IsUpText('xe'));
x1:=xadd;
getmousepos(x1,y1); //
writeln('const');
writeln(' InvSlot1X1= '+inttostr(x1+1)+';');

yadd:=y;
MMouse(x,yadd,0,0);
repeat
yadd:=yadd-1;
MMouse(x,yadd,0,0);
wait(400+random(50));
until not(IsUpText('xe'));
y1:=yadd;
getmousepos(x1,y1); //
writeln('const');
writeln(' InvSlot1Y1= '+inttostr(y1+1)+';');

xadd:=x+50;
MMouse(x+50,y,0,0);
repeat
xadd:=xadd-1;
MMouse(xadd,y,0,0);
wait(400+random(50));
until not(IsUpText('inder'));
x2:=xadd;
getmousepos(x2,y2);
writeln('const');
writeln(' InvSlot2X1= '+inttostr(x2+1)+';');

yadd:=y+50;
MMouse(x,y+50,0,0);
repeat
yadd:=yadd-1;
MMouse(x,yadd,0,0);
wait(400+random(50));
until not(IsUpText('ucket'));
y2:=yadd;
getmousepos(x2,y2);
writeln('const');
writeln(' InvSlot5Y1= '+inttostr(y2+1)+';');

writeln('Tmpx1:='+inttostr(x1)+'+(((((WhichSlot-48)+3)mod 4))*'+inttostr(x2-x1)+');');
writeln('Tmpy1:='+inttostr(y1)+'+(((((WhichSlot-48)-1)/4))*'+inttostr(y2-y1)+');');


end;
procedure DeclarePlayers;
begin
HowManyPlayers := 1;
CurrentPlayer:=0;
NumberOfPlayers(HowManyPlayers);

Players[0].Name :='';// a noob STRAIGHT from tut island
Players[0].Pass :='';
Players[0].Nick :='';
Players[0].Active:=True;
end;
begin
Setupsrl;
BenMouse:=false;
DeclarePlayers;
LoginPlayer;
CalibrateInv;
end.