Subversion Repositories plumbers

Compare Revisions

Regard whitespace Rev 1 → Rev 2

/trunk/SceneEditor/Unit1.pas
0,0 → 1,1244
unit Unit1;
 
// TODO: create for "unused files" box a small thumbnail, too?
 
interface
 
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, Grids, GameBinStruct, ComCtrls, ExtCtrls, Vcl.MPlayer,
Vcl.Menus;
 
const
CUR_VER = '2017-08-09';
 
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button10: TButton;
PageControl2: TPageControl;
TabSheet4: TTabSheet;
Label1: TLabel;
Label2: TLabel;
SpinEdit1: TSpinEdit;
Edit1: TEdit;
Button6: TButton;
Button7: TButton;
Button8: TButton;
Button9: TButton;
ListBox2: TListBox;
TabSheet5: TTabSheet;
Label3: TLabel;
Image1: TImage;
Label10: TLabel;
Label11: TLabel;
Edit2: TEdit;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
Label5: TLabel;
Label4: TLabel;
Label6: TLabel;
SpinEdit6: TSpinEdit;
SpinEdit2: TSpinEdit;
SpinEdit3: TSpinEdit;
SpinEdit4: TSpinEdit;
SpinEdit5: TSpinEdit;
ComboBox1: TComboBox;
TabSheet2: TTabSheet;
Label13: TLabel;
Label14: TLabel;
Label15: TLabel;
ComboBox2: TComboBox;
SpinEdit17: TSpinEdit;
SpinEdit18: TSpinEdit;
SpinEdit19: TSpinEdit;
SpinEdit20: TSpinEdit;
SpinEdit21: TSpinEdit;
TabSheet3: TTabSheet;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
ComboBox3: TComboBox;
SpinEdit7: TSpinEdit;
SpinEdit8: TSpinEdit;
SpinEdit9: TSpinEdit;
SpinEdit10: TSpinEdit;
SpinEdit11: TSpinEdit;
SpinEdit12: TSpinEdit;
Image2: TImage;
Edit3: TEdit;
SpinEdit13: TSpinEdit;
Label12: TLabel;
Label16: TLabel;
Button13: TButton;
Button14: TButton;
MediaPlayer1: TMediaPlayer;
Timer1: TTimer;
GroupBox1: TGroupBox;
Label20: TLabel;
Label21: TLabel;
Label22: TLabel;
Label23: TLabel;
GroupBox2: TGroupBox;
Button15: TButton;
Button17: TButton;
Button16: TButton;
Label18: TLabel;
Label17: TLabel;
ListBox3: TListBox;
Label19: TLabel;
Label24: TLabel;
Label25: TLabel;
Label26: TLabel;
Label27: TLabel;
Label28: TLabel;
Label29: TLabel;
Button11: TButton;
Button12: TButton;
Button18: TButton;
MainMenu1: TMainMenu;
File1: TMenuItem;
Close1: TMenuItem;
Newfile1: TMenuItem;
Savetogamebin1: TMenuItem;
Saveandtest1: TMenuItem;
N1: TMenuItem;
N2: TMenuItem;
Help1: TMenuItem;
About1: TMenuItem;
PopupMenu1: TPopupMenu;
Addtoscene1: TMenuItem;
procedure ListBox1Click(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure Edit2Change(Sender: TObject);
procedure SpinEdit1Change(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure SpinEdit12Change(Sender: TObject);
procedure ActionTargetChange(Sender: TObject);
procedure ActionSpinEditsChange(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button10Click(Sender: TObject);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure ListBox2Click(Sender: TObject);
procedure SpinEdit13Change(Sender: TObject);
procedure Edit3Change(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button13Click(Sender: TObject);
procedure Button14Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button17Click(Sender: TObject);
procedure Button15Click(Sender: TObject);
procedure Button16Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure ListBox2DblClick(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure Button9Click(Sender: TObject);
procedure Image1MouseLeave(Sender: TObject);
procedure ListBox3DblClick(Sender: TObject);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Button11Click(Sender: TObject);
procedure Button12Click(Sender: TObject);
procedure Button18Click(Sender: TObject);
procedure Image1MouseEnter(Sender: TObject);
procedure About1Click(Sender: TObject);
procedure Close1Click(Sender: TObject);
procedure Addtoscene1Click(Sender: TObject);
procedure ListBox3MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
Game: TGameBinFile;
PlayStart: Cardinal;
MediaplayerOpened: boolean;
StopPlayRequest: boolean;
FirstTickCount: Cardinal;
function CurScene: PSceneDef;
procedure LoadScene;
procedure Load;
procedure Save;
procedure ReloadActionSceneLists;
function FindSceneIndex(sceneID: integer): integer;
function GetGreatestSceneID: integer;
function SearchSceneIDGapFromTop: integer;
procedure RedrawDecisionBitmap;
function CurPicture: PPictureDef;
function CurPictureTimepos: Cardinal;
procedure New;
procedure NewScene;
procedure SetupGUIAfterLoad;
procedure RecalcSlideshowLength;
procedure RecalcSoundtrackLength;
procedure RecalcUnusedFiles;
procedure HandlePossibleEmptySceneList;
procedure DisableEnableSceneControls(enable: boolean);
procedure DisableEnablePictureControls(enable: boolean);
procedure DisableEnableFileControls(enable: boolean);
end;
 
var
Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses
Math, MMSystem, ShellAPI;
 
function GetSceneIDFromName(sceneName: string): Integer;
var
sSceneID: string;
begin
if Copy(sceneName, 1, 2) <> 'SC' then raise Exception.Create('Scene name invalid');
sSceneID := Copy(sceneName, 3, 2);
if not TryStrToInt(sSceneID, result) then raise Exception.Create('Scene name invalid');
end;
 
function _DecisecondToTime(ds: integer): string;
begin
result := FormatDatetime('hh:nn:ss', ds / 10 / (24*60*60))+','+IntToStr(ds mod 10);
end;
 
{ TForm1 }
 
function TForm1.GetGreatestSceneID: integer;
var
i: integer;
begin
result := -1;
for i := 0 to ListBox1.Items.Count - 1 do
begin
result := Max(result, GetSceneIDFromName(ListBox1.Items.Strings[i]));
end;
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
sE1, sE2, sE3, sE4: TSpinEdit;
 
procedure _Go;
begin
if Button = mbLeft then
begin
sE1.Value := Round(Image1.Picture.Width*(X/Image1.Width));
sE2.Value := Round(Image1.Picture.Height*(Y/Image1.Height));
end
else if Button = mbRight then
begin
sE3.Value := Round(Image1.Picture.Width*(X/Image1.Width));
sE4.Value := Round(Image1.Picture.Height*(Y/Image1.Height));
end;
end;
 
begin
if PageControl1.ActivePage = TabSheet1 then
begin
sE1 := SpinEdit3;
sE2 := SpinEdit2;
sE3 := SpinEdit4;
sE4 := SpinEdit5;
_Go;
end
else if PageControl1.ActivePage = TabSheet2 then
begin
sE1 := SpinEdit17;
sE2 := SpinEdit18;
sE3 := SpinEdit19;
sE4 := SpinEdit20;
_Go;
end
else if PageControl1.ActivePage = TabSheet3 then
begin
sE1 := SpinEdit7;
sE2 := SpinEdit8;
sE3 := SpinEdit10;
sE4 := SpinEdit9;
_Go;
end;
end;
 
procedure TForm1.Image1MouseEnter(Sender: TObject);
begin
Label28.Visible := true;
Label29.Visible := true;
end;
 
procedure TForm1.Image1MouseLeave(Sender: TObject);
begin
Label10.Caption := '';
Label28.Visible := false;
Label29.Visible := false;
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
label10.Caption := Format('Coords: [%d, %d]', [Round(Image1.Picture.Width*(X/Image1.Width)),
Round(Image1.Picture.Height*(Y/Image1.Height))]);
end;
 
function TForm1.SearchSceneIDGapFromTop: integer;
var
i: integer;
begin
result := -1;
for i := 99 downto 0 do
begin
if ListBox1.Items.IndexOf(Format('SC%.2d', [i])) = -1 then
begin
result := i;
exit;
end;
end;
end;
 
procedure TForm1.Button10Click(Sender: TObject);
begin
Save;
if not FileExists('ShowTime32.exe') then raise Exception.Create('ShowTime32.exe not found.');
ShellExecute(Application.Handle, 'open', 'ShowTime32.exe', '', '', SW_NORMAL);
end;
 
procedure TForm1.Button11Click(Sender: TObject);
var
fileName: string;
begin
fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDecisionBmp;
if not FileExists(fileName) then exit;
ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
end;
 
procedure TForm1.Button12Click(Sender: TObject);
var
fileName: string;
begin
fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurPicture^.szBitmapFile;
if not FileExists(fileName) then exit;
ShellExecute(Application.Handle, 'open', Pchar(fileName), '', '', SW_NORMAL);
end;
 
procedure TForm1.Button13Click(Sender: TObject);
var
fileName: string;
begin
fileName := CurScene^.szSceneFolder;
if not DirectoryExists(fileName) then MkDir(fileName);
ShellExecute(Application.Handle, 'open', 'explorer.exe', PChar(fileName), '', SW_NORMAL);
end;
 
procedure TForm1.HandlePossibleEmptySceneList;
begin
if Game.numScenes = 0 then
begin
PageControl2.ActivePage := nil;
PageControl2.Pages[0].TabVisible := false;
PageControl2.Pages[1].TabVisible := false;
end
else
begin
if PageControl2.ActivePage = nil then PageControl2.ActivePageIndex := 0;
PageControl2.Pages[0].TabVisible := true;
PageControl2.Pages[1].TabVisible := true;
end;
end;
 
procedure TForm1.Button14Click(Sender: TObject);
begin
New;
HandlePossibleEmptySceneList;
end;
 
procedure TForm1.DisableEnableSceneControls(enable: boolean);
begin
ListBox1.Enabled := enable;
Button1.Enabled := enable;
Button2.Enabled := enable;
Button4.Enabled := enable;
Button5.Enabled := enable;
end;
 
procedure TForm1.DisableEnablePictureControls(enable: boolean);
begin
Button8.Enabled := enable;
Button9.Enabled := enable;
Button6.Enabled := enable;
Button7.Enabled := enable;
end;
 
procedure TForm1.DisableEnableFileControls(enable: boolean);
begin
Button3.Enabled := enable;
Button10.Enabled := enable;
Button14.Enabled := enable;
end;
 
procedure TForm1.Button15Click(Sender: TObject);
var
decisionBMP: string;
PictureLastFrame: Cardinal;
i: integer;
DecisionPicSet: boolean;
begin
if PlayStart <> 0 then
begin
if MediaplayerOpened then
begin
if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
Mediaplayer1.TimeFormat := tfMilliseconds;
if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
begin
MediaPlayer1.Position := CurPictureTimepos * 100;
MediaPlayer1.Play;
end;
end;
FirstTickCount := GetTickCount;
PlayStart := GetTickCount - CurPictureTimepos * 100;
end
else
begin
DisableEnablePictureControls(false);
DisableEnableSceneControls(false);
DisableEnableFileControls(false);
Edit1.Enabled := false;
Edit3.Enabled := false;
SpinEdit1.Enabled := false;
SpinEdit13.Enabled := false;
Label18.Font.Color := clGreen;
try
Timer1.Enabled := false;
 
RecalcSoundtrackLength; // optional
 
Mediaplayer1.FileName := Format('%s\%s', [CurScene^.szSceneFolder, CurScene^.szDialogWav]);
if FileExists(Mediaplayer1.FileName) then
begin
Mediaplayer1.TimeFormat := tfMilliseconds;
Mediaplayer1.Open;
MediaplayerOpened := true;
if CurPictureTimepos*100 < Cardinal(MediaPlayer1.Length) then
begin
MediaPlayer1.Position := CurPictureTimepos * 100;
MediaPlayer1.Play;
end;
end
else
begin
MediaplayerOpened := false;
MediaPlayer1.FileName := '';
end;
PlayStart := GetTickCount - CurPictureTimepos * 100;
Timer1.Enabled := true;
 
{$REGION 'Calculate PictureLastFrame'}
PictureLastFrame := 0;
for i := 0 to CurScene^.numPics-1 do
begin
Inc(PictureLastFrame, Game.pictures[CurScene^.pictureIndex + i].duration);
end;
PictureLastFrame := PictureLastFrame * 100;
{$ENDREGION}
 
DecisionPicSet := false;
while not Application.Terminated and
not StopPlayRequest and
(
(MediaPlayer1.Mode = mpPlaying) or
(GetTickCount - PlayStart <= PictureLastFrame)
) do
begin
if GetTickCount - PlayStart <= PictureLastFrame then
begin
DecisionPicSet := false;
FirstTickCount := GetTickCount;
while not Application.Terminated and ((GetTickCount - FirstTickCount) < CurPicture^.duration * 100) and not StopPlayRequest do
begin
Application.ProcessMessages;
Sleep(0);
end;
 
if not Application.Terminated and (ListBox2.ItemIndex < ListBox2.Count-1) and not StopPlayRequest then
begin
ListBox2.ItemIndex := ListBox2.ItemIndex + 1;
ListBox2Click(ListBox2);
end;
end
else
begin
if not DecisionPicSet then
begin
decisionBMP := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDecisionBmp;
if (CurScene^.szDecisionBmp <> '') and FileExists(decisionBMP) then
begin
Image2.Picture.LoadFromFile(decisionBMP);
end
else
begin
Image2.Picture := nil;
end;
DecisionPicSet := true;
end;
Application.ProcessMessages;
Sleep(0);
end;
end;
finally
PlayStart := 0;
if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Stop;
if MediaplayerOpened then MediaPlayer1.Close;
StopPlayRequest := false;
Label18.Font.Color := clWindowText;
Timer1.Enabled := false;
DisableEnableFileControls(true);
DisableEnableSceneControls(true);
DisableEnablePictureControls(true);
Edit1.Enabled := true;
SpinEdit1.Enabled := true;
Edit3.Enabled := true;
SpinEdit13.Enabled := true;
Label18.Caption := _DecisecondToTime(CurPictureTimepos);
ListBox2Click(ListBox2);
end;
end;
end;
 
procedure TForm1.Button16Click(Sender: TObject);
begin
ListBox2.ItemIndex := 0; // go to the beginning
ListBox2Click(ListBox2); // load picture data
Button15Click(Button15); // play
end;
 
procedure TForm1.Button17Click(Sender: TObject);
begin
if PlayStart <> 0 then
begin
Timer1.Enabled := false;
if MediaplayerOpened then MediaPlayer1.Stop;
StopPlayRequest := true;
end;
end;
 
procedure TForm1.Button18Click(Sender: TObject);
var
fileName: string;
begin
fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
if not FileExists(fileName) then exit;
ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
end;
 
procedure TForm1.NewScene;
var
sceneID: integer;
newScene: PSceneDef;
begin
if ListBox1.Items.Count = 100 then
begin
raise Exception.Create('No more space for another scene');
end;
 
sceneID := GetGreatestSceneID+1;
if sceneID >= Length(Game.scenes) then sceneID := SearchSceneIDGapFromTop;
 
newScene := Game.AddSceneAtEnd(sceneID);
newScene.actions[0].nextSceneID := SCENEID_ENDGAME;
ListBox1.Items.Add(newScene.szSceneFolder);
ReloadActionSceneLists;
HandlePossibleEmptySceneList;
ListBox1.ItemIndex := ListBox1.Items.Count - 1;
ListBox1Click(ListBox1);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
NewScene;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
iScene, iAction, sceneID: integer;
conflicts: TStringList;
sWarning: string;
bakItemindex: integer;
begin
if ListBox1.Count = 0 then exit;
 
(*
if ListBox1.Count = 1 then
begin
raise Exception.Create('Can''t delete the scene if there is only one.');
end;
*)
 
conflicts := TStringList.Create;
try
sceneID := GetSceneIDFromName(CurScene^.szSceneFolder);
for iScene := 0 to Game.numScenes-1 do
begin
for iAction := 0 to Game.scenes[iScene].numActions-1 do
begin
if Game.scenes[iScene].actions[iAction].nextSceneID = sceneID then
begin
conflicts.Add(Format('Scene %s, action #%d', [Game.scenes[iScene].szSceneFolder, iAction+1]));
end;
end;
end;
if conflicts.Count > 0 then
begin
raise Exception.Create('Can''t delete this scene. There are following dependencies:'+#13#10#13#10+conflicts.Text);
end;
finally
FreeAndNil(conflicts);
end;
 
sWarning := Format('Do you really want to delete scene %s?', [CurScene^.szSceneFolder]);
if (ListBox1.ItemIndex = 0) and (ListBox1.Count >= 2) then
sWarning := Format('Attention: This will make %s to your new intro sequence. Is that OK?', [ListBox1.Items[ListBox1.ItemIndex+1]]);
if (MessageDlg(sWarning, mtConfirmation, mbYesNoCancel, 0) <> mrYes) then
begin
Exit;
end;
 
Game.DeleteScene(ListBox1.ItemIndex);
Dec(Game.numScenes);
 
bakItemindex := ListBox1.ItemIndex;
ListBox1.Items.Delete(bakItemindex);
ReloadActionSceneLists;
HandlePossibleEmptySceneList;
if ListBox1.Count > 0 then
begin
if bakItemindex = ListBox1.Count then Dec(bakItemindex);
Listbox1.ItemIndex := bakItemindex;
ListBox1Click(ListBox1);
end;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
begin
Save;
end;
 
procedure TForm1.Button4Click(Sender: TObject);
begin
if ListBox1.ItemIndex <= 0 then exit;
Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex-1);
ReloadActionSceneLists;
end;
 
procedure TForm1.Button5Click(Sender: TObject);
begin
if ListBox1.ItemIndex = ListBox1.Count-1 then exit;
Game.SwapScene(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
ListBox1.Items.Exchange(ListBox1.ItemIndex, ListBox1.ItemIndex+1);
ReloadActionSceneLists;
end;
 
procedure TForm1.Button6Click(Sender: TObject);
var
pic: PPictureDef;
begin
pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0));
pic.duration := 0;
pic.szBitmapFile := 'DUMMY.BMP';
ListBox2.Items.Insert(ListBox2.ItemIndex, '(0) DUMMY.BMP');
if ListBox2.ItemIndex = -1 then
begin
ListBox2.ItemIndex := ListBox2.Count - 1;
end
else
begin
ListBox2.ItemIndex := ListBox2.ItemIndex - 1;
end;
ListBox2Click(Listbox2);
end;
 
procedure TForm1.Button7Click(Sender: TObject);
var
bakIdx: integer;
begin
if Listbox2.Count > 0 then
begin
bakIdx := ListBox2.ItemIndex;
Game.DeletePicture(bakIdx);
ListBox2.Items.Delete(bakIdx);
if ListBox2.Count > 0 then
begin
if bakIdx = ListBox2.Count then Dec(bakIdx);
ListBox2.ItemIndex := bakIdx;
ListBox2Click(Listbox2);
end;
end;
end;
 
procedure TForm1.Button8Click(Sender: TObject);
begin
if ListBox2.ItemIndex <= 0 then exit;
Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex-1);
ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex-1);
end;
 
procedure TForm1.Button9Click(Sender: TObject);
begin
if ListBox2.ItemIndex = ListBox2.Count-1 then exit;
Game.SwapPicture(CurScene^.pictureIndex+ListBox2.ItemIndex, CurScene^.pictureIndex+ListBox2.ItemIndex+1);
ListBox2.Items.Exchange(ListBox2.ItemIndex, ListBox2.ItemIndex+1);
end;
 
procedure TForm1.Save;
var
fs: TFileStream;
begin
fs := TFileStream.Create('GAME.BIN', fmOpenWrite or fmCreate);
try
fs.WriteBuffer(Game, SizeOf(Game));
finally
FreeAndNil(fs);
end;
end;
 
procedure TForm1.ActionTargetChange(Sender: TObject);
var
actionIdx: integer;
itemIdx: Integer;
begin
if Sender = ComboBox1 then actionIdx := 0
else if Sender = ComboBox2 then actionIdx := 1
else if Sender = ComboBox3 then actionIdx := 2
else raise Exception.Create('Unexpected sender for ActionTargetChange()');
 
itemIdx := TComboBox(Sender).ItemIndex;
if itemIdx = 0 then
CurScene^.actions[actionIdx].nextSceneID := SCENEID_ENDGAME
else if itemIdx = 1 then
CurScene^.actions[actionIdx].nextSceneID := SCENEID_PREVDECISION
else
CurScene^.actions[actionIdx].nextSceneID := GetSceneIDFromName(ListBox1.Items[itemIdx - 2]);
end;
 
procedure TForm1.Addtoscene1Click(Sender: TObject);
var
fil: string;
begin
if ListBox3.ItemIndex = -1 then exit;
fil := ListBox3.Items[ListBox3.ItemIndex];
Button6.Click;
Edit3.Text := fil;
end;
 
procedure TForm1.Edit1Change(Sender: TObject);
begin
_WriteStringToFilename(@CurScene^.szDialogWav, Edit1.Text);
RecalcSoundtrackLength;
RecalcUnusedFiles;
 
Label24.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit1.Text);
Label25.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + 'E' + Edit1.Text);
 
