Subversion Repositories plumbers

Rev

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

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