

{

  Pacman X
  Just like Pacman only... more fun... 
  Hey, you can always cheat by changing the code :)
  08/16/01

  Justin: http://www.homelessinsane.com
  Antti: http://www.htk.fi/public/akirjavainen

  Code modified by Antti Kirjavainen in 2003 - 2004.

}


unit UnitMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Menus, ScktComp, MPlayer, MMSystem;

const
        tmr1Val = 200;
        ENTER = #13 + #10;
        SOUND_COMPLETE = 'complete.wav';
        SOUND_DRUGEND = 'drugstop.wav';
        SOUND_DEAD = 'dead.wav';
        SOUND_PLUP = 'plup.wav';
        MUSIC_INTRO = 'intro.mid';
        POS_OFFLEVEL = -100;
        POS_OFFLEVEL2 = -1000;
        SCORE_EXTRALIFE = 5000;


type
  TBlock = record
    mType: Word; // 0 = wall, 1 = meatball, 2 = drug, 3 = blank, 4 = jail entrance
  end;

  TPacMan = record
    mX: Integer;
    mY: Integer;  
    StartX: Integer;
    StartY: Integer;
    Direction: Integer; // 0 = left, 2 = down, 4 = right, 6 = up
    State: Integer; // 0 = mouth closed, 1 = mouth open
    Drugged: Boolean;
    DruggedTime: TTime;
  end;
  
  TGhoul = record
    mX: Integer;
    mY: Integer;  
    Direction: Integer; // 0 = left, 2 = down, 4 = right, 6 = up
    FreshRedirect: Boolean;
    Jailed: Boolean;
    JailedTime: TTime;
  end;

  TfrmMain = class(TForm)
    Image1: TImage;
    Timer1: TTimer;
    Image2: TImage;
    TimerGhoul: TTimer;
    ImageLogo: TImage;
    MainMenu1: TMainMenu;
    LoadLevel1: TMenuItem;
    od: TOpenDialog;
    sckServer: TServerSocket;
    sckClient: TClientSocket;
    mnuSingle: TMenuItem;
    mnuHost: TMenuItem;
    mnuJoin: TMenuItem;
    N1: TMenuItem;
    N2: TMenuItem;
    mnuExit: TMenuItem;
    mnuDisconnect: TMenuItem;
    mnuChat: TMenuItem;
    N3: TMenuItem;
    txtChat: TMemo;
    mnuMultiplayer: TMenuItem;
    mnuSoundMenu: TMenuItem;
    mnuSounds: TMenuItem;
    mnuMusic: TMenuItem;
    mnuHelp: TMenuItem;
    mnuAbout: TMenuItem;
    mpSound: TMediaPlayer;
    mpMusic: TMediaPlayer;
    tmrMusic: TTimer;                                          
    mnuClearChat: TMenuItem;
    mnuStop: TMenuItem;
    N4: TMenuItem;
    tmrShowScores: TTimer;
    mnuSingle2: TMenuItem;
    mnuGame: TMenuItem;
    mnuSingle3: TMenuItem;
    mnuSingle4: TMenuItem;
    Image3: TImage;
    Image4: TImage;
    mnuSingle5: TMenuItem;
    sckMID: TClientSocket;
    tmrMID: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);
    procedure TimerGhoulTimer(Sender: TObject);
    procedure LoadLevel1Click(Sender: TObject);
    procedure sckServerClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure mnuSingleClick(Sender: TObject);
    procedure mnuHostClick(Sender: TObject);
    procedure mnuJoinClick(Sender: TObject);
procedure SendCommand(cmdCommand : String);
procedure SendLevel(LevelFile : String);
procedure SaveLevel(LevelData : String; FileName : String);
procedure ProcessCommand(cmdCommand : String; cmdParameter : String);
    procedure sckClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure sckServerClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
procedure ParseData(const dData : String);
function Split2Params(const dData: String; const dPosition: Integer): String;
    procedure sckClientRead(Sender: TObject; Socket: TCustomWinSocket);

    procedure AppException(Sender: TObject; E: Exception);
    procedure sckClientConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure mnuExitClick(Sender: TObject);
    procedure mnuDisconnectClick(Sender: TObject);
    procedure mnuChatClick(Sender: TObject);
    procedure mnuSoundsClick(Sender: TObject);
    procedure mnuMusicClick(Sender: TObject);
procedure PlaySound(FileName : String);
procedure PlayMusic(FileName : String);
    procedure tmrMusicTimer(Sender: TObject);
    procedure mnuClearChatClick(Sender: TObject);
procedure ResetVariables;
    procedure tmrShowScoresTimer(Sender: TObject);
    procedure sckServerClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure sckClientError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure Disconnect(SocketDisconnect : Boolean);
    procedure txtChatChange(Sender: TObject);
    procedure mnuSingle2Click(Sender: TObject);
    procedure mnuStopClick(Sender: TObject);
    procedure mnuSingle3Click(Sender: TObject);
    procedure mnuGameClick(Sender: TObject);
    procedure mnuSingle4Click(Sender: TObject);
    procedure mnuSingle5Click(Sender: TObject);
procedure EnableDisableEpisodes(const sEnable: Boolean);
procedure GhostsToJail();
procedure CheckLives();
procedure GiveExtraLife();
procedure CleanHall();
    procedure sckMIDConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure tmrMIDTimer(Sender: TObject);

  private
    Server : Boolean;
    NetworkGame : Boolean;
    ClientConnected : Boolean;

    Playing: Boolean;
    GameOver: Boolean; 

    UseSkin: Boolean;
    CustomLevel: Boolean;
    
    Score: Integer;
    Score2: Integer;
    LastLifeGivenScore: Integer;
    Level: Integer; 
    Lives: Integer;
    Lives2: Integer;
    JailX: Integer;
    JailY: Integer;

    ClientHandle : Integer;

    InfoY: Integer;
    InfoCurrentY: Integer;

    LastKey: Word;
    EpisodeText : String;
    LevelText : String;
    curMusic : String;
    Loading : Boolean;
    ImmediateMove: Boolean;
    DownloadLevel: String;

    WorkCanvas: TCanvas;

    PacMan: TPacMan;
    PacMan2: TPacMan;
    Ghoul: Array[0..3] of TGhoul;
    
    Grid: Array[0..19, 0..19] of TBlock;
    Area: TRect;

    HallOfFame: TStringList;
    
    function GetBlockRect(n, n2: Integer): TRect;
    procedure DrawIt(Sender: TObject; var Done: Boolean);
    procedure LoadLevel(const CustomFile: String = '');
    procedure AddToHall(sScore: Integer; s: String);

    function Ghoul_Look(i: Integer): Integer;
    procedure Ghoul_ChangeDirection(i, dontgo: Integer);

    function iif(cExpression: Boolean; const TruePart, FalsePart: Integer): Integer;
  public                       
    { Public declarations }
  end;

const  
  BlockWidth = 20;
  BlockHeight = 20;

var
  frmMain: TfrmMain;
  lastAddress: String;
  AppPath : String;
  LevelPath : String;
  SoundPath : String;
  MusicPath : String;
  onLinux: Boolean;
  procedure LoadLastAddress();
  procedure SaveLastAddress();

implementation

{$R *.dfm}

procedure LoadLastAddress();
var
        sFile: TStringList;

begin
try
sFile := TStringList.Create();
if (FileExists(AppPath + 'network.dat')) then begin
                                                sFile.LoadFromFile(AppPath + 'network.dat');
                                                if (sFile.Count >= 1) then lastAddress := sFile.Strings[0] else lastAddress := ''; 
                                                end
                                                else begin
                                                lastAddress := '';
                                                end;

finally
        sFile.Free();
end;
end;

procedure SaveLastAddress();
var
        sFile: TStringList;

begin
try
sFile := TStringList.Create();
sFile.Text := lastAddress;
sFile.SaveToFile(AppPath + 'network.dat'); 

finally
        sFile.Free();
end;
end;

function TfrmMain.iif(cExpression: Boolean; const TruePart, FalsePart: Integer): Integer;
begin
  if cExpression then
    Result := TruePart
  else
    Result := FalsePart;
end;

function TfrmMain.GetBlockRect(n, n2: Integer): TRect;
begin
  Result := Rect(Area.Left + (BlockWidth * n), Area.Top + (BlockHeight * n2), (Area.Left + (BlockWidth * n)) + BlockWidth, (Area.Top + (BlockHeight * n2)) + BlockHeight)
end;

procedure TfrmMain.AddToHall(sScore: Integer; s: String);
var
  n, nTemp: Integer;
  sBool: Boolean;
begin

DrawIt(frmMain, sBool);
if (sScore = 0) then exit;

try
  with HallofFame do begin

if (Count = 0) then begin
        	    if (Length(s) <= 0) then begin
        	     			     if InputQuery('Hall of Fame', 'You''ve made the Hall of Fame!  What''s your name?', s) then begin
                                        					                                                         SendCommand('HALL ' + s + ' ' + IntToStr(sScore) + ENTER);
                                        					                                                         Insert(0, s + ' - ' + IntToStr(sScore));
                                        					                                                         exit;
                                                                                                                                         end;
                                             end
                                             else begin
                                             Insert(0, s + ' - ' + IntToStr(sScore));
                                             exit;
                                             end;
                     end;