Button18.Visible := CurScene^.szDialogWav <> '';
end;
 
procedure TForm1.Edit2Change(Sender: TObject);
begin
_WriteStringToFilename(@CurScene^.szDecisionBmp, Edit2.Text);
RecalcUnusedFiles;
Label27.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text) and not (Edit2.Text = '');
Button11.Visible := CurScene^.szDecisionBmp <> '';
end;
 
procedure TForm1.Edit3Change(Sender: TObject);
begin
_WriteStringToFilename(@CurPicture^.szBitmapFile, Edit3.Text);
ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
RecalcUnusedFiles;
Label26.Visible := not FileExists(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit3.Text);
Button12.Visible := CurPicture^.szBitmapFile <> '';
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
PageControl1.ActivePageIndex := 0;
PageControl2.ActivePageIndex := 0;
Label10.Caption := '';
Label21.Caption := '';
Label23.Caption := '';
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
if FileExists('GAME.BIN') then
Load
else
New;
end;
 
function TForm1.CurScene: PSceneDef;
begin
if ListBox1.Count = 0 then raise Exception.Create('No scene available. Please create one.');
if ListBox1.ItemIndex = -1 then raise Exception.Create('No scene selected. Please select one.');
result := @Game.scenes[ListBox1.ItemIndex];
end;
 
