Subversion Repositories plumbers

Rev

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