Updated first post with bold questions for step 2.
Printable View
Updated first post with bold questions for step 2.
I think naturally we should use INI because simba has INI functions and does not have XML functions. Even though I personally enjoy XML a lot more and I am sure many others would concur.
Edit: I think this would be a good opportunity to rewrite all symbol finding functions. I know in the past several alternatives have been offered (e.g. nielsie) but none have flourished.
e2: it is not viable to record symbol locations because they are random. thus symbols location detection should be independent from symbols, and if it so happens to find a symbol then we can narrow down the number of chunks that could be a possible match.
because of the random symbol location, perhaps if we find a symbol in one chunk we should also attribute the symbol to the chunks around it? the other option would be to only attribute the symbol to the chunk in which it was found while data collecting, and when recalling chunks when you have found a symbol, also check the chunks adjacent to the chunk with the symbol for a match. following me?
i understand this logic could be subject to change because i do not know how dependent our location detection will be upon symbols. perhaps (hopefully) not at all.
e3: the only exception to the above is the dungeon arrow, which i think is consistent with it's location on the map. please someone correct me if i'm wrong.
e4: reread your first post. "approximate symbol tiles" could work.
e5: i think that grabbing the symbols through pathmaker, then storing the tiles is a good plan. Then when calling upon the chunks that have that symbol, also include chunks say within 30 tiles of the symbol that was found.
Gotcha, INI it is then.
Yea the randomness of symbols is why they will be stripped out for the clean chunks. However if their approximate locations are recorded in an INI, at least we will know which chunks to give priority. Let's say that symbols can vary by as much as 10 tiles, if a symbol is within 10 tiles from the edge of the 25x25 tile chunk, then the adjacent chunk can also be given priority.
E: Re your E5. Yea now that I think about it the less real time processing the better. Removing symbols and dots is enough as it is.
That actually could work very well when there isn't a LastKnownPosition, or when the available symbols/trees/rocks/etc on the minimap are not enough to get a location. The symbols on the in-game world map don't move. In fact, the map in the reflection SVN for the PathMaker is almost exactly the same (I saw one symbol in the port sarim/draynor area slightly off). So if we make a text file with symbol tiles from the PathMaker, and make a reverse symbol finder that IDs all symbols on the in-game world map viewed at 100%, we could get a tile location purely based on symbols, without even using simplification algorithms. Of course it would only be used when all else fails as it takes forever to load.
Edit: Actually it's even easier than that, I didn't know about the map in map button by the zoom level.
Ignore this, the map in map is a much better way.
Code:program new;
//Make sure world map is at 100%
const //Fill in bounds for in-game world map.
WMX1 =
WMY1 =
WMX2 =
WMY2 =
//1600 pts out of 337,500
function WorldMapSymbols: array of TPointArray;
var
Grid: array of array of boolean;
i,i2,i3: integer;
Point, CenterPoint, NewPoint: Tpoint;
BlackTPA, SymbolTPA: TPointArray;
begin
//Make grid for world map
SetArrayLength(Grid, 750);
for i := 0 to 759 do
begin
SetArrayLength(Grid[i), 450);
end;
//Fill grid with black points
FindColors(BlackTPA, 65536, WMX1, WMY1, WMX2, WMY2);
for i := 0 to High(BlackTPA) do
begin
Grid[BlackTPA[i].x][BlackTPA[i].y] := true;
end;
for i := 0 to High(BlackTPA) do
begin
Point:=BlackTPA[i];
i2 := 0;
repeat
CenterPoint.x := Point.x+Round(7*Sin(Radians(i2)));
CenterPoint.y := Point.y+Round(7*Cos(Radians(i2)));
Score := 0;
i3 := 0;
repeat
TempPoint.x:= CenterPoint.x+Round(7*Sin(Radians(i3)));
TempPoint.y:= CenterPoint.y+Round(7*Cos(Radians(i3)));
if Grid[TempPoint.x][TempPoint.y] then
Score := Score + 1;
i3 := i3 + 9;
//In addition to score threshold below, if you are halfway
//around and have less than 10 hits, don't bother
if (i3 = 180) and (Score < 10) then
break;
until i3 = 360;
//Max score is 40, meaning CenterPoint is the center point
//of a symbol whos outline is not covered at all
//If you want, you can use a lower score threshold, but then
//check if you see the background color 12632256 at radius 6
//from CenterPoint probably every 10 degrees
//Using 20 for now
if Score > 20 then //CenterPoint is probably a symbol
SymbolTPA := CombineTPA(SymbolTPA,[CenterPoint]);
i2 := i2 + 9;
until i2=360;
end;
SetArrayLength(BlackTPA, 0);
SetArrayLength(Grid, 0);
//SymbolTPA now has the centerpoints of all the symbols
//
For i:= 0 to High(SymbolTPA) do
writeln(inttostr(SymbolTPA[i].x)+','+inttostr(SymbolTPA[i].y));
Note that we can't do shit before we can make real plugins to Simba, as now it's practically impossible. So many errors there.
Also, my method doesn't need a "cleaned" map, the RS worldmap with 100% zoom works fine.
I've tried practically everything and still I get the
because it looks like I really can't use 3D Integer arrays in an exported function. I am truly confused with all this.Code:[Error] (2:1): Unable to register function function Galileo_FindMapInMapExx(LargeMap, SmallMap: array of array of array of integer; var foundX, foundY: integer; SideLength: integer; tol: extended; MaxFails: integer): boolean; at line 1
No. That is not a solution. Like I said, it'll be investigated soon enough. ATM I don't have time.
Speaking of Simba, what's the best way to go about this?
1) Copy a piece of the client to a bitmap
2) Do color searches and set pixels on the bitmap
3)Load a second bitmap from a file, creating that file if it doesn't exist
---When creating a bitmap, is there a default color or do we have to fill it in?
4) Copy a TBox of pixels from first bitmap to second bitmap, except the clWhite (or whatever default color is) pixels in first bitmap
5) Free second bitmap and repeat steps 3-4 with the same first bitmap, but different TBoxes of the first bitmap and different second bitmaps
6) Assuming step 2 required setting the target, reset the target back to SMART. Also free first bitmap.
Code://Is this right?
MainBitmap := CreateBMP(128,128) //Create a bitmap 128x128
//Freeze; //Is this needed for CopyClientToBitmap?
//What is the command to do this?
CopyClientToBitmap(MainBitmap, 564, 21, 691, 148, 0, 0, 127, 127)
//Unfreeze;//Is this needed for CopyClientToBitmap?
//What is the command to do this?
SetTargetBitmap(MainBitmap);
//Do FindColorsTolerance etc on the MainBitmap
CollectDotsCTW; //needs to set pixels on MainBitmap
White out the symbols //needs to set pixels on MainBitmap
//end of setting pixels on MainBitmap
SetLength(CopiedChunks,1);
CopiedChunks[0] := Point(-1,-1);
for i:= 0 to 3 do
Skip := false;
for i2 := 0 to counter do
begin
if (Chunks[i].x = CopiedChunks[i2].x) and (Chunks[i].x = CopiedChunks[i2].x) then
begin
Skip := true;
break;
end;
end;
if not Skip then
begin
SetArrayLength(CopiedChunks, counter+1);
CopiedChunks[Counter] := Chunks[i];
Inc(Counter);
//How to Load bitmap? How to make a number 2 digits by padding 0 on the left if needed? ie CleanChunk03-48.bmp
ChunkBitmap := CreateBitmapFromFile(CTWPath+'CleanChunk'+Pad(2,inttostr(Chunks[i].x))+'-'+Pad(2,inttostr(Chunks[i].y))'+'.bmp');
//If this file does not exist, create it, and fill with clWhite if it isn't already. (clWhite is RGB 255,255,255 right?)
//How to do this while skipping pixels in box FragmentPixels in MainBitmap that are clWhite?
Copy from FragmentsPixels[i].x1, FragmentsPixels[i].y1, FragmentsPixels[i].x2 FragmentsPixels[i].y2 on MainBitmap
to FragmentsPos[i].x1, FragmentsPos[i].y1, FragmentsPos[i].x2, FragmentsPos[i].y2 on ChunkBitmap
end;
end;
//restore the target
end;
Thanks for that. Also thanks to Wizz and Ray for answering other questions.
_____________________________________
Step 2 alpha is pretty much done, just gotta make it compile with Simba and test symbol finding methods.
Simba Code:const
CTWBOn = false; //Make true to help out CTWB
color_Black = 65536;
CTWBPath = AppPath + 'CTWB\';
var
CircleOffsets: TPointArray;
//LordSaturn
{function }procedure CTWBCollectDots(Bitmap: integer);//: TPointArray;
var
SearchColors: TIntegerArray;
OtherColors: T2DIntegerArray;
i, j, Hi, x, y, leftDev, rightDev, L, LTop: Integer;
ATPA: T2DPointArray;
TPA, FoundColorsTPA: TPointArray;
begin //red white yellow
//Freeze;
SearchColors := [217, 188, 14869218, 12961221, 56797, 52428];
SetLength(OtherColors, 3);
OtherColors[0] := [3553023, 789758, 2105598, 395004, 237, 206, 65536, 217, 188]; //red
OtherColors[1] := [16711422, 15527148, 13816530, color_Black, 14869218, 12961221]; //white
OtherColors[2] := [1179390, 195836, 62965, 56797, 60909, 52428, color_Black]; //yellow
LTop := 999;
SetLength(Result, LTop);
for i := 0 to 5 do
begin
if FindColors(TPA, SearchColors[i], 14, 14, 113, 113) then
FoundColorsTPA := CombineTPA(FoundColorsTPA, TPA); //if one color is covered, we will find the other
if (i mod 2 = 1) then
begin
ATPA := TPAtoATPAEx(FoundColorsTPA, 1, 0);
Hi := High(ATPA);
for j := 0 to Hi do
begin
//if (GetColor(ATPA[j][0].x, ATPA[j][0].y+1) = color_Black) then //it is a dot
begin //begin finding the whole dot
leftDev := 0;
if (GetColor(ATPA[j][0].x-1, ATPA[j][0].y) = color_Black) then //finding the left bound of the dot
leftDev := -1
else
if (GetColor(ATPA[j][0].x-2, ATPA[j][0].y) = color_Black) then
leftDev := -2
else
if (GetColor(ATPA[j][0].x-1, ATPA[j][0].y) = 217) then
leftDev := -1;
rightDev := 0;
if (GetColor(ATPA[j][0].x+1, ATPA[j][0].y) = color_Black) then //finding the right bound of the dot
rightDev := 1
else
if (GetColor(ATPA[j][0].x+2, ATPA[j][0].y) = color_Black) then
rightDev := 2
else
if (GetColor(ATPA[j][0].x+1, ATPA[j][0].y) = 188) then
rightDev := 1;
for x := ATPA[j][0].x + leftDev to ATPA[j][0].x + rightDev do
for y := ATPA[j][0].y - 3 to ATPA[j][0].y + 1 do
begin
if ((x = ATPA[j][0].x + leftDev) and (y = ATPA[j][0].y - 3)) or //ignore 4 corners
((x = ATPA[j][0].x + leftDev) and (y = ATPA[j][0].y + 1)) or
((x = ATPA[j][0].x + rightDev) and (y = ATPA[j][0].y - 3)) or
((x = ATPA[j][0].x + rightDev) and (y = ATPA[j][0].y + 1)) then
Continue;
if InIntArray(OtherColors[i/2], GetColor(x, y)) then
begin
if (L = LTop) then
begin
LTop := LTop*2;
//SetLength(Result, LTop);
end;
FastSetPixel(Bitmap, x, y, 0); //Result[L] := Point(x, y);
Inc(L);
end;
end;
end;
end;
SetLength(FoundColorsTPA, 0);
end;
end;
//SetLength(Result, L);
//Unfreeze;
end;
//Determines whether TPoint has at least Threshold color_BlackPoints in radius 7 around it
function CTWBIsSymbolCenter (ThePoint: TPoint, Threshold: integer): boolean;
var
i, Score: integer;
begin
result := false;
//if point is near the edge of the bitmap, doing a GetColor 7 away will result in out of range
//also, we only care about circle edge points 14 pixels in from the edges, so skip it
if (ThePoint.x > 6) and (ThePoint.x < 122) and (ThePoint.y > 6) and (ThePoint.y < 122) then
exit;
Score := 0;
for i := 0 to 39 do
begin
if GetColor(ThePoint.x + CircleOffsets[i].x, ThePoint.y + CircleOffsets[i].y) = color_Black then
begin
Inc(Score);
if Score > Threshold then
begin
result := true;
exit;
end;
end;
end;
end;
procedure CTWBMakeClean(MyTile: TTile);
var
CAB: TBox; //CurrentAreaBox
Chunks, Corners, Corners2, BlackPixels, CircleCenters: TPointArray;
i, i2, counter, MainBitmap, ChunkBitmap, NewTarget, OldTarget: intger;
CircleSliceOffsets, CircleSliceWidths: array of integer;
TmpPoint: TPoint;
TmpString: String;
Skip: Boolean;
ChunksTiles, FragmentsTiles, FragmentsPixels, FragmentsPos: TBoxArray;
begin
//Get tile bounds of CurrentAreaBox
CAB := IntToBox(MyTile.x - 12, MyTile.y + 12, MyTile.x + 12, MyTile.y - 12);//Make sure this does not normalize
//CurrentAreaBox is spread over 1, 2, or 4 chunks, so these arrays are set to 4
//In these arrays, [0] corresponds to the chunk that the top left corner of CAB is in,
//[1] is top right, [2] is bottom left, [3] is bottom right. This defined in Corners
Corners := [Point(CAB.x1, CAB.y1), Point(CAB.x2, CAB.y1), Point(CAB.x1, CAB.y2), Point(CAB.x2, CAB.y2)];
SetArrayLength(Chunks, 4);
SetArrayLength(ChunksTiles, 4);
SetArrayLength(FragmentsTiles, 4);
SetArrayLength(FragmentsPixels, 4);
SetArrayLength(FragmentsPos, 4);
//Contains offsets between the center and 40 outline points of circle with raidus 7 (ie a symbol)
CircleOffsets := [Point(0, 7), Point(1, 7), Point(2, 7), Point(3, 6), Point(4, 6), Point(5, 5), Point(6, 4),
Point(6, 3), Point(7, 2), Point(7, 1), Point(7, 0), Point(7, -1), Point(7, -2), Point(6, -3), Point(6, -4),
Point(5, -5), Point(4, -6), Point(3, -6), Point(2, -7), Point(1, -7), Point(0, -7), Point(-1, -7), Point(-2, -7),
Point(-3, -6), Point(-4, -6), Point(-5, -5), Point(-6, -4), Point(-6, -3), Point(-7, -2), Point(-7, -1),
Point(-7, 0), Point(-7, 1), Point(-7, 2), Point(-6, 3), Point(-6, 4), Point(-5, 5), Point(-4, 6), Point(-3, 6),
Point(-2, 7), Point(-1, 7)];
CircleSliceOffsets := [-2, -4, -5, -6, -6, -7, -7, -7];
CircleSliceWidths := [5, 9, 11, 13, 13, 15, 15, 15];
//Using these conventions when working with tiles and pixels
//Pixels have 0,0 in the top left
//Tiles have 0,0 in the bottom left
//Chunks have 0,0 in the bottom left (the are 100x100 pixels, but they deliberately start and end on tiles so that no tile
//is spread over multiple chunks (25x25 tiles), therefore, they follow the tile convention)
//X1,Y1 is always top left, X2,Y2 is always bottom right
//For pixels, Y1 is lower than Y2. For tiles and chunks, Y2 is lower than Y1
for i:= 0 to 3) do
begin
//Find the Chunk that the corresponding corner of CAB is in
Chunks[i] := Point(((Corners[i].x-2044) div 25),((Corners[i].y-861) div 25));
//Find the tile bounds of that chunk
ChunksTiles[i] := IntToBox(2044+Chunks[i].x*25, 885+Chunks[i].y*25, 2068+Chunks[i].x*25, 861+Chunks[i].y*25);//No normalize
//These are the opposite corners of Corners
Corners2 := [Point(ChunksTiles[i].x2, ChunksTiles[i].y2), Point(ChunksTiles[i].x1, ChunksTiles[i].y2), Point(ChunksTiles
[i].x2, ChunksTiles[i].y1), Point(ChunksTiles[i].x1, ChunksTiles[i].y1)]; //yes normalize
//Find the intersection of the corresponding Corner of CAB and the opposite corner of the Chunk
//that contains the Corner of CAB. Also make X1 lower than X2, and Y1 higher than Y2 (tiles start from the bottom left)
FragmentsTiles[i] := IntToBox(Min(Corners[i].x,Corners2[i].x), Max(Corners[i].y,Corners2[i].y), Max(Corners[i].x,Corners2
[i].x), Min(Corners[i].y,Corners2[i].y);
//Find the pixel bounds (on MainBitmap) of thoses tiles
FragmentsPixels[i] := IntToBox(14+(FragmentsTiles[i].x1-(MyTile.x-12))*4, 14+((MyTile.y+12)-FragmentsTiles[i].y1)*4, 112-
((MyTile.x+12)-FragmentsTiles[i].x2)*4, 112-(FragmentsTiles[i].y2-(MyTile.y-12))*4);
//Find the pixel box in Chunk that fragment will be copied to
FragmentsPos := IntToBox((FragmentsTiles[i].x1-ChunksTiles[i].x1)*4, (ChunkTiles[i].y1-FragmentTiles[i].y1)*4,
(FragmentsTiles[i].x1-ChunksTiles[i].x1)*4 + (FragmentPixels[i].x2 - FragmentPixels[i].x1),
(ChunkTiles[i].y1-FragmentTiles[i].y1)*4 + (FragmentPixels[i].y2 - FragmentPixels[i].y1));
end;
MainBitmap := BitmapFromClient(564, 21, 691, 148,);
OldTarget := GetImageTarget;
SetTargetBitmap(MainBitmap);
NewTarget := GetImageTarget;
//0 out the dots
CTWBCollectDots(MainBitmap);
//0 out the symbols
FindColors(BlackPixels, color_Black, 0, 0, 113, 113);
for i := 0 to High(BlackPixels) do
begin
//Start-Checking if this pixel is a part of a circle we already know about
Skip := false;
for i2 := 0 to High(CircleCenters) do
begin
counter:= (BlackPixels[i].x-CircleCenters[i2].x)^2+(BlackPixels[i].y-CircleCenters[i2].y)^2)
if (counter < 54) and (counter >44) then
begin
Skip := true;
break;
end;
end;
//End-Checking if this pixel is a part of a circle we already know about
if not Skip then
begin
//Start- Hope the top 5 pixels of the symbol are uncovered
Score := 0;
if GetColor(BlackPixels[i].x+1, BlackPixels[i].y) = color_Black then
if GetColor(BlackPixels[i].x+2, BlackPixels[i].y) = color_Black then
if GetColor(BlackPixels[i].x+3, BlackPixels[i].y) = color_Black then
if GetColor(BlackPixels[i].x+4, BlackPixels[i].y) = color_Black then //pixel is top left of group horizontal 5
begin
TmpPoint := Point(BlackPixels[i].x+2, BlackPixels[i].y+7); //Center of possible circle;
if CTWBIsSymbolCenter(TmpPoint, 20) then //TmpPoint is probably the center of a symbol
begin
CircleCenters := CombineTPA(CircleCenters, [TmpPoint]);
Skip := true;
break;
end;
end;
//End- Hope the top 5 pixels of the symbol are uncovered
//Start- Bruteforce
if not Skip then
begin
for i2 := 0 to 39 do
begin
TmpPoint := (BlackPixels[i].x+CircleOffsets[i2].x,BlackPixels[i].y+CircleOffsets[i2].y);
if CTWBIsSymbolCenter(TmpPoint, 20) then
begin
CircleCenters := CombineTPA(CircleCenters, [TmpPoint]);
Skip := true;
break;
end;
end;
end;
//End- Bruteforce
end;
end;
//now 0 out the circles (and contents)
for i := 0 to High(CircleCenters) do
begin
for i2:= 0 to 7 do
for i3 := 0 to CircleSliceWidths[i2] do
begin
FastSetPixel(MainBitmap, 0, CircleCenter[i].x + CircleSliceOffsets[i2] + i3, CircleCenter[i].y-7+i2);
if i2 < 7 then
FastSetPixel(MainBitmap, 0, CircleCenter[i].x + CircleSliceOffsets[i2] + i3, CircleCenter[i].y+7-i2);
end;
end;
//end of setting pixels on MainBitmap
OldTrans := GetTransparentColor;
SetTransparentColor(MainBitmap, 0);
SetLength(CopiedChunks,1);
Counter := 0;
CopiedChunks[0] := Point(-1,-1);
for i:= 0 to 3 do
begin
Skip := false;
TmpString := 'CleanChunk'+ Padz(IntToStr(Chunks[i].x),2)+'-'+Padz(IntToStr(Chunks[i].y),2);
for i2 := 0 to counter do
begin
if ReadINI('CleanChunksDone', TmpString, CTWBPath + 'CTWBSVN\SVNCleanChunks.INI')='DONE' then
begin
Skip := true;
break;
end;
if ReadINI('CleanChunksDone', TmpString, CTWBPath + 'UserCleanChunks.INI')='DONE' then
begin
Skip := true;
break;
end;
if (Chunks[i].x = CopiedChunks[i2].x) and (Chunks[i].x = CopiedChunks[i2].x) then
begin
Skip := true;
break;
end;
end;
if not Skip then
begin
SetArrayLength(CopiedChunks, counter+1);
CopiedChunks[Counter] := Chunks[i];
Inc(Counter);
TmpString := CTWBPath + TmpString +'.bmp';
if FileExists(TmpString) then
ChunkBitmap := LoadBitmap(TmpString)
else
ChunkBitmap := CreateBitmap(100,100);
FragmentBitmap := BitmapFromClient(FragmentsPixels[i].x1, FragmentsPixels[i].y1,
FragmentsPixels[i].x2, FragmentsPixels[i].y2);
FastDrawTransparent(FragmentsPos[i].x1, FragmentsPos[i].y1, FragmentBitmap, ChunkBitmap);
FreeBitmap(FragmentBitmap);
SaveBitmap(ChunkBitmap, TmpString);
FreeBitmap(ChunkBitmap);
end;
end;
SetTransparentColor(MainBitmap, OldTrans);
SetImageTarget(OldTarget);
FreeTarget(NewTarget);
FreeBitmap(MainBitmap);
end;
{*******************************************************************************
function CTWBGetMyPos: TTile;
By: BenLand100
Description: Returns the global tile position of your player.
*******************************************************************************}
function CTWBGetMyPos: TTile;
var
me: Integer;
begin
me := SmartGetFieldObject(0, hook_static_MyPlayer);
Result.x := SmartGetFieldInt(0, hook_static_BaseX) + SmartGetFieldInt(me, hook_animable_PixelX) / 512;
Result.y := SmartGetFieldInt(0, hook_static_BaseY) + SmartGetFieldInt(me, hook_animable_PixelY) / 512;
SmartFreeObject(me);
if CTWBOn then
CTWBMakeClean(Result);
end;
Edit: alpha was a nightmare, beta is much better
Simba Code:program new;
{$Define SMART}
{$i srl\srl.scar}
{$i Reflection\reflection.simba}
const
CTWBOn = true; //Make true to help out CTWB
color_Black = 65536;
CTWBPath = AppPath + 'CTWB\';
//lordsaturn
function CollectDots: TPointArray;
var
SearchColors: T2DIntegerArray;
TPA, TotalTPA: TPointArray;
i, j: Integer;
begin
SetLength(SearchColors, 3);
SearchColors[0] := [3553023, 789758, 2105598, 395004, 237, 206, 65536, 217, 188]; //red
SearchColors[1] := [16711422, 15527148, 13816530, 14869218, 12961221]; //white
SearchColors[2] := [1179390, 195836, 62965, 56797, 60909, 52428]; //yellow
for i := 0 to 2 do
begin
for j := 0 to High(SearchColors[i]) do
if FindColors(TPA, SearchColors[i][j], MMX1, MMY1, MMX2, MMY2) then
TotalTPA := CombineTPA(TotalTPA, TPA);
end;
Result := TotalTPA;
end;
//lordsaturn
function CollectSymbols: TPointArray;
var
SearchTPA, InsideTPA, OutlineTPA: TPointArray;
ATPA, SymbolATPA, PossiblesATPA, SearchATPA: T2DPointArray;
i, j, k, Hi, Hi2, Hi3, lowX, highX, x, y, L, L2, highCount, counter: Integer;
mid, aPt: TPoint;
SearchBox: TBox;
BadColors: TIntegerArray;
begin
//tpa of symbol outline, length = 40, midpoint = 7,7, bounds 14x14
SearchTPA := [Point(5, 0), Point(6, 0), Point(7, 0), Point(8, 0), Point(9, 0),
{5} Point(3, 1), Point(4, 1), Point(10, 1), Point(11, 1),
{9} Point(2, 2), Point(12, 2),
{11} Point(1, 3), Point(13, 3),
{13} Point(1, 4), Point(13, 4),
{15} Point(0, 5), Point(14, 5),
{17} Point(0, 6), Point(14, 6),
{19} Point(0, 7), Point(14, 7),
{21} Point(0, 8), Point(14, 8),
{23} Point(0, 9), Point(14, 9),
{25} Point(1, 10), Point(13, 10),
{27} Point(1, 11), Point(13, 11),
{29} Point(2, 12), Point(12, 12),
{31} Point(3, 13), Point(4, 13), Point(10, 13), Point(11, 13),
{35} Point(5, 14), Point(6, 14), Point(7, 14), Point(8, 14), Point(9, 14)];
BadColors := [789758, 217, 188, 206, 16711422, 14869218, 12961221, 13816530, 195836, 56797, 52428, 52428];
FindColors(InsideTPA, 12632256, MMX1, MMY1, MMX2, MMY2);
ATPA := TPAtoATPAEx(InsideTPA, 15, 15);
InsideTPA := []; //run faster
Hi := High(ATPA);
Hi3 := 39; //High(SearchTPA);
SetLength(SymbolATPA, Hi+1);
for i := 0 to Hi do
begin
//find top left, bottom right
SearchBox := GetTPABounds(ATPA[i]);
//get symbol outline
FindColors(OutlineTPA, 65536, SearchBox.x1-1, SearchBox.y1-1, SearchBox.x2+1, SearchBox.y2+1);
//build midpoint possibilities
Hi2 := High(OutlineTPA);
L2 := 0;
SetLength(PossiblesATPA, Hi2+1);
for j := 0 to Hi2 do
begin
if not (InIntArray(BadColors, GetColor(OutlineTPA[j].x, OutlineTPA[j].y-1))) then
begin
SetLength(PossiblesATPA[L2], Hi3+1);
for k := 0 to Hi3 do
begin
PossiblesATPA[L2][k].x := SearchTPA[k].x + OutlineTPA[j].x - 7;
PossiblesATPA[L2][k].y := SearchTPA[k].y + OutlineTPA[j].y - 7;
end;
Inc(L2);
end;
end;
OutlineTPA := []; //run faster
SetLength(PossiblesATPA, L2);
//find common midpoint
Hi2 := L2-1; //because it changed
highCount := 0;
for k := 0 to Hi3 do
begin
aPt := PossiblesATPA[0][k];
counter := 0;
for j := 1 to Hi2 do
if PointInTPA(aPt, PossiblesATPA[j]) then
Inc(counter);
if counter > highCount then
begin
mid := aPt;
highCount := counter;
end;
end;
PossiblesATPA := []; //run faster
//filler up
SetLength(SymbolATPA[i], 177);
if L = 0 then
SearchATPA := TPAtoATPAEx(SearchTPA, 15, 0); //go faster
L := 0;
Hi2 := 14; //High(SearchATPA);
for j := 0 to Hi2 do
begin
lowX := mid.x + SearchATPA[j][0].x - 7;
highX := mid.x + SearchATPA[j][High(SearchATPA[j])].x - 7;
y := mid.y + SearchATPA[j][0].y - 7;
for x := lowX to highX do
begin
SymbolATPA[i][L] := Point(x, y);
Inc(L);
end;
end;
end;
Result := MergeATPA(SymbolATPA);
end;
//lordsaturn
function StuffOnMM: TPointArray;
var
timer: Integer;
begin
timer := GetSystemTime;
Result := CombineTPA(CollectDots, CollectSymbols);
//Writeln('StuffOnMM took '+tostr(GetSystemTime-timer)+' msec.');
end;
procedure CTWBMakeClean(MyTile: TPoint);
var
CAB: TBox; //CurrentAreaBox
Chunks, Corners, Corners2, CopiedChunks, DotsTPA: TPointArray;
t,i, i2, counter, MainBitmap, ChunkBitmap, FragmentBitmap, NewTarget, OldTarget: integer;
TmpPoint: TPoint;
TmpString: String;
Skip: Boolean;
ChunksTiles, FragmentsTiles, FragmentsPixels, FragmentsPos: TBoxArray;
var
SearchColors: T2DIntegerArray;
TPA, TotalTPA: TPointArray;
il, jl: Integer;
begin
t := getsystemtime;
//Get tile bounds of CurrentAreaBox
CAB := IntToBox(MyTile.x - 12, MyTile.y + 12, MyTile.x + 12, MyTile.y - 12);//Make sure this does not normalize
//CurrentAreaBox is spread over 1, 2, or 4 chunks, so these arrays are set to 4
//In these arrays, [0] corresponds to the chunk that the top left corner of CAB is in,
//[1] is top right, [2] is bottom left, [3] is bottom right. This defined in Corners
Corners := [Point(CAB.x1, CAB.y1), Point(CAB.x2, CAB.y1), Point(CAB.x1, CAB.y2), Point(CAB.x2, CAB.y2)];
SetArrayLength(Chunks, 4);
SetArrayLength(ChunksTiles, 4);
SetArrayLength(FragmentsTiles, 4);
SetArrayLength(FragmentsPixels, 4);
SetArrayLength(FragmentsPos, 4);
//Using these conventions when working with tiles and pixels
//Pixels have 0,0 in the top left
//Tiles have 0,0 in the bottom left
//Chunks have 0,0 in the bottom left (the are 100x100 pixels, but they deliberately start and end on tiles so that no tile
//is spread over multiple chunks (25x25 tiles), therefore, they follow the tile convention)
//X1,Y1 is always top left, X2,Y2 is always bottom right
//For pixels, Y1 is lower than Y2. For tiles and chunks, Y2 is lower than Y1
for i:= 0 to 3 do
begin
//Find the Chunk that the corresponding corner of CAB is in
Chunks[i] := Point(((Corners[i].x-2044) div 25),((Corners[i].y-861) div 25));
//Find the tile bounds of that chunk
ChunksTiles[i] := IntToBox(2044+Chunks[i].x*25, 885+Chunks[i].y*25, 2068+Chunks[i].x*25, 861+Chunks[i].y*25);//No normalize
//These are the opposite corners of Corners
Corners2 := [Point(ChunksTiles[i].x2, ChunksTiles[i].y2), Point(ChunksTiles[i].x1, ChunksTiles[i].y2), Point(ChunksTiles
[i].x2, ChunksTiles[i].y1), Point(ChunksTiles[i].x1, ChunksTiles[i].y1)]; //yes normalize
//Find the intersection of the corresponding Corner of CAB and the opposite corner of the Chunk
//that contains the Corner of CAB. Also make X1 lower than X2, and Y1 higher than Y2 (tiles start from the bottom left)
FragmentsTiles[i] := IntToBox(Min(Corners[i].x,Corners2[i].x), Max(Corners[i].y,Corners2[i].y), Max(Corners[i].x,Corners2
[i].x), Min(Corners[i].y, Corners2[i].y));
//Find the pixel bounds (on MainBitmap) of thoses tiles
FragmentsPixels[i] := IntToBox(14+(FragmentsTiles[i].x1-(MyTile.x-12))*4, 14+((MyTile.y+12)-FragmentsTiles[i].y1)*4, 112-
((MyTile.x+12)-FragmentsTiles[i].x2)*4, 112-(FragmentsTiles[i].y2-(MyTile.y-12))*4);
//Find the pixel box in Chunk that fragment will be copied to
FragmentsPos[i] := IntToBox((FragmentsTiles[i].x1-ChunksTiles[i].x1)*4, (ChunksTiles[i].y1-FragmentsTiles[i].y1)*4,
(FragmentsTiles[i].x1-ChunksTiles[i].x1)*4 + (FragmentsPixels[i].x2 - FragmentsPixels[i].x1),
(ChunksTiles[i].y1-FragmentsTiles[i].y1)*4 + (FragmentsPixels[i].y2 - FragmentsPixels[i].y1));
end;
DotsTPA :=StuffOnMM;
MainBitmap := BitmapFromClient(564, 21, 691, 148);
OldTarget := GetImageTarget;
SetTargetBitmap(MainBitmap);
NewTarget := GetImageTarget;
for i := 0 to High(DotsTPA) do
begin
il:=DotsTPA[i].x-564;
jl:=DotsTPA[i].y-21;
if (il > -1) and (il < 128) and (jl > -1) and (jl < 128) then
FastSetPixel(MainBitmap, il, jl, 0);
end;
for il:= mmcx-1 to mmcx+1 do
for jl:= mmcy-1 to mmcy +1 do
FastSetPixel(MainBitmap, il-564, jl-21, 0);
SetLength(CopiedChunks,1);
Counter := 0;
CopiedChunks[0] := Point(-1,-1);
for i:= 0 to 3 do
begin
Skip := false;
TmpString := 'CleanChunk'+ Padz(IntToStr(Chunks[i].x),2)+'-'+Padz(IntToStr(Chunks[i].y),2);
for i2 := 0 to High(CopiedChunks) do
begin
if ReadINI('CleanChunksDone', TmpString, CTWBPath + 'CTWBSVN\SVNCleanChunks.INI')='DONE' then
begin
Skip := true;
break;
end;
if ReadINI('CleanChunksDone', TmpString, CTWBPath + 'UserCleanChunks.INI')='DONE' then
begin
Skip := true;
break;
end;
if (Chunks[i].x = CopiedChunks[i2].x) and (Chunks[i].y = CopiedChunks[i2].y) then
begin
Skip := true;
break;
end;
end;
if not Skip then
begin
SetArrayLength(CopiedChunks, counter+1);
CopiedChunks[Counter] := Chunks[i];
Inc(Counter);
TmpString := CTWBPath + TmpString +'.bmp';
if FileExists(TmpString) then
ChunkBitmap := LoadBitmap(TmpString)
else
ChunkBitmap := CreateBitmap(100,100);
FragmentBitmap := BitmapFromClient(FragmentsPixels[i].x1, FragmentsPixels[i].y1,
FragmentsPixels[i].x2, FragmentsPixels[i].y2);
SetTransparentColor(FragmentBitmap, 0);
FastDrawTransparent(FragmentsPos[i].x1, FragmentsPos[i].y1, FragmentBitmap, ChunkBitmap);
FreeBitmap(FragmentBitmap);
SaveBitmap(ChunkBitmap, TmpString);
FreeBitmap(ChunkBitmap);
end;
end;
SetImageTarget(OldTarget);
FreeTarget(NewTarget);
FreeBitmap(MainBitmap);
end;
{*******************************************************************************
function CTWBGetMyPos: TTile;
By: BenLand100
Description: Returns the global tile position of your player.
*******************************************************************************}
function CTWBGetMyPos: TPoint;
var
me: Integer;
begin
me := SmartGetFieldObject(0, hook_static_MyPlayer);
Result.x := SmartGetFieldInt(0, hook_static_BaseX) + SmartGetFieldInt(me, hook_animable_PixelX) / 512;
Result.y := SmartGetFieldInt(0, hook_static_BaseY) + SmartGetFieldInt(me, hook_animable_PixelY) / 512;
SmartFreeObject(me);
if CTWBOn then
if R_MakeCompass('n') then
if not R_FlagExists then
CTWBMakeClean(Result);
end;
var mypoint: tpoint;
begin
Smart_Server := 152;
Smart_Members := false;
Smart_signed := true;
Smart_SuperDetail := false;
SetUpSRL;
SetUpReflection;
HowManyPlayers := 1;
CurrentPlayer := 0;
NumberOfPlayers(HowmanyPlayers);
with Players[0] do
begin
Name := '';
Pass := '';
Active := true;
end;
LoginPlayer;
mypoint:= CTWBGetMyPos;
end.