procedure TForm1.ListBox1Click(Sender: TObject);
begin
LoadScene;
end;
 
procedure TForm1.ListBox1DblClick(Sender: TObject);
begin
Button16Click(Button16);
end;
 
procedure TForm1.Close1Click(Sender: TObject);
begin
Close;
end;
 
function TForm1.CurPicture: PPictureDef;
begin
if ListBox2.Count = 0 then raise Exception.Create('No pictures available. Please create one.');
if ListBox2.ItemIndex = -1 then raise Exception.Create('No pictures selected. Please select one.');
result := @Game.pictures[CurScene^.pictureIndex + ListBox2.ItemIndex]
end;
 
function TForm1.CurPictureTimepos: Cardinal;
var
i: integer;
begin
result := 0;
for i := curScene^.pictureIndex to curScene^.pictureIndex + ListBox2.ItemIndex - 1 do
begin
Inc(result, Game.pictures[i].duration);
end;
end;
 
procedure TForm1.ListBox2Click(Sender: TObject);
var
Filename: string;
begin
SpinEdit13.Value := CurPicture^.duration;
Edit3.Text := string(CurPicture^.szBitmapFile);
 
Filename := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurPicture^.szBitmapFile);
if FileExists(Filename) then
Image2.Picture.LoadFromFile(Filename) // TODO: keep aspect ratio
else
Image2.Picture := nil;
 
