SRL Archive - Research & Development Lounge

New way to find Objects (FindObjects)


marpis

2009-04-14 12:43:58

i got this idea from reflection. My function FindObjects() finds all objects in the mainscreen, and saves them in an array of TObject2. As we all know, names cannot be found with colors so TObject2 has no 'name' property.

What makes it better than FindObj()?
For finding a single object, a door for example, FindObj() is accurate enough. But when you have 5 monsters on your screen, and you need to find the best one to attack (which is the nearest unattacked monster) it is much easier to inspect the monsters as an array. I use this technique in my new universal Multifighter (not ready yet) and it seems to work fine.
Remember: No color-based function is 100% accurate. It sometimes doesnt notice if a monster is in fight, but hasnt been a problem for me.

MAJOR UPDATE TO FindObjects() !!
MAJOR UPDATE TO FindObjects() again !!
- Now you can define the size of the object (width, height)
- You can define the accuracy required (see the description)
* now the accuracy actually works ^^
* removed double check colors, no need for that. now its much faster and still reliable
* colorspeedmodifiers, its now even more accurate
Here are all the functions i made to make this system work:

//type TObject2 by marpis
type TObject2 = record
x: integer;
y: integer;
InFight: boolean;
end;

{*******************************************************************************
function IsInFight(x, y: integer): Boolean;
By: marpis
Description: Checks if there is a fight at (x, y)
*******************************************************************************}
function IsInFight(x, y: integer): Boolean;
var
G, R: TPointArray;
begin
if not loggedin then exit;
FindColorsTolerance(G, 65280, x-35, y-35, x+35, y+35, 0);
FindColorsTolerance(R, 255, x-35, y-35, x+35, y+35, 0);
Result := High(CombineTPA(G, R)) > 10;
end;

{*******************************************************************************
procedure DeleteATPAIndex(i: Integer; var arr: T2DPointArray);
By: Nava2 & marpis
Description: Deletes an ATPA index in array
*******************************************************************************}
//DeleteIndex by Nava2. Thanks! (again)
procedure DeleteATPAIndex(i: Integer; var arr: T2DPointArray);
begin
swap(arr[i], arr[High(arr)]);
SetLength(arr, High(arr));
end;
{*******************************************************************************
procedure DeleteObj2ArrayIndex(i: Integer; var arr: Array of TObject2);
By: Nava2 & marpis
Description: Deletes an Object index in array of TObject2
*******************************************************************************}
procedure DeleteObj2ArrayIndex(i: Integer; var arr: Array of TObject2);
begin
swap(arr[i], arr[High(arr)]);
SetLength(arr, High(arr));
end;

