Subversion Repositories plumbers

Rev

Rev 14 | 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
18 daniel-mar 23
  CUR_VER = '2020-06-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);
18 daniel-mar 414
resourcestring
415
  S_DISCARD = 'Are you sure you want to discard all changes and create a new game file?';
2 daniel-mar 416
begin
18 daniel-mar 417
  if MessageDlg(S_DISCARD, mtConfirmation, mbYesNoCancel, 0) = mrYes then
418
  begin
419
    New;
420
  end;
2 daniel-mar 421
end;
422
 
423
procedure TForm1.DisableEnableSceneControls(enable: boolean);
424
begin
425
  ListBox1.Enabled := enable;
426
  Button1.Enabled := enable;
427
  Button2.Enabled := enable;
428
  Button4.Enabled := enable;
429
  Button5.Enabled := enable;
430
end;
431
 
432
procedure TForm1.DisableEnablePictureControls(enable: boolean);
433
begin
434
  Button8.Enabled := enable;
435
  Button9.Enabled := enable;
436
  Button6.Enabled := enable;
437
  Button7.Enabled := enable;
438
end;
439
 
440
procedure TForm1.DisableEnableFileControls(enable: boolean);
441
begin
442
  Button3.Enabled := enable;
443
  Button10.Enabled := enable;
444
  Button14.Enabled := enable;
445
end;
446
 
6 daniel-mar 447
var
448
  AutomaticNextDia: boolean;
449
 
2 daniel-mar 450
procedure TForm1.Button15Click(Sender: TObject);
451
var
452
  decisionBMP: string;
453
  PictureLastFrame: Cardinal;
454
  i: integer;
455
  DecisionPicSet: boolean;
456
begin
457
  if PlayStart <> 0 then
458
  begin
6 daniel-mar 459
    if MediaplayerOpened and not AutomaticNextDia then
2 daniel-mar 460
    begin
461
      if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
462
      Mediaplayer1.TimeFormat := tfMilliseconds;
463
      if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
464
      begin
465
        MediaPlayer1.Position := CurPictureTimepos * 100;
466
        MediaPlayer1.Play;
467
      end;
468
    end;
6 daniel-mar 469
    AutomaticNextDia := false;
2 daniel-mar 470
    FirstTickCount := GetTickCount;
471
    PlayStart := GetTickCount - CurPictureTimepos * 100;
472
  end
473
  else
474
  begin
8 daniel-mar 475
    TabSheet5.TabVisible := false;
2 daniel-mar 476
    DisableEnablePictureControls(false);
477
    DisableEnableSceneControls(false);
478
    DisableEnableFileControls(false);
479
    Edit1.Enabled := false;
480
    Edit3.Enabled := false;
481
    SpinEdit1.Enabled := false;
482
    SpinEdit13.Enabled := false;
483
    Label18.Font.Color := clGreen;
484
    try
485
      Timer1.Enabled := false;
486
 
487
      RecalcSoundtrackLength; // optional
488
 
489
      Mediaplayer1.FileName := Format('%s\%s', [CurScene^.szSceneFolder, CurScene^.szDialogWav]);
490
      if FileExists(Mediaplayer1.FileName) then
491
      begin
492
        Mediaplayer1.TimeFormat := tfMilliseconds;
493
        Mediaplayer1.Open;
494
        MediaplayerOpened := true;
495
        if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
496
        begin
497
          MediaPlayer1.Position := CurPictureTimepos * 100;
498
          MediaPlayer1.Play;
499
        end;
500
      end
501
      else
502
      begin
503
        MediaplayerOpened := false;
504
        MediaPlayer1.FileName := '';
505
      end;
506
      PlayStart := GetTickCount - CurPictureTimepos * 100;
507
      Timer1.Enabled := true;
508
 
509
      {$REGION 'Calculate PictureLastFrame'}
510
      PictureLastFrame := 0;
511
      for i := 0 to CurScene^.numPics-1 do
512
      begin
513
        Inc(PictureLastFrame, Game.pictures[CurScene^.pictureIndex + i].duration);
514
      end;
515
      PictureLastFrame := PictureLastFrame * 100;
516
      {$ENDREGION}
517
 
518
      DecisionPicSet := false;
519
      while not Application.Terminated and
520
            not StopPlayRequest and
521
            (
522
                  (MediaPlayer1.Mode = mpPlaying) or
523
                  (GetTickCount - PlayStart <= PictureLastFrame)
524
            ) do
525
      begin
526
        if GetTickCount - PlayStart <= PictureLastFrame then
527
        begin
528
          DecisionPicSet := false;
529
          FirstTickCount := GetTickCount;
530
          while not Application.Terminated and ((GetTickCount - FirstTickCount) < CurPicture^.duration * 100) and not StopPlayRequest do
531
          begin
532
            Application.ProcessMessages;
533
            Sleep(0);
534
          end;
535
 
536
          if not Application.Terminated and (ListBox2.ItemIndex < ListBox2.Count-1) and not StopPlayRequest then
537
          begin
538
            ListBox2.ItemIndex := ListBox2.ItemIndex + 1;
6 daniel-mar 539
            AutomaticNextDia := true;
2 daniel-mar 540
            ListBox2Click(ListBox2);
541
          end;
542
        end
543
        else
544
        begin
545
          if not DecisionPicSet then
546
          begin
547
            decisionBMP := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDecisionBmp;
548
            if (CurScene^.szDecisionBmp <> '') and FileExists(decisionBMP) then
549
            begin
550
              Image2.Picture.LoadFromFile(decisionBMP);
6 daniel-mar 551
              AspectRatio(Image2, Panel2);
2 daniel-mar 552
            end
553
            else
554
            begin
555
              Image2.Picture := nil;
556
            end;
557
            DecisionPicSet := true;
558
          end;
559
          Application.ProcessMessages;
560
          Sleep(0);
561
        end;
562
      end;
563
    finally
564
      PlayStart := 0;
565
      if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
566
      if MediaplayerOpened then MediaPlayer1.Close;
567
      StopPlayRequest := false;
568
      Label18.Font.Color := clWindowText;
