Program MapMaker;

uses Exec, graphics, Intuition, Utility,vartags;


{
    Patrick Quaid.
    This program just draws a blocky map from straight overhead,
then repeatedly splits each block into four parts and adjusts the
elevation of each of the parts until it gets down to one pixel per
block.  It ends up looking something like a terrain map.  It's kind
of a fractal thing, but not too much.  Some program a long time ago
inspired this, but I apologize for forgetting which one.  As I
recall, that program was derived from Chris Gray's sc.
    Once upon a time I was thinking about writing an overblown
strategic conquest game, and this was the first stab at a map
maker.  The maps it produces look nifty, but have no sense of
geology so they're really not too useful for a game.
    When the map is finished, press the left button inside the
window somewhere and the program will go away.
}

{
    Changed the source to 2.0+.
    12 May 1998.

    Translated to FPC. This was one of the first
    program I tried with fpc, just to check that
    the amiga units worked.
    08 Aug 1998.

    Changed to use TAGS.
    01 Nov 1998.

    nils.sjoholm@mailbox.swipnet.se
}

const
    MinX = 0;
    MaxX = 320;
    MinY = 0;
    MaxY = 200;

type
    MapArray = array [MinX .. MaxX - 1, MinY .. MaxY - 1] of Longint;

VAR
    average,x,y,
    nextx,nexty,count1,
    skip,level    : Longint;
    rp            : pRastPort;
    vp            : Pointer;
    s             : pScreen;
    w             : pWindow;
    m             : pMessage;
    Map           : MapArray;
    Quit          : Boolean;
    i             : Longint;

Function FixX(x : Longint): Longint;
begin
    if x < 0 then
    FixX := x + MaxX
    else if x >= MaxX then
    FixX := x mod MaxX
    else
    FixX := x;
end;

Function FixY(y : Longint) : Longint;
begin
    if x < 0 then
    FixY := y + MaxY
    else if x >= MaxY then
    FixY := y mod MaxY
    else
    FixY := y;
end;

Procedure DrawMap;
begin
    if skip = 1 then begin
    for x := MinX to MaxX - 1 do begin
        for y := MinY to MaxY - 1 DO begin
        if Map[x,y] < 100 then begin
            SetAPen(rp, 0);
            i := WritePixel(rp, x, y)
        end else begin
            average := (Map[x,y] - 100) DIV 6 + 1;
            if average > 15 then
            average := 15;
            SetAPen(rp, average);
            i := WritePixel(rp, x, y)
        end
        end
    end
   end else begin
    x := MinX;
    while x < MaxX do begin
        y := MinY;
        while y < MaxY do begin
        if Map[x,y] < 100 then begin
            SetAPen(rp, 0);
            RectFill(rp,x,y,x + skip - 1,y + skip - 1)
        end else begin
            average := (Map[x,y] - 100) DIV 6 + 1;
            if average > 15 then
            average := 15;
            SetAPen(rp,average);
            RectFill(rp,x,y,x + skip - 1,y + skip - 1);
        end;
        y := y + skip;
        end;
        x := x + skip;
    end;
    end;
end;

Function Min(x,y : Longint) : Longint;
begin
    if x < y then
    Min := x
    else
    Min := y;
end;

Function Max(x,y : Longint) : Longint;
begin
    if x > y then
    Max := x
    else
    Max := y;
end;


Function Height(x,y : Longint) : Longint;
begin
    Height := Map[x,y] div 32;
end;

Procedure ChangeDelta(var d : Longint);
begin
    case Random(100) of
      51..75   : if d < 1 then
             Inc(d);
      76..100  : if d > -1 then
             Dec(d);
    end;
end;

Procedure MakeRivers;
var
    i    : Longint;
    x,y,
    dx,dy  : Longint;
    OK   : Boolean;
    LastHeight : Longint;
    count1      : Longint;
    cx,cy      : Longint;
    Search     : Longint;
    CheckHeight : Longint;
begin
    SetAPen(rp, 16);

    for cx := 0 to 319 do begin
    for cy := 0 to 199 do begin
        if (Map[cx,cy] > 153) and (Map[cx,cy] < 162) and
           (Random(100) < 3) then begin

        x := cx;
        y := cy;

        dx := 0;
        dy := 0;
        while (dx = 0) and (dy = 0) do begin
            dx := Random(2) - 1;
            dy := Random(2) - 1;
        end;

        OK := True;

        count1 := 0;
        while OK do begin
            LastHeight := Map[x,y]; { Height(x,y); }
            Map[x,y] := 0;
            i := WritePixel(rp, x, y);

            CheckHeight := -6;
            Search := 0;
            repeat
                repeat
                ChangeDelta(dx);
                ChangeDelta(dy);
                until (dx <> 0) or (dy <> 0);
            Inc(Search);
            if (Map[FixX(x + dx), FixY(y + dy)] > 0) and
                         {  (Height(FixX(x + dx), FixY(y + dy)) < CheckHeight) then begin }
               (Map[FixX(x + dx), FixY(y + dy)] < (LastHeight + CheckHeight)) then begin
                x := FixX(x + dx);
                y := FixY(y + dy);
                Search := 0;
            end else if Search > 200 then begin
                if CheckHeight < 6 then begin
                Inc(CheckHeight,2);
                Search := 1;
                end else begin
                Search := 0;
                OK := False;
                end;
            end;
            until Search = 0;

            Inc(count1);
            if count1 > 150 then
            OK := False;
            if Map[x,y] < 100 then
            OK := False;
        end;
        end;
    end;
    end;
