Subversion Repositories plumbers

Rev

Rev 10 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
unit GameBinStruct;
2
 
3
{$A-}
4
 
5
interface
6
 
7
const
8
  SCENEID_PREVDECISION = -1;
9
  SCENEID_ENDGAME      = 32767;
10
 
11
type
12
  PCoord = ^TCoord;
13
  TCoord = packed record
14
    x: Word;
15
    y: Word;
16
  end;
17
 
18
  PActionDef = ^TActionDef;
19
  TActionDef = packed record
20
    scoreDelta: Integer;
21
    nextSceneID: SmallInt;  // will jump to the scene with the name "SC<nextSceneID>"
22
                            // 7FFF (32767) = end game
23
                            // FFFF (   -1) = go back to the last decision
24
    sceneSegment: SmallInt; // 0 = scene from beginning, 1 = decision page
25
    cHotspotTopLeft: TCoord;
26
    cHotspotBottomRight: TCoord;
27
  end;
28
 
29
  PAnsiFileName = ^TAnsiFileName;
30
  TAnsiFileName = array[0..13] of AnsiChar;
31
 
32
  PSceneDef = ^TSceneDef;
33
  TSceneDef = packed record
34
    numPics: Word;
35
    pictureIndex: Word;
36
    numActions: Word;
37
    szSceneFolder: TAnsiFileName; // Foldername *must* be "SCxx" (case sensitive) where xx stands for a 2 digit ID
38
    szDialogWav:   TAnsiFileName;
39
    szDecisionBmp: TAnsiFileName;
40
    actions: array[0..2] of TActionDef;
41
  end;
42
 
43
  PPictureDef = ^TPictureDef;
44
  TPictureDef = packed record
45
    duration: Word; // deciseconds
46
    szBitmapFile: TAnsiFileName;
47
  end;
48
 
49
  PGameBinFile = ^TGameBinFile;
50
  TGameBinFile = packed record
51
    unknown1: array[0..6] of Word;
52
    numScenes: Word;
53
    numPics: Word;
54
    unknown2: array[0..1] of Word;
55
    scenes: array[0..99] of TSceneDef;        // Scenes start at 0x0016
56
    pictures: array[0..1999] of TPictureDef;  // Pictures start at 0x2596
57
    function AddSceneAtEnd(SceneID: integer): PSceneDef;
58
    procedure DeleteScene(SceneIndex: integer);
59
    procedure SwapScene(IndexA, IndexB: integer);
60
    procedure DeletePicture(PictureIndex: integer);
61
    procedure SwapPicture(IndexA, IndexB: integer);
62
    function AddPictureBetween(Index: integer): PPictureDef;
63
  end;
64
 
65
procedure _WriteStringToFilename(x: PAnsiFileName; s: AnsiString);
66
 
67
implementation
68
 
69
uses
70
  Windows, SysUtils, Math;
71
 
72
procedure _WriteStringToFilename(x: PAnsiFileName; s: AnsiString);
73
begin
74
  ZeroMemory(x, Length(x^));
75
  StrPLCopy(x^, s, Length(x^));
76
end;
77
 
78
function TGameBinFile.AddSceneAtEnd(SceneID: integer): PSceneDef;
79
begin
80
  if Self.numScenes >= Length(Self.scenes) then raise Exception.Create('No more space for another scene');
81
  if sceneID >= Length(Self.scenes) then raise Exception.Create('SceneID is too large.');
82
  result := @Self.scenes[Self.numScenes];
83
  ZeroMemory(result, SizeOf(TSceneDef));
84
  _WriteStringToFilename(@result.szSceneFolder, AnsiString(Format('SC%.2d', [sceneID])));
85
  Inc(Self.numScenes);
86
end;
87
 
88
procedure TGameBinFile.DeleteScene(SceneIndex: integer);
89
begin
90
  if ((SceneIndex < 0) or (SceneIndex >= Length(Self.scenes))) then raise Exception.Create('Invalid scene index');
91
  If SceneIndex < Length(Self.scenes)-1 then
92
  begin
93
    CopyMemory(@Self.scenes[SceneIndex], @Self.scenes[SceneIndex+1], (Length(Self.scenes)-SceneIndex-1)*SizeOf(TSceneDef));
