SRL Archive - SRL Positioning System

Rotated SPS a simple attempt


Ixilisi

2012-05-01 05:22:11

Updates:
Thanks to Wizzup I worked out some of the problems. It works for me when on 90 degree angles on the surface and I think it is because of lines not being straight when at different angles, possibly. Anyhow I will try to think of a way of fixing that, perhaps SPS_accuracy should be higher/lower.

ToDo:
A failsafe, incase it can't find the point, to rotate it North and try again. - Easy to do.
More testing of all the SPS functions, I have a feeling I left some bad useless code lying around somewhere in there.
More testing of it in general
Get it to work at any angle (Maybe Anti-aliasing may be needed)

If your testing it and getting compile errors for SPS you're doing it wrong, find a script that uses SPS (like the MSI scripts)

I had a look at the ToDo file on SPS and being able to have SPS while the minimap was rotated was one of them, Thus I have attempted to make SPS work while rotated. I haven't tested this yet, and it's a very basic thing that relies upon the accuracy of rs_getCompassAngleRadians

Hope it works, test it out, report back.
Any changes made should have "NEW_STUFF" written close to it, so you can see what I have done,so just ctrl + F for it.

Based off Coh3n's SPS2 so test with scripts that worked with sps2.

I know that it may look slightly ugly with a long line where there is a rotation, but I didn't think it was necessary to assign another variable to be used only once.

To test backup your \Simba\Includes\SPS\sps.simba and put my one there instead.

I don't have much time to script which is why this little one was good for me to do, point out any other fixes or todo's for includes etc and I will try to do it.

Officially this is my first modification of a script (wouldn't call it a script since most of it isn't mine).


(*
SPS ~ SRL Positioning System
============================

Concept and original work done by marpis @ SRL-Forums.


###IxilisI###
Search for NEW_STUFF to see entries I have Added
Search for CHANGEHERE to see things I need to investigate/change/rotate.
One problem may be that if it is currently rotating while
####
*)

{$loadlib sps}

const
// Path where all the SPS files are
SPS_IMG_PATH = IncludePath + 'SPS\img\';
SPS_IMG_FMT = '.png';



// Surfaces
RUNESCAPE_SURFACE = 0;
RUNESCAPE_SURFACE_FOLDER = 'runescape_surface\';

RUNESCAPE_OTHER = 1;
RUNESCAPE_OTHER_FOLDER = 'runescape_other\';

// SPS Global variables
var
SPS_Debug, SPS_MultiMouse: boolean;
SPS_Areas: TStringArray;
SPS_AreaMaps: T3DIntegerArray; // Grids of the combined SPS_Areas
SPS_Tolerance, SPS_MatchesPercent: extended;
SPS_Accuracy: integer; // Splits minimap/areas into squares of this side length; used for area recognition




// Returns an image of the minimap in a TMufasaBitmap
function SPS_GatherMinimap: TMufasaBitmap;
var
c: TClient; bCopy: TMufasaBitmap;
//NEW_STUFF Rotates Bitmap to the negative angle
begin
try

bCopy := TMufasaBitmap.create;
bCopy.SetSize(150, 150);

Result := TMufasaBitmap.Create;
Result.SetSize(150, 150);

c := getTClient;

Result.CopyClientToBitmap(c.IOManager, false, 0, 0, MMCX-75, MMCY-75, MMCX+75, MMCY+75);
Result.RotateBitmap(-rs_GetCompassAngleRadians,bCopy);

Result.Free;