end;

Procedure MakeMap;
begin

    rp:= w^.RPort;
    vp:= ViewPortAddress(w);

    SetRGB4(vp, 0, 0, 0, 12); { Ocean Blue }
    SetRGB4(vp, 1, 1, 1, 0);
    SetRGB4(vp, 2, 0, 3, 0);
    SetRGB4(vp, 3, 0, 4, 0); { Dark Green }
    SetRGB4(vp, 4, 0, 5, 0);
    SetRGB4(vp, 5, 1, 6, 0);
    SetRGB4(vp, 6, 2, 8, 0); { Medium Green }
    SetRGB4(vp, 7, 4, 10, 0);
    SetRGB4(vp, 8, 6, 10, 0);
    SetRGB4(vp, 9, 9, 9, 0); { Brown }
    SetRGB4(vp, 10, 8, 8, 0);
    SetRGB4(vp, 11, 7, 7, 0); { Dark Brown }
    SetRGB4(vp, 12, 10, 10, 0); { Dark Grey }
    SetRGB4(vp, 13, 10, 10, 10);
    SetRGB4(vp, 14, 12, 12, 12);
    SetRGB4(vp, 15, 14, 14, 15); { White }
    SetRGB4(vp, 16, 0, 0, 10);   { River blue }

    Randomize; { Seed the Random Number Generator }

    level := 7;
    skip  := 16;

    y := MinY;
    while y < MaxY do begin
    x := MinX;
    while x < MaxX do begin
        Map[x,y] := Random(220);
        x := x + skip;
    end;
    y := y + skip;
    end;

    DrawMap;

    for level := 2 to 5 do begin
    skip := skip DIV 2;
    y := MinY;
    while y < MaxY do begin
        if (y MOD (2*skip)) = 0 then
        nexty := skip * 2
        else
        nexty:=skip;
        x := MinX;
        while x < MaxX do begin
        if (x MOD (2*skip)) = 0 then
            nextx := skip * 2
        else
            nextx := skip;
        if (nextx = skip * 2) AND (nexty = skip * 2) then begin
            average := Map[x,y] * 5;
            count1 := 9;
        end else begin
            average := 0;
            count1 := 4;
        end;
        if (nextx = skip * 2) then begin
            average := average + Map[x,FixY(y - skip)];
            average := average + Map[x,FixY(y + nexty)];
            count1 := count1 + 2;
        end;
        if (nexty = skip * 2) then begin
            average := average + Map[FixX(x - skip),y];
            average := average + Map[FixX(x + nextx),y];
            count1 := count1 + 2;
        end;
        average := average + Map[FixX(x-skip),FixY(y-skip)]
                   + Map[FixX(x-nextx),FixY(y+nexty)]
                   + Map[FixX(x+skip),FixY(y-skip)]
                   + Map[FixX(x+nextx),FixY(y+nexty)];
        average := (average DIV count1) +
                (Random(4) - 2) * (9 - level);
        case Average of
          150..255 : Average := Average + 2;
          100..149 : Inc(Average);
        else
            Average := Average - 3;
        end;
        if average < 0 then
            average := 0;
        if average > 220 then
            average := 220;
        Map[x,y] := average;

        x := x + skip;
        end;
        m := GetMsg(w^.UserPort);
        if m <> Nil then begin
        Quit := True;
        Exit;
        end;
        y := y + skip;
    end;
    DrawMap;
    end;
    MakeRivers;
end;

begin
    GfxBase := OpenLibrary(GRAPHICSNAME,0);
    if GfxBase <> nil then begin

    s := OpenScreenTagList(NIL, TAGS(
                           SA_Left,      0,
                           SA_Top,       0,
                           SA_Width,     320,
                           SA_Height,    200,
                           SA_Depth,     5,
                           SA_DetailPen, 3,
                           SA_BlockPen,  2,
                           SA_Type,      CUSTOMSCREEN_f,
                           TAG_END));

    

    if s <> NIL then begin

        w := OpenWindowTagList(NIL, TAGS(
        WA_IDCMP,        IDCMP_MOUSEBUTTONS,
        WA_Left,         MinX,
        WA_Top,          MinY,
        WA_Width,        MaxX,
        WA_Height,       MaxY,
        WA_MinWidth,     50,
        WA_MinHeight,    20,
        WA_Borderless,   ltrue,
        WA_BackDrop,     ltrue,
        WA_SmartRefresh, ltrue,
        WA_Activate,     ltrue,
        WA_CustomScreen, longint(s),
        TAG_END));

        

        IF w <> NIL THEN begin
        Quit := False;
        ShowTitle(s, 0);
        MakeMap;
        if not Quit then
            m := WaitPort(w^.UserPort);
        Forbid;
        repeat
            m := GetMsg(w^.UserPort);
        until m = nil;
        CloseWindow(w);
        Permit;
        end else
        writeln('Could not open the window.');
        CloseScreen(s);
    end else
        writeln('Could not open the screen.');
    CloseLibrary(GfxBase);
    end else writeln('no graphics.library');
end.