94
  end;
95
  ZeroMemory(@Self.scenes[Length(Self.scenes)-1], SizeOf(TSceneDef));
96
end;
97
 
98
procedure TGameBinFile.SwapScene(IndexA, IndexB: integer);
99
var
100
  bakScene: TSceneDef;
101
begin
102
  if IndexA = IndexB then exit;
103
  if ((Min(IndexA, IndexB) < 0) or (Max(IndexA, IndexB) >= Length(Self.scenes))) then raise Exception.Create('Invalid scene index');
104
  CopyMemory(@bakScene, @Self.scenes[IndexA], SizeOf(TSceneDef));
105
  CopyMemory(@Self.scenes[IndexA], @Self.scenes[IndexB], SizeOf(TSceneDef));
106
  CopyMemory(@Self.scenes[IndexB], @bakScene, SizeOf(TSceneDef));
107
end;
108
 
109
procedure TGameBinFile.DeletePicture(PictureIndex: integer);
110
var
111
  iScene: integer;
112
begin
113
  if (PictureIndex < 0) or (PictureIndex >= Length(Self.pictures)) then raise Exception.Create('Invalid picture index');
114
 
115
  for iScene := 0 to Self.numScenes-1 do
116
  begin
117
    if (PictureIndex >= Self.scenes[iScene].pictureIndex) and
118
       (PictureIndex <= Self.scenes[iScene].pictureIndex + Self.scenes[iScene].numPics - 1) then
119
    begin
120
      Dec(Self.scenes[iScene].numPics);
121
    end
122
    else if (PictureIndex < Self.scenes[iScene].pictureIndex) then
123
    begin
124
      Dec(Self.scenes[iScene].pictureIndex);
125
    end;
126
  end;
127
 
128
  If PictureIndex < Length(Self.pictures)-1 then
129
  begin
130
    CopyMemory(@Self.pictures[PictureIndex], @Self.pictures[PictureIndex+1], (Length(Self.pictures)-PictureIndex-1)*SizeOf(TPictureDef));
131
  end;
132
  ZeroMemory(@Self.pictures[Length(Self.pictures)-1], SizeOf(TPictureDef));
133
end;
134
 
135
procedure TGameBinFile.SwapPicture(IndexA, IndexB: integer);
136
var
137
  bakPicture: TPictureDef;
138
begin
139
  // QUE: should we forbid that a picture between "scene borders" are swapped?
140
 
141
  if IndexA = IndexB then exit;
142
  if ((Min(IndexA, IndexB) < 0) or (Max(IndexA, IndexB) >= Length(Self.pictures))) then raise Exception.Create('Invalid picture index');
143
 
144
  CopyMemory(@bakPicture, @Self.pictures[IndexA], SizeOf(TPictureDef));
145
  CopyMemory(@Self.pictures[IndexA], @Self.pictures[IndexB], SizeOf(TPictureDef));
146
  CopyMemory(@Self.pictures[IndexB], @bakPicture, SizeOf(TPictureDef));
147
end;
148
 
149
function TGameBinFile.AddPictureBetween(Index: integer): PPictureDef;
150
var
151
  iScene: integer;
152
begin
153
  if Self.numPics >= Length(Self.pictures) then raise Exception.Create('No more space for another picture');
154
  if ((Index < 0) or (Index >= Length(Self.pictures))) then raise Exception.Create('Invalid picture index');
155
 
156
  for iScene := 0 to Self.numScenes-1 do
157
  begin
158
    if (Index >= Self.scenes[iScene].pictureIndex) and
159
       (index <= Self.scenes[iScene].pictureIndex + Max(0,Self.scenes[iScene].numPics - 1)) then
160
    begin
161
      Inc(Self.scenes[iScene].numPics);
162
    end
163
    else if (index < Self.scenes[iScene].pictureIndex) then
164
    begin
165
      Inc(Self.scenes[iScene].pictureIndex);
166
    end;
167
  end;
168
 
169
  result := @Self.pictures[Index];
170
  CopyMemory(@Self.pictures[Index+1], result, (Length(Self.pictures)-Index-1)*SizeOf(TPictureDef));
171
  ZeroMemory(result, SizeOf(TPictureDef));
172
end;
173
 
174
end.