for n := 0 to Count - 1 do begin
      nTemp := pos('-', Strings[n]);
      if sScore > StrToInt(Trim(copy(Strings[n], nTemp+1, length(Strings[n])-nTemp))) then begin
        if (Length(s) <= 0) then begin
                                 if InputQuery('Hall of Fame', 'You''ve made the Hall of Fame!  What''s your name?', s) then begin
                                                                                                            SendCommand('HALL ' + s + ' ' + IntToStr(sScore) + ENTER);
                                                                                                            Insert(n, s + ' - ' + IntToStr(sScore));
                                                                                                            CleanHall();
                                                                                                            exit;
                                                                                                            end;
                                 end
                                 else begin
                                 Insert(n, s + ' - ' + IntToStr(sScore));
                                 CleanHall();
                                 exit;
                                 end;
                                 end;
end;

if (Count < 10) then begin
        	    if (Length(s) <= 0) then begin
        	     			     if InputQuery('Hall of Fame', 'You''ve made the Hall of Fame!  What''s your name?', s) then begin
                                        					                                                         SendCommand('HALL ' + s + ' ' + IntToStr(sScore) + ENTER);
                                        					                                                         Add(s + ' - ' + IntToStr(sScore));
                                        					                                                         exit;
                                                                                                                                         end;
                                             end
                                             else begin
                                             Add(s + ' - ' + IntToStr(sScore));
                                             exit;
                                             end;
                     end;

CleanHall();
  end;

except
end;
end;

procedure TfrmMain.CleanHall();
var
        n: Integer;

begin
with HallofFame do begin

if (Count) > 10 then begin
                     for n := Count - 1 downto 10 do begin
                         Delete(n);
                     end;
                     end;

end;
end;

function TfrmMain.Ghoul_Look(i: Integer): Integer;
var
  lookX, lookY: Integer;
begin
  Result := 0;


  // left
  lookX := Ghoul[i].mX;
  lookY := Ghoul[i].mY;
  repeat
    dec(lookX);
    if (PacMan.mX = lookX) and (PacMan.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 1, 3);
      Exit;
    end;
    if (PacMan2.mX = lookX) and (PacMan2.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 1, 3);
      Exit;
    end;
  until (Grid[lookX, lookY].mType = 0) or (lookX < low(Grid));

  
  // down 
  lookX := Ghoul[i].mX;
  lookY := Ghoul[i].mY;
  repeat
    inc(lookY);
    if (PacMan.mX = lookX) and (PacMan.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 2, 4);
      Exit;
    end;
    if (PacMan2.mX = lookX) and (PacMan2.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 2, 4);
      Exit;
    end;
  until (Grid[lookX, lookY].mType = 0) or (lookY > high(Grid[0]));


  // right
  lookX := Ghoul[i].mX;
  lookY := Ghoul[i].mY;
  repeat
    inc(lookX);
    if (PacMan.mX = lookX) and (PacMan.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 3, 1);
      Exit;
    end;
    if (PacMan2.mX = lookX) and (PacMan2.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 3, 1);
      Exit;
    end;
  until (Grid[lookX, lookY].mType = 0) or (lookX > high(Grid));


  // up 
  lookX := Ghoul[i].mX;
  lookY := Ghoul[i].mY;
  repeat
    dec(lookY);
    if (PacMan.mX = lookX) and (PacMan.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 4, 2);
      Exit;
    end;
    if (PacMan2.mX = lookX) and (PacMan2.mY = lookY) then begin
      Result := iif(not Pacman.Drugged, 4, 2);
      Exit;
    end;
  until (Grid[lookX, lookY].mType = 0) or (lookX < low(Grid[0]));

end;

procedure TfrmMain.Ghoul_ChangeDirection(i, dontgo: Integer);
begin
  // remember, if pacman is drugged, the ghouls run away
  case Round(Random * 3) of
  0: begin
    // start rotating at left (counter-clockwise)
    if (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 4) and (dontgo <> 0) then
      Ghoul[i].Direction := 0 
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 4) and (dontgo <> 1) then   
      Ghoul[i].Direction := 1
    else if (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 4) and (dontgo <> 2) then   
      Ghoul[i].Direction := 2 
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 4) and (dontgo <> 3) then   
      Ghoul[i].Direction := 3 
  end;
  1: begin
    // start rotating at right (counter-clockwise) 
    if (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 4) and (dontgo <> 2) then
      Ghoul[i].Direction := 2
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 4) and (dontgo <> 3) then   
      Ghoul[i].Direction := 3 
    else if (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 4) and (dontgo <> 0) then   
      Ghoul[i].Direction := 0
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 4) and (dontgo <> 1) then   
      Ghoul[i].Direction := 1
  end;
  2: begin
    // start rotating at top (clockwise) 
    if (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 4) and (dontgo <> 3) then
      Ghoul[i].Direction := 3
    else if (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 4) and (dontgo <> 2) then   
      Ghoul[i].Direction := 2 
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 4) and (dontgo <> 1) then   
      Ghoul[i].Direction := 1
    else if (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 4) and (dontgo <> 0) then   
      Ghoul[i].Direction := 0
  end;
  3: begin
    // start rotating at bottom (clockwise) 
    if (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY+1].mType <> 4) and (dontgo <> 1) then
      Ghoul[i].Direction := 1
    else if (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX-1, Ghoul[i].mY].mType <> 4) and (dontgo <> 0) then   
      Ghoul[i].Direction := 0 
    else if (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 0) and (Grid[Ghoul[i].mX, Ghoul[i].mY-1].mType <> 4) and (dontgo <> 2) then   
      Ghoul[i].Direction := 3
    else if (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 0) and (Grid[Ghoul[i].mX+1, Ghoul[i].mY].mType <> 4) and (dontgo <> 3) then   
      Ghoul[i].Direction := 2
  end;
  end;

  Ghoul[i].FreshRedirect := True;
end;

procedure TfrmMain.EnableDisableEpisodes(const sEnable: Boolean);
begin
   mnuSingle.Enabled := sEnable;
   mnuSingle2.Enabled := sEnable;
   mnuSingle3.Enabled := sEnable;
   mnuSingle4.Enabled := sEnable;
   mnuSingle5.Enabled := sEnable;
end;

procedure TfrmMain.LoadLevel(const CustomFile: String = '');
var
  n, n2: Integer;
  s: String;
begin          


  UseSkin := True;
   Pacman.mX := POS_OFFLEVEL;
   Pacman.mY := POS_OFFLEVEL;
   Pacman2.mX := POS_OFFLEVEL;
   Pacman2.mY := POS_OFFLEVEL;


  // setup blocks
  with TStringList.Create() do
  try
    if (CustomLevel) and (FileExists(CustomFile)) then
    begin
    if Server then begin
                   Loading := True;
                   Playing := False;
                   SendCommand('LEVEL ' + ExtractFileName(CustomFile) + ENTER);
                   end;
   Self.Refresh;
   Lives := 5;
   Lives2 := 5;
   Score := 0;
   Score2 := 0;
   LastLifeGivenScore := 0;

   tmrShowScores.Tag := 0;
   tmrShowScores.Enabled := True;
   EpisodeText := 'Custom';
   LevelText := UpperCase(ExtractFilename(CustomFile));
   EnableDisableEpisodes(False);
   PlayMusic(ChangeFileExt(ExtractFileName(CustomFile), '.mid'));
   if not NetworkGame then Self.Caption := 'Pacman X';
   LoadFromFile(CustomFile);



    end else if (FileExists(LevelPath + 'level' + IntToStr(Level) + '.pml')) and (not CustomLevel) then
    begin
    if Server then begin
                   Loading := True;
                   Playing := False;
                   SendCommand('LEVEL ' + IntToStr(Level) + ENTER);
                   end;
    SendCommand('SCORE ' + IntToStr(Score) + ENTER);
    Self.Refresh;

    tmrShowScores.Tag := 0;
    tmrShowScores.Enabled := True;
    LevelText := copy(IntToStr(Level), 2, 2);
    
    // In a single player game, give one extra life to player at halfways on the episode.
    // It would be TOO hard, almost impossible to complete the game otherwise, believe me! 
    if not NetworkGame then begin
                            if (LevelText = '10') then Lives := Lives + 1;
                            end;


    LevelText := 'Level: ' + LevelText;
    EnableDisableEpisodes(False);
    PlayMusic('level' + IntToStr(Level) + '.mid');
    LoadFromFile(LevelPath + 'level' + IntToStr(Level) + '.pml');


    end else begin
       if CustomLevel then
      begin
       InfoY := Area.Bottom;
       EpisodeText := '';
       LevelText := '';
       Playing := False;
       GameOver := True;
       mnuStop.Enabled := False;
       EnableDisableEpisodes(True);
       if NetworkGame then begin
                           SendCommand('SCORE ' + IntToStr(Score) + ENTER + 'WONGAME 1' + ENTER);
                           if Server then Self.Caption := 'Pacman X: Network game with ' + sckServer.Socket.Connections[0].RemoteAddress else Self.Caption := 'Pacman X: Network game with ' + sckClient.Socket.RemoteAddress;
                           end
                           else begin
                           Caption := 'You have completed the level';
                           end;

     end else begin // Customlevel = False
       if NetworkGame then begin
                           if Server then Self.Caption := 'Pacman X: Network game with ' + sckServer.Socket.Connections[0].RemoteAddress else Self.Caption := 'Pacman X: Network game with ' + sckClient.Socket.RemoteAddress;
                           end
                           else begin
                           Caption := 'You have completed the episode!';
                           end;

       EpisodeText := '';
       LevelText := '';
       mnuStop.Enabled := False;
       EnableDisableEpisodes(True);

       InfoY := Area.Bottom;
       Playing := False;
       GameOver := True;
       Score := Score + (Lives * 200);
       SendCommand('SCORE ' + IntToStr(Score) + ENTER + 'WONGAME 1' + ENTER);
       AddToHall(Score, '');
      end;
      Exit;
    end;

    for n2 := low(Grid[0]) to high(Grid[0]) do // y
      for n := low(Grid) to high(Grid) do // x   
      begin
        s := Copy(Strings[n2], n + 1, 1);  
        

        if s = 'a' then // ghoul 0 start
        begin
          Grid[n, n2].mType := 3;
          Ghoul[0].mX := n;
          Ghoul[0].mY := n2; 
          Ghoul[0].Direction := 2;
          Ghoul[0].FreshRedirect := False;
          Ghoul[0].Jailed := True;
          Ghoul[0].JailedTime := Time;

          JailX := n;
          JailY := n2;
        end else if s = 'b' then // ghoul 1 start
        begin
          Grid[n, n2].mType := 3;
          Ghoul[1].mX := n;
          Ghoul[1].mY := n2;  
          Ghoul[1].Direction := 2; 
          Ghoul[1].FreshRedirect := False; 
          Ghoul[1].Jailed := True;
          Ghoul[1].JailedTime := Time;
        end else if s = 'c' then // ghoul 2 start
        begin
          Grid[n, n2].mType := 3;
          Ghoul[2].mX := n;
          Ghoul[2].mY := n2; 
          Ghoul[2].Direction := 2; 
          Ghoul[2].FreshRedirect := False;
          Ghoul[2].Jailed := True;
          Ghoul[2].JailedTime := Time;
        end else if s = 'd' then // ghoul 3 start
        begin
          Grid[n, n2].mType := 3;
          Ghoul[3].mX := n;
          Ghoul[3].mY := n2;
          Ghoul[3].Direction := 2; 
          Ghoul[3].FreshRedirect := False;
          Ghoul[3].Jailed := True;
          Ghoul[3].JailedTime := Time;
        end else if s = 'w' then // jail entrance
        begin
          Grid[n, n2].mType := 4;
        end else if (s = 'p') then begin // pacman start position
          Grid[n, n2].mType := 3;
          Pacman.Drugged := False;
          Pacman2.Drugged := False;
          if (Lives > 0) then begin
                              Pacman.mX := n;
                              Pacman.mY := n2;
                              Pacman.Direction := 0;
                              Pacman.StartX := n;
                              Pacman.StartY := n2;
                              Pacman.State := 1;
                              end
                              else begin
                              Pacman.mX := POS_OFFLEVEL;
                              Pacman.mY := POS_OFFLEVEL;
                              Pacman.StartX := POS_OFFLEVEL;
                              Pacman.StartY := POS_OFFLEVEL;
                              end;

          if (NetworkGame) and (Lives2 > 0) then begin
                                Pacman2.mX := Pacman.StartX;
                                Pacman2.mY := Pacman.StartY;
                                Pacman2.Direction := 0;
                                Pacman2.StartX := Pacman.StartX;
                                Pacman2.StartY := Pacman.StartY;
                                Pacman2.State := 1;
                                end
                                else begin // Dead don't play
                                Pacman2.mX := POS_OFFLEVEL;
                                Pacman2.mY := POS_OFFLEVEL;
                                Pacman2.StartX := POS_OFFLEVEL;
                                Pacman2.StartY := POS_OFFLEVEL;
                                end;
        end else begin
          Grid[n, n2].mType := StrToInt(s);
        end;
      end;
  finally
    Free();
  end;