Label18.Caption := _DecisecondToTime(CurPictureTimepos);
 
if PlayStart <> 0 then
begin
Button15Click(Button15);
end;
end;
 
procedure TForm1.ListBox2DblClick(Sender: TObject);
begin
Button15Click(Button15);
end;
 
procedure TForm1.ListBox3DblClick(Sender: TObject);
var
fileName: string;
begin
if ListBox3.ItemIndex = -1 then exit;
fileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + ListBox3.Items[ListBox3.ItemIndex];
if not FileExists(FileName) then exit;
ShellExecute(Application.Handle, 'open', PChar(fileName), '', '', SW_NORMAL);
end;
 
procedure TForm1.ListBox3MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
APoint: TPoint;
Index: integer;
begin
if Button = mbRight then
begin
APoint.X := X;
APoint.Y := Y;
Index := TListbox(Sender).ItemAtPos(APoint, True);
if Index > -1 then TListbox(Sender).Selected[Index] := True;
end;
end;
 
procedure TForm1.SetupGUIAfterLoad;
var
i: integer;
begin
ListBox1.Clear;
for i := 0 to Game.numScenes - 1 do
begin
ListBox1.Items.Add(string(Game.scenes[i].szSceneFolder));
end;
(*
if ListBox1.Items.Count = 0 then
begin
NewScene;
end;
*)
 
