Subversion Repositories spacemission

Rev

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

  1. unit LevMain;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, MMSystem,
  7.   Dialogs, StdCtrls, ExtCtrls, Menus, DIB, DXClass, DXSprite, DXDraws,
  8.   DXSounds, Spin, ComCtrls{$IF CompilerVersion >= 23.0}, System.UITypes,
  9.   WinAPI.DirectDraw{$ENDIF}, DirectX, ComLevelReader, Global, IOUtils;
  10.  
  11. type
  12.   TMainForm = class(TDXForm)
  13.     MainMenu: TMainMenu;
  14.     Spiel: TMenuItem;
  15.     Beenden: TMenuItem;
  16.     Hilfe: TMenuItem;
  17.     Leer1: TMenuItem;
  18.     Level: TMenuItem;
  19.     Informationen: TMenuItem;
  20.     Enemy1: TRadioButton;
  21.     Enemy2: TRadioButton;
  22.     Enemy3: TRadioButton;
  23.     Enemy4: TRadioButton;
  24.     Enemy5: TRadioButton;
  25.     Enemy6: TRadioButton;
  26.     Enemy7: TRadioButton;
  27.     ScrollBar: TScrollBar;
  28.     Bevel1: TBevel;
  29.     Bevel2: TBevel;
  30.     SelLabel: TLabel;
  31.     SelPanel: TPanel;
  32.     Bevel3: TBevel;
  33.     SLabel1a: TLabel;
  34.     SLabel2a: TLabel;
  35.     SLabel1b: TLabel;
  36.     SLabel2b: TLabel;
  37.     SLabel0: TLabel;
  38.     Neu: TMenuItem;
  39.     Image1: TImage;
  40.     SLabel3a: TLabel;
  41.     SLabel3b: TLabel;
  42.     SLabel4a: TLabel;
  43.     SLabel4b: TLabel;
  44.     LivesLabel: TLabel;
  45.     StatusBar: TStatusBar;
  46.     N1: TMenuItem;
  47.     Spielfelderweitern1: TMenuItem;
  48.     SidePanel: TPanel;
  49.     LivesEdit: TSpinEdit;
  50.     AlleLeveldateienaktualisieren1: TMenuItem;
  51.     N2: TMenuItem;
  52.     Leveltesten1: TMenuItem;
  53.     Hilfe1: TMenuItem;
  54.     N3: TMenuItem;
  55.     AufUpdatesprfen1: TMenuItem;
  56.     N4: TMenuItem;
  57.     WasgibtesNeues1: TMenuItem;
  58.     Enemy8: TRadioButton;
  59.     procedure DXDrawFinalize(Sender: TObject);
  60.     procedure DXDrawInitialize(Sender: TObject);
  61.     procedure FormCreate(Sender: TObject);
  62.     procedure DXTimerTimer(Sender: TObject; LagCount: Integer);
  63.     procedure BeendenClick(Sender: TObject);
  64.     procedure FormDestroy(Sender: TObject);
  65.     procedure LevelClick(Sender: TObject);
  66.     procedure FormShow(Sender: TObject);
  67.     procedure InformationenClick(Sender: TObject);
  68.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  69.     procedure DXDrawMouseDown(Sender: TObject; Button: TMouseButton;
  70.       Shift: TShiftState; X, Y: Integer);
  71.     procedure EnemyClick(Sender: TObject);
  72.     procedure NeuClick(Sender: TObject);
  73.     procedure DXDrawMouseMove(Sender: TObject; Shift: TShiftState; X,
  74.       Y: Integer);
  75.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  76.     procedure Spielfelderweitern1Click(Sender: TObject);
  77.     procedure ScrollBarScroll(Sender: TObject; ScrollCode: TScrollCode;
  78.       var ScrollPos: Integer);
  79.     procedure AlleLeveldateienaktualisieren1Click(Sender: TObject);
  80.     procedure Leveltesten1Click(Sender: TObject);
  81.     procedure HilfeTopicClick(Sender: TObject);
  82.     procedure AufUpdatesprfen1Click(Sender: TObject);
  83.   private
  84.     function GetTestlevelFilename: string;
  85.   public
  86.     { VCL-Ersatz }
  87.     spriteengine: tdxspriteengine;
  88.     dxtimer: tdxtimer;
  89.     imagelist: tdximagelist;
  90.     dxdraw: tdxdraw;
  91.     { Variablen }
  92.     FMenuItem: integer;
  93.     LevData: TLevelData;
  94.     ScrollP: integer;
  95.     AltScrollPos: integer;
  96.     Boss: boolean;
  97.     LevChanged: boolean;
  98.     NumEnemys: integer;
  99.     function SelectedEnemyType: TEnemyType;
  100.     { Grafik-Routinen }
  101.     function GetSpriteGraphic(Sprite: TSpaceMissionGraphicSprite): TPictureCollectionItem;
  102.     { Level-Routinen }
  103.     procedure EnemyCreateSprite(x, y: integer; AEnemyType: TEnemyType; ALives: integer);
  104.     procedure DestroyLevel;
  105.     procedure RefreshFromLevData;
  106.     procedure AnzeigeAct;
  107.     { Initialisiations-Routinen }
  108.     procedure DXInit;
  109.     procedure ProgramInit;
  110.     { Farb-Routinen }
  111.     function ComposeColor(Dest, Src: TRGBQuad; Percent: Integer): TRGBQuad;
  112.     procedure PalleteAnim(Col: TRGBQuad; Time: Integer);
  113.   end;
  114.  
  115. var
  116.   MainForm: TMainForm;
  117.  
  118. implementation
  119.  
  120. uses
  121.   LevSplash, LevSpeicherung, ComInfo, LevOptions, ShellAPI, ComHilfe;
  122.  
  123. {$R *.DFM}
  124.  
  125. type
  126.   TBackground = class(TBackgroundSprite)
  127.   strict protected
  128.     procedure DoMove(MoveCount: Integer); override;
  129.   end;
  130.  
  131.   TEnemyOrItem = class(TImageSprite)
  132.   strict private
  133.     FLives: integer;
  134.     FEnemyType: TEnemyType;
  135.     FXCor: integer;
  136.     FCorInit: boolean;
  137.   strict protected
  138.     procedure DoMove(MoveCount: Integer); override;
  139.   public
  140.     constructor Create(AParent: TSprite; AEnemyType: TEnemyType; ALives: Integer); reintroduce;
  141.   end;
  142.  
  143. { TBackground }
  144.  
  145. procedure TBackground.DoMove(MoveCount: Integer);
  146. begin
  147.   X := -(MainForm.ScrollP * LevEditRasterW);
  148. end;
  149.  
  150. { TEnemy }
  151.  
  152. procedure TEnemyOrItem.DoMove(MoveCount: Integer);
  153. begin
  154.   if not FCorInit then
  155.   begin
  156.     FXCor := trunc(x) + (MainForm.ScrollP * LevEditRasterW);
  157.     FCorInit := true;
  158.   end;
  159.   if MainForm.LevData.IndexOfEnemy(FXCor, integer(round(Y)), FEnemyType, FLives) = -1 then dead;
  160.   X := FXCor - (MainForm.ScrollP * LevEditRasterW);
  161. end;
  162.  
  163. constructor TEnemyOrItem.Create(AParent: TSprite; AEnemyType: TEnemyType; ALives: Integer);
  164. begin
  165.   inherited Create(AParent);
  166.   if AEnemyType = etEnemyAttacker  then Image := MainForm.GetSpriteGraphic(smgEnemyAttacker);
  167.   if AEnemyType = etEnemyAttacker2 then Image := MainForm.GetSpriteGraphic(smgEnemyAttacker2);
  168.   if AEnemyType = etEnemyAttacker3 then Image := MainForm.GetSpriteGraphic(smgEnemyAttacker3);
  169.   if AEnemyType = etEnemyMeteor    then Image := MainForm.GetSpriteGraphic(smgEnemyMeteor);
  170.   if AEnemyType = etEnemyUFO       then Image := MainForm.GetSpriteGraphic(smgEnemyDisk);
  171.   if AEnemyType = etEnemyUFO2      then Image := MainForm.GetSpriteGraphic(smgEnemyDisk2);
  172.   if AEnemyType = etEnemyBoss      then Image := MainForm.GetSpriteGraphic(smgEnemyBoss);
  173.   if AEnemyType = etItemMedikit    then Image := MainForm.GetSpriteGraphic(smgItemMedikit);
  174.  
  175.   if not EnemyTypeHasLives(AEnemyType) then
  176.     FLives := 0
  177.   else
  178.     FLives := ALives;
  179.   FEnemyType := AEnemyType;
  180.   Width := Image.Width;
  181.   Height := Image.Height;
  182.   PixelCheck := True;
  183. end;
  184.  
  185. { TMainForm }
  186.  
  187. procedure TMainForm.DXInit;
  188. begin
  189.   Imagelist.Items.LoadFromFile(OwnDirectory+DxgFile);
  190.   ImageList.Items.MakeColorTable;
  191.   DXDraw.ColorTable := ImageList.Items.ColorTable;
  192.   DXDraw.DefColorTable := ImageList.Items.ColorTable;
  193.   DXDraw.UpdatePalette;
  194.   DXDraw.Initialize;
  195. end;
  196.  
  197. procedure TMainForm.FormCreate(Sender: TObject);
  198. resourcestring
  199.   SFileError = 'Die Datei kann von SpaceMission nicht geöffnet werden!';
  200.   SCaption = 'SpaceMission %s - Leveleditor';
  201. begin
  202.   { VCL-Ersatz start }
  203.   dxtimer := tdxtimer.create(self);
  204.   dxtimer.Interval := 100;
  205.   dxtimer.ActiveOnly := false;
  206.   dxtimer.Enabled := false;
  207.   dxtimer.OnTimer := DxTimerTimer;
  208.  
  209.   dxdraw := tdxdraw.Create(self);
  210.   dxdraw.Parent := self;
  211.   dxdraw.Left := 0;
  212.   dxdraw.Top := 0;
  213.   dxdraw.Width := SidePanel.Left;
  214.   dxdraw.Height := ScrollBar.Top;
  215.   dxdraw.AutoInitialize := False;
  216.   dxdraw.AutoSize := False;
  217.   dxdraw.Color := clBlack;
  218.   (*
  219.   dxdraw.Display.BitCount := 24;
  220.   dxdraw.Display.FixedBitCount := False;
  221.   dxdraw.Display.FixedRatio := False;
  222.   dxdraw.Display.FixedSize := False;
  223.   dxdraw.Display.Height := 600;
  224.   dxdraw.Display.Width := 800;
  225.   *)
  226.   dxdraw.Options := [doAllowReboot, doWaitVBlank, doAllowPalette256, doCenter, {doRetainedMode,} doHardware, doSelectDriver];
  227.   dxdraw.OnFinalize := DXDrawFinalize;
  228.   dxdraw.OnInitialize := DXDrawInitialize;
  229.   dxdraw.ParentShowHint := False;
  230.   dxdraw.ShowHint := False;
  231.   dxdraw.TabOrder := 0;
  232.   dxdraw.OnMouseDown := DXDrawMouseDown;
  233.   dxdraw.OnMouseMove := DXDrawMouseMove;
  234.  
  235.   spriteengine := tdxspriteengine.create(self);
  236.   spriteengine.DXDraw := dxdraw;
  237.  
  238.   imagelist := tdximagelist.create(self);
  239.   imagelist.DXDraw := dxdraw;
  240.  
  241.   { VCL-Ersatz ende }
  242.  
  243.   LivesEdit.MinValue := 1;
  244.   LivesEdit.MaxValue := MaxPossibleEnemyLives;
  245.   LivesEdit.Value := 1;
  246.  
  247.   Enemy1.Checked := true;
  248.   EnemyClick(Enemy1);
  249.   // Leeres Level am Anfang braucht keine Beenden-Bestätigung.
  250.   // LevChanged := true;
  251.  
  252.   //Application.Title := Format(SCaption, [ProgramVersion]);
  253.   Caption := Format(SCaption, [ProgramVersion]);
  254.   DXInit;
  255.   LevData := TLevelData.create;
  256.   ProgramInit;
  257.   DestroyLevel;
  258.   if (paramcount > 0) and (fileexists(paramstr(1))) and (ExtractFileExt(paramstr(1)).ToLower = '.lev') then
  259.   begin
  260.     try
  261.       LevData.RasterErzwingen := true;
  262.       LevData.LoadFromFile(paramstr(1));
  263.     except
  264.       on E: Exception do
  265.       begin
  266.         showmessage(SFileError + ' ' +E.Message);
  267.         DestroyLevel;
  268.       end;
  269.     end;
  270.     RefreshFromLevData;
  271.     LevChanged := false;
  272.     AnzeigeAct;
  273.   end;
  274. end;
  275.  
  276. procedure TMainForm.FormDestroy(Sender: TObject);
  277. var
  278.   tmp: string;
  279. begin
  280.   FreeAndNil(dxdraw);
  281.   FreeAndNil(LevData);
  282.   //FreeAndNil(spriteengine);
  283.   FreeAndNil(dxtimer);
  284.   FreeAndNil(imagelist);
  285.   tmp := GetTestlevelFilename;
  286.  
  287.   // SpaceMission.exe only loads a file once, so we can delete any test level
  288.   if FileExists(tmp) then DeleteFile(GetTestlevelFilename);
  289. end;
  290.  
  291. procedure TMainForm.BeendenClick(Sender: TObject);
  292. begin
  293.   close;
  294. end;
  295.  
  296. procedure TMainForm.DXDrawInitialize(Sender: TObject);
  297. begin
  298.   if Assigned(DXTimer) then DXTimer.Enabled := True;
  299. end;
  300.  
  301. procedure TMainForm.DXDrawFinalize(Sender: TObject);
  302. begin
  303.   if Assigned(DXTimer) then DXTimer.Enabled := False;
  304. end;
  305.  
  306. procedure TMainForm.DXTimerTimer(Sender: TObject; LagCount: Integer);
  307. begin
  308.   if not DXDraw.CanDraw then exit;
  309.   LagCount := 1000 div 60;
  310.   SpriteEngine.Move(LagCount);
  311.   SpriteEngine.Dead;
  312.   DxDraw.Surface.Fill(0);
  313.   SpriteEngine.Draw;
  314.   DXDraw.Flip;
  315. end;
  316.  
  317. function TMainForm.ComposeColor(Dest, Src: TRGBQuad; Percent: Integer): TRGBQuad;
  318. begin
  319.   with Result do
  320.   begin
  321.     rgbRed := Src.rgbRed+((Dest.rgbRed-Src.rgbRed)*Percent div 256);
  322.     rgbGreen := Src.rgbGreen+((Dest.rgbGreen-Src.rgbGreen)*Percent div 256);
  323.     rgbBlue := Src.rgbBlue+((Dest.rgbBlue-Src.rgbBlue)*Percent div 256);
  324.     rgbReserved := 0;
  325.   end;
  326. end;
  327.  
  328. procedure TMainForm.PalleteAnim(Col: TRGBQuad; Time: Integer);
  329. var
  330.   i: Integer;
  331.   t, t2: DWORD;
  332.   ChangePalette: Boolean;
  333.   c: Integer;
  334. begin
  335.   if DXDraw.Initialized then
  336.   begin
  337.     c := DXDraw.Surface.ColorMatch(RGB(Col.rgbRed, Col.rgbGreen, Col.rgbBlue));
  338.     ChangePalette := False;
  339.     if DXDraw.CanPaletteAnimation then
  340.     begin
  341.       t := GetTickCount;
  342.       while Abs(GetTickCount-t)<Time do
  343.       begin
  344.         t2 := Trunc(Abs(GetTickCount-t)/Time*255);
  345.         for i := 0 to 255 do
  346.           DXDraw.ColorTable[i] := ComposeColor(Col, DXDraw.DefColorTable[i], t2);
  347.         DXDraw.UpdatePalette;
  348.         ChangePalette := True;
  349.       end;
  350.     end else
  351.       Sleep(Time);
  352.     for i := 0 to 4 do
  353.     begin
  354.       DXDraw.Surface.Fill(c);
  355.       DXDraw.Flip;
  356.     end;
  357.     if ChangePalette then
  358.     begin
  359.       DXDraw.ColorTable := DXDraw.DefColorTable;
  360.       DXDraw.UpdatePalette;
  361.     end;
  362.     DXDraw.Surface.Fill(c);
  363.     DXDraw.Flip;
  364.   end;
  365. end;
  366.  
  367. procedure TMainForm.ProgramInit;
  368. {var
  369.   i, j: Integer;}
  370. begin
  371.   sleep(500);
  372.   //PlayerSprite
  373.   with TBackground.Create(SpriteEngine.Engine) do
  374.   begin
  375.     SetMapSize(1, 1);
  376.     Image := MainForm.GetSpriteGraphic(smgStar3);
  377.     Z := -13;
  378.     Y := 40;
  379.     Tile := True;
  380.   end;
  381.   with TBackground.Create(SpriteEngine.Engine) do
  382.   begin
  383.     SetMapSize(1, 1);
  384.     Image := MainForm.GetSpriteGraphic(smgStar2);
  385.     Z := -12;
  386.     Y := 30;
  387.     Tile := True;
  388.   end;
  389.   with TBackground.Create(SpriteEngine.Engine) do
  390.   begin
  391.     SetMapSize(1, 1);
  392.     Image := MainForm.GetSpriteGraphic(smgStar1);
  393.     Z := -11;
  394.     Y := 10;
  395.     Tile := True;
  396.   end;
  397.   with TBackground.Create(SpriteEngine.Engine) do
  398.   begin
  399.     SetMapSize(1, 1);
  400.     Image := MainForm.GetSpriteGraphic(smgMatrix);
  401.     Z := -10;
  402.     Tile := True;
  403.   end;
  404.   {with TBackground.Create(SpriteEngine.Engine) do
  405.   begin
  406.     SetMapSize(200, 10);
  407.     Y := 10;
  408.     Z := -13;
  409.     FSpeed := 1 / 2;
  410.     Tile := True;
  411.     for i := 0 to MapHeight-1 do
  412.     begin
  413.       for j := 0 to MapWidth-1 do
  414.       begin
  415.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 8);
  416.         if Random(100)<95 then Chips[j, i] := -1;
  417.       end;
  418.     end;
  419.   end;
  420.   with TBackground.Create(SpriteEngine.Engine) do
  421.   begin
  422.     SetMapSize(200, 10);
  423.     Y := 30;
  424.     Z := -12;
  425.     FSpeed := 1;
  426.     Tile := True;
  427.     for i := 0 to MapHeight-1 do
  428.     begin
  429.       for j := 0 to MapWidth-1 do
  430.       begin
  431.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 4);
  432.         if Random(100)<95 then Chips[j, i] := -1;
  433.       end;
  434.     end;
  435.   end;
  436.   with TBackground.Create(SpriteEngine.Engine) do
  437.   begin
  438.     SetMapSize(200, 10);
  439.     Y := 40;
  440.     Z := -11;
  441.     FSpeed := 2;
  442.     Tile := True;
  443.     for i := 0 to MapHeight-1 do
  444.     begin
  445.       for j := 0 to MapWidth-1 do
  446.       begin
  447.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 2);
  448.         if Random(100)<95 then Chips[j, i] := -1;
  449.       end;
  450.     end;
  451.   end;}
  452.   PalleteAnim(RGBQuad(0, 0, 0), 300);
  453.   mainform.Visible := true;
  454. end;
  455.  
  456. procedure TMainForm.RefreshFromLevData;
  457. var
  458.   i: integer;
  459. begin
  460.   MainForm.ScrollBar.Max := MainForm.LevData.LevelEditorLength;
  461.   for i := 0 to MainForm.LevData.CountEnemies - 1 do
  462.   begin
  463.     MainForm.EnemyCreateSprite(
  464.       MainForm.LevData.EnemyAdventTable[i].x,
  465.       MainForm.LevData.EnemyAdventTable[i].y,
  466.       MainForm.LevData.EnemyAdventTable[i].enemyType,
  467.       MainForm.LevData.EnemyAdventTable[i].lifes
  468.     );
  469.   end;
  470.   MainForm.NumEnemys := MainForm.LevData.CountEnemies;
  471.   MainForm.Boss := MainForm.LevData.HasBoss;
  472.   AnzeigeAct;
  473. end;
  474.  
  475. procedure TMainForm.LevelClick(Sender: TObject);
  476. begin
  477.   speicherungform.showmodal;
  478. end;
  479.  
  480. procedure TMainForm.Leveltesten1Click(Sender: TObject);
  481. var
  482.   sav: TSaveData;
  483.   tmp: string;
  484. begin
  485.   KillTask(SpaceMissionExe);
  486.  
  487.   sav := TSaveData.Create;
  488.   try
  489.     sav.Score := 0;
  490.     sav.Life := 6;
  491.     if Assigned(SpeicherungForm) then
  492.       sav.Level := SpeicherungForm.LevelNumber.Value
  493.     else
  494.       sav.Level := 1;
  495.     sav.GameMode := gmLevels;
  496.     sav.LevelData := TlevelData.Create;
  497.     sav.LevelData.Assign(LevData);
  498.     tmp := GetTestlevelFilename;
  499.     sav.SaveToFile(tmp);
  500.     ShellExecute(Handle, 'open', PChar(OwnDirectory+SpaceMissionExe), PChar('"'+tmp+'"'), PChar(OwnDirectory), SW_NORMAL); // do not localize
  501.   finally
  502.     FreeAndNil(sav);
  503.   end;
  504. end;
  505.  
  506. procedure TMainForm.FormShow(Sender: TObject);
  507. begin
  508.   if Assigned(SplashForm) then
  509.   begin
  510.     SplashForm.Hide;
  511.     FreeAndNil(SplashForm);
  512.   end;
  513.  
  514.   dxtimer.Enabled := true;
  515.   dxtimer.ActiveOnly := true;
  516. end;
  517.  
  518. function TMainForm.GetSpriteGraphic(
  519.   Sprite: TSpaceMissionGraphicSprite): TPictureCollectionItem;
  520. begin
  521.   if (Sprite<>smgNone) and (imagelist.Items.Count >= Ord(Sprite)) then
  522.     result := imagelist.Items.Items[Ord(Sprite)-1]
  523.   else
  524.     result := nil;
  525. end;
  526.  
  527. function TMainForm.GetTestlevelFilename: string;
  528. begin
  529.   result := IncludeTrailingPathDelimiter(TPath.GetTempPath) + 'SpaceMissionTest.sav'; // do not localize
  530. end;
  531.  
  532. procedure TMainForm.HilfeTopicClick(Sender: TObject);
  533. // Please keep this code in-sync with GamMain.pas
  534. var
  535.   bakTimerEnabled: boolean;
  536. begin
  537.   bakTimerEnabled := dxtimer.Enabled;
  538.   try
  539.     dxtimer.Enabled := false;
  540.     HilfeForm.Caption := TMenuItem(Sender).Caption;
  541.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, '&&', #1, [rfReplaceAll]);
  542.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, '&', '', [rfReplaceAll]);
  543.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, #1, '&', [rfReplaceAll]);
  544.     HilfeForm.ShowMarkDownHelp(OwnDirectory+TMenuItem(Sender).Hint);
  545.     HilfeForm.ShowModal;
  546.   finally
  547.     dxtimer.Enabled := bakTimerEnabled;
  548.   end;
  549. end;
  550.  
  551. procedure TMainForm.InformationenClick(Sender: TObject);
  552. begin
  553.   mainform.dxtimer.enabled := false;
  554.   InfoForm.showmodal;
  555.   mainform.dxtimer.enabled := true;
  556. end;
  557.  
  558. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
  559. begin
  560.   SpriteEngine.Engine.Clear;
  561.   DXTimer.Enabled := False;
  562. end;
  563.  
  564. procedure TMainForm.DXDrawMouseDown(Sender: TObject; Button: TMouseButton;
  565.   Shift: TShiftState; X, Y: Integer);
  566. var
  567.   i: TEnemyType;
  568.   j, k, l, ex, ey: integer;
  569.   ok, breaked: boolean;
  570. begin
  571.   ex := trunc(x/LevEditRasterW) * LevEditRasterW;
  572.   ey := trunc(y/LevEditRasterH) * LevEditRasterH;
  573.   EnemyCreateSprite(ex, ey, SelectedEnemyType, LivesEdit.Value);
  574.   breaked := false;
  575.   { Setzen }
  576.   if Button = mbLeft then
  577.   begin
  578.     ok := true;
  579.     if (SelectedEnemyType = etEnemyBoss) and boss then
  580.       ok := false // boss already exists
  581.     else
  582.     begin
  583.       for i := Low(TEnemyType) to High(TEnemyType) do
  584.       begin
  585.         for j := 0 to MaxPossibleEnemyLives do
  586.         begin
  587.           if boss then
  588.           begin
  589.             for k := 0 to BossWidth-1 do
  590.             begin
  591.               for l := 0 to BossHeight-2 do
  592.               begin
  593.                 if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), etEnemyBoss, j) <> -1 then
  594.                 begin
  595.                   ok := false;
  596.                   break;
  597.                 end;
  598.               end;
  599.               if not ok then break;
  600.             end;
  601.             if not ok then break;
  602.           end;
  603.           if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
  604.           begin
  605.             ok := false;
  606.             break;
  607.           end;
  608.         end;
  609.         if not ok then break;
  610.       end;
  611.     end;
  612.     if ok then
  613.     begin
  614.       if EnemyTypeHasLives(SelectedEnemyType) then
  615.         LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, LivesEdit.Value)
  616.       else
  617.         LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, 0);
  618.       inc(NumEnemys);
  619.       if SelectedEnemyType = etEnemyBoss then boss := true;
  620.     end
  621.     else beep;
  622.   end
  623.   { Löschen }
  624.   else if Button = mbRight then
  625.   begin
  626.     for i := Low(TEnemyType) to High(TEnemyType) do
  627.     begin
  628.       for j := 0 to MaxPossibleEnemyLives do
  629.       begin
  630.         if boss and (i = etEnemyBoss) then
  631.         begin
  632.           for k := 0 to BossWidth - 1 do
  633.           begin
  634.             for l := 0 to BossHeight - 1 do
  635.             begin
  636.               if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
  637.               begin
  638.                 LevData.DeleteEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j);
  639.                 Boss := false;
  640.                 dec(NumEnemys);
  641.                 breaked := true;
  642.                 break;
  643.               end;
  644.             end;
  645.             if breaked then break;
  646.           end;
  647.         end;
  648.         if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
  649.         begin
  650.           LevData.DeleteEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j);
  651.           if i = etEnemyBoss then Boss := false;
  652.           dec(NumEnemys);
  653.           breaked := true;
  654.           break;
  655.         end;
  656.       end;
  657.       if breaked then break;
  658.     end;
  659.   end;
  660.   LevChanged := true;
  661.   AnzeigeAct;
  662. end;
  663.  
  664. procedure TMainForm.EnemyClick(Sender: TObject);
  665. var
  666.   et: TEnemyType;
  667. begin
  668.   et := SelectedEnemyType;
  669.   Image1.Left := -(87 * (Ord(et) - 1)) + 1;
  670.   LivesEdit.Enabled := EnemyTypeHasLives(et);
  671.   LivesLabel.Enabled := EnemyTypeHasLives(et);
  672. end;
  673.  
  674. procedure TMainForm.EnemyCreateSprite(x, y: integer; AEnemyType: TEnemyType; ALives: integer);
  675. var
  676.   Enemy: TSprite;
  677. begin
  678.   Enemy := TEnemyOrItem.Create(SpriteEngine.Engine, AEnemyType, ALives);
  679.   Enemy.x := x;
  680.   Enemy.y := y;
  681. end;
  682.  
  683. procedure TMainForm.DestroyLevel;
  684. begin
  685.   ScrollBar.Position := 0; // this doesn't call ScrollBarScroll()
  686.   ScrollP := 0;
  687.   LevData.Clear;
  688.   ScrollBar.Max := LevData.LevelEditorLength;
  689.   NumEnemys := 0;
  690.   Boss := false;
  691.   LevChanged := true;
  692.   LivesEdit.Value := 1;
  693.   Enemy1.Checked := true;
  694.   EnemyClick(Enemy1);
  695.   AnzeigeAct;
  696. end;
  697.  
  698. procedure TMainForm.AlleLeveldateienaktualisieren1Click(Sender: TObject);
  699. var
  700.   i: integer;
  701. begin
  702.   // Just for internal/development purposes
  703.   for i := 1 to MaxPossibleLevels do
  704.   begin
  705.     if FileExists('Levels\Level '+IntToStr(i)+'.lev') then
  706.     begin
  707.       LevData.RasterErzwingen := true;
  708.       LevData.LoadFromFile('Levels\Level '+IntToStr(i)+'.lev');
  709.       LevData.SaveToFile('Levels\Level '+IntToStr(i)+'.lev');
  710.     end;
  711.   end;
  712. end;
  713.  
  714. procedure TMainForm.AnzeigeAct;
  715. resourcestring
  716.   SYes = 'Ja';
  717.   SNo = 'Nein';
  718. begin
  719.   SLabel1b.Caption := inttostr(NumEnemys);
  720.   if Boss then SLabel2b.Caption := SYes else SLabel2b.Caption := SNo;
  721.   SLabel3b.Caption := inttostr(ScrollBar.Max);
  722.   if LevChanged then
  723.   begin
  724.     SLabel4a.Font.Color := $00000096;
  725.     SLabel4b.Font.Color := $00000096;
  726.     SLabel4b.Caption := SNo;
  727.   end
  728.   else
  729.   begin
  730.     SLabel4a.Font.Color := $00009600;
  731.     SLabel4b.Font.Color := $00009600;
  732.     SLabel4b.Caption := SYes;
  733.   end;
  734. end;
  735.  
  736. procedure TMainForm.AufUpdatesprfen1Click(Sender: TObject);
  737. begin
  738.   CheckForUpdates('spacemission', ProgramVersion); // do not localize
  739. end;
  740.  
  741. procedure TMainForm.NeuClick(Sender: TObject);
  742. resourcestring
  743.   SReallyDeleteLevel = 'Level wirklich löschen?';
  744. begin
  745.   if MessageDlg(SReallyDeleteLevel, mtConfirmation, mbYesNoCancel, 0) = mrYes then
  746.     DestroyLevel;
  747. end;
  748.  
  749. procedure TMainForm.DXDrawMouseMove(Sender: TObject; Shift: TShiftState; X,
  750.   Y: Integer);
  751. resourcestring
  752.   status_info = 'Zeigen Sie mit dem Mauszeiger auf eine Einheit, um deren Eigenschaften anzuzeigen...';
  753.   status_lives = 'Leben: ';
  754.   status_nolives = 'Einheit hat keine Lebensangabe';
  755.   SUnknownEnemyType = '???';
  756. var
  757.   i: TEnemyType;
  758.   ex, ey, j, k, l: integer;
  759.   lifes: integer;
  760.   enemyType: TEnemyType;
  761.   enemyName: string;
  762.   breaked: boolean;
  763. begin
  764.   if sender <> DxDraw then
  765.   begin
  766.     StatusBar.SimpleText := ' ' + status_info;
  767.     exit;
  768.   end;
  769.   ex := trunc(x/LevEditRasterW) * LevEditRasterW;
  770.   ey := trunc(y/LevEditRasterH) * LevEditRasterH;
  771.   lifes := -1;
  772.   enemyType := etUnknown;
  773.   breaked := false;
  774.   for i := Low(TEnemyType) to High(TEnemyType) do
  775.   begin
  776.     for j := 0 to MaxPossibleEnemyLives do
  777.     begin
  778.       if boss and (i = etEnemyBoss) then
  779.       begin
  780.         for k := 0 to BossWidth - 1 do
  781.         begin
  782.           for l := 0 to BossHeight - 1 do
  783.           begin
  784.             if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
  785.             begin
  786.               lifes := j;
  787.               breaked := true;
  788.               break;
  789.             end;
  790.           end;
  791.           if breaked then break;
  792.         end;
  793.       end;
  794.       if (breaked = false) and (LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1) then
  795.       begin
  796.         lifes := j;
  797.         enemyType := i;
  798.         breaked := true;
  799.         break;
  800.       end;
  801.     end;
  802.     if breaked then break;
  803.   end;
  804.   if lifes <> -1 then
  805.   begin
  806.     if Ord(enemyType) = 1 then enemyName := Enemy1.Caption
  807.     else if Ord(enemyType) = 2 then enemyName := Enemy2.Caption
  808.     else if Ord(enemyType) = 3 then enemyName := Enemy3.Caption
  809.     else if Ord(enemyType) = 4 then enemyName := Enemy4.Caption
  810.     else if Ord(enemyType) = 5 then enemyName := Enemy5.Caption
  811.     else if Ord(enemyType) = 6 then enemyName := Enemy6.Caption
  812.     else if Ord(enemyType) = 7 then enemyName := Enemy7.Caption
  813.     else if Ord(enemyType) = 8 then enemyName := Enemy8.Caption
  814.     else enemyName := SUnknownEnemyType;
  815.     if lifes > 0 then
  816.       StatusBar.SimpleText := ' ' + enemyName + ' - ' + status_lives + inttostr(lifes)
  817.     else
  818.       StatusBar.SimpleText := ' ' + enemyName + ' - ' + status_nolives;
  819.   end
  820.   else
  821.     StatusBar.SimpleText := ' ' + status_info;
  822. end;
  823.  
  824. procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  825. resourcestring
  826.   SExitWithoutSave = 'Beenden ohne abspeichern?';
  827. begin
  828.   if Assigned(LevData) and LevChanged and (LevData.CountEnemies>0) then
  829.     CanClose := MessageDlg(SExitWithoutSave, mtConfirmation, mbYesNoCancel, 0) = mrYes;
  830. end;
  831.  
  832. procedure TMainForm.Spielfelderweitern1Click(Sender: TObject);
  833. begin
  834.   LevelForm.Aktualisieren;
  835.   LevelForm.showmodal;
  836. end;
  837.  
  838. procedure TMainForm.ScrollBarScroll(Sender: TObject;
  839.   ScrollCode: TScrollCode; var ScrollPos: Integer);
  840. begin
  841.   ScrollP := ScrollPos;
  842. end;
  843.  
  844. function TMainForm.SelectedEnemyType: TEnemyType;
  845. begin
  846.   if Enemy1.Checked then result := etEnemyAttacker
  847.   else if Enemy2.Checked then result := etEnemyAttacker2
  848.   else if Enemy3.Checked then result := etEnemyAttacker3
  849.   else if Enemy4.Checked then result := etEnemyMeteor
  850.   else if Enemy5.Checked then result := etEnemyUFO
  851.   else if Enemy6.Checked then result := etEnemyUFO2
  852.   else if Enemy7.Checked then result := etEnemyBoss
  853.   else if Enemy8.Checked then result := etItemMedikit
  854.   else result := etUnknown;
  855. end;
  856.  
  857. end.
  858.  
  859.