{=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
{ function FindObjects
var Objs: Array of TObject2 Here the found objects are stored
width, height: Size of the object
colors: TIntegerArray, object colors
tolerance: Color tolerance
accuracy: Minimum amount of pixels per object
ExcludeSelf: Ignore objects at the same spot than you are
{=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
function FindObjects(var Objs: Array of TObject2; width, height: integer; colors: TIntegerArray; accuracy, tolerance: integer; ExcludeSelf: boolean): boolean;
var
TPA, TempTPA: TPointArray;
ATPA: T2DPointArray;
i, hi, CTS: integer;
P: TPoint;
Box: TBox;
begin
if not loggedin then exit;
CTS := GetColorToleranceSpeed;
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(0.1, 0.4);
for i:= 0 to high(colors) do
begin
FindColorsSpiralTolerance(MSCX, MSCY, TempTPA, colors[i], MSX1, MSY1, MSX2, MSY2, tolerance);
TPA:= CombineTPA(TPA, TempTPA);
end;
SetColorspeed2Modifiers(0.2, 0.2);
ColorToleranceSpeed(CTS);
if (Length(TPA) < accuracy) then exit;
ATPA:= SplitTPAEx(TPA, width, height);
SetArrayLength(Objs, Length(ATPA));
Result:= Length(ATPA) > 0;
SortATPASize(ATPA, true);
//DebugATPA(ATPA, '');
for i:= 0 to High(ATPA) do
begin
P:= MiddleTPA(ATPA[i]);
Box:= IntToBox(245, 145, 275, 180);
if (PointInBox(P, Box) and ExcludeSelf) or (Length(ATPA[i]) < accuracy) then
DeleteATPAIndex(i, ATPA)
else
begin
Objs[i].x := P.x;
Objs[i].y := P.y;
Objs[i].InFight := IsInFight(P.x, P.y);
end;
end;
end;


{*******************************************************************************
procedure QuickSort(var A: array of Integer; iLo, iHi: Integer);
By: some dude in IRC: #delphi @ Quakenet
Description: Sorts integerarray from min to max
*******************************************************************************}
procedure QuickSort(var A: array of Integer; iLo, iHi: Integer);
var
Lo, Hi, Pivot, T: Integer;
begin
Lo := iLo;
Hi := iHi;
Pivot := A[(Lo + Hi) div 2];
repeat
while A[Lo] < Pivot do Inc(Lo);
while A[Hi] > Pivot do Dec(Hi);
if Lo <= Hi then
begin
T := A[Lo];
A[Lo] := A[Hi];
A[Hi] := T;
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if Hi > iLo then QuickSort(A, iLo, Hi);
if Lo < iHi then QuickSort(A, Lo, iHi);
end;

{*******************************************************************************
function ArrangeObjects(Objs: Array of TObject2): array of TObject2;
By: marpis
Description: Arrange objects in array from closest to furthers
*******************************************************************************}
function ArrangeObjects(Objs: Array of TObject2): array of TObject2;
var
i, w: integer;
Distances, Distances2: TIntegerArray;
begin
SetArrayLength(Distances, GetArrayLength(Objs));
SetArrayLength(Distances2, GetArrayLength(Objs));
for i:= 0 to High(Objs) do
begin
Distances[i] := Distance(MSCX, MSCY, Objs[i].x, Objs[i].y);
Distances2[i] := Distance(MSCX, MSCY, Objs[i].x, Objs[i].y);
end;
QuickSort(distances, Low(distances), High(distances));
for i:= 0 to High(Objs) do
begin
InIntArrayEx(Distances2, w, distances[i]);
Result[i] := Objs[w];
end;
end;

{*******************************************************************************
procedure FilterFightingMonsters(Mobs: Array of TObject2);
By: marpis
Description: Filters objects that are in fight in array
*******************************************************************************}
procedure FilterFightingMonsters(Mobs: Array of TObject2);
var
i: integer;
begin
for i:= 0 to High(Mobs) do
if Mobs[i].InFight then
DeleteObj2ArrayIndex(i, Mobs);
end;

Example of fnding a giant rat:

function KillRat: boolean
var
Rats: array of TObject2;
i, x, y: integer;
begin
if FindObjects(Rats, 50, 30, [1904881, 293719, 945789], 5, 15, true) then
begin
FilterFightingMonsters(Rats);
Rats:= ArrangeObjects(Rats);
for i:= 0 to High(Rats) do
begin
MMouse(Rats[i].x, Rats[i].y, 5, 5);
if IsUpText('iant') then
begin
GetMousePos(x, y);
Mouse(x, y, 0, 0, false);
Result:= ChooseOption('ttack');
end;
end;
end else writeln('No rats found!');
end;

Thanks for comments!
:)

3Garrett3

2009-04-18 03:30:00

I will make a comment to lighten the mood. A very sexy piece of work. I haven't shaken off the rust yet, but I will say that it looks pretty darn great to me :P. I didn't even really figure this was possible. Very much enjoy this though. :)

Cazax

2009-04-18 03:41:37

It's a pretty good function, I want to point some things:
- It only can be used for fighting from I can see, so you should make it compatible for finding objects.
- It has many functions and procedures, people wouldn't want to include them in their scripts… As a public include it is ok.
- QuickSort is already in SCAR.
- Storing High() in a variable will save you quite few milliseconds, so it's not a bad habit.

I like the way you structure your functions, good job :)

n3ss3s

2009-04-18 11:48:19

The invention to put them in an array and pick the closest one is maybe 2-3 years old at SRL, and it's been called a new one around 200-300 times :p

HyperSecret

2009-04-18 20:23:03

From: n3ss3s
The invention to put them in an array and pick the closest one is maybe 2-3 years old at SRL, and it's been called a new one around 200-300 times :p


Agreed Nice thought though. Narcle has a pretty good TPA system in both his fighters and I have something similar in my autofigher.

marpis

2009-04-19 20:18:27

From: Cazax

- It only can be used for fighting from I can see, so you should make it compatible for finding objects.


??


function FindNearestDoor: boolean;
var
Doors: array of TObject2;
begin
if FindObjects(Doors, 20, 40, [DoorColor1, DoorColor2, DoorColor3], 20, 20, false) then
begin
Doors:= ArrangeObjects(Doors);
MMouse(Doors[0].x, Doors[0].y, 3, 3);
result:= IsUpText('pen');
end;
end;

Cazax

2009-04-19 21:30:37

I should have looked further into your functions :p… IsInFight made me believe that. I think that it's not needed since SRL has it in Randoms.scar and Fighting.scar.