Self.Refresh();
if (Server) then SendCommand('READY 1' + ENTER);
end;

procedure TfrmMain.DrawIt(Sender: TObject; var Done: Boolean);
var
  n, n2: Integer;
  AreThereMeatballs: Boolean;
  r: TRect;
begin
  Done := False;
  Sleep(100); // re-draw every one tenth of a second

  if (Loading) then begin
                    Self.Refresh();
                    WorkCanvas.Brush.Color := clBlack;
                    WorkCanvas.FillRect(Area);
                    WorkCanvas.TextOut((Area.Right div 2) - 20, (Area.Bottom div 2) - 20, 'Loading...');
                    Canvas.CopyRect(Area, WorkCanvas, Area);
                    exit;
                    end;

  if (Playing) then
  begin
  
    // check to see if drug time is over
    if Pacman.Drugged then
      if Pacman.DruggedTime < Time - StrToTime('12:00:07 AM') then
      begin
        PlaySound(SOUND_DRUGEND);
        Pacman.Drugged := False;
        Timer1.Interval := tmr1Val;
        UseSkin := True;
      end else if Pacman.DruggedTime < Time - StrToTime('12:00:05 AM') then // flash
      begin
        UseSkin := not UseSkin;
      end;

    ////////////////////////////////////////////////////////////////////////////
    // drawing
  
    AreThereMeatballs := False;
    for n2 := low(Grid[0]) to high(Grid[0]) do // y
      for n := low(Grid) to high(Grid) do // x
      begin
        if (Grid[n, n2].mType = 1) or (Grid[n, n2].mType = 2) then
          AreThereMeatballs := True;
        
        r := GetBlockRect(n, n2);
        StretchBlt(WorkCanvas.Handle, r.Left, r.Top, BlockWidth, BlockHeight, iif(UseSkin, Image1.Canvas.Handle, Image2.Canvas.Handle), Grid[n, n2].mType * 20, 0, 20, 20, SRCCOPY);
      end;
    
    if not AreThereMeatballs then begin
      Pacman.Drugged := True;
      if NetworkGame then begin
                          if not Server then exit;
                          end;
      curMusic := MUSIC_INTRO;
      Inc(Level, 1);
      LoadLevel();
      PlaySound(SOUND_COMPLETE);
    end;

    // draw Pacman with different colors to network game:
    if not (NetworkGame) then begin
    StretchBlt(WorkCanvas.Handle, Pacman.mX * BlockWidth, Pacman.mY * BlockHeight, BlockWidth, BlockHeight,
              iif(UseSkin, Image1.Canvas.Handle, Image2.Canvas.Handle), (Pacman.Direction + Pacman.State) * 20, 20, 20, 20, SRCCOPY);
                        StretchBlt(WorkCanvas.Handle, Pacman2.mX * BlockWidth, Pacman2.mY * BlockHeight, BlockWidth, BlockHeight,
                                iif(UseSkin, Image3.Canvas.Handle, Image4.Canvas.Handle), (Pacman2.Direction + Pacman2.State) * 20, 20, 20, 20, SRCCOPY);
    end
    else begin
    if not (Server) then begin
                StretchBlt(WorkCanvas.Handle, Pacman.mX * BlockWidth, Pacman.mY * BlockHeight, BlockWidth, BlockHeight,
                        iif(UseSkin, Image3.Canvas.Handle, Image4.Canvas.Handle), (Pacman.Direction + Pacman.State) * 20, 20, 20, 20, SRCCOPY);
                                        StretchBlt(WorkCanvas.Handle, Pacman2.mX * BlockWidth, Pacman2.mY * BlockHeight, BlockWidth, BlockHeight,
                                                iif(UseSkin, Image1.Canvas.Handle, Image2.Canvas.Handle), (Pacman2.Direction + Pacman2.State) * 20, 20, 20, 20, SRCCOPY);
                         end
                         else begin
                                StretchBlt(WorkCanvas.Handle, Pacman.mX * BlockWidth, Pacman.mY * BlockHeight, BlockWidth, BlockHeight,
                                        iif(UseSkin, Image1.Canvas.Handle, Image2.Canvas.Handle), (Pacman.Direction + Pacman.State) * 20, 20, 20, 20, SRCCOPY);
                                StretchBlt(WorkCanvas.Handle, Pacman2.mX * BlockWidth, Pacman2.mY * BlockHeight, BlockWidth, BlockHeight,
                                        iif(UseSkin, Image3.Canvas.Handle, Image4.Canvas.Handle), (Pacman2.Direction + Pacman2.State) * 20, 20, 20, 20, SRCCOPY);
                         end;
    end;

    // draw those damn ghosts
    for n := low(Ghoul) to high(Ghoul) do
      StretchBlt(WorkCanvas.Handle, Ghoul[n].mX * BlockWidth, Ghoul[n].mY * BlockHeight, BlockWidth, BlockHeight,
                 iif(UseSkin, Image1.Canvas.Handle, Image2.Canvas.Handle), n * 20, 40, 20, 20, SRCCOPY);

    // now paint onto the form
    Canvas.CopyRect(Area, WorkCanvas, Area);
  
  end else begin // playing = false
    InfoCurrentY := InfoY;

    WorkCanvas.Brush.Color := clBlack;
    WorkCanvas.FillRect(Area);

    WorkCanvas.Draw((Area.Right div 2) - (ImageLogo.Width div 2), InfoCurrentY, ImageLogo.Picture.Bitmap);
    InfoCurrentY := InfoCurrentY + ImageLogo.Height + 10;

    WorkCanvas.Font.Name := 'Terminal';
    WorkCanvas.Font.Size := 10;
    WorkCanvas.Font.Color := clWhite;

    with TStringList.Create() do
    try
      Text := 'Pacman X (v2.2)' + ENTER +
              ENTER +
              'http://www.homelessinsane.com' + ENTER +
              'http://www.htk.fi/public/akirjavainen' + ENTER +
              ENTER +
              'This one is dedicated to Kylen,' + ENTER +
              'the cool girl who always plays my games' + ENTER +
              'I never got into Pacman myself,' + ENTER +
              'I always got too freaked out trying to' + ENTER +
              'stay away from the monsters.' + ENTER +
              ENTER +
              'Hall of Fame' + ENTER +
              HallofFame.Text + 
              ENTER +
              'Controls:' + ENTER +
              'Use arrow keys to move' + ENTER +
              'Use "p" to pause' + ENTER +
              'Press "x" if your losing' + ENTER +
              ENTER +
              'Press 1 to start the first episode.' + ENTER +
              'Press 2 to start the second episode.' + ENTER +
              'Press 3 to start the third episode.' + ENTER +
              'Press 4 to start the fourth episode.' + ENTER +
              'Press 5 to start the fifth episode.' + ENTER
              + ENTER
              + ENTER
              + ENTER
              + ENTER +
              'Credits:' + ENTER + ENTER +
              'Game programming:' + ENTER +
              'Justin Tunney' + ENTER
              + ENTER +
              'Graphics:' + ENTER +
              'Justin Tunney' + ENTER
              + ENTER +
              'Game design:' + ENTER +
              'Justin Tunney' + ENTER
              + ENTER +
              'Network game:' + ENTER +
              'Antti Kirjavainen' + ENTER
              + ENTER +
              'Sounds & Music:' + ENTER +
              'See MIDI-files for more info' + ENTER +
              ENTER +
              'Level design:' + ENTER +
              'Antti Kirjavainen' + ENTER +
              'Justin Tunney' + ENTER +
              'Mikko Kirjavainen' + ENTER +
              'Veli-Matti Kokkala' + ENTER +
              ENTER +
              'Level Editor improvements:' + ENTER +
              'Antti Kirjavainen' + ENTER
              + ENTER;

      for n := 0 to Count - 1 do
      begin
        WorkCanvas.TextOut((Area.Right div 2) - (WorkCanvas.TextWidth(Strings[n]) div 2), InfoCurrentY, Strings[n]);
        InfoCurrentY := InfoCurrentY + WorkCanvas.TextHeight('X');
      end;
    finally
      Free();
    end;

    if InfoCurrentY < 0 then
      InfoY := Area.Bottom
    else
      InfoY := InfoY - 3;

    // now paint onto the form
    Canvas.CopyRect(Area, WorkCanvas, Area);
  end;


    // draw the score
    Canvas.Font.Color := clYellow;
    Canvas.TextOut(Area.Right + 3, 0, 'Score: ' + IntToStr(Score));
    Canvas.TextOut(Area.Right + 3, 15, 'Lives: ' + IntToStr(Lives));

    if NetworkGame then begin
                        Canvas.TextOut(Area.Right + 3, 370, 'Score: ' + IntToStr(Score2));
                        Canvas.TextOut(Area.Right + 3, 385, 'Lives: ' + IntToStr(Lives2));
                        end;
    Canvas.TextOut(Area.Right + 3, 180, EpisodeText);
    Canvas.TextOut(Area.Right + 3, 195, LevelText);