569
      Timer1.Enabled := false;
570
      DisableEnableFileControls(true);
571
      DisableEnableSceneControls(true);
572
      DisableEnablePictureControls(true);
8 daniel-mar 573
      TabSheet5.TabVisible := true;
2 daniel-mar 574
      Edit1.Enabled := true;
575
      SpinEdit1.Enabled := true;
576
      Edit3.Enabled := true;
577
      SpinEdit13.Enabled := true;
578
      Label18.Caption := _DecisecondToTime(CurPictureTimepos);
579
      ListBox2Click(ListBox2);
580
    end;
581
  end;
582
end;
583
 
8 daniel-mar 584
procedure TForm1.ShowSceneBmp;
585
var
586
  Filename: string;
587
begin
588
  Filename := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurPicture^.szBitmapFile);
589
  if FileExists(Filename) then
590
  begin
591
    Image2.Picture.LoadFromFile(Filename);
592
    AspectRatio(Image2, Panel2);
593
  end
594
  else
595
  begin
596
    Image2.Picture := nil;
597
  end;
598
end;
599
 
2 daniel-mar 600
procedure TForm1.Button16Click(Sender: TObject);
601
begin
602
  ListBox2.ItemIndex := 0; // go to the beginning
603
  ListBox2Click(ListBox2); // load picture data
604
  Button15Click(Button15); // play
605
end;
606
 
607
procedure TForm1.Button17Click(Sender: TObject);
608
begin
609
  if PlayStart <> 0 then
610
  begin
611
    Timer1.Enabled := false;
612
    if MediaplayerOpened then MediaPlayer1.Stop;
613
    StopPlayRequest := true;
614
  end;
615
end;
616
 
617
procedure TForm1.Button18Click(Sender: TObject);
618
var
619
  fileName: string;
620
begin
621
  fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
622
  if not FileExists(fileName) then exit;
623
  ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
624
end;
625
 
10 daniel-mar 626
procedure TForm1.Button19Click(Sender: TObject);
12 daniel-mar 627
resourcestring
628
  S_DISCARD = 'Are you sure you want to discard all changes?';
10 daniel-mar 629
begin
12 daniel-mar 630
  if MessageDlg(S_DISCARD, mtConfirmation, mbYesNoCancel, 0) = mrYes then
11 daniel-mar 631
  begin
632
    CopyMemory(@Game, @GameBak, SizeOf(Game));
633
    SetupGUIAfterLoad;
634
  end;
10 daniel-mar 635
end;
636
 
2 daniel-mar 637
procedure TForm1.NewScene;
12 daniel-mar 638
resourcestring
639
  S_SCENE_FULL = 'No more space for another scene';
2 daniel-mar 640
var
641
  sceneID: integer;
642
  newScene: PSceneDef;
643
begin
644
  if ListBox1.Items.Count = 100 then
645
  begin
12 daniel-mar 646
    raise Exception.Create(S_SCENE_FULL);
2 daniel-mar 647
  end;
648
 
649
  sceneID := GetGreatestSceneID+1;
650
  if sceneID >= Length(Game.scenes) then sceneID := SearchSceneIDGapFromTop;
651
 
652
  newScene := Game.AddSceneAtEnd(sceneID);
653
  newScene.actions[0].nextSceneID := SCENEID_ENDGAME;
10 daniel-mar 654
  newScene.pictureIndex := Game.numPics;
2 daniel-mar 655
  ListBox1.Items.Add(newScene.szSceneFolder);
656
  ReloadActionSceneLists;
657
  HandlePossibleEmptySceneList;
658
  ListBox1.ItemIndex := ListBox1.Items.Count - 1;
659
  ListBox1Click(ListBox1);
660
end;
661
 
662
procedure TForm1.Button1Click(Sender: TObject);
663
begin
664
  NewScene;
665
end;
666
 
11 daniel-mar 667
procedure TForm1.Button20Click(Sender: TObject);
668
begin
669
  Game.Defrag;
670
  RecalcStats;
671
end;
672
 
2 daniel-mar 673
procedure TForm1.Button2Click(Sender: TObject);
12 daniel-mar 674
resourcestring
675
  S_CONFLICT = 'Can''t delete this scene. There are following dependencies:'+#13#10#13#10+'%s';
676
  S_SCENEID = 'Scene %s, action #%d';
677
  // S_ONLYONE = 'Can''t delete the scene if there is only one.';
678
  S_REALLY_DEL = 'Do you really want to delete scene %s?';
679
  S_NEW_INTRO = 'Attention: This will make %s to your new intro sequence. Is that OK?';
2 daniel-mar 680
var
681
  iScene, iAction, sceneID: integer;
682
  conflicts: TStringList;
683
  sWarning: string;
684
  bakItemindex: integer;
685
begin
686
  if ListBox1.Count = 0 then exit;
687
 
688
  (*
689
  if ListBox1.Count = 1 then
690
  begin
12 daniel-mar 691
    raise Exception.Create(S_ONLYONE);
2 daniel-mar 692
  end;
693
  *)
694
 
695
  conflicts := TStringList.Create;
696
  try
697
    sceneID := GetSceneIDFromName(CurScene^.szSceneFolder);
698
    for iScene := 0 to Game.numScenes-1 do
699
    begin
700
      for iAction := 0 to Game.scenes[iScene].numActions-1 do
701
      begin
702
        if Game.scenes[iScene].actions[iAction].nextSceneID = sceneID then
703
        begin
12 daniel-mar 704
          conflicts.Add(Format(S_SCENEID, [Game.scenes[iScene].szSceneFolder, iAction+1]));
2 daniel-mar 705
        end;
706
      end;
707
    end;
708
    if conflicts.Count > 0 then
709
    begin
12 daniel-mar 710
      raise Exception.CreateFmt(S_CONFLICT, [conflicts.Text]);
2 daniel-mar 711
    end;
712
  finally
713
    FreeAndNil(conflicts);
714
  end;
715
 
12 daniel-mar 716
  sWarning := Format(S_REALLY_DEL, [CurScene^.szSceneFolder]);
