Subversion Repositories plumbers

Rev

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

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