Boreas
12-30-2010, 03:25 AM
Brief Overview
CTWB is a set of functions that generate screenshots of the minimap to be uploaded to a community collection of bitmaps.
Users: how to get CTWB
Save this as CTWB.simba file in your includes folder. If would like to contribute, see next section.
{CTWB}
const
CTWBOn = false; //Make true to help out CTWB
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
Freeze;
timer := GetSystemTime;
Result := CombineTPA(CollectDots, CollectSymbols);
//Writeln('StuffOnMM took '+tostr(GetSystemTime-timer)+' msec.');
Unfreeze;
end;
procedure CTWBMakeClean(MyTile: TPoint);
var
CAB: TBox; //CurrentAreaBox
Chunks, Corners, Corners2, CopiedChunks, DotsTPA: TPointArray;
il, jl, t,i, i2, counter, MainBitmap, ChunkBitmap, FragmentBitmap, NewTarget, OldTarget: integer;
TmpString: String;
Skip: Boolean;
ChunksTiles, FragmentsTiles, FragmentsPixels, FragmentsPos: TBoxArray;
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;
{************************************************* ******************************
function TileToMM(tile: TTile): TPoint;
By: BenLand100
Description: Converts the global tile position to a screen location on the
minimap, taking map rotation into account.
************************************************** *****************************}
function CTWBTileToMM(tile: TTile): TPoint;
var
angle, x, y: extended;
temp: TPoint;
begin
angle:= -GetMinimapAngleRad;
temp := CTWBGetMyPos();
x:= (tile.x - temp.x) * 4 - 2;
y:= (temp.y - tile.y) * 4 - 2;
result.x:= round(x*cos(angle) + y*sin(angle)) + 628;
result.y:= round(y*cos(angle) - x*sin(angle)) + 87;
end;
{************************************************* ******************************
function TileOnMM(Tile: TTile): boolean;
By: Drags111
Description: Checks if the Tile is on the MM.
************************************************** *****************************}
function CTWBTileOnMM(Tile: TTile): boolean;
var
P: TPoint;
begin
P := CTWBTileToMM(Tile);
Result := rs_OnMinimap(P.x, P.y);
end;
{************************************************* ******************************
Function WalkToTile(Tile: TPoint; Randomness, FlagD: Integer): Boolean;
By: Wizzup, TheGuyWhoGotOn, and Drags111
Description: Walks to the tile using minimap.
************************************************** *****************************}
function CTWBWalkToTile(TheTile: TTile; Randomness, FlagD: Integer): Boolean;
var
wTile: TPoint;
t: Integer;
begin
Result := False;
TheTile := RandomizeTile(TheTile, Randomness, Randomness);
wTile := CTWBTileToMM(TheTile);
if not rs_OnMiniMap(wTile.X, wTile.Y) then
Exit;
Mouse(wTile.x, wTile.y, 1, 1, true);
Wait(RandomRange(80, 100));
t := getsystemtime;
if (FlagD = 0)then
begin
R_Flag;
end else
R_FFlag(FlagD);
Result := (GetSystemTime - t) < 60000;
end;
{************************************************* ******************************
function WalkPath(Tiles: TTileArray): boolean;
By: Drags111
Description: Walks the tile path. Looks like an ugly function, but it works
Beautifully.
************************************************** *****************************}
function CTWBWalkPath(Tiles: TTileArray): boolean;
var
i, t, attempts: integer;
P: TPoint;
next: boolean;
label
ProcStart;
begin
Inc(attempts);
ProcStart:
i := -1;
Result := false;
if(DistanceFrom(Tiles[High(Tiles)]) < 6)then
begin
Result := true;
Exit;
end;
//Getting the starting index.
for i := High(Tiles) downto 0 do
if(CTWBTileOnMM(Tiles[i]))then
begin
i := i;
Break;
end;
if(i = -1)then
Exit;
//Walk remainder of the path.
for i := i to High(Tiles) do
begin
next := false;
if not(TileOnMM(Tiles[i]))then
begin
Writeln('Tile not on MM.');
break;
end;
P := CTWBTileToMM(Tiles[i]);
Mouse(P.x, P.y, 1, 1, true);
while(DistanceFromFlag <> 0)do
begin
if not WaitToMove(3000)then
begin
MarkTime(t);
while(TimeFromMark(t) < 7000)do
if(WaitToMove(1000))then break;
if(TimeFromMark(t) >= 7000)then
begin
Writeln('***Didn''t move for 10 seconds. Exiting***');
next := false;
break;
end;
end;
if(i < High(Tiles))then
begin
if(TileOnMM(Tiles[i+1]))then
begin
next := true;
break;
end;
end;
end;
if(i < High(Tiles))then
if(TileOnMM(Tiles[i+1]))then
next := true;
if not next then
break;
end;
Result := DistanceFrom(Tiles[High(Tiles)]) <= 5;
if not Result then
begin
if(attempts > 7)then
begin
Writeln('Failed more than ten attempts.');
Exit;
end;
While(GetSpeed > 0)do wait(100+Random(100));
goto ProcStart;
end;
While(GetSpeed > 0)do wait(100+Random(100));
end;
{************************************************* ******************************
Function WebWalk(T: TTile): Boolean;
By: JuKKa
Description: Walks blindly using WindPath!
************************************************** *****************************}
Function CTWBr_WebWalk(T: TTile): Boolean;
Var
I: Integer;
M, P: TPoint;
CTRLPoints: TPointArray;
Begin
P := TileToPoint(T);
Repeat
M := GetMyPos;
CtrlPoints := r_WindPath(M.x, M.y, P.X, P.Y, 5.0, 2.5, 0.0, 0.0, 4.5, 2.5);
For I:= High(CtrlPoints) DownTo 0 Do
if CTWBWalkToTile(Tile(CtrlPoints[i].x, CtrlPoints[i].y),0, 10) Then
Begin
Result := I = High(CtrlPoints);
Break;
End;
Until( Result );
End;
Users: how to enable CTWB
In CTWB.simba change 'CTWB = false;' to 'CTWB = true;'. You can also change CTWBPath if you would like. Now that CTWB is enabled, when you are running scripts that are CTWB Ready (they will have {$i CTWB.smba} at the top), bitmaps will be generated and saved to that path. Thanks for contributing!
Users: how to upload bitmaps
Once a week/month, or whenever you want, run this script.
<need to write a script that:
Downloads latest version of CommunityCompletedChunks.INI and StaticNPCTiles.INI,
SetPixel static NPC tiles yellow
Finds chunks with no remaining black, adds to UserCompletedChunks.INI, and uploads them to ???>
Scripters: how to make a script CTWB Ready
If your script uses reflection for walking, you can make it CTWB Ready (users still have to actually turn it on for it to do anything, see above). Add {$i CTWB.simba} after you include reflection. Wherever you call GetMyPos/WalkToTile/WalkPath, if making the compass north and an extra 250-1000ms won't hurt GetMyPos, replace them with CTWBGetMyPos/CTWBWalkToTile/CTWBWalkPath. On your script thread or in the instructions, link to this page so that users can get CTWB.simba. Thanks for contributing!
Extra information
CTWBGetMyPos takes screenshots of the minimap, and saves them to bitmaps. These bitmaps are named according to your current tile (hence the need for reflection). Dots and symbols are not included in these bitmaps, they are replaced with black. On the following runs, pixels that were black are updated (so the dots and symbols automagically disappear).
CTWB is a set of functions that generate screenshots of the minimap to be uploaded to a community collection of bitmaps.
Users: how to get CTWB
Save this as CTWB.simba file in your includes folder. If would like to contribute, see next section.
{CTWB}
const
CTWBOn = false; //Make true to help out CTWB
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
Freeze;
timer := GetSystemTime;
Result := CombineTPA(CollectDots, CollectSymbols);
//Writeln('StuffOnMM took '+tostr(GetSystemTime-timer)+' msec.');
Unfreeze;
end;
procedure CTWBMakeClean(MyTile: TPoint);
var
CAB: TBox; //CurrentAreaBox
Chunks, Corners, Corners2, CopiedChunks, DotsTPA: TPointArray;
il, jl, t,i, i2, counter, MainBitmap, ChunkBitmap, FragmentBitmap, NewTarget, OldTarget: integer;
TmpString: String;
Skip: Boolean;
ChunksTiles, FragmentsTiles, FragmentsPixels, FragmentsPos: TBoxArray;
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;
{************************************************* ******************************
function TileToMM(tile: TTile): TPoint;
By: BenLand100
Description: Converts the global tile position to a screen location on the
minimap, taking map rotation into account.
************************************************** *****************************}
function CTWBTileToMM(tile: TTile): TPoint;
var
angle, x, y: extended;
temp: TPoint;
begin
angle:= -GetMinimapAngleRad;
temp := CTWBGetMyPos();
x:= (tile.x - temp.x) * 4 - 2;
y:= (temp.y - tile.y) * 4 - 2;
result.x:= round(x*cos(angle) + y*sin(angle)) + 628;
result.y:= round(y*cos(angle) - x*sin(angle)) + 87;
end;
{************************************************* ******************************
function TileOnMM(Tile: TTile): boolean;
By: Drags111
Description: Checks if the Tile is on the MM.
************************************************** *****************************}
function CTWBTileOnMM(Tile: TTile): boolean;
var
P: TPoint;
begin
P := CTWBTileToMM(Tile);
Result := rs_OnMinimap(P.x, P.y);
end;
{************************************************* ******************************
Function WalkToTile(Tile: TPoint; Randomness, FlagD: Integer): Boolean;
By: Wizzup, TheGuyWhoGotOn, and Drags111
Description: Walks to the tile using minimap.
************************************************** *****************************}
function CTWBWalkToTile(TheTile: TTile; Randomness, FlagD: Integer): Boolean;
var
wTile: TPoint;
t: Integer;
begin
Result := False;
TheTile := RandomizeTile(TheTile, Randomness, Randomness);
wTile := CTWBTileToMM(TheTile);
if not rs_OnMiniMap(wTile.X, wTile.Y) then
Exit;
Mouse(wTile.x, wTile.y, 1, 1, true);
Wait(RandomRange(80, 100));
t := getsystemtime;
if (FlagD = 0)then
begin
R_Flag;
end else
R_FFlag(FlagD);
Result := (GetSystemTime - t) < 60000;
end;
{************************************************* ******************************
function WalkPath(Tiles: TTileArray): boolean;
By: Drags111
Description: Walks the tile path. Looks like an ugly function, but it works
Beautifully.
************************************************** *****************************}
function CTWBWalkPath(Tiles: TTileArray): boolean;
var
i, t, attempts: integer;
P: TPoint;
next: boolean;
label
ProcStart;
begin
Inc(attempts);
ProcStart:
i := -1;
Result := false;
if(DistanceFrom(Tiles[High(Tiles)]) < 6)then
begin
Result := true;
Exit;
end;
//Getting the starting index.
for i := High(Tiles) downto 0 do
if(CTWBTileOnMM(Tiles[i]))then
begin
i := i;
Break;
end;
if(i = -1)then
Exit;
//Walk remainder of the path.
for i := i to High(Tiles) do
begin
next := false;
if not(TileOnMM(Tiles[i]))then
begin
Writeln('Tile not on MM.');
break;
end;
P := CTWBTileToMM(Tiles[i]);
Mouse(P.x, P.y, 1, 1, true);
while(DistanceFromFlag <> 0)do
begin
if not WaitToMove(3000)then
begin
MarkTime(t);
while(TimeFromMark(t) < 7000)do
if(WaitToMove(1000))then break;
if(TimeFromMark(t) >= 7000)then
begin
Writeln('***Didn''t move for 10 seconds. Exiting***');
next := false;
break;
end;
end;
if(i < High(Tiles))then
begin
if(TileOnMM(Tiles[i+1]))then
begin
next := true;
break;
end;
end;
end;
if(i < High(Tiles))then
if(TileOnMM(Tiles[i+1]))then
next := true;
if not next then
break;
end;
Result := DistanceFrom(Tiles[High(Tiles)]) <= 5;
if not Result then
begin
if(attempts > 7)then
begin
Writeln('Failed more than ten attempts.');
Exit;
end;
While(GetSpeed > 0)do wait(100+Random(100));
goto ProcStart;
end;
While(GetSpeed > 0)do wait(100+Random(100));
end;
{************************************************* ******************************
Function WebWalk(T: TTile): Boolean;
By: JuKKa
Description: Walks blindly using WindPath!
************************************************** *****************************}
Function CTWBr_WebWalk(T: TTile): Boolean;
Var
I: Integer;
M, P: TPoint;
CTRLPoints: TPointArray;
Begin
P := TileToPoint(T);
Repeat
M := GetMyPos;
CtrlPoints := r_WindPath(M.x, M.y, P.X, P.Y, 5.0, 2.5, 0.0, 0.0, 4.5, 2.5);
For I:= High(CtrlPoints) DownTo 0 Do
if CTWBWalkToTile(Tile(CtrlPoints[i].x, CtrlPoints[i].y),0, 10) Then
Begin
Result := I = High(CtrlPoints);
Break;
End;
Until( Result );
End;
Users: how to enable CTWB
In CTWB.simba change 'CTWB = false;' to 'CTWB = true;'. You can also change CTWBPath if you would like. Now that CTWB is enabled, when you are running scripts that are CTWB Ready (they will have {$i CTWB.smba} at the top), bitmaps will be generated and saved to that path. Thanks for contributing!
Users: how to upload bitmaps
Once a week/month, or whenever you want, run this script.
<need to write a script that:
Downloads latest version of CommunityCompletedChunks.INI and StaticNPCTiles.INI,
SetPixel static NPC tiles yellow
Finds chunks with no remaining black, adds to UserCompletedChunks.INI, and uploads them to ???>
Scripters: how to make a script CTWB Ready
If your script uses reflection for walking, you can make it CTWB Ready (users still have to actually turn it on for it to do anything, see above). Add {$i CTWB.simba} after you include reflection. Wherever you call GetMyPos/WalkToTile/WalkPath, if making the compass north and an extra 250-1000ms won't hurt GetMyPos, replace them with CTWBGetMyPos/CTWBWalkToTile/CTWBWalkPath. On your script thread or in the instructions, link to this page so that users can get CTWB.simba. Thanks for contributing!
Extra information
CTWBGetMyPos takes screenshots of the minimap, and saves them to bitmaps. These bitmaps are named according to your current tile (hence the need for reflection). Dots and symbols are not included in these bitmaps, they are replaced with black. On the following runs, pixels that were black are updated (so the dots and symbols automagically disappear).