/where.pas
program Where;
uses Apricot, GfxManager, CBI, GfxText, Music, Util, GameData;

var i: Word;
    bg, img1, img2, img3: ChunkedBitmapImage;
    tmp: String;

procedure FadeOut;
var a, i, j: Word;
    p: PWord;
begin
    for i := 0 to 14 do begin
        a := NOT (1 SHL i);
        p := @charmem;
        for j := 0 to 2048 do begin
            p^ := p^ AND a;
            Inc(p);
            a := (a SHL 1) OR 1;
            if a = $FFFF then
                a := $FFFE;
        end;
    end;
    for i := 0 to 1249 do
        charTable[i] := CHAR_BLACK;
end;

{ this will also destroy any font characters being displayed }
procedure WindowBlindReset;
var i, j, k: Word;
    pattern: Word;
    p, q: ^Word;
begin
    pattern := $1111;
    for i := 0 to 2 do begin
        p := @chartable;
        for j := 0 to 1250 do begin
            q := Ptr(0, p^ SHL 5);
            for k := 0 to 31 do begin
                q^ := q^ AND (NOT pattern);
                Inc(q);
            end;
            Inc(p);
        end;
        pattern := pattern OR (pattern SHL 1);
        Delay50(1);
    end;
    p := @charTable;
    for i := 0 to 1250 do begin
        p^ := CHAR_BLACK;
        Inc(p);
    end;
end;

procedure BlankReset;
var i: Word;
begin
    for i := 0 to 1249 do
        charTable[i] := CHAR_BLACK;
end;

procedure CheckerboardReset;
var i: Word;
begin
    for i := 0 to 2500 do
        charTable[LfsrShift mod 1250] := CHAR_BLACK;
    for i := 0 to 1249 do
        charTable[i] := CHAR_BLACK;
end;

function StdTextBox(const s: String): Char;
begin
    TextBox(4, 19, 46, 24, s);
    StdTextBox := ReadKey;
end;

procedure FlyAway(c: City);
begin
    gs.currentCity := c;
    DisposeCBI(bg);
    CheckerboardReset;
    StopMusic(false);
    gfxman.Reset;
    LoadCBI('airplane.cbi', img1);
    SfxTakeoff;
    DisplayCBI(img1, 7, 3);
    Delay50(90);
    DisposeCBI(img1);
    BlankReset;
    gfxman.Reset;
    LoadCBI(cityBackgrounds[c] + '.cbi', bg);
    DisplayCBI(bg, 0, 0);
    StopMusic(false);
    LoadMusic(citySongs[c] + '.sn');
    musicPlaying := true;
end;

procedure OpeningScene;
var st: Word;
begin
    CheckerboardReset;
    gfxman.Init;
    LoadCBI('desk.cbi', bg);
    DisplayCBI(bg, 0, 0);
    DebugOut('Randomizing game');
    RandomizeGame;
    StdTextBox('Aaaah, time to sit down and play one of my favorite games, ' +
        gameName[gs.game] + '.');
    TextBox(4, 19, 46, 24, 'Wait... where is it? I''m sure I left it over here.');
    st := gfxman.SaveTop;
    LoadCBI('owl1.cbi', img1);
    ReadKey;
    DisplayCBI(img1, 6, 2);
    DisposeCBI(img1);
    gfxman.RestoreTop(st);
    StdTextBox('HOOOOT!');
    StdTextBox('Oh no, not you again! You took my disk, didn''t you! You always take '
        + 'my games and fly all over the world!');
    StdTextBox('And then I have to fly after you and solve a series of geographical '
        + 'knowledge puzzles to find you!');
    StdTextBox('HOOOOT!');
    DisplayCBI(bg, 0, 0);
    StdTextBox('Ah, he left a note... "See you in ' + cityName[gs.currentCity] + ', sucker!"');
    StdTextBox('That is one very rude bird.');
end;

procedure CaughtHim;
begin
    StdTextBox('Hey you! Wait right there!');
    gs.progress := gs.progress + 1;
end;

procedure AskAround;
var savedScreen: PGfxTableArray;
    st: Word;
    nstr: String[2];
    clue: PClueStr;
begin
    if EndGame then begin
        CaughtHim;
        Exit;
    end;
    savedScreen := SaveScreen;
    st := gfxman.SaveTop;
    Str(gs.path[gs.progress].person, nstr);
    LoadCBI('person' + nstr + '.cbi', img1);
    Box(4, 4, 20, 15);
    DisplayCBI(img1, 5, 5);
    DisposeCBI(img1);
    gfxman.RestoreTop(st);
    clue := GetTalkClue;
    StdTextBox(clue^);
    RestoreScreen(savedScreen);
    gs.hours := gs.hours + 1;
end;

procedure Research;
var clue: PClueStr;
begin
    if EndGame then begin
        CaughtHim;
        Exit;
    end;
    clue := GetResearchClue;
    if clue <> nil then
        StdTextBox('You research the whereabouts of the owl. ' + clue^)
    else
        StdTextBox('You try to do some research but you don''t find anything.');
    gs.hours := gs.hours + 2;
end;

