nielsie95
05-04-2007, 04:25 PM
Hello and welcome to the tutorial:
Autocoloring for intermediates
With this tutorial you will hopefully learn how you automaticly get a color! :)
Chapters
SRL Autocoloring
Bitmaps
BruteForce
Unique facts
SRL AutoColoring
This is the most simple way to automaticly get a color for your script. I made you a list of all the functions. The names pretty much explain what they are for. The red colors are the map in where they can be found.
/core/AutoColor.scar
FindWaterColor
FindRoadColor
FindFallyRoadColor
FindRockColor
FindDirtRoadColor
FindBridgeColor
FindLadderColor
/core/DoorProfiles.scar
GetDoorColor;
Place specified:
/misc/DraynorColorFinder.scar
/misc/FaladorColorFinder.scar
/misc/MiscellaneousColorFinder.scar
/misc/VarrockWestColorFinder.scar
How to use:
This is how you use the SRL autocolor functions in your script:
procedure WalkToWater;
var Water: integer; //All colors are integers!
begin
Water := FindWaterColor; //Now the variable water contains the WaterColor
if FindColorSpiral(x, y, Water, MMX1, MMY1, MMX2, MMY2) then //You DONT need tolerance if you've autocolored a color.
Mouse(x, y, 1, 1, True);
Flag;
end;
Bitmaps
Another way that's used a lot is using Bitmaps.
With this way you make a little bitmap and look for it. If the bitmap is found it will get the color from the TOP-LEFT corner of the bitmap. So make sure that the top-left of your bitmap contains the color you want.
Also make sure you dont use too big bitmaps, slices of 2*15 are most of the time more then enough.
SRL has also for bitmaps a nice autocolor function: AutoColorThis.
How to use:
Before you can find the bitmap, you have to declare the bitmap somewhere in your script or procedure!
procedure FindDockColor;
var DockColor, TheBitmap, MaxTolerance: integer;
begin
TheBitmap := BitmapFromString(33, 2, 'z78DA33713436333433192507' +
'01090001FF53CB'); //Declare the bitmap first!
MaxTolerance := 40;
DockColor := AutoColorThis(TheBitmap, MaxTolerance, MMX1, MMY1, MMX2, MMY2); //40 is the Maximal tolerance that can be used to find your bitmap.
WriteLn('DockColor: '+IntToStr(DockColor));
FreeBitmap(TheBitmap); /Be sure to release a bmp after use =]
end;
Bruteforce
Bruteforce is a hard way to autocolor. In this way all the colors on the minimap are being compared to set values. Most of the time these values are RGB (SRL autocoloring is based on this). What you need to do is: get a lot of colors from different world and convert these to RGB:
procedure ConvertColorToRGB(Color: integer);
begin
WriteLn('Red: '+IntTostr(Color mod 256)+' Green: '+IntToStr((Color / 256) mod 256)+' Blue: '+IntToStr((Color / 256) / 256));
end;
After you've done that, you only need to keep the highest and the lowest value of each color and fill it in:
function AutoColor:integer; //Based on Boreas GetLadderColor
var
TmpBmp,MyX,MyY:integer;
MyColor,TmpInt: integer;
MyCanvas:tcanvas;
TmpBool:boolean;
begin
TmpBmp:= BitmapFromString(100,90,'');
MyCanvas:=GetBitmapCanvas(TmpBmp);
CopyCanvas(GetClientCanvas,MyCanvas,598,39,698,129 ,0,0,100,90)
for MyY:=0 to 99 do
begin
for MyX:=0 to 89 do
begin
MyColor:= MyCanvas.pixels[MyX,MyY];
if ((MyColor/256) / 256) < {Biggest value of Blue}then
begin
if ((MyColor/256) mod 256) < {Biggest value of Green} then
begin
if ((MyColor/256) mod 256) > {Lowest value of Green} then
begin
if (MyColor mod 256) < {Biggest value of Red} then
begin
if (MyColor mod 256) > {Lowest value of Red}then
TmpBool:=true;
end;
end;
end;
end;
if TmpBool then break;
end;
if TmpBool then break;
end;
if TmpBool then result:=MyColor;
end;
This is an explanation of Tarajunky, how the SRL AutoColoring procedures work (thank Tara):
function FindWaterColor: Integer;
var
GC, a, l, TestColor, Red, Green, Blue : integer;
var
P:array of Tpoint;
begin
GC := 12095356; { <--- You put the 'Generic Color' here (median color value)}
Flag;
FindColorsSpiralTolerance(x, y, P, GC, MMX1, MMY1, MMX2, MMY2, 50); { <--- This grabs ALL the colors
as TPoints on the minimap that are within 50 tolerance of the GC and puts them in an array.
(This can be thousands of points!)}
l:=GetArrayLength(P);
for a:= 0 to l-1 do { <--- Takes each TPoint position in the array. }
begin
TestColor := GetColor(P[a].x, P[a].y); { <--- Grabs the color at the TPoint}
red := (TestColor mod 256); { <-- Splits the color}
green := ((TestColor / 256) mod 256);
blue := ((TestColor / 256) / 256);
if Green - Red <= 22 then if Green - Red >= 18 then { //Unique criteria for your color goes in
the next few lines. Usually comparisons between color components work best.
(R-G or G-B or R-B) In this case Green-Red ranges between a lower limit of 18
and and upper limit of 22}
if Blue - Red >= 55 then if Blue - Red <= 72 then
if Blue - Green >= 35 then if Blue - Green <= 52 then
if GetColor(P[a].x + 2, P[a].y + 2) = TestColor then { <--- Checks if matching color appears as
a block of uniform color}
if GetColor(P[a].x + 1, P[a].y + 1) = TestColor then
if GetColor(P[a].x, P[a].y + 2) = TestColor then
if GetColor(P[a].x + 2, P[a].y) = TestColor then
if GetColor(P[a].x, P[a].y + 1) = TestColor then
if GetColor(P[a].x + 1, P[a].y) = TestColor then
if GetColor(P[a].x + 2, P[a].y + 1) = TestColor then
if GetColor(P[a].x + 1, P[a].y + 2) = TestColor then
begin
Result := TestColor; { <--- Yep, it matched ALL criteria! Must be the correct color}
WaterColor := TestColor;
WriteLn('WaterColor = ' + IntToStr(TestColor));
Exit;
end;
end; { <--- Oops, wasn't your color, goes back and tests the next TPoint in the array}
WriteLn('Could not find Water Color!'); { <--- NONE of the Tpoints matched!}
Result := 0;
end;
Unique facts
This is probably the hardest, but maybe the best way to autocolor: use the unique facts of the color (and the place). These unique things you will have to find out yourself, but here are some examples:
Using the amount of the colors on the minimap:
program UniqueColorFinder;
{.Include SRL/SRL.SCAR}
const ReferenceColor = 1587244; // Refence color of the one we're looking for.
Tolerance = 15; // Tolerance added to the reference color.
Count = 30; // How much of these colors can be found on the MM.
Range = 15; // Range added to Count.
DebugCount = False; // Set to true to get / test your settings for above.
Color = 1191977; // Color you want to count / Usefull for finding the right settings for above.
type ColorMatch = Record
Color, Pixels: Integer;
end;
procedure WriteCount(Color: integer);
begin
WriteLn('Color: '+IntTostr(Color)+' Count: '+IntToStr(CountColor(Color, MMX1, MMY1, MMX2, MMY2)));
end;
function GetUniqueColor(var Color: integer; RefColor, Tol, HowManyOnMM, Range: integer): Boolean;
var
ColorArray: Array of ColorMatch;
Colors: Array of integer;
TempCount, TempCount2, TempColor, i, j: integer;
begin
SetArrayLength(Colors, 0);
for i := MMX1 to MMX2 do
for j := MMY1 to MMY2 do
if Rs_OnMinimap(i, j) then
begin
TempColor := GetColor(i, j);
if SimilarColors(RefColor, TempColor, Tol) then
begin
SetArrayLength(Colors, Length(Colors) +1);
Colors[(Length(Colors)) -1] := TempColor;
end
end
SetArrayLength(ColorArray, 0);
for i := 0 to Length(Colors) -1 do
begin
TempCount := CountColor(Colors[i], MMX1, MMY1, MMX2, MMY2);
if TempCount = HowManyOnMM then
begin
if Colors[i] > 0 then
begin
Color := Colors[i];
Result := True;
WriteLn('Found color with range 0');
Exit;
end
end else
begin
if Colors[i] > 0 then
begin
TempCount2 := HowManyOnMM - TempCount;
if TempCount2 < 0 then TempCount2 := TempCount - HowManyOnMM;
if (TempCount2 < Range) then
begin
SetArrayLength(ColorArray, Length(ColorArray) +1);
ColorArray[(Length(ColorArray)) -1].Color := Colors[i];
ColorArray[(Length(ColorArray)) -1].Pixels := TempCount2;
end
end;
end;
end;
if Length(ColorArray) = 1 then
begin
Color := ColorArray[0].Color;
Result := True;
WriteLn('Found color with range '+IntTostr(ColorArray[0].Pixels));
Exit;
end
try
begin
TempCount := Min(ColorArray[0].Pixels, ColorArray[1].Pixels)
for i := 1 to Length(ColorArray) -2 do TempCount := Min(TempCount, ColorArray[i +1].Pixels);
for i := 0 to Length(ColorArray) -1 do if TempCount = ColorArray[i].Pixels then
begin
Color := ColorArray[i].Color;
Result := True;
WriteLn('Found color with range '+IntTostr(ColorArray[i].Pixels));
Exit;
end
end
except
Result := False;
end;
if not Result then WriteLn('Unique Color NOT found! Please set it yourself.');
end;
var Color1: integer;
begin
SetupSRl;
ActivateClient;
if DebugCount then WriteCount(Color);
GetUniqueColor(Color1, ReferenceColor, Tolerance, Count, Range);
WriteLn('Color found: '+IntTostr(Color1));
end.
Using the length of the door (they are always 4 pixels long): (Tarajunky)
program FindDoorColor;
{.include SRL/SRL.scar}
var DoorColor:integer;
var ColorArray: array of integer;
Function CountArray:integer;
var TestColor,n:integer;
begin
TestColor:=GetColor(x,y);
For n:= 0 to 32 do
begin
if ColorArray[n]=TestColor then result:=result+1;
end;
end;
Function FindDoorColor:integer;
var a,b,i,j,n:integer;
begin
a:=MMX1;
b:=MMY1;
repeat;
a:=a+1;
repeat;
b:=b+1;
if FindColorTolerance(x,y,255,a,b,a,MMY2,10) then //Finds all similar DoorColors
begin
b:=y;
SetArrayLength(ColorArray,32);
n:=0;
for i:= 0 to 3 do
begin
for j:= 0 to 7 do
begin
ColorArray[n]:=GetColor(a+i,b-3+j); //Will get the colors around the found color to count the pixels
n:=n+1;
end;
end;
if CountArray=4 then //if there are exactly 4 pixels it's probably a door =]
begin
Result:=GetColor(x,y);
exit;
end;
end else b:=MMY2;
until b>=MMY2;
until a>=MMX2;
end;
begin
SetupSRL;
ActivateClient;
Doorcolor:=FindDoorColor;
end.
I hope this has helped you on your way to autocolor. I'm sorry if I was hard to follow on some parts, but English isn't my main language (which you may have guessed :p)
It's upto you now to make some nice autocolor functions! :)
Thanks for reading,
Nielsie95
Autocoloring for intermediates
With this tutorial you will hopefully learn how you automaticly get a color! :)
Chapters
SRL Autocoloring
Bitmaps
BruteForce
Unique facts
SRL AutoColoring
This is the most simple way to automaticly get a color for your script. I made you a list of all the functions. The names pretty much explain what they are for. The red colors are the map in where they can be found.
/core/AutoColor.scar
FindWaterColor
FindRoadColor
FindFallyRoadColor
FindRockColor
FindDirtRoadColor
FindBridgeColor
FindLadderColor
/core/DoorProfiles.scar
GetDoorColor;
Place specified:
/misc/DraynorColorFinder.scar
/misc/FaladorColorFinder.scar
/misc/MiscellaneousColorFinder.scar
/misc/VarrockWestColorFinder.scar
How to use:
This is how you use the SRL autocolor functions in your script:
procedure WalkToWater;
var Water: integer; //All colors are integers!
begin
Water := FindWaterColor; //Now the variable water contains the WaterColor
if FindColorSpiral(x, y, Water, MMX1, MMY1, MMX2, MMY2) then //You DONT need tolerance if you've autocolored a color.
Mouse(x, y, 1, 1, True);
Flag;
end;
Bitmaps
Another way that's used a lot is using Bitmaps.
With this way you make a little bitmap and look for it. If the bitmap is found it will get the color from the TOP-LEFT corner of the bitmap. So make sure that the top-left of your bitmap contains the color you want.
Also make sure you dont use too big bitmaps, slices of 2*15 are most of the time more then enough.
SRL has also for bitmaps a nice autocolor function: AutoColorThis.
How to use:
Before you can find the bitmap, you have to declare the bitmap somewhere in your script or procedure!
procedure FindDockColor;
var DockColor, TheBitmap, MaxTolerance: integer;
begin
TheBitmap := BitmapFromString(33, 2, 'z78DA33713436333433192507' +
'01090001FF53CB'); //Declare the bitmap first!
MaxTolerance := 40;
DockColor := AutoColorThis(TheBitmap, MaxTolerance, MMX1, MMY1, MMX2, MMY2); //40 is the Maximal tolerance that can be used to find your bitmap.
WriteLn('DockColor: '+IntToStr(DockColor));
FreeBitmap(TheBitmap); /Be sure to release a bmp after use =]
end;
Bruteforce
Bruteforce is a hard way to autocolor. In this way all the colors on the minimap are being compared to set values. Most of the time these values are RGB (SRL autocoloring is based on this). What you need to do is: get a lot of colors from different world and convert these to RGB:
procedure ConvertColorToRGB(Color: integer);
begin
WriteLn('Red: '+IntTostr(Color mod 256)+' Green: '+IntToStr((Color / 256) mod 256)+' Blue: '+IntToStr((Color / 256) / 256));
end;
After you've done that, you only need to keep the highest and the lowest value of each color and fill it in:
function AutoColor:integer; //Based on Boreas GetLadderColor
var
TmpBmp,MyX,MyY:integer;
MyColor,TmpInt: integer;
MyCanvas:tcanvas;
TmpBool:boolean;
begin
TmpBmp:= BitmapFromString(100,90,'');
MyCanvas:=GetBitmapCanvas(TmpBmp);
CopyCanvas(GetClientCanvas,MyCanvas,598,39,698,129 ,0,0,100,90)
for MyY:=0 to 99 do
begin
for MyX:=0 to 89 do
begin
MyColor:= MyCanvas.pixels[MyX,MyY];
if ((MyColor/256) / 256) < {Biggest value of Blue}then
begin
if ((MyColor/256) mod 256) < {Biggest value of Green} then
begin
if ((MyColor/256) mod 256) > {Lowest value of Green} then
begin
if (MyColor mod 256) < {Biggest value of Red} then
begin
if (MyColor mod 256) > {Lowest value of Red}then
TmpBool:=true;
end;
end;
end;
end;
if TmpBool then break;
end;
if TmpBool then break;
end;
if TmpBool then result:=MyColor;
end;
This is an explanation of Tarajunky, how the SRL AutoColoring procedures work (thank Tara):
function FindWaterColor: Integer;
var
GC, a, l, TestColor, Red, Green, Blue : integer;
var
P:array of Tpoint;
begin
GC := 12095356; { <--- You put the 'Generic Color' here (median color value)}
Flag;
FindColorsSpiralTolerance(x, y, P, GC, MMX1, MMY1, MMX2, MMY2, 50); { <--- This grabs ALL the colors
as TPoints on the minimap that are within 50 tolerance of the GC and puts them in an array.
(This can be thousands of points!)}
l:=GetArrayLength(P);
for a:= 0 to l-1 do { <--- Takes each TPoint position in the array. }
begin
TestColor := GetColor(P[a].x, P[a].y); { <--- Grabs the color at the TPoint}
red := (TestColor mod 256); { <-- Splits the color}
green := ((TestColor / 256) mod 256);
blue := ((TestColor / 256) / 256);
if Green - Red <= 22 then if Green - Red >= 18 then { //Unique criteria for your color goes in
the next few lines. Usually comparisons between color components work best.
(R-G or G-B or R-B) In this case Green-Red ranges between a lower limit of 18
and and upper limit of 22}
if Blue - Red >= 55 then if Blue - Red <= 72 then
if Blue - Green >= 35 then if Blue - Green <= 52 then
if GetColor(P[a].x + 2, P[a].y + 2) = TestColor then { <--- Checks if matching color appears as
a block of uniform color}
if GetColor(P[a].x + 1, P[a].y + 1) = TestColor then
if GetColor(P[a].x, P[a].y + 2) = TestColor then
if GetColor(P[a].x + 2, P[a].y) = TestColor then
if GetColor(P[a].x, P[a].y + 1) = TestColor then
if GetColor(P[a].x + 1, P[a].y) = TestColor then
if GetColor(P[a].x + 2, P[a].y + 1) = TestColor then
if GetColor(P[a].x + 1, P[a].y + 2) = TestColor then
begin
Result := TestColor; { <--- Yep, it matched ALL criteria! Must be the correct color}
WaterColor := TestColor;
WriteLn('WaterColor = ' + IntToStr(TestColor));
Exit;
end;
end; { <--- Oops, wasn't your color, goes back and tests the next TPoint in the array}
WriteLn('Could not find Water Color!'); { <--- NONE of the Tpoints matched!}
Result := 0;
end;
Unique facts
This is probably the hardest, but maybe the best way to autocolor: use the unique facts of the color (and the place). These unique things you will have to find out yourself, but here are some examples:
Using the amount of the colors on the minimap:
program UniqueColorFinder;
{.Include SRL/SRL.SCAR}
const ReferenceColor = 1587244; // Refence color of the one we're looking for.
Tolerance = 15; // Tolerance added to the reference color.
Count = 30; // How much of these colors can be found on the MM.
Range = 15; // Range added to Count.
DebugCount = False; // Set to true to get / test your settings for above.
Color = 1191977; // Color you want to count / Usefull for finding the right settings for above.
type ColorMatch = Record
Color, Pixels: Integer;
end;
procedure WriteCount(Color: integer);
begin
WriteLn('Color: '+IntTostr(Color)+' Count: '+IntToStr(CountColor(Color, MMX1, MMY1, MMX2, MMY2)));
end;
function GetUniqueColor(var Color: integer; RefColor, Tol, HowManyOnMM, Range: integer): Boolean;
var
ColorArray: Array of ColorMatch;
Colors: Array of integer;
TempCount, TempCount2, TempColor, i, j: integer;
begin
SetArrayLength(Colors, 0);
for i := MMX1 to MMX2 do
for j := MMY1 to MMY2 do
if Rs_OnMinimap(i, j) then
begin
TempColor := GetColor(i, j);
if SimilarColors(RefColor, TempColor, Tol) then
begin
SetArrayLength(Colors, Length(Colors) +1);
Colors[(Length(Colors)) -1] := TempColor;
end
end
SetArrayLength(ColorArray, 0);
for i := 0 to Length(Colors) -1 do
begin
TempCount := CountColor(Colors[i], MMX1, MMY1, MMX2, MMY2);
if TempCount = HowManyOnMM then
begin
if Colors[i] > 0 then
begin
Color := Colors[i];
Result := True;
WriteLn('Found color with range 0');
Exit;
end
end else
begin
if Colors[i] > 0 then
begin
TempCount2 := HowManyOnMM - TempCount;
if TempCount2 < 0 then TempCount2 := TempCount - HowManyOnMM;
if (TempCount2 < Range) then
begin
SetArrayLength(ColorArray, Length(ColorArray) +1);
ColorArray[(Length(ColorArray)) -1].Color := Colors[i];
ColorArray[(Length(ColorArray)) -1].Pixels := TempCount2;
end
end;
end;
end;
if Length(ColorArray) = 1 then
begin
Color := ColorArray[0].Color;
Result := True;
WriteLn('Found color with range '+IntTostr(ColorArray[0].Pixels));
Exit;
end
try
begin
TempCount := Min(ColorArray[0].Pixels, ColorArray[1].Pixels)
for i := 1 to Length(ColorArray) -2 do TempCount := Min(TempCount, ColorArray[i +1].Pixels);
for i := 0 to Length(ColorArray) -1 do if TempCount = ColorArray[i].Pixels then
begin
Color := ColorArray[i].Color;
Result := True;
WriteLn('Found color with range '+IntTostr(ColorArray[i].Pixels));
Exit;
end
end
except
Result := False;
end;
if not Result then WriteLn('Unique Color NOT found! Please set it yourself.');
end;
var Color1: integer;
begin
SetupSRl;
ActivateClient;
if DebugCount then WriteCount(Color);
GetUniqueColor(Color1, ReferenceColor, Tolerance, Count, Range);
WriteLn('Color found: '+IntTostr(Color1));
end.
Using the length of the door (they are always 4 pixels long): (Tarajunky)
program FindDoorColor;
{.include SRL/SRL.scar}
var DoorColor:integer;
var ColorArray: array of integer;
Function CountArray:integer;
var TestColor,n:integer;
begin
TestColor:=GetColor(x,y);
For n:= 0 to 32 do
begin
if ColorArray[n]=TestColor then result:=result+1;
end;
end;
Function FindDoorColor:integer;
var a,b,i,j,n:integer;
begin
a:=MMX1;
b:=MMY1;
repeat;
a:=a+1;
repeat;
b:=b+1;
if FindColorTolerance(x,y,255,a,b,a,MMY2,10) then //Finds all similar DoorColors
begin
b:=y;
SetArrayLength(ColorArray,32);
n:=0;
for i:= 0 to 3 do
begin
for j:= 0 to 7 do
begin
ColorArray[n]:=GetColor(a+i,b-3+j); //Will get the colors around the found color to count the pixels
n:=n+1;
end;
end;
if CountArray=4 then //if there are exactly 4 pixels it's probably a door =]
begin
Result:=GetColor(x,y);
exit;
end;
end else b:=MMY2;
until b>=MMY2;
until a>=MMX2;
end;
begin
SetupSRL;
ActivateClient;
Doorcolor:=FindDoorColor;
end.
I hope this has helped you on your way to autocolor. I'm sorry if I was hard to follow on some parts, but English isn't my main language (which you may have guessed :p)
It's upto you now to make some nice autocolor functions! :)
Thanks for reading,
Nielsie95