Subversion Repositories spacemission

Rev

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