end;

////////////////////////////////////////////////////////////////////////////////

procedure TfrmMain.FormCreate(Sender: TObject);
var
  workDC: HDC;
  bmp: HBitmap;
  n: Integer;
begin
Application.OnException := AppException;
AppPath := ExtractFilePath(Application.ExeName);
LevelPath := AppPath + 'Levels\';
SoundPath := AppPath + 'Sounds\';
MusicPath := AppPath + 'Music\';

if (Pos('-linux', LowerCase(CMDLine)) > 0) then onLinux := True else onLinux := False;
if (onLinux) then begin
		  tmrMIDTimer(Self);
		  tmrMID.Enabled := True;
                  Self.Caption := 'Pacman X for Linux';
                  Self.Height := 500;
		  end;

  PlayMusic(MUSIC_INTRO);
  Randomize();

  // set down the thread priority so this application doesn't lag others
  // *** IF IT RUNS CHOPPY DELETE THIS LINE ***

  // *********************************
  // *** Well it DID run choppy :) ***
  // *********************************

  //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);


  // set draw loop thing
  Application.OnIdle := DrawIt;

  // setup rects     
  Area := Rect(0, 0, length(Grid) * BlockWidth, length(Grid[0]) * BlockHeight); 

  // setup workcanvas
  WorkCanvas := TCanvas.Create(); 
  workDC := CreateCompatibleDC(Canvas.Handle);
  bmp := CreateCompatibleBitmap(Canvas.Handle, Area.Right, Area.Bottom);
  SelectObject(workDC, bmp);
  WorkCanvas.Handle := workDC;

  // load Hall of Fame
try
  HallofFame := TStringList.Create();
  with HallofFame do begin
    if FileExists(AppPath + 'halloffame.dat') then LoadFromFile(AppPath + 'halloffame.dat');
    CleanHall();
  end;
except
end;

  LastKey := 0;
  ImmediateMove := True;

  UseSkin := True;
  CustomLevel := False;
  
  InfoY := Area.Bottom;
  Playing := False;
  GameOver := True;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
var
	strFile: TStringList;

begin
  try
	HallofFame.SaveToFile(AppPath + 'halloffame.dat');
  	HallofFame.Free();
  	WorkCanvas.Free();

  	if (onLinux) then begin
                          if (sckMID.Socket.Connected) then sckMID.Socket.SendText('exit' + ENTER);
			  end;
  except
  end;
end;

procedure TfrmMain.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = 'p') and (not GameOver) then
  begin
    Playing := not Playing;
    if Playing then SendCommand('PAUSE 1' + ENTER) else SendCommand('PAUSE 0' + ENTER);
  end else if (Key = '1') and (GameOver) then
  begin
  if NetworkGame then begin
                      if not Server then exit;
                      if not ClientConnected then exit;
                      end;
    if not (FileExists(LevelPath + 'level101.pml')) then begin
                                                              SendCommand('ERROR LEVEL' + ENTER);
                                                              MessageDlg('Level file not found!', mtError, [mbOK], 0);
                                                              exit;
                                                              end;

   if not NetworkGame then Self.Caption := 'Pacman X';
    Level := 101;
    EpisodeText := 'Episode I';
    Lives := 5;
    Lives2 := 5;
    Score := 0;
    Score2 := 0;
   LastLifeGivenScore := 0;
  EnableDisableEpisodes(False);
mnuStop.Enabled := True;

    CustomLevel := False;
    GameOver := False;
    Playing := True;
    LoadLevel();
  end else if (Key = '2') and (GameOver) then
  begin
  if NetworkGame and not Server then exit;
    if not (FileExists(LevelPath + 'level201.pml')) then begin
                                                              SendCommand('ERROR LEVEL' + ENTER);
                                                              MessageDlg('Level file not found!', mtError, [mbOK], 0);
                                                              exit;
                                                              end;
   if not NetworkGame then Self.Caption := 'Pacman X';
    Level := 201;
    EpisodeText := 'Episode II';
    Lives := 5;
    Lives2 := 5;
    Score := 0;
    Score2 := 0;
    LastLifeGivenScore := 0;
    EnableDisableEpisodes(False);
    mnuStop.Enabled := True;
    CustomLevel := False;
    GameOver := False;
    Playing := True;
    LoadLevel();
  end else if (Key = '3') and (GameOver) then
  begin
  if NetworkGame and not Server then exit;
    if not (FileExists(LevelPath + 'level301.pml')) then begin
                                                              SendCommand('ERROR LEVEL' + ENTER);
                                                              MessageDlg('Level file not found!', mtError, [mbOK], 0);
                                                              exit;
                                                              end;
   if not NetworkGame then Self.Caption := 'Pacman X';
    Level := 301;
    EpisodeText := 'Episode III';
    Lives := 5;
    Lives2 := 5;
    Score := 0;
    Score2 := 0;
    LastLifeGivenScore := 0;
    EnableDisableEpisodes(False);
    mnuStop.Enabled := True;
    CustomLevel := False;
    GameOver := False;
    Playing := True;
    LoadLevel();
  end else if (Key = '4') and (GameOver) then
  begin
  if NetworkGame and not Server then exit;
    if not (FileExists(LevelPath + 'level401.pml')) then begin
                                                              SendCommand('ERROR LEVEL' + ENTER);
                                                              MessageDlg('Level file not found!', mtError, [mbOK], 0);
                                                              exit;
                                                              end;
   if not NetworkGame then Self.Caption := 'Pacman X';
    Level := 401;
    EpisodeText := 'Episode IV';
    Lives := 5;
    Lives2 := 5;
    Score := 0;
    Score2 := 0;
    LastLifeGivenScore := 0;
    EnableDisableEpisodes(False);
    mnuStop.Enabled := True;
    CustomLevel := False;
     GameOver := False;
    Playing := True;
   LoadLevel();
  end else if (Key = '5') and (GameOver) then
  begin
  if NetworkGame and not Server then exit;
    if not (FileExists(LevelPath + 'level501.pml')) then begin
                                                              SendCommand('ERROR LEVEL' + ENTER);
                                                              MessageDlg('Level file not found!', mtError, [mbOK], 0);
                                                              exit;
                                                              end;
   if not NetworkGame then Self.Caption := 'Pacman X';
    Level := 501;
    EpisodeText := 'Episode V';
    Lives := 5;
    Lives2 := 5;
    Score := 0;
    Score2 := 0;
    LastLifeGivenScore := 0;
    EnableDisableEpisodes(False);
    mnuStop.Enabled := True;
    CustomLevel := False;
     GameOver := False;
    Playing := True;
   LoadLevel();
  end else if Key = 'x' then
  begin
    ShowMessage('Gummo''s Secret Strategy' + #13 +
                'and you thought you''d get a cheat...' + #13 +
                #13 + 
                'The ghouls are programmed to just move around' + #13 +
                'They look down hallways all the time for you' + #13 +
                'but they don''t know where you are if they can''t see' + #13 +
                'you.  A ghoul will continue to the end of a hallway' + #13 + 
                'unless it sees you.');
  end;
end;

procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
// Dead players don't move:
  if (Lives <= 0) then exit;

  LastKey := Key;

  // It was so damn slow, if this line was enabled:
  //if ImmediateMove then
    Timer1Timer(Timer1);
end;

procedure TfrmMain.Timer1Timer(Sender: TObject);
var
  n: Integer;
