Olly
2012-12-17 19:29:17
>> Video <<
From: Coh3n
Would love it if a few people could test this out. Worked for me getting going back and forth from GE bank and VE bank. Was using it at any compass angle and using the new maps.
For this to work at any compass angle, you need to set SPS_AnyAngle to true before you start walking.There were also 4 unnecessary SPS_GetMyPos calls so getting rid of those greatly increased the speed of SPS. I can increase the speed of SPS_BlinkWalk by 2 if I add a parameter to SPS_WalkPath; however, doing so will cause compiling errors with any script that calls SPS_WalkPath. My question is, does everyone use SPS_BlindWalk, or do the majority of people use SPS_WalkPath?
(*
SPS ~ SRL Positioning System
============================
Concept and original work done by marpis @ SRL-Forums. Work continued by Coh3n
and members of the SRL community.
*)
{$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\';
// User defined SPS global variables
var
SPS_Debug: boolean;
SPS_MultiMouse: boolean; // simulates a human like "spam-click" when walking
SPS_AnyAngle: boolean; // true = work at any angle; false = only north
SPS_ClickNorth: boolean; // call ClickNorth instead of MakeCompass to set the compass to north
// SPS Global variables
var
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
// Author: marpis & Coh3n
// 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.CopyClientToBitmap(
c.IOManager, false, 0, 0, MMCX-75, MMCY-75, MMCX+75, MMCY+75
);
except
Writeln('SPS_GatherMinimap ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;
// Author: Ollybest & J J
// gets the rotated RS minimap and rotates to face north
// needed for SPS to work at any compass angle
function SPS_RotateMinimap: TMufasaBitmap;
var
W, H, t: Integer;
mmBMP, rBMP: TMufasaBitmap;
MiddleBMP: TPoint;
begin
try
t := getSystemTime();
//gathering minimap
mmBMP := SPS_GatherMinimap;
//rotating minimap
rBMP := GetMufasaBitmap(RotateBitmap(mmBMP.index, 0-rs_GetCompassAngleRadians))
//getting the middle of the rotated bitmap
GetBitmapSize(rBMP.Index, W, H);
MiddleBMP := Point(W/2, H/2);
//creating the result by using a 74 radius around the centre
Result := rbmp.Copy(MiddleBMP.X-74, MiddleBMP.Y-74, MiddleBMP.X+74, MiddleBMP.Y+74);
mmBMP.free
rbmp.free
If SPS_Debug Then
Writeln('Rotating map took '+toStr(getSystemTime - t)+' ms.');
except
Writeln('SPS_RotateMinimap ERROR: '+ExceptionToString(ExceptionType, ExceptionParam));
end;
end;
// Author: marpis & Coh3n
// 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;
// Author: marpis
// 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;
// Author: marpis
// 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;
// Author: marpis
// 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;
// Author: Coh3n
// 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;
// Author: marpis & SRL Community
function SPS_GetMyPos(): TPoint;
var
Minimap: TMufasaBitmap;
SmallMap: T3DIntegerArray;
a, t, FoundMatches: integer;
P: TPoint;
Searches: extended;
begin
Result := Point(-1, -1);
if (length(SPS_Areas) <= 0) then
begin
writeln('ERROR: SPS areas not set');
exit;
end;
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;
a := round(rs_GetCompassAngleDegrees);
if (SPS_AnyAngle) and (inRange(a, 10, 350)) then
Minimap := SPS_RotateMinimap()
else begin
if (inRange(a, 10, 350)) then
if (SPS_ClickNorth) then
ClickNorth(SRL_ANGLE_HIGH)
else
MakeCompass('N');
Minimap := SPS_GatherMinimap();
end;
t := getSystemTime();
SPS_FilterMinimap(Minimap);
//DrawBitmapDebugImg(Minimap.Index);
//DisplayDebugImgWindow(150, 150);
{$IFDEF SIMBAMAJOR990}
SetLength(SmallMap, 0); // Using this instead of SmallMap := [];
SPS_BitmapToMap(Minimap, SPS_Accuracy, SmallMap);
{$ELSE}
SmallMap := [];
SmallMap := SPS_BitmapToMap(Minimap, SPS_Accuracy);
{$ENDIF}
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;
// Author: marpis
// Finds position P in minimap by checking your own location
function SPS_PosToMM(P: TPoint): TPoint;
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 := RotatePoint(Point(MMCX + P.X - MyPos.X, MMCY + P.Y - MyPos.Y), 0-rs_GetCompassAngleRadians, MMCX, MMCY);
end;
// Author: marpis
// 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;
// Author: marpis
// 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;
// Author: marpis & Coh3n
// Walks the path "Path"; always walks to the furthest point possible
function SPS_WalkPath(Path: TPointArray): boolean;
var
I, H, T, D, Fails: integer;
P, MM, MMF: TPoint;
begin
H := High(Path);
T := GetSystemTime + 20000 + Random(5000);
Fails := 0;
while (not Result) and (GetSystemTime < T) and (Fails < 5) do
begin
RunEnergy(20);
P := SPS_GetMyPos(); // for Lape, remove this call and pass player's pos as a parameter
for I := H downto 0 do
begin
MM := RotatePoint(Point(MMCX + Path[I].X - P.X, MMCY + Path[I].Y - P.Y),
0-rs_GetCompassAngleRadians, MMCX, MMCY);
if MM = MMF then
Inc(Fails);
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);
MMF := MM;
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), Point(P.X, P.Y), 20 + Random(15), 10);
Inc(Tries);
if (Tries > 20) then
Exit;
Result := SPS_WalkPath(ctrlPoints);
until(Result);
end;
// Author: Coh3n
// 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;
{$IFDEF SIMBAMAJOR990}
SPS_BitmapToMap(tmp, SPS_Accuracy, SPS_AreaMaps);
{$ELSE}
SPS_AreaMaps := SPS_BitmapToMap(tmp, SPS_Accuracy);
{$ENDIF}
if (surface = RUNESCAPE_SURFACE) then
SPS_Areas := SPS_SortAreas(areas)
else
if (surface = RUNESCAPE_OTHER) then
SPS_Areas := 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;
that accuracy