Rev 51 | Rev 53 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 51 | Rev 52 | ||
---|---|---|---|
Line 74... | Line 74... | ||
74 | function GetLevelFileName(lev: integer; forceuserdir: boolean): string; |
74 | function GetLevelFileName(lev: integer; forceuserdir: boolean): string; |
75 | 75 | ||
76 | implementation |
76 | implementation |
77 | 77 | ||
78 | uses |
78 | uses |
79 | SysUtils, StrUtils, Global, Windows; |
79 | SysUtils, StrUtils, Global, Windows, System.Types; |
- | 80 | ||
- | 81 | const |
|
- | 82 | // { 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) } |
|
- | 83 | // https://hosted.oidplus.com/viathinksoft/?goto=oid%3A1.3.6.1.4.1.37476.2.8.1.1 |
|
- | 84 | OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1'; |
|
80 | 85 | ||
81 | function GetLevelFileName(lev: integer; forceuserdir: boolean): string; |
86 | function GetLevelFileName(lev: integer; forceuserdir: boolean): string; |
82 | 87 | ||
83 | function _GetLevelVerzeichnisSystem: string; |
88 | function _GetLevelVerzeichnisSystem: string; |
84 | begin |
89 | begin |
Line 137... | Line 142... | ||
137 | if fileexists(usr) or forceuserdir then exit(usr); |
142 | if fileexists(usr) or forceuserdir then exit(usr); |
138 | if fileexists(sys) then exit(sys); |
143 | if fileexists(sys) then exit(sys); |
139 | exit(usr); |
144 | exit(usr); |
140 | end; |
145 | end; |
141 | 146 | ||
- | 147 | // this is just an example, there are many |
|
- | 148 | // different ways you can implement this |
|
- | 149 | // more efficiently, ie using a TStringBuilder, |
|
- | 150 | // or even modifying the String in-place... |
|
- | 151 | function CollapseSpaces(const S: string): string; |
|
- | 152 | var |
|
- | 153 | P: PChar; |
|
- | 154 | AddSpace: Boolean; |
|
- | 155 | begin |
|
- | 156 | Result := ''; |
|
- | 157 | AddSpace := False; |
|
- | 158 | P := PChar(S); |
|
- | 159 | while P^ <> #0 do |
|
- | 160 | begin |
|
- | 161 | while CharInSet(P^, [#1..' ']) do Inc(P); |
|
- | 162 | if P^ = #0 then Exit; |
|
- | 163 | if AddSpace then |
|
- | 164 | Result := Result + ' ' |
|
- | 165 | else |
|
- | 166 | AddSpace := True; |
|
- | 167 | repeat |
|
- | 168 | Result := Result + P^; |
|
- | 169 | Inc(P); |
|
- | 170 | until P^ <= ' '; |
|
- | 171 | end; |
|
- | 172 | end; |
|
- | 173 | ||
142 | { TLevelData } |
174 | { TLevelData } |
143 | 175 | ||
144 | procedure TLevelData.AssignTo(Dest: TPersistent); |
176 | procedure TLevelData.AssignTo(Dest: TPersistent); |
145 | var |
177 | var |
146 | DestLevelData: TLevelData; |
178 | DestLevelData: TLevelData; |
Line 258... | Line 290... | ||
258 | curline: integer; |
290 | curline: integer; |
259 | z, act: integer; |
291 | z, act: integer; |
260 | sl2: TStringList; |
292 | sl2: TStringList; |
261 | tmpX, tmpY, tmpLifes: integer; |
293 | tmpX, tmpY, tmpLifes: integer; |
262 | tmpEnemy: TEnemyType; |
294 | tmpEnemy: TEnemyType; |
263 | tmpRest: string; |
- | |
264 | ergebnis: string; |
295 | ergebnis: string; |
- | 296 | ary: TStringDynArray; |
|
- | 297 | sLine: string; |
|
265 | begin |
298 | begin |
266 | Clear; |
299 | Clear; |
267 | 300 | ||
268 | LevelEditorLength := DefaultLevelLength; |
301 | LevelEditorLength := DefaultLevelLength; |
269 | LevelName := ''; |
302 | LevelName := ''; |
270 | LevelAuthor := ''; |
303 | LevelAuthor := ''; |
271 | 304 | ||
272 | if sl.Strings[0] = '; SpaceMission 0.3' then |
305 | if sl.Strings[0] = '; SpaceMission 0.3' then // do not localize |
273 | begin |
306 | begin |
274 | {$REGION 'Backwards compatibility level format 0.3 (convert to 0.4)'} |
307 | {$REGION 'Backwards compatibility level format 0.3 (convert to 0.4)'} |
275 | sl.Strings[0] := '; SpaceMission 0.4'; |
308 | sl.Strings[0] := '; SpaceMission 0.4'; // do not localize |
276 | sl.Insert(1, '; LEV-File'); |
309 | sl.Insert(1, '; LEV-File'); // do not localize |
277 | {$ENDREGION} |
310 | {$ENDREGION} |
278 | end; |
311 | end; |
279 | 312 | ||
280 | if (sl.Strings[0] = '; SpaceMission 0.4') and |
313 | if (sl.Strings[0] = '; SpaceMission 0.4') and // do not localize |
281 | (sl.Strings[1] = '; LEV-File') then |
314 | (sl.Strings[1] = '; LEV-File') then // do not localize |
282 | begin |
315 | begin |
283 | {$REGION 'Backwards compatibility level format 0.4 (convert to 1.0)'} |
316 | {$REGION 'Backwards compatibility level format 0.4 (convert to 1.0)'} |
284 | sl2 := TStringList.Create; |
317 | sl2 := TStringList.Create; |
285 | try |
318 | try |
286 | z := 0; |
319 | z := 0; |
Line 315... | Line 348... | ||
315 | FreeAndNil(sl2); |
348 | FreeAndNil(sl2); |
316 | end; |
349 | end; |
317 | {$ENDREGION} |
350 | {$ENDREGION} |
318 | end; |
351 | end; |
319 | 352 | ||
320 | if (sl.Strings[0] = '; SpaceMission 1.0') and |
353 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
321 | (sl.Strings[1] = '; LEV-File') then |
354 | (sl.Strings[1] = '; LEV-File') then // do not localize |
322 | begin |
355 | begin |
323 | {$REGION 'Level format 1.0'} |
356 | {$REGION 'Level format 1.0'} |
324 | LevelEditorLength := StrToInt(sl.Strings[2]); |
357 | LevelEditorLength := StrToInt(sl.Strings[2]); |
325 | curline := 3; |
358 | curline := 3; |
326 | while curline < sl.Count do |
359 | while curline < sl.Count do |
Line 335... | Line 368... | ||
335 | Inc(curline); |
368 | Inc(curline); |
336 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
369 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
337 | end; |
370 | end; |
338 | {$ENDREGION} |
371 | {$ENDREGION} |
339 | end |
372 | end |
340 | else if (SameText(sl.Strings[0], '[SpaceMission Level, Format 1.2]')) or |
373 | else if (SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']')) then |
341 | (SameText(sl.Strings[0], '[SpaceMission Savegame, Format 1.2]')) then |
- | |
342 | begin |
374 | begin |
343 | {$REGION 'Level format 1.2'} |
375 | {$REGION 'Level format 1.2'} |
344 | for curline := 1 to sl.Count-1 do |
376 | for curline := 1 to sl.Count-1 do |
345 | begin |
377 | begin |
346 | // 1234567890123456789012345678901234567890 |
- | |
347 | // 123456 123456 123456 123456 123456 ; Kommentar |
- | |
348 | if (sl.Strings[curline].Trim = '') or |
378 | sLine := sl.Strings[curline].Trim; |
349 | (Copy(sl.Strings[curline], 1, 1) = ';') then |
379 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
350 | // Do nothing |
380 | ary := SplitString(CollapseSpaces(sLine), ' '); |
351 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Width' then |
381 | if ary[0] = 'Width' then // do not localize |
352 | begin |
382 | begin |
353 | LevelEditorLength := StrToInt(TrimRight(Copy(sl.Strings[curline], 8, 6))) |
383 | LevelEditorLength := StrToInt(ary[1]); |
- | 384 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
|
- | 385 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
|
354 | end |
386 | end |
355 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Name' then |
387 | else if ary[0] = 'Name' then // do not localize |
356 | begin |
388 | begin |
357 | LevelName := TrimRight(Copy(sl.Strings[curline], 8, Length(sl.Strings[curline]))) |
389 | LevelName := Copy(sLine, Length(ary[0])+2, Length(sLine)); |
358 | end |
390 | end |
359 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Author' then |
391 | else if ary[0] = 'Author' then // do not localize |
360 | begin |
392 | begin |
361 | LevelAuthor := TrimRight(Copy(sl.Strings[curline], 8, Length(sl.Strings[curline]))) |
393 | LevelAuthor := Copy(sLine, Length(ary[0])+2, Length(sLine)); |
362 | end |
394 | end |
363 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Enemy' then |
395 | else if ary[0] = 'Enemy' then // do not localize |
364 | begin |
396 | begin |
365 | tmpEnemy := TEnemyType(strtoint(TrimRight(Copy(sl.Strings[curline], 8, 6)))); |
397 | tmpEnemy := TEnemyType(strtoint(ary[1])); |
366 | tmpX := strtoint(TrimRight(Copy(sl.Strings[curline], 15, 6))); |
398 | tmpX := strtoint(ary[2]); |
367 | tmpY := strtoint(TrimRight(Copy(sl.Strings[curline], 22, 6))); |
399 | tmpY := strtoint(ary[3]); |
368 | tmpLifes := strtoint(TrimRight(Copy(sl.Strings[curline], 29, 6))); |
400 | tmpLifes := strtoint(ary[4]); |
369 | tmpRest := Copy(sl.Strings[curline], 36, Length(sl.Strings[curline])-36+1); |
- | |
370 | if (Copy(tmpRest, 1, 1) <> ';') and (Trim(tmpRest) <> '') then |
401 | if (Length(ary) > 5) and (Copy(ary[5], 1, 1) <> ';') then |
371 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
402 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
372 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
403 | AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes); |
373 | end; |
404 | end; |
374 | end; |
405 | end; |
375 | {$ENDREGION} |
406 | {$ENDREGION} |
Line 389... | Line 420... | ||
389 | temp: string; |
420 | temp: string; |
390 | m: array[1..6] of tstrings; |
421 | m: array[1..6] of tstrings; |
391 | begin |
422 | begin |
392 | sl := TStringList.Create; |
423 | sl := TStringList.Create; |
393 | try |
424 | try |
394 | if EndsText('A1.lev', filename) then |
425 | if EndsText('A1.lev', filename) then // do not localize |
395 | begin |
426 | begin |
396 | {$REGION 'Backwards compatibility level format 0.2 (split into 5-6 files; convert to 0.3)'} |
427 | {$REGION 'Backwards compatibility level format 0.2 (split into 5-6 files; convert to 0.3)'} |
397 | m[1] := TStringList.create; |
428 | m[1] := TStringList.create; |
398 | m[2] := TStringList.create; |
429 | m[2] := TStringList.create; |
399 | m[3] := TStringList.create; |
430 | m[3] := TStringList.create; |
Line 408... | Line 439... | ||
408 | m[i].loadfromfile(filename); |
439 | m[i].loadfromfile(filename); |
409 | end; |
440 | end; |
410 | m[1].strings[0] := '-624'; |
441 | m[1].strings[0] := '-624'; |
411 | if m[6].Text = '' then m[6].Text := '30000'; |
442 | if m[6].Text = '' then m[6].Text := '30000'; |
412 | 443 | ||
413 | sl.Add('; SpaceMission 0.3'); |
444 | sl.Add('; SpaceMission 0.3'); // do not localize |
414 | sl.Add(temp); |
445 | sl.Add(temp); |
415 | for j := 0 to m[1].count-2 do |
446 | for j := 0 to m[1].count-2 do |
416 | begin |
447 | begin |
417 | for i := 0 to m[1].count-2 do |
448 | for i := 0 to m[1].count-2 do |
418 | begin |
449 | begin |
Line 460... | Line 491... | ||
460 | procedure TLevelData.SaveToStrings(sl: TStrings); |
491 | procedure TLevelData.SaveToStrings(sl: TStrings); |
461 | var |
492 | var |
462 | i: integer; |
493 | i: integer; |
463 | begin |
494 | begin |
464 | sl.Clear; |
495 | sl.Clear; |
465 | sl.Add('[SpaceMission Level, Format 1.2]'); |
496 | sl.Add('['+OID_LEVSAV_VER12+']'); |
466 | if LevelName <> '' then sl.Add('Name ' + LevelName); |
497 | if LevelName <> '' then sl.Add('Name ' + LevelName); // do not localize |
467 | if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); |
498 | if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); // do not localize |
468 | sl.Add('Width ' + IntToStr(LevelEditorLength)); |
499 | sl.Add('Width ' + IntToStr(LevelEditorLength)); // do not localize |
469 | SortEnemies; |
500 | SortEnemies; |
470 | sl.Add('; Type XCoord YCoord Lives'); |
501 | sl.Add('; Type XCoord YCoord Lives'); |
471 | for i := 0 to Length(EnemyAdventTable)-1 do |
502 | for i := 0 to Length(EnemyAdventTable)-1 do |
472 | begin |
503 | begin |
473 | sl.Add( |
504 | sl.Add(Trim( |
474 | 'Enemy'.PadRight(6, ' ')+ |
505 | 'Enemy'.PadRight(6, ' ')+ // do not localize |
475 | ' '+ |
506 | ' '+ |
476 | IntToStr(Ord(EnemyAdventTable[i].enemyType)).PadRight(6, ' ')+ |
507 | IntToStr(Ord(EnemyAdventTable[i].enemyType)).PadRight(6, ' ')+ |
477 | ' '+ |
508 | ' '+ |
478 | IntToStr(EnemyAdventTable[i].x).PadRight(6, ' ')+ |
509 | IntToStr(EnemyAdventTable[i].x).PadRight(6, ' ')+ |
479 | ' '+ |
510 | ' '+ |
480 | IntToStr(EnemyAdventTable[i].y).PadRight(6, ' ')+ |
511 | IntToStr(EnemyAdventTable[i].y).PadRight(6, ' ')+ |
481 | ' '+ |
512 | ' '+ |
482 | IntToStr(EnemyAdventTable[i].lifes).PadRight(6, ' ')+ |
513 | IntToStr(EnemyAdventTable[i].lifes).PadRight(6, ' ')+ |
483 | ' ' |
514 | ' ' |
484 | ); |
515 | )); |
485 | end; |
516 | end; |
486 | end; |
517 | end; |
487 | 518 | ||
488 | procedure TLevelData.SaveToFile(filename: string); |
519 | procedure TLevelData.SaveToFile(filename: string); |
489 | var |
520 | var |
Line 565... | Line 596... | ||
565 | var |
596 | var |
566 | sl2: TStringList; |
597 | sl2: TStringList; |
567 | begin |
598 | begin |
568 | sl2 := TStringList.Create; |
599 | sl2 := TStringList.Create; |
569 | try |
600 | try |
570 | sl.Add('[SpaceMission Savegame, Format 1.2]'); |
601 | sl.Add('['+OID_LEVSAV_VER12+']'); |
571 | sl.Add('Score ' + IntToStr(Score)); |
602 | sl.Add('Score ' + IntToStr(Score)); // do not localize |
572 | sl.Add('Lives ' + IntToStr(Life)); |
603 | sl.Add('Lives ' + IntToStr(Life)); // do not localize |
573 | sl.Add('Level ' + IntToStr(Level)); |
604 | sl.Add('Level ' + IntToStr(Level)); // do not localize |
574 | sl.Add('Mode ' + IntToStr(Ord(GameMode))); |
605 | sl.Add('Mode ' + IntToStr(Ord(GameMode))); // do not localize |
575 | LevelData.SaveToStrings(sl2); |
606 | LevelData.SaveToStrings(sl2); |
576 | sl2.Delete(0); // Signature |
607 | sl2.Delete(0); // Delete additional level signature |
577 | sl.AddStrings(sl2); |
608 | sl.AddStrings(sl2); |
578 | finally |
609 | finally |
579 | FreeAndNil(sl2); |
610 | FreeAndNil(sl2); |
580 | end; |
611 | end; |
581 | end; |
612 | end; |
582 | 613 | ||
583 | procedure TSaveData.LoadFromStrings(sl: TStrings); |
614 | procedure TSaveData.LoadFromStrings(sl: TStrings); |
584 | var |
615 | var |
585 | curline: Integer; |
616 | curline: Integer; |
- | 617 | ary: TStringDynArray; |
|
- | 618 | sLine: string; |
|
586 | begin |
619 | begin |
587 | if (sl.Strings[0] = '; SpaceMission 1.0') and |
620 | if (sl.Strings[0] = '; SpaceMission 1.0') and // do not localize |
588 | (sl.Strings[1] = '; SAV-File') then |
621 | (sl.Strings[1] = '; SAV-File') then // do not localize |
589 | begin |
622 | begin |
590 | Score := StrToInt(sl.Strings[2]); |
623 | Score := StrToInt(sl.Strings[2]); |
591 | Life := StrToInt(sl.Strings[3]); |
624 | Life := StrToInt(sl.Strings[3]); |
592 | Level := StrToInt(sl.Strings[4]); |
625 | Level := StrToInt(sl.Strings[4]); |
593 | GameMode := TGameMode(StrToInt(sl.Strings[5])); |
626 | GameMode := TGameMode(StrToInt(sl.Strings[5])); |
594 | if Assigned(LevelData) then FreeAndNil(LevelData); |
627 | if Assigned(LevelData) then FreeAndNil(LevelData); |
595 | end |
628 | end |
596 | else if SameText(sl.Strings[0], '[SpaceMission Savegame, Format 1.2]') then |
629 | else if SameText(sl.Strings[0], '['+OID_LEVSAV_VER12+']') then |
597 | begin |
630 | begin |
598 | Score := 0; |
631 | Score := 0; |
599 | Life := 0; |
632 | Life := 0; |
600 | Level := 0; |
633 | Level := 0; |
601 | GameMode := gmUnknown; |
634 | GameMode := gmUnknown; |
602 | for curline := 1 to sl.Count-1 do |
635 | for curline := 1 to sl.Count-1 do |
603 | begin |
636 | begin |
604 | // 1234567890123456789012345678901234567890 |
- | |
605 | // 123456 123456 123456 123456 123456 ; Kommentar |
- | |
606 | if (sl.Strings[curline].Trim = '') or |
637 | sLine := sl.Strings[curline].Trim; |
607 | (Copy(sl.Strings[curline], 1, 1) = ';') then |
638 | if (sLine = '') or (Copy(sLine, 1, 1) = ';') then continue; |
608 | // Do nothing |
639 | ary := SplitString(CollapseSpaces(sLine), ' '); |
609 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Score' then |
640 | if ary[0] = 'Score' then // do not localize |
610 | begin |
641 | begin |
611 | Score := StrToInt(TrimRight(Copy(sl.Strings[curline], 8, 6))) |
642 | Score := StrToInt(ary[1]); |
- | 643 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
|
- | 644 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
|
612 | end |
645 | end |
613 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Lives' then |
646 | else if ary[0] = 'Lives' then // do not localize |
614 | begin |
647 | begin |
615 | Life := StrToInt(TrimRight(Copy(sl.Strings[curline], 8, 6))) |
648 | Life := StrToInt(ary[1]); |
- | 649 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
|
- | 650 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
|
616 | end |
651 | end |
617 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Level' then |
652 | else if ary[0] = 'Level' then // do not localize |
618 | begin |
653 | begin |
619 | Level := StrToInt(TrimRight(Copy(sl.Strings[curline], 8, 6))) |
654 | Level := StrToInt(ary[1]); |
- | 655 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
|
- | 656 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
|
620 | end |
657 | end |
621 | else if Copy(sl.Strings[curline], 1, 6).TrimRight = 'Mode' then |
658 | else if ary[0] = 'Mode' then // do not localize |
622 | begin |
659 | begin |
623 | GameMode := TGameMode(StrToInt(TrimRight(Copy(sl.Strings[curline], 8, 6)))) |
660 | GameMode := TGameMode(StrToInt(ary[1])); |
- | 661 | if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then |
|
- | 662 | raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]); |
|
624 | end; |
663 | end; |
625 | end; |
664 | end; |
626 | if Assigned(LevelData) then FreeAndNil(LevelData); |
665 | if Assigned(LevelData) then FreeAndNil(LevelData); |
627 | LevelData := TLevelData.Create; |
666 | LevelData := TLevelData.Create; |
628 | LevelData.RasterErzwingen := false; |
667 | LevelData.RasterErzwingen := false; |