ReloadActionSceneLists;
HandlePossibleEmptySceneList;
 
if ListBox1.Count > 0 then
begin
ListBox1.ItemIndex := 0;
ListBox1Click(Listbox1);
end;
end;
 
procedure TForm1.New;
begin
ZeroMemory(@Game, SizeOf(Game));
 
SetupGUIAfterLoad;
end;
 
procedure TForm1.Load;
var
fs: TFileStream;
begin
fs := TFileStream.Create('GAME.BIN', fmOpenRead);
try
fs.ReadBuffer(Game, SizeOf(Game));
finally
FreeAndNil(fs);
end;
 
SetupGUIAfterLoad;
end;
 
function TForm1.FindSceneIndex(sceneID: integer): integer;
var
i: Integer;
sSceneID: string;
begin
sSceneID := Format('SC%.2d', [sceneID]);
for i := 0 to ListBox1.Count - 1 do
begin
if ListBox1.Items.Strings[i] = sSceneID then
begin
result := i;
exit;
end;
end;
result := -1;
end;
 
procedure TForm1.RecalcSlideshowLength;
var
i: integer;
Sum: integer;
begin
Sum := 0;
for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
begin
Inc(Sum, Game.pictures[i].duration);
end;
Label21.Caption := _DecisecondToTime(Sum);
end;
 