begin
  if (GameOver) or (not Playing) then
    Exit;

  if LastKey = 0 then
  begin
    ImmediateMove := True;
    Exit;
  end;

  ImmediateMove := False;
                     
  if Pacman.State = 0 then
    Pacman.State := 1
  else
    Pacman.State := 0;
      
  if LastKey = VK_LEFT then
  begin       
    Pacman.Direction := 0;

    if (Grid[Pacman.mX-1, Pacman.mY].mType <> 0) or (Pacman.mX-1 < low(Grid)) then
      Pacman.mX := Pacman.mX - 1;

    if Pacman.mX < low(Grid) then
      Pacman.mX := high(Grid);


  end else if LastKey = VK_DOWN then
  begin           
    Pacman.Direction := 2;

    if (Grid[Pacman.mX, Pacman.mY+1].mType <> 0) or (Pacman.mY+1 > high(Grid[0])) then
      Pacman.mY := Pacman.mY + 1;

    if Pacman.mY > high(Grid[0]) then
      Pacman.mY := low(Grid[0]);


  end else if LastKey = VK_RIGHT then
  begin             
    Pacman.Direction := 4;

    if (Grid[Pacman.mX+1, Pacman.mY].mType <> 0) or (Pacman.mX+1 > high(Grid)) then
      Pacman.mX := Pacman.mX + 1;

    if Pacman.mX > high(Grid) then
      Pacman.mX := low(Grid);


  end else if LastKey = VK_UP then
  begin             
    Pacman.Direction := 6;

    if (Grid[Pacman.mX, Pacman.mY-1].mType <> 0) or (Pacman.mY-1 < low(Grid[0])) then
      Pacman.mY := Pacman.mY - 1;

    if Pacman.mY < low(Grid[0]) then
      Pacman.mY := high(Grid[0]);



  end;

  case Grid[Pacman.mX, Pacman.mY].mType of
    1: begin // meatball
      Score := Score + 1;
      SendCommand('EAT ' + IntToStr(Pacman.mX) + ' ' + IntToStr(Pacman.mY) + ENTER);
      Grid[Pacman.mX, Pacman.mY].mType := 3;
      GiveExtraLife();


    end;
    2: begin // drug
      SendCommand('DRUG ' + IntToStr(Pacman.mX) + ' ' + IntToStr(Pacman.mY) + ENTER);
      PlaySound(SOUND_PLUP);
      Grid[Pacman.mX, Pacman.mY].mType := 3;
      Pacman.Drugged := True;
      Pacman.DruggedTime := Time;
      UseSkin := False;
      Score := Score + 1;
      Timer1.Interval := 150;
      GiveExtraLife();
    end;
  end;
  
  for n := low(Ghoul) to high(Ghoul) do
    if (Ghoul[n].mX = Pacman.mX) and (Ghoul[n].mY = Pacman.mY) then
      if Pacman.Drugged then begin
        Score := Score + 50;
        SendCommand('EATGHOUL ' + IntToStr(n) + ' 0' + ENTER);
        PlaySound(SOUND_PLUP);
        Ghoul[n].mX := POS_OFFLEVEL2;
        Ghoul[n].mY := POS_OFFLEVEL2;
        Ghoul[n].Jailed := True;
        Ghoul[n].JailedTime := Time;
      GiveExtraLife();
      end else begin    
        Lives := Lives - 1;
        SendCommand('LIVES ' + IntToStr(Lives) + ENTER + 'DEAD 0' + ENTER);
        PlaySound(SOUND_DEAD);
        GhostsToJail();

        Pacman.mX := Pacman.StartX;
        Pacman.mY := Pacman.StartY;
        CheckLives();

    // Was the second player on a ghost?
    if (Ghoul[n].mX = Pacman2.mX) and (Ghoul[n].mY = Pacman2.mY) and (NetworkGame) and (Lives2 > 0) then begin
        if (Pacman.Drugged) then begin
        SendCommand('EATGHOUL ' + IntToStr(n) + ' 1' + ENTER);
        PlaySound(SOUND_PLUP);
        Ghoul[n].mX := POS_OFFLEVEL2;
        Ghoul[n].mY := POS_OFFLEVEL2;
        Ghoul[n].Jailed := True;
        Ghoul[n].JailedTime := Time;
        end
        else begin
        GhostsToJail();
        Pacman2.mX := Pacman.StartX;
        Pacman2.mY := Pacman.StartY;
        SendCommand('YOURDEAD 1' + ENTER);
        PlaySound(SOUND_DEAD);
        end;
        end;

  end;
      
  LastKey := 0;
SendCommand('PACMAN ' + IntToStr(Pacman.mX) + ' ' + IntToStr(Pacman.mY) + ' ' + IntToStr(Pacman.Direction) + ' ' + IntToStr(Pacman.State) + ENTER);



end;


procedure TfrmMain.PlaySound(FileName : String);
begin
if not mnuSounds.Checked then exit;

FileName := SoundPath + FileName;
if not FileExists(FileName) then begin
                                 exit;
                                 end;

try
        sndPlaySound(PChar(FileName), SND_NODEFAULT Or SND_ASYNC);
        //mpSound.Close;
except
end;

{
try
        mpSound.FileName := FileName;
        mpSound.Open;
        mpSound.Stop;
        mpSound.Play;
except
end;
}
end;


procedure TfrmMain.PlayMusic(FileName : String);
var
        rndNumber : Integer;
        rndNumber2 : Integer;
	strFile : TStringList;

begin
tmrMusic.Enabled := False;
if not mnuMusic.Checked then exit;

curMusic := FileName;

// If level music not found, select a random song:
FileName := MusicPath + FileName;
if not FileExists(FileName) then begin
                                 Randomize;
                                 rndNumber := Random(20) + 1;
                                 Randomize;
                                 rndNumber2 := Random(4) + 1;
                                 if (Length(IntToStr(rndNumber)) = 2) then FileName := MusicPath + 'level' + IntToStr(rndNumber2) + IntToStr(rndNumber) + '.mid' else FileName := MusicPath + 'level' + IntToStr(rndNumber2) + '0' + IntToStr(rndNumber) + '.mid';
                                 if not FileExists(FileName) then exit;
                                 curMusic := 'level' + IntToStr(rndNumber) + '.mid';
                                 end;


if (onLinux) then begin
                  if not (sckMID.Socket.Connected) then exit;
                  sckMID.Socket.SendText('Music/' + curMusic + ENTER);
                  //MCISendString(PChar('stop ' + FileName), nil, 0, 0);
		  //MCISendString(PChar('play ' + FileName), nil, 0, 0);
		  exit;
                  end;

try
        mpMusic.Filename := FileName;
        mpMusic.Open;
        mpMusic.Stop;
        mpMusic.Play;
        tmrMusic.Interval := (mpMusic.Length * 100) + 1000;
        tmrMusic.Enabled := True;
except
end;
end;

procedure TfrmMain.TimerGhoulTimer(Sender: TObject);
var
  n, nTemp: Integer;
  sI : Integer;
  eI : Integer;

begin
  if (GameOver) or (not Playing) then
    Exit;

   (**************************

>>> one word: seek and destroy <<<

    **************************)

  // this ai is programmed so that the ghosts just blob around and
  // are constantly looking down the hallways.  if they see Pacman
  // (that handsome devil...), they will chase him.




// ---------------------------- Network Ghosts -------------------
// Client moves ghosts 2 & 3, server moves 0 & 1.
// All the ghosts chase both players.

