Sir R. M8gic1an
2010-05-31 12:39:56
program QuickWebWalkSystem;
{
II | I
- - - - -
III | IV
}
const
MM_RADIUS = 5;
type
TTile = TPoint;
WDir = record
xL : boolean;
yL : boolean;
xH : boolean;
yH : boolean;
end;
WPoint = record //Walkable Point
WTile: TTile;
WP : TPoint; //To avoid precious ms loss in loops
Walkable: Boolean;
WalkD : WDir;
end;
var
WebWPoints: array of WPoint;
WebTPoints: TPointArray;
function Tile(x, y: integer): TTile;
begin
Result.x := x;
Result.y := y;
end;
function TileToPoint(T: TTile): TPoint;
begin
Result.x := T.x;
Result.y := T.y;
end;
function PointToTile(TP: TPoint): TTile;
begin
Result.x := TP.x;
Result.y := TP.y;
end;
procedure WriteTP(T: TPoint);
begin
writeln('TP: ('+IntToStr(T.x)+', '+IntToStr(T.y)+')');
end;
procedure LoadWPA;
begin
SetLength(WebWPoints, 3);
SetLength(WebTPoints, 3);
with WebWPoints[0] do
begin
WTile := Tile(0, 0);
WP := TileToPoint(WTile);
Walkable := true;
{This point connects W, N, E}
WalkD.xL := true;
WalkD.yL := true;
WalkD.xH := true;
WalkD.yH := false;
end;
with WebWPoints[1] do
begin
WTile := Tile(30, 25);
WP := TileToPoint(WTile);
Walkable := true;
{Bank only approachable from South-> North}
WalkD.xL := false;
WalkD.yL := true;
WalkD.xH := false;
WalkD.yH := false;
end;
with WebWPoints[2] do
begin
WTile := Tile(35, 27);
WP := TileToPoint(WTile);
Walkable := true;
{This point connects all}
WalkD.xL := true;
WalkD.yL := true;
WalkD.xH := true;
WalkD.yH := true;
end;
end;
function GetWebTPA: TPointArray;
var
i, t: integer;
begin
SetLength(Result, Length(WebWPoints));
t := High(WebWPoints);
for i := 0 to t do
Result[i] := WebWPoints[i].WP;
end;
function DirsToWDir(RxL, RyL, RxH, RyH: boolean): WDir;
begin
with Result do
begin
xL := RxL;
yL := RyL;
xH := RxH;
yH := RyH;
end;
end;
function TileToWP(T: TTile; Walk: boolean; WD: WDir): WPoint;
begin
with Result do
begin
WTile := T;
WP := TileToPoint(T);
Walkable := Walk;
WalkD := WD;
end;
end;
function GetWPoint(T: TTile): WPoint; //This will scan to find the closest walkable point
var
i, Pi, Dis, tDis, tot: integer;
begin
writeln('GetWPoint');
//Could be made faster if WebWPoints has a logic behind it
tot := High(WebTPoints);
Dis := 99999;
Pi := 0;
for i:= 0 to tot do
begin
tDis := Distance(T.x, T.y, WebTPoints[i].x, WebTPoints[i].y );
if tDis < Dis then
if WebWPoints[i].Walkable then
begin
Dis := tDis;
Pi := i;
if Dis = 0 then
break;
end;
end;
Result := WebWPoints[Pi];
writeln(Result.Walkable);
end;
function GetMiddlePoint(StartP, EndP: TPoint; angle: extended): TPoint;
begin
//So the angle can always be calculated in the same way
if StartP.x > EndP.x then
begin
if StartP.y > EndP.y then
begin
// Q II
angle := 90.0;
Result := Point(StartP.x, EndP.y);
end else begin
// Q III
angle := 180.0;
Result := Point(EndP.x, StartP.y);
end;
end else begin
if StartP.y > EndP.y then
begin
// Q IV
angle := 270.0;
Result := Point(EndP.x, StartP.y);
end else begin
// Q I
angle := 0.0;
Result := Point(StartP.x, EndP.y);
end;
end;
end;
function Approachable(SP: TPoint; EP: WPoint): boolean;
var
TP: TPoint;
begin
TP := EP.WP;
if abs(TP.x - SP.x) > abs(TP.y - SP.y) then
//sort by x
if TP.x > SP.x then
Result := EP.WalkD.xH
else
Result := EP.WalkD.xL
else
//sort by y
if TP.y > SP.y then
Result := EP.WalkD.yH
else
Result := EP.WalkD.yL;
end;
//Using the WebWalkArray, Returns TPoint of next Walkable Point
//Parts pretty much ripped off of Nielsie's RadialWalkEx
function TPA_RadialWalkEx(var NextP: TPoint; StartP, EndP: TPoint): boolean;
var
i, h, SD, ED, radius: Integer;
angle: extended;
tpa: TPointArray;
MPoint, TP: TPoint;
WP: WPoint;
begin
tpa := WebTPoints;
WP := GetWPoint(PointToTile(EndP));
TP := WP.WP;
writeTP(TP);
radius := Max(
Distance(StartP.x, StartP.y, EndP.x, EndP.y) + 10,
Distance(StartP.x, StartP.y, TP.x, TP.y) + 5
);
writeln('r');
writeln(radius);
MPoint := GetMiddlePoint(StartP, TP, angle);
writeln('no trig');
writeln(angle);
angle := angle + Cos( distance(StartP.x, StartP.y, MPoint.x, MPoint.y) /
distance(StartP.x, StartP.y, TP.x, TP.y)
);
writeln('angle');
writeln(angle);
SD := Round(angle - 22.0);
ED := Round(angle + 22.0);
while not Result do
begin
writeln('i: ' + IntToStr(i));
SD := SD - 5 * i;
ED := ED + 5 * i;
Radius := Radius + 5 * i;
SD := Trunc(FixD(SD + 0.0));
ED := Trunc(FixD(ED + 0.0));
try
tpa := GetWebTPA;
FilterPointsPie(tpa, SD, ED, MM_RADIUS, Radius, StartP.x, StartP.y);
SortCircleWise(tpa, StartP.x, StartP.y, SD, true, true);
Result := (Length(tpa) > 0);
except writeln('except'); end;
if Result then
begin
writeln('TPA length');
writeln(Length(TPA));
end else begin
inc(i);
continue;
writeln('continued');
end;
try
for h := 0 to High(tpa) do
begin
writeTP(TPA[h]);
WP := GetWPoint(PointToTile(tpa[h]));
if not WP.Walkable or
not Approachable(StartP, WP)
then
Result := false
else begin
NextP := TPA[h];
Result := true;
break;
end;
end;
except
writeln('Out of TPA range?');
Result := false;
end;
inc(i);
end;
end;
var
TP: TPoint;
begin
ClearDebug;
LoadWPA;
WebTPoints := GetWebTPA;
TPA_RadialWalkEx(TP, Point(0, 0), Point(20, 20));
writeln('Coords'); writeln(TP.x); writeln(TP.y);
end.
Well, this has some useless stuff in there for now, and is not exactly very reader friendly.
But here is a picture of what it will do:
The only real improvement of this compared to previous WebWalkSystems made here at SRL is the Non_Walkable point. It is not yet properly scripted. Here's how it will work:Find straightest path between StartPoint and EndPoint;
Find Any NonWalkable Points in that path.
Find Alternative walk around NonWalkable point
Generate TTileArray with propper walk.
ATM it does not go around NonWalkable Points. It just avoids them. So it would've failed in the above picture.
Now, my question is this:

Should it follow the orange path, or the light blue path?
Orange path would probably mean walking through woods and so on.
Light blue path would mean longer walks, but walking through 'mapped' places.
~RM