Result := bCopy;
//DrawBitmapDebugImg(Result);
//DisplayDebugImgWindow(150, 150);
except
Writeln('SPS_GatherMinimap ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;

// Gets the starting area coordinates depending on the area image
procedure SPS_GetAreaCoords(Area: string; var x, y: integer);
var
p: integer;
begin
// if it's a specific dungeon map (i.e. name isn't 0_0, 10_2, etc.)
if (length(getNumbers(Area)) < 2) then
begin
x := 0;
y := 0;
Exit;
end;

p := pos('_', Area);

x := StrToIntDef(copy(Area, 1, p - 1), -1);
y := StrToIntDef(copy(Area, p + 1, Length(Area) - p), -1);

//writeln('SPS_GetAreaCoords: '+toStr(point(x, y)));
end;

// Converts a point from a map piece to a point on the entire map
function SPS_LocalToGlobal(Area: string; x, y: integer): TPoint;
var
cx, cy: integer;
begin
SPS_GetAreaCoords(Area, cx, cy);
Result.x := (cx * 400) + x;
Result.y := (cy * 400) + y;
end;

// Converts a point from the entire map to a point on the main screen
function SPS_GlobalToLocal(x, y: integer): TPoint;
var
cx, cy: integer;
begin
cx := Floor(x / 400);
cy := Floor(y / 400);

Result.x := x - (cx * 400);
Result.y := y - (cy * 400);
end;

// Returns the coordinates (x, y) in the form of a string
function SPS_AreaCoordsToString(x, y: integer): string;
begin
Result := IntToStr(x)+'_'+IntToStr(y);
end;

// Author: Coh3n
// Returns a TPA of the areas' values
function SPS_TPAFromAreas(areas: TStringArray): TPointArray;
var
i: integer;
begin
setLength(result, length(areas));

for i := 0 to high(areas) do
SPS_GetAreaCoords(areas[i], result[i].x, result[i].y);
end;

// Author: Coh3n
// Sorts the areas by columns, and sorts each column by rows
// Example: ['1_5', '1_3', '0_5'] results ['0_5', '1_3', '1_5']
function SPS_SortAreas(areas: TStringArray): TStringArray;
var
i, j: integer;
tpa: TPointArray;
begin
setLength(tpa, length(areas));

tpa := SPS_TPAFromAreas(areas);
clearDoubleTPA(tpa);

sortTPAByX(tpa, true); // first sort by column number

// then sort the Y values for each column number
for i := 0 to high(tpa) do
for j := i to high(tpa) do
if (tpa[i].x = tpa[j].x) then
if (tpa[i].y > tpa[j].y) then
tSwap(tpa[i], tpa[j]);

setLength(result, length(tpa));

for i := 0 to high(tpa) do
result[i] := SPS_AreaCoordsToString(tpa[i].x, tpa[i].y);

//writeln('SPS_SortAreas: '+toStr(result));
end;

// Loads the "Area" image
function SPS_GetArea(Area: string; surface: integer): TMufasaBitmap;
var
x, y: integer;
S: string;
begin
SPS_GetAreaCoords(Area, x, y);

case surface of
RUNESCAPE_SURFACE: s := RUNESCAPE_SURFACE_FOLDER;
RUNESCAPE_OTHER: s := RUNESCAPE_OTHER_FOLDER;
end;

try
Result := TMufasaBitmap.Create;
Result.LoadFromFile(SPS_IMG_PATH + s + Area + SPS_IMG_FMT);
except
Writeln('SPS_GetArea ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;

// Author: Coh3n
// Merges the SPS 'areas' into one bitmap (makes more more accurate GetMyPos)
function SPS_MergeAreas(areas: TStringArray): TMufasaBitmap;
var
t, i, l, x, y, diffX, diffY, newWidth, newHeight: integer;
startPoint: TPoint;
newAreas: TStringArray;
xVals, yVals: TIntegerArray;
bmpTemp: TMufasaBitmap;
tmpTPA: TPointArray;
begin
if (length(areas) <= 0) then
exit;

t := getSystemTime();

// sort the areas from by columns/rows; remove duplicates
newAreas := SPS_SortAreas(areas);
l := length(newAreas);

// if there's only one area in the array
if (l = 1) then
begin
result := SPS_GetArea(areas[0], RUNESCAPE_SURFACE);
exit;
end;

// get the x and y values for each area
setLength(xVals, l);
setLength(yVals, l);

for i := 0 to high(newAreas) do
SPS_GetAreaCoords(newAreas[i], xVals[i], yVals[i]);

// get the lowest Y value so we can calculate the starting point to draw the first image
tmpTPA := SPS_TPAFromAreas(newAreas);
sortTPAByY(tmpTPA, true);

try
result := TMufasaBitmap.create();

// calculate the starting point
// x is always 0 because of how the areas are sorted
// y is relative to the lowest y value in the areas
SPS_GetAreaCoords(newAreas[0], x, y);
startPoint.x := 0;
startPoint.y := ((y - tmpTPA[0].y) * 400);

// draw the first area to the starting point on the bitmap
bmpTemp := SPS_GetArea(newAreas[0], RUNESCAPE_SURFACE);
result.SetSize(bmpTemp.width, bmpTemp.height + startPoint.y);
bmpTemp.fastDrawTransparent(startPoint.x, startPoint.y, result);
bmpTemp.free();

// loop through each area, drawing them to the result bitmap
// coordinates are calculated relative to the first area drawn (areas[0])
for i := 0 to (l - 2) do
begin
diffX := (xVals[i + 1] - xVals[0]);
diffY := (yVals[i + 1] - yVals[0]);

newWidth := 500 + (round(abs(diffX)) * 400);
newHeight := 500 + (round(abs(diffY)) * 400);

// only set the size if the width or height is increasing
if (newWidth > result.width) then
result.setSize(newWidth, result.height);

if (newHeight > result.height) then
result.setSize(result.width, newHeight);

// copy the area image to the resulting bitmap
bmpTemp := SPS_GetArea(newAreas[i + 1], RUNESCAPE_SURFACE);
bmpTemp.fastDrawTransparent(startPoint.x + (diffX * 400 + 1),
startPoint.y + (diffY * 400 + 1), result);
bmpTemp.free();
end;

//result.saveToFile('C:/Simba/test.bmp');
except
Writeln('SPS_MergeAreas ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;

if (SPS_Debug) then
writeln('SPS_MergeAreas: Merged areas in '+toStr(getSystemTime - t)+' ms.');
end;

// Author: Coh3n
// Returns an SPS area of lowest x and y value. Used for calculating the
// player's correct position
function SPS_GetTopLeftCoords(areas: TStringArray): string;
var
tpa: TPointArray;
begin
tpa := SPS_TPAFromAreas(areas);

if (length(tpa) <= 0) then
begin
result := '0_0';
exit;
end;

sortTPAByX(tpa, true);
result := toStr(tpa[0].x);

sortTPAByY(tpa, true);
result := result + '_'+toStr(tpa[0].y);

//writeln('SPS_GetTopLeftCoords: '+result);
end;

// SPS2


function SPS_GetMyPos(): TPoint;
var
Minimap: TMufasaBitmap;
SmallMap: T3DIntegerArray;
t, FoundMatches: integer;
P: TPoint;
Searches: extended;
begin
Result := Point(-1, -1);

if (not LoggedIn) then
Exit;

if (SPS_Tolerance < 1.0) then
SPS_Tolerance := 600.0;

if (SPS_MatchesPercent = 0.0) then
SPS_MatchesPercent := 0.35;

//NEW_STUFF - Removed stuff below - Shouldn't be required any more
{ if (inRange(round(rs_GetCompassAngleDegrees), 10, 350)) then
MakeCompass('N'); }

t := getSystemTime();

Minimap := SPS_GatherMinimap;
SPS_FilterMinimap(Minimap);
//DrawBitmapDebugImg(Minimap.Index);
//DisplayDebugImgWindow(150, 150);
SmallMap := [];
SmallMap := SPS_BitmapToMap(Minimap, SPS_Accuracy);

FoundMatches := SPS_FindMapInMap(P.x, P.y, SPS_AreaMaps, SmallMap, SPS_Tolerance);
Searches := ((Minimap.Width / SPS_Accuracy) * (Minimap.Height / SPS_Accuracy));
{
writeln('fx: '+toStr(p.x)+' ~ on area: '+toStr(P.X * SPS_Accuracy + (Minimap.Width / 2)));
writeln('fy: '+toStr(p.y)+' ~ on area: '+toStr(P.Y * SPS_Accuracy + (Minimap.Width / 2)));
writeln('matches: '+toStr(foundMatches));
writeln('searches: '+toStr(searches));
writeln('percent: '+toStr(FoundMatches / Searches));
}


if ((FoundMatches / Searches) > SPS_MatchesPercent) then
Result := SPS_LocalToGlobal(SPS_GetTopLeftCoords(SPS_Areas), // the top left of the total area
P.x * SPS_Accuracy + (Minimap.Width / 2),
P.y * SPS_Accuracy + (Minimap.Width / 2));

Minimap.Free;

t := (GetSystemTime - t);
if (SPS_Debug) then
Writeln('SPS_GetMyPos: Finished in '+ToStr(t)+' ms. Result = '+ToStr(Result));
end;


// Finds position P in minimap by checking your own location
function SPS_PosToMM(P: TPoint): TPoint; //changehere????
var
MyPos: TPoint;
begin
if not LoggedIn then
Exit;

Result := Point(-1, -1);
MyPos := SPS_GetMyPos;

if (Distance(MyPos.X, MyPos.Y, P.X, P.Y) < 75) then
Result := Point(MMCX + P.X - MyPos.X, MMCY + P.Y - MyPos.Y);
end;


// Walks to position, P.
function SPS_WalkToPos(P: TPoint): boolean;
var
MM: TPoint;
begin
if not LoggedIn then
Exit;

MM := SPS_PosToMM(P);

if (MM.X > 0) then
begin
if (SPS_MultiMouse) then
MultiMouse(MM.X, MM.Y, 25, 3, false)
else
Mouse(MM.X, MM.Y, 0, 0, mouse_Left);

if WaitFunc(@IsMoving, 1, 3000 + random(500)) then
while IsMoving do
Flag;

Result := True;
end;
end;

// Returns true if the point "Pt" is on the minimap
function SPS_PosOnMM(Pt: TPoint): Boolean;
var
p: TPoint;
begin
p := SPS_PosToMM(Pt);
Result := rs_OnMinimap(p.x, p.y);
end;

// Walks the path "Path"; always walks to the furthest point possible
function SPS_WalkPath(Path: TPointArray): boolean;
var
I, H, T, D: integer;
P, MM: TPoint;
A: Extended;
begin
H := High(Path);
T := GetSystemTime + 20000 + Random(5000);

while (not Result) and (GetSystemTime < T) do
begin
RunEnergy(20);

P := SPS_GetMyPos;
for I := H downto 0 do
begin

A := -rs_GetCompassAngleRadians; //NEW_STUFF
MM.X := Round(MMCX + ((Path[I].X - P.X)*cos(A))-((Path[I].Y - P.Y)*sin(A))); //MMCX + Path[I].X - P.X;
MM.Y := Round(MMCY + ((Path[I].X - P.X)*sin(A))+((Path[I].Y - P.Y)*cos(A))); //MMCY + Path[I].Y - P.Y;

D := Distance(MM.X, MM.Y, MMCX, MMCY);

if (D < 10) then
break
else
if (D < 70) then
begin
if (SPS_MultiMouse) then
MultiMouse(MM.X, MM.Y, 25, 3, false)
else
Mouse(MM.X, MM.Y, 5, 5, mouse_Left);

FFlag(Integer(I <> H) * 15);

T := getSystemTime + 20000 + Random(1000);
Break;
end;
end;

Result := (I = H);
end;
end;


// Walks blindly from the player's current position to the point T
function SPS_BlindWalk(P: TPoint): Boolean;
var
Tries: Integer;
M: TPoint;
ctrlPoints: TPointArray;
begin
repeat
M := SPS_GetMyPos;

if (Length(ctrlPoints) = 0) then
ctrlPoints := TPABetweenPoints(Point(M.X, M.Y), RotatePoint(Point(P.X, P.Y), rs_GetCompassAngleRadians, MMCX, MMCY), 20 + Random(15), 10);

Inc(Tries);
if (Tries > 20) then
Exit;

Result := SPS_WalkPath(ctrlPoints);
until(Result);
end;


// Sets up SPS; needs to be called if you want to switch RS surfaces
function SPS_Setup(surface: integer; areas: TStringArray): boolean;
var
t: integer;
tmp: TMufasaBitmap;
begin
t := getSystemTime;

SPS_MultiMouse := true;
SPS_Accuracy := 4;

if (length(areas) > 0) then
begin
if (surface = RUNESCAPE_SURFACE) then
tmp := SPS_MergeAreas(areas) // combine the SPS areas into 1; makes for a more accurate read
else
if (surface = RUNESCAPE_OTHER) then
if (length(areas) = 1) then
tmp := SPS_GetArea(areas[0], surface)
else begin
writeln('SPS_Setup(): Invalid dungeon areas. You can only select one!');
exit;
end;

result := true;
SPS_AreaMaps := SPS_BitmapToMap(tmp, SPS_Accuracy);
SPS_Areas := SPS_SortAreas(areas);
tmp.free();

end else
writeln('SPS_Setup(): ERROR: SPS areas are not set!');

t := (getSystemTime - t);

if (SPS_Debug) and (result) then
writeln('[SPS] SPS_Setup() took '+toStr(t)+' ms. Areas: '+toStr(SPS_Areas));
end;

I keep the attached file + copied text above up to date with the last working version, if I have split ideas I will attach more files

Sir Ducksworthy

2012-05-01 06:22:47

Kool, seem's like it could work I'll give it a go
Edit: Ok….. well it doesnt even compile lol good try tho.


// Returns an image of the minimap in a TMufasaBitmap
function SPS_GatherMinimap: TMufasaBitmap;
var
c: TClient;
begin
try

Result := TMufasaBitmap.Create;
Result.SetSize(150, 150);
Result = RotateBitmap(Result, -rs_GetCompassAngleDegrees()); //NEW_STUFF Rotates Bitmap to the negative angle
c := getTClient;

Result.CopyClientToBitmap(
c.IOManager, false, 0, 0, MMCX-75, MMCY-75, MMCX+75, MMCY+75
);

except
Writeln('SPS_GatherMinimap ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;

Also this doesn't actually do anything being modified since this is only capturing an image of your minimap.

Ixilisi

2012-05-01 07:12:14

Thats original code, but with the
Result = RotateBitmap(Result, -rs_GetCompassAngleDegrees());
Which is just meant to rotate the map to a North orientation
Is there meant to be () after rs_getCompassAngleDegrees? I looked for an example and didn't find () after it, but it is a function rather than a procedure…. so?

Ahh I see what you mean now, it should be something like:


// Returns an image of the minimap in a TMufasaBitmap
function SPS_GatherMinimap: TMufasaBitmap;
var
c: TClient;
begin
try

Result := TMufasaBitmap.Create;
Result.SetSize(150, 150);

c := getTClient;

Result.RotateBitmap(
CopyClientToBitmap(c.IOManager, false, 0, 0, MMCX-75, MMCY-75, MMCX+75, MMCY+75),
-rs_GetCompassAngleDegrees); //Over here instead

except
Writeln('SPS_GatherMinimap ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;

Ixilisi

2012-05-01 08:47:04

From: leetsxc

Ok….. well it doesnt even compile lol good try tho.


It can't compile without the srl include stated above it, but since it is an include this is not in the actual file.

Find a script that uses SPS 2.0, for walking and backup first and then replace your include file, eg back up /simba/include/sps/sps.simba, and then replace that with this file. Run & compile a normal script that uses SPS (MSI I believe uses SPS 2.0)

Please note I am looking for bugs specific to this version, so if it worked in SPS 1.0 but not SPS 2.0 telling me about these bugs are not very useful.
Get something that worked with SPS 2.0 and now is having problems

Sir Ducksworthy

2012-05-01 08:50:39

No, I have the includes and loaded it with the SRL Includes.

Ixilisi

2012-05-01 09:11:08

hmmm…. What's it saying the problem is when compiling?

putonajonny

2012-05-01 10:44:53

What your minimap is showing is a rotated version of the map, to whatever angle you are looking at, if you rotate it back it won't look perfect due to the amount of pixels shown, however if you rotate the SPS maps, they should look much more like what you see on your minimap, just saying… :)

Edit:
if you are going to try this you need to edit out the part where it rotates the minimap to north

Ixilisi

2012-05-02 06:52:30

From: putonajonny
What your minimap is showing is a rotated version of the map, to whatever angle you are looking at, if you rotate it back it won't look perfect due to the amount of pixels shown, however if you rotate the SPS maps, they should look much more like what you see on your minimap, just saying… :)

Edit:
if you are going to try this you need to edit out the part where it rotates the minimap to north


Are you suggesting that instead of rotating the captured bitmap from the clients screen to find a match, that rotating the larger conjoined bitmaps would be better?

I would've thought it would be just as effective either way, and quicker to do it for the smaller minimap image. But if the larger bitmaps are of a higher resolution then it probably is more effective.

If anyone can test it this way at various angles then we can assess whether this method works at all. Apparently just compiling it is having problems, but I can't see where this would come from.

Mat

2012-05-03 10:28:57

Didn't work for me nice going tho I would love to see this working some time :)
E:Only way i found to make it work, is if you make the map the rotation you want and making the map in that style then, removing the makecompass('n'); part but kinda defeats the objective of this thread.

Ixilisi

2012-05-05 08:59:00

I have updated it, file is in the first post, It now works for me reasonably well on North South East and West. I somehow need to fix it so the lines that become all jagged are either blurred (through use of Anti-Aliasing I suppose) or are somehow straightened (Would require some thought as to how to do that!)

Mat

2012-05-05 10:21:45

Now That is Sick.
The Walking is just as fast I'm loving this, very nice <3
Thank you <3
Mat

Ixilisi

2012-05-05 19:00:57

Just need to get it to work on any angle now :P Thanks for testing it!

Justin

2012-05-12 11:23:37

This looks very interesting, will give this a test

dweg

2012-05-12 11:31:13

good stuff. love the fact you're attempting to do this.

here's a suggestion to the simba devs: add png support. with png we can edit the map to just have the main paths (maybe like 2-3 pixels long?) with the surrounding colors, and the stuff that shifts with minimap rotation be an aplha channel. this would be extremely effective in terms of world positioning, but this would be horrible in terms of speed and efficiency. again, just a thought.

Ixilisi

2012-05-12 20:42:54

Im very busy now with school stuff, but when I have more time, I'll try to get it working on all angles

Ixilisi

2012-11-28 04:00:49

Okay Im back and Im going to have a relook over this very today hopefully

Flight

2012-11-28 04:19:58

I'm looking forward to that. :) I updated it with SPS 2 as far as I could and it works within 10 degrees of all N/S/E/W camera angles, but more than that and it simply doesn't find any matches.

Ixilisi

2012-11-28 04:35:50

Is SPS 2.0 currently included in the auto updater, or do I need to get in manually because it hasn't been fully released? I have been away for quite some time :P

Flight

2012-11-28 08:24:36

From: Ixilisi
Is SPS 2.0 currently included in the auto updater, or do I need to get in manually because it hasn't been fully released? I have been away for quite some time :P


I believe it's supposed to be, but personally my Simba is having issues with the auto-updater for SPS specifically. I wouldn't know the full story on it; I'd just recommend dropping Coh3n a line and asking him.

Coh3n

2012-11-28 08:59:53

SPS 2 should be in the updater, yes. It hasn't been updated for quite some time, Flight (at least not by me, Wizzup? is the only other one who can commit), so if you've downloaded within the last few months, you probably have the latest version.

E: I have, however, updated the map pieces locally (to include the new RS areas) and posted them somewhere for testing, but I don't think anyone actually tested them, so SPS still uses the old map.

If someone wants to test the new ones, they can post here or PM me. Keep in the mind the SPS points for the current map will be slightly off for the new map (because of new areas, etc.).

Ixilisi

2012-11-28 10:08:00

Well ill get it off Github just to make sure.
I think I know what the problem is. When rotating the image of the minimap, due to it being a bitmap the image is distorted, which is why perfect angles (90/180/270) appeared to work. So to fix this I would have to rotate both the map being compared and the minimap by a similar amount, or use vector graphics (which would be nicer but more difficult and I don't actually know how I would go about that)

I will take a look tomorrow and try to fix it up

footballjds

2012-11-28 12:00:51

keep it up man this looks promising! :)