2 daniel-mar 717
  if (ListBox1.ItemIndex = 0) and (ListBox1.Count >= 2) then
12 daniel-mar 718
    sWarning := Format(S_NEW_INTRO, [ListBox1.Items[ListBox1.ItemIndex+1]]);
2 daniel-mar 719
  if (MessageDlg(sWarning, mtConfirmation, mbYesNoCancel, 0) <> mrYes) then
720
  begin
721
    Exit;
722
  end;
723
 
724
  Game.DeleteScene(ListBox1.ItemIndex);
725
 
726
  bakItemindex := ListBox1.ItemIndex;
727
  ListBox1.Items.Delete(bakItemindex);
728
  ReloadActionSceneLists;
729
  HandlePossibleEmptySceneList;
730
  if ListBox1.Count > 0 then
731
  begin
732
    if bakItemindex = ListBox1.Count then Dec(bakItemindex);
733
    Listbox1.ItemIndex := bakItemindex;
734
    ListBox1Click(ListBox1);
735
  end;
736
end;
737
 
738
procedure TForm1.Button3Click(Sender: TObject);
739
begin
740
  Save;
741
end;
742
 
743
procedure TForm1.Button4Click(Sender: TObject);
744
begin
745
  if ListBox1.ItemIndex <= 0 then exit;
746
  Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
747
  ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
748
  ReloadActionSceneLists;
749
end;
750
 
751
procedure TForm1.Button5Click(Sender: TObject);
752
begin
753
  if ListBox1.ItemIndex = ListBox1.Count-1 then exit;
754
  Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
755
  ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
756
  ReloadActionSceneLists;
757
end;
758
 
759
procedure TForm1.Button6Click(Sender: TObject);
760
var
761
  pic: PPictureDef;
762
begin
10 daniel-mar 763
  if ListBox2.Items.Count > 0 then
764
    pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex+1,0), false)
765
  else
766
    pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0), true);
767
  pic.duration     := DEFAULT_DURATION;
768
  pic.szBitmapFile := DEFAULT_FILENAME;
2 daniel-mar 769
  if ListBox2.ItemIndex = -1 then
770
  begin
10 daniel-mar 771
    ListBox2.Items.Insert(ListBox2.Count, Format('(%d) %s', [DEFAULT_DURATION, DEFAULT_FILENAME]));
2 daniel-mar 772
    ListBox2.ItemIndex := ListBox2.Count - 1;
773
  end
774
  else
775
  begin
10 daniel-mar 776
    ListBox2.Items.Insert(ListBox2.ItemIndex+1, Format('(%d) %s', [DEFAULT_DURATION, DEFAULT_FILENAME]));
777
    ListBox2.ItemIndex := ListBox2.ItemIndex + 1;
2 daniel-mar 778
  end;
779
  ListBox2Click(Listbox2);
10 daniel-mar 780
  SelectFilenameBase(Edit3);
781
  RecalcStats;
2 daniel-mar 782
end;
783
 
784
procedure TForm1.Button7Click(Sender: TObject);
785
var
786
  bakIdx: integer;
787
begin
788
  if Listbox2.Count > 0 then
789
  begin
790
    bakIdx := ListBox2.ItemIndex;
10 daniel-mar 791
    Game.DeletePicture(CurScene^.pictureIndex + bakIdx);
2 daniel-mar 792
    ListBox2.Items.Delete(bakIdx);
793
    if ListBox2.Count > 0 then
794
    begin
795
      if bakIdx = ListBox2.Count then Dec(bakIdx);
796
      ListBox2.ItemIndex := bakIdx;
797
      ListBox2Click(Listbox2);
798
    end;
8 daniel-mar 799
    RecalcUnusedFiles;
2 daniel-mar 800
  end;
10 daniel-mar 801
  RecalcStats;
2 daniel-mar 802
end;
803
 
804
procedure TForm1.Button8Click(Sender: TObject);
805
begin
806
  if ListBox2.ItemIndex <= 0 then exit;
807
  Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex-1);
808
  ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex-1);
809
end;
810
 
811
procedure TForm1.Button9Click(Sender: TObject);
812
begin
813
  if ListBox2.ItemIndex = ListBox2.Count-1 then exit;
814
  Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex+1);
815
  ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex+1);
816
end;
817
 
818
procedure TForm1.Save;
819
var
820
  fs: TFileStream;
821
begin
10 daniel-mar 822
  CopyMemory(@GameBak, @Game, SizeOf(Game));
823
 
2 daniel-mar 824
  fs := TFileStream.Create('GAME.BIN', fmOpenWrite or fmCreate);
825
  try
826
    fs.WriteBuffer(Game, SizeOf(Game));
827
  finally
828
    FreeAndNil(fs);
829
  end;
830
end;
831
 
832
procedure TForm1.ActionTargetChange(Sender: TObject);
12 daniel-mar 833
resourcestring
834
  S_ASSERT_SENDER = 'Unexpected sender for ActionTargetChange()';
2 daniel-mar 835
var
836
  actionIdx: integer;
837
  itemIdx: Integer;
838
begin
839
       if Sender = ComboBox1 then actionIdx := 0
840
  else if Sender = ComboBox2 then actionIdx := 1
841
  else if Sender = ComboBox3 then actionIdx := 2
12 daniel-mar 842
  else raise Exception.Create(S_ASSERT_SENDER);
2 daniel-mar 843
 
844
  itemIdx := TComboBox(Sender).ItemIndex;
845
  if itemIdx = 0 then
846
    CurScene^.actions[actionIdx].nextSceneID := SCENEID_ENDGAME
847
  else if itemIdx = 1 then
848
    CurScene^.actions[actionIdx].nextSceneID := SCENEID_PREVDECISION
849
  else
850
    CurScene^.actions[actionIdx].nextSceneID := GetSceneIDFromName(ListBox1.Items[itemIdx - 2]);
851
end;
852
 
853
procedure TForm1.Addtoscene1Click(Sender: TObject);
854
var
855
  fil: string;
856
begin
857
  if ListBox3.ItemIndex = -1 then exit;
858
  fil := ListBox3.Items[ListBox3.ItemIndex];
