Good day folks,
I wanted to explain and show my surfaces-system, which should be quite useful for finding objects accurately in RuneScape.
You might have seen it in action in my script Irony. So, to cut the chase, the basic part of a surface consists of the following
structure:
Simba Code:
type
TSurfacePart = record
// The filter function which ultimately decides which surface to pick up.
filter: TSurfacePartFilterFunc;
// Hue modifier.
hm: extened;
// Saturation modifier.
sm: extended;
// Color.
c: integer;
// Tolerance.
t: integer;
// Minimum width of the surface.
minw: integer;
// Maximum width of the surface.
maxw: integer;
// Minimum height of the surface.
minh: integer;
// Maximum height of the surface.
maxh: integer;
// Offset Y-axis, from the median.
off_y: integer;
// Offset X-axis, from the median.
off_x: integer;
// A simple TBox containing the bounds of the surface.
bounds: TBox;
// Pixel density / distance.
step: integer;
// Ignore, for internal use.
index: integer;
// The point where the surface was found.
p: TPoint;
// Ignore, for internal use.
base_atpa: T2DPointArray;
// Maximum distance allowed, where the surface can be found.
max_distance: integer;
end;
One of the useful things about the system is that you can define a surface object which
constructs out of multiple surfaces. This ensures great accuracy.
Maybe it's the best to demonstrate this through an example. Lets take an iron rock and try to detect it, closest to us
and as accurately as possible! First off, you need to define your surface variable for the rock itself. Not iron rock, but an
empty one instead! Lets call it..
Simba Code:
var
surface_rock: TSurfacePart;
Fantastic, now lets put there some values:
Simba Code:
// c, hm, sm and t can be neatly found with the wonderful ACA.
with surface_rock do begin
c := 3367539;
hm := 0.02;
sm := 0.07;
t := 16;
minw := 4; // At least 4 pixels wide.
maxw := 80; // No more than 80 pixels wide.
minh := 4; // At least 4 pixels tall.
maxh := 80; // No more than 80 pixel tall.
step := 9;
max_distance := 200;
end;
We can use now surface_rock as a base for all type of rocks, like iron, mithril and adamantite, since all of those has the same
looking rock when its empty or mined.
Now, lets define our iron rock surface object:
Simba Code:
var
obj_iron_rock: TSurfaceObject;
As explained above, we use the base surface for all type of rocks:
Simba Code:
// We need two different surfaces for iron rock. The rock and the brown part in middle of it.
// Remember, the consecutive parts has to be found inside the previous one.
CreateSurfaceParts(obj_iron_rock, 2);
with obj_iron_rock do begin
// So, the first part we copy:
parts[0] := CopySurfacePart(surface_rock);
// And then the second one, which is the brown part in iron rock when it's not mined yet.
// For mithril, you can use ACA for the blue-part, etc.
parts[1].c := 2831959;
parts[1].hm := 0.05;
parts[1].sm := 0.64;
parts[1].t := 10;
parts[1].filter := @SurfaceFilterClosest; // We want to have the closest iron rock next to us.
parts[1].minw := 1;
parts[1].maxw := parts[0].maxw;
parts[1].minh := 1;
parts[1].maxh := parts[0].maxh;
parts[1].step := 16;
parts[1].max_distance := parts[0].max_distance;
name := 'Iron ore';
uptext := 'Iron';
filter := @SurfaceFilterClosest;
end;
That's pretty much the basics. Now if you want to find an iron rock, you can simply call
Simba Code:
if FindSurfaceObject(obj_iron_rock, MSX1, MSY1, MSX2, MSY2) then begin
WriteLn('Found the iron rock!');
// Now you can click the iron rock, if you wish..
with obj_iron_rock do
Mouse(p.x, p.y, 2, 2, mouse_left);
end;
and you should get this:
If you want the system to automatically click it, you can call
Simba Code:
if ClickSurfaceObject(obj_iron_rock, true) then // False for left click through menu instead.
WriteLn('Clicked iron ore!');
You can download su_surfaces.simba, which contains all the necessary functions etc. To summarize, here's the actual script
which find you the iron ore:
Simba Code:
program surfaces;
{$DEFINE SMART}
{$i srl\srl.simba}
{$i srl\srl\misc\SmartGraphics.simba}
{$i su_surfaces.simba}
var
surface_rock: TSurfacePart;
obj_iron_rock: TSurfaceObject;
procedure Init();
begin
SetupSRL();
SMART_ClearMS();
with surface_rock do begin
c := 3367539;
hm := 0.02;
sm := 0.07;
t := 16;
minw := 4; // At least 4 pixels wide.
maxw := 80; // No more than 80 pixels wide.
minh := 4; // At least 4 pixels tall.
maxh := 80; // No more than 80 pixel tall.
step := 9;
max_distance := 200;
end;
CreateSurfaceParts(obj_iron_rock, 2);
with obj_iron_rock do begin
// So, the first part we copy:
parts[0] := CopySurfacePart(surface_rock);
// And then the second one, which is the brown part in iron rock when it's not mined yet.
parts[1].c := 2831959;
parts[1].hm := 0.05;
parts[1].sm := 0.64;
parts[1].t := 10;
parts[1].filter := @SurfaceFilterClosest; // We want to have the closest iron rock next to us.
parts[1].minw := 1;
parts[1].maxw := parts[0].maxw;
parts[1].minh := 1;
parts[1].maxh := parts[0].maxh;
parts[1].step := 16;
parts[1].max_distance := parts[0].max_distance;
name := 'Iron ore';
uptext := 'Iron';
filter := @SurfaceFilterClosest;
end;
end;
begin
Init();
if FindSurfaceObject(obj_iron_rock, MSX1, MSY1, MSX2, MSY2) then begin
WriteLn('Found the iron rock at ' + IntToStr(obj_iron_rock.p.x) + ', ' + IntToStr(obj_iron_rock.p.y));
end;
end.
There's still more to the surfaces, but this'll get you started. Please shoot if you have any guestions.
Edit:
Just a curious thought, but it would be possible to create huge database of various objects (surfaces) of RuneScape. Now
wouldn't that be nice, eh?
All the best,
superuser