Subversion Repositories spacemission

Rev

Rev 24 | Rev 28 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit ComLevelReader;
  2.  
  3. interface
  4.  
  5. const
  6.   NumEnemyTypes = 7;
  7.  
  8. type
  9.   TEnemyType = (
  10.     etUnknown,
  11.     etEnemyAttacker,
  12.     etEnemyAttacker2,
  13.     etEnemyAttacker3,
  14.     etEnemyMeteor,
  15.     etEnemyUFO,
  16.     etEnemyUFO2,
  17.     etEnemyBoss
  18.   );
  19.  
  20.   TEnemyAdvent = record
  21.     enemyType: TEnemyType;
  22.     x: integer;
  23.     y: integer;
  24.     lifes: integer;
  25.   end;
  26.  
  27.   TLevelData = class(TObject)
  28.   strict private
  29.     procedure SortEnemies;
  30.   public
  31.     LevelEditorLength: integer;
  32.     EnemyAdventTable: array of TEnemyAdvent;
  33.     function IndexOfEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer): integer;
  34.     procedure AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer);
  35.     procedure DeleteEnemy(i: integer); overload;
  36.     procedure DeleteEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer); overload;
  37.     function CountEnemies: integer;
  38.     function HasBoss: boolean;
  39.     procedure Clear;
  40.     procedure Load(filename: string);
  41.     procedure Save(filename: string);
  42.   end;
  43.  
  44. function GetLevelFileName(lev: integer): string;
  45.  
  46. implementation
  47.  
  48. uses
  49.   SysUtils, StrUtils, Classes, Global;
  50.  
  51. const
  52.   DefaultLevelLength = 1200;
  53.  
  54. function GetLevelFileName(lev: integer): string;
  55. begin
  56.   result := FDirectory+'Levels\Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files
  57.   if not FileExists(Result) then
  58.     result := FDirectory+'Levels\Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files
  59. end;
  60.  
  61. { TLevelData }
  62.  
  63. procedure TLevelData.Clear;
  64. begin
  65.   SetLength(EnemyAdventTable, 0);
  66.   LevelEditorLength := DefaultLevelLength;
  67. end;
  68.  
  69. function TLevelData.CountEnemies: integer;
  70. begin
  71.   result := Length(EnemyAdventTable);
  72. end;
  73.  
  74. procedure TLevelData.DeleteEnemy(i: integer);
  75. var
  76.   j: integer;
  77. begin
  78.   for j := i+1 to CountEnemies-1 do
  79.   begin
  80.     EnemyAdventTable[j-1] := EnemyAdventTable[j];
  81.   end;
  82.   SetLength(EnemyAdventTable, Length(EnemyAdventTable)-1);
  83. end;
  84.  
  85. procedure TLevelData.DeleteEnemy(x, y: integer; enemyType: TEnemyType;
  86.   lifes: integer);
  87. begin
  88.   DeleteEnemy(IndexOfEnemy(x, y, enemyType, lifes));
  89. end;
  90.  
  91. function TLevelData.HasBoss: boolean;
  92. var
  93.   i: integer;
  94. begin
  95.   for i := 0 to Length(EnemyAdventTable) - 1 do
  96.   begin
  97.     if EnemyAdventTable[i].enemyType = etEnemyBoss then
  98.     begin
  99.       result := true;
  100.       exit;
  101.     end;
  102.   end;
  103.   result := false;
  104. end;
  105.  
  106. procedure TLevelData.AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer);
  107. begin
  108.   SetLength(EnemyAdventTable, Length(EnemyAdventTable)+1);
  109.   EnemyAdventTable[Length(EnemyAdventTable)-1].x         := x;
  110.   EnemyAdventTable[Length(EnemyAdventTable)-1].y         := y;
  111.   EnemyAdventTable[Length(EnemyAdventTable)-1].enemyType := enemyType;
  112.   EnemyAdventTable[Length(EnemyAdventTable)-1].lifes     := lifes;
  113. end;
  114.  
  115. function TLevelData.IndexOfEnemy(x, y: integer; enemyType: TEnemyType;
  116.   lifes: integer): integer;
  117. var
  118.   i: integer;
  119. begin
  120.   for i := 0 to Length(EnemyAdventTable) - 1 do
  121.   begin
  122.     if (EnemyAdventTable[i].x = x) and
  123.        (EnemyAdventTable[i].y = y) and
  124.        (EnemyAdventTable[i].enemyType = enemyType) and
  125.        (EnemyAdventTable[i].lifes = lifes) then
  126.     begin
  127.       result := i;
  128.       exit;
  129.     end;
  130.   end;
  131.   result := -1;
  132. end;
  133.  
  134. procedure TLevelData.Load(filename: string);
  135. var
  136.   sl, sl2: TStringList;
  137.   curline: integer;
  138.   ergebnis: string;
  139.   z, act: integer;
  140.   i, j: integer;
  141.   temp: string;
  142.   m: array[1..6] of tstrings;
  143.   tmpX, tmpY, tmpLifes: integer;
  144.   tmpEnemy: TEnemyType;
  145. begin
  146.   Clear;
  147.  
  148.   sl := TStringList.Create;
  149.   try
  150.     if EndsText('A1.lev', filename) then
  151.     begin
  152.       {$REGION 'Backwards compatibility level format 0.2 (split into 5-6 files)'}
  153.       m[1] := TStringList.create;
  154.       m[2] := TStringList.create;
  155.       m[3] := TStringList.create;
  156.       m[4] := TStringList.create;
  157.       m[5] := TStringList.create;
  158.       m[6] := TStringList.create;
  159.       try
  160.         for i := 1 to 6 do
  161.         begin
  162.           filename[Length(filename)-4] := IntToStr(i)[1]; // ...A2.sav, ...A3.sav, etc.
  163.           if FileExists(filename) then
  164.             m[i].loadfromfile(filename);
  165.         end;
  166.         m[1].strings[0] := '-624';
  167.         if m[6].Text = '' then m[6].Text := '30000';
  168.  
  169.         sl.Add('; SpaceMission 0.3');
  170.         sl.Add(temp);
  171.         for j := 0 to m[1].count-2 do
  172.         begin
  173.           for i := 0 to m[1].count-2 do
  174.           begin
  175.             if strtoint(m[1].strings[i]) > strtoint(m[1].strings[i+1]) then
  176.             begin
  177.               m[1].exchange(i, i+1);
  178.               m[2].exchange(i, i+1);
  179.               m[3].exchange(i, i+1);
  180.               m[4].exchange(i, i+1);
  181.               m[5].exchange(i, i+1);
  182.             end;
  183.           end;
  184.         end;
  185.         for i := 0 to m[3].count-1 do
  186.         begin
  187.           for j := 1 to 4 do
  188.           begin
  189.             if j = 1 then sl.Add(m[3].strings[i]);
  190.             if j = 2 then sl.Add(m[1].strings[i]);
  191.             if j = 3 then sl.Add(m[2].strings[i]);
  192.             if j = 4 then sl.Add(m[4].strings[i]);
  193.           end;
  194.         end;
  195.       finally
  196.         FreeAndNil(m[1]);
  197.         FreeAndNil(m[2]);
  198.         FreeAndNil(m[3]);
  199.         FreeAndNil(m[4]);
  200.         FreeAndNil(m[5]);
  201.         FreeAndNil(m[6]);
  202.       end;
  203.       {$ENDREGION}
  204.     end
  205.     else
  206.     begin
  207.       sl.LoadFromFile(filename);
  208.     end;
  209.  
  210.     if sl.Strings[0] = '; SpaceMission 0.3' then
  211.     begin
  212.       {$REGION 'Backwards compatibility level format 0.3'}
  213.       sl.Strings[0] := '; SpaceMission 0.4';
  214.       sl.Insert(1, '; SAV-File');
  215.       {$ENDREGION}
  216.     end;
  217.  
  218.     if sl.Strings[0] = '; SpaceMission 0.4' then
  219.     begin
  220.       {$REGION 'Backwards compatibility level format 0.4'}
  221.       sl2 := TStringList.Create;
  222.       try
  223.         z := 0;
  224.         act := 0;
  225.         while z < sl.Count do
  226.         begin
  227.           inc(z);
  228.           if z > 2 then inc(act);
  229.           if act = 5 then act := 1;
  230.           ergebnis := sl.Strings[z-1];
  231.           if ergebnis = '; SpaceMission 0.4' then
  232.             sl2.Add('; SpaceMission 1.0')
  233.           else
  234.           begin
  235.             if (ergebnis = '30000') and (z = 3) then
  236.               sl2.Add(IntTostr(DefaultLevelLength))
  237.             else
  238.             begin
  239.               //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
  240.               if (z < 4) or (z > 7) then
  241.               begin
  242.                 if act = 4 then
  243.                   sl2.Add(inttostr(strtoint(ergebnis) + 32 - (5 * (strtoint(ergebnis) div 37))))
  244.                 else
  245.                   sl2.Add(Ergebnis);
  246.               end;
  247.             end;
  248.           end;
  249.         end;
  250.         sl.Text := sl2.Text;
  251.       finally
  252.         FreeAndNil(sl2);
  253.       end;
  254.       {$ENDREGION}
  255.     end;
  256.  
  257.     if sl.Strings[0] = '; SpaceMission 1.0' then
  258.     begin
  259.       {$REGION 'Level format 1.0'}
  260.       if sl.Strings[1]  <> '; LEV-File' then
  261.       begin
  262.         raise Exception.Create('Dies ist keine SpaceMission Level-Datei');
  263.       end;
  264.  
  265.       LevelEditorLength := StrToInt(sl.Strings[2]);
  266.  
  267.       curline := 3;
  268.       while curline < sl.Count do
  269.       begin
  270.         tmpEnemy := TEnemyType(strtoint(sl.Strings[curline]));
  271.         Inc(curline);
  272.         tmpX := strtoint(sl.Strings[curline]);
  273.         Inc(curline);
  274.         tmpY := strtoint(sl.Strings[curline]);
  275.         Inc(curline);
  276.         tmpLifes := strtoint(sl.Strings[curline]);
  277.         Inc(curline);
  278.         AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes);
  279.       end;
  280.       {$ENDREGION}
  281.     end
  282.     else
  283.     begin
  284.       raise Exception.CreateFmt('Level-Format "%s" nicht unterstützt', [Copy(ergebnis, 3, Length(ergebnis)-2)]);
  285.     end;
  286.   finally
  287.     FreeAndNil(sl);
  288.   end;
  289.   SortEnemies;
  290. end;
  291.  
  292. procedure TLevelData.Save(filename: string);
  293. var
  294.   sl: TStringList;
  295.   i: integer;
  296. begin
  297.   sl := TStringList.Create;
  298.   try
  299.     sl.Add('; SpaceMission 1.0');
  300.     sl.Add('; LEV-File');
  301.     sl.Add(IntToStr(LevelEditorLength));
  302.     SortEnemies;
  303.     for i := 0 to Length(EnemyAdventTable)-1 do
  304.     begin
  305.       sl.Add(IntToStr(Ord(EnemyAdventTable[i].enemyType)));
  306.       sl.Add(IntToStr(EnemyAdventTable[i].x));
  307.       sl.Add(IntToStr(EnemyAdventTable[i].y));
  308.       sl.Add(IntToStr(EnemyAdventTable[i].lifes));
  309.     end;
  310.     sl.SaveToFile(filename);
  311.   finally
  312.     FreeAndNil(sl);
  313.   end;
  314. end;
  315.  
  316. procedure TLevelData.SortEnemies;
  317. var
  318.   i, n: integer;
  319.   e: TEnemyAdvent;
  320. begin
  321.   // Bubble Sort Algorithmus
  322.   for n := Length(EnemyAdventTable) downto 2 do
  323.   begin
  324.     for i := 0 to n - 2 do
  325.     begin
  326.       if
  327.         // Sort by X-coord (important for the game!)
  328.         (EnemyAdventTable[i].x > EnemyAdventTable[i+1].x)
  329.         or
  330.         // Sort by Y-coord (just cosmetics)
  331.         ((EnemyAdventTable[i].x = EnemyAdventTable[i+1].x) and (EnemyAdventTable[i].y > EnemyAdventTable[i+1].y))
  332.       then
  333.       begin
  334.         e := EnemyAdventTable[i];
  335.         EnemyAdventTable[i] := EnemyAdventTable[i + 1];
  336.         EnemyAdventTable[i + 1] := e;
  337.       end;
  338.     end;
  339.   end;
  340. end;
  341.  
  342. end.
  343.