859
  Button6.Click;
860
  Edit3.Text := fil;
861
end;
862
 
863
procedure TForm1.Edit1Change(Sender: TObject);
864
begin
865
  _WriteStringToFilename(@CurScene^.szDialogWav, Edit1.Text);
866
  RecalcSoundtrackLength;
867
  RecalcUnusedFiles;
868
 
869
  Label24.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit1.Text);
870
  Label25.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + 'E' + Edit1.Text);
871
 
872
  Button18.Visible := CurScene^.szDialogWav <> '';
873
end;
874
 
875
procedure TForm1.Edit2Change(Sender: TObject);
876
begin
877
  _WriteStringToFilename(@CurScene^.szDecisionBmp, Edit2.Text);
878
  RecalcUnusedFiles;
8 daniel-mar 879
  RedrawDecisionBitmap;
2 daniel-mar 880
  Label27.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text) and not (Edit2.Text = '');
881
  Button11.Visible := CurScene^.szDecisionBmp <> '';
882
end;
883
 
884
procedure TForm1.Edit3Change(Sender: TObject);
885
begin
886
  _WriteStringToFilename(@CurPicture^.szBitmapFile, Edit3.Text);
887
  ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
888
  RecalcUnusedFiles;
8 daniel-mar 889
  ShowSceneBmp;
2 daniel-mar 890
  Label26.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit3.Text);
891
  Button12.Visible := CurPicture^.szBitmapFile <> '';
892
end;
893
 
10 daniel-mar 894
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
12 daniel-mar 895
resourcestring
896
  S_SAVE_CHANGES = 'Do you want to save the changes?';
10 daniel-mar 897
begin
898
  if not CompareMem(@Game, @GameBak, SizeOf(Game)) then
899
  begin
12 daniel-mar 900
    case MessageDlg(S_SAVE_CHANGES, mtConfirmation, mbYesNoCancel, 0) of
11 daniel-mar 901
      mrYes:
10 daniel-mar 902
      begin
903
        Save;
904
        CanClose := true;
905
      end;
11 daniel-mar 906
      mrNo:
10 daniel-mar 907
      begin
908
        CanClose := true;
909
      end;
11 daniel-mar 910
      mrCancel:
10 daniel-mar 911
      begin
912
        CanClose := false;
913
      end;
914
    end;
915
  end;
916
end;
917
 
2 daniel-mar 918
procedure TForm1.FormCreate(Sender: TObject);
919
begin
920
  PageControl1.ActivePageIndex := 0;
921
  PageControl2.ActivePageIndex := 0;
10 daniel-mar 922
  PageControl3.ActivePageIndex := 0;
2 daniel-mar 923
  Label10.Caption := '';
924
  Label21.Caption := '';
925
  Label23.Caption := '';
926
end;
927
 
928
procedure TForm1.FormShow(Sender: TObject);
929
begin
930
  if FileExists('GAME.BIN') then
931
    Load
932
  else
933
    New;
934
end;
935
 
936
function TForm1.CurScene: PSceneDef;
12 daniel-mar 937
resourcestring
938
  S_NO_SCENE_AVAILABLE = 'No scenes available. Please create one.';
939
  S_NO_SCENE_SELECTED = 'No scene selected. Please select one.';
2 daniel-mar 940
begin
12 daniel-mar 941
  if ListBox1.Count = 0 then raise Exception.Create(S_NO_SCENE_AVAILABLE);
942
  if ListBox1.ItemIndex = -1 then raise Exception.Create(S_NO_SCENE_SELECTED);
2 daniel-mar 943
  result := @Game.scenes[ListBox1.ItemIndex];
944
end;
945
 
946
procedure TForm1.ListBox1Click(Sender: TObject);
947
begin
948
  LoadScene;
949
end;
950
 
951
procedure TForm1.ListBox1DblClick(Sender: TObject);
952
begin
953
  Button16Click(Button16);
954
end;
955
 
11 daniel-mar 956
procedure TForm1.CheckBox1Click(Sender: TObject);
957
begin
958
  RedrawDecisionBitmap;
959
end;
960
 
2 daniel-mar 961
procedure TForm1.Close1Click(Sender: TObject);
962
begin
963
  Close;
964
end;
965
 
966
function TForm1.CurPicture: PPictureDef;
12 daniel-mar 967
resourcestring
968
  S_NO_PICTURE_AVAILABLE = 'No pictures available. Please create one.';
969
  S_NO_PICTURE_SELECTED = 'No picture selected. Please select one.';
2 daniel-mar 970
begin
12 daniel-mar 971
  if ListBox2.Count = 0 then raise Exception.Create(S_NO_PICTURE_AVAILABLE);
972
  if ListBox2.ItemIndex = -1 then raise Exception.Create(S_NO_PICTURE_SELECTED);
2 daniel-mar 973
  result := @Game.pictures[CurScene^.pictureIndex + ListBox2.ItemIndex]
974
end;
975
 
976
function TForm1.CurPictureTimepos: Cardinal;
977
var
978
  i: integer;
979
begin
980
  result := 0;
981
  for i := curScene^.pictureIndex to curScene^.pictureIndex + ListBox2.ItemIndex - 1 do
982
  begin
983
    Inc(result, Game.pictures[i].duration);
984
  end;
985
end;
986
 
6 daniel-mar 987
class procedure TForm1.AspectRatio(image: TImage; panel: TControl);
988
var
989
  wi, hi, ws, hs: integer;
990
  ri, rs: double;
991
begin
992
  wi := image.Picture.Width;
993
  hi := image.Picture.Height;
994
  ri := wi / hi;
995
 
996
  ws := panel.Width;
997
  hs := panel.Height;
998
  rs := ws / hs;
999
 
1000
  if rs > ri then
1001
  begin
1002
    image.Width  := Round(wi * hs/hi);
1003
    image.Height := hs;
1004
  end
1005
  else
1006
  begin
1007
    image.Width  := ws;
1008
    image.Height := Round(hi * ws/wi);
1009
  end;
1010
 
1011
  image.Left := Round(panel.Width  / 2 - image.Width  / 2);
