unit uGmPathfind;

interface

uses
  uGmArena, uGmCreature;

const
  W_R   = 0;
  W_RD  = 1;
  W_LD  = 2;
  W_L   = 3;
  W_LU  = 4;
  W_RU  = 5;

var
  Wave : array[0..11, 0..9] of integer;

procedure CreateWave( x1, y1, r : integer; Fly : boolean );
procedure CreatePath( Creature : TCreature; x2, y2 : integer );
function Wave_GetNear( x1, y1 : integer; nt : byte ): integer;

implementation

//==============================================================================
procedure FillWave( r : integer );
var
  i, j, k : integer;
  bool    : boolean;
begin
  k := 1;
  repeat
    bool := False;
    for j := 0 to 8 do
      for i := 0 to 10 do
        if Wave[ i, j ] = k then
        begin
          if i > 0 then
            if Wave[ i - 1, j ] = 0 then Wave[ i - 1, j ] := k + 1;
          if i < 10 then
            if Wave[ i + 1, j ] = 0 then Wave[ i + 1, j ] := k + 1;
          if j > 0 then
          begin
            if Wave[ i, j - 1 ] = 0 then Wave[ i, j - 1 ] := k + 1;
            if ( j mod 2 = 0 ) and ( i < 10 ) then
              if Wave[ i + 1, j - 1 ] = 0 then Wave[ i + 1, j - 1 ] := k + 1;
            if ( j mod 2 <> 0 ) and ( i > 0 ) then
              if Wave[ i - 1, j - 1 ] = 0 then Wave[ i - 1, j - 1 ] := k + 1;
          end;
          if j < 8  then
          begin
            if Wave[ i, j + 1 ] = 0 then Wave[ i, j + 1 ] := k + 1;
            if ( j mod 2 = 0 ) and ( i < 10 ) then
              if Wave[ i + 1, j + 1 ] = 0 then Wave[ i + 1, j + 1 ] := k + 1;
            if ( j mod 2 <> 0 ) and ( i > 0 ) then
              if Wave[ i - 1, j + 1 ] = 0 then Wave[ i - 1, j + 1 ] := k + 1;
          end;
          bool := True;
        end;
    k := k + 1;
  until ( k >= r ) or ( bool = False );
end;

//==============================================================================
procedure CreateWave( x1, y1, r : integer; Fly : boolean );
var
  i, j : integer;
begin
  if ( x1 < 0 ) or ( x1 > 10 ) or ( y1 < 0 ) or ( y1 > 8 ) then Exit;

  for j := 0 to 8 do
    for i := 0 to 10 do
      Wave[ i, j ] := 0;

  if Fly = True then
  begin
    Wave[ x1, y1 ] := 1;
    FillWave( 100 );
  end;

  for i := 0 to Arena.CreaturesCnt - 1 do
    with Arena.Creatures[ i ] do
    begin
      if State <> CS_DIE then Wave[ TX, TY ] := -Arena.Creatures[ i ].PlayerN;
    end;

  for i := 0 to Arena.BlocksCnt - 1 do
    Wave[ Arena.Blocks[ i ].X, Arena.Blocks[ i ].Y ] := -3;

  Wave[ x1, y1 ] := 1;

  if Fly = True then Exit;

  FillWave( r );
end;

//==============================================================================
procedure CreatePath( Creature : TCreature; x2, y2 : integer );
var
  k     : integer;
  bool  : boolean;
begin
  if ( x2 < 0 ) or ( x2 > 10 ) or ( y2 < 0 ) or ( y2 > 8 ) then Exit;
  if Wave[ x2, y2 ] <= 1 then Exit;

  with Creature do
  begin
    if Pat.CanFly = True then
    begin
      PathLen := 2;
      SetLength( PathX, 2 );
      SetLength( PathY, 2 );
      PathX[ 0 ] := TX;
      PathY[ 0 ] := TY;
      PathX[ 1 ] := x2;
      PathY[ 1 ] := y2;
      Exit;
    end;
    PathLen := Wave[ x2, y2 ];
    SetLength( PathX, PathLen );
    SetLength( PathY, PathLen );
    PathX[ PathLen - 1 ] := x2;
    PathY[ PathLen - 1 ] := y2;
    k := PathLen - 1;
  end;

  repeat
    bool := False;

    if y2 > 0 then
    begin
      if Wave[ x2, y2 - 1 ] = k then
      begin
        y2    := y2 - 1;
        bool  := True;
      end;
      if ( y2 mod 2 = 0 ) and ( x2 < 10 ) and ( bool = False ) then
        if Wave[ x2 + 1, y2 - 1 ] = k then
        begin
          y2    := y2 - 1;
          x2    := x2 + 1;
          bool  := True;
        end;
      if ( y2 mod 2 <> 0 ) and ( x2 > 0 ) and ( bool = False ) then
        if Wave[ x2 - 1, y2 - 1 ] = k then
        begin
          y2    := y2 - 1;
          x2    := x2 - 1;
          bool  := True;
        end;
    end;
    if y2 < 8 then
    begin
      if ( Wave[ x2, y2 + 1 ] = k ) and ( bool = False ) then
      begin
        y2    := y2 + 1;
        bool  := True;
      end;
      if ( y2 mod 2 = 0 ) and ( x2 < 10 ) and ( bool = False ) then
        if Wave[ x2 + 1, y2 + 1 ] = k then
        begin
          y2    := y2 + 1;
          x2    := x2 + 1;
          bool  := True;
        end;
      if ( y2 mod 2 <> 0 ) and ( x2 > 0 ) and ( bool = False ) then
        if Wave[ x2 - 1, y2 + 1 ] = k then
        begin
          y2    := y2 + 1;
          x2    := x2 - 1;
          bool  := True;
        end;
    end;

    if ( x2 > 0 ) and ( bool = False ) then
      if Wave[ x2 - 1, y2 ] = k then
      begin
        x2    := x2 - 1;
        bool  := True;
      end;
    if ( x2 < 10 ) and ( bool = False ) then
      if Wave[ x2 + 1, y2 ] = k then
      begin
        x2 := x2 + 1;
      end;

    k := k - 1;
    Creature.PathX[ k ] := x2;
    Creature.PathY[ k ] := y2;
  until k = 0;
end;

//==============================================================================
function Wave_GetNear( x1, y1 : integer; nt : byte ): integer;
var
  x2, y2 : integer;
begin
  Result := 0;
  if ( x1 < 0 ) or ( x1 > 10 ) or ( y1 < 0 ) or ( y1 > 8 ) then Exit;
  x2 := x1;
  y2 := y1;
  if nt = W_R then x2 := x2 + 1;
  if nt = W_L then x2 := x2 - 1;
  if ( nt = W_RD ) or ( nt = W_LD ) then
  begin
    y2 := y2 + 1;
    if ( y1 mod 2 = 0 ) and ( nt = W_RD ) then x2 := x2 + 1;
    if ( y1 mod 2 <> 0 ) and ( nt = W_LD ) then x2 := x2 - 1;    
  end;
  if ( nt = W_LU ) or ( nt = W_RU ) then
  begin
    y2 := y2 - 1;
    if ( y1 mod 2 = 0 ) and ( nt = W_RU ) then x2 := x2 + 1;
    if ( y1 mod 2 <> 0 ) and ( nt = W_LU ) then x2 := x2 - 1;    
  end;

  if ( x2 < 0 ) or ( x2 > 10 ) or ( y2 < 0 ) or ( y2 > 8 ) then Exit;
  Result := Wave[ x2, y2 ];
end;

end.
