SRL Archive - Research & Development Lounge

New DoorProfiles.scar!


lordsaturn

2008-11-17 00:16:15

Updated: Dec. 12, 2010
//-----------------------------------------------------------------//
//-- Scar Standard Resource Library --//
//-- ? Door Routines --//
//-----------------------------------------------------------------//
// * function IsDropDot(Pt: TPoint): Boolean; // * by lordsaturn
// * function IsNPCDot(Pt: TPoint): Boolean; // * by lordsaturn
// * function IsDungeonArrow(Pt: TPoint): Boolean; // * by lordsaturn
// * function FilterDropDots(P: TPointArray): TPointArray; // * by lordsaturn
// * function GetDoorPoints: T2DPointArray; // * by lordsaturn
// * function GetDoorColors: TIntegerArray; // * by lordsaturn
// * function GetDoorColor: integer; // * by lordsaturn
// * function RearrangeTPA(TPA: TPointArray; sortX, up: Boolean): TPointArray; // * by lordsaturn
// * function MiddleDoor(var P: TPointArray; var slope: extended): TPoint; // * by lordsaturn
// * function GetDoors: array of TDoorProfile; // * by lordsaturn
// * function GetDoorsIn(x1, y1, x2, y2: integer): array of TDoorProfile; // * by lordsaturn
// * procedure SortDoorsFrom(var d: array of TDoorProfile; From: TPoint); // * by lordsaturn
// * procedure DebugDoors(doors: array of TDoorProfile); // * by lordsaturn

type
TDoorProfile = record
Points: TPointArray;
MidPoint: TPoint;
PixelCount: Integer;
Slope: Extended;
Color: Integer;
end;

{ 3553023 789758
3553023 2105598 395004 237
789758 395004 237 206
65536 217 188 65536
65536 65536 }


{*******************************************************************************
function IsDropDot(Pt: TPoint): Boolean;
By: lordsaturn
Description: Returns true if a point is in a drop dot.
*******************************************************************************}
function IsDropDot(Pt: TPoint): Boolean;
var
Col: integer;
begin
Col := GetColor(Pt.x, Pt.y);
if (Col = 395004) or (Col = 237) then
case Col of
206: Result := (GetColor(Pt.x-2, Pt.y) = 395004) or (GetColor(Pt.x-1, Pt.y) = 237);
217: Result := (GetColor(Pt.x, Pt.y-1) = 395004) or (GetColor(Pt.x+1, Pt.y-1) = 237);
237: Result := (((GetColor(Pt.x-1, Pt.y+1) = Col) or (GetColor(Pt.x+1, Pt.y-1) = Col)) and
(GetColor(Pt.x, Pt.y+2) = 65536)) or ((GetColor(Pt.x-2, Pt.y-1) = 3553023) or
(GetColor(Pt.x-1, Pt.y-2) = 3553023)) or (GetColor(Pt.x-1, Pt.y) = 395004);
395004: Result := (GetColor(Pt.x+1, Pt.y) = 237) or (GetColor(Pt.x+1, Pt.y+2) = 65536) or
(GetColor(Pt.x-1, Pt.y-1) = 3553023);
end;
end;

{ 16711422 16711422
16711422 16711422 16711422 15527148
16711422 16711422 15527148 13816530
65536 14869218 12961221 65536
65536 65536 }
//white

{ 1179390 1179390
1179390 195836 62965 56797
195836 195836 60909 52428
65536 56797 52428 65536
65536 65536 }
//yellow
{*******************************************************************************
function IsNPCDot(Pt: TPoint): Boolean;
By: lordsaturn
Description: Returns true if a point is in a npc dot.
*******************************************************************************}
function IsNPCDot(Pt: TPoint): Boolean;
var
Col: integer;
begin
Col := GetColor(Pt.x, Pt.y);
if (Col = 195836) or (Col = 62965) or (Col = 60909) then
case Col of
195836: Result := (GetColor(Pt.x+1, Pt.y+2) = 65536) or (GetColor(Pt.x, Pt.y-1) = 1179390) or
(GetColor(Pt.x+1, Pt.y-1) = 62965) or (GetColor(Pt.x, Pt.y+1) = Col) or
(GetColor(Pt.x, Pt.y+1) = 56797) or (GetColor(Pt.x+1, Pt.y+1) = 56797) or
(GetColor(Pt.x+1, Pt.y+1) = 52428);
62965: Result := (GetColor(Pt.x-2, Pt.y) = 1179390) or (GetColor(Pt.x, Pt.y-1) = 1179390) or
(GetColor(Pt.x+1, Pt.y) = 56797) or (GetColor(Pt.x, Pt.y+3) = 65536);
60909: Result := (GetColor(Pt.x - 2, Pt.y) = 195836) or (GetColor(Pt.x+1, Pt.y) = 52428) or
(GetColor(Pt.x, Pt.y-2) = 1179390) or (GetColor(Pt.x, Pt.y+2) = 65536);
end;
end;