1012
  image.Top  := Round(panel.Height / 2 - image.Height / 2);
1013
end;
1014
 
2 daniel-mar 1015
procedure TForm1.ListBox2Click(Sender: TObject);
10 daniel-mar 1016
var
1017
  bakEvent: TNotifyEvent;
2 daniel-mar 1018
begin
10 daniel-mar 1019
  if CurScene^.numPics = 0 then
1020
  begin
1021
    SpinEdit13.Value := 0;
1022
 
1023
    bakEvent := Edit3.OnChange;
1024
    try
1025
      Edit3.OnChange := nil;
1026
      Edit3.Text := '';
1027
    finally
1028
      Edit3.OnChange := bakEvent;
1029
    end;
1030
 
1031
    Label18.Caption := '';
1032
    Image2.Picture := nil;
1033
    exit;
1034
  end;
1035
 
2 daniel-mar 1036
  SpinEdit13.Value := CurPicture^.duration;
1037
  Edit3.Text := string(CurPicture^.szBitmapFile);
1038
 
8 daniel-mar 1039
  ShowSceneBmp;
2 daniel-mar 1040
 
1041
  Label18.Caption := _DecisecondToTime(CurPictureTimepos);
1042
 
1043
  if PlayStart <> 0 then
1044
  begin
1045
    Button15Click(Button15);
1046
  end;
10 daniel-mar 1047
 
1048
  RecalcStats;
2 daniel-mar 1049
end;
1050
 
1051
procedure TForm1.ListBox2DblClick(Sender: TObject);
1052
begin
1053
  Button15Click(Button15);
1054
end;
1055
 
8 daniel-mar 1056
procedure TForm1.ListBox3Click(Sender: TObject);
1057
var
1058
  fileName: string;
1059
begin
1060
  if ListBox3.ItemIndex = -1 then exit;
1061
  fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + ListBox3.Items[ListBox3.ItemIndex];
14 daniel-mar 1062
 
1063
  if not FileExists(FileName) then
1064
  begin
1065
    Image3.Visible := false;
1066
    exit;
1067
  end;
1068
 
1069
  try
1070
    Image3.Picture.LoadFromFile(Filename);
1071
    AspectRatio(Image3, Panel3);
1072
    Image3.Visible := true;
1073
  except
1074
    Image3.Visible := false;
1075
    // It could also be a sound file, so we do not show errors
1076
  end;
8 daniel-mar 1077
end;
1078
 
2 daniel-mar 1079
procedure TForm1.ListBox3DblClick(Sender: TObject);
1080
var
1081
  fileName: string;
1082
begin
1083
  if ListBox3.ItemIndex = -1 then exit;
1084
  fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + ListBox3.Items[ListBox3.ItemIndex];
1085
  if not FileExists(FileName) then exit;
1086
  ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
1087
end;
1088
 
1089
procedure TForm1.ListBox3MouseDown(Sender: TObject; Button: TMouseButton;
1090
  Shift: TShiftState; X, Y: Integer);
1091
var
1092
  APoint: TPoint;
1093
  Index: integer;
1094
begin
1095
  if Button = mbRight then
1096
  begin
1097
    APoint.X := X;
1098
    APoint.Y := Y;
1099
    Index := TListbox(Sender).ItemAtPos(APoint, True);
1100
    if Index > -1 then TListbox(Sender).Selected[Index] := True;
1101
  end;
1102
end;
1103
 
1104
procedure TForm1.SetupGUIAfterLoad;
1105
var
1106
  i: integer;
1107
begin
1108
  ListBox1.Clear;
1109
  for i := 0 to Game.numScenes - 1 do
1110
  begin
1111
    ListBox1.Items.Add(string(Game.scenes[i].szSceneFolder));
1112
  end;
1113
  (*
1114
  if ListBox1.Items.Count = 0 then
1115
  begin
1116
    NewScene;
1117
  end;
1118
  *)
1119
 
1120
  ReloadActionSceneLists;
1121
  HandlePossibleEmptySceneList;
1122
 
1123
  if ListBox1.Count > 0 then
1124
  begin
1125
    ListBox1.ItemIndex := 0;
1126
    ListBox1Click(Listbox1);
1127
  end;
1128
end;
1129
 
1130
procedure TForm1.New;
1131
begin
11 daniel-mar 1132
  PageControl1.ActivePageIndex := 0;
1133
  PageControl2.ActivePageIndex := 0;
1134
  PageControl3.ActivePageIndex := 0;
1135
  Label10.Caption := '';
1136
  Label21.Caption := '';
1137
  Label23.Caption := '';
1138
 
2 daniel-mar 1139
  ZeroMemory(@Game, SizeOf(Game));
10 daniel-mar 1140
  ZeroMemory(@GameBak, SizeOf(Game));
2 daniel-mar 1141
 
1142
  SetupGUIAfterLoad;
1143
end;
1144
 
1145
procedure TForm1.Load;
12 daniel-mar 1146
resourcestring
1147
  S_CORRECTED_PICTURE_COUNT = 'Picture count was wrong. Value was corrected.';
2 daniel-mar 1148
var
1149
  fs: TFileStream;
1150
begin
1151
  fs := TFileStream.Create('GAME.BIN', fmOpenRead);
1152
  try
1153
    fs.ReadBuffer(Game, SizeOf(Game));
1154
  finally
1155
    FreeAndNil(fs);
1156
  end;
1157
 
11 daniel-mar 1158
  CopyMemory(@GameBak, @Game, SizeOf(Game));
1159
 
10 daniel-mar 1160
  if Game.RealPictureCount <> Game.numPics then
1161
  begin
12 daniel-mar 1162
    MessageDlg(S_CORRECTED_PICTURE_COUNT, mtInformation, [mbOk], 0);
10 daniel-mar 1163
    Game.numPics := Game.RealPictureCount;
1164
  end;
1165
 
2 daniel-mar 1166
  SetupGUIAfterLoad;
1167
end;
1168
 
1169
procedure TForm1.RecalcSlideshowLength;
1170
var
1171
  i: integer;
