Simba Code:
(*
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;