//GetColor(Pt.x, Pt.y) = 254
{*******************************************************************************
function IsDungeonArrow(Pt: TPoint): Boolean;
By: lordsaturn
Description: Returns true if a point is in a dungeon arrow.
*******************************************************************************}
function IsDungeonArrow(Pt: TPoint): Boolean;
var
Col: integer;
begin
Col := GetColor(Pt.x, Pt.y-1);
Result := ((Col = GetColor(Pt.x-1, Pt.y-2)) and (Col = GetColor(Pt.x+1, Pt.y)) and
(Col = GetColor(Pt.x+2, Pt.y))) or (GetColor(Pt.x, Pt.y+1) = 92) or (GetColor(Pt.x-2, Pt.y) = 1787389)
or (GetColor(Pt.x-1,Pt.y) = 92) or (GetColor(Pt.x, Pt.y+1) = 1787389);
end;

{*******************************************************************************
function FilterDropDots(P: TPointArray): TPointArray;
By: lordsaturn
Description: Returns a TPointArray filtered of drop dots.
*******************************************************************************}
function FilterDropDots(P: TPointArray): TPointArray;
var
i, Hi, L: integer;
begin
Hi := High(P);
if Hi < 0 then Exit;
SetLength(Result, Hi+1);
for i := 0 to Hi do
if rs_OnMinimap(P[i].x, P[i].y) and (not(IsDropDot(P[i]))) and (not(IsNPCDot(P[i])))
and (not(IsDungeonArrow(P[i]))) then
begin
Result[L] := P[i];
Inc(L);
end;
SetLength(Result, L);
end;

{*******************************************************************************
function GetDoorPoints: T2DPointArray;
By: lordsaturn
Description: Returns all door points on the minimap in a T2DPointArray.
*******************************************************************************}
function GetDoorPoints: T2DPointArray;
var
CTS, notUsedX, notUsedY: integer;
huemod, satmod: Extended;
P: TPointArray;
begin
CTS := GetColorToleranceSpeed;
SetColorToleranceSpeed(2);
GetToleranceSpeed2Modifiers(huemod, satmod);
SetToleranceSpeed2Modifiers(16.65, 0.82);
FindColorsSpiralTolerance(notUsedX, notUsedY, P, 15987715, MMX1, MMY1, MMX2, MMY2, 3);
SetToleranceSpeed2Modifiers(huemod, satmod);
SetColorToleranceSpeed(CTS);
if Length(P) < 1 then Exit;
Result := SplitTPA(FilterDropDots(P), 6);
SortATPAFrom(Result, Point(MMCX, MMCY));
end;

{*******************************************************************************
function GetDoorColors: TIntegerArray;
By: lordsaturn
Description: Returns all door colors on the minimap in an array.
*******************************************************************************}
function GetDoorColors: TIntegerArray;
var
aP: T2DPointArray;
Hi, i, c, L: integer;
begin
try
Freeze;
aP := GetDoorPoints;
Hi := High(aP);
if Hi < 0 then Exit;
SetLength(Result, Hi+1);
for i := 0 to Hi do
begin
c := GetColor(aP[i][0].x, aP[i][0].y);
if (c > 0) and (not(InIntArray(Result, c))) then
begin
Result[L] := c;
Inc(L);
end;
end;
SetLength(Result, L);
finally
Unfreeze;
end;
end;

{*******************************************************************************
function GetDoorColor: integer;
By: lordsaturn
Description: Returns the first door color found from the center of the minimap.
*******************************************************************************}
function GetDoorColor: integer;
var
a: TIntegerArray;
begin
a := GetDoorColors;
if Length(a) < 1 then Exit;
Result := a[0];
end;

