Rev 2 | Rev 11 | 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 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 |
||
10 | daniel-mar | 57 | |
2 | daniel-mar | 58 | function AddSceneAtEnd(SceneID: integer): PSceneDef; |
59 | procedure DeleteScene(SceneIndex: integer); |
||
60 | procedure SwapScene(IndexA, IndexB: integer); |
||
61 | procedure DeletePicture(PictureIndex: integer); |
||
62 | procedure SwapPicture(IndexA, IndexB: integer); |
||
10 | daniel-mar | 63 | function AddPictureBetween(Index: integer; assignToUpperScene: boolean=true): PPictureDef; |
64 | function RealPictureCount: integer; |
||
65 | function RealActionCount: integer; |
||
2 | daniel-mar | 66 | end; |
67 | |||
68 | procedure _WriteStringToFilename(x: PAnsiFileName; s: AnsiString); |
||
69 | |||
70 | implementation |
||
71 | |||
72 | uses |
||
73 | Windows, SysUtils, Math; |
||
74 | |||
75 | procedure _WriteStringToFilename(x: PAnsiFileName; s: AnsiString); |
||
76 | begin |
||
77 | ZeroMemory(x, Length(x^)); |
||
78 | StrPLCopy(x^, s, Length(x^)); |
||
79 | end; |
||
80 | |||
81 | function TGameBinFile.AddSceneAtEnd(SceneID: integer): PSceneDef; |
||
82 | begin |
||
83 | if Self.numScenes >= Length(Self.scenes) then raise Exception.Create('No more space for another scene'); |
||
84 | if sceneID >= Length(Self.scenes) then raise Exception.Create('SceneID is too large.'); |
||
85 | result := @Self.scenes[Self.numScenes]; |
||
86 | ZeroMemory(result, SizeOf(TSceneDef)); |
||
87 | _WriteStringToFilename(@result.szSceneFolder, AnsiString(Format('SC%.2d', [sceneID]))); |
||
88 | Inc(Self.numScenes); |
||
89 | end; |
||
90 | |||
91 | procedure TGameBinFile.DeleteScene(SceneIndex: integer); |
||
92 | begin |
||
93 | if ((SceneIndex < 0) or (SceneIndex >= Length(Self.scenes))) then raise Exception.Create('Invalid scene index'); |
||
94 | If SceneIndex < Length(Self.scenes)-1 then |
||
95 | begin |
||
96 | CopyMemory(@Self.scenes[SceneIndex], @Self.scenes[SceneIndex+1], (Length(Self.scenes)-SceneIndex-1)*SizeOf(TSceneDef)); |
||
97 | end; |
||
98 | ZeroMemory(@Self.scenes[Length(Self.scenes)-1], SizeOf(TSceneDef)); |
||
10 | daniel-mar | 99 | Dec(Self.numScenes); |
2 | daniel-mar | 100 | end; |
101 | |||
10 | daniel-mar | 102 | function TGameBinFile.RealActionCount: integer; |
103 | var |
||
104 | iScene: integer; |
||
105 | begin |
||
106 | result := 0; |
||
107 | for iScene := 0 to Self.numScenes - 1 do |
||
108 | begin |
||
109 | result := result + Self.scenes[iScene].numActions; |
||
110 | end; |
||
111 | end; |
||
112 | |||
113 | function TGameBinFile.RealPictureCount: integer; |
||
114 | var |
||
115 | iScene: integer; |
||
116 | begin |
||
117 | result := 0; |
||
118 | for iScene := 0 to Self.numScenes - 1 do |
||
119 | begin |
||
120 | result := result + Self.scenes[iScene].numPics; |
||
121 | end; |
||
122 | end; |
||
123 | |||
2 | daniel-mar | 124 | procedure TGameBinFile.SwapScene(IndexA, IndexB: integer); |
125 | var |
||
126 | bakScene: TSceneDef; |
||
127 | begin |
||
128 | if IndexA = IndexB then exit; |
||
129 | if ((Min(IndexA, IndexB) < 0) or (Max(IndexA, IndexB) >= Length(Self.scenes))) then raise Exception.Create('Invalid scene index'); |
||
130 | CopyMemory(@bakScene, @Self.scenes[IndexA], SizeOf(TSceneDef)); |
||
131 | CopyMemory(@Self.scenes[IndexA], @Self.scenes[IndexB], SizeOf(TSceneDef)); |
||
132 | CopyMemory(@Self.scenes[IndexB], @bakScene, SizeOf(TSceneDef)); |
||
133 | end; |
||
134 | |||
135 | procedure TGameBinFile.DeletePicture(PictureIndex: integer); |
||
136 | var |
||
10 | daniel-mar | 137 | iScene, iScene2: integer; |
138 | protection: integer; // prevents that two scenes get the same picture index when all pictures in a scene are deleted |
||
2 | daniel-mar | 139 | begin |
140 | if (PictureIndex < 0) or (PictureIndex >= Length(Self.pictures)) then raise Exception.Create('Invalid picture index'); |
||
141 | |||
10 | daniel-mar | 142 | protection := 0; |
2 | daniel-mar | 143 | for iScene := 0 to Self.numScenes-1 do |
144 | begin |
||
145 | if (PictureIndex >= Self.scenes[iScene].pictureIndex) and |
||
146 | (PictureIndex <= Self.scenes[iScene].pictureIndex + Self.scenes[iScene].numPics - 1) then |
||
147 | begin |
||
148 | Dec(Self.scenes[iScene].numPics); |
||
10 | daniel-mar | 149 | if Self.scenes[iScene].numPics = 0 then |
150 | begin |
||
151 | for iScene2 := 0 to Self.numScenes-1 do |
||
152 | begin |
||
153 | if Self.scenes[iScene2].pictureIndex = PictureIndex+1 then |
||
154 | begin |
||
155 | protection := 1; |
||
156 | break; |
||
157 | end; |
||
158 | end; |
||
159 | end; |
||
2 | daniel-mar | 160 | end |
10 | daniel-mar | 161 | else if (PictureIndex+protection < Self.scenes[iScene].pictureIndex) then |
2 | daniel-mar | 162 | begin |
163 | Dec(Self.scenes[iScene].pictureIndex); |
||
164 | end; |
||
165 | end; |
||
166 | |||
10 | daniel-mar | 167 | If (PictureIndex+protection < Length(Self.pictures)-1) and (protection = 0) then |
2 | daniel-mar | 168 | begin |
10 | daniel-mar | 169 | CopyMemory(@Self.pictures[PictureIndex+protection], @Self.pictures[PictureIndex+protection+1], (Length(Self.pictures)-PictureIndex+protection-1)*SizeOf(TPictureDef)); |
2 | daniel-mar | 170 | end; |
171 | ZeroMemory(@Self.pictures[Length(Self.pictures)-1], SizeOf(TPictureDef)); |
||
10 | daniel-mar | 172 | |
173 | Dec(Self.numPics); |
||
2 | daniel-mar | 174 | end; |
175 | |||
176 | procedure TGameBinFile.SwapPicture(IndexA, IndexB: integer); |
||
177 | var |
||
178 | bakPicture: TPictureDef; |
||
179 | begin |
||
180 | // QUE: should we forbid that a picture between "scene borders" are swapped? |
||
181 | |||
182 | if IndexA = IndexB then exit; |
||
183 | if ((Min(IndexA, IndexB) < 0) or (Max(IndexA, IndexB) >= Length(Self.pictures))) then raise Exception.Create('Invalid picture index'); |
||
184 | |||
185 | CopyMemory(@bakPicture, @Self.pictures[IndexA], SizeOf(TPictureDef)); |
||
186 | CopyMemory(@Self.pictures[IndexA], @Self.pictures[IndexB], SizeOf(TPictureDef)); |
||
187 | CopyMemory(@Self.pictures[IndexB], @bakPicture, SizeOf(TPictureDef)); |
||
188 | end; |
||
189 | |||
10 | daniel-mar | 190 | function TGameBinFile.AddPictureBetween(Index: integer; assignToUpperScene: boolean=true): PPictureDef; |
191 | |||
192 | function _HasBuffer(Index: integer): boolean; |
||
193 | var |
||
194 | iScene: integer; |
||
195 | begin |
||
196 | for iScene := 0 to Self.numScenes-1 do |
||
197 | begin |
||
198 | if Self.scenes[iScene].pictureIndex = Index+1 then |
||
199 | begin |
||
200 | result := true; |
||
201 | exit; |
||
202 | end; |
||
203 | end; |
||
204 | result := false; |
||
205 | end; |
||
206 | |||
2 | daniel-mar | 207 | var |
208 | iScene: integer; |
||
209 | begin |
||
210 | if Self.numPics >= Length(Self.pictures) then raise Exception.Create('No more space for another picture'); |
||
211 | if ((Index < 0) or (Index >= Length(Self.pictures))) then raise Exception.Create('Invalid picture index'); |
||
212 | |||
10 | daniel-mar | 213 | if assignToUpperScene then |
2 | daniel-mar | 214 | begin |
10 | daniel-mar | 215 | // Sc1 Sc2 Sc1 Sc2 |
216 | // A B | C ==> A B | X C |
||
217 | // ^ |
||
218 | for iScene := 0 to Self.numScenes-1 do |
||
2 | daniel-mar | 219 | begin |
10 | daniel-mar | 220 | if (Index >= Self.scenes[iScene].pictureIndex) and |
221 | (index <= Self.scenes[iScene].pictureIndex + Max(0,Self.scenes[iScene].numPics - 1)) then |
||
222 | begin |
||
223 | Inc(Self.scenes[iScene].numPics); |
||
224 | end |
||
225 | else if (index < Self.scenes[iScene].pictureIndex) and not _HasBuffer(index) then |
||
226 | begin |
||
227 | Inc(Self.scenes[iScene].pictureIndex); |
||
228 | end; |
||
229 | end; |
||
230 | end |
||
231 | else |
||
232 | begin |
||
233 | // Sc1 Sc2 Sc1 Sc2 |
||
234 | // A B | C ==> A B X | C |
||
235 | // ^ |
||
236 | for iScene := 0 to Self.numScenes-1 do |
||
2 | daniel-mar | 237 | begin |
10 | daniel-mar | 238 | if (Index >= 1 + Self.scenes[iScene].pictureIndex) and |
239 | (index <= 1 + Self.scenes[iScene].pictureIndex + Max(0,Self.scenes[iScene].numPics-1)) then |
||
240 | begin |
||
241 | Inc(Self.scenes[iScene].numPics); |
||
242 | end |
||
243 | else if (index <= Self.scenes[iScene].pictureIndex) and not _HasBuffer(index) then |
||
244 | begin |
||
245 | Inc(Self.scenes[iScene].pictureIndex); |
||
246 | end; |
||
2 | daniel-mar | 247 | end; |
248 | end; |
||
249 | |||
250 | result := @Self.pictures[Index]; |
||
10 | daniel-mar | 251 | if not _HasBuffer(index) then |
252 | begin |
||
253 | CopyMemory(@Self.pictures[Index+1], result, (Length(Self.pictures)-Index-1)*SizeOf(TPictureDef)); |
||
254 | end; |
||
255 | |||
2 | daniel-mar | 256 | ZeroMemory(result, SizeOf(TPictureDef)); |
10 | daniel-mar | 257 | |
258 | Inc(Self.numPics); |
||
2 | daniel-mar | 259 | end; |
260 | |||
261 | end. |