1172
  Sum: integer;
1173
begin
1174
  Sum := 0;
1175
  for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
1176
  begin
1177
    Inc(Sum, Game.pictures[i].duration);
1178
  end;
1179
  Label21.Caption := _DecisecondToTime(Sum);
1180
end;
1181
 
1182
procedure TForm1.RecalcUnusedFiles;
1183
var
1184
  i, idx: integer;
1185
  SR: TSearchRec;
6 daniel-mar 1186
  ext: string;
14 daniel-mar 1187
  sl: TStringList;
1188
  s: string;
2 daniel-mar 1189
begin
14 daniel-mar 1190
  sl := TStringList.Create;
6 daniel-mar 1191
  try
1192
    if FindFirst(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + '*.*', faArchive, SR) = 0 then
1193
    begin
1194
      repeat
1195
        ext := UpperCase(ExtractFileExt(SR.Name));
1196
        if ((ext <> '.PK' {Adobe Audition}) and (ext <> '.DB' {Windows Thumbnail})) then
1197
        begin
14 daniel-mar 1198
          sl.Add(SR.Name); //Fill the list
6 daniel-mar 1199
        end;
1200
      until FindNext(SR) <> 0;
1201
      FindClose(SR);
1202
    end;
2 daniel-mar 1203
 
6 daniel-mar 1204
    // Remove the entries which are present
1205
    for i := CurScene^.pictureIndex to CurScene^.pictureIndex+CurScene^.numPics-1 do
1206
    begin
14 daniel-mar 1207
      idx := sl.IndexOf(Game.pictures[i].szBitmapFile);
1208
      if idx <> -1 then sl.Delete(idx);
6 daniel-mar 1209
    end;
1210
 
14 daniel-mar 1211
    idx := sl.IndexOf(Edit1.Text);
1212
    if idx <> -1 then sl.Delete(idx);
1213
    idx := sl.IndexOf('E'+Edit1.Text);
1214
    if idx <> -1 then sl.Delete(idx);
2 daniel-mar 1215
 
14 daniel-mar 1216
    idx := sl.IndexOf(Edit2.Text);
1217
    if idx <> -1 then sl.Delete(idx);
2 daniel-mar 1218
 
14 daniel-mar 1219
    idx := sl.IndexOf(Edit3.Text);
1220
    if idx <> -1 then sl.Delete(idx);
1221
 
1222
    if sl.Text <> ListBox3.Items.Text then
1223
    begin
1224
      i := ListBox3.ItemIndex;
1225
      if i >= 0 then
1226
        s := ListBox3.Items.Strings[i]
1227
      else
1228
        s := '';
1229
      ListBox3.Items.Assign(sl);
1230
      i := ListBox3.Items.IndexOf(s);
1231
      if i >= 0 then
1232
        ListBox3.ItemIndex := i
1233
      else
1234
        Image3.Visible := false;
1235
    end;
6 daniel-mar 1236
  finally
14 daniel-mar 1237
    sl.Free;
6 daniel-mar 1238
  end;
2 daniel-mar 1239
end;
1240
 
1241
procedure TForm1.RecalcSoundtrackLength;
1242
var
1243
  FileName: string;
12 daniel-mar 1244
resourcestring
1245
  S_NA = 'n/a';
2 daniel-mar 1246
begin
1247
  if MediaPlayer1.Mode = mpPlaying then exit;
1248
 
1249
  FileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
1250
  if not FileExists(FileName) then
1251
  begin
12 daniel-mar 1252
    Label23.Caption := S_NA;
2 daniel-mar 1253
    exit;
1254
  end;
1255
  MediaPlayer1.FileName := FileName;
1256
  MediaPlayer1.TimeFormat := tfMilliseconds;
1257
  MediaPlayer1.Open;
1258
  Label23.Caption := _DecisecondToTime(MediaPlayer1.Length div 100);
1259
  MediaPlayer1.Close;
1260
end;
1261
 
1262
procedure TForm1.LoadScene;
1263
 
1264
  procedure _SelectActionComboBox(ComboBox: TComboBox; sceneID: SmallInt);
1265
  var
1266
    idx: Integer;
1267
  begin
1268
    if sceneID = SCENEID_ENDGAME then
1269
      ComboBox.ItemIndex := 0
1270
    else if sceneID = SCENEID_PREVDECISION then
1271
      ComboBox.ItemIndex := 1
1272
    else
1273
    begin
12 daniel-mar 1274
      idx := Game.FindSceneIndex(sceneID);
2 daniel-mar 1275
      if idx = -1 then
1276
        ComboBox.ItemIndex := -1
1277
      else
1278
        ComboBox.ItemIndex := 2 + idx;
1279
    end;
1280
  end;
1281
 
1282
  procedure _PreparePictureList;
1283
  var
1284
    i: integer;
10 daniel-mar 1285
    //pic: PPictureDef;
2 daniel-mar 1286
  begin
1287
    ListBox2.Clear;
1288
 
1289
    if CurScene^.numPics = 0 then
1290
    begin
10 daniel-mar 1291
      (*
2 daniel-mar 1292
      pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0));
10 daniel-mar 1293
      pic.duration := DEFAULT_DURATION;
1294
      pic.szBitmapFile := DEFAULT_FILENAME;
1295
      *)
2 daniel-mar 1296
    end;
1297
 
1298
    for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
1299
    begin
1300
      Listbox2.Items.Add(Format('(%d) %s', [Game.pictures[i].duration, Game.pictures[i].szBitmapFile]));
1301
    end;
1302
  end;
1303
 
1304
begin
1305
  SpinEdit1.Value := GetSceneIDFromName(CurScene^.szSceneFolder);
1306
  Edit1.Text := string(CurScene^.szDialogWav);
1307
  Edit2.Text := string(CurScene^.szDecisionBmp);
1308
 
1309
  _PreparePictureList;
1310
  ListBox2.ItemIndex := 0;
1311
  ListBox2Click(Listbox2);
1312
 
1313
  _SelectActionComboBox(ComboBox1, CurScene^.actions[0].nextSceneID);