if NetworkGame then begin
                    if Server then begin
                                   sI := 0;
                                   eI := 1;
                                   end
                                   else begin
                                   sI := 2;
                                   eI := 3;
                                   end;
                    end
                    else begin
                    sI := low(Ghoul);
                    eI := high(Ghoul);
                    end;  

  for n := sI to eI do
  begin  
    // free them from jail
    if Ghoul[n].Jailed then
      if Ghoul[n].JailedTime <= Time - StrToTime('12:00:01 AM') then begin
                                                                     if (Ghoul[n].mX < 0) or (Ghoul[n].mY < 0) then begin
                                                                                                                    Ghoul[n].mX := JailX;
                                                                                                                    Ghoul[n].mY := JailY;
                                                                                                                    end;
                                                                     end;

      if Ghoul[n].JailedTime < Time - StrToTime('12:00:05 AM') then Ghoul[n].Jailed := False;
  
    nTemp := Ghoul_Look(n);
    if not Ghoul[n].FreshRedirect then
      if nTemp <> 0 then
        Ghoul[n].Direction := nTemp - 1; // i see him!

    Ghoul[n].FreshRedirect := False;
    
    case Ghoul[n].Direction of
      0: begin // left
        if Ghoul[n].mX-1 < low(Grid) then
        begin
          Ghoul[n].mX := high(Grid);
        end else if Grid[Ghoul[n].mX-1, Ghoul[n].mY].mType = 0 then
        begin
          Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4);
        end else if Grid[Ghoul[n].mX-1, Ghoul[n].mY].mType = 4 then
        begin
          if Ghoul[n].Jailed then
            Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4)
          else
            dec(Ghoul[n].mX);
        end else begin
          dec(Ghoul[n].mX);
        end;
      end;
      1: begin // bottom
        if Ghoul[n].mY+1 > high(Grid[0]) then
        begin
          Ghoul[n].mY := low(Grid[0]);
        end else if Grid[Ghoul[n].mX, Ghoul[n].mY+1].mType = 0 then
        begin
          Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4);
        end else if Grid[Ghoul[n].mX, Ghoul[n].mY+1].mType = 4 then
        begin
          if Ghoul[n].Jailed then
            Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4)
          else
            inc(Ghoul[n].mY);
        end else begin
          inc(Ghoul[n].mY);
        end;
      end;
      2: begin // right
        if Ghoul[n].mX+1 > high(Grid) then
        begin
          Ghoul[n].mX := low(Grid);
        end else if Grid[Ghoul[n].mX+1, Ghoul[n].mY].mType = 0 then
        begin       
          Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4);  
        end else if Grid[Ghoul[n].mX+1, Ghoul[n].mY].mType = 4 then
        begin    
          if Ghoul[n].Jailed then
            Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4)
          else
            inc(Ghoul[n].mX);
        end else begin
          inc(Ghoul[n].mX);
        end;
      end;
      3: begin // top
        if Ghoul[n].mY-1 < low(Grid[0]) then
        begin

          // Fixed a bug here, original code was "Ghoul[n].mX := high(Grid[0]);".
          // Caused the ghosts to go to the upper right corner, but now fixed with this:
          Ghoul[n].mY := 19;

        end else if Grid[Ghoul[n].mX, Ghoul[n].mY-1].mType = 0 then
        begin
          Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4);
        end else if Grid[Ghoul[n].mX, Ghoul[n].mY-1].mType = 4 then
        begin
          if Ghoul[n].Jailed then
            Ghoul_ChangeDirection(n, (0 - (nTemp - 1)) + 4)
          else  
            dec(Ghoul[n].mY);
        end else begin
          dec(Ghoul[n].mY);
        end;
      end;
    end;

    // Was the second player on a ghost?
    if (Ghoul[n].mX = Pacman2.mX) and (Ghoul[n].mY = Pacman2.mY) and (NetworkGame) and (Lives2 > 0) then begin
        if (Pacman.Drugged) then begin
        SendCommand('EATGHOUL ' + IntToStr(n) + ' 1' + ENTER);
        Ghoul[n].mX := POS_OFFLEVEL2;
        Ghoul[n].mY := POS_OFFLEVEL2;
        Ghoul[n].Jailed := True;
        Ghoul[n].JailedTime := Time;
        PlaySound(SOUND_PLUP);
        end
        else begin
        GhostsToJail();
        Pacman2.mX := Pacman.StartX;
        Pacman2.mY := Pacman.StartY;
        SendCommand('YOURDEAD 1' + ENTER);
        PlaySound(SOUND_DEAD);
        end;
        end;

    // did he eat Pacman
    if (Ghoul[n].mX = Pacman.mX) and (Ghoul[n].mY = Pacman.mY) and (Lives > 0) then
      if Pacman.Drugged then begin
        SendCommand('EATGHOUL ' + IntToStr(n) + ' 0' + ENTER);
        Score := Score + 50;
        Ghoul[n].mX := POS_OFFLEVEL2;
        Ghoul[n].mY := POS_OFFLEVEL2;
        Ghoul[n].Jailed := True;
        Ghoul[n].JailedTime := Time;
        PlaySound(SOUND_PLUP);
      GiveExtraLife();
      end else begin    
        Lives := Lives - 1;
        SendCommand('LIVES ' + IntToStr(Lives) + ENTER + 'DEAD 0' + ENTER);
        GhostsToJail();
        Pacman.mX := Pacman.StartX;
        Pacman.mY := Pacman.StartY;
        PlaySound(SOUND_DEAD);
        CheckLives();

      end;
  end;


// So, server moves the first 2 ghosts, and client the other 2:
if Server then begin
                SendCommand('GHOUL 0 ' + IntToStr(Ghoul[0].mX) + ' ' + IntToStr(Ghoul[0].mY) + ENTER);
                SendCommand('GHOUL 1 ' + IntToStr(Ghoul[1].mX) + ' ' + IntToStr(Ghoul[1].mY) + ENTER);
                end
                else begin
                SendCommand('GHOUL 2 ' + IntToStr(Ghoul[2].mX) + ' ' + IntToStr(Ghoul[2].mY) + ENTER);
                SendCommand('GHOUL 3 ' + IntToStr(Ghoul[3].mX) + ' ' + IntToStr(Ghoul[3].mY) + ENTER);
                end;


end;

procedure TfrmMain.CheckLives();
var
        sBool: Boolean;

begin
if not (NetworkGame) then Lives2 := 0;

// Do any of the players have lives left?
        if (Lives <= 0) and (Lives2 <= 0) then begin
          Lives := 0;
          Lives2 := 0;
          SendCommand('GAMEOVER 0' + ENTER);
          PlayMusic(MUSIC_INTRO);
          DrawIt(frmMain, sBool);
          Playing := False;
          GameOver := True;
          if not (CustomLevel) then AddToHall(Score, '');
          if not (NetworkGame) then begin
                                    EnableDisableEpisodes(True);
                                    end
                                    else begin
                                    if (Server) then EnableDisableEpisodes(True);
                                    end;
          exit;
        end;
        if (Lives <= 0) then begin
          Lives := 0;
          Pacman.mX := POS_OFFLEVEL;
          Pacman.mY := POS_OFFLEVEL;
          SendCommand('PACMAN ' + IntToStr(Pacman.mX) + ' ' + IntToStr(Pacman.mY) + ' ' + IntToStr(Pacman.Direction) + ' ' + IntToStr(Pacman.State) + ENTER);
          SendCommand('LIVES ' + IntToStr(Lives) + ENTER);
          exit;
        end;
end;

procedure TfrmMain.GhostsToJail();
var
        n : Integer;

begin
// Jail all ghosts:
        for n := low(Ghoul) to high(Ghoul) do begin
          Ghoul[n].mX := POS_OFFLEVEL2;
          Ghoul[n].mY := POS_OFFLEVEL2;
          Ghoul[n].Jailed := True;
          Ghoul[n].JailedTime := Time;
        end;
end;

procedure TfrmMain.GiveExtraLife();
begin
// Give extra life every 5000 points:
if ((Score - LastLifeGivenScore) < SCORE_EXTRALIFE) then exit;

LastLifeGivenScore := Score;
Lives := Lives + 1;
SendCommand('LIVES ' + IntToStr(Lives) + ENTER);
end;

procedure TfrmMain.LoadLevel1Click(Sender: TObject);
begin
  if od.Execute then
  begin
    CustomLevel := True;
    Level := 1;
    Lives := 5;
    Score := 0;
    Lives2 := 5;
    Score2 := 0;
    LastLifeGivenScore := 0;
    GameOver := False;
    Playing := True;

    mnuStop.Enabled := True;
    LoadLevel(od.FileName);
  end;
end;

procedure TfrmMain.SendCommand(cmdCommand : String);
begin
if not NetworkGame then exit;

try
if Server then begin
               sckServer.Socket.Connections[0].SendText(cmdCommand);
               end
               else begin
               sckClient.Socket.SendText(cmdCommand);
               end;
except
end;

end;

procedure TfrmMain.SendLevel(LevelFile : String);
var
        i: Integer;
        curLevel: String;
        sLevel: TStringList;

begin
// Send the missing level file to the client:
if not NetworkGame then exit;

try
curLevel := LowerCase(LevelFile);
if (Pos('.pml', curLevel) = 0) then curLevel := 'level' + curLevel + '.pml';
if not (FileExists(LevelPath + curLevel)) then begin
                                                         SendCommand('ERROR LEVEL' + ENTER);
                                                         exit;
                                                         end;

sLevel := TStringList.Create();
sLevel.Clear();
sLevel.LoadFromFile(LevelPath + curLevel);

// Start command:
SendCommand('LEVELFILE ' + LevelFile + ENTER);

// Level data:
for i := 0 to sLevel.Count - 1 do begin
         SendCommand('LEVELDATA ' + sLevel.Strings[i] + ENTER);
end;

// End command:
SendCommand('LEVELSENT ' + LevelFile + ENTER + 'READY 1' + ENTER);

except
        SendCommand('ERROR LEVEL' + ENTER);
        sLevel.Free();
        exit;
end;

sLevel.Free();
end;

procedure TfrmMain.SaveLevel(LevelData : String; FileName : String);
var
        curLevel: String;
        sLevel: TStringList;

begin

// Save the downloaded level:
try
        ForceDirectories(AppPath + 'Levels');
        curLevel := LowerCase(FileName);
        if (Pos('.pml', curLevel) = 0) then curLevel := 'level' + curLevel + '.pml';

        sLevel := TStringList.Create();
        sLevel.Text := LevelData;
        sLevel.SaveToFile(LevelPath + curLevel);


except
        SendCommand('ERROR LEVEL' + ENTER);
        sLevel.Free();
        exit;
end;

sLevel.Free();

end;


procedure TfrmMain.ProcessCommand(cmdCommand : String; cmdParameter : String);

// Check the received commands and process them.

var
        p1 : Integer;
        p2 : Integer;
        p3 : Integer;
        sBool : Boolean;
        intTmp : Integer;
        strTemp : String;
        strTemp2 : String;

begin

try
// Client identification string:
if (cmdCommand = 'GUMMO') then begin
                                 Lives := 5;
                                 Lives2 := 5;
                                 Score := 0;
                                 Score2 := 0;
                                 LastLifeGivenScore := 0;
                                 Server := True;
                                 NetworkGame := True;
                                 ClientConnected := True;
                                 mnuDisconnect.Enabled := True;
                                 LoadLevel1.Enabled := True;
                                 EnableDisableEpisodes(True);
                                 mnuChat.Enabled := True;
                                 Self.Caption := 'Pacman X: Network game with ' + sckServer.Socket.Connections[0].RemoteAddress;
                                 exit;
                                 end;

