Subversion Repositories plumbers

Rev

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

  1. unit Unit1;
  2.  
  3. // TODO: the "folder open" icons look like you can CHOOSE a file, not open it!
  4. //       - change the icon to something else
  5. //       - add open-dialogs for choosing the bmp and wav files
  6. // TODO: Give controls better names
  7. // TODO: When loading the file, check if dependencies are broken and output a warning
  8. // Idea: About the hotspot / action markings:
  9. //       - anti moiree?
  10. //       - allow user to draw a rectangle with drag'n'drop instead of left and right mouse button.
  11. //         also, automatically determine the left/top and right/bottom border, so the user can draw the rectange in every direction
  12. // Idea: unused liste auch bei decision page anzeigen
  13. // Idea: Function to re-order stuff?
  14.  
  15. interface
  16.  
  17. uses
  18.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  19.   Dialogs, StdCtrls, Spin, Grids, GameBinStruct, ComCtrls, ExtCtrls, MPlayer,
  20.   Menus;
  21.  
  22. const
  23.   CUR_VER = '2017-10-04';
  24.  
  25. type
  26.   TForm1 = class(TForm)
  27.     ListBox1: TListBox;
  28.     Button1: TButton;
  29.     Button2: TButton;
  30.     Button3: TButton;
  31.     Button4: TButton;
  32.     Button5: TButton;
  33.     Button10: TButton;
  34.     PageControl2: TPageControl;
  35.     TabSheet4: TTabSheet;
  36.     Label1: TLabel;
  37.     Label2: TLabel;
  38.     SpinEdit1: TSpinEdit;
  39.     Edit1: TEdit;
  40.     Button6: TButton;
  41.     Button7: TButton;
  42.     Button8: TButton;
  43.     Button9: TButton;
  44.     ListBox2: TListBox;
  45.     TabSheet5: TTabSheet;
  46.     Label3: TLabel;
  47.     Image1: TImage;
  48.     Label10: TLabel;
  49.     Label11: TLabel;
  50.     Edit2: TEdit;
  51.     PageControl1: TPageControl;
  52.     TabSheet1: TTabSheet;
  53.     Label5: TLabel;
  54.     Label4: TLabel;
  55.     Label6: TLabel;
  56.     SpinEdit6: TSpinEdit;
  57.     SpinEdit2: TSpinEdit;
  58.     SpinEdit3: TSpinEdit;
  59.     SpinEdit4: TSpinEdit;
  60.     SpinEdit5: TSpinEdit;
  61.     ComboBox1: TComboBox;
  62.     TabSheet2: TTabSheet;
  63.     Label13: TLabel;
  64.     Label14: TLabel;
  65.     Label15: TLabel;
  66.     ComboBox2: TComboBox;
  67.     SpinEdit17: TSpinEdit;
  68.     SpinEdit18: TSpinEdit;
  69.     SpinEdit19: TSpinEdit;
  70.     SpinEdit20: TSpinEdit;
  71.     SpinEdit21: TSpinEdit;
  72.     TabSheet3: TTabSheet;
  73.     Label7: TLabel;
  74.     Label8: TLabel;
  75.     Label9: TLabel;
  76.     ComboBox3: TComboBox;
  77.     SpinEdit7: TSpinEdit;
  78.     SpinEdit8: TSpinEdit;
  79.     SpinEdit9: TSpinEdit;
  80.     SpinEdit10: TSpinEdit;
  81.     SpinEdit11: TSpinEdit;
  82.     SpinEdit12: TSpinEdit;
  83.     Image2: TImage;
  84.     Edit3: TEdit;
  85.     SpinEdit13: TSpinEdit;
  86.     Label12: TLabel;
  87.     Label16: TLabel;
  88.     Button13: TButton;
  89.     Button14: TButton;
  90.     MediaPlayer1: TMediaPlayer;
  91.     Timer1: TTimer;
  92.     GroupBox2: TGroupBox;
  93.     Button15: TButton;
  94.     Button17: TButton;
  95.     Button16: TButton;
  96.     Label18: TLabel;
  97.     Label17: TLabel;
  98.     ListBox3: TListBox;
  99.     Label19: TLabel;
  100.     Label24: TLabel;
  101.     Label25: TLabel;
  102.     Label26: TLabel;
  103.     Label27: TLabel;
  104.     Label28: TLabel;
  105.     Label29: TLabel;
  106.     Button11: TButton;
  107.     Button12: TButton;
  108.     Button18: TButton;
  109.     MainMenu1: TMainMenu;
  110.     File1: TMenuItem;
  111.     Close1: TMenuItem;
  112.     Newfile1: TMenuItem;
  113.     Savetogamebin1: TMenuItem;
  114.     Saveandtest1: TMenuItem;
  115.     N1: TMenuItem;
  116.     N2: TMenuItem;
  117.     Help1: TMenuItem;
  118.     About1: TMenuItem;
  119.     PopupMenu1: TPopupMenu;
  120.     Addtoscene1: TMenuItem;
  121.     Panel1: TPanel;
  122.     Panel2: TPanel;
  123.     Panel3: TPanel;
  124.     Image3: TImage;
  125.     Button19: TButton;
  126.     PageControl3: TPageControl;
  127.     TabSheet6: TTabSheet;
  128.     TabSheet7: TTabSheet;
  129.     Label20: TLabel;
  130.     Label21: TLabel;
  131.     Label22: TLabel;
  132.     Label23: TLabel;
  133.     Label34: TLabel;
  134.     Label35: TLabel;
  135.     Label32: TLabel;
  136.     Label33: TLabel;
  137.     Label30: TLabel;
  138.     Label31: TLabel;
  139.     Label36: TLabel;
  140.     Label37: TLabel;
  141.     CheckBox1: TCheckBox;
  142.     TabSheet8: TTabSheet;
  143.     Button20: TButton;
  144.     procedure ListBox1Click(Sender: TObject);
  145.     procedure Edit1Change(Sender: TObject);
  146.     procedure Edit2Change(Sender: TObject);
  147.     procedure SpinEdit1Change(Sender: TObject);
  148.     procedure Button3Click(Sender: TObject);
  149.     procedure FormShow(Sender: TObject);
  150.     procedure SpinEdit12Change(Sender: TObject);
  151.     procedure ActionTargetChange(Sender: TObject);
  152.     procedure ActionSpinEditsChange(Sender: TObject);
  153.     procedure Button1Click(Sender: TObject);
  154.     procedure Button10Click(Sender: TObject);
  155.     procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  156.       Y: Integer);
  157.     procedure ListBox2Click(Sender: TObject);
  158.     procedure SpinEdit13Change(Sender: TObject);
  159.     procedure Edit3Change(Sender: TObject);
  160.     procedure FormCreate(Sender: TObject);
  161.     procedure Button13Click(Sender: TObject);
  162.     procedure Button14Click(Sender: TObject);
  163.     procedure Button2Click(Sender: TObject);
  164.     procedure Timer1Timer(Sender: TObject);
  165.     procedure Button17Click(Sender: TObject);
  166.     procedure Button15Click(Sender: TObject);
  167.     procedure Button16Click(Sender: TObject);
  168.     procedure ListBox1DblClick(Sender: TObject);
  169.     procedure ListBox2DblClick(Sender: TObject);
  170.     procedure Button4Click(Sender: TObject);
  171.     procedure Button5Click(Sender: TObject);
  172.     procedure Button6Click(Sender: TObject);
  173.     procedure Button7Click(Sender: TObject);
  174.     procedure Button8Click(Sender: TObject);
  175.     procedure Button9Click(Sender: TObject);
  176.     procedure Image1MouseLeave(Sender: TObject);
  177.     procedure ListBox3DblClick(Sender: TObject);
  178.     procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
  179.       Shift: TShiftState; X, Y: Integer);
  180.     procedure Button11Click(Sender: TObject);
  181.     procedure Button12Click(Sender: TObject);
  182.     procedure Button18Click(Sender: TObject);
  183.     procedure Image1MouseEnter(Sender: TObject);
  184.     procedure About1Click(Sender: TObject);
  185.     procedure Close1Click(Sender: TObject);
  186.     procedure Addtoscene1Click(Sender: TObject);
  187.     procedure ListBox3MouseDown(Sender: TObject; Button: TMouseButton;
  188.       Shift: TShiftState; X, Y: Integer);
  189.     procedure ListBox3Click(Sender: TObject);
  190.     procedure Button19Click(Sender: TObject);
  191.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  192.     procedure Button20Click(Sender: TObject);
  193.     procedure CheckBox1Click(Sender: TObject);
  194.   private
  195.     Game: TGameBinFile;
  196.     GameBak: TGameBinFile;
  197.     PlayStart: Cardinal;
  198.     MediaplayerOpened: boolean;
  199.     StopPlayRequest: boolean;
  200.     FirstTickCount: Cardinal;
  201.     procedure ShowSceneBmp;
  202.     function CurScene: PSceneDef;
  203.     procedure LoadScene;
  204.     procedure Load;
  205.     procedure Save;
  206.     procedure ReloadActionSceneLists;
  207.     function FindSceneIndex(sceneID: integer): integer;
  208.     function GetGreatestSceneID: integer;
  209.     function SearchSceneIDGapFromTop: integer;
  210.     procedure RedrawDecisionBitmap;
  211.     function CurPicture: PPictureDef;
  212.     function CurPictureTimepos: Cardinal;
  213.     procedure New;
  214.     procedure NewScene;
  215.     procedure SetupGUIAfterLoad;
  216.     procedure RecalcSlideshowLength;
  217.     procedure RecalcSoundtrackLength;
  218.     procedure RecalcUnusedFiles;
  219.     procedure RecalcStats;
  220.     procedure HandlePossibleEmptySceneList;
  221.     procedure DisableEnableSceneControls(enable: boolean);
  222.     procedure DisableEnablePictureControls(enable: boolean);
  223.     procedure DisableEnableFileControls(enable: boolean);
  224.     class procedure AspectRatio(image: TImage; panel: TControl);
  225.   end;
  226.  
  227. var
  228.   Form1: TForm1;
  229.  
  230. implementation
  231.  
  232. {$R *.dfm}
  233.  
  234. uses
  235.   Math, MMSystem, ShellAPI;
  236.  
  237. const
  238.   DEFAULT_DURATION = 0;
  239.   DEFAULT_FILENAME = 'DUMMY.BMP';
  240.  
  241. function GetSceneIDFromName(sceneName: string): Integer;
  242. var
  243.   sSceneID: string;
  244. begin
  245.   if Copy(sceneName, 1, 2) <> 'SC' then raise Exception.Create('Scene name invalid');
  246.   sSceneID := Copy(sceneName, 3, 2);
  247.   if not TryStrToInt(sSceneID, result) then raise Exception.Create('Scene name invalid');
  248. end;
  249.  
  250. procedure SelectFilenameBase(Edit: TEdit);
  251. begin
  252.   if Edit.CanFocus then
  253.   begin
  254.     Edit.SetFocus;
  255.     Edit.SelStart := 0;
  256.     Edit.SelLength := Pos('.', Edit.Text)-1;
  257.   end;
  258. end;
  259.  
  260. function _DecisecondToTime(ds: integer): string;
  261. begin
  262.   result := FormatDatetime('hh:nn:ss', ds / 10 / (24*60*60))+','+IntToStr(ds mod 10);
  263. end;
  264.  
  265. { TForm1 }
  266.  
  267. function TForm1.GetGreatestSceneID: integer;
  268. var
  269.   i: integer;
  270. begin
  271.   result := -1;
  272.   for i := 0 to ListBox1.Items.Count - 1 do
  273.   begin
  274.     result := Max(result, GetSceneIDFromName(ListBox1.Items.Strings[i]));
  275.   end;
  276. end;
  277.  
  278. procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  279.   Shift: TShiftState; X, Y: Integer);
  280. var
  281.   sE1, sE2, sE3, sE4: TSpinEdit;
  282.  
  283.   procedure _Go;
  284.   begin
  285.     if Button = mbLeft then
  286.     begin
  287.       sE1.Value := Round(Image1.Picture.Width*(X/Image1.Width));
  288.       sE2.Value := Round(Image1.Picture.Height*(Y/Image1.Height));
  289.     end
  290.     else if Button = mbRight then
  291.     begin
  292.       sE3.Value := Round(Image1.Picture.Width*(X/Image1.Width));
  293.       sE4.Value := Round(Image1.Picture.Height*(Y/Image1.Height));
  294.     end;
  295.   end;
  296.  
  297. begin
  298.   if PageControl1.ActivePage = TabSheet1 then
  299.   begin
  300.     sE1 := SpinEdit3;
  301.     sE2 := SpinEdit2;
  302.     sE3 := SpinEdit4;
  303.     sE4 := SpinEdit5;
  304.     _Go;
  305.   end
  306.   else if PageControl1.ActivePage = TabSheet2 then
  307.   begin
  308.     sE1 := SpinEdit17;
  309.     sE2 := SpinEdit18;
  310.     sE3 := SpinEdit19;
  311.     sE4 := SpinEdit20;
  312.     _Go;
  313.   end
  314.   else if PageControl1.ActivePage = TabSheet3 then
  315.   begin
  316.     sE1 := SpinEdit7;
  317.     sE2 := SpinEdit8;
  318.     sE3 := SpinEdit10;
  319.     sE4 := SpinEdit9;
  320.     _Go;
  321.   end;
  322. end;
  323.  
  324. procedure TForm1.Image1MouseEnter(Sender: TObject);
  325. begin
  326.   Label28.Visible := true;
  327.   Label29.Visible := true;
  328. end;
  329.  
  330. procedure TForm1.Image1MouseLeave(Sender: TObject);
  331. begin
  332.   Label10.Caption := '';
  333.   Label28.Visible := false;
  334.   Label29.Visible := false;
  335. end;
  336.  
  337. procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  338.   Y: Integer);
  339. begin
  340.   label10.Caption := Format('Coords: [%d, %d]', [Round(Image1.Picture.Width*(X/Image1.Width)),
  341.                                                  Round(Image1.Picture.Height*(Y/Image1.Height))]);
  342. end;
  343.  
  344. function TForm1.SearchSceneIDGapFromTop: integer;
  345. var
  346.   i: integer;
  347. begin
  348.   result := -1;
  349.   for i := 99 downto 0 do
  350.   begin
  351.     if ListBox1.Items.IndexOf(Format('SC%.2d', [i])) = -1 then
  352.     begin
  353.       result := i;
  354.       exit;
  355.     end;
  356.   end;
  357. end;
  358.  
  359. procedure TForm1.Button10Click(Sender: TObject);
  360. begin
  361.   Save;
  362.   if not FileExists('ShowTime32.exe') then raise Exception.Create('GAME.BIN saved; ShowTime32.exe not found.');
  363.   ShellExecute(Application.Handle, 'open', 'ShowTime32.exe', '', '', SW_NORMAL);
  364. end;
  365.  
  366. procedure TForm1.Button11Click(Sender: TObject);
  367. var
  368.   fileName: string;
  369. begin
  370.   fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDecisionBmp;
  371.   if not FileExists(fileName) then exit;
  372.   ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
  373. end;
  374.  
  375. procedure TForm1.Button12Click(Sender: TObject);
  376. var
  377.   fileName: string;
  378. begin
  379.   fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurPicture^.szBitmapFile;
  380.   if not FileExists(fileName) then exit;
  381.   ShellExecute(Application.Handle, 'open', Pchar(fileName), '', '', SW_NORMAL);
  382. end;
  383.  
  384. procedure TForm1.Button13Click(Sender: TObject);
  385. var
  386.   fileName: string;
  387. begin
  388.   fileName := CurScene^.szSceneFolder;
  389.   if not DirectoryExists(fileName) then MkDir(fileName);
  390.   ShellExecute(Application.Handle, 'open', 'explorer.exe', PChar(fileName), '', SW_NORMAL);
  391. end;
  392.  
  393. procedure TForm1.HandlePossibleEmptySceneList;
  394. begin
  395.   if Game.numScenes = 0 then
  396.   begin
  397.     PageControl2.ActivePage := nil;
  398.     PageControl2.Pages[0].TabVisible := false;
  399.     PageControl2.Pages[1].TabVisible := false;
  400.   end
  401.   else
  402.   begin
  403.     if PageControl2.ActivePage = nil then PageControl2.ActivePageIndex := 0;
  404.     PageControl2.Pages[0].TabVisible := true;
  405.     PageControl2.Pages[1].TabVisible := true;
  406.   end;
  407. end;
  408.  
  409. procedure TForm1.Button14Click(Sender: TObject);
  410. begin
  411.   New;
  412. end;
  413.  
  414. procedure TForm1.DisableEnableSceneControls(enable: boolean);
  415. begin
  416.   ListBox1.Enabled := enable;
  417.   Button1.Enabled := enable;
  418.   Button2.Enabled := enable;
  419.   Button4.Enabled := enable;
  420.   Button5.Enabled := enable;
  421. end;
  422.  
  423. procedure TForm1.DisableEnablePictureControls(enable: boolean);
  424. begin
  425.   Button8.Enabled := enable;
  426.   Button9.Enabled := enable;
  427.   Button6.Enabled := enable;
  428.   Button7.Enabled := enable;
  429. end;
  430.  
  431. procedure TForm1.DisableEnableFileControls(enable: boolean);
  432. begin
  433.   Button3.Enabled := enable;
  434.   Button10.Enabled := enable;
  435.   Button14.Enabled := enable;
  436. end;
  437.  
  438. var
  439.   AutomaticNextDia: boolean;
  440.  
  441. procedure TForm1.Button15Click(Sender: TObject);
  442. var
  443.   decisionBMP: string;
  444.   PictureLastFrame: Cardinal;
  445.   i: integer;
  446.   DecisionPicSet: boolean;
  447. begin
  448.   if PlayStart <> 0 then
  449.   begin
  450.     if MediaplayerOpened and not AutomaticNextDia then
  451.     begin
  452.       if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
  453.       Mediaplayer1.TimeFormat := tfMilliseconds;
  454.       if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
  455.       begin
  456.         MediaPlayer1.Position := CurPictureTimepos * 100;
  457.         MediaPlayer1.Play;
  458.       end;
  459.     end;
  460.     AutomaticNextDia := false;
  461.     FirstTickCount := GetTickCount;
  462.     PlayStart := GetTickCount - CurPictureTimepos * 100;
  463.   end
  464.   else
  465.   begin
  466.     TabSheet5.TabVisible := false;
  467.     DisableEnablePictureControls(false);
  468.     DisableEnableSceneControls(false);
  469.     DisableEnableFileControls(false);
  470.     Edit1.Enabled := false;
  471.     Edit3.Enabled := false;
  472.     SpinEdit1.Enabled := false;
  473.     SpinEdit13.Enabled := false;
  474.     Label18.Font.Color := clGreen;
  475.     try
  476.       Timer1.Enabled := false;
  477.  
  478.       RecalcSoundtrackLength; // optional
  479.  
  480.       Mediaplayer1.FileName := Format('%s\%s', [CurScene^.szSceneFolder, CurScene^.szDialogWav]);
  481.       if FileExists(Mediaplayer1.FileName) then
  482.       begin
  483.         Mediaplayer1.TimeFormat := tfMilliseconds;
  484.         Mediaplayer1.Open;
  485.         MediaplayerOpened := true;
  486.         if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
  487.         begin
  488.           MediaPlayer1.Position := CurPictureTimepos * 100;
  489.           MediaPlayer1.Play;
  490.         end;
  491.       end
  492.       else
  493.       begin
  494.         MediaplayerOpened := false;
  495.         MediaPlayer1.FileName := '';
  496.       end;
  497.       PlayStart := GetTickCount - CurPictureTimepos * 100;
  498.       Timer1.Enabled := true;
  499.  
  500.       {$REGION 'Calculate PictureLastFrame'}
  501.       PictureLastFrame := 0;
  502.       for i := 0 to CurScene^.numPics-1 do
  503.       begin
  504.         Inc(PictureLastFrame, Game.pictures[CurScene^.pictureIndex + i].duration);
  505.       end;
  506.       PictureLastFrame := PictureLastFrame * 100;
  507.       {$ENDREGION}
  508.  
  509.       DecisionPicSet := false;
  510.       while not Application.Terminated and
  511.             not StopPlayRequest and
  512.             (
  513.                   (MediaPlayer1.Mode = mpPlaying) or
  514.                   (GetTickCount - PlayStart <= PictureLastFrame)
  515.             ) do
  516.       begin
  517.         if GetTickCount - PlayStart <= PictureLastFrame then
  518.         begin
  519.           DecisionPicSet := false;
  520.           FirstTickCount := GetTickCount;
  521.           while not Application.Terminated and ((GetTickCount - FirstTickCount) < CurPicture^.duration * 100) and not StopPlayRequest do
  522.           begin
  523.             Application.ProcessMessages;
  524.             Sleep(0);
  525.           end;
  526.  
  527.           if not Application.Terminated and (ListBox2.ItemIndex < ListBox2.Count-1) and not StopPlayRequest then
  528.           begin
  529.             ListBox2.ItemIndex := ListBox2.ItemIndex + 1;
  530.             AutomaticNextDia := true;
  531.             ListBox2Click(ListBox2);
  532.           end;
  533.         end
  534.         else
  535.         begin
  536.           if not DecisionPicSet then
  537.           begin
  538.             decisionBMP := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDecisionBmp;
  539.             if (CurScene^.szDecisionBmp <> '') and FileExists(decisionBMP) then
  540.             begin
  541.               Image2.Picture.LoadFromFile(decisionBMP);
  542.               AspectRatio(Image2, Panel2);
  543.             end
  544.             else
  545.             begin
  546.               Image2.Picture := nil;
  547.             end;
  548.             DecisionPicSet := true;
  549.           end;
  550.           Application.ProcessMessages;
  551.           Sleep(0);
  552.         end;
  553.       end;
  554.     finally
  555.       PlayStart := 0;
  556.       if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
  557.       if MediaplayerOpened then MediaPlayer1.Close;
  558.       StopPlayRequest := false;
  559.       Label18.Font.Color := clWindowText;
  560.       Timer1.Enabled := false;
  561.       DisableEnableFileControls(true);
  562.       DisableEnableSceneControls(true);
  563.       DisableEnablePictureControls(true);
  564.       TabSheet5.TabVisible := true;
  565.       Edit1.Enabled := true;
  566.       SpinEdit1.Enabled := true;
  567.       Edit3.Enabled := true;
  568.       SpinEdit13.Enabled := true;
  569.       Label18.Caption := _DecisecondToTime(CurPictureTimepos);
  570.       ListBox2Click(ListBox2);
  571.     end;
  572.   end;
  573. end;
  574.  
  575. procedure TForm1.ShowSceneBmp;
  576. var
  577.   Filename: string;
  578. begin
  579.   Filename := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurPicture^.szBitmapFile);
  580.   if FileExists(Filename) then
  581.   begin
  582.     Image2.Picture.LoadFromFile(Filename);
  583.     AspectRatio(Image2, Panel2);
  584.   end
  585.   else
  586.   begin
  587.     Image2.Picture := nil;
  588.   end;
  589. end;
  590.  
  591. procedure TForm1.Button16Click(Sender: TObject);
  592. begin
  593.   ListBox2.ItemIndex := 0; // go to the beginning
  594.   ListBox2Click(ListBox2); // load picture data
  595.   Button15Click(Button15); // play
  596. end;
  597.  
  598. procedure TForm1.Button17Click(Sender: TObject);
  599. begin
  600.   if PlayStart <> 0 then
  601.   begin
  602.     Timer1.Enabled := false;
  603.     if MediaplayerOpened then MediaPlayer1.Stop;
  604.     StopPlayRequest := true;
  605.   end;
  606. end;
  607.  
  608. procedure TForm1.Button18Click(Sender: TObject);
  609. var
  610.   fileName: string;
  611. begin
  612.   fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
  613.   if not FileExists(fileName) then exit;
  614.   ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
  615. end;
  616.  
  617. procedure TForm1.Button19Click(Sender: TObject);
  618. begin
  619.   if MessageDlg('Are you sure you want to discard all changes?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
  620.   begin
  621.     CopyMemory(@Game, @GameBak, SizeOf(Game));
  622.     SetupGUIAfterLoad;
  623.   end;
  624. end;
  625.  
  626. procedure TForm1.NewScene;
  627. var
  628.   sceneID: integer;
  629.   newScene: PSceneDef;
  630. begin
  631.   if ListBox1.Items.Count = 100 then
  632.   begin
  633.     raise Exception.Create('No more space for another scene');
  634.   end;
  635.  
  636.   sceneID := GetGreatestSceneID+1;
  637.   if sceneID >= Length(Game.scenes) then sceneID := SearchSceneIDGapFromTop;
  638.  
  639.   newScene := Game.AddSceneAtEnd(sceneID);
  640.   newScene.actions[0].nextSceneID := SCENEID_ENDGAME;
  641.   newScene.pictureIndex := Game.numPics;
  642.   ListBox1.Items.Add(newScene.szSceneFolder);
  643.   ReloadActionSceneLists;
  644.   HandlePossibleEmptySceneList;
  645.   ListBox1.ItemIndex := ListBox1.Items.Count - 1;
  646.   ListBox1Click(ListBox1);
  647. end;
  648.  
  649. procedure TForm1.Button1Click(Sender: TObject);
  650. begin
  651.   NewScene;
  652. end;
  653.  
  654. procedure TForm1.Button20Click(Sender: TObject);
  655. begin
  656.   Game.Defrag;
  657.   RecalcStats;
  658. end;
  659.  
  660. procedure TForm1.Button2Click(Sender: TObject);
  661. var
  662.   iScene, iAction, sceneID: integer;
  663.   conflicts: TStringList;
  664.   sWarning: string;
  665.   bakItemindex: integer;
  666. begin
  667.   if ListBox1.Count = 0 then exit;
  668.  
  669.   (*
  670.   if ListBox1.Count = 1 then
  671.   begin
  672.     raise Exception.Create('Can''t delete the scene if there is only one.');
  673.   end;
  674.   *)
  675.  
  676.   conflicts := TStringList.Create;
  677.   try
  678.     sceneID := GetSceneIDFromName(CurScene^.szSceneFolder);
  679.     for iScene := 0 to Game.numScenes-1 do
  680.     begin
  681.       for iAction := 0 to Game.scenes[iScene].numActions-1 do
  682.       begin
  683.         if Game.scenes[iScene].actions[iAction].nextSceneID = sceneID then
  684.         begin
  685.           conflicts.Add(Format('Scene %s, action #%d', [Game.scenes[iScene].szSceneFolder, iAction+1]));
  686.         end;
  687.       end;
  688.     end;
  689.     if conflicts.Count > 0 then
  690.     begin
  691.       raise Exception.Create('Can''t delete this scene. There are following dependencies:'+#13#10#13#10+conflicts.Text);
  692.     end;
  693.   finally
  694.     FreeAndNil(conflicts);
  695.   end;
  696.  
  697.   sWarning := Format('Do you really want to delete scene %s?', [CurScene^.szSceneFolder]);
  698.   if (ListBox1.ItemIndex = 0) and (ListBox1.Count >= 2) then
  699.     sWarning := Format('Attention: This will make %s to your new intro sequence. Is that OK?', [ListBox1.Items[ListBox1.ItemIndex+1]]);
  700.   if (MessageDlg(sWarning, mtConfirmation, mbYesNoCancel, 0) <> mrYes) then
  701.   begin
  702.     Exit;
  703.   end;
  704.  
  705.   Game.DeleteScene(ListBox1.ItemIndex);
  706.  
  707.   bakItemindex := ListBox1.ItemIndex;
  708.   ListBox1.Items.Delete(bakItemindex);
  709.   ReloadActionSceneLists;
  710.   HandlePossibleEmptySceneList;
  711.   if ListBox1.Count > 0 then
  712.   begin
  713.     if bakItemindex = ListBox1.Count then Dec(bakItemindex);
  714.     Listbox1.ItemIndex := bakItemindex;
  715.     ListBox1Click(ListBox1);
  716.   end;
  717. end;
  718.  
  719. procedure TForm1.Button3Click(Sender: TObject);
  720. begin
  721.   Save;
  722. end;
  723.  
  724. procedure TForm1.Button4Click(Sender: TObject);
  725. begin
  726.   if ListBox1.ItemIndex <= 0 then exit;
  727.   Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
  728.   ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
  729.   ReloadActionSceneLists;
  730. end;
  731.  
  732. procedure TForm1.Button5Click(Sender: TObject);
  733. begin
  734.   if ListBox1.ItemIndex = ListBox1.Count-1 then exit;
  735.   Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
  736.   ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
  737.   ReloadActionSceneLists;
  738. end;
  739.  
  740. procedure TForm1.Button6Click(Sender: TObject);
  741. var
  742.   pic: PPictureDef;
  743. begin
  744.   if ListBox2.Items.Count > 0 then
  745.     pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex+1,0), false)
  746.   else
  747.     pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0), true);
  748.   pic.duration     := DEFAULT_DURATION;
  749.   pic.szBitmapFile := DEFAULT_FILENAME;
  750.   if ListBox2.ItemIndex = -1 then
  751.   begin
  752.     ListBox2.Items.Insert(ListBox2.Count, Format('(%d) %s', [DEFAULT_DURATION, DEFAULT_FILENAME]));
  753.     ListBox2.ItemIndex := ListBox2.Count - 1;
  754.   end
  755.   else
  756.   begin
  757.     ListBox2.Items.Insert(ListBox2.ItemIndex+1, Format('(%d) %s', [DEFAULT_DURATION, DEFAULT_FILENAME]));
  758.     ListBox2.ItemIndex := ListBox2.ItemIndex + 1;
  759.   end;
  760.   ListBox2Click(Listbox2);
  761.   SelectFilenameBase(Edit3);
  762.   RecalcStats;
  763. end;
  764.  
  765. procedure TForm1.Button7Click(Sender: TObject);
  766. var
  767.   bakIdx: integer;
  768. begin
  769.   if Listbox2.Count > 0 then
  770.   begin
  771.     bakIdx := ListBox2.ItemIndex;
  772.     Game.DeletePicture(CurScene^.pictureIndex + bakIdx);
  773.     ListBox2.Items.Delete(bakIdx);
  774.     if ListBox2.Count > 0 then
  775.     begin
  776.       if bakIdx = ListBox2.Count then Dec(bakIdx);
  777.       ListBox2.ItemIndex := bakIdx;
  778.       ListBox2Click(Listbox2);
  779.     end;
  780.     RecalcUnusedFiles;
  781.   end;
  782.   RecalcStats;
  783. end;
  784.  
  785. procedure TForm1.Button8Click(Sender: TObject);
  786. begin
  787.   if ListBox2.ItemIndex <= 0 then exit;
  788.   Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex-1);
  789.   ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex-1);
  790. end;
  791.  
  792. procedure TForm1.Button9Click(Sender: TObject);
  793. begin
  794.   if ListBox2.ItemIndex = ListBox2.Count-1 then exit;
  795.   Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex+1);
  796.   ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex+1);
  797. end;
  798.  
  799. procedure TForm1.Save;
  800. var
  801.   fs: TFileStream;
  802. begin
  803.   CopyMemory(@GameBak, @Game, SizeOf(Game));
  804.  
  805.   fs := TFileStream.Create('GAME.BIN', fmOpenWrite or fmCreate);
  806.   try
  807.     fs.WriteBuffer(Game, SizeOf(Game));
  808.   finally
  809.     FreeAndNil(fs);
  810.   end;
  811. end;
  812.  
  813. procedure TForm1.ActionTargetChange(Sender: TObject);
  814. var
  815.   actionIdx: integer;
  816.   itemIdx: Integer;
  817. begin
  818.        if Sender = ComboBox1 then actionIdx := 0
  819.   else if Sender = ComboBox2 then actionIdx := 1
  820.   else if Sender = ComboBox3 then actionIdx := 2
  821.   else raise Exception.Create('Unexpected sender for ActionTargetChange()');
  822.  
  823.   itemIdx := TComboBox(Sender).ItemIndex;
  824.   if itemIdx = 0 then
  825.     CurScene^.actions[actionIdx].nextSceneID := SCENEID_ENDGAME
  826.   else if itemIdx = 1 then
  827.     CurScene^.actions[actionIdx].nextSceneID := SCENEID_PREVDECISION
  828.   else
  829.     CurScene^.actions[actionIdx].nextSceneID := GetSceneIDFromName(ListBox1.Items[itemIdx - 2]);
  830. end;
  831.  
  832. procedure TForm1.Addtoscene1Click(Sender: TObject);
  833. var
  834.   fil: string;
  835. begin
  836.   if ListBox3.ItemIndex = -1 then exit;
  837.   fil := ListBox3.Items[ListBox3.ItemIndex];
  838.   Button6.Click;
  839.   Edit3.Text := fil;
  840. end;
  841.  
  842. procedure TForm1.Edit1Change(Sender: TObject);
  843. begin
  844.   _WriteStringToFilename(@CurScene^.szDialogWav, Edit1.Text);
  845.   RecalcSoundtrackLength;
  846.   RecalcUnusedFiles;
  847.  
  848.   Label24.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit1.Text);
  849.   Label25.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + 'E' + Edit1.Text);
  850.  
  851.   Button18.Visible := CurScene^.szDialogWav <> '';
  852. end;
  853.  
  854. procedure TForm1.Edit2Change(Sender: TObject);
  855. begin
  856.   _WriteStringToFilename(@CurScene^.szDecisionBmp, Edit2.Text);
  857.   RecalcUnusedFiles;
  858.   RedrawDecisionBitmap;
  859.   Label27.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text) and not (Edit2.Text = '');
  860.   Button11.Visible := CurScene^.szDecisionBmp <> '';
  861. end;
  862.  
  863. procedure TForm1.Edit3Change(Sender: TObject);
  864. begin
  865.   _WriteStringToFilename(@CurPicture^.szBitmapFile, Edit3.Text);
  866.   ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
  867.   RecalcUnusedFiles;
  868.   ShowSceneBmp;
  869.   Label26.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit3.Text);
  870.   Button12.Visible := CurPicture^.szBitmapFile <> '';
  871. end;
  872.  
  873. procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  874. begin
  875.   if not CompareMem(@Game, @GameBak, SizeOf(Game)) then
  876.   begin
  877.     case MessageDlg('Do you want to save the changes?', mtConfirmation, mbYesNoCancel, 0) of
  878.       mrYes:
  879.       begin
  880.         Save;
  881.         CanClose := true;
  882.       end;
  883.       mrNo:
  884.       begin
  885.         CanClose := true;
  886.       end;
  887.       mrCancel:
  888.       begin
  889.         CanClose := false;
  890.       end;
  891.     end;
  892.   end;
  893. end;
  894.  
  895. procedure TForm1.FormCreate(Sender: TObject);
  896. begin
  897.   PageControl1.ActivePageIndex := 0;
  898.   PageControl2.ActivePageIndex := 0;
  899.   PageControl3.ActivePageIndex := 0;
  900.   Label10.Caption := '';
  901.   Label21.Caption := '';
  902.   Label23.Caption := '';
  903. end;
  904.  
  905. procedure TForm1.FormShow(Sender: TObject);
  906. begin
  907.   if FileExists('GAME.BIN') then
  908.     Load
  909.   else
  910.     New;
  911. end;
  912.  
  913. function TForm1.CurScene: PSceneDef;
  914. begin
  915.   if ListBox1.Count = 0 then raise Exception.Create('No scene available. Please create one.');
  916.   if ListBox1.ItemIndex = -1 then raise Exception.Create('No scene selected. Please select one.');
  917.   result := @Game.scenes[ListBox1.ItemIndex];
  918. end;
  919.  
  920. procedure TForm1.ListBox1Click(Sender: TObject);
  921. begin
  922.   LoadScene;
  923. end;
  924.  
  925. procedure TForm1.ListBox1DblClick(Sender: TObject);
  926. begin
  927.   Button16Click(Button16);
  928. end;
  929.  
  930. procedure TForm1.CheckBox1Click(Sender: TObject);
  931. begin
  932.   RedrawDecisionBitmap;
  933. end;
  934.  
  935. procedure TForm1.Close1Click(Sender: TObject);
  936. begin
  937.   Close;
  938. end;
  939.  
  940. function TForm1.CurPicture: PPictureDef;
  941. begin
  942.   if ListBox2.Count = 0 then raise Exception.Create('No pictures available. Please create one.');
  943.   if ListBox2.ItemIndex = -1 then raise Exception.Create('No pictures selected. Please select one.');
  944.   result := @Game.pictures[CurScene^.pictureIndex + ListBox2.ItemIndex]
  945. end;
  946.  
  947. function TForm1.CurPictureTimepos: Cardinal;
  948. var
  949.   i: integer;
  950. begin
  951.   result := 0;
  952.   for i := curScene^.pictureIndex to curScene^.pictureIndex + ListBox2.ItemIndex - 1 do
  953.   begin
  954.     Inc(result, Game.pictures[i].duration);
  955.   end;
  956. end;
  957.  
  958. class procedure TForm1.AspectRatio(image: TImage; panel: TControl);
  959. var
  960.   wi, hi, ws, hs: integer;
  961.   ri, rs: double;
  962. begin
  963.   wi := image.Picture.Width;
  964.   hi := image.Picture.Height;
  965.   ri := wi / hi;
  966.  
  967.   ws := panel.Width;
  968.   hs := panel.Height;
  969.   rs := ws / hs;
  970.  
  971.   if rs > ri then
  972.   begin
  973.     image.Width  := Round(wi * hs/hi);
  974.     image.Height := hs;
  975.   end
  976.   else
  977.   begin
  978.     image.Width  := ws;
  979.     image.Height := Round(hi * ws/wi);
  980.   end;
  981.  
  982.   image.Left := Round(panel.Width  / 2 - image.Width  / 2);
  983.   image.Top  := Round(panel.Height / 2 - image.Height / 2);
  984. end;
  985.  
  986. procedure TForm1.ListBox2Click(Sender: TObject);
  987. var
  988.   bakEvent: TNotifyEvent;
  989. begin
  990.   if CurScene^.numPics = 0 then
  991.   begin
  992.     SpinEdit13.Value := 0;
  993.  
  994.     bakEvent := Edit3.OnChange;
  995.     try
  996.       Edit3.OnChange := nil;
  997.       Edit3.Text := '';
  998.     finally
  999.       Edit3.OnChange := bakEvent;
  1000.     end;
  1001.  
  1002.     Label18.Caption := '';
  1003.     Image2.Picture := nil;
  1004.     exit;
  1005.   end;
  1006.  
  1007.   SpinEdit13.Value := CurPicture^.duration;
  1008.   Edit3.Text := string(CurPicture^.szBitmapFile);
  1009.  
  1010.   ShowSceneBmp;
  1011.  
  1012.   Label18.Caption := _DecisecondToTime(CurPictureTimepos);
  1013.  
  1014.   if PlayStart <> 0 then
  1015.   begin
  1016.     Button15Click(Button15);
  1017.   end;
  1018.  
  1019.   RecalcStats;
  1020. end;
  1021.  
  1022. procedure TForm1.ListBox2DblClick(Sender: TObject);
  1023. begin
  1024.   Button15Click(Button15);
  1025. end;
  1026.  
  1027. procedure TForm1.ListBox3Click(Sender: TObject);
  1028. var
  1029.   fileName: string;
  1030. begin
  1031.   if ListBox3.ItemIndex = -1 then exit;
  1032.   fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + ListBox3.Items[ListBox3.ItemIndex];
  1033.   Image3.Visible := FileExists(FileName);
  1034.   if not FileExists(FileName) then exit;
  1035.   Image3.Picture.LoadFromFile(Filename);
  1036.   AspectRatio(Image3, Panel3);
  1037. end;
  1038.  
  1039. procedure TForm1.ListBox3DblClick(Sender: TObject);
  1040. var
  1041.   fileName: string;
  1042. begin
  1043.   if ListBox3.ItemIndex = -1 then exit;
  1044.   fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + ListBox3.Items[ListBox3.ItemIndex];
  1045.   if not FileExists(FileName) then exit;
  1046.   ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
  1047. end;
  1048.  
  1049. procedure TForm1.ListBox3MouseDown(Sender: TObject; Button: TMouseButton;
  1050.   Shift: TShiftState; X, Y: Integer);
  1051. var
  1052.   APoint: TPoint;
  1053.   Index: integer;
  1054. begin
  1055.   if Button = mbRight then
  1056.   begin
  1057.     APoint.X := X;
  1058.     APoint.Y := Y;
  1059.     Index := TListbox(Sender).ItemAtPos(APoint, True);
  1060.     if Index > -1 then TListbox(Sender).Selected[Index] := True;
  1061.   end;
  1062. end;
  1063.  
  1064. procedure TForm1.SetupGUIAfterLoad;
  1065. var
  1066.   i: integer;
  1067. begin
  1068.   ListBox1.Clear;
  1069.   for i := 0 to Game.numScenes - 1 do
  1070.   begin
  1071.     ListBox1.Items.Add(string(Game.scenes[i].szSceneFolder));
  1072.   end;
  1073.   (*
  1074.   if ListBox1.Items.Count = 0 then
  1075.   begin
  1076.     NewScene;
  1077.   end;
  1078.   *)
  1079.  
  1080.   ReloadActionSceneLists;
  1081.   HandlePossibleEmptySceneList;
  1082.  
  1083.   if ListBox1.Count > 0 then
  1084.   begin
  1085.     ListBox1.ItemIndex := 0;
  1086.     ListBox1Click(Listbox1);
  1087.   end;
  1088. end;
  1089.  
  1090. procedure TForm1.New;
  1091. begin
  1092.   PageControl1.ActivePageIndex := 0;
  1093.   PageControl2.ActivePageIndex := 0;
  1094.   PageControl3.ActivePageIndex := 0;
  1095.   Label10.Caption := '';
  1096.   Label21.Caption := '';
  1097.   Label23.Caption := '';
  1098.  
  1099.   ZeroMemory(@Game, SizeOf(Game));
  1100.   ZeroMemory(@GameBak, SizeOf(Game));
  1101.  
  1102.   SetupGUIAfterLoad;
  1103. end;
  1104.  
  1105. procedure TForm1.Load;
  1106. var
  1107.   fs: TFileStream;
  1108. begin
  1109.   fs := TFileStream.Create('GAME.BIN', fmOpenRead);
  1110.   try
  1111.     fs.ReadBuffer(Game, SizeOf(Game));
  1112.   finally
  1113.     FreeAndNil(fs);
  1114.   end;
  1115.  
  1116.   CopyMemory(@GameBak, @Game, SizeOf(Game));
  1117.  
  1118.   if Game.RealPictureCount <> Game.numPics then
  1119.   begin
  1120.     MessageDlg('Picture count was wrong. Value was corrected.', mtInformation, [mbOk], 0);
  1121.     Game.numPics := Game.RealPictureCount;
  1122.   end;
  1123.  
  1124.   SetupGUIAfterLoad;
  1125. end;
  1126.  
  1127. function TForm1.FindSceneIndex(sceneID: integer): integer;
  1128. var
  1129.   i: Integer;
  1130.   sSceneID: string;
  1131. begin
  1132.   sSceneID := Format('SC%.2d', [sceneID]);
  1133.   for i := 0 to ListBox1.Count - 1 do
  1134.   begin
  1135.     if ListBox1.Items.Strings[i] = sSceneID then
  1136.     begin
  1137.       result := i;
  1138.       exit;
  1139.     end;
  1140.   end;
  1141.   result := -1;
  1142. end;
  1143.  
  1144. procedure TForm1.RecalcSlideshowLength;
  1145. var
  1146.   i: integer;
  1147.   Sum: integer;
  1148. begin
  1149.   Sum := 0;
  1150.   for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
  1151.   begin
  1152.     Inc(Sum, Game.pictures[i].duration);
  1153.   end;
  1154.   Label21.Caption := _DecisecondToTime(Sum);
  1155. end;
  1156.  
  1157. procedure TForm1.RecalcUnusedFiles;
  1158. var
  1159.   i, idx: integer;
  1160.   SR: TSearchRec;
  1161.   ext: string;
  1162. begin
  1163.   ListBox3.Items.BeginUpdate;
  1164.   try
  1165.     ListBox3.Clear;
  1166.  
  1167.     Image3.Visible := false;
  1168.  
  1169.     if FindFirst(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + '*.*', faArchive, SR) = 0 then
  1170.     begin
  1171.       repeat
  1172.         ext := UpperCase(ExtractFileExt(SR.Name));
  1173.         if ((ext <> '.PK' {Adobe Audition}) and (ext <> '.DB' {Windows Thumbnail})) then
  1174.         begin
  1175.           ListBox3.Items.Add(SR.Name); //Fill the list
  1176.         end;
  1177.       until FindNext(SR) <> 0;
  1178.       FindClose(SR);
  1179.     end;
  1180.  
  1181.     // Remove the entries which are present
  1182.     for i := CurScene^.pictureIndex to CurScene^.pictureIndex+CurScene^.numPics-1 do
  1183.     begin
  1184.       idx := ListBox3.Items.IndexOf(Game.pictures[i].szBitmapFile);
  1185.       if idx <> -1 then ListBox3.Items.Delete(idx);
  1186.     end;
  1187.  
  1188.     idx := ListBox3.Items.IndexOf(Edit1.Text);
  1189.     if idx <> -1 then ListBox3.Items.Delete(idx);
  1190.     idx := ListBox3.Items.IndexOf('E'+Edit1.Text);
  1191.     if idx <> -1 then ListBox3.Items.Delete(idx);
  1192.  
  1193.     idx := ListBox3.Items.IndexOf(Edit2.Text);
  1194.     if idx <> -1 then ListBox3.Items.Delete(idx);
  1195.  
  1196.     idx := ListBox3.Items.IndexOf(Edit3.Text);
  1197.     if idx <> -1 then ListBox3.Items.Delete(idx);
  1198.   finally
  1199.     ListBox3.Items.EndUpdate;
  1200.   end;
  1201. end;
  1202.  
  1203. procedure TForm1.RecalcSoundtrackLength;
  1204. var
  1205.   FileName: string;
  1206. begin
  1207.   if MediaPlayer1.Mode = mpPlaying then exit;
  1208.  
  1209.   FileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
  1210.   if not FileExists(FileName) then
  1211.   begin
  1212.     Label23.Caption := 'n/a';
  1213.     exit;
  1214.   end;
  1215.   MediaPlayer1.FileName := FileName;
  1216.   MediaPlayer1.TimeFormat := tfMilliseconds;
  1217.   MediaPlayer1.Open;
  1218.   Label23.Caption := _DecisecondToTime(MediaPlayer1.Length div 100);
  1219.   MediaPlayer1.Close;
  1220. end;
  1221.  
  1222. procedure TForm1.LoadScene;
  1223.  
  1224.   procedure _SelectActionComboBox(ComboBox: TComboBox; sceneID: SmallInt);
  1225.   var
  1226.     idx: Integer;
  1227.   begin
  1228.     if sceneID = SCENEID_ENDGAME then
  1229.       ComboBox.ItemIndex := 0
  1230.     else if sceneID = SCENEID_PREVDECISION then
  1231.       ComboBox.ItemIndex := 1
  1232.     else
  1233.     begin
  1234.       idx := FindSceneIndex(sceneID);
  1235.       if idx = -1 then
  1236.         ComboBox.ItemIndex := -1
  1237.       else
  1238.         ComboBox.ItemIndex := 2 + idx;
  1239.     end;
  1240.   end;
  1241.  
  1242.   procedure _PreparePictureList;
  1243.   var
  1244.     i: integer;
  1245.     //pic: PPictureDef;
  1246.   begin
  1247.     ListBox2.Clear;
  1248.  
  1249.     if CurScene^.numPics = 0 then
  1250.     begin
  1251.       (*
  1252.       pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0));
  1253.       pic.duration := DEFAULT_DURATION;
  1254.       pic.szBitmapFile := DEFAULT_FILENAME;
  1255.       *)
  1256.     end;
  1257.  
  1258.     for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
  1259.     begin
  1260.       Listbox2.Items.Add(Format('(%d) %s', [Game.pictures[i].duration, Game.pictures[i].szBitmapFile]));
  1261.     end;
  1262.   end;
  1263.  
  1264. begin
  1265.   SpinEdit1.Value := GetSceneIDFromName(CurScene^.szSceneFolder);
  1266.   Edit1.Text := string(CurScene^.szDialogWav);
  1267.   Edit2.Text := string(CurScene^.szDecisionBmp);
  1268.  
  1269.   _PreparePictureList;
  1270.   ListBox2.ItemIndex := 0;
  1271.   ListBox2Click(Listbox2);
  1272.  
  1273.   _SelectActionComboBox(ComboBox1, CurScene^.actions[0].nextSceneID);
  1274.   _SelectActionComboBox(ComboBox2, CurScene^.actions[1].nextSceneID);
  1275.   _SelectActionComboBox(ComboBox3, CurScene^.actions[2].nextSceneID);
  1276.  
  1277.   SpinEdit12.Value := CurScene^.numActions;
  1278.   SpinEdit12Change(SpinEdit12);
  1279.   PageControl1.ActivePageIndex := 0;
  1280.  
  1281.   SpinEdit3.Value  := CurScene^.actions[0].cHotspotTopLeft.X;
  1282.   SpinEdit17.Value := CurScene^.actions[1].cHotspotTopLeft.X;
  1283.   SpinEdit7.Value  := CurScene^.actions[2].cHotspotTopLeft.X;
  1284.   SpinEdit2.Value  := CurScene^.actions[0].cHotspotTopLeft.Y;
  1285.   SpinEdit18.Value := CurScene^.actions[1].cHotspotTopLeft.Y;
  1286.   SpinEdit8.Value  := CurScene^.actions[2].cHotspotTopLeft.Y;
  1287.   SpinEdit4.Value  := CurScene^.actions[0].cHotspotBottomRight.X;
  1288.   SpinEdit19.Value := CurScene^.actions[1].cHotspotBottomRight.X;
  1289.   SpinEdit10.Value := CurScene^.actions[2].cHotspotBottomRight.X;
  1290.   SpinEdit5.Value  := CurScene^.actions[0].cHotspotBottomRight.Y;
  1291.   SpinEdit20.Value := CurScene^.actions[1].cHotspotBottomRight.Y;
  1292.   SpinEdit9.Value  := CurScene^.actions[2].cHotspotBottomRight.Y;
  1293.   SpinEdit6.Value  := CurScene^.actions[0].scoreDelta;
  1294.   SpinEdit21.Value := CurScene^.actions[1].scoreDelta;
  1295.   SpinEdit11.Value := CurScene^.actions[2].scoreDelta;
  1296.  
  1297.   RedrawDecisionBitmap;
  1298.  
  1299.   RecalcSlideshowLength;
  1300.   RecalcSoundtrackLength;
  1301.  
  1302.   RecalcUnusedFiles;
  1303.  
  1304.   RecalcStats;
  1305. end;
  1306.  
  1307. procedure TForm1.RecalcStats;
  1308. begin
  1309.   Label35.Caption := IntToStr(ListBox1.ItemIndex) + ' / ' + IntToStr(Game.numScenes);
  1310.  
  1311.   if ListBox2.ItemIndex >= 0 then
  1312.     Label31.Caption := IntToStr(CurScene^.pictureIndex) + ' + ' + IntToStr(ListBox2.ItemIndex) + ' = ' + IntToStr(CurScene^.pictureIndex+ListBox2.ItemIndex)
  1313.   else
  1314.     Label31.Caption := IntToStr(CurScene^.pictureIndex);
  1315.  
  1316.   Label33.Caption := IntToStr(CurScene^.numPics) + ' / ' + IntToStr(Game.numPics);
  1317.  
  1318.   Label37.Caption := IntToStr(CurScene^.numActions) + ' / ' + IntToStr(Game.RealActionCount);
  1319. end;
  1320.  
  1321. procedure TForm1.ReloadActionSceneLists;
  1322.  
  1323.   procedure _ReloadActionSceneLists(ComboBox: TComboBox);
  1324.   var
  1325.     prevSelection: string;
  1326.     i: Integer;
  1327.   begin
  1328.     prevSelection := ComboBox.Text;
  1329.     try
  1330.       ComboBox.Items.Clear;
  1331.       ComboBox.Items.Add('Terminate program');
  1332.       ComboBox.Items.Add('Previous decision');
  1333.       ComboBox.Items.AddStrings(ListBox1.Items);
  1334.     finally
  1335.       ComboBox.ItemIndex := 0;
  1336.       for i := ComboBox.Items.Count - 1 downto 0 do
  1337.       begin
  1338.         if ComboBox.Items.Strings[i] = prevSelection then
  1339.         begin
  1340.           ComboBox.ItemIndex := i;
  1341.         end;
  1342.       end;
  1343.     end;
  1344.   end;
  1345.  
  1346. begin
  1347.   _ReloadActionSceneLists(ComboBox1);
  1348.   _ReloadActionSceneLists(ComboBox2);
  1349.   _ReloadActionSceneLists(ComboBox3);
  1350. end;
  1351.  
  1352. procedure TForm1.SpinEdit12Change(Sender: TObject);
  1353. begin
  1354.   TabSheet3.TabVisible := SpinEdit12.Value >= 3;
  1355.   if PageControl1.ActivePage = TabSheet3 then PageControl1.ActivePage := TabSheet2;
  1356.  
  1357.   TabSheet2.TabVisible := SpinEdit12.Value >= 2;
  1358.   if PageControl1.ActivePage = TabSheet2 then PageControl1.ActivePage := TabSheet1;
  1359.  
  1360.   // TabSheet1.TabVisible := SpinEdit12.Value >= 1;
  1361.  
  1362.   CurScene^.numActions := SpinEdit12.Value;
  1363.  
  1364.   // QUE: zero data of actions which are inactive (numActions<action)?
  1365.  
  1366.   RecalcStats;
  1367.   RedrawDecisionBitmap;
  1368. end;
  1369.  
  1370. procedure TForm1.SpinEdit13Change(Sender: TObject);
  1371. begin
  1372.   if SpinEdit13.Text = '' then exit;
  1373.   CurPicture^.duration := SpinEdit13.Value;
  1374.   ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
  1375.   RecalcSlideshowLength;
  1376. end;
  1377.  
  1378. procedure TForm1.SpinEdit1Change(Sender: TObject);
  1379.  
  1380.   function _CountNumScenes(str: string): integer;
  1381.   var
  1382.     i: integer;
  1383.   begin
  1384.     result := 0;
  1385.     for i := 0 to ListBox1.Count-1 do
  1386.     begin
  1387.       if ListBox1.Items[i] = str then Inc(result);
  1388.     end;
  1389.   end;
  1390.  
  1391. var
  1392.   sNew: string;
  1393. begin
  1394.   // TODO: warn if dependencies are broken
  1395.  
  1396.   if SpinEdit1.Text = '' then exit;
  1397.   CurScene; // verify that a scene exists and is selected
  1398.   sNew := Format('SC%.2d', [SpinEdit1.Value]);
  1399.   ListBox1.Items[ListBox1.ItemIndex] := sNew;
  1400.   Label17.Visible := _CountNumScenes(sNew) > 1;
  1401.   ReloadActionSceneLists;
  1402.   _WriteStringToFilename(@CurScene^.szSceneFolder, ListBox1.Items[ListBox1.ItemIndex]);
  1403. end;
  1404.  
  1405. procedure TForm1.Timer1Timer(Sender: TObject);
  1406. var
  1407.   ms: Cardinal;
  1408. begin
  1409.   ms := GetTickCount - PlayStart;
  1410.   Label18.Caption := FormatDatetime('hh:nn:ss', ms / 1000 / (24*60*60)) + ',' + IntToStr(ms mod 1000 div 100);
  1411. end;
  1412.  
  1413. procedure TForm1.About1Click(Sender: TObject);
  1414. begin
  1415.   ShowMessage('Plumbers Don''t Wear Ties - GAME.BIN editor (can be also used to create new games based on the "ShowTime" engine!)'+#13#10#13#10+'Written by Daniel Marschall (www.daniel-marschall.de)'+#13#10#13#10+'Published by ViaThinkSoft (www.viathinksoft.com)'+#13#10#13#10+'Current version: ' + CUR_VER);
  1416. end;
  1417.  
  1418. procedure TForm1.ActionSpinEditsChange(Sender: TObject);
  1419. begin
  1420.   if TSpinEdit(Sender).Text = '' then exit; // user is about to enter a negative value
  1421.   if TSpinEdit(Sender).Text = '-' then exit; // user is about to enter a negative value
  1422.  
  1423.        if Sender = SpinEdit3  then CurScene^.actions[0].cHotspotTopLeft.X := TSpinEdit(Sender).Value
  1424.   else if Sender = SpinEdit17 then CurScene^.actions[1].cHotspotTopLeft.X := TSpinEdit(Sender).Value
  1425.   else if Sender = SpinEdit7  then CurScene^.actions[2].cHotspotTopLeft.X := TSpinEdit(Sender).Value
  1426.   else if Sender = SpinEdit2  then CurScene^.actions[0].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
  1427.   else if Sender = SpinEdit18 then CurScene^.actions[1].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
  1428.   else if Sender = SpinEdit8  then CurScene^.actions[2].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
  1429.   else if Sender = SpinEdit4  then CurScene^.actions[0].cHotspotBottomRight.X := TSpinEdit(Sender).Value
  1430.   else if Sender = SpinEdit19 then CurScene^.actions[1].cHotspotBottomRight.X := TSpinEdit(Sender).Value
  1431.   else if Sender = SpinEdit10 then CurScene^.actions[2].cHotspotBottomRight.X := TSpinEdit(Sender).Value
  1432.   else if Sender = SpinEdit5  then CurScene^.actions[0].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
  1433.   else if Sender = SpinEdit20 then CurScene^.actions[1].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
  1434.   else if Sender = SpinEdit9  then CurScene^.actions[2].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
  1435.   else if Sender = SpinEdit6  then CurScene^.actions[0].scoreDelta := TSpinEdit(Sender).Value
  1436.   else if Sender = SpinEdit21 then CurScene^.actions[1].scoreDelta := TSpinEdit(Sender).Value
  1437.   else if Sender = SpinEdit11 then CurScene^.actions[2].scoreDelta := TSpinEdit(Sender).Value;
  1438.  
  1439.   RedrawDecisionBitmap;
  1440. end;
  1441.  
  1442. procedure TForm1.RedrawDecisionBitmap;
  1443. var
  1444.   Filename: string;
  1445. begin
  1446.   FileName := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text);
  1447.  
  1448.   Image1.Visible := FileExists(FileName);
  1449.  
  1450.   if not FileExists(FileName) then exit;
  1451.  
  1452.   Image1.Picture.Bitmap.LoadFromFile(FileName);
  1453.   AspectRatio(Image1, Panel1);
  1454.  
  1455.   Image1.Picture.Bitmap.PixelFormat := pf24bit; // Extend the palette, so we have red, green and blue guaranteed.
  1456.  
  1457.   Image1.Canvas.Brush.Style := bsDiagCross;
  1458.  
  1459.   if (CheckBox1.Checked or (CurScene^.numActions >= 1)) and
  1460.      (SpinEdit3.Value < SpinEdit4.Value) and (SpinEdit2.Value < SpinEdit5.Value) then
  1461.   begin
  1462.     Image1.Canvas.Pen.Color := clRed;
  1463.     Image1.Canvas.Brush.Color := clRed;
  1464.     Image1.Canvas.Rectangle(SpinEdit3.Value,  SpinEdit2.Value,  SpinEdit4.Value,  SpinEdit5.Value);
  1465.   end;
  1466.  
  1467.   if (CheckBox1.Checked or (CurScene^.numActions >= 2)) and
  1468.      (SpinEdit17.Value < SpinEdit19.Value) and (SpinEdit18.Value < SpinEdit20.Value) then
  1469.   begin
  1470.     Image1.Canvas.Pen.Color := clLime;
  1471.     Image1.Canvas.Brush.Color := clLime;
  1472.     Image1.Canvas.Rectangle(SpinEdit17.Value, SpinEdit18.Value, SpinEdit19.Value, SpinEdit20.Value);
  1473.   end;
  1474.  
  1475.   if (CheckBox1.Checked or (CurScene^.numActions >= 3)) and
  1476.      (SpinEdit7.Value < SpinEdit10.Value) and (SpinEdit8.Value < SpinEdit9.Value) then
  1477.   begin
  1478.     Image1.Canvas.Pen.Color := clBlue;
  1479.     Image1.Canvas.Brush.Color := clBlue;
  1480.     Image1.Canvas.Rectangle(SpinEdit7.Value,  SpinEdit8.Value,  SpinEdit10.Value, SpinEdit9.Value);
  1481.   end;
  1482. end;
  1483.  
  1484. end.
  1485.