Subversion Repositories plumbers

Rev

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

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