// Load this level (parameter: level filename);
if (cmdCommand = 'LEVEL') then begin
                               strTemp2 := cmdParameter;
                               strTemp := LevelPath + cmdParameter;
                               cmdParameter := UpperCase(cmdParameter);
                               if (Pos('.PML', cmdParameter) = 0) then begin
                                                                  CustomLevel := False;
                                                                  EpisodeText := copy(cmdParameter, 1, 1);
                                                                  if (EpisodeText = '1') then EpisodeText := 'Episode I';
                                                                  if (EpisodeText = '2') then EpisodeText := 'Episode II';
                                                                  if (EpisodeText = '3') then EpisodeText := 'Episode III';
                                                                  if (EpisodeText = '4') then EpisodeText := 'Episode IV';
                                                                  if (EpisodeText = '5') then EpisodeText := 'Episode V';
                                                                  Level := StrToInt(cmdParameter);
                                                                  cmdParameter := 'LEVEL' + cmdParameter + '.PML';
                                                                  strTemp := LevelPath + cmdParameter;
                                                                  end
                                                                  else begin
                                                                  CustomLevel := True;
                                                                  end;
                               // If the level is missing from the client, download it from the host:
                               if not FileExists(strTemp) then begin
                                                               Playing := False;
                                                               Loading := True;
                                                               SendCommand('LEVELGET ' + strTemp2 + ENTER);
                                                               exit;
                                                               end;
                               if not (Playing) then begin
                                                     Lives := 5;
                                                     Lives2 := 5;
                                                     Score := 0;
                                                     Score2 := 0;
                                                     LastLifeGivenScore := 0;
                                                     end;
                               Loading := True;
                               Playing := False;
                               GameOver := False;
                               Self.Refresh;
                               LoadLevel(LevelPath + cmdParameter);
                               Self.Refresh();
                                Pacman.Drugged := False;
                                Pacman2.Drugged := False;
          			if (Lives2 > 0) then begin
                                			Pacman2.mX := Pacman.StartX;
                                			Pacman2.mY := Pacman.StartY;
                                			end
                                			else begin // Dead don't play
                                			Pacman2.mX := POS_OFFLEVEL;
                                			Pacman2.mY := POS_OFFLEVEL;
                                			Pacman2.StartX := POS_OFFLEVEL;
                                			Pacman2.StartY := POS_OFFLEVEL;
                                			end;
                               SendCommand('PACMAN ' + IntToStr(Pacman.mX) + ' ' + IntToStr(Pacman.mY) + ' ' + IntToStr(Pacman.Direction) + ' ' + IntToStr(Pacman.State) + ENTER);
                               SendCommand('READY 1' + ENTER);
                               //Loading := False;
                               //Playing := True;
                               exit;
                               end;

// Ready to start the next level:
if (cmdCommand = 'READY') then begin
                               Playing := True;
                               Loading := False;
                               exit;
                               end;

// Level file missing, get it from the other player:
if (cmdCommand = 'LEVELGET') then begin
                                  SendLevel(cmdParameter);
                                  exit;
                                  end;

// Level incoming:
if (cmdCommand = 'LEVELFILE') then begin
                                   DownloadLevel := '';
                                   exit;
                                   end;

// Level data incoming:
if (cmdCommand = 'LEVELDATA') then begin
                                   DownloadLevel := DownloadLevel + cmdParameter + ENTER;
                                   exit;
                                   end;

// Level download completed, now start the level:
if (cmdCommand = 'LEVELSENT') then begin
                                   SaveLevel(DownloadLevel, cmdParameter);
                                   DownloadLevel := '';
                                   ProcessCommand('LEVEL', cmdParameter);
                                   exit;
                                   end;

// Errors will end the current level:
if (cmdCommand = 'ERROR') then begin
                               GameOver := True;
                               Playing := False;
                               CustomLevel := False;
                               tmrShowScores.Tag := 1;
                               tmrShowScores.Enabled := True;
                               if (cmdParameter = 'LEVEL') then MessageDlg('The other player does not have and cannot receive this level!', mtError, [mbOK], 0);
                               exit;
                               end;

// Chat text:
if (cmdCommand = 'CHAT') then begin
                              txtChat.Text := txtChat.Text + 'OTHER: ' + cmdParameter + ENTER;
                              txtChat.Visible := True;
                              mnuClearChat.Enabled := True;
                              if (onLinux) then Self.Height := 625 else Self.Height := 576;
                              exit;
                              end;



// From here, these control the game environment:

// Pacman position, direction and movement:
if (cmdCommand = 'PACMAN') then begin
                                p1 := StrToInt(Split2Params(cmdParameter, 1));
                                p2 := StrToInt(Split2Params(cmdParameter, 2));
                                p3 := Grid[p1, p2].mType;
                                if (p3 = 1) or (p3 = 2) then Grid[p1, p2].mType := 3;
                                Pacman2.mX := p1;
                                Pacman2.mY := p2;
                                Pacman2.Direction := StrToInt(Split2Params(cmdParameter, 3));
                                Pacman2.State := StrToInt(Split2Params(cmdParameter, 4));
                                exit;
                                end;

// Ghouls position:
if (cmdCommand = 'GHOUL') then begin
                              intTmp := StrToInt(Split2Params(cmdParameter, 1));
                              Ghoul[intTmp].mX := StrToInt(Split2Params(cmdParameter, 2));
                              Ghoul[intTmp].mY := StrToInt(Split2Params(cmdParameter, 3));
                              exit;
                              end;

// A meatball has been eaten:
if (cmdCommand = 'EAT') then begin
                               Score2 := Score2 + 1;
                               p1 := StrToInt(Split2Params(cmdParameter, 1));
                               p2 := StrToInt(Split2Params(cmdParameter, 2));
                               Grid[p1, p2].mType := 3;
                               Pacman2.mX := p1;
                               Pacman2.mY := p2;
                               exit;
                               end;

// A ghost has been eaten:
if (cmdCommand = 'EATGHOUL') then begin
                               p1 := StrToInt(Split2Params(cmdParameter, 1));
                               p2 := StrToInt(Split2Params(cmdParameter, 2));
                               Ghoul[p1].mX := POS_OFFLEVEL2;
                               Ghoul[p1].mY := POS_OFFLEVEL2;
                               Ghoul[p1].Jailed := True;
                               Ghoul[p1].JailedTime := Time;
                               if (p2 = 0) then Score2 := Score2 + 50 else Score := Score + 50;
                               PlaySound(SOUND_PLUP);
                               exit;
                               end;

// Other player's lives:
if (cmdCommand = 'LIVES') then begin
                                Lives2 := StrToInt(cmdParameter);
                                exit;
                                end;

// Other player's score (NOT 100% accurate, but this will fix it and make accurate enough):
if (cmdCommand = 'SCORE') then begin
                                Score2 := StrToInt(cmdParameter);
                                exit;
                                end;

// The other player has been drugged, so make us drugged too:
if (cmdCommand = 'DRUG') then begin
                               Pacman.Drugged := True;
                               Pacman.DruggedTime := Time;
                               UseSkin := False;
                               Timer1.Interval := 150;
                               Score2 := Score2 + 1;
                               p1 := StrToInt(Split2Params(cmdParameter, 1));
                               p2 := StrToInt(Split2Params(cmdParameter, 2));
                               Grid[p1, p2].mType := 3;
                               Pacman2.mX := p1;
                               Pacman2.mY := p2;
                               PlaySound(SOUND_PLUP);
                               exit;
                               end;
// Other player is dead:
if (cmdCommand = 'DEAD') then begin
                                GhostsToJail();
			        Pacman2.mX := Pacman.StartX;
			        Pacman2.mY := Pacman.StartY;
				PlaySound(SOUND_DEAD);
                                exit;
                                end;
// I'm dead:
if (cmdCommand = 'YOURDEAD') then begin
                                  Lives := Lives - 1;
                                  SendCommand('LIVES ' + IntToStr(Lives) + ENTER);
                                  Pacman.mX := Pacman.StartX;
                                  Pacman.mY := Pacman.StartY;
                                  GhostsToJail();
                                  PlaySound(SOUND_DEAD);
                                  CheckLives();
                                  end;

// Pause both player's game:
if (cmdCommand = 'PAUSE') then begin
                                  if (StrToInt(cmdParameter) = 0) then Playing := False else Playing := True;
                                  exit;
                                  end;

// Add other player's score to Hall of Fame:
if (cmdCommand = 'HALL') then begin
                                  Score2 := StrToInt(Split2Params(cmdParameter, 2));
                                  AddToHall(Score2, Split2Params(cmdParameter, 1));
                                  exit;
                                  end;

if (cmdCommand = 'GAMEOVER') then begin
                                  Disconnect(False);
                                  if not (CustomLevel) then AddToHall(Score, '');
                                  exit;
                                  end;

if (cmdCommand = 'WONGAME') then begin
                                  curMusic := MUSIC_INTRO;
                                  InfoY := Area.Bottom;
                                  if not (CustomLevel) then Score := Score + (Lives * 200);
                                  DrawIt(frmMain, sBool);
                                  Playing := False;
                                  GameOver := True;
                                  SendCommand('SCORE ' + IntToStr(Score) + ENTER);
                                  if not (CustomLevel) then AddToHall(Score, '');
                                  exit;
                                  end;
except
end;

end;

procedure TfrmMain.ParseData(const dData : String);
var
        sCommand : String;
        sParameter : String;
        RestString : String;
        sLine : String;
        iPos : Integer;

begin
// Separate commands and parameters and process them in ProcessCommand-procedure:
RestString := '';
iPos := Pos(ENTER, dData);
if (iPos <= 0) then exit;

sLine := copy(dData, 1, iPos - 1);
RestString := copy(dData, iPos + 2, Length(dData) - iPos - 1);

     iPos := Pos(' ', sLine);
     sCommand := '';
     sParameter := '';
     try
     if (iPos > 0) then begin
                        sCommand := copy(sLine, 1, iPos - 1);
                        sParameter := copy(sLine, iPos + 1, Length(sLine) - iPos);
                        ProcessCommand(sCommand, sParameter);
                        end
                        else begin
                        end;
     except
     exit;
     end;