Procedure Look;
var clue: PClueStr;
begin
    if EndGame then begin
        CaughtHim;
        Exit;
    end;
    DisplayCBI(bg, 0, 0);
    ReadKey;
    clue := GetLookClue;
    if clue <> nil then
        StdTextBox('You look around for a bit and find ' + clue^ + '.');
    gs.hours := gs.hours + 1;
end;

procedure TravelMenu;
var i: Integer;
    c: City;
    k: Char;
    savedScreen: PGfxTableArray;
begin
    savedScreen := SaveScreen;
    TextBox(1, 7, 22, 22, 'Select Destination');
    for c := Low(City) to High(City) do begin
        i := Ord(c);
        WriteLine(2, 10 + i, Char($30 + i) + ') ' + cityName[c], 20);
    end;
    WriteLine(2, 21, 'X) Exit', 20);
    k := ReadKey;
    if (k >= #$30) AND (k < #$3A) then begin
        i := Integer(k);
        c := City(i - $30);
        Dispose(savedScreen);
        FlyAway(c);
        Exit;
    end;
    RestoreScreen(savedScreen);
    Dispose(savedScreen);
end;

procedure Dream;
var c: City;
begin
    StdTextBox('ZZZZZZzzzzzzz.....');
    if (Random(20) = 0) AND (gs.progress < gs.totalCities - 1) then begin
        c := gs.path[gs.progress + 1].city;
        StdTextBox('A terrible bird haunts your dreams. ' +
            'Flying. Clawing. Hooting. But you fight him off, and as ' +
            'he flies away, you look around.');
        StdTextBox('"This is ' + cityName[c] +
            '! That ' + #$1B#$1C#$1D#$1E + ' owl is in ' + cityName[c] + '!"');
    end;
    gs.hours := gs.hours + 8;
end;

procedure AskQuit;
var k: Char;
begin
    k := StdTextBox('Are you sure you want to let that bird get away? y/N');
    if (k = 'y') or (k = 'Y') then
        Halt(0);
end;

function GameTime: String;
var d, h: Word;
    s: String[2];
begin
    d := (gs.hours div 24) mod 7;
    h := gs.hours mod 24;
    Str(h:2, s);
    if h < 10 then
        s[1] := '0';
    GameTime := days[d] + ' ' + s + ':00';
end;

procedure CityMenu;
var i: Integer;
    k: Char;
    s: String[50];
    time: String[9];
label rekey;
begin
    FillChar(s, SizeOf(s), ' ');
    time := GameTime;
    Move(time[1], s[42], 9);
    s[0] := #50;
    WriteLine(0, 0, s, 50);
    TextRegion(0, 0, 40, 1, cityDetail[gs.currentCity] + ', ' + cityName[gs.currentcity] + ', ' +
         cityCountry[gs.currentCity]);
    TextBox(4, 19, 46, 24, 'What would you like to do?' + #13#13 +
        '[A]sk Around  [R]esearch  [L]ook' + #13 +
        '[T]ravel      [S]leep     [Q]uit');
    rekey:
    k := ReadKey;
    case k of
        'a', 'A': AskAround;
        'r', 'R': Research;
        'l', 'L': Look;
        't', 'T': TravelMenu;
        's', 'S': Dream;
        'q', 'Q': AskQuit;
        '!': begin
            DisplayCBI(bg, 0, 0);
            DumpGameState;
            ReadKey;
        end;
    else
        Goto rekey;
    end;
end;

procedure Ending;
begin
    StopMusic(false);
    LoadMusic('fly2moon.sn');
    musicPlaying := true;
    DisposeCBI(bg);
    CheckerboardReset;
    gfxman.Reset;
    LoadCBI('ending.cbi', bg);
    DisplayCBI(bg, 0, 0);
    StdTextBox('The owl seems to smile as he hands you a note with his claw.');
    StdTextBox('"Ha ha! You caught me. I didn''t really want to play your copy of ' +
        gameName[gs.game] + '. I don''t even have opposable thumbs!');
    StdTextBox('But I hope ' +
        'you learned a bit about world geography and history along the way. ' +
        'Well anyway, here you go."');
    StdTextBox('The owl drops your floppy disk and flies off.');
    StdTextBox('He... didn''t even want to play it? ' +
        'I''ve charged thousands of dollars on hotels and flights!');
    StdTextBox('If only I''d made a backup copy...');
    StdTextBox('THE END' + #13#13#13 + 'Final time: ' + GameTime);
end;

begin
    BlankReset;
    ScreenMode(ScreenModeGfx);
    LoadFont('font.bin');
    WriteLine(0, 24, 'Loading...', 50);
    LoadCBI('title.cbi', bg);
    DisplayCBI(bg, 0, 0);
    LoadMusic('quickie.sn');
    musicPlaying := true;
    WriteLine(0, 24, 'Press any key...', 50);
    ReadKey;
    DisposeCBI(bg);

    OpeningScene;
    FlyAway(gs.currentCity);

    repeat
        CityMenu;
        ProcessGameLogic;
    until gs.progress = gs.totalCities;

    Ending;

    ScreenMode(ScreenModeText);
end.