{***********************************************************

Project:    C-evo External Map Generator
Copyright:  1999-2023 P Blackman
License:    GPLv3+

Routines for defining the coastal area
Sea tiles within 2 tiles of land, need to be set as coast

***********************************************************}


procedure tMap.GetNeighbour(Ww, Hh, N: Integer; out W, H: Integer);
var O: Integer;
begin
    O := Integer(NOT odd(Hh)); { Even rows need an offset }

    H := Hh;
    W := Ww;

    case N of
        1: H := H-2;
        2: begin
            H := pred(H);
            W := pred(W) + O;
        end;
        3: begin
            H := pred(H);
            W := W + O;
        end;
        4: W := pred(W);
        5: W := succ(W);
        6: begin
            H := succ(H);
            W := pred(W) + O;
        end;
        7: begin
            H := succ(H);
            W := W + O;
        end;
        8: H := H+2;
    end;
    W := WrapCheck(W);
end;


function tMap.Isolated(W, H: Integer): Boolean;
var T, Wt, Ht: Integer;
    SingleTile: Boolean;
begin
    SingleTile := True;
    for T := 1 to 8 do
    begin
        GetNeighbour(W, H, T, Wt, Ht);

        { Check if this Tile actually on the Map? }
        if (Ht >= 1) AND (Ht <= Height) then
            if (GetTerrain(Wt, Ht) <> Ocean) then
                SingleTile := False;
    end;
    Result := SingleTile;
end;


procedure tMap.CullSingleTileIslands;
var W, H, I : Integer;
begin
    I := 0;
    for W := 1 to Width do
        for H := 1 to Height do
            if GetTerrain(W, H) <> Ocean then
                if Isolated(W, H) then
                begin
                    SetTerrain(W, H, Ocean, False);
                    Inc (I);
                end;
end;


{-------------------------------------------------------------------------------}
{ Switch Ocean tiles within two tiles of land to Coast                          }

function tMap.CoastTarget(W, H: Integer; C: Boolean): Boolean;
var T: tTerrain;
begin
    T := GetTerrain(W, H);

    if C then
        if (T <> Ocean) AND (T <> Coast) then
            { Land Tile, so orignal Tile should switch }
            Result := True
        else
            Result := False
    else
        { If Coast Tile, orignal Tile should switch }
        Result := Tiles[W, H].InnerCoast;
end;


procedure tMap.CheckNearest(Ww, Hh: Integer; C: Boolean);
var W, H, T: Integer;
begin
    for T := 1 to 8 do
    begin
        GetNeighbour(Ww, Hh, T, W, H);

        { Check if this Tile actually on the Map? }
        if (H >= 1) AND (H <= Height) then
            { If so, is it a target for change? }
            if CoastTarget(W, H, C) then
            begin
                { If so, change start tile }
                if C then
                    Tiles[Ww, Hh].InnerCoast := True
                else
                    Tiles[Ww, Hh].OuterCoast := True;
            end;
    end;
end;


procedure tMap.DoInnerCoast;
var W, H: Integer;
begin
    for W := 1 to Width do
        for H := 1 to Height do
            if GetTerrain(W, H) = Coast then
                Tiles[W, H].InnerCoast := True
            else
            if GetTerrain(W, H) = Ocean then
                CheckNearest(W, H, True);
end;

procedure tMap.DoOuterCoast;
var W, H: Integer;
begin
    for W := 1 to Width do
        for H := 1 to Height do
            if GetTerrain(W, H) = Ocean then
                CheckNearest(W, H, False);

    for W := 1 to Width do
        for H := 1 to Height do
            if Tiles[W, H].InnerCoast OR Tiles[W, H].OuterCoast then
                Tiles[W, H].Terrain := Coast;
end;