1314
  _SelectActionComboBox(ComboBox2, CurScene^.actions[1].nextSceneID);
1315
  _SelectActionComboBox(ComboBox3, CurScene^.actions[2].nextSceneID);
1316
 
1317
  SpinEdit12.Value := CurScene^.numActions;
1318
  SpinEdit12Change(SpinEdit12);
1319
  PageControl1.ActivePageIndex := 0;
1320
 
1321
  SpinEdit3.Value  := CurScene^.actions[0].cHotspotTopLeft.X;
1322
  SpinEdit17.Value := CurScene^.actions[1].cHotspotTopLeft.X;
1323
  SpinEdit7.Value  := CurScene^.actions[2].cHotspotTopLeft.X;
1324
  SpinEdit2.Value  := CurScene^.actions[0].cHotspotTopLeft.Y;
1325
  SpinEdit18.Value := CurScene^.actions[1].cHotspotTopLeft.Y;
1326
  SpinEdit8.Value  := CurScene^.actions[2].cHotspotTopLeft.Y;
1327
  SpinEdit4.Value  := CurScene^.actions[0].cHotspotBottomRight.X;
1328
  SpinEdit19.Value := CurScene^.actions[1].cHotspotBottomRight.X;
1329
  SpinEdit10.Value := CurScene^.actions[2].cHotspotBottomRight.X;
1330
  SpinEdit5.Value  := CurScene^.actions[0].cHotspotBottomRight.Y;
1331
  SpinEdit20.Value := CurScene^.actions[1].cHotspotBottomRight.Y;
1332
  SpinEdit9.Value  := CurScene^.actions[2].cHotspotBottomRight.Y;
1333
  SpinEdit6.Value  := CurScene^.actions[0].scoreDelta;
1334
  SpinEdit21.Value := CurScene^.actions[1].scoreDelta;
1335
  SpinEdit11.Value := CurScene^.actions[2].scoreDelta;
1336
 
1337
  RedrawDecisionBitmap;
1338
 
1339
  RecalcSlideshowLength;
1340
  RecalcSoundtrackLength;
1341
 
1342
  RecalcUnusedFiles;
10 daniel-mar 1343
 
1344
  RecalcStats;
2 daniel-mar 1345
end;
1346
 
10 daniel-mar 1347
procedure TForm1.RecalcStats;
1348
begin
1349
  Label35.Caption := IntToStr(ListBox1.ItemIndex) + ' / ' + IntToStr(Game.numScenes);
1350
 
1351
  if ListBox2.ItemIndex >= 0 then
1352
    Label31.Caption := IntToStr(CurScene^.pictureIndex) + ' + ' + IntToStr(ListBox2.ItemIndex) + ' = ' + IntToStr(CurScene^.pictureIndex+ListBox2.ItemIndex)
1353
  else
1354
    Label31.Caption := IntToStr(CurScene^.pictureIndex);
1355
 
1356
  Label33.Caption := IntToStr(CurScene^.numPics) + ' / ' + IntToStr(Game.numPics);
1357
 
1358
  Label37.Caption := IntToStr(CurScene^.numActions) + ' / ' + IntToStr(Game.RealActionCount);
1359
end;
1360
 
2 daniel-mar 1361
procedure TForm1.ReloadActionSceneLists;
1362
 
1363
  procedure _ReloadActionSceneLists(ComboBox: TComboBox);
12 daniel-mar 1364
  resourcestring
1365
    S_TERMINATE = 'Terminate program';
1366
    S_PREV_DEC = 'Previous decision';
2 daniel-mar 1367
  var
1368
    prevSelection: string;
1369
    i: Integer;
1370
  begin
1371
    prevSelection := ComboBox.Text;
1372
    try
1373
      ComboBox.Items.Clear;
12 daniel-mar 1374
      ComboBox.Items.Add(S_TERMINATE);
1375
      ComboBox.Items.Add(S_PREV_DEC);
2 daniel-mar 1376
      ComboBox.Items.AddStrings(ListBox1.Items);
1377
    finally
1378
      ComboBox.ItemIndex := 0;
1379
      for i := ComboBox.Items.Count - 1 downto 0 do
1380
      begin
1381
        if ComboBox.Items.Strings[i] = prevSelection then
1382
        begin
1383
          ComboBox.ItemIndex := i;
1384
        end;
1385
      end;
1386
    end;
1387
  end;
1388
 
1389
begin
1390
  _ReloadActionSceneLists(ComboBox1);
1391
  _ReloadActionSceneLists(ComboBox2);
1392
  _ReloadActionSceneLists(ComboBox3);
1393
end;
1394
 
1395
procedure TForm1.SpinEdit12Change(Sender: TObject);
1396
begin
1397
  TabSheet3.TabVisible := SpinEdit12.Value >= 3;
1398
  if PageControl1.ActivePage = TabSheet3 then PageControl1.ActivePage := TabSheet2;
1399
 
1400
  TabSheet2.TabVisible := SpinEdit12.Value >= 2;
1401
  if PageControl1.ActivePage = TabSheet2 then PageControl1.ActivePage := TabSheet1;
1402
 
1403
  // TabSheet1.TabVisible := SpinEdit12.Value >= 1;
1404
 
1405
  CurScene^.numActions := SpinEdit12.Value;
1406
 
1407
  // QUE: zero data of actions which are inactive (numActions<action)?
10 daniel-mar 1408
 
1409
  RecalcStats;
11 daniel-mar 1410
  RedrawDecisionBitmap;
2 daniel-mar 1411
end;
1412
 
1413
procedure TForm1.SpinEdit13Change(Sender: TObject);
1414
begin
1415
  if SpinEdit13.Text = '' then exit;
1416
  CurPicture^.duration := SpinEdit13.Value;
1417
  ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
1418
  RecalcSlideshowLength;
1419
end;
1420
 
1421
procedure TForm1.SpinEdit1Change(Sender: TObject);
1422
 
1423
  function _CountNumScenes(str: string): integer;
1424
  var
1425
    i: integer;
1426
  begin
1427
    result := 0;
1428
    for i := 0 to ListBox1.Count-1 do