// Process remaining commands in the incoming data:
if (Length(RestString) > 0) then ParseData(RestString);
end;

function TfrmMain.Split2Params(const dData: String; const dPosition: Integer): String;
var
        sParameter : String;
        RestString : String;
        sPosition : Integer;
        iPos : Integer;
        i: Integer;

begin
// Get the Nth parameter from a string:
RestString := dData;
sPosition := 0;

for i := 1 to dPosition do begin
        iPos := Pos(' ', RestString);

        sPosition := sPosition + 1;
        if (iPos <= 0) then begin
                            if (sPosition = dPosition) then Result := RestString else Result := '';
                            exit;
                            end;

        sParameter := copy(RestString, 1, iPos - 1);
        if (sPosition = dPosition) then begin
                                        Result := sParameter;
                                        exit;
                                        end;

        RestString := copy(RestString, iPos + 1, Length(RestString) - iPos);
end;

Result := '';
end;

procedure TfrmMain.sckServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ParseData(Socket.ReceiveText);
end;

procedure TfrmMain.mnuSingleClick(Sender: TObject);
var
        Key : Char;

begin

Key := Char('1');

FormKeypress(Sender, Key);
end;

procedure TfrmMain.ResetVariables;
begin
Level := 101;
Lives := 5;
Score := 0;
Lives2 := 5;
Score2 := 0;
LastLifeGivenScore := 0;
GameOver := False;
Playing := True;
end;

procedure TfrmMain.mnuHostClick(Sender: TObject);
begin

Disconnect(True);

try
        sckServer.Close;
except
end;

try
        sckServer.Open;
except
        MessageDlg('Could not open socket. The port ' + IntToStr(sckServer.Port) + ' might be already in use!', mtError, [mbOK], 0);
        exit; 
end;


ClientConnected := False;
LoadLevel1.Enabled := False;
EnableDisableEpisodes(False);
mnuHost.Enabled := False;
mnuJoin.Enabled := False;
NetworkGame := True;

mnuDisconnect.Enabled := True;
Self.Caption := 'Waiting for players @ ' + UpperCase(sckServer.Socket.LocalHost) + '...';

end;

procedure TfrmMain.mnuJoinClick(Sender: TObject);
var
        msgHost : String;

begin

LoadLastAddress();
msgHost := InputBox('Join network game', 'Address or hostname:', lastAddress);
if (Length(msgHost) = 0) then exit;
lastAddress := msgHost;
SaveLastAddress();

Self.Caption := 'Connecting...';

LoadLevel1.Enabled := False;

    CustomLevel := True;
    Level := 101;
    Lives := 5;
    Score := 0;
    Lives2 := 5;
    Score2 := 0;
    LastLifeGivenScore := 0;
    GameOver := True;
    Loading := False;
    Playing := False;

Server := False;
NetworkGame := True;

try
        sckClient.Close;
except
end;

try
        sckClient.Host := msgHost;
        sckClient.Open;
except
        MessageDlg('Connection failed!', mtError, [mbOK], 0);
end;

try
        sckClient.Close;
except
end;

end;

procedure TfrmMain.AppException(Sender: TObject; E: Exception);
begin
// Nothing
end;

procedure TfrmMain.sckClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
Disconnect(True);
MessageDlg('Disconnected.', mtError, [mbOK], 0);
end;

procedure TfrmMain.sckServerClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
if (Socket.SocketHandle <> ClientHandle) then exit;

Disconnect(True);
MessageDlg('Disconnected.', mtError, [mbOK], 0);
end;

procedure TfrmMain.sckClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ParseData(Socket.ReceiveText);
end;

procedure TfrmMain.sckClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
LoadLevel1.Enabled := False;
EnableDisableEpisodes(False);
mnuHost.Enabled := False;
mnuJoin.Enabled := False;
SendCommand('GUMMO PACMAN X' + ENTER);

mnuDisconnect.Enabled := True;
mnuChat.Enabled := True;
Self.Caption := 'Pacman X: Network game with ' + sckClient.Socket.RemoteAddress;
end;

procedure TfrmMain.mnuExitClick(Sender: TObject);
begin
Application.Terminate;
end;

procedure TfrmMain.mnuDisconnectClick(Sender: TObject);
begin
if not GameOver then begin
                     if (MessageDlg('This will end the game.', mtConfirmation, [mbOK, mbCancel], 0) = mrCancel) then exit;
                     end;

Disconnect(True);

end;

procedure TfrmMain.Disconnect(SocketDisconnect : Boolean);
var
        sBool: Boolean;

begin
PlayMusic(MUSIC_INTRO);

EnableDisableEpisodes(True);
mnuStop.Enabled := False;
LoadLevel1.Enabled := True;

Lives := 0;
Lives2 := 0;
DrawIt(frmMain, sBool);
Loading := False;
GameOver := True;
Playing := False;
Score := 0;
Score2 := 0;
LastLifeGivenScore := 0;


if not (SocketDisconnect) then exit;

tmrShowScores.Tag := 1;
tmrShowScores.Enabled := True;
NetworkGame := False;
Server := False;
mnuDisconnect.Enabled := False;
ClientConnected := False;
mnuChat.Enabled := False;
mnuHost.Enabled := True;
mnuJoin.Enabled := True;
Self.Caption := 'Pacman X';

try
        sckServer.Close;
except
end;

try
        sckClient.Close;
except
end;


end;

procedure TfrmMain.mnuChatClick(Sender: TObject);
var
        msgChat : String;

begin
msgChat := InputBox('Chat', 'Send:', '');
if (Length(msgChat) = 0) then exit;

txtChat.Text := txtChat.Text + 'YOU: ' + msgChat + ENTER;
txtChat.Visible := True;
mnuClearChat.Enabled := True;
if (onLinux) then Self.Height := 625 else Self.Height := 576;

SendCommand('CHAT ' + msgChat + ENTER);

end;

procedure TfrmMain.mnuSoundsClick(Sender: TObject);
begin
if mnuSounds.Checked then mnuSounds.Checked := False else mnuSounds.Checked := True;

end;

procedure TfrmMain.mnuMusicClick(Sender: TObject);
begin
if mnuMusic.Checked then mnuMusic.Checked := False else mnuMusic.Checked := True;

try
if mnuMusic.Checked then begin
                         PlayMusic(curMusic);
                         end
                         else begin
                         mpMusic.Stop
                         end;
except
end;
end;

procedure TfrmMain.tmrMusicTimer(Sender: TObject);
begin
tmrMusic.Enabled := False;
if (Pos('level', curMusic) > 0) then exit;
PlayMusic(curMusic);
end;

procedure TfrmMain.mnuClearChatClick(Sender: TObject);
begin
mnuClearChat.Enabled := False;
txtChat.Visible := False;
if (onLinux) then Self.Height := 500 else Self.Height := 447;
end;

procedure TfrmMain.tmrShowScoresTimer(Sender: TObject);
begin
// Show/Hide scores:
if (tmrShowScores.Tag = 0) then begin
                                if (Self.Width >= 481) then begin
                                                            tmrShowScores.Enabled := False;
                                                            exit;
                                                            end;
                                Self.Width := Self.Width + 10;
                                end;

if (tmrShowScores.Tag = 1) then begin
                                if (Self.Width <= 409) then begin
                                                            tmrShowScores.Enabled := False;
                                                            exit;
                                                            end;
                                Self.Width := Self.Width - 10;
                                end;
end;

procedure TfrmMain.sckServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
if not ClientConnected then ClientHandle := Socket.SocketHandle;

end;

procedure TfrmMain.sckClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin

Self.Caption := 'Pacman X';

try
        sckClient.Close;
except
end;

end;


procedure TfrmMain.txtChatChange(Sender: TObject);
begin
txtChat.SelLength := Length(txtChat.Text);
end;

procedure TfrmMain.mnuSingle2Click(Sender: TObject);
var
        Key : Char;

begin

Key := Char('2');

FormKeypress(Sender, Key);

end;

procedure TfrmMain.mnuStopClick(Sender: TObject);
begin
if not GameOver then begin
                     if (MessageDlg('This will end the game.', mtConfirmation, [mbOK, mbCancel], 0) = mrCancel) then exit;
                     end;

if not NetworkGame then Self.Caption := 'Pacman X';
SendCommand('GAMEOVER 0' + ENTER);
Disconnect(False);
end;

procedure TfrmMain.mnuSingle3Click(Sender: TObject);
var
        Key : Char;

begin

Key := Char('3');

FormKeypress(Sender, Key);

end;

procedure TfrmMain.mnuSingle4Click(Sender: TObject);
var
        Key : Char;

begin

Key := Char('4');

FormKeypress(Sender, Key);
end;

procedure TfrmMain.mnuSingle5Click(Sender: TObject);
var
        Key : Char;

begin

Key := Char('5');

FormKeypress(Sender, Key);
end;


procedure TfrmMain.mnuGameClick(Sender: TObject);
begin
if NetworkGame and not Server then begin
                                EnableDisableEpisodes(False);
                                mnuStop.Enabled := False;
                                LoadLevel1.Enabled := False;
                                end;
end;


procedure TfrmMain.sckMIDConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
tmrMID.Enabled := False;
PlayMusic(MUSIC_INTRO);
end;

procedure TfrmMain.tmrMIDTimer(Sender: TObject);
begin
if (sckMID.Socket.Connected) then begin
			          tmrMID.Enabled := False;
			          exit;
			          end;
			   
try
	sckMID.Open();
except
end;
end;

end.