procedure TForm1.RecalcUnusedFiles;
var
i, idx: integer;
SR: TSearchRec;
begin
ListBox3.Clear;
 
if FindFirst(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + '*.*', faArchive, SR) = 0 then
begin
repeat
ListBox3.Items.Add(SR.Name); //Fill the list
until FindNext(SR) <> 0;
FindClose(SR);
end;
 
for i := CurScene^.pictureIndex to CurScene^.pictureIndex+CurScene^.numPics-1 do
begin
idx := ListBox3.Items.IndexOf(Game.pictures[i].szBitmapFile);
if idx <> -1 then ListBox3.Items.Delete(idx);
end;
 
idx := ListBox3.Items.IndexOf(Edit1.Text);
if idx <> -1 then ListBox3.Items.Delete(idx);
idx := ListBox3.Items.IndexOf('E'+Edit1.Text);
if idx <> -1 then ListBox3.Items.Delete(idx);
 
idx := ListBox3.Items.IndexOf(Edit2.Text);
if idx <> -1 then ListBox3.Items.Delete(idx);
 
idx := ListBox3.Items.IndexOf(Edit3.Text);
if idx <> -1 then ListBox3.Items.Delete(idx);
end;
 
procedure TForm1.RecalcSoundtrackLength;
var
FileName: string;
begin
if MediaPlayer1.Mode = mpPlaying then exit;
 
FileName := IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + CurScene^.szDialogWav;
if not FileExists(FileName) then
begin
Label23.Caption := 'n/a';
exit;
end;
MediaPlayer1.FileName := FileName;
MediaPlayer1.TimeFormat := tfMilliseconds;
MediaPlayer1.Open;
Label23.Caption := _DecisecondToTime(MediaPlayer1.Length div 100);
MediaPlayer1.Close;
end;
 
procedure TForm1.LoadScene;
 
procedure _SelectActionComboBox(ComboBox: TComboBox; sceneID: SmallInt);
var
idx: Integer;
begin
if sceneID = SCENEID_ENDGAME then
ComboBox.ItemIndex := 0
else if sceneID = SCENEID_PREVDECISION then
ComboBox.ItemIndex := 1
else
begin
idx := FindSceneIndex(sceneID);
if idx = -1 then
ComboBox.ItemIndex := -1
else
ComboBox.ItemIndex := 2 + idx;
end;
end;
 