1429
    begin
1430
      if ListBox1.Items[i] = str then Inc(result);
1431
    end;
1432
  end;
1433
 
1434
var
1435
  sNew: string;
1436
begin
1437
  // TODO: warn if dependencies are broken
1438
 
1439
  if SpinEdit1.Text = '' then exit;
1440
  CurScene; // verify that a scene exists and is selected
1441
  sNew := Format('SC%.2d', [SpinEdit1.Value]);
1442
  ListBox1.Items[ListBox1.ItemIndex] := sNew;
1443
  Label17.Visible := _CountNumScenes(sNew) > 1;
1444
  ReloadActionSceneLists;
1445
  _WriteStringToFilename(@CurScene^.szSceneFolder, ListBox1.Items[ListBox1.ItemIndex]);
1446
end;
1447
 
1448
procedure TForm1.Timer1Timer(Sender: TObject);
1449
var
1450
  ms: Cardinal;
1451
begin
1452
  ms := GetTickCount - PlayStart;
1453
  Label18.Caption := FormatDatetime('hh:nn:ss', ms / 1000 / (24*60*60)) + ',' + IntToStr(ms mod 1000 div 100);
1454
end;
1455
 
1456
procedure TForm1.About1Click(Sender: TObject);
1457
begin
10 daniel-mar 1458
  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 1459
end;
1460
 
1461
procedure TForm1.ActionSpinEditsChange(Sender: TObject);
1462
begin
1463
  if TSpinEdit(Sender).Text = '' then exit; // user is about to enter a negative value
1464
  if TSpinEdit(Sender).Text = '-' then exit; // user is about to enter a negative value
1465
 
1466
       if Sender = SpinEdit3  then CurScene^.actions[0].cHotspotTopLeft.X := TSpinEdit(Sender).Value
1467
  else if Sender = SpinEdit17 then CurScene^.actions[1].cHotspotTopLeft.X := TSpinEdit(Sender).Value
1468
  else if Sender = SpinEdit7  then CurScene^.actions[2].cHotspotTopLeft.X := TSpinEdit(Sender).Value
1469
  else if Sender = SpinEdit2  then CurScene^.actions[0].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
1470
  else if Sender = SpinEdit18 then CurScene^.actions[1].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
1471
  else if Sender = SpinEdit8  then CurScene^.actions[2].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
1472
  else if Sender = SpinEdit4  then CurScene^.actions[0].cHotspotBottomRight.X := TSpinEdit(Sender).Value
1473
  else if Sender = SpinEdit19 then CurScene^.actions[1].cHotspotBottomRight.X := TSpinEdit(Sender).Value
1474
  else if Sender = SpinEdit10 then CurScene^.actions[2].cHotspotBottomRight.X := TSpinEdit(Sender).Value
1475
  else if Sender = SpinEdit5  then CurScene^.actions[0].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
1476
  else if Sender = SpinEdit20 then CurScene^.actions[1].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
1477
  else if Sender = SpinEdit9  then CurScene^.actions[2].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
1478
  else if Sender = SpinEdit6  then CurScene^.actions[0].scoreDelta := TSpinEdit(Sender).Value
1479
  else if Sender = SpinEdit21 then CurScene^.actions[1].scoreDelta := TSpinEdit(Sender).Value
1480
  else if Sender = SpinEdit11 then CurScene^.actions[2].scoreDelta := TSpinEdit(Sender).Value;
1481
 
1482
  RedrawDecisionBitmap;
1483
end;
1484
 
1485
procedure TForm1.RedrawDecisionBitmap;
1486
var
1487
  Filename: string;
1488
begin
1489
  FileName := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text);
8 daniel-mar 1490
 
1491
  Image1.Visible := FileExists(FileName);
1492
 
6 daniel-mar 1493
  if not FileExists(FileName) then exit;
2 daniel-mar 1494
 
6 daniel-mar 1495
  Image1.Picture.Bitmap.LoadFromFile(FileName);
1496
  AspectRatio(Image1, Panel1);
1497
 
2 daniel-mar 1498
  Image1.Picture.Bitmap.PixelFormat := pf24bit; // Extend the palette, so we have red, green and blue guaranteed.
1499
 
1500
  Image1.Canvas.Brush.Style := bsDiagCross;
1501
 
11 daniel-mar 1502
  if (CheckBox1.Checked or (CurScene^.numActions >= 1)) and
1503
     (SpinEdit3.Value < SpinEdit4.Value) and (SpinEdit2.Value < SpinEdit5.Value) then
2 daniel-mar 1504
  begin
1505
    Image1.Canvas.Pen.Color := clRed;
1506
    Image1.Canvas.Brush.Color := clRed;
1507
    Image1.Canvas.Rectangle(SpinEdit3.Value,  SpinEdit2.Value,  SpinEdit4.Value,  SpinEdit5.Value);
1508
  end;
1509
 
11 daniel-mar 1510
  if (CheckBox1.Checked or (CurScene^.numActions >= 2)) and
1511
     (SpinEdit17.Value < SpinEdit19.Value) and (SpinEdit18.Value < SpinEdit20.Value) then
2 daniel-mar 1512
  begin
1513
    Image1.Canvas.Pen.Color := clLime;
1514
    Image1.Canvas.Brush.Color := clLime;
1515
    Image1.Canvas.Rectangle(SpinEdit17.Value, SpinEdit18.Value, SpinEdit19.Value, SpinEdit20.Value);
1516
  end;
1517
 
11 daniel-mar 1518
  if (CheckBox1.Checked or (CurScene^.numActions >= 3)) and
1519
     (SpinEdit7.Value < SpinEdit10.Value) and (SpinEdit8.Value < SpinEdit9.Value) then
2 daniel-mar 1520
  begin
1521
    Image1.Canvas.Pen.Color := clBlue;
1522
    Image1.Canvas.Brush.Color := clBlue;
1523
    Image1.Canvas.Rectangle(SpinEdit7.Value,  SpinEdit8.Value,  SpinEdit10.Value, SpinEdit9.Value);
1524
  end;
1525
end;
1526
 
1527
end.