{*******************************************************************************
function RearrangeTPA(TPA: TPointArray; sortX, up: Boolean): TPointArray;
By: lordsaturn
Description: Sorts a TPA according to params.
*******************************************************************************}
function RearrangeTPA(TPA: TPointArray; sortX, up: Boolean): TPointArray;
var
i, Hi, j: integer;
ints, indexes: TIntegerArray;
P: TPointArray;
begin
Hi := High(TPA);
SetLength(Result, Hi+1);
if Hi < 1 then
begin
Result := TPA;
Exit;
end;
P := TPA;
SetLength(ints, Hi+1);
SetLength(indexes, Hi+1);
for i := 0 to Hi do
begin
indexes[i] := -1;
if sortX then
ints[i] := P[i].x
else
ints[i] := P[i].y;
end;
QuickSort(ints);
for i := 0 to Hi do
for j := 0 to Hi do
if (sortX and (ints[i] = P[j].x)) or ((not(sortX)) and (ints[i] = P[j].y)) then
if not InIntArray(indexes, j) then
begin
if up then
Result[i] := P[j]
else
Result[Hi-i] := P[j];
Inc(i);
if i > Hi then Exit;
indexes[i] := j;
j := -1;
end;
end;

{*******************************************************************************
function MiddleDoor(var P: TPointArray; var s: extended): TPoint;
By: lordsaturn
Description: Returns the slope and midpoint of a door. Returns -1 for slope if
the slope is infinite.
*******************************************************************************}
function MiddleDoor(P: TPointArray; var slope: extended): TPoint;
var
Hi, i, minX, maxX, minY, maxY: integer;
d, tD, PtX, PtY: extended;
begin
Hi := High(P);
if Hi < 0 then Exit;
if Hi = 0 then
begin
Result := P[0];
slope := 0;
Exit;
end;
RearrangeTPA(P, True, True);
minX := P[0].x;
maxX := P[Hi].x;
RearrangeTPA(P, False, True);
minY := P[0].y;
maxY := P[Hi].y;
SortTPAFrom(P, Point(minX, minY));
PtX := (minX+maxX)/2;
PtY := (minY+maxY)/2;
for i := 0 to Hi do
begin
tD := Sqrt(Sqr(P[i].x-PtX)+Sqr(P[i].y-PtY));
if (tD < d) or (i = 0) then
begin
Result := P[i];
d := tD;
end;
end;
try
slope := (maxY-minY)/(maxX-minX);
except
slope := -1;
end;
end;

{*******************************************************************************
function GetDoors: array of TDoorProfile;
By: lordsaturn
Description: Returns information about the doors on the minimap in an array of
TDoorProfile.
*******************************************************************************}
function GetDoors: array of TDoorProfile;
var
aP: T2DPointArray;
Hi, i, L: integer;
begin
try
Freeze;
aP := GetDoorPoints;
SortATPAFrom(aP, Point(MMCX, MMCY));
Hi := High(aP);
if Hi < 0 then Exit;
SetLength(Result, Hi+1);
for i := 0 to Hi do
begin
Result[i].Midpoint := MiddleDoor(aP[i], Result[i].Slope);
Result[i].Points := aP[i];
L := Length(aP[i]);
Result[i].PixelCount := L;
Result[i].Color := GetColor(aP[i][0].x, aP[i][0].y);
end;
finally
Unfreeze;
end;
end;

{*******************************************************************************
function GetDoorsIn(x1, y1, x2, y2: integer): array of TDoorProfile;
By: lordsaturn
Description: Returns information about the doors on a portion of the minimap in
an array of TDoorProfile.
*******************************************************************************}
function GetDoorsIn(x1, y1, x2, y2: integer): array of TDoorProfile;
var
d: array of TDoorProfile;
Hi, i, L: integer;
begin
d := GetDoors;
Hi := High(d);
if Hi < 0 then Exit;
SetLength(Result, Hi+1);
for i := 0 to Hi do
if InRange(d[i].MidPoint.x, x1, x2) and InRange(d[i].MidPoint.y, y1, y2) then
begin
Result[L] := d[i];
Inc(L);
end;
SetLength(Result, L);
end;

{*******************************************************************************
procedure SortDoorsFrom(var d: array of TDoorProfile; From: TPoint);
By: lordsaturn
Description: Sorts an array of TDoorProfile from a TPoint.
*******************************************************************************}
procedure SortDoorsFrom(var d: array of TDoorProfile; From: TPoint);
var
P: TPointArray;
clone: array of TDoorProfile;
i, j, L: integer;
begin
L := Length(d);
if L < 2 then Exit;
SetLength(clone, L);
clone := d;
SetLength(P, L);
for i := 0 to L-1 do
P[i] := clone[i].Midpoint;
SortTPAFrom(P, From);
for i := 0 to L-1 do
for j := 0 to L-1 do
if (P[i].x = clone[j].Midpoint.x) and (P[i].y = clone[j].Midpoint.y) then
d[i] := clone[j];
end;