procedure _PreparePictureList;
var
i: integer;
pic: PPictureDef;
begin
ListBox2.Clear;
 
if CurScene^.numPics = 0 then
begin
pic := Game.AddPictureBetween(CurScene^.pictureIndex + Max(ListBox2.ItemIndex,0));
pic.duration := 0;
pic.szBitmapFile := 'DUMMY.BMP';
end;
 
for i := CurScene^.pictureIndex to CurScene^.pictureIndex + CurScene^.numPics - 1 do
begin
Listbox2.Items.Add(Format('(%d) %s', [Game.pictures[i].duration, Game.pictures[i].szBitmapFile]));
end;
end;
 
begin
SpinEdit1.Value := GetSceneIDFromName(CurScene^.szSceneFolder);
Edit1.Text := string(CurScene^.szDialogWav);
Edit2.Text := string(CurScene^.szDecisionBmp);
 
_PreparePictureList;
ListBox2.ItemIndex := 0;
ListBox2Click(Listbox2);
 
_SelectActionComboBox(ComboBox1, CurScene^.actions[0].nextSceneID);
_SelectActionComboBox(ComboBox2, CurScene^.actions[1].nextSceneID);
_SelectActionComboBox(ComboBox3, CurScene^.actions[2].nextSceneID);
 
SpinEdit12.Value := CurScene^.numActions;
SpinEdit12Change(SpinEdit12);
PageControl1.ActivePageIndex := 0;
 
SpinEdit3.Value := CurScene^.actions[0].cHotspotTopLeft.X;
SpinEdit17.Value := CurScene^.actions[1].cHotspotTopLeft.X;
SpinEdit7.Value := CurScene^.actions[2].cHotspotTopLeft.X;
SpinEdit2.Value := CurScene^.actions[0].cHotspotTopLeft.Y;
SpinEdit18.Value := CurScene^.actions[1].cHotspotTopLeft.Y;
SpinEdit8.Value := CurScene^.actions[2].cHotspotTopLeft.Y;
SpinEdit4.Value := CurScene^.actions[0].cHotspotBottomRight.X;
SpinEdit19.Value := CurScene^.actions[1].cHotspotBottomRight.X;
SpinEdit10.Value := CurScene^.actions[2].cHotspotBottomRight.X;
SpinEdit5.Value := CurScene^.actions[0].cHotspotBottomRight.Y;
SpinEdit20.Value := CurScene^.actions[1].cHotspotBottomRight.Y;
SpinEdit9.Value := CurScene^.actions[2].cHotspotBottomRight.Y;
SpinEdit6.Value := CurScene^.actions[0].scoreDelta;
SpinEdit21.Value := CurScene^.actions[1].scoreDelta;
SpinEdit11.Value := CurScene^.actions[2].scoreDelta;
 
RedrawDecisionBitmap;
 
RecalcSlideshowLength;
RecalcSoundtrackLength;
 
RecalcUnusedFiles;
end;
 
procedure TForm1.ReloadActionSceneLists;
 
procedure _ReloadActionSceneLists(ComboBox: TComboBox);
var
prevSelection: string;
i: Integer;
begin
prevSelection := ComboBox.Text;
try
ComboBox.Items.Clear;
ComboBox.Items.Add('Terminate program');
ComboBox.Items.Add('Previous decision');
ComboBox.Items.AddStrings(ListBox1.Items);
finally
ComboBox.ItemIndex := 0;
for i := ComboBox.Items.Count - 1 downto 0 do
begin
if ComboBox.Items.Strings[i] = prevSelection then
begin
ComboBox.ItemIndex := i;
end;
end;
end;
end;
 
begin
_ReloadActionSceneLists(ComboBox1);
_ReloadActionSceneLists(ComboBox2);
_ReloadActionSceneLists(ComboBox3);
end;
 
procedure TForm1.SpinEdit12Change(Sender: TObject);
begin
TabSheet3.TabVisible := SpinEdit12.Value >= 3;
if PageControl1.ActivePage = TabSheet3 then PageControl1.ActivePage := TabSheet2;
 
TabSheet2.TabVisible := SpinEdit12.Value >= 2;
if PageControl1.ActivePage = TabSheet2 then PageControl1.ActivePage := TabSheet1;
 
// TabSheet1.TabVisible := SpinEdit12.Value >= 1;
 
CurScene^.numActions := SpinEdit12.Value;
 
// QUE: zero data of actions which are inactive (numActions<action)?
end;
 
procedure TForm1.SpinEdit13Change(Sender: TObject);
begin
if SpinEdit13.Text = '' then exit;
CurPicture^.duration := SpinEdit13.Value;
ListBox2.Items[ListBox2.ItemIndex] := Format('(%d) %s', [CurPicture^.duration, CurPicture^.szBitmapFile]);
RecalcSlideshowLength;
end;
 
