Subversion Repositories plumbers

Rev

Rev 12 | Rev 18 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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