Subversion Repositories spacemission

Rev

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