Subversion Repositories plumbers

Rev

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