{*******************************************************************************
procedure DebugDoors(doors: array of TDoorProfile);
By: lordsaturn
Description: Prints out all information for an array of TDoorProfile.
*******************************************************************************}
procedure DebugDoors(doors: array of TDoorProfile);
var
i, Hi: integer;
begin
Hi := High(doors);
for i := 0 to Hi do
begin
Writeln('Door Index #'+ToStr(i)+':');
Writeln('Color: '+ToStr(doors[i].Color));
Writeln('MidPoint: '+ToStr(doors[i].MidPoint));
Writeln('PixelCount: '+ToStr(doors[i].PixelCount));
Writeln('Points: '+ToStr(doors[i].Points));
Writeln('Slope: '+ToStr(doors[i].Slope));
Writeln('');
end;
end;

Boreas

2008-11-18 19:38:35

Looks pretty good, but it didn't get both of the doors in lumby chapel.

lordsaturn

2008-11-18 22:54:39

From: Boreas
Looks pretty good, but it didn't get both of the doors in lumby chapel.


Fixed, now it will.

Boreas

2008-11-19 16:34:34

Yup, works great. Nice job.

lordsaturn

2008-11-19 21:33:08

From: Boreas
Yup, works great. Nice job.


Thanks, it means a lot coming from you :D
But do you have any suggestions on how i could improve it? Or does anyone?


Btw, added a sorting function.

Boreas

2008-11-20 00:12:49

If it accomplishes its purpose, it doesn't need improving. It's been a long time, but from what I can remember, my checklist was something like this:

Return all the information anyone could possibly want about every door on the minimap
Do that faster than a human could spot all the doors (1-2 seconds?)
Work at any compass angle.
Be able to handle both door colors (horizontal/vertical and diagonal IIRC)
Not mistake drop dots for doors (full or partial [partial meaning partly covered by other dots or symbols]).

As long as it can do that, IMO it's all set to be committed.


I just realized, the one in SRL doesn't even compile, because someone replaced the SplitTPA I had in there with one in SCAR/plugin, but with different parameters :duh: I've been retired too long lol.

lordsaturn

2008-11-20 15:51:29

From: Boreas
If it accomplishes its purpose, it doesn't need improving. It's been a long time, but from what I can remember, my checklist was something like this:

Return all the information anyone could possibly want about every door on the minimap
Do that faster than a human could spot all the doors (1-2 seconds?)
Work at any compass angle.
Be able to handle both door colors (horizontal/vertical and diagonal IIRC)
Not mistake drop dots for doors (full or partial [partial meaning partly covered by other dots or symbols]).

As long as it can do that, IMO it's all set to be committed.


I just realized, the one in SRL doesn't even compile, because someone replaced the SplitTPA I had in there with one in SCAR/plugin, but with different parameters :duh: I've been retired too long lol.


Yes, my include meets all of the requirements on that checklist :)
And from my experiences, there is only one constant door color on the minimap. Is this incorrect?

Boreas

2008-11-20 23:11:01

Diagonal doors have a different color, but there aren't many of them.

ZephyrsFury

2008-11-20 23:22:59

From: Boreas
Diagonal doors have a different color, but there aren't many of them.


See wizard's tower ground floor. It used to be a constant 238.

lordsaturn

2008-11-22 00:23:21

From: ZephyrsFury
See wizard's tower ground floor. It used to be a constant 238.


I think it still is.
Alright, well I readded the GetDoorColors function because of reasons stated above.

lordsaturn

2008-12-01 01:09:43

Bump, small update.

Edit: Added function GetDoorsIn for getting doors in a portion of the minimap.

EvilChicken!

2009-02-04 11:15:49

Very nice, I committed this to the developer's SVN.
Does this work 100%? How well is it tested?

And, if you have any more addons to this, tell me.
Rep+ for you, btw ;)

Gu3st...

2009-02-04 18:02:50

From: EvilChicken!
Very nice, I committed this to the developer's SVN.
Does this work 100%? How well is it tested?

And, if you have any more addons to this, tell me.
Rep+ for you, btw ;)

Over 3 month old, but might still work..? :) Test it :D

Good job lordsaturn. ;)

lordsaturn

2009-02-04 20:16:54

I use it in my Tutorial Island Runner, it's in my siggy. It works perfectly, test it all you want. I promise it won't fail ;)

Edit: If anyone has any functions/ideas they'd like to see added to this, please let me know.

lordsaturn

2010-12-12 21:32:39

updated. If anyone has problems with this finding symbols, let me know and I will create a IsSymbol function.