procedure TForm1.SpinEdit1Change(Sender: TObject);
 
function _CountNumScenes(str: string): integer;
var
i: integer;
begin
result := 0;
for i := 0 to ListBox1.Count-1 do
begin
if ListBox1.Items[i] = str then Inc(result);
end;
end;
 
var
sNew: string;
begin
// TODO: warn if dependencies are broken
 
if SpinEdit1.Text = '' then exit;
CurScene; // verify that a scene exists and is selected
sNew := Format('SC%.2d', [SpinEdit1.Value]);
ListBox1.Items[ListBox1.ItemIndex] := sNew;
Label17.Visible := _CountNumScenes(sNew) > 1;
ReloadActionSceneLists;
_WriteStringToFilename(@CurScene^.szSceneFolder, ListBox1.Items[ListBox1.ItemIndex]);
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
var
ms: Cardinal;
begin
ms := GetTickCount - PlayStart;
Label18.Caption := FormatDatetime('hh:nn:ss', ms / 1000 / (24*60*60)) + ',' + IntToStr(ms mod 1000 div 100);
end;
 
procedure TForm1.About1Click(Sender: TObject);
begin
ShowMessage('Plumbers Dont''t Wear Ties - GAME.BIN editor (can be also used to create new games based on the "ShowTime" engine!)'+#13#10#13#10+'Written by Daniel Marschall (www.daniel-marschall.de)'+#13#10#13#10+'Published by ViaThinkSoft (www.viathinksoft.com).'+#13#10#13#10+'Current version: ' + CUR_VER);
end;
 
procedure TForm1.ActionSpinEditsChange(Sender: TObject);
begin
if TSpinEdit(Sender).Text = '' then exit; // user is about to enter a negative value
if TSpinEdit(Sender).Text = '-' then exit; // user is about to enter a negative value
 
if Sender = SpinEdit3 then CurScene^.actions[0].cHotspotTopLeft.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit17 then CurScene^.actions[1].cHotspotTopLeft.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit7 then CurScene^.actions[2].cHotspotTopLeft.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit2 then CurScene^.actions[0].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit18 then CurScene^.actions[1].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit8 then CurScene^.actions[2].cHotspotTopLeft.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit4 then CurScene^.actions[0].cHotspotBottomRight.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit19 then CurScene^.actions[1].cHotspotBottomRight.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit10 then CurScene^.actions[2].cHotspotBottomRight.X := TSpinEdit(Sender).Value
else if Sender = SpinEdit5 then CurScene^.actions[0].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit20 then CurScene^.actions[1].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit9 then CurScene^.actions[2].cHotspotBottomRight.Y := TSpinEdit(Sender).Value
else if Sender = SpinEdit6 then CurScene^.actions[0].scoreDelta := TSpinEdit(Sender).Value
else if Sender = SpinEdit21 then CurScene^.actions[1].scoreDelta := TSpinEdit(Sender).Value
else if Sender = SpinEdit11 then CurScene^.actions[2].scoreDelta := TSpinEdit(Sender).Value;
 
RedrawDecisionBitmap;
end;
 
procedure TForm1.RedrawDecisionBitmap;
var
Filename: string;
begin
FileName := string(IncludeTrailingPathDelimiter(CurScene^.szSceneFolder) + Edit2.Text);
if FileExists(FileName) then
Image1.Picture.Bitmap.LoadFromFile(FileName) // TODO: keep aspect ratio
else
Image1.Picture := nil;
 
Image1.Picture.Bitmap.PixelFormat := pf24bit; // Extend the palette, so we have red, green and blue guaranteed.
 
Image1.Canvas.Brush.Style := bsDiagCross;
 
if (SpinEdit3.Value < SpinEdit4.Value) and (SpinEdit2.Value < SpinEdit5.Value) then
begin
Image1.Canvas.Pen.Color := clRed;
Image1.Canvas.Brush.Color := clRed;
Image1.Canvas.Rectangle(SpinEdit3.Value, SpinEdit2.Value, SpinEdit4.Value, SpinEdit5.Value);
end;
 
if (SpinEdit17.Value < SpinEdit19.Value) and (SpinEdit18.Value < SpinEdit20.Value) then
begin
Image1.Canvas.Pen.Color := clLime;
Image1.Canvas.Brush.Color := clLime;
Image1.Canvas.Rectangle(SpinEdit17.Value, SpinEdit18.Value, SpinEdit19.Value, SpinEdit20.Value);
end;
 
if (SpinEdit7.Value < SpinEdit10.Value) and (SpinEdit8.Value < SpinEdit9.Value) then
begin
Image1.Canvas.Pen.Color := clBlue;
Image1.Canvas.Brush.Color := clBlue;
Image1.Canvas.Rectangle(SpinEdit7.Value, SpinEdit8.Value, SpinEdit10.Value, SpinEdit9.Value);
end;
end;
 
end.