Subversion Repositories plumbers

Rev

Rev 8 | Rev 17 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit Main;
  2.  
  3. // BUG: If you drag the window, the dia show will stop playing, but the sound continues! This makes everything out of sync.
  4. // TODO: When the windows is only resized a little bit (A few pixels), the window should not centered
  5. //       ... Calc the width and height of ALL pictures, and then size the form to the biggest value?
  6. //       ... or hard code the resolution in the INI file?
  7. // Idea: Ini Parameter if fullscreen is applied or not
  8. // Idea: Savestates, speedup, pause, Use Space bar to go to the next decision point.
  9.  
  10. // -----------------------------------------------------------------------------
  11.  
  12. // HOTSPOT_RELATIVE_ORIGIN is a new behavior which is not compatible with the original engine.
  13. // With HOTSPOT_RELATIVE_ORIGIN enabled, the coordinates will be relative to the picture
  14. // The original game has the origin at the top left corner of the screen.
  15. // This is a problem because the game as well as the scene editor does not know the
  16. // desired resolution, as it is automatically determined.
  17. // If we would hardcode the desired canvas (640x480) in <ExeName>.ini, then
  18. // it would work, but then, the scene Editor can not know the desired resolution...
  19. {$DEFINE HOTSPOT_RELATIVE_ORIGIN}
  20.  
  21. interface
  22.  
  23. uses
  24.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  25.   Dialogs, ExtCtrls, StdCtrls, Game;
  26.  
  27. type
  28.   TMainForm = class(TForm)
  29.     Image1: TImage;
  30.     Panel1: TPanel;
  31.     StartupTimer: TTimer;
  32.     procedure FormCreate(Sender: TObject);
  33.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  34.     procedure StartupTimerTimer(Sender: TObject);
  35.     procedure ControlClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  36.     procedure FormDestroy(Sender: TObject);
  37.   private
  38.     FHotspots: array[0..2] of THotspot;
  39.     FullscreenMode: boolean;
  40.     procedure cbPictureShow(ASender: TGame; AFilename: string; AType: TPictureType);
  41.     procedure cbAsyncSound(ASender: TGame; AFilename: string);
  42.     procedure cbExit(ASender: TGame);
  43.     procedure cbWait(ASender: TGame; AMilliseconds: integer);
  44.     procedure cbSetHotspot(ASender: TGame; AIndex: THotspotIndex; AHotspot: THotspot);
  45.     procedure cbClearHotspots(ASender: TGame);
  46.     procedure ClickEvent(X, Y: Integer);
  47.   public
  48.     game: TGame;
  49.   end;
  50.  
  51. var
  52.   MainForm: TMainForm;
  53.  
  54. implementation
  55.  
  56. {$R *.dfm}
  57.  
  58. uses
  59.   MMSystem, IniFiles, Math;
  60.  
  61. procedure Delay(const Milliseconds: DWord);
  62. var
  63.   FirstTickCount: DWord;
  64. begin
  65.   FirstTickCount := GetTickCount; // TODO: Attention, GetTickCount can overflow
  66.   while not Application.Terminated and ((GetTickCount - FirstTickCount) < Milliseconds) do
  67.   begin
  68.     Application.ProcessMessages;
  69.     Sleep(0);
  70.   end;
  71. end;
  72.  
  73. function AddThouSeps(const S: string): string;
  74. var
  75.   LS, L2, I, N: Integer;
  76.   Temp: string;
  77. begin
  78.   // http://www.delphigroups.info/2/11/471892.html
  79.   result := S ;
  80.   LS := Length(S);
  81.   N := 1 ;
  82.   if LS > 1 then
  83.   begin
  84.     if S [1] = '-' then  // check for negative value
  85.     begin
  86.       N := 2;
  87.       LS := LS - 1;
  88.     end;
  89.   end;
  90.   if LS <= 3 then exit;
  91.   L2 := (LS - 1) div 3;
  92.   Temp := '';
  93.   for I := 1 to L2 do
  94.   begin
  95.     Temp := {$IF not Declared(ThousandSeparator)}FormatSettings.{$IFEND}ThousandSeparator + Copy (S, LS - 3 * I + 1, 3) + Temp;
  96.   end;
  97.   Result := Copy (S, N, (LS - 1) mod 3 + 1) + Temp;
  98.   if N > 1 then Result := '-' + Result;
  99. end;
  100.  
  101. { TMainForm }
  102.  
  103. procedure TMainForm.cbPictureShow(ASender: TGame; AFilename: string; AType: TPictureType);
  104. resourcestring
  105.   S_YOUR_SCORE = 'Your score is: %s';
  106. begin
  107.   if FileExists(AFilename) then
  108.   begin
  109.     Image1.Visible := false;
  110.     try
  111.       Image1.Picture.LoadFromFile(AFilename);
  112.       Image1.Autosize := true;
  113.     finally
  114.       // This speeds up the picture loading on very old computers
  115.       Image1.Visible := true;
  116.     end;
  117.  
  118.     // Make form bigger if necessary
  119.     if Image1.Width > ClientWidth then
  120.     begin
  121.       ClientWidth := Min(Image1.Width, Screen.Width);
  122.       if (ClientWidth >= Screen.Width) then FullscreenMode := true;
  123.       Position := poScreenCenter;
  124.     end;
  125.     if Image1.Height > ClientHeight then
  126.     begin
  127.       ClientHeight := Min(Image1.Height, Screen.Height);
  128.       if (ClientHeight >= Screen.Height) then FullscreenMode := true;
  129.       Position := poScreenCenter;
  130.     end;
  131.  
  132.     // Center image
  133.     Image1.Left := ClientWidth div 2 - Image1.Width div 2;
  134.     Image1.Top := ClientHeight div 2 - Image1.Height div 2;
  135.   end
  136.   else
  137.   begin
  138.     Image1.Picture := nil;
  139.   end;
  140.  
  141.   if FullScreenMode then
  142.   begin
  143.     BorderStyle := bsNone;
  144.     FormStyle := fsStayOnTop;
  145.     Case AType of
  146.       ptDia: Screen.Cursor := -1;
  147.       ptDecision: Screen.Cursor := 0;
  148.     End;
  149.   end;
  150.  
  151.   Panel1.Caption := Format(S_YOUR_SCORE, [AddThouSeps(IntToStr(ASender.Score))]);
  152.   Panel1.Left := 8;
  153.   Panel1.Top := Min(ClientHeight, Screen.Height) - Panel1.Height - 8;
  154.   Panel1.Visible := AType = ptDecision;
  155. end;
  156.  
  157. procedure TMainForm.cbAsyncSound(ASender: TGame; AFilename: string);
  158. begin
  159.   PlaySound(nil, hinstance, 0);
  160.   if FileExists(AFilename) then
  161.   begin
  162.     PlaySound(PChar(AFilename), hinstance, SND_FILENAME or SND_ASYNC);
  163.   end;
  164. end;
  165.  
  166. procedure TMainForm.cbSetHotspot(ASender: TGame; AIndex: THotspotIndex; AHotspot: THotspot);
  167. begin
  168.   FHotspots[AIndex] := AHotspot;
  169. end;
  170.  
  171. procedure TMainForm.cbClearHotspots(ASender: TGame);
  172. var
  173.   i: Integer;
  174. begin
  175.   for i := Low(FHotspots) to High(FHotspots) - 1 do
  176.   begin
  177.     FHotspots[i].lpAction := nil;
  178.   end;
  179. end;
  180.  
  181. procedure TMainForm.cbExit(ASender: TGame);
  182. begin
  183.   Application.Terminate;
  184. end;
  185.  
  186. procedure TMainForm.cbWait(ASender: TGame; AMilliseconds: integer);
  187. begin
  188.   //Cursor := crHourglass;
  189.   try
  190.     Delay(AMilliseconds);
  191.   finally
  192.     //Cursor := crDefault;
  193.   end;
  194. end;
  195.  
  196. procedure TMainForm.FormCreate(Sender: TObject);
  197. var
  198.   ini: TMemIniFile;
  199.   iniFilename: string;
  200. begin
  201.   iniFilename := ChangeFileExt(ExtractFileName(ParamStr(0)), '.ini');
  202.  
  203.   DoubleBuffered := true;
  204.  
  205.   if FileExists(iniFilename) then
  206.   begin
  207.     ini := TMemIniFile.Create(iniFilename);
  208.     try
  209.       Caption := ini.ReadString('Config', 'Title', '');
  210.     finally
  211.       FreeAndNil(ini);
  212.     end;
  213.   end;
  214.  
  215.   try
  216.     Game := TGame.Create('.');
  217.     Game.PictureShowCallback := cbPictureShow;
  218.     Game.AsyncSoundCallback := cbAsyncSound;
  219.     Game.ExitCallback := cbExit;
  220.     Game.WaitCallback := cbWait;
  221.     Game.SetHotspotCallback := cbSetHotspot;
  222.     Game.ClearHotspotsCallback := cbClearHotspots;
  223.     StartupTimer.Enabled := true;
  224.   except
  225.     Application.Terminate;
  226.   end;
  227. end;
  228.  
  229. procedure TMainForm.FormDestroy(Sender: TObject);
  230. begin
  231.   // Without this, some audio drivers could crash if you press ESC to end the game.
  232.   // (VPC 2007 with Win95; cpsman.dll crashes sometimes)
  233.   PlaySound(nil, hinstance, 0);
  234. end;
  235.  
  236. procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
  237.   Shift: TShiftState);
  238. begin
  239.   if Key = VK_ESCAPE then Close;
  240. end;
  241.  
  242. procedure TMainForm.ClickEvent(X, Y: Integer);
  243. var
  244.   i: integer;
  245. begin
  246.   // If hotspots are overlaying, the lowest action will be chosen (same behavior as original game)
  247.   for i := Low(FHotspots) to High(FHotspots) do
  248.   begin
  249.     if Assigned(FHotspots[i].lpAction) and
  250.        (X >= FHotspots[i].cHotspotTopLeft.X) and
  251.        (Y >= FHotspots[i].cHotspotTopLeft.Y) and
  252.        (X <= FHotspots[i].cHotspotBottomRight.X) and
  253.        (Y <= FHotspots[i].cHotspotBottomRight.Y) then
  254.     begin
  255.       FHotspots[i].Game.PerformAction(FHotspots[i].lpAction);
  256.       Exit;
  257.     end;
  258.   end;
  259. end;
  260.  
  261. procedure TMainForm.ControlClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  262. begin
  263.   {$IFDEF HOTSPOT_RELATIVE_ORIGIN}
  264.   ClickEvent(X, Y);
  265.   {$ELSE}
  266.   ClickEvent(X+TControl(Sender).Left, Y+TControl(Sender).Top);
  267.   {$ENDIF}
  268. end;
  269.  
  270. procedure TMainForm.StartupTimerTimer(Sender: TObject);
  271. begin
  272.   StartupTimer.Enabled := false;
  273.   Game.Run;
  274. end;
  275.  
  276. end.
  277.