SRL Archive - Devs' Corner

R_WalkPathEx to be the new WalkPath


Cstrike

2010-12-01 13:32:58

Here's two functions side-by-side
{*******************************************************************************
function WalkPath(Tiles: TTileArray): boolean;
By: Drags111
Description: Walks the tile path. Looks like an ugly function, but it works
Beautifully.
*******************************************************************************}
function WalkPath(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(TileOnMM(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 := TileToMM(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 R_WalkPathEx(Tiles: TTileArray; MouseRandomness, TimeoutMs, AcceptableDistanceFromLastTile: Integer; ExitIfTimeout : Boolean): Boolean;
By: Drags111/Cstrike
Description: Walks the tile path. Looks like an ugly function, but it works
Beautifully. Modded by Cstrike to be less bannable/no infinite loops. Also added
prevention from crashing if you enter a high = 0 TTA. If we're <= AcceptableDist
FromLastTile then function returns true
*******************************************************************************}
function R_WalkPathEx(Tiles: TTileArray; MouseRandomness, TimeoutMs, AcceptableDistanceFromLastTile: Integer; ExitIfTimeout : Boolean): Boolean;
var
i, t, attempts: integer;
P: TPoint;
next: boolean;
label
ProcStart;
begin
Inc(attempts);
ProcStart:
i := -1;
Result := false;
if high(Tiles) < 0 then
begin
Writeln ('[Reflection] Empty tile array, exiting R_WalkPath');
Exit;
end;
if(DistanceFrom(Tiles[High(Tiles)]) <= AcceptableDistanceFromLastTile)then
begin
Result := true;
Exit;
end;

//Getting the starting index.
for i := High(Tiles) downto 0 do
if(TileOnMM(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('[Reflection] Tile not on MM.');
break;
end;
P := TileToMM(Tiles[i]);
Mouse(P.x, P.y, MouseRandomness, MouseRandomness, 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('[Reflection] Warning: Didn''t move for '+ToStr(TimeoutMs));
next := false;
if ExitIfTimeout then
begin
Writeln ('[Reflection] Exiting path walking procedure');
Exit;
end;
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)]) <= AcceptableDistanceFromLastTile;
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;


Problems with Walkpath:
- No customization
- Limited to a randomness of 1 (detectable)
- Runs an infinite loop if you get stuck (yes this has happened to me multiple times

Some of these are solved, with big parameter names.
Do you think this would be a good implementation? WalkPath works great most (to all) of the time.

Nava2

2010-12-01 14:35:29

Semi-on-topic:

I think that Zeph and I had a Generate path function that should be included. Check this out:
function FurthestVisibleTile(tPath: TPointArray; P: TPoint; sTile, eTile: Integer): Integer;
var {Returns the Index of the furthest tile in a path }
H: Integer; {between given indices that is still on the MM}
begin
SetLength(tPath, eTile + 1); //Removes tiles not in range
InvertTPA(tPath);
SetLength(tPath, Length(tPath) - sTile);
InvertTPA(tPath);

H := High(tPath);
for Result := H downto 0 do //Finds the furthest visible tile.
if (Sqrt(Sqr((tPath[Result].X - P.X) * 4.0) + Sqr((tPath[Result].Y - P.Y) * 4.0)) < 69.0) then
begin
IncEx(Result, sTile);
Exit;
end;
Result := -1;
end;

function CreatePathBetween(fT, tT: TPoint; tDist, Rand: Integer): TPointArray; {Creates a TPA between points, tDist intervals, Rand randonmness (Tiles)}
var
hyp, xR, yR: Extended;
l: Integer;
begin
if not LoggedIn then Exit;

SetLength(Result, Ceil(Distance(fT.X, fT.y, tT.X, tT.Y) * 1.0 / tDist) + 1); //Set Result Length and first point at initial tile.
Result[0] := fT;

if (Distance(fT.X, fT.Y, tT.X, tT.Y) <= tDist) then //If no need for intermediate tiles then nvm. :)
begin
Result[High(Result)] := tT;
Exit;
end;

hyp := Hypot(fT.X - tT.x, fT.Y - tT.Y); //Ratios for 'Similar Triangles' maths.
xR := (tT.X - fT.X) / hyp;
yR := (tT.Y - fT.Y) / hyp;

for l := 1 to High(Result) - 1 do //Sets points
begin
Result[l].X := Round(fT.X + l * tDist * xR);
Result[l].Y := Round(fT.Y + l * tDist * yR);
RandomizeTile(Result[l], Rand, Rand);
end;

Result[High(Result)] := tT; //Last point is tT
end;

function ExpandPath(ctrlTiles: TPointArray; tDist, Randomness: Integer): TPointArray;
var {Expands ctrlPoints into a path with tDist intervals and Randomness}
i, h: Integer;
t: T2DPointArray;
begin
Result := [];
h := High(ctrlTiles);
SetLength(t, h);

for i := 1 to h do
t[i - 1] := CreatePathBetween(ctrlTiles[I - 1], ctrlTiles[I], tDist, Randomness);

Result := MergeATPA(t);
end;

function WalkTileOff(t: TPoint): Boolean; {Walks to a tile, creating a path if necessary}
var
h, tileInd, Attempts, pInd: Integer;
nP: TPointArray;
P: TPoint;
begin
Result := False;
if not LoggedIn then Exit;

{$IFDEF DEBUG}Debug('WalkTileOff: Walking to ' + IntToStr(t.x) + ', ' + IntToStr(t.y));{$ENDIF}
nP := CreatePathBetween(GetMyPos, t, 1, Random(3)); //Creates the path
h := High(nP);

P := GetMyPos;
while (Distance(P.X, P.Y, nP[H].X, nP[H].Y) > 5) and (Attempts < 5) do //Loops through the tiles and walks :)
begin
tileInd := FurthestVisibleTile(nP, P, pInd, H);
if (tileInd > -1) then //If FurthestTile found then walk
begin
Debug('WalkToTile: ' + IntToStr(nP[tileInd].X) + ',' + IntToStr(nP[tileInd].Y));
if (WalkToTile(nP[tileInd], 0, RandomRange(10, 25) + Random(10) * Integer(RBoolEx(10)))) then
begin
Attempts := 0;
Wait(100 + Random(100));
P := GetMyPos;
FindMeOnPath(pInd, nP, 5);
end;
end;

Inc(Attempts);
end;

if (Attempts >= 5) then
begin
SetLoc('E:: Lost on WalkTileOff');
LogOut;
Exit;
end;

R_Flag;
Result := (DistanceFrom(t) <= 5);
end;

function WalkPath(Path: TPointArray): Boolean; {Walks a Path} {OMG ORLY? :O}
var
P: TPoint;
H, tileInd, pInd, Attempts, time: Integer;
label
Start, lost;
begin
time := GetTimeRunning;
Start:
if GetTimeRunning - Time > 60000 then
goto lost;

H := High(Path);
if (H < 0) then Exit;

if (not(FindMeOnPath(pInd, Path, 20))) then //Finds you on a path and attempts to walk to it if possible
begin
P := NearestTile(Path, 0);
if (DistanceFrom(P) < 50) then
if (WalkTileOff(P)) then
goto Start;
lost:
p := GetMyPos;
SetLoc('E:: Lost en route. ' + IntToStr(p.x) + ', ' + IntToStr(p.y));;
LogOut;
Exit;
end;

P := GetMyPos;
while (Distance(P.X, P.Y, Path[H].X, Path[H].Y) > 3) and (Attempts < 5) do //Loops through the tiles and walks :)
begin
tileInd := FurthestVisibleTile(Path, P, pInd, H);
if (tileInd > -1) then //If FurthestTile found then walk
begin
Debug('Next Tile: ' + IntToStr(tileInd) + ' (' + IntToStr(Path[tileInd].X) + ',' + inttostr(Path[tileInd].Y) + ')');
if (WalkToTile(Path[tileInd], 0, RandomRange(10, 30) + Random(10) * Integer(RBoolEx(10)))) then
begin
Attempts := 0;
Wait(100 + Random(100));
P := GetMyPos;
FindMeOnPath(pInd, Path, 5);
end;
end;
Inc(Attempts);
end;

R_FFlag(10);
Result := (DistanceFrom(Path[H]) <= 3); //True if successful.
if (not(Result)) then
WriteLn('WalkPath failed');
end;

Any questions, let me know.. or zephypoo.

E: More explanation:
So, basically it will take any tile and create a random path between it. It will create a zig-zag of sorts between the point randomly moving across the direct path. This makes EVERY path different. The WalkPath function can take a series of ctrl points and will generate the path between each point to make sure that it can be walked to. This means you can have one control path and (essentially) a massive number of options. Also, its damn quick as it merely does cos/sin using precalculated ratios of similar triangles.