Rev 66 | Rev 79 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 66 | Rev 72 | ||
---|---|---|---|
1 | unit ComLevelReader; |
1 | unit ComLevelReader; |
2 | 2 | ||
3 | interface |
3 | interface |
4 | 4 | ||
5 | uses |
5 | uses |
6 | Classes; |
6 | Classes; |
7 | 7 | ||
8 | const |
- | |
9 | NumEnemyTypes = 7; |
- | |
10 | - | ||
11 | type |
8 | type |
- | 9 | // If you add a new enemy or item, please edit |
|
- | 10 | // - ComLevelReader.pas : EnemyTypeHasLives() |
|
- | 11 | // - GamMain.pas : TMainForm.SceneMain |
|
- | 12 | // - LevMain.pas : * GUI |
|
- | 13 | // * TMainForm.SelectedEnemyType |
|
- | 14 | // * TEnemy.Create |
|
- | 15 | // * TMainForm.DXDrawMouseMove |
|
- | 16 | // * TMainForm.DXDrawMouseDown |
|
12 | TEnemyType = ( |
17 | TEnemyType = ( |
13 | etUnknown, |
18 | etUnknown, |
14 | etEnemyAttacker, |
19 | etEnemyAttacker, |
15 | etEnemyAttacker2, |
20 | etEnemyAttacker2, |
16 | etEnemyAttacker3, |
21 | etEnemyAttacker3, |
17 | etEnemyMeteor, |
22 | etEnemyMeteor, |
18 | etEnemyUFO, |
23 | etEnemyUFO, |
19 | etEnemyUFO2, |
24 | etEnemyUFO2, |
20 | etEnemyBoss |
25 | etEnemyBoss, |
- | 26 | etItemMedikit |
|
21 | ); |
27 | ); |
22 | 28 | ||
23 | TEnemyAdvent = record |
29 | TEnemyAdvent = record |
24 | enemyType: TEnemyType; |
30 | enemyType: TEnemyType; |
25 | x: integer; |
31 | x: integer; |
26 | y: integer; |
32 | y: integer; |
27 | lifes: integer; |
33 | lifes: integer; |
28 | end; |
34 | end; |
29 | 35 | ||
30 | TLevelData = class(TPersistent) |
36 | TLevelData = class(TPersistent) |
31 | strict private |
37 | strict private |
32 | procedure SortEnemies; |
38 | procedure SortEnemies; |
33 | strict protected |
39 | strict protected |
34 | procedure AssignTo(Dest: TPersistent); override; |
40 | procedure AssignTo(Dest: TPersistent); override; |
35 | public |
41 | public |
36 | RasterErzwingen: boolean; |
42 | RasterErzwingen: boolean; |
37 | LevelEditorLength: integer; |
43 | LevelEditorLength: integer; |
38 | LevelName: string; |
44 | LevelName: string; |
39 | LevelAuthor: string; |
45 | LevelAuthor: string; |
40 | EnemyAdventTable: array of TEnemyAdvent; |
46 | EnemyAdventTable: array of TEnemyAdvent; |
41 | function IndexOfEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer): integer; |
47 | function IndexOfEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer): integer; |
42 | procedure AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); |
48 | procedure AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); |
43 | procedure DeleteEnemy(i: integer); overload; |
49 | procedure DeleteEnemy(i: integer); overload; |
44 | procedure DeleteEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); overload; |
50 | procedure DeleteEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); overload; |
45 | function CountEnemies: integer; |
51 | function CountEnemies: integer; |
46 | function HasBoss: boolean; |
52 | function HasBoss: boolean; |
47 | procedure Clear; |
53 | procedure Clear; |
48 | procedure LoadFromStrings(sl: TStrings); // version 0.3 - version 1.2 files |
54 | procedure LoadFromStrings(sl: TStrings); // version 0.3 - version 1.2 files |
49 | procedure LoadFromFile(filename: string); // version 0.2 - version 1.2 files |
55 | procedure LoadFromFile(filename: string); // version 0.2 - version 1.2 files |
50 | procedure SaveToStrings(sl: TStrings); |
56 | procedure SaveToStrings(sl: TStrings); |
51 | procedure SaveToFile(filename: string); |
57 | procedure SaveToFile(filename: string); |
52 | destructor Destroy; override; |
58 | destructor Destroy; override; |
53 | end; |
59 | end; |
54 | 60 | ||
55 | TGameMode = (gmUnknown, gmLevels, gmRandom, gmEditor); |
61 | TGameMode = (gmUnknown, gmLevels, gmRandom, gmEditor); |
56 | 62 | ||
57 | TSaveData = class(TPersistent) |
63 | TSaveData = class(TPersistent) |
58 | strict protected |
64 | strict protected |
59 | procedure AssignTo(Dest: TPersistent); override; |
65 | procedure AssignTo(Dest: TPersistent); override; |
60 | public |
66 | public |
61 | Score: integer; |
67 | Score: integer; |
62 | Life: integer; |
68 | Life: integer; |
63 | Level: integer; |
69 | Level: integer; |
64 | GameMode: TGameMode; |
70 | GameMode: TGameMode; |
65 | LevelData: TLevelData; |
71 | LevelData: TLevelData; |
66 | procedure Clear; |
72 | procedure Clear; |
67 | procedure LoadFromStrings(sl: TStrings); |
73 | procedure LoadFromStrings(sl: TStrings); |
68 | procedure LoadFromFile(filename: string); |
74 | procedure LoadFromFile(filename: string); |
69 | procedure SaveToStrings(sl: TStrings); |
75 | procedure SaveToStrings(sl: TStrings); |
70 | procedure SaveToFile(filename: string); |
76 | procedure SaveToFile(filename: string); |
71 | destructor Destroy; override; |
77 | destructor Destroy; override; |
72 | end; |
78 | end; |
73 | 79 | ||
74 | TLevelFile = record |
80 | TLevelFile = record |
75 | levelNumber: integer; |
81 | levelNumber: integer; |
76 | fileLocation: string; |
82 | fileLocation: string; |
77 | isUser: boolean; |
83 | isUser: boolean; |
78 | found: boolean; |
84 | found: boolean; |
79 | end; |
85 | end; |
80 | 86 | ||
81 | function GetLevelFileName(lev: integer; forceuserdir: boolean): TLevelFile; |
87 | function GetLevelFileName(lev: integer; forceuserdir: boolean): TLevelFile; |
82 | 88 | ||
- | 89 | function EnemyTypeHasLives(et: TEnemyType): boolean; |
|
- | 90 | ||
83 | implementation |
91 | implementation |
84 | 92 | ||
85 | uses |
93 | uses |
86 | SysUtils, StrUtils, Global, Windows, System.Types; |
94 | SysUtils, StrUtils, Global, Windows, System.Types; |
87 | 95 | ||
88 | const |
96 | const |
89 | // { iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) spacemission(8) file-format(1) lev-sav-v12(1) } |
97 | // { iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) spacemission(8) file-format(1) lev-sav-v12(1) } |
90 | // https://hosted.oidplus.com/viathinksoft/?goto=oid%3A1.3.6.1.4.1.37476.2.8.1.1 |
98 | // https://hosted.oidplus.com/viathinksoft/?goto=oid%3A1.3.6.1.4.1.37476.2.8.1.1 |
91 | OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1'; |
99 | OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1'; |
92 | 100 | ||
93 | function GetLevelFileName(lev: integer; forceuserdir: boolean): TLevelFile; |
101 | function GetLevelFileName(lev: integer; forceuserdir: boolean): TLevelFile; |
94 | 102 | ||
95 | function _GetLevelVerzeichnisSystem: string; |
103 | function _GetLevelVerzeichnisSystem: string; |
96 | begin |
104 | begin |
97 | // Für die Auslieferungs-Levels |
105 | // Für die Auslieferungs-Levels |
98 | result := OwnDirectory + 'Levels'; |
106 | result := OwnDirectory + 'Levels'; |
99 | end; |
107 | end; |
100 | 108 | ||
101 | function _GetLevelVerzeichnisUser: string; |
109 | function _GetLevelVerzeichnisUser: string; |
102 | begin |
110 | begin |
103 | try |
111 | try |
104 | result := GetKnownFolderPath(FOLDERID_SavedGames); |
112 | result := GetKnownFolderPath(FOLDERID_SavedGames); |
105 | except |
113 | except |
106 | result := ''; |
114 | result := ''; |
107 | end; |
115 | end; |
108 | if result = '' then |
116 | if result = '' then |
109 | begin |
117 | begin |
110 | // Pre Vista |
118 | // Pre Vista |
111 | result := OwnDirectory + 'Levels'; |
119 | result := OwnDirectory + 'Levels'; |
112 | end |
120 | end |
113 | else |
121 | else |
114 | begin |
122 | begin |
115 | result := IncludeTrailingPathDelimiter(result); |
123 | result := IncludeTrailingPathDelimiter(result); |
116 | result := result + 'SpaceMission'; |
124 | result := result + 'SpaceMission'; |
117 | end; |
125 | end; |
118 | result := IncludeTrailingPathDelimiter(result); |
126 | result := IncludeTrailingPathDelimiter(result); |
119 | ForceDirectories(result); |
127 | ForceDirectories(result); |
120 | end; |
128 | end; |
121 | 129 | ||
122 | function _GetLevelFileNameUser(lev: integer): string; |
130 | function _GetLevelFileNameUser(lev: integer): string; |
123 | var |
131 | var |
124 | old, new: string; |
132 | old, new: string; |
125 | begin |
133 | begin |
126 | new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files |
134 | new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files |
127 | old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files |
135 | old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files |
128 | if fileexists(new) then exit(new); |
136 | if fileexists(new) then exit(new); |
129 | if fileexists(old) then exit(old); |
137 | if fileexists(old) then exit(old); |
130 | exit(new); |
138 | exit(new); |
131 | end; |
139 | end; |
132 | 140 | ||
133 | function _GetLevelFileNameSystem(lev: integer): string; |
141 | function _GetLevelFileNameSystem(lev: integer): string; |
134 | var |
142 | var |
135 | old, new: string; |
143 | old, new: string; |
136 | begin |
144 | begin |
137 | new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files |
145 | new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files |
138 | old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files |
146 | old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files |
139 | if fileexists(new) then exit(new); |
147 | if fileexists(new) then exit(new); |
140 | if fileexists(old) then exit(old); |
148 | if fileexists(old) then exit(old); |
141 | exit(new); |
149 | exit(new); |
142 | end; |
150 | end; |
143 | 151 | ||
144 | var |
152 | var |
145 | usr, sys: string; |
153 | usr, sys: string; |
146 | bfound: boolean; |
154 | bfound: boolean; |
147 | begin |
155 | begin |
148 | result.levelNumber := lev; |
156 | result.levelNumber := lev; |
149 | usr := _GetLevelFileNameUser(lev); |
157 | usr := _GetLevelFileNameUser(lev); |
150 | sys := _GetLevelFileNameSystem(lev); |
158 | sys := _GetLevelFileNameSystem(lev); |
151 | bfound := fileexists(usr); |
159 | bfound := fileexists(usr); |
152 | if bfound or forceuserdir then |
160 | if bfound or forceuserdir then |
153 | begin |
161 | begin |
154 | result.isUser := true; |
162 | result.isUser := true; |
155 | result.fileLocation := usr; |
163 | result.fileLocation := usr; |
156 | result.found := bfound; |
164 | result.found := bfound; |
157 | exit; |
165 | exit; |
158 | end; |
166 | end; |
159 | bfound := fileexists(sys); |
167 | bfound := fileexists(sys); |
160 | if bfound then |
168 | if bfound then |
161 | begin |
169 | begin |
162 | result.isUser := false; |
170 | result.isUser := false; |
163 | result.fileLocation := sys; |
171 | result.fileLocation := sys; |
164 | result.found := bfound; |
172 | result.found := bfound; |
165 | exit; |
173 | exit; |
166 | end; |
174 | end; |
167 | result.isUser := true; |
175 | result.isUser := true; |
168 | result.fileLocation := usr; |
176 | result.fileLocation := usr; |
169 | result.found := false; |
177 | result.found := false; |
170 | end; |
178 | end; |
171 | 179 | ||
172 | // this is just an example, there are many |
180 | // this is just an example, there are many |
173 | // different ways you can implement this |
181 | // different ways you can implement this |
174 | // more efficiently, ie using a TStringBuilder, |
182 | // more efficiently, ie using a TStringBuilder, |
175 | // or even modifying the String in-place... |
183 | // or even modifying the String in-place... |
176 | function CollapseSpaces(const S: string): string; |
184 | function CollapseSpaces(const S: string): string; |
177 | var |
185 | var |
178 | P: PChar; |
186 | P: PChar; |
179 | AddSpace: Boolean; |
187 | AddSpace: Boolean; |
180 | begin |
188 | begin |
181 | Result := ''; |
189 | Result := ''; |
182 | AddSpace := False; |
190 | AddSpace := False; |
183 | P := PChar(S); |
191 | P := PChar(S); |
184 | while P^ <> #0 do |
192 | while P^ <> #0 do |
185 | begin |
193 | begin |
186 | while CharInSet(P^, [#1..' ']) do Inc(P); |
194 | while CharInSet(P^, [#1..' ']) do Inc(P); |
187 | if P^ = #0 then Exit; |
195 | if P^ = #0 then Exit; |
188 | if AddSpace then |
196 | if AddSpace then |
189 | Result := Result + ' ' |
197 | Result := Result + ' ' |
190 | else |
198 | else |
191 | AddSpace := True; |
199 | AddSpace := True; |
192 | repeat |
200 | repeat |
193 | Result := Result + P^; |
201 | Result := Result + P^; |
194 | Inc(P); |
202 | Inc(P); |
195 | until P^ <= ' '; |
203 | until P^ <= ' '; |
196 | end; |
204 | end; |
197 | end; |
205 | end; |
198 | 206 | ||
199 | { TLevelData } |
207 | { TLevelData } |
200 | 208 | ||
201 | procedure TLevelData.AssignTo(Dest: TPersistent); |
209 | procedure TLevelData.AssignTo(Dest: TPersistent); |
202 | var |
210 | var |
203 | DestLevelData: TLevelData; |
211 | DestLevelData: TLevelData; |
204 | i: integer; |
212 | i: integer; |
205 | begin |
213 | begin |
206 | DestLevelData := Dest as TLevelData; |
214 | DestLevelData := Dest as TLevelData; |
207 | if Assigned(DestLevelData) then |
215 | if Assigned(DestLevelData) then |
208 | begin |
216 | begin |
209 | DestLevelData.RasterErzwingen := Self.RasterErzwingen; |
217 | DestLevelData.RasterErzwingen := Self.RasterErzwingen; |
210 | DestLevelData.LevelEditorLength := Self.LevelEditorLength; |
218 | DestLevelData.LevelEditorLength := Self.LevelEditorLength; |
211 | DestLevelData.LevelName := Self.LevelName; |
219 | DestLevelData.LevelName := Self.LevelName; |
212 | DestLevelData.LevelAuthor := Self.LevelAuthor; |
220 | DestLevelData.LevelAuthor := Self.LevelAuthor; |
213 | SetLength(DestLevelData.EnemyAdventTable, Length(Self.EnemyAdventTable)); |
221 | SetLength(DestLevelData.EnemyAdventTable, Length(Self.EnemyAdventTable)); |
214 | for i := 0 to Length(Self.EnemyAdventTable)-1 do |
222 | for i := 0 to Length(Self.EnemyAdventTable)-1 do |
215 | begin |
223 | begin |
216 | DestLevelData.EnemyAdventTable[i] := Self.EnemyAdventTable[i]; |
224 | DestLevelData.EnemyAdventTable[i] := Self.EnemyAdventTable[i]; |
217 | end; |
225 | end; |
218 | end |
226 | end |
219 | else |
227 | else |
220 | begin |
228 | begin |
221 | inherited; |
229 | inherited; |
222 | end; |
230 | end; |
223 | end; |
231 | end; |
224 | 232 | ||
225 | procedure TLevelData.Clear; |
233 | procedure TLevelData.Clear; |
226 | begin |
234 | begin |
227 | SetLength(EnemyAdventTable, 0); |
235 | SetLength(EnemyAdventTable, 0); |
228 | LevelEditorLength := DefaultLevelLength; |
236 | LevelEditorLength := DefaultLevelLength; |
229 | LevelName := ''; |
237 | LevelName := ''; |
230 | LevelAuthor := ''; |
238 | LevelAuthor := ''; |
231 | end; |
239 | end; |
232 | 240 | ||
233 | function TLevelData.CountEnemies: integer; |
241 | function TLevelData.CountEnemies: integer; |
234 | begin |
242 | begin |
235 | result := Length(EnemyAdventTable); |
243 | result := Length(EnemyAdventTable); |
236 | end; |
244 | end; |
237 | 245 | ||
238 | procedure TLevelData.DeleteEnemy(i: integer); |
246 | procedure TLevelData.DeleteEnemy(i: integer); |
239 | var |
247 | var |
240 | j: integer; |
248 | j: integer; |
241 | begin |
249 | begin |
242 | for j := i+1 to CountEnemies-1 do |
250 | for j := i+1 to CountEnemies-1 do |
243 | begin |
251 | begin |
244 | EnemyAdventTable[j-1] := EnemyAdventTable[j]; |
252 | EnemyAdventTable[j-1] := EnemyAdventTable[j]; |
245 | end; |
253 | end; |
246 | SetLength(EnemyAdventTable, Length(EnemyAdventTable)-1); |
254 | SetLength(EnemyAdventTable, Length(EnemyAdventTable)-1); |
247 | end; |
255 | end; |
248 | 256 | ||
249 | procedure TLevelData.DeleteEnemy(x, y: integer; enemyType: TEnemyType; |
257 | procedure TLevelData.DeleteEnemy(x, y: integer; enemyType: TEnemyType; |
250 | lifes: integer); |
258 | lifes: integer); |
251 | begin |
259 | begin |
252 | DeleteEnemy(IndexOfEnemy(x, y, enemyType, lifes)); |
260 | DeleteEnemy(IndexOfEnemy(x, y, enemyType, lifes)); |
253 | end; |
261 | end; |
254 | 262 | ||
255 | destructor TLevelData.Destroy; |
263 | destructor TLevelData.Destroy; |
256 | begin |
264 | begin |
257 | Clear; |
265 | Clear; |
258 | inherited; |
266 | inherited; |
259 | end; |
267 | end; |
260 | 268 | ||
261 | function TLevelData.HasBoss: boolean; |
269 | function TLevelData.HasBoss: boolean; |
262 | var |
270 | var |
263 | i: integer; |
271 | i: integer; |
264 | begin |
272 | begin |
265 | for i := 0 to Length(EnemyAdventTable) - 1 do |
273 | for i := 0 to Length(EnemyAdventTable) - 1 do |
266 | begin |
274 | begin |
267 | if EnemyAdventTable[i].enemyType = etEnemyBoss then |
275 | if EnemyAdventTable[i].enemyType = etEnemyBoss then |
268 | begin |
276 | begin |
269 | result := true; |
277 | result := true; |
270 | exit; |
278 | exit; |
271 | end; |
279 | end; |
272 | end; |
280 | end; |
273 | result := false; |
281 | result := false; |
274 | end; |
282 | end; |
275 | 283 | ||
276 | procedure TLevelData.AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); |
284 | procedure TLevelData.AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); |
277 | begin |
285 | begin |
278 | SetLength(EnemyAdventTable, Length(EnemyAdventTable)+1); |
286 | SetLength(EnemyAdventTable, Length(EnemyAdventTable)+1); |
279 | 287 | ||
280 | if enemyType = etEnemyMeteor then lifes := 0; |
288 | if enemyType = etEnemyMeteor then lifes := 0; |
281 | if RasterErzwingen then |
289 | if RasterErzwingen then |
282 | begin |
290 | begin |
283 | if x mod RasterW <> 0 then raise Exception.CreateFmt('X-Koordinate muss ohne Rest durch %d teilbar sein', [RasterW]); |
291 | if x mod RasterW <> 0 then raise Exception.CreateFmt('X-Koordinate muss ohne Rest durch %d teilbar sein', [RasterW]); |
284 | if y mod RasterH <> 0 then raise Exception.CreateFmt('Y-Koordinate muss ohne Rest durch %d teilbar sein', [RasterH]); |
292 | if y mod RasterH <> 0 then raise Exception.CreateFmt('Y-Koordinate muss ohne Rest durch %d teilbar sein', [RasterH]); |
285 | end; |
293 | end; |
286 | if lifes > MaxPossibleEnemyLives then lifes := MaxPossibleEnemyLives; |
294 | if lifes > MaxPossibleEnemyLives then lifes := MaxPossibleEnemyLives; |
287 | 295 | ||
288 | EnemyAdventTable[Length(EnemyAdventTable)-1].x := x; |
296 | EnemyAdventTable[Length(EnemyAdventTable)-1].x := x; |
289 | EnemyAdventTable[Length(EnemyAdventTable)-1].y := y; |
297 | EnemyAdventTable[Length(EnemyAdventTable)-1].y := y; |
290 | EnemyAdventTable[Length(EnemyAdventTable)-1].enemyType := enemyType; |
298 | EnemyAdventTable[Length(EnemyAdventTable)-1].enemyType := enemyType; |
291 | EnemyAdventTable[Length(EnemyAdventTable)-1].lifes := lifes; |
299 | EnemyAdventTable[Length(EnemyAdventTable)-1].lifes := lifes; |
292 | end; |
300 | end; |
293 | 301 | ||
294 | function TLevelData.IndexOfEnemy(x, y: integer; enemyType: TEnemyType; |
302 | function TLevelData.IndexOfEnemy(x, y: integer; enemyType: TEnemyType; |
295 | lifes: integer): integer; |
303 | lifes: integer): integer; |
296 | var |
304 | var |
297 | i: integer; |
305 | i: integer; |
298 | begin |
306 | begin |
299 | for i := 0 to Length(EnemyAdventTable) - 1 do |
307 | for i := 0 to Length(EnemyAdventTable) - 1 do |
300 | begin |
308 | begin |
301 | if (EnemyAdventTable[i].x = x) and |
309 | if (EnemyAdventTable[i].x = x) and |
302 | (EnemyAdventTable[i].y = y) and |
310 | (EnemyAdventTable[i].y = y) and |
303 | (EnemyAdventTable[i].enemyType = enemyType) and |
311 | (EnemyAdventTable[i].enemyType = enemyType) and |
304 | (EnemyAdventTable[i].lifes = lifes) then |
312 | (EnemyAdventTable[i].lifes = lifes) then |
305 | begin |
313 | begin |
306 | result := i; |
314 | result := i; |
307 | exit; |
315 | exit; |
308 | end; |
316 | end; |
309 | end; |
317 | end; |
310 | result := -1; |
318 | result := -1; |
311 | end; |
319 | end; |
312 | 320 | ||
313 | procedure TLevelData.LoadFromStrings(sl: TStrings); |
321 | procedure TLevelData.LoadFromStrings(sl: TStrings); |
314 | var |
322 | var |
315 | curline: integer; |
323 | curline: integer; |
316 | z, act: integer; |
324 | z, act: integer; |
317 | sl2: TStringList; |
325 | sl2: TStringList; |
318 | tmpX, tmpY, tmpLifes: integer; |
326 | tmpX, tmpY, tmpLifes: integer; |
319 | tmpEnemy: TEnemyType; |
327 | tmpEnemy: TEnemyType; |
320 | ergebnis: string; |
328 | ergebnis: string; |
321 | ary: TStringDynArray; |
329 | ary: TStringDynArray; |
322 | sLine: string; |
330 | sLine: string; |
323 | begin |
331 | begin |
324 | Clear; |
332 | Clear; |
325 | 333 | ||
326 | LevelEditorLength := DefaultLevelLength; |
334 | LevelEditorLength := DefaultLevelLength; |
327 | LevelName := ''; |
335 | LevelName := ''; |
328 | LevelAuthor := ''; |
336 | LevelAuthor := ''; |
329 | 337 | ||
330 | if sl.Strings[0] = '; SpaceMission 0.3' then // do not localize |
338 | if sl.Strings[0] = '; SpaceMission 0.3' then // do not localize |
331 | begin |
339 | begin |
332 | {$REGION 'Backwards compatibility level format 0.3 (convert to 0.4)'} |
340 | {$REGION 'Backwards compatibility level format 0.3 (convert to 0.4)'} |
333 | sl.Strings[0] := '; SpaceMission 0.4'; // do not localize |
341 | sl.Strings[0] := '; SpaceMission 0.4'; // do not localize |
334 | sl.Insert(1, '; LEV-File'); // do not localize |
342 | sl.Insert(1, '; LEV-File'); // do not localize |
335 | {$ENDREGION} |
343 | {$ENDREGION} |
336 | end; |
344 | end; |
337 | 345 | ||
338 | if (sl.Strings[0] = '; SpaceMission 0.4') and // do not localize |
346 | if (sl.Strings[0] = '; SpaceMission 0.4') and // do not localize |
339 | (sl.Strings[1] = '; LEV-File') then // do not localize |
347 | (sl.Strings[1] = '; LEV-File') then // do not localize |
340 | begin |
348 | begin |
341 | {$REGION 'Backwards compatibility level format 0.4 (convert to 1.0)'} |
349 | {$REGION 'Backwards compatibility level format 0.4 (convert to 1.0)'} |
342 | sl2 := TStringList.Create; |
350 | sl2 := TStringList.Create; |
343 | try |
351 | try |
344 | z := 0; |
352 | z := 0; |
345 | act := 0; |
353 | act := 0; |
346 | while z < sl.Count do |
354 | while z < sl.Count do |
347 | begin |
355 | begin |
348 | inc(z); |
356 | inc(z); |
349 | if z > 2 then inc(act); |
357 | if z > 2 then inc(act); |
350 | if act = 5 then act := 1; |
358 | if act = 5 then act := 1; |
351 | ergebnis := sl.Strings[z-1]; |
359 | ergebnis := sl.Strings[z-1]; |
352 | if ergebnis = '; SpaceMission 0.4' then |
360 | if ergebnis = '; SpaceMission 0.4' then |
353 | sl2.Add('; SpaceMission 1.0') |
361 | sl2.Add('; SpaceMission 1.0') |
354 | else |
362 | else |
355 | begin |
363 | begin |
356 | if (ergebnis = '30000') and (z = 3) then |
364 | if (ergebnis = '30000') and (z = 3) then |
357 | sl2.Add(IntTostr(DefaultLevelLength)) |
365 | sl2.Add(IntTostr(DefaultLevelLength)) |
358 | else |
366 | else |
359 | begin |
367 | begin |
360 | //if not (((ergebnis = '0') and (z = 4)) or ((ergebnis = '-624') and (z = 5)) or ((ergebnis = '222') and (z = 6)) or ((ergebnis = '3') and (z = 7))) then |
368 | //if not (((ergebnis = '0') and (z = 4)) or ((ergebnis = '-624') and (z = 5)) or ((ergebnis = '222') and (z = 6)) or ((ergebnis = '3') and (z = 7))) then |
361 | if (z < 4) or (z > 7) then |
369 | if (z < 4) or (z > 7) then |
362 | begin |
370 | begin |
363 | if act = 4 then |
371 | if act = 4 then |
364 | sl2.Add(inttostr(strtoint(ergebnis) + 32 - (5 * (strtoint(ergebnis) div 37)))) |
372 | sl2.Add(inttostr(strtoint(ergebnis) + 32 - (5 * (strtoint(ergebnis) div 37)))) |
365 | else |
373 | else |
366 | sl2.Add(Ergebnis); |
374 | sl2.Add(Ergebnis); |
367 | end; |
375 | end; |
368 | end; |
376 | end; |
369 | end; |
377 | end; |
370 | end; |
378 | end; |
371 | sl.Text := sl2.Text; |
379 | sl.Text := sl2.Text; |
372 | finally |
380 | finally |
373 | FreeAndNil(sl2); |
381 | FreeAndNil(sl2); |
374 | end; |
382 | end; |
375 | {$ENDREGION} |
383 | {$ENDREGION} |
376 | end; |
384 | end; |
377 | 385 | ||
378 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
386 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
379 | (sl.Strings[1] = '; LEV-File') then // do not localize |
387 | (sl.Strings[1] = '; LEV-File') then // do not localize |
380 | begin |
388 | begin |
381 | {$REGION 'Level format 1.0'} |
389 | {$REGION 'Level format 1.0'} |
382 | LevelEditorLength := StrToInt(sl.Strings[2]); |
390 | LevelEditorLength := StrToInt(sl.Strings[2]); |
383 | curline := 3; |
391 | curline := 3; |
384 | while curline < sl.Count do |
392 | while curline < sl.Count do |
385 | begin |
393 | begin |
386 | tmpEnemy := TEnemyType(strtoint(sl.Strings[curline])); |
394 | tmpEnemy := TEnemyType(strtoint(sl.Strings[curline])); |
387 | Inc(curline); |
395 | Inc(curline); |
388 | tmpX := strtoint(sl.Strings[curline]); |
396 | tmpX := strtoint(sl.Strings[curline]); |
389 | Inc(curline); |
397 | Inc(curline); |
390 | tmpY := strtoint(sl.Strings[curline]); |
398 | tmpY := strtoint(sl.Strings[curline]); |
391 | Inc(curline); |
399 | Inc(curline); |
392 | tmpLifes := strtoint(sl.Strings[curline]); |
400 | tmpLifes := strtoint(sl.Strings[curline]); |
393 | Inc(curline); |
401 | Inc(curline); |
394 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
402 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
395 | end; |
403 | end; |
396 | {$ENDREGION} |
404 | {$ENDREGION} |
397 | end |
405 | end |
398 | else if (SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']')) then |
406 | else if (SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']')) then |
399 | begin |
407 | begin |
400 | {$REGION 'Level format 1.2'} |
408 | {$REGION 'Level format 1.2'} |
401 | for curline := 1 to sl.Count-1 do |
409 | for curline := 1 to sl.Count-1 do |
402 | begin |
410 | begin |
403 | sLine := sl.Strings[curline].Trim; |
411 | sLine := sl.Strings[curline].Trim; |
404 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
412 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
405 | ary := SplitString(CollapseSpaces(sLine), ' '); |
413 | ary := SplitString(CollapseSpaces(sLine), ' '); |
406 | if SameText(ary[0], 'Width') then // do not localize |
414 | if SameText(ary[0], 'Width') then // do not localize |
407 | begin |
415 | begin |
408 | LevelEditorLength := StrToInt(ary[1]); |
416 | LevelEditorLength := StrToInt(ary[1]); |
409 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
417 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
410 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
418 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
411 | end |
419 | end |
412 | else if SameText(ary[0], 'Name') then // do not localize |
420 | else if SameText(ary[0], 'Name') then // do not localize |
413 | begin |
421 | begin |
414 | LevelName := Trim(Copy(sLine, Length(ary[0])+2, Length(sLine))); |
422 | LevelName := Trim(Copy(sLine, Length(ary[0])+2, Length(sLine))); |
415 | end |
423 | end |
416 | else if SameText(ary[0], 'Author') then // do not localize |
424 | else if SameText(ary[0], 'Author') then // do not localize |
417 | begin |
425 | begin |
418 | LevelAuthor := Trim(Copy(sLine, Length(ary[0])+2, Length(sLine))); |
426 | LevelAuthor := Trim(Copy(sLine, Length(ary[0])+2, Length(sLine))); |
419 | end |
427 | end |
420 | else if SameText(ary[0], 'Enemy') then // do not localize |
428 | else if SameText(ary[0], 'Enemy') then // do not localize |
421 | begin |
429 | begin |
422 | tmpEnemy := TEnemyType(strtoint(ary[1])); |
430 | tmpEnemy := TEnemyType(strtoint(ary[1])); |
423 | tmpX := strtoint(ary[2]); |
431 | tmpX := strtoint(ary[2]); |
424 | tmpY := strtoint(ary[3]); |
432 | tmpY := strtoint(ary[3]); |
425 | tmpLifes := strtoint(ary[4]); |
433 | tmpLifes := strtoint(ary[4]); |
426 | if (Length(ary) > 5) and (Copy(ary[5], 1, 1) <> ';') then |
434 | if (Length(ary) > 5) and (Copy(ary[5], 1, 1) <> ';') then |
427 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
435 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
428 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
436 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
429 | end; |
437 | end; |
430 | end; |
438 | end; |
431 | {$ENDREGION} |
439 | {$ENDREGION} |
432 | end |
440 | end |
433 | else |
441 | else |
434 | begin |
442 | begin |
435 | raise Exception.Create('Level-Format nicht unterstützt oder Datei ist beschädigt'); |
443 | raise Exception.Create('Level-Format nicht unterstützt oder Datei ist beschädigt'); |
436 | end; |
444 | end; |
437 | 445 | ||
438 | SortEnemies; // Sortierung nach X-Koordinate ist sehr wichtig für das Spiel! |
446 | SortEnemies; // Sortierung nach X-Koordinate ist sehr wichtig für das Spiel! |
439 | end; |
447 | end; |
440 | 448 | ||
441 | procedure TLevelData.LoadFromFile(filename: string); |
449 | procedure TLevelData.LoadFromFile(filename: string); |
442 | var |
450 | var |
443 | sl: TStringList; |
451 | sl: TStringList; |
444 | i, j: integer; |
452 | i, j: integer; |
445 | temp: string; |
453 | temp: string; |
446 | m: array[1..6] of tstrings; |
454 | m: array[1..6] of tstrings; |
447 | begin |
455 | begin |
448 | sl := TStringList.Create; |
456 | sl := TStringList.Create; |
449 | try |
457 | try |
450 | if EndsText('A1.lev', filename) then // do not localize |
458 | if EndsText('A1.lev', filename) then // do not localize |
451 | begin |
459 | begin |
452 | {$REGION 'Backwards compatibility level format 0.2 (split into 5-6 files; convert to 0.3)'} |
460 | {$REGION 'Backwards compatibility level format 0.2 (split into 5-6 files; convert to 0.3)'} |
453 | m[1] := TStringList.create; |
461 | m[1] := TStringList.create; |
454 | m[2] := TStringList.create; |
462 | m[2] := TStringList.create; |
455 | m[3] := TStringList.create; |
463 | m[3] := TStringList.create; |
456 | m[4] := TStringList.create; |
464 | m[4] := TStringList.create; |
457 | m[5] := TStringList.create; |
465 | m[5] := TStringList.create; |
458 | m[6] := TStringList.create; |
466 | m[6] := TStringList.create; |
459 | try |
467 | try |
460 | for i := 1 to 6 do |
468 | for i := 1 to 6 do |
461 | begin |
469 | begin |
462 | filename[Length(filename)-4] := IntToStr(i)[1]; // ...A2.sav, ...A3.sav, etc. |
470 | filename[Length(filename)-4] := IntToStr(i)[1]; // ...A2.sav, ...A3.sav, etc. |
463 | if FileExists(filename) then |
471 | if FileExists(filename) then |
464 | m[i].loadfromfile(filename); |
472 | m[i].loadfromfile(filename); |
465 | end; |
473 | end; |
466 | m[1].strings[0] := '-624'; |
474 | m[1].strings[0] := '-624'; |
467 | if m[6].Text = '' then m[6].Text := '30000'; |
475 | if m[6].Text = '' then m[6].Text := '30000'; |
468 | 476 | ||
469 | sl.Add('; SpaceMission 0.3'); // do not localize |
477 | sl.Add('; SpaceMission 0.3'); // do not localize |
470 | sl.Add(temp); |
478 | sl.Add(temp); |
471 | for j := 0 to m[1].count-2 do |
479 | for j := 0 to m[1].count-2 do |
472 | begin |
480 | begin |
473 | for i := 0 to m[1].count-2 do |
481 | for i := 0 to m[1].count-2 do |
474 | begin |
482 | begin |
475 | if strtoint(m[1].strings[i]) > strtoint(m[1].strings[i+1]) then |
483 | if strtoint(m[1].strings[i]) > strtoint(m[1].strings[i+1]) then |
476 | begin |
484 | begin |
477 | m[1].exchange(i, i+1); |
485 | m[1].exchange(i, i+1); |
478 | m[2].exchange(i, i+1); |
486 | m[2].exchange(i, i+1); |
479 | m[3].exchange(i, i+1); |
487 | m[3].exchange(i, i+1); |
480 | m[4].exchange(i, i+1); |
488 | m[4].exchange(i, i+1); |
481 | m[5].exchange(i, i+1); |
489 | m[5].exchange(i, i+1); |
482 | end; |
490 | end; |
483 | end; |
491 | end; |
484 | end; |
492 | end; |
485 | for i := 0 to m[3].count-1 do |
493 | for i := 0 to m[3].count-1 do |
486 | begin |
494 | begin |
487 | for j := 1 to 4 do |
495 | for j := 1 to 4 do |
488 | begin |
496 | begin |
489 | if j = 1 then sl.Add(m[3].strings[i]); |
497 | if j = 1 then sl.Add(m[3].strings[i]); |
490 | if j = 2 then sl.Add(m[1].strings[i]); |
498 | if j = 2 then sl.Add(m[1].strings[i]); |
491 | if j = 3 then sl.Add(m[2].strings[i]); |
499 | if j = 3 then sl.Add(m[2].strings[i]); |
492 | if j = 4 then sl.Add(m[4].strings[i]); |
500 | if j = 4 then sl.Add(m[4].strings[i]); |
493 | end; |
501 | end; |
494 | end; |
502 | end; |
495 | finally |
503 | finally |
496 | FreeAndNil(m[1]); |
504 | FreeAndNil(m[1]); |
497 | FreeAndNil(m[2]); |
505 | FreeAndNil(m[2]); |
498 | FreeAndNil(m[3]); |
506 | FreeAndNil(m[3]); |
499 | FreeAndNil(m[4]); |
507 | FreeAndNil(m[4]); |
500 | FreeAndNil(m[5]); |
508 | FreeAndNil(m[5]); |
501 | FreeAndNil(m[6]); |
509 | FreeAndNil(m[6]); |
502 | end; |
510 | end; |
503 | {$ENDREGION} |
511 | {$ENDREGION} |
504 | end |
512 | end |
505 | else |
513 | else |
506 | begin |
514 | begin |
507 | sl.LoadFromFile(filename); |
515 | sl.LoadFromFile(filename); |
508 | end; |
516 | end; |
509 | 517 | ||
510 | LoadFromStrings(sl); |
518 | LoadFromStrings(sl); |
511 | finally |
519 | finally |
512 | FreeAndNil(sl); |
520 | FreeAndNil(sl); |
513 | end; |
521 | end; |
514 | end; |
522 | end; |
515 | 523 | ||
516 | procedure TLevelData.SaveToStrings(sl: TStrings); |
524 | procedure TLevelData.SaveToStrings(sl: TStrings); |
517 | var |
525 | var |
518 | i: integer; |
526 | i: integer; |
519 | begin |
527 | begin |
520 | sl.Clear; |
528 | sl.Clear; |
521 | sl.Add('['+OID_LEVSAV_VER12+']'); |
529 | sl.Add('['+OID_LEVSAV_VER12+']'); |
522 | if LevelName <> '' then sl.Add('Name ' + LevelName); // do not localize |
530 | if LevelName <> '' then sl.Add('Name ' + LevelName); // do not localize |
523 | if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); // do not localize |
531 | if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); // do not localize |
524 | sl.Add('Width ' + IntToStr(LevelEditorLength)); // do not localize |
532 | sl.Add('Width ' + IntToStr(LevelEditorLength)); // do not localize |
525 | SortEnemies; |
533 | SortEnemies; |
526 | sl.Add('; Type XCoord YCoord Lives'); |
534 | sl.Add('; Type XCoord YCoord Lives'); |
527 | for i := 0 to Length(EnemyAdventTable)-1 do |
535 | for i := 0 to Length(EnemyAdventTable)-1 do |
528 | begin |
536 | begin |
529 | sl.Add(Trim( |
537 | sl.Add(Trim( |
530 | 'Enemy'.PadRight(6, ' ')+ // do not localize |
538 | 'Enemy'.PadRight(6, ' ')+ // do not localize |
531 | ' '+ |
539 | ' '+ |
532 | IntToStr(Ord(EnemyAdventTable[i].enemyType)).PadRight(6, ' ')+ |
540 | IntToStr(Ord(EnemyAdventTable[i].enemyType)).PadRight(6, ' ')+ |
533 | ' '+ |
541 | ' '+ |
534 | IntToStr(EnemyAdventTable[i].x).PadRight(6, ' ')+ |
542 | IntToStr(EnemyAdventTable[i].x).PadRight(6, ' ')+ |
535 | ' '+ |
543 | ' '+ |
536 | IntToStr(EnemyAdventTable[i].y).PadRight(6, ' ')+ |
544 | IntToStr(EnemyAdventTable[i].y).PadRight(6, ' ')+ |
537 | ' '+ |
545 | ' '+ |
538 | IntToStr(EnemyAdventTable[i].lifes).PadRight(6, ' ')+ |
546 | IntToStr(EnemyAdventTable[i].lifes).PadRight(6, ' ')+ |
539 | ' ' |
547 | ' ' |
540 | )); |
548 | )); |
541 | end; |
549 | end; |
542 | end; |
550 | end; |
543 | 551 | ||
544 | procedure TLevelData.SaveToFile(filename: string); |
552 | procedure TLevelData.SaveToFile(filename: string); |
545 | var |
553 | var |
546 | sl: TStringList; |
554 | sl: TStringList; |
547 | begin |
555 | begin |
548 | sl := TStringList.Create; |
556 | sl := TStringList.Create; |
549 | try |
557 | try |
550 | SaveToStrings(sl); |
558 | SaveToStrings(sl); |
551 | sl.SaveToFile(filename); |
559 | sl.SaveToFile(filename); |
552 | finally |
560 | finally |
553 | FreeAndNil(sl); |
561 | FreeAndNil(sl); |
554 | end; |
562 | end; |
555 | end; |
563 | end; |
556 | 564 | ||
557 | procedure TLevelData.SortEnemies; |
565 | procedure TLevelData.SortEnemies; |
558 | var |
566 | var |
559 | i, n: integer; |
567 | i, n: integer; |
560 | e: TEnemyAdvent; |
568 | e: TEnemyAdvent; |
561 | begin |
569 | begin |
562 | // Bubble Sort Algorithmus |
570 | // Bubble Sort Algorithmus |
563 | for n := Length(EnemyAdventTable) downto 2 do |
571 | for n := Length(EnemyAdventTable) downto 2 do |
564 | begin |
572 | begin |
565 | for i := 0 to n - 2 do |
573 | for i := 0 to n - 2 do |
566 | begin |
574 | begin |
567 | if |
575 | if |
568 | // Sort by X-coord (important for the game!) |
576 | // Sort by X-coord (important for the game!) |
569 | (EnemyAdventTable[i].x > EnemyAdventTable[i+1].x) |
577 | (EnemyAdventTable[i].x > EnemyAdventTable[i+1].x) |
570 | or |
578 | or |
571 | // Sort by Y-coord (just cosmetics) |
579 | // Sort by Y-coord (just cosmetics) |
572 | ((EnemyAdventTable[i].x = EnemyAdventTable[i+1].x) and (EnemyAdventTable[i].y > EnemyAdventTable[i+1].y)) |
580 | ((EnemyAdventTable[i].x = EnemyAdventTable[i+1].x) and (EnemyAdventTable[i].y > EnemyAdventTable[i+1].y)) |
573 | then |
581 | then |
574 | begin |
582 | begin |
575 | e := EnemyAdventTable[i]; |
583 | e := EnemyAdventTable[i]; |
576 | EnemyAdventTable[i] := EnemyAdventTable[i + 1]; |
584 | EnemyAdventTable[i] := EnemyAdventTable[i + 1]; |
577 | EnemyAdventTable[i + 1] := e; |
585 | EnemyAdventTable[i + 1] := e; |
578 | end; |
586 | end; |
579 | end; |
587 | end; |
580 | end; |
588 | end; |
581 | end; |
589 | end; |
582 | 590 | ||
583 | { TSaveData } |
591 | { TSaveData } |
584 | 592 | ||
585 | procedure TSaveData.AssignTo(Dest: TPersistent); |
593 | procedure TSaveData.AssignTo(Dest: TPersistent); |
586 | var |
594 | var |
587 | DestSaveData: TSaveData; |
595 | DestSaveData: TSaveData; |
588 | begin |
596 | begin |
589 | DestSaveData := Dest as TSaveData; |
597 | DestSaveData := Dest as TSaveData; |
590 | if Assigned(DestSaveData) then |
598 | if Assigned(DestSaveData) then |
591 | begin |
599 | begin |
592 | DestSaveData.Score := Self.Score; |
600 | DestSaveData.Score := Self.Score; |
593 | DestSaveData.Life := Self.Life; |
601 | DestSaveData.Life := Self.Life; |
594 | DestSaveData.Level := Self.Level; |
602 | DestSaveData.Level := Self.Level; |
595 | DestSaveData.GameMode := Self.GameMode; |
603 | DestSaveData.GameMode := Self.GameMode; |
596 | if not Assigned(DestSaveData.LevelData) then DestSaveData.LevelData := TLevelData.Create; |
604 | if not Assigned(DestSaveData.LevelData) then DestSaveData.LevelData := TLevelData.Create; |
597 | DestSaveData.LevelData.Assign(Self.LevelData); |
605 | DestSaveData.LevelData.Assign(Self.LevelData); |
598 | end |
606 | end |
599 | else |
607 | else |
600 | begin |
608 | begin |
601 | inherited; |
609 | inherited; |
602 | end; |
610 | end; |
603 | end; |
611 | end; |
604 | 612 | ||
605 | procedure TSaveData.Clear; |
613 | procedure TSaveData.Clear; |
606 | begin |
614 | begin |
607 | Score := 0; |
615 | Score := 0; |
608 | Life := 0; |
616 | Life := 0; |
609 | Level := 0; |
617 | Level := 0; |
610 | GameMode := gmUnknown; |
618 | GameMode := gmUnknown; |
611 | FreeAndNil(LevelData); |
619 | FreeAndNil(LevelData); |
612 | end; |
620 | end; |
613 | 621 | ||
614 | destructor TSaveData.Destroy; |
622 | destructor TSaveData.Destroy; |
615 | begin |
623 | begin |
616 | Clear; |
624 | Clear; |
617 | inherited; |
625 | inherited; |
618 | end; |
626 | end; |
619 | 627 | ||
620 | procedure TSaveData.SaveToStrings(sl: TStrings); |
628 | procedure TSaveData.SaveToStrings(sl: TStrings); |
621 | var |
629 | var |
622 | sl2: TStringList; |
630 | sl2: TStringList; |
623 | begin |
631 | begin |
624 | sl2 := TStringList.Create; |
632 | sl2 := TStringList.Create; |
625 | try |
633 | try |
626 | sl.Add('['+OID_LEVSAV_VER12+']'); |
634 | sl.Add('['+OID_LEVSAV_VER12+']'); |
627 | sl.Add('Score ' + IntToStr(Score)); // do not localize |
635 | sl.Add('Score ' + IntToStr(Score)); // do not localize |
628 | sl.Add('Lives ' + IntToStr(Life)); // do not localize |
636 | sl.Add('Lives ' + IntToStr(Life)); // do not localize |
629 | sl.Add('Level ' + IntToStr(Level)); // do not localize |
637 | sl.Add('Level ' + IntToStr(Level)); // do not localize |
630 | sl.Add('Mode ' + IntToStr(Ord(GameMode))); // do not localize |
638 | sl.Add('Mode ' + IntToStr(Ord(GameMode))); // do not localize |
631 | LevelData.SaveToStrings(sl2); |
639 | LevelData.SaveToStrings(sl2); |
632 | sl2.Delete(0); // Delete additional level signature |
640 | sl2.Delete(0); // Delete additional level signature |
633 | sl.AddStrings(sl2); |
641 | sl.AddStrings(sl2); |
634 | finally |
642 | finally |
635 | FreeAndNil(sl2); |
643 | FreeAndNil(sl2); |
636 | end; |
644 | end; |
637 | end; |
645 | end; |
638 | 646 | ||
639 | procedure TSaveData.LoadFromStrings(sl: TStrings); |
647 | procedure TSaveData.LoadFromStrings(sl: TStrings); |
640 | var |
648 | var |
641 | curline: Integer; |
649 | curline: Integer; |
642 | ary: TStringDynArray; |
650 | ary: TStringDynArray; |
643 | sLine: string; |
651 | sLine: string; |
644 | begin |
652 | begin |
645 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
653 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
646 | (sl.Strings[1] = '; SAV-File') then // do not localize |
654 | (sl.Strings[1] = '; SAV-File') then // do not localize |
647 | begin |
655 | begin |
648 | Score := StrToInt(sl.Strings[2]); |
656 | Score := StrToInt(sl.Strings[2]); |
649 | Life := StrToInt(sl.Strings[3]); |
657 | Life := StrToInt(sl.Strings[3]); |
650 | Level := StrToInt(sl.Strings[4]); |
658 | Level := StrToInt(sl.Strings[4]); |
651 | GameMode := TGameMode(StrToInt(sl.Strings[5])); |
659 | GameMode := TGameMode(StrToInt(sl.Strings[5])); |
652 | if Assigned(LevelData) then FreeAndNil(LevelData); |
660 | if Assigned(LevelData) then FreeAndNil(LevelData); |
653 | end |
661 | end |
654 | else if SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']') then |
662 | else if SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']') then |
655 | begin |
663 | begin |
656 | Score := 0; |
664 | Score := 0; |
657 | Life := 0; |
665 | Life := 0; |
658 | Level := 0; |
666 | Level := 0; |
659 | GameMode := gmUnknown; |
667 | GameMode := gmUnknown; |
660 | for curline := 1 to sl.Count-1 do |
668 | for curline := 1 to sl.Count-1 do |
661 | begin |
669 | begin |
662 | sLine := sl.Strings[curline].Trim; |
670 | sLine := sl.Strings[curline].Trim; |
663 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
671 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
664 | ary := SplitString(CollapseSpaces(sLine), ' '); |
672 | ary := SplitString(CollapseSpaces(sLine), ' '); |
665 | if SameText(ary[0], 'Score') then // do not localize |
673 | if SameText(ary[0], 'Score') then // do not localize |
666 | begin |
674 | begin |
667 | Score := StrToInt(ary[1]); |
675 | Score := StrToInt(ary[1]); |
668 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
676 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
669 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
677 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
670 | end |
678 | end |
671 | else if SameText(ary[0], 'Lives') then // do not localize |
679 | else if SameText(ary[0], 'Lives') then // do not localize |
672 | begin |
680 | begin |
673 | Life := StrToInt(ary[1]); |
681 | Life := StrToInt(ary[1]); |
674 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
682 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
675 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
683 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
676 | end |
684 | end |
677 | else if SameText(ary[0], 'Level') then // do not localize |
685 | else if SameText(ary[0], 'Level') then // do not localize |
678 | begin |
686 | begin |
679 | Level := StrToInt(ary[1]); |
687 | Level := StrToInt(ary[1]); |
680 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
688 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
681 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
689 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
682 | end |
690 | end |
683 | else if SameText(ary[0], 'Mode') then // do not localize |
691 | else if SameText(ary[0], 'Mode') then // do not localize |
684 | begin |
692 | begin |
685 | GameMode := TGameMode(StrToInt(ary[1])); |
693 | GameMode := TGameMode(StrToInt(ary[1])); |
686 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
694 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
687 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
695 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
688 | end; |
696 | end; |
689 | end; |
697 | end; |
690 | if Assigned(LevelData) then FreeAndNil(LevelData); |
698 | if Assigned(LevelData) then FreeAndNil(LevelData); |
691 | LevelData := TLevelData.Create; |
699 | LevelData := TLevelData.Create; |
692 | LevelData.RasterErzwingen := false; |
700 | LevelData.RasterErzwingen := false; |
693 | LevelData.LoadFromStrings(sl); |
701 | LevelData.LoadFromStrings(sl); |
694 | end |
702 | end |
695 | else |
703 | else |
696 | begin |
704 | begin |
697 | raise Exception.Create('Spielstand-Format nicht unterstützt oder Datei beschädigt'); |
705 | raise Exception.Create('Spielstand-Format nicht unterstützt oder Datei beschädigt'); |
698 | end; |
706 | end; |
699 | end; |
707 | end; |
700 | 708 | ||
701 | procedure TSaveData.LoadFromFile(filename: string); |
709 | procedure TSaveData.LoadFromFile(filename: string); |
702 | var |
710 | var |
703 | sl: TStringList; |
711 | sl: TStringList; |
704 | begin |
712 | begin |
705 | sl := TStringList.Create; |
713 | sl := TStringList.Create; |
706 | try |
714 | try |
707 | sl.LoadFromFile(filename); |
715 | sl.LoadFromFile(filename); |
708 | LoadFromStrings(sl); |
716 | LoadFromStrings(sl); |
709 | finally |
717 | finally |
710 | FreeAndNil(sl); |
718 | FreeAndNil(sl); |
711 | end; |
719 | end; |
712 | end; |
720 | end; |
713 | 721 | ||
714 | procedure TSaveData.SaveToFile(filename: string); |
722 | procedure TSaveData.SaveToFile(filename: string); |
715 | var |
723 | var |
716 | sl: TStringList; |
724 | sl: TStringList; |
717 | begin |
725 | begin |
718 | sl := TStringList.Create; |
726 | sl := TStringList.Create; |
719 | try |
727 | try |
720 | SaveToStrings(sl); |
728 | SaveToStrings(sl); |
721 | sl.SaveToFile(filename); |
729 | sl.SaveToFile(filename); |
722 | finally |
730 | finally |
723 | FreeAndNil(sl); |
731 | FreeAndNil(sl); |
724 | end; |
732 | end; |
725 | end; |
733 | end; |
- | 734 | ||
- | 735 | function EnemyTypeHasLives(et: TEnemyType): boolean; |
|
- | 736 | begin |
|
- | 737 | result := (et <> etEnemyMeteor) and (et <> etItemMedikit); |
|
- | 738 | end; |
|
726 | 739 | ||
727 | end. |
740 | end. |
728 | 741 |