Subversion Repositories spacemission

Rev

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

  1. unit GamMain;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, ExtCtrls, Menus, DIB, DXClass, DXSprite, DXDraws, DXInput, DXSounds,
  8.   ShellAPI, DirectX{$IF CompilerVersion >= 23.0},
  9.   System.UITypes{$IFEND}, ComLevelReader, DirectMusic, Global;
  10.  
  11. type
  12.   TGameScene = (
  13.     gsNone,
  14.     gsTitle,
  15.     gsMain,
  16.     gsGameOver,
  17.     gsNewLevel,
  18.     gsWin
  19.   );
  20.  
  21.   TGameInterval = (
  22.     giLeicht,
  23.     giMittel,
  24.     giSchwer,
  25.     giMaster
  26.   );
  27.  
  28.   TBackground = class(TBackgroundSprite)
  29.   strict private
  30.     FSpeed: Double;
  31.   strict protected
  32.     procedure DoMove(MoveCount: Integer); override;
  33.   public
  34.     property Speed: Double read FSpeed write FSpeed;
  35.   end;
  36.  
  37.   TBackgroundSpecial = class(TBackgroundSprite)
  38.   strict private
  39.     FSpeed: Double;
  40.   strict protected
  41.     procedure DoMove(MoveCount: Integer); override;
  42.   public
  43.     property Speed: Double read FSpeed write FSpeed;
  44.   end;
  45.  
  46.   TExplosion = class(TImageSprite)
  47.   strict private
  48.     FCounter: Integer;
  49.   strict protected
  50.     procedure DoMove(MoveCount: Integer); override;
  51.   public
  52.     constructor Create(AParent: TSprite); override;
  53.   end;
  54.  
  55.   TPlayerOrEnemyOrItemState = (
  56.     pesUnknown,
  57.     pesNormal,
  58.     pesExploding, // only boss, as preparation of pesDead
  59.     pesDead,
  60.     pesDeadVanished,
  61.     pesFlyaway, // only player at mission end
  62.     pesEntering,
  63.     pesHovering // only some kind of enemies
  64.   );
  65.  
  66.   TPlayerOrEnemyOrItem = class abstract (TImageSprite)
  67.   strict protected
  68.     State: TPlayerOrEnemyOrItemState;
  69.   end;
  70.  
  71.   TPlayerSprite = class(TPlayerOrEnemyOrItem)
  72.   private
  73.     FTamaCount: Integer; // accessed by TPlayerTamaSprite.Destroy
  74.   strict private
  75.     FCounter: Integer;
  76.     FOldTamaTime: Integer;
  77.   strict protected
  78.     procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
  79.     procedure DoMove(MoveCount: Integer); override;
  80.   public
  81.     constructor Create(AParent: TSprite); override;
  82.     procedure FlyAway;
  83.   end;
  84.  
  85.   TPlayerTamaSprite = class(TImageSprite)
  86.   strict private
  87.     FPlayerSprite: TPlayerSprite;
  88.   strict protected
  89.     property PlayerSprite: TPlayerSprite read FPlayerSprite write FPlayerSprite;
  90.     procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
  91.     procedure DoMove(MoveCount: Integer); override;
  92.   public
  93.     constructor Create(AParent: TSprite; APlayerSprite: TPlayerSprite); reintroduce;
  94.     destructor Destroy; override;
  95.   end;
  96.  
  97.   TEnemyClass = class of TEnemy;
  98.   TEnemy = class abstract (TPlayerOrEnemyOrItem)
  99.   strict protected
  100.     FCounter: Integer;
  101.     FLife: integer;
  102.     procedure HitEnemy(ADead: Boolean); virtual;
  103.   public
  104.     property Life: integer read FLife;
  105.     procedure Hit(AHitStrength: integer = 1);
  106.     constructor Create(AParent: TSprite; ALifes: integer); reintroduce; virtual;
  107.     destructor Destroy; override;
  108.   end;
  109.  
  110.   TEnemyTama = class(TImageSprite)
  111.   strict private
  112.     FEnemySprite: TSprite;
  113.   strict protected
  114.     property EnemySprite: TSprite read FEnemySprite write FEnemySprite;
  115.     procedure DoMove(MoveCount: Integer); override;
  116.   public
  117.     constructor Create(AParent: TSprite; AEnemySprite: TSprite); reintroduce;
  118.   end;
  119.  
  120.   TEnemyMeteor = class(TEnemy)
  121.   strict protected
  122.     procedure DoMove(MoveCount: Integer); override;
  123.     procedure HitEnemy(ADead: Boolean); override;
  124.   public
  125.     constructor Create(AParent: TSprite; ALifes: integer); override;
  126.   end;
  127.  
  128.   TEnemyUFO = class(TEnemy)
  129.   strict protected
  130.     procedure DoMove(MoveCount: Integer); override;
  131.     procedure HitEnemy(ADead: Boolean); override;
  132.   public
  133.     constructor Create(AParent: TSprite; ALifes: integer); override;
  134.   end;
  135.  
  136.   TEnemyUFO2 = class(TEnemy)
  137.   strict private
  138.     FCounter: Integer;
  139.     FTamaCount: Integer;
  140.     FOldTamaTime: Integer;
  141.   strict protected
  142.     procedure DoMove(MoveCount: Integer); override;
  143.     procedure HitEnemy(ADead: Boolean); override;
  144.   public
  145.     constructor Create(AParent: TSprite; ALifes: integer); override;
  146.   end;
  147.  
  148.   TEnemyAttacker = class(TEnemy)
  149.   strict protected
  150.     procedure DoMove(MoveCount: Integer); override;
  151.     procedure HitEnemy(ADead: Boolean); override;
  152.   public
  153.     constructor Create(AParent: TSprite; ALifes: integer); override;
  154.   end;
  155.  
  156.   TEnemyAttacker2 = class(TEnemy)
  157.   strict private
  158.     FCounter: Integer;
  159.     FTamaF: Integer;
  160.     FTamaT: Integer;
  161.     FPutTama: Boolean;
  162.   strict protected
  163.     procedure DoMove(MoveCount: Integer); override;
  164.     procedure HitEnemy(ADead: Boolean); override;
  165.   public
  166.     constructor Create(AParent: TSprite; ALifes: integer); override;
  167.   end;
  168.  
  169.   TEnemyAttacker3 = class(TEnemy)
  170.   strict private
  171.     FCounter: Integer;
  172.     FTamaCount: Integer;
  173.     FOldTamaTime: Integer;
  174.   strict protected
  175.     procedure DoMove(MoveCount: Integer); override;
  176.     procedure HitEnemy(ADead: Boolean); override;
  177.   public
  178.     constructor Create(AParent: TSprite; ALifes: integer); override;
  179.   end;
  180.  
  181.   TEnemyBoss = class(TEnemy)
  182.   strict private
  183.     FCounter: Integer;
  184.     FTamaF: Integer;
  185.     FTamaT: Integer;
  186.     FPutTama: Boolean;
  187.     waiter1, waiter2: integer;
  188.   strict protected
  189.     procedure DoMove(MoveCount: Integer); override;
  190.     procedure HitEnemy(ADead: Boolean); override;
  191.   public
  192.     constructor Create(AParent: TSprite; ALifes: integer); override;
  193.   end;
  194.  
  195.   TItemClass = class of TItem;
  196.   TItem = class abstract (TPlayerOrEnemyOrItem)
  197.   strict protected
  198.     procedure DoMove(MoveCount: Integer); override;
  199.   public
  200.     procedure Collected; virtual;
  201.   end;
  202.  
  203.   TItemMedikit = class(TItem)
  204.   public
  205.     procedure Collected; override;
  206.     constructor Create(AParent: TSprite); override;
  207.   end;
  208.  
  209.   TMainForm = class(TDXForm)
  210.     MainMenu: TMainMenu;
  211.     Spiel: TMenuItem;
  212.     GameStart: TMenuItem;
  213.     GamePause: TMenuItem;
  214.     Beenden: TMenuItem;
  215.     Einstellungen: TMenuItem;
  216.     OptionMusic: TMenuItem;
  217.     Hilfe: TMenuItem;
  218.     OptionSound: TMenuItem;
  219.     Leer3: TMenuItem;
  220.     Spielstand: TMenuItem;
  221.     Leer5: TMenuItem;
  222.     Neustart: TMenuItem;
  223.     Spielgeschwindigkeit: TMenuItem;
  224.     Leicht: TMenuItem;
  225.     Mittel: TMenuItem;
  226.     Schwer: TMenuItem;
  227.     Informationen: TMenuItem;
  228.     Leer6: TMenuItem;
  229.     Leer1: TMenuItem;
  230.     Cheat: TMenuItem;
  231.     CheckUpdates: TMenuItem;
  232.     Master: TMenuItem;
  233.     Hilfe1: TMenuItem;
  234.     N1: TMenuItem;
  235.     Wasgibtesneues1: TMenuItem;
  236.     procedure DXDrawFinalize(Sender: TObject);
  237.     procedure DXDrawInitialize(Sender: TObject);
  238.     procedure FormCreate(Sender: TObject);
  239.     procedure DXTimerTimer(Sender: TObject; LagCount: Integer);
  240.     procedure DXTimerActivate(Sender: TObject);
  241.     procedure DXTimerDeactivate(Sender: TObject);
  242.     procedure DXDrawInitializing(Sender: TObject);
  243.     procedure GameStartClick(Sender: TObject);
  244.     procedure GamePauseClick(Sender: TObject);
  245.     procedure BeendenClick(Sender: TObject);
  246.     procedure OptionSoundClick(Sender: TObject);
  247.     procedure OptionMusicClick(Sender: TObject);
  248.     procedure SpielstandClick(Sender: TObject);
  249.     procedure NeustartClick(Sender: TObject);
  250.     procedure LeichtClick(Sender: TObject);
  251.     procedure MittelClick(Sender: TObject);
  252.     procedure SchwerClick(Sender: TObject);
  253.     procedure FormShow(Sender: TObject);
  254.     procedure InformationenClick(Sender: TObject);
  255.     procedure CheatClick(Sender: TObject);
  256.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  257.     procedure FormDestroy(Sender: TObject);
  258.     procedure CheckUpdatesClick(Sender: TObject);
  259.     procedure MasterClick(Sender: TObject);
  260.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  261.     procedure HilfeTopicClick(Sender: TObject);
  262.   private
  263.     ProgrammGestartet: boolean;
  264.     FInterval: TGameInterval;
  265.     FScene: TGameScene;
  266.     FMusic: TSpaceMissionMusicTrack;
  267.     FBlink: DWORD;
  268.     FBlinkTime: DWORD;
  269.     FFrame, FAngle, FCounter, FEnemyAdventPos: Integer;
  270.     PlayerSprite: TPlayerSprite;
  271.     TimerCS: TRTLCriticalSection;
  272.     procedure StartScene(Scene: TGameScene);
  273.     procedure EndScene;
  274.     procedure BlinkStart;
  275.     procedure BlinkUpdate;
  276.     procedure StartSceneTitle;
  277.     procedure SceneTitle;
  278.     procedure EndSceneTitle;
  279.     procedure StartSceneMain;
  280.     procedure SceneMain;
  281.     procedure EndSceneMain;
  282.     procedure StartSceneGameOver;
  283.     procedure SceneGameOver;
  284.     procedure EndSceneGameOver;
  285.     procedure StartSceneWin;
  286.     procedure SceneWin;
  287.     procedure EndSceneWin;
  288.     procedure StartSceneNewLevel;
  289.     procedure SceneNewLevel;
  290.     procedure EndSceneNewLevel;
  291.     procedure LevelNeuStarten;
  292.   private
  293.     { Diverse temporƤre Variablen }
  294.     Crash2: integer;
  295.     EnemyCounter: integer;
  296.     FBossImLevel: boolean;
  297.     FBossLife: integer;
  298.     Crash: boolean;
  299.     crashsound: boolean;
  300.   public
  301.     FNextScene: TGameScene;
  302.     FScore: Integer;
  303.     FNotSave: boolean;
  304.     FLife: integer;
  305.     FLevel: integer;
  306.     FGameMode: TGameMode;
  307.     FLifeAtLevelStart: integer;
  308.     FScoreAtLevelStart: integer;
  309.     FLevelDataAlreadyLoaded: boolean;
  310.     FRestEnemies: integer;
  311.     FCheat: boolean;
  312.     { VCL-Ersatz }
  313.     dxdraw: TDxDraw;
  314.     imagelist: TDxImageList;
  315.     spriteengine: tdxspriteengine;
  316.     dxsound: tdxsound;
  317.     dxmusic: tdxmusic;
  318.     wavelist: tdxwavelist;
  319.     dxinput: tdxinput;
  320.     dxtimer: tdxtimer;
  321.     { Level-Routinen }
  322.     LevelData: TLevelData;
  323.     procedure NewLevel(lev: integer);
  324.     procedure ResetLevelData;
  325.     { Musik-Routinen }
  326.     procedure MusicSwitchTrack(Name: TSpaceMissionMusicTrack);
  327.     procedure PlayMusic(Name: TSpaceMissionMusicTrack);
  328.     procedure StopMusic(Name: TSpaceMissionMusicTrack);
  329.     procedure ResumeMusic(Name: TSpaceMissionMusicTrack);
  330.     procedure PauseMusic(Name: TSpaceMissionMusicTrack);
  331.     { Sound-Routinen }
  332.     procedure PlaySound(Sound: TSpaceMissionSound; Wait: Boolean);
  333.     { Grafik-Routinen }
  334.     function GetSpriteGraphic(Sprite: TSpaceMissionGraphicSprite): TPictureCollectionItem;
  335.     { Initialisiations-Routinen }
  336.     procedure DXInit;
  337.     procedure SoundInit;
  338.     procedure MusicInit;
  339.     { Einstellungs-Routinen }
  340.     procedure LoadOptions;
  341.     procedure WriteOptions;
  342.     { Farb-Routinen }
  343.     function ComposeColor(Dest, Src: TRGBQuad; Percent: Integer): TRGBQuad;
  344.     procedure PalleteAnim(Col: TRGBQuad; Time: Integer);
  345.   end;
  346.  
  347. var
  348.   MainForm: TMainForm;
  349.  
  350. implementation
  351.  
  352. uses
  353.   GamSplash, GamSpeicherung, ComInfo, GamCheat, MMSystem, Registry,
  354.   ComHilfe;
  355.  
  356. {$R *.DFM}
  357.  
  358. const
  359.   DXInputButton = [isButton1, isButton2, isButton3,
  360.     isButton4, isButton5, isButton6, isButton7, isButton8, isButton9, isButton10, isButton11,
  361.     isButton12, isButton13, isButton14, isButton15, isButton16, isButton17, isButton18,
  362.     isButton19, isButton20, isButton21, isButton22, isButton23, isButton24, isButton25,
  363.     isButton26, isButton27, isButton28, isButton29, isButton30, isButton31, isButton32];
  364.  
  365. { TBackground }
  366.  
  367. procedure TBackground.DoMove(MoveCount: Integer);
  368. var
  369.   ran: integer;
  370.   bgs: TBackgroundSpecial;
  371. begin
  372.   inherited DoMove(MoveCount);
  373.   X := X - MoveCount*(60/1000)*FSpeed;
  374.   ran := Random(1500);
  375.   if ran = 150 then
  376.   begin
  377.     bgs := TBackgroundSpecial.Create(mainform.SpriteEngine.Engine);
  378.     bgs.SetMapSize(1, 1);
  379.     bgs.Image := MainForm.GetSpriteGraphic(smgBackgroundPlanet1);
  380.     bgs.Width := Image.Width;
  381.     bgs.Height := Image.Height;
  382.     bgs.Y := random(mainform.dxdraw.height);
  383.     bgs.X := mainform.dxdraw.width;
  384.     ran := Random(2);
  385.     if ran = 0 then
  386.     begin
  387.       bgs.Z := -20;
  388.       bgs.Speed := 1.8;
  389.     end
  390.     else if ran = 1 then
  391.     begin
  392.       bgs.Z := -40;
  393.       bgs.Speed := 0.8;
  394.     end
  395.     else if ran = 2 then
  396.     begin
  397.       bgs.Z := -60;
  398.       bgs.Speed := 0.3;
  399.     end;
  400.   end
  401.   else if ran = 500 then
  402.   begin
  403.     bgs := TBackgroundSpecial.Create(mainform.SpriteEngine.Engine);
  404.     bgs.SetMapSize(1, 1);
  405.     ran := Random(4);
  406.     if ran = 0 then
  407.       bgs.Image := MainForm.GetSpriteGraphic(smgBackgroundRed)
  408.     else if ran = 1 then
  409.       bgs.Image := MainForm.GetSpriteGraphic(smgBackgroundBlue)
  410.     else if ran = 2 then
  411.       bgs.Image := MainForm.GetSpriteGraphic(smgBackgroundYellow)
  412.     else if ran = 3 then
  413.       bgs.Image := MainForm.GetSpriteGraphic(smgHintergrundRot);
  414.     bgs.Width := Image.Width;
  415.     bgs.Height := Image.Height;
  416.  
  417.     bgs.Y := random(mainform.dxdraw.height);
  418.     bgs.X := mainform.dxdraw.width;
  419.  
  420.     { ran := Random(2);
  421.     if ran = 0 then
  422.     begin
  423.       bgs.Z := -20;
  424.       bgs.Speed := 1.8;
  425.     end
  426.     else if ran = 1 then
  427.     begin
  428.       bgs.Z := -40;
  429.       bgs.Speed := 0.8;
  430.     end
  431.     else if ran = 2 then
  432.     begin }
  433.       bgs.Z := -60;
  434.       bgs.Speed := 0.3;
  435.     { end; }
  436.   end;
  437. end;
  438.  
  439. { TBackgroundSpecial }
  440.  
  441. procedure TBackgroundSpecial.DoMove(MoveCount: Integer);
  442. begin
  443.   inherited DoMove(MoveCount);
  444.   X := X - MoveCount*(60/1000)*FSpeed;
  445.   if X < -Width then Dead;
  446. end;
  447.  
  448. { TExplosion }
  449.  
  450. constructor TExplosion.Create(AParent: TSprite);
  451. begin
  452.   inherited Create(AParent);
  453.   mainform.PlaySound(smsExplosion, false);
  454.   Image := MainForm.GetSpriteGraphic(smgExplosion);
  455.   Width := Image.Width;
  456.   Height := Image.Height;
  457.   AnimCount := Image.PatternCount;
  458.   AnimLooped := True;
  459.   AnimSpeed := DEFAULT_ANIMSPEED;
  460.   AnimPos := Random(AnimCount);
  461. end;
  462.  
  463. procedure TExplosion.DoMove(MoveCount: Integer);
  464. begin
  465.   inherited DoMove(MoveCount);
  466.   inc(FCounter, MoveCount);
  467.   if FCounter > 2999 then dead;
  468. end;
  469.  
  470. { TPlayerSprite }
  471.  
  472. constructor TPlayerSprite.Create(AParent: TSprite);
  473. begin
  474.   inherited Create(AParent);
  475.   State := pesEntering;
  476.   Image := MainForm.GetSpriteGraphic(smgMachine);
  477.   Width := Image.Width;
  478.   Height := Image.Height;
  479.   X := -70{20};
  480.   Y := mainform.dxdraw.surfaceHeight / 2 - (height / 2);
  481.   Z := 2;
  482.   AnimCount := Image.PatternCount;
  483.   AnimLooped := True;
  484.   AnimSpeed := DEFAULT_ANIMSPEED;
  485. end;
  486.  
  487. procedure TPlayerSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
  488. begin
  489.   if mainform.FCheat then exit;
  490.   if (Sprite is TItem) then
  491.   begin
  492.     TItem(Sprite).Collected;
  493.   end
  494.   else if (Sprite is TEnemy) or (Sprite is TEnemyTama) then
  495.   begin
  496.     if not mainform.crash then
  497.     begin
  498.       dec(MainForm.FLife);
  499.       mainform.Crash := true;
  500.       if MainForm.Flife=0 then
  501.       begin
  502.         MainForm.PlaySound(smsExplosion, false);
  503.         Collisioned := false;
  504.         FCounter := 0;
  505.         State := pesDead;
  506.         Done := false;
  507.         Image := MainForm.GetSpriteGraphic(smgExplosion);
  508.         Width := Image.Width;
  509.         Height := Image.Height;
  510.         AnimCount := Image.PatternCount;
  511.         AnimLooped := False;
  512.         AnimSpeed := DEFAULT_ANIMSPEED;
  513.         AnimPos := 0;
  514.       end;
  515.     end
  516.     else
  517.     begin
  518.       if not mainform.crashsound then
  519.       begin
  520.         MainForm.PlaySound(smsHit, False);
  521.         mainform.crashsound := true;
  522.       end;
  523.     end;
  524.   end;
  525. end;
  526.  
  527. procedure TPlayerSprite.DoMove(MoveCount: Integer);
  528. const
  529.   WegduesKonstante = 1.75;
  530. begin
  531.   inherited DoMove(MoveCount);
  532.   if State = pesNormal then
  533.   begin
  534.     if isUp in MainForm.DXInput.States then Y := Y - (250/1000)*MoveCount;
  535.     if isDown in MainForm.DXInput.States then Y := Y + (250/1000)*MoveCount;
  536.     if isLeft in MainForm.DXInput.States then X := X - (250/1000)*MoveCount;
  537.     if isRight in MainForm.DXInput.States then X := X + (250/1000)*MoveCount;
  538.     if X<0 then X := 0;
  539.     if X>mainform.dxdraw.surfacewidth-Width then X := mainform.dxdraw.surfacewidth-Width;
  540.     if Y<0 then Y := 0;
  541.     if Y>mainform.dxdraw.surfaceheight-Height then Y := mainform.dxdraw.surfaceheight-Height;
  542.     if isButton1 in MainForm.DXInput.States then
  543.     begin
  544.       if (FTamaCount<8) and (FCounter-FOldTamaTime>=100) then
  545.       begin
  546.         Inc(FTamaCount);
  547.         with TPlayerTamaSprite.Create(Engine, Self) do
  548.         begin
  549.           X := Self.X+Self.Width;
  550.           Y := Self.Y+Self.Height div 2-Height div 2;
  551.           Z := 10;
  552.         end;
  553.         FOldTamaTime := FCounter;
  554.       end;
  555.     end;
  556.     Collision;
  557.   end
  558.   else if State = pesDead then
  559.   begin
  560.     if FCounter>200 then
  561.     begin
  562.       FCounter := 0;
  563.       State := pesDeadVanished;
  564.       Visible := false; // Cannot use "Dead;" because we need to still be able to handle pesDeadVanished
  565.     end;
  566.   end
  567.   else if State = pesDeadVanished then
  568.   begin
  569.     if FCounter>2000 then
  570.     begin
  571.       MainForm.LevelNeuStarten;
  572.       (*
  573.       MainForm.FNextScene := gsGameOver;
  574.       MainForm.PlaySound(smsSceneMov, false);
  575.       MainForm.PalleteAnim(RGBQuad(0, 0, 0), 300);
  576.       Sleep(200);
  577.       *)
  578.     end;
  579.   end
  580.   else if State = pesFlyaway then
  581.   begin
  582.     X := X + MoveCount*(300/1000) * (X/MainForm.DXDraw.Width + WegduesKonstante);
  583.     if X > MainForm.DXDraw.Width+Width then
  584.     begin
  585.       Dead;
  586.       inc(mainform.FLevel);
  587.       MainForm.FLevelDataAlreadyLoaded := false; // allow NewLevel() to work again
  588.       MainForm.FNextScene := gsNewLevel;
  589.       MainForm.PlaySound(smsSceneMov, false);
  590.       MainForm.PalleteAnim(RGBQuad(0, 0, 0), 300);
  591.     end;
  592.   end
  593.   else if State = pesEntering then
  594.   begin
  595.     X := X + MoveCount*(300/1000);
  596.     if X > 19 then State := pesNormal;
  597.   end;
  598.   inc(FCounter, MoveCount);
  599. end;
  600.  
  601. procedure TPlayerSprite.FlyAway;
  602. begin
  603.   State := pesFlyaway;
  604. end;
  605.  
  606. { TPlayerTamaSprite }
  607.  
  608. constructor TPlayerTamaSprite.Create(AParent: TSprite; APlayerSprite: TPlayerSprite);
  609. begin
  610.   inherited Create(AParent);
  611.   FPlayerSprite := APlayerSprite;
  612.   Image := MainForm.GetSpriteGraphic(smgBounce);
  613.   Z := 2;
  614.   Width := Image.Width;
  615.   Height := Image.Height;
  616.   AnimCount := Image.PatternCount;
  617.   AnimLooped := True;
  618.   AnimSpeed := DEFAULT_ANIMSPEED;
  619.   MainForm.PlaySound(smsShoot, False);
  620. end;
  621.  
  622. destructor TPlayerTamaSprite.Destroy;
  623. begin
  624.   inherited Destroy;
  625.   Dec(FPlayerSprite.FTamaCount);
  626. end;
  627.  
  628. procedure TPlayerTamaSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
  629. begin
  630.   if (Sprite is TEnemy) and not (Sprite is TEnemyTama) then
  631.   begin
  632.     TEnemy(Sprite).Hit;
  633.     Dead;
  634.   end;
  635.   Done := False;
  636. end;
  637.  
  638. procedure TPlayerTamaSprite.DoMove(MoveCount: Integer);
  639. begin
  640.   inherited DoMove(MoveCount);
  641.   X := X+(800/1000)*MoveCount;
  642.   if X>=mainform.dxdraw.surfacewidth then Dead;
  643.   Collision;
  644. end;
  645.  
  646. { TEnemy }
  647.  
  648. constructor TEnemy.Create(AParent: TSprite; ALifes: integer);
  649. begin
  650.   inherited Create(AParent);
  651.   FLife := ALifes;
  652.   inc(mainform.EnemyCounter);
  653. end;
  654.  
  655. destructor TEnemy.Destroy;
  656. begin
  657.   inherited Destroy;
  658.   dec(mainform.EnemyCounter);
  659. end;
  660.  
  661. procedure TEnemy.Hit(AHitStrength: integer = 1);
  662. begin
  663.   Dec(FLife, AHitStrength);
  664.   if FLife<=0 then
  665.   begin
  666.     Collisioned := False;
  667.     HitEnemy(True);
  668.   end
  669.   else
  670.     HitEnemy(False);
  671. end;
  672.  
  673. procedure TEnemy.HitEnemy(ADead: Boolean);
  674. begin
  675.   if ADead then
  676.     MainForm.PlaySound(smsExplosion, False)
  677.   else
  678.     MainForm.PlaySound(smsHit, False);
  679. end;
  680.  
  681. { TEnemyTama }
  682.  
  683. constructor TEnemyTama.Create(AParent: TSprite; AEnemySprite: TSprite);
  684. begin
  685.   inherited Create(AParent);
  686.   FEnemySprite := AEnemySprite;
  687.   Image := MainForm.GetSpriteGraphic(smgBounce2);
  688.   Width := Image.Width;
  689.   Height := Image.Height;
  690.   AnimCount := Image.PatternCount;
  691.   AnimLooped := True;
  692.   AnimSpeed := DEFAULT_ANIMSPEED;
  693.   MainForm.PlaySound(smsShoot, False);
  694. end;
  695.  
  696. procedure TEnemyTama.DoMove(MoveCount: Integer);
  697. begin
  698.   inherited DoMove(MoveCount);
  699.   X := X - MoveCount*(600/1000);
  700.   if X < -Width then Dead;
  701. end;
  702.  
  703. { TEnemyMeteor }
  704.  
  705. constructor TEnemyMeteor.Create(AParent: TSprite; ALifes: integer);
  706. begin
  707.   inherited Create(AParent, ALifes);
  708.   State := pesNormal;
  709.   Image := MainForm.GetSpriteGraphic(smgEnemyMeteor);
  710.   Width := Image.Width;
  711.   Height := Image.Height;
  712.   AnimCount := Image.PatternCount;
  713.   AnimLooped := True;
  714.   AnimSpeed := DEFAULT_ANIMSPEED;
  715.   PixelCheck := True;
  716. end;
  717.  
  718. procedure TEnemyMeteor.HitEnemy(ADead: Boolean);
  719. begin
  720.   inherited HitEnemy(False);
  721.  
  722.   if ADead then Collisioned := True;
  723. end;
  724.  
  725. procedure TEnemyMeteor.DoMove(MoveCount: Integer);
  726. begin
  727.   X := X - MoveCount*(250/1000);
  728.   if X < -Width then Dead;
  729. end;
  730.  
  731. { TEnemyUFO }
  732.  
  733. constructor TEnemyUFO.Create(AParent: TSprite; ALifes: integer);
  734. begin
  735.   inherited Create(AParent, ALifes);
  736.   State := pesNormal;
  737.   Image := MainForm.GetSpriteGraphic(smgEnemyDisk);
  738.   Width := Image.Width;
  739.   Height := Image.Height;
  740.   AnimCount := Image.PatternCount;
  741.   AnimLooped := True;
  742.   AnimSpeed := DEFAULT_ANIMSPEED;
  743. end;
  744.  
  745. procedure TEnemyUFO.HitEnemy(ADead: Boolean);
  746. begin
  747.   inherited HitEnemy(ADead);
  748.  
  749.   if ADead then
  750.   begin
  751.     State := pesDead;
  752.     FCounter := 0;
  753.     Inc(MainForm.FScore, 1000);
  754.     Image := MainForm.GetSpriteGraphic(smgExplosion);
  755.     Width := Image.Width;
  756.     Height := Image.Height;
  757.     AnimCount := Image.PatternCount;
  758.     AnimLooped := False;
  759.     AnimSpeed := DEFAULT_ANIMSPEED;
  760.     AnimPos := 0;
  761.   end
  762.   else
  763.   begin
  764.     Inc(MainForm.FScore, 100);
  765.   end;
  766. end;
  767.  
  768. procedure TEnemyUFO.DoMove(MoveCount: Integer);
  769. begin
  770.   inherited DoMove(MoveCount);
  771.   if State = pesNormal then
  772.   begin
  773.     X := X - MoveCount*(300/1000);
  774.     Y := Y + Cos256(FCounter div 15)*2;
  775.     if X < -Width then Dead;
  776.   end
  777.   else if State = pesDead then
  778.   begin
  779.     X := X - MoveCount*(300/1000);
  780.     if FCounter>200 then
  781.     begin
  782.       State := pesDeadVanished;
  783.       Dead;
  784.     end;
  785.   end;
  786.   inc(FCounter, MoveCount);
  787. end;
  788.  
  789. { TEnemyUFO2 }
  790.  
  791. constructor TEnemyUFO2.Create(AParent: TSprite; ALifes: integer);
  792. begin
  793.   inherited Create(AParent, ALifes);
  794.   State := pesNormal;
  795.   Image := MainForm.GetSpriteGraphic(smgEnemyDisk2);
  796.   Width := Image.Width;
  797.   Height := Image.Height;
  798.   AnimCount := Image.PatternCount;
  799.   AnimLooped := True;
  800.   AnimSpeed := DEFAULT_ANIMSPEED;
  801. end;
  802.  
  803. procedure TEnemyUFO2.HitEnemy(ADead: Boolean);
  804. begin
  805.   inherited HitEnemy(ADead);
  806.  
  807.   if ADead then
  808.   begin
  809.     State := pesDead;
  810.     FCounter := 0;
  811.     Inc(MainForm.FScore, 1000);
  812.     Image := MainForm.GetSpriteGraphic(smgExplosion);
  813.     Width := Image.Width;
  814.     Height := Image.Height;
  815.     AnimCount := Image.PatternCount;
  816.     AnimLooped := False;
  817.     AnimSpeed := DEFAULT_ANIMSPEED;
  818.     AnimPos := 0;
  819.   end
  820.   else
  821.   begin
  822.     Inc(MainForm.FScore, 100);
  823.   end;
  824. end;
  825.  
  826. procedure TEnemyUFO2.DoMove(MoveCount: Integer);
  827. begin
  828.   inherited DoMove(MoveCount);
  829.   if State = pesNormal then
  830.   begin
  831.     X := X - MoveCount*(300/1000);
  832.     Y := Y + Cos256(FCounter div 15)*2;
  833.     if X < -Width then Dead;
  834.     if FCounter-FOldTamaTime>=100 then
  835.     begin
  836.       Inc(FTamaCount);
  837.       with TEnemyTama.Create(Engine, Self) do
  838.       begin
  839.         X := Self.X;
  840.         Y := Self.Y+Self.Height div 2-Height div 2;
  841.         Z := 10;
  842.       end;
  843.       FOldTamaTime := FCounter;
  844.     end;
  845.   end
  846.   else if State = pesDead then
  847.   begin
  848.     X := X - MoveCount*(300/1000);
  849.     if FCounter>200 then
  850.     begin
  851.       State := pesDeadVanished;
  852.       Dead;
  853.     end;
  854.   end;
  855.   inc(FCounter, MoveCount);
  856. end;
  857.  
  858. { TEnemyAttacker }
  859.  
  860. constructor TEnemyAttacker.Create(AParent: TSprite; ALifes: integer);
  861. begin
  862.   inherited Create(AParent, ALifes);
  863.   State := pesNormal;
  864.   Image := MainForm.GetSpriteGraphic(smgEnemyAttacker);
  865.   Width := Image.Width;
  866.   Height := Image.Height;
  867.   AnimCount := Image.PatternCount;
  868.   AnimLooped := True;
  869.   AnimSpeed := DEFAULT_ANIMSPEED;
  870.   PixelCheck := True;
  871. end;
  872.  
  873. procedure TEnemyAttacker.HitEnemy(ADead: Boolean);
  874. begin
  875.   inherited HitEnemy(ADead);
  876.  
  877.   if ADead then
  878.   begin
  879.     State := pesDead;
  880.     FCounter := 0;
  881.     Inc(MainForm.FScore, 1000);
  882.     Image := MainForm.GetSpriteGraphic(smgExplosion);
  883.     Width := Image.Width;
  884.     Height := Image.Height;
  885.     AnimCount := Image.PatternCount;
  886.     AnimLooped := False;
  887.     AnimSpeed := DEFAULT_ANIMSPEED;
  888.     AnimPos := 0;
  889.   end
  890.   else
  891.   begin
  892.     Inc(MainForm.FScore, 100);
  893.   end;
  894. end;
  895.  
  896. procedure TEnemyAttacker.DoMove(MoveCount: Integer);
  897. begin
  898.   inherited DoMove(MoveCount);
  899.   if State = pesNormal then
  900.   begin
  901.     X := X - MoveCount*(300/1000)-FCounter div 128;
  902.     if X < -Width then Dead;
  903.   end
  904.   else if State = pesDead then
  905.   begin
  906.     X := X - MoveCount*(300/1000);
  907.     if FCounter>200 then
  908.     begin
  909.       State := pesDeadVanished;
  910.       Dead;
  911.     end;
  912.   end;
  913.   inc(FCounter, MoveCount);
  914. end;
  915.  
  916. { TEnemyAttacker2 }
  917.  
  918. constructor TEnemyAttacker2.Create(AParent: TSprite; ALifes: integer);
  919. begin
  920.   inherited Create(AParent, ALifes);
  921.   State := pesEntering;
  922.   Image := MainForm.GetSpriteGraphic(smgEnemyAttacker2);
  923.   Width := Image.Width;
  924.   Height := Image.Height;
  925.   AnimCount := Image.PatternCount;
  926.   AnimLooped := True;
  927.   AnimSpeed := DEFAULT_ANIMSPEED;
  928.   PixelCheck := True;
  929. end;
  930.  
  931. procedure TEnemyAttacker2.HitEnemy(ADead: Boolean);
  932. begin
  933.   inherited HitEnemy(ADead);
  934.  
  935.   if ADead then
  936.   begin
  937.     State := pesDead;
  938.     FCounter := 0;
  939.     Inc(MainForm.FScore, 5000);
  940.     Image := MainForm.GetSpriteGraphic(smgExplosion);
  941.     Width := Image.Width;
  942.     Height := Image.Height;
  943.     AnimCount := Image.PatternCount;
  944.     AnimLooped := False;
  945.     AnimSpeed := DEFAULT_ANIMSPEED;
  946.     AnimPos := 0;
  947.   end
  948.   else
  949.   begin
  950.     Inc(MainForm.FScore, 100);
  951.   end;
  952. end;
  953.  
  954. procedure TEnemyAttacker2.DoMove(MoveCount: Integer);
  955. begin
  956.   inherited DoMove(MoveCount);
  957.   if State = pesEntering then
  958.   begin
  959.     if X>((mainform.dxdraw.width/4) + (mainform.dxdraw.width/2) - (width/2)){450} then
  960.       X := X - MoveCount*(300/1000)
  961.     else
  962.     begin
  963.       Collisioned := True;
  964.       State := pesHovering;
  965.       FPutTama := True;
  966.     end;
  967.     Y := Y + Cos256(FCounter div 15)*5;
  968.   end
  969.   else if State = pesHovering then
  970.   begin
  971.     Y := Y + Cos256(FCounter div 15)*5;
  972.     if FPutTama then
  973.     begin
  974.       if FTamaT>100 then
  975.       begin
  976.         with TEnemyTama.Create(Engine, Self) do
  977.         begin
  978.           Z := 1;
  979.           X := Self.X-Width;
  980.           Y := Self.Y+Self.Height div 2-Height div 2;
  981.         end;
  982.         Inc(FTamaF);
  983.         if FTamaF>Random(30) then FPutTama := False;
  984.         FTamaT := 0;
  985.       end;
  986.       FTamaT := FTamaT + MoveCount;
  987.     end
  988.     else
  989.     begin
  990.       FTamaT := FTamaT + MoveCount;
  991.       if FTamaT>2000+Random(500) then
  992.       begin
  993.         FPutTama := True;
  994.         FTamaF := 0;
  995.         FTamaT := 0;
  996.       end;
  997.     end;
  998.   end
  999.   else if State = pesDead then
  1000.   begin
  1001.     if FCounter>200 then
  1002.     begin
  1003.       State := pesDeadVanished;
  1004.       Dead;
  1005.     end;
  1006.   end;
  1007.   inc(FCounter, MoveCount);
  1008. end;
  1009.  
  1010. { TEnemyAttacker3 }
  1011.  
  1012. constructor TEnemyAttacker3.Create(AParent: TSprite; ALifes: integer);
  1013. begin
  1014.   inherited Create(AParent, ALifes);
  1015.   State := pesNormal;
  1016.   Image := MainForm.GetSpriteGraphic(smgEnemyAttacker3);
  1017.   Width := Image.Width;
  1018.   Height := Image.Height;
  1019.   AnimCount := Image.PatternCount;
  1020.   AnimLooped := True;
  1021.   AnimSpeed := DEFAULT_ANIMSPEED;
  1022.   PixelCheck := True;
  1023. end;
  1024.  
  1025. procedure TEnemyAttacker3.HitEnemy(ADead: Boolean);
  1026. begin
  1027.   inherited HitEnemy(ADead);
  1028.  
  1029.   if ADead then
  1030.   begin
  1031.     State := pesDead;
  1032.     FCounter := 0;
  1033.     Inc(MainForm.FScore, 5000);
  1034.     Image := MainForm.GetSpriteGraphic(smgExplosion);
  1035.     Width := Image.Width;
  1036.     Height := Image.Height;
  1037.     AnimCount := Image.PatternCount;
  1038.     AnimLooped := False;
  1039.     AnimSpeed := DEFAULT_ANIMSPEED;
  1040.     AnimPos := 0;
  1041.   end
  1042.   else
  1043.   begin
  1044.     Inc(MainForm.FScore, 100);
  1045.   end;
  1046. end;
  1047.  
  1048. procedure TEnemyAttacker3.DoMove(MoveCount: Integer);
  1049. begin
  1050.   inherited DoMove(MoveCount);
  1051.   if State = pesNormal then
  1052.   begin
  1053.     X := X - (250/1000)*MoveCount;
  1054.     if X < -Width then Dead;
  1055.     if FCounter-FOldTamaTime>=100 then
  1056.     begin
  1057.       Inc(FTamaCount);
  1058.       with TEnemyTama.Create(Engine, Self) do
  1059.       begin
  1060.         X := Self.X;
  1061.         Y := Self.Y+Self.Height div 2-Height div 2;
  1062.         Z := 10;
  1063.       end;
  1064.       FOldTamaTime := FCounter;
  1065.      end;
  1066.   end
  1067.   else if State = pesDead then
  1068.   begin
  1069.     if FCounter>200 then
  1070.     begin
  1071.       State := pesDeadVanished;
  1072.       Dead;
  1073.     end;
  1074.   end;
  1075.   inc(FCounter, MoveCount);
  1076. end;
  1077.  
  1078. { TEnemyBoss }
  1079.  
  1080. constructor TEnemyBoss.Create(AParent: TSprite; ALifes: integer);
  1081. begin
  1082.   inherited Create(AParent, ALifes);
  1083.   State := pesEntering;
  1084.   Image := MainForm.GetSpriteGraphic(smgEnemyBoss);
  1085.   Width := Image.Width;
  1086.   Height := Image.Height;
  1087.   MainForm.MusicSwitchTrack(smmBoss);
  1088.   AnimCount := Image.PatternCount;
  1089.   AnimLooped := True;
  1090.   AnimSpeed := DEFAULT_ANIMSPEED;
  1091.   PixelCheck := True;
  1092.   Collisioned := False;
  1093.   MainForm.FBossLife := FLife;
  1094.   waiter1 := 0;
  1095.   waiter2 := 0;
  1096. end;
  1097.  
  1098. procedure TEnemyBoss.HitEnemy(ADead: Boolean);
  1099. begin
  1100.   inherited HitEnemy(ADead);
  1101.  
  1102.   if ADead then
  1103.   begin
  1104.     State := pesExploding; // not pesDead for the boss!
  1105.     FCounter := 0;
  1106.     Inc(MainForm.FScore, 100000);
  1107.     dec(MainForm.FBossLife);
  1108.   end
  1109.   else
  1110.   begin
  1111.     Inc(MainForm.FScore, 100);
  1112.     dec(MainForm.FBossLife);
  1113.   end;
  1114. end;
  1115.  
  1116. procedure TEnemyBoss.DoMove(MoveCount: Integer);
  1117. begin
  1118.   inherited DoMove(MoveCount);
  1119.   if State = pesEntering then
  1120.   begin
  1121.     if X>((mainform.dxdraw.width/4) + (mainform.dxdraw.width/2) - (width/4)){450} then
  1122.       X := X - MoveCount*(300/1000)
  1123.     else
  1124.     begin
  1125.       Collisioned := True;
  1126.       State := pesHovering;
  1127.       FPutTama := True;
  1128.     end;
  1129.     Y := Y + Cos256(FCounter div 15)*5;
  1130.   end
  1131.   else if State = pesHovering then
  1132.   begin
  1133.     Y := Y + Cos256(FCounter div 15)*5;
  1134.     if FPutTama then
  1135.     begin
  1136.       if FTamaT>100 then
  1137.       begin
  1138.         with TEnemyTama.Create(Engine, Self) do
  1139.         begin
  1140.           Z := 1;
  1141.           X := Self.X-Width;
  1142.           Y := Self.Y+Self.Height div 2-Height div 2;
  1143.         end;
  1144.         Inc(FTamaF);
  1145.         if FTamaF>Random(30) then FPutTama := False;
  1146.         FTamaT := 0;
  1147.       end;
  1148.       FTamaT := FTamaT + MoveCount;
  1149.     end
  1150.     else
  1151.     begin
  1152.       FTamaT := FTamaT + MoveCount;
  1153.       if FTamaT>2000+Random(500) then
  1154.       begin
  1155.         FPutTama := True;
  1156.         FTamaF := 0;
  1157.         FTamaT := 0;
  1158.       end;
  1159.     end;
  1160.   end
  1161.   else if State = pesExploding then
  1162.   begin
  1163.     inc(waiter1);
  1164.     if waiter1 = 3 then
  1165.     begin
  1166.       waiter1 := 0;
  1167.       inc(waiter2);
  1168.       if waiter2 <= 20 then
  1169.       begin
  1170.         with TExplosion.Create(Engine) do
  1171.         begin
  1172.           Z := 10;
  1173.           X := Self.X+Random(Self.Width)-16;
  1174.           Y := Self.Y+Random(Self.Height)-16;
  1175.         end;
  1176.       end
  1177.       else
  1178.       begin
  1179.         Inc(MainForm.FScore, 10000);
  1180.         State := pesDead;
  1181.       end;
  1182.     end;
  1183.   end
  1184.   else if State = pesDead then
  1185.   begin
  1186.     if FCounter>4000 then
  1187.     begin
  1188.       State := pesDeadVanished;
  1189.       Dead;
  1190.     end;
  1191.   end;
  1192.   inc(FCounter, MoveCount);
  1193. end;
  1194.  
  1195. { TItem }
  1196.  
  1197. procedure TItem.Collected;
  1198. begin
  1199.   MainForm.PlaySound(smsItemCollected, false);
  1200.   Dead;
  1201. end;
  1202.  
  1203. procedure TItem.DoMove(MoveCount: Integer);
  1204. begin
  1205.   X := X - MoveCount*(250/1000);
  1206.   if X < -Width then Dead;
  1207. end;
  1208.  
  1209. { TItemMedikit }
  1210.  
  1211. procedure TItemMedikit.Collected;
  1212. begin
  1213.   Inc(MainForm.FLife);
  1214.   inherited;
  1215. end;
  1216.  
  1217. constructor TItemMedikit.Create(AParent: TSprite);
  1218. begin
  1219.   inherited Create(AParent);
  1220.   State := pesNormal;
  1221.   Image := MainForm.GetSpriteGraphic(smgItemMedikit);
  1222.   Width := Image.Width;
  1223.   Height := Image.Height;
  1224.   AnimCount := Image.PatternCount;
  1225.   AnimLooped := True;
  1226.   AnimSpeed := DEFAULT_ANIMSPEED;
  1227.   PixelCheck := True;
  1228. end;
  1229.  
  1230. { TMainForm }
  1231.  
  1232. procedure TMainForm.FormCreate(Sender: TObject);
  1233. resourcestring
  1234.   SAppTitle = 'SpaceMission %s';
  1235. begin
  1236.   Randomize;
  1237.  
  1238.   LevelData := TLevelData.Create;
  1239.  
  1240.   { Beginne VCL-Ersatz }
  1241.   dxtimer := tdxtimer.Create(self);
  1242.   dxtimer.Interval := 33;
  1243.   dxtimer.OnActivate := DXTimerActivate;
  1244.   dxtimer.OnDeactivate := DXTimerDeactivate;
  1245.   dxtimer.OnTimer := DXTimerTimer;
  1246.   dxtimer.ActiveOnly := false;
  1247.   dxtimer.Enabled := false;
  1248.  
  1249.   dxdraw := tdxdraw.Create(self);
  1250.   dxdraw.Parent := self;
  1251.   dxdraw.Align := alClient;
  1252.   dxdraw.Left := 0;
  1253.   dxdraw.Top := 0;
  1254.   dxdraw.Width := ClientWidth;
  1255.   dxdraw.Height := ClientHeight;
  1256.   dxdraw.AutoInitialize := False;
  1257.   dxdraw.AutoSize := False;
  1258.   dxdraw.Color := clBlack;
  1259.   (*
  1260.   dxdraw.Display.BitCount := 24;
  1261.   dxdraw.Display.FixedBitCount := False;
  1262.   dxdraw.Display.FixedRatio := False;
  1263.   dxdraw.Display.FixedSize := False;
  1264.   dxdraw.Display.Height := 600;
  1265.   dxdraw.Display.Width := 800;
  1266.   *)
  1267.   dxdraw.Options := [doAllowReboot, doWaitVBlank, doAllowPalette256, doCenter, {doRetainedMode,} doHardware, doSelectDriver];
  1268.   dxdraw.TabOrder := 0;
  1269.   dxdraw.Visible := true;
  1270.   dxdraw.OnFinalize := DXDrawFinalize;
  1271.   dxdraw.OnInitialize := DXDrawInitialize;
  1272.   dxdraw.OnInitializing := DXDrawInitializing;
  1273.  
  1274.   dxsound := tdxsound.Create(self);
  1275.   dxsound.AutoInitialize := false;
  1276.  
  1277.   dxmusic := TDXMusic.Create(self);
  1278.   dxmusic.DXSound := dxsound;
  1279.  
  1280.   dxinput := tdxinput.Create(self);
  1281.   dxinput.Joystick.ForceFeedback := true;
  1282.   dxinput.Keyboard.ForceFeedback := true;
  1283.  
  1284.   wavelist := tdxwavelist.Create(self);
  1285.   wavelist.DXSound := dxsound;
  1286.  
  1287.   imagelist := tdximagelist.create(self);
  1288.   imagelist.DXDraw := dxdraw;
  1289.  
  1290.   spriteengine := tdxspriteengine.create(self);
  1291.   spriteengine.DXDraw := dxdraw;
  1292.  
  1293.   InitializeCriticalSection(TimerCS);
  1294.  
  1295.   { Ende VCL-Ersatz }
  1296.  
  1297.   Application.Title := Format(SAppTitle, [ProgramVersion]);
  1298.   LoadOptions;
  1299.   DXInit;
  1300.   SoundInit;
  1301.   MusicInit;
  1302.  
  1303.   GameStartClick(GameStart);
  1304. end;
  1305.  
  1306. procedure TMainForm.GameStartClick(Sender: TObject);
  1307. begin
  1308.   StartScene(gsTitle);
  1309. end;
  1310.  
  1311. function TMainForm.GetSpriteGraphic(
  1312.   Sprite: TSpaceMissionGraphicSprite): TPictureCollectionItem;
  1313. begin
  1314.   if (Sprite<>smgNone) and (imagelist.Items.Count >= Ord(Sprite)) then
  1315.     result := imagelist.Items.Items[Ord(Sprite)-1]
  1316.   else
  1317.     result := nil;
  1318. end;
  1319.  
  1320. procedure TMainForm.HilfeTopicClick(Sender: TObject);
  1321. // Please keep this code in-sync with LevMain.pas
  1322. var
  1323.   bakTimerEnabled: boolean;
  1324. begin
  1325.   bakTimerEnabled := dxtimer.Enabled;
  1326.   try
  1327.     dxtimer.Enabled := false;
  1328.     HilfeForm.Caption := TMenuItem(Sender).Caption;
  1329.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, '&&', #1, [rfReplaceAll]);
  1330.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, '&', '', [rfReplaceAll]);
  1331.     HilfeForm.Caption := StringReplace(HilfeForm.Caption, #1, '&', [rfReplaceAll]);
  1332.     HilfeForm.ShowMarkDownHelp(OwnDirectory+TMenuItem(Sender).Hint);
  1333.     HilfeForm.ShowModal;
  1334.   finally
  1335.     dxtimer.Enabled := bakTimerEnabled;
  1336.   end;
  1337. end;
  1338.  
  1339. procedure TMainForm.GamePauseClick(Sender: TObject);
  1340. begin
  1341.   GamePause.Checked := not GamePause.Checked;
  1342.   DXTimer.Enabled := not GamePause.Checked;
  1343.   if GamePause.Checked then
  1344.   begin
  1345.     if Assigned(DXTimer.OnDeactivate) then
  1346.       DXTimer.OnDeactivate(DXTimer);
  1347.   end
  1348.   else
  1349.   begin
  1350.     if Assigned(DXTimer.OnActivate) then
  1351.       DXTimer.OnActivate(DXTimer);
  1352.   end;
  1353. end;
  1354.  
  1355. procedure TMainForm.DXInit;
  1356. const
  1357.   DxgFile = 'DirectX\Graphics.dxg'; // do not localize
  1358. begin
  1359.   try
  1360.     Imagelist.Items.LoadFromFile(OwnDirectory+DxgFile);
  1361.     ImageList.Items.MakeColorTable;
  1362.     DXDraw.ColorTable := ImageList.Items.ColorTable;
  1363.     DXDraw.DefColorTable := ImageList.Items.ColorTable;
  1364.     DXDraw.UpdatePalette;
  1365.     DXDraw.Finalize;
  1366.     DXDraw.Options := DXDraw.Options - [doFullScreen];
  1367.     DXDraw.autosize := true;
  1368.     DXDraw.Initialize;
  1369.   except
  1370.     //Imagelist.Items.clear;
  1371.     //application.terminate;
  1372.   end;
  1373. end;
  1374.  
  1375. procedure TMainForm.CheckUpdatesClick(Sender: TObject);
  1376. begin
  1377.   CheckForUpdates('spacemission', ProgramVersion); // do not localize
  1378. end;
  1379.  
  1380. procedure TMainForm.BeendenClick(Sender: TObject);
  1381. begin
  1382.   close;
  1383. end;
  1384.  
  1385. procedure TMainForm.OptionSoundClick(Sender: TObject);
  1386. begin
  1387.   OptionSound.Checked := not OptionSound.Checked;
  1388.   SoundInit;
  1389.   WriteOptions;
  1390. end;
  1391.  
  1392. procedure TMainForm.SoundInit;
  1393. const
  1394.   DxwFile = 'DirectX\Sound.dxw'; // do not localize
  1395. begin
  1396.   if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxwFile) then
  1397.   begin
  1398.     OptionSound.Checked := false;
  1399.     OptionSound.Enabled := False;
  1400.     exit;
  1401.   end;
  1402.  
  1403.   if OptionSound.Checked then
  1404.   begin
  1405.     if not DXSound.Initialized then
  1406.     begin
  1407.       try
  1408.         DXSound.Initialize;
  1409.         WaveList.Items.LoadFromFile(OwnDirectory+DxwFile);
  1410.       except
  1411.         OptionSound.enabled := False;
  1412.         WaveList.items.clear;
  1413.       end;
  1414.     end;
  1415.   end
  1416.   else DXSound.Finalize;
  1417. end;
  1418.  
  1419. procedure TMainForm.MusicInit;
  1420. const
  1421.   DxmFile = 'DirectX\Music.dxm'; // do not localize
  1422. var
  1423.   i: integer;
  1424. begin
  1425.   if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxmFile) then
  1426.   begin
  1427.     optionmusic.Checked := false;
  1428.     optionmusic.Enabled := False;
  1429.     exit;
  1430.   end;
  1431.  
  1432.   try
  1433.     dxmusic.Midis.LoadFromFile(OwnDirectory+DxmFile);
  1434.     for i := 0 to dxmusic.Midis.Count-1 do
  1435.     begin
  1436.       if not dxmusic.Midis.Items[i].IsInitialized then
  1437.       begin
  1438.         dxmusic.Midis.Items[i].Init;
  1439.         dxmusic.Midis.Items[i].Load;
  1440.       end;
  1441.     end;
  1442.   except
  1443.     optionmusic.enabled := false;
  1444.   end;
  1445. end;
  1446.  
  1447. procedure TMainForm.DXDrawInitializing(Sender: TObject);
  1448. begin
  1449.   if doFullScreen in DXDraw.Options then
  1450.   begin
  1451.     BorderStyle := bsNone;
  1452.     DXDraw.Cursor := crNone;
  1453.   end
  1454.   else
  1455.   begin
  1456.     BorderStyle := bsSingle;
  1457.     DXDraw.Cursor := crDefault;
  1458.   end;
  1459. end;
  1460.  
  1461. procedure TMainForm.DXDrawInitialize(Sender: TObject);
  1462. begin
  1463.   if Assigned(DXTimer) then DXTimer.Enabled := True;
  1464. end;
  1465.  
  1466. procedure TMainForm.DXDrawFinalize(Sender: TObject);
  1467. begin
  1468.   if Assigned(DXTimer) then DXTimer.Enabled := False;
  1469. end;
  1470.  
  1471. procedure TMainForm.DXTimerActivate(Sender: TObject);
  1472. begin
  1473.   if TDxTimer(Sender).Tag > 0 then
  1474.     TDxTimer(Sender).Tag := TDxTimer(Sender).Tag - 1; // es kƶnnen mehrere activate/deactivate vorkommen, wegen dem Pause-Button
  1475.   if TDxTimer(Sender).Tag > 0 then
  1476.     exit;
  1477.   Caption := Application.Title;
  1478.   if not ProgrammGestartet then
  1479.   begin
  1480.     Programmgestartet := true;
  1481.     exit;
  1482.   end;
  1483.   ResumeMusic(FMusic);
  1484. end;
  1485.  
  1486. procedure TMainForm.DXTimerDeactivate(Sender: TObject);
  1487. resourcestring
  1488.   SPauseTitle = '%s [Pause]';
  1489. begin
  1490.   TDxTimer(Sender).Tag := TDxTimer(Sender).Tag + 1;
  1491.   Caption := Format(SPauseTitle, [Application.Title]);
  1492.   PauseMusic(FMusic);
  1493. end;
  1494.  
  1495. procedure TMainForm.DXTimerTimer(Sender: TObject; LagCount: Integer);
  1496. begin
  1497.   EnterCriticalSection(TimerCS);
  1498.   try
  1499.     if crash then
  1500.     begin
  1501.       inc(Crash2);
  1502.       if crash2 = 30 then
  1503.       begin
  1504.         Crash2 := 0;
  1505.         crash := false;
  1506.         crashsound := false;
  1507.       end;
  1508.     end;
  1509.     if not DXDraw.CanDraw then exit;
  1510.     DXInput.Update;
  1511.     case FScene of
  1512.       gsTitle   : SceneTitle;
  1513.       gsMain    : SceneMain;
  1514.       gsGameOver: SceneGameOver;
  1515.       gsWin     : SceneWin;
  1516.       gsNewLevel: SceneNewLevel;
  1517.     end;
  1518.     if FNextScene<>gsNone then
  1519.     begin
  1520.       StartScene(FNextScene);
  1521.       FNextScene := gsNone;
  1522.     end;
  1523.     DXDraw.Flip;
  1524.   finally
  1525.     LeaveCriticalSection(TimerCS);
  1526.   end;
  1527. end;
  1528.  
  1529. procedure TMainForm.BlinkStart;
  1530. begin
  1531.   FBlink := 0;
  1532.   FBlinkTime := GetTickCount;
  1533. end;
  1534.  
  1535. procedure TMainForm.WriteOptions;
  1536. var
  1537.   Reg: TRegistry;
  1538. begin
  1539.   Reg := TRegistry.Create;
  1540.   try
  1541.     Reg.RootKey := HKEY_CURRENT_USER;
  1542.     if Reg.OpenKey(RegistrySettingsKey, true) then
  1543.     begin
  1544.       Reg.WriteBool(MusicSettingKey, OptionMusic.checked);
  1545.       Reg.WriteBool(SoundSettingKey, OptionSound.checked);
  1546.       Reg.WriteInteger(SpeedSettingKey, Ord(FInterval));  // TODO : maybe it would be better to let the user change the real speed, so they can set their own custom one!
  1547.       Reg.CloseKey;
  1548.     end;
  1549.   finally
  1550.     FreeAndNil(Reg);
  1551.   end;
  1552. end;
  1553.  
  1554. procedure TMainForm.LoadOptions;
  1555. var
  1556.   Reg: TRegistry;
  1557. begin
  1558.   Reg := TRegistry.Create;
  1559.   try
  1560.     Reg.RootKey := HKEY_CURRENT_USER;
  1561.     if Reg.OpenKey(RegistrySettingsKey, true) then
  1562.     begin
  1563.       if Reg.ValueExists(MusicSettingKey) then
  1564.         optionmusic.checked := Reg.ReadBool(MusicSettingKey)
  1565.       else
  1566.         optionmusic.checked := true; // default
  1567.  
  1568.       if Reg.ValueExists(SoundSettingKey) then
  1569.         optionsound.checked := Reg.ReadBool(SoundSettingKey)
  1570.       else
  1571.         optionsound.checked := true; // default
  1572.  
  1573.       if Reg.ValueExists(SpeedSettingKey) then
  1574.         FInterval := TGameInterval(Reg.ReadInteger(SpeedSettingKey))
  1575.       else
  1576.         FInterval := giMittel; // default
  1577.  
  1578.       Reg.CloseKey;
  1579.     end;
  1580.   finally
  1581.     FreeAndNil(Reg);
  1582.   end;
  1583.   WriteOptions;
  1584. end;
  1585.  
  1586. procedure TMainForm.BlinkUpdate;
  1587. begin
  1588.   if GetTickCount<>FBlinkTime then
  1589.   begin
  1590.     FBlink := FBlink + (GetTickCount-FBlinkTime);
  1591.     FBlinkTime := GetTickCount;
  1592.   end;
  1593. end;
  1594.  
  1595. procedure TMainForm.PlaySound(Sound: TSpaceMissionSound; Wait: Boolean);
  1596. begin
  1597.   if (Sound<>smsNone) and (OptionSound.Checked) and (OptionSound.Enabled) and (WaveList.Items.Count >= Ord(Sound)) then
  1598.     WaveList.Items.Items[Ord(Sound)-1].Play(Wait);
  1599. end;
  1600.  
  1601. procedure TMainForm.MusicSwitchTrack(Name: TSpaceMissionMusicTrack);
  1602. begin
  1603.   if (not mainform.active) and (mainform.visible) then //1st Programmstart
  1604.     exit;
  1605.   if (OptionMusic.checked) and (OptionMusic.enabled) then
  1606.   begin
  1607.     StopMusic(FMusic);
  1608.     PlayMusic(Name);
  1609.   end;
  1610.   FMusic := Name;
  1611. end;
  1612.  
  1613. function TMainForm.ComposeColor(Dest, Src: TRGBQuad; Percent: Integer): TRGBQuad;
  1614. begin
  1615.   with Result do
  1616.   begin
  1617.     rgbRed := Src.rgbRed+((Dest.rgbRed-Src.rgbRed)*Percent div 256);
  1618.     rgbGreen := Src.rgbGreen+((Dest.rgbGreen-Src.rgbGreen)*Percent div 256);
  1619.     rgbBlue := Src.rgbBlue+((Dest.rgbBlue-Src.rgbBlue)*Percent div 256);
  1620.     rgbReserved := 0;
  1621.   end;
  1622. end;
  1623.  
  1624. procedure TMainForm.PalleteAnim(Col: TRGBQuad; Time: Integer);
  1625. var
  1626.   i: Integer;
  1627.   t, t2: DWORD;
  1628.   ChangePalette: Boolean;
  1629.   c: Integer;
  1630. begin
  1631.   if DXDraw.Initialized then
  1632.   begin
  1633.     c := DXDraw.Surface.ColorMatch(RGB(Col.rgbRed, Col.rgbGreen, Col.rgbBlue));
  1634.     ChangePalette := False;
  1635.     if DXDraw.CanPaletteAnimation then
  1636.     begin
  1637.       t := GetTickCount;
  1638.       while Abs(GetTickCount-t)<Time do
  1639.       begin
  1640.         t2 := Trunc(Abs(GetTickCount-t)/Time*255);
  1641.         for i := 0 to 255 do
  1642.           DXDraw.ColorTable[i] := ComposeColor(Col, DXDraw.DefColorTable[i], t2);
  1643.         DXDraw.UpdatePalette;
  1644.         ChangePalette := True;
  1645.       end;
  1646.     end
  1647.     else
  1648.     begin
  1649.       Sleep(Time);
  1650.     end;
  1651.     for i := 0 to 4 do
  1652.     begin
  1653.       DXDraw.Surface.Fill(c);
  1654.       DXDraw.Flip;
  1655.     end;
  1656.     if ChangePalette then
  1657.     begin
  1658.       DXDraw.ColorTable := DXDraw.DefColorTable;
  1659.       DXDraw.UpdatePalette;
  1660.     end;
  1661.     DXDraw.Surface.Fill(c);
  1662.     DXDraw.Flip;
  1663.   end;
  1664. end;
  1665.  
  1666. procedure TMainForm.StartScene(Scene: TGameScene);
  1667. begin
  1668.   EndScene;
  1669.   DXInput.States := DXInput.States - DXInputButton;
  1670.   FScene := Scene;
  1671.   BlinkStart;
  1672.   case FScene of
  1673.     gsTitle   : StartSceneTitle;
  1674.     gsMain    : StartSceneMain;
  1675.     gsGameOver: StartSceneGameOver;
  1676.     gsWin     : StartSceneWin;
  1677.     gsNewLevel: StartSceneNewLevel;
  1678.   end;
  1679. end;
  1680.  
  1681. procedure TMainForm.StartSceneTitle;
  1682. begin
  1683.   sleep(500);
  1684.   FCheat := false;
  1685.   FLife := StartLives;
  1686.   FLevel := 0;
  1687.   FScore := 0;
  1688.   FLevelDataAlreadyLoaded := false; // do allow NewLevel() to work again
  1689.   FNotSave := true;
  1690.   Cheat.enabled := false;
  1691.   Neustart.enabled := false;
  1692.   GamePause.enabled := false;
  1693.   GameStart.enabled := false;
  1694.   Spielgeschwindigkeit.enabled := false;
  1695.   mainform.Visible := true;
  1696.   MusicSwitchTrack(smmTitle);
  1697. end;
  1698.  
  1699. procedure TMainForm.StartSceneMain;
  1700. {var
  1701.   i, j: Integer;}
  1702. begin
  1703.   sleep(500);
  1704.   FCounter := 0;
  1705.   if not FLevelDataAlreadyLoaded then NewLevel(FLevel);
  1706.   FRestEnemies := Length(LevelData.EnemyAdventTable);
  1707.   FBossImLevel := LevelData.HasBoss;
  1708.   FBossLife := -1; // Boss noch nicht aufgetaucht
  1709.   FLifeAtLevelStart := FLife;     // Das ist wichtig, wenn man neu starten mƶchte
  1710.   FScoreAtLevelStart := FScore;   //
  1711.   MusicSwitchTrack(smmGame);
  1712.   FEnemyAdventPos := 0;
  1713.   FFrame := -4;
  1714.   PlayerSprite := TPlayerSprite.Create(SpriteEngine.Engine);
  1715.   with TBackground.Create(SpriteEngine.Engine) do
  1716.   begin
  1717.     SetMapSize(1, 1);
  1718.     Image := MainForm.GetSpriteGraphic(smgStar3);
  1719.     Z := -13;
  1720.     Y := 40;
  1721.     Speed := 1 / 2;
  1722.     Tile := True;
  1723.   end;
  1724.   with TBackground.Create(SpriteEngine.Engine) do
  1725.   begin
  1726.     SetMapSize(1, 1);
  1727.     Image := MainForm.GetSpriteGraphic(smgStar2);
  1728.     Z := -12;
  1729.     Y := 30;
  1730.     Speed := 1;
  1731.     Tile := True;
  1732.   end;
  1733.   with TBackground.Create(SpriteEngine.Engine) do
  1734.   begin
  1735.     SetMapSize(1, 1);
  1736.     Image := MainForm.GetSpriteGraphic(smgStar1);
  1737.     Z := -11;
  1738.     Y := 10;
  1739.     Speed := 2;
  1740.     Tile := True;
  1741.   end;
  1742.   {with TBackground.Create(SpriteEngine.Engine) do
  1743.   begin
  1744.     SetMapSize(200, 10);
  1745.     Y := 10;
  1746.     Z := -13;
  1747.     Speed := 1 / 2;
  1748.     Tile := True;
  1749.     for i := 0 to MapHeight-1 do
  1750.     begin
  1751.       for j := 0 to MapWidth-1 do
  1752.       begin
  1753.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 8);
  1754.         if Random(100)<95 then Chips[j, i] := -1;
  1755.       end;
  1756.     end;
  1757.   end;
  1758.   with TBackground.Create(SpriteEngine.Engine) do
  1759.   begin
  1760.     SetMapSize(200, 10);
  1761.     Y := 30;
  1762.     Z := -12;
  1763.     Speed := 1;
  1764.     Tile := True;
  1765.     for i := 0 to MapHeight-1 do
  1766.     begin
  1767.       for j := 0 to MapWidth-1 do
  1768.       begin
  1769.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 4);
  1770.         if Random(100)<95 then Chips[j, i] := -1;
  1771.       end;
  1772.     end;
  1773.   end;
  1774.   with TBackground.Create(SpriteEngine.Engine) do
  1775.   begin
  1776.     SetMapSize(200, 10);
  1777.     Y := 40;
  1778.     Z := -11;
  1779.     Speed := 2;
  1780.     Tile := True;
  1781.     for i := 0 to MapHeight-1 do
  1782.     begin
  1783.       for j := 0 to MapWidth-1 do
  1784.       begin
  1785.         Chips[j, i] := Image.PatternCount-Random(Image.PatternCount div 2);
  1786.         if Random(100)<95 then Chips[j, i] := -1;
  1787.       end;
  1788.     end;
  1789.   end;}
  1790.   FNotSave := false;
  1791.   Cheat.enabled := true;
  1792.   Neustart.enabled := true;
  1793.   GamePause.enabled := true;
  1794.   GameStart.enabled := true;
  1795.   Spielgeschwindigkeit.enabled := true;
  1796. end;
  1797.  
  1798. procedure TMainForm.StartSceneGameOver;
  1799. begin
  1800.   sleep(500);
  1801.   FNotSave := true; // Wenn man speichert, wĆ¼rde man LevelAdventTable vom vorherigen Level machen, das wƤr mĆ¼ll!
  1802.   Cheat.enabled := false;
  1803.   Spielgeschwindigkeit.enabled := false;
  1804.   Neustart.enabled := false;
  1805.   GamePause.enabled := false;
  1806.   MusicSwitchTrack(smmScene);
  1807. end;
  1808.  
  1809. procedure TMainForm.StartSceneWin;
  1810. begin
  1811.   sleep(500);
  1812.   FNotSave := true; // Wenn man speichert, wĆ¼rde man LevelAdventTable vom vorherigen Level machen, das wƤr mĆ¼ll!
  1813.   Cheat.enabled := false;
  1814.   Spielgeschwindigkeit.enabled := false;
  1815.   Neustart.enabled := false;
  1816.   GamePause.enabled := false;
  1817.   MusicSwitchTrack(smmScene);
  1818. end;
  1819.  
  1820. procedure TMainForm.EndScene;
  1821. begin
  1822.   case FScene of
  1823.     gsTitle   : EndSceneTitle;
  1824.     gsMain    : EndSceneMain;
  1825.     gsGameOver: EndSceneGameOver;
  1826.     gsWin     : EndSceneWin;
  1827.     gsNewLevel: EndSceneNewLevel;
  1828.   end;
  1829. end;
  1830.  
  1831. procedure TMainForm.EndSceneTitle;
  1832. begin
  1833.   {  Ende Title  }
  1834. end;
  1835.  
  1836. procedure TMainForm.EndSceneMain;
  1837. begin
  1838.   SpriteEngine.Engine.Clear;
  1839. end;
  1840.  
  1841. procedure TMainForm.EndSceneGameOver;
  1842. begin
  1843.   {  Ende GameOver  }
  1844. end;
  1845.  
  1846. procedure TMainForm.EndSceneWin;
  1847. begin
  1848.   {  Ende Win  }
  1849. end;
  1850.  
  1851. procedure TMainForm.ResetLevelData;
  1852. begin
  1853.   LevelData.Clear;
  1854.   FRestEnemies := 0;
  1855. end;
  1856.  
  1857. procedure TMainForm.NewLevel(lev: integer);
  1858. resourcestring
  1859.   SLevelInvalid = 'Das Level Nr. %d ist ungĆ¼ltig!'+#13#10+'Das Programm wird beendet.';
  1860. const
  1861.   RandomLevelMaxEnemyLives = 10;
  1862. var
  1863.   act: integer;
  1864.   Enemies: array[1..32] of TEnemyType;
  1865.   numEnemies: integer;
  1866.   e: TEnemyAdvent;
  1867.   bossPosition: integer;
  1868.   levFile: TLevelFile;
  1869. begin
  1870.   ResetLevelData;
  1871.   if FGameMode = gmRandom then
  1872.   begin
  1873.     {$REGION 'Random game'}
  1874.     Enemies[1] := etEnemyAttacker;     // ab Lev 1
  1875.     Enemies[2] := etEnemyMeteor;       // ab Lev 1
  1876.     Enemies[3] := etEnemyUFO;          // ab Lev 1
  1877.     Enemies[4] := etEnemyAttacker;     // ab Lev 2
  1878.     Enemies[5] := etEnemyMeteor;       // ab Lev 3
  1879.     Enemies[6] := etEnemyUFO;          // ab Lev 4
  1880.     Enemies[7] := etEnemyAttacker;     // ab Lev 5
  1881.     Enemies[8] := etEnemyMeteor;       // ab Lev 6
  1882.     Enemies[9] := etEnemyUFO;          // ab Lev 7
  1883.     Enemies[10] := etEnemyAttacker;    // ab Lev 8
  1884.     Enemies[11] := etEnemyMeteor;      // ab Lev 9
  1885.     Enemies[12] := etEnemyUFO;         // ab Lev 10
  1886.     Enemies[13] := etEnemyAttacker;    // ab Lev 11
  1887.     Enemies[14] := etEnemyMeteor;      // ab Lev 12
  1888.     Enemies[15] := etEnemyUFO;         // ab Lev 13
  1889.     Enemies[16] := etEnemyAttacker3;   // ab Lev 14
  1890.     Enemies[17] := etEnemyAttacker;    // ab Lev 15
  1891.     Enemies[18] := etEnemyMeteor;      // ab Lev 16
  1892.     Enemies[19] := etEnemyUFO;         // ab Lev 17
  1893.     Enemies[20] := etEnemyUFO2;        // ab Lev 18
  1894.     Enemies[21] := etEnemyAttacker;    // ab Lev 19
  1895.     Enemies[22] := etEnemyMeteor;      // ab Lev 20
  1896.     Enemies[23] := etEnemyUFO;         // ab Lev 21
  1897.     Enemies[24] := etEnemyAttacker2;   // ab Lev 22
  1898.     Enemies[25] := etEnemyMeteor;      // ab Lev 23
  1899.     Enemies[26] := etEnemyUFO;         // ab Lev 24
  1900.     Enemies[27] := etEnemyAttacker;    // ab Lev 25
  1901.     Enemies[28] := etEnemyAttacker;    // ab Lev 26
  1902.     Enemies[29] := etEnemyAttacker2;   // ab Lev 27
  1903.     Enemies[30] := etEnemyAttacker3;   // ab Lev 28
  1904.     Enemies[31] := etEnemyUFO;         // ab Lev 29
  1905.     Enemies[32] := etEnemyUFO2;        // ab Lev 30
  1906.     numEnemies := lev*ADDITIONAL_ENEMIES_PER_LEVEL;
  1907.     SetLength(LevelData.EnemyAdventTable, numEnemies);
  1908.     for act := 0 to numEnemies-1 do
  1909.     begin
  1910.       e.enemyType := Enemies[min(random(lev+2)+1, High(Enemies))];
  1911.       if e.enemyType = etEnemyAttacker2 then
  1912.       begin
  1913.         //e.enemyType := Enemies[min(random(lev+2)+1, High(Enemies))];
  1914.         if Random(2) = 0 then e.enemyType := etEnemyAttacker3;
  1915.       end;
  1916.       e.x := 85-(lev+(random(lev))*2){O_o};
  1917.       if e.x < 1 then e.x := 1; // passiert bei groƟen Levels
  1918.       e.x := act*30 + random(e.x);
  1919.       e.y := random(dxdraw.surfaceheight);
  1920.       if e.enemyType = etEnemyAttacker2 then
  1921.       begin
  1922.         e.lifes := random(6)+1{O_o};
  1923.       end
  1924.       else
  1925.       begin
  1926.         if lev > RandomLevelMaxEnemyLives then
  1927.         begin
  1928.           e.lifes := random(RandomLevelMaxEnemyLives)+1;
  1929.         end
  1930.         else
  1931.         begin
  1932.           e.lifes := random(lev)+1;
  1933.         end;
  1934.       end;
  1935.  
  1936.       if (act-1) mod 200 = 0 then
  1937.       begin
  1938.         e.enemyType := etItemMedikit;
  1939.         e.lifes := 0;
  1940.       end;
  1941.  
  1942.       LevelData.EnemyAdventTable[act] := e;
  1943.     end;
  1944.  
  1945.     if lev < 5 then
  1946.     begin
  1947.       // Level 1-4: No boss
  1948.       bossPosition := -1;
  1949.     end
  1950.     else if lev < 10 then
  1951.     begin
  1952.       // Level 5-9: Boss is at the end of the level
  1953.       bossPosition := numEnemies-1;
  1954.     end
  1955.     else
  1956.     begin
  1957.       // Starting with Level 10: Boss at 75% of the level
  1958.       bossPosition := round(0.75 * numEnemies);
  1959.     end;
  1960.  
  1961.     if LevelData.EnemyAdventTable[bossPosition].enemyType = etItemMedikit then
  1962.       Inc(bossPosition);
  1963.  
  1964.     if bossPosition >= 0 then
  1965.     begin
  1966.       e.enemyType := etEnemyBoss;
  1967.       //e.x := lev*75*30{O_o} div lev;
  1968.       e.x := LevelData.EnemyAdventTable[bossPosition-1].x;
  1969.       e.y := (dxdraw.surfaceheight div 2) - (MainForm.GetSpriteGraphic(smgEnemyBoss).height div 2);
  1970.       e.lifes := lev*5;
  1971.       LevelData.EnemyAdventTable[bossPosition] := e;
  1972.     end;
  1973.  
  1974.     {$ENDREGION}
  1975.   end
  1976.   else
  1977.   begin
  1978.     {$REGION 'Normal game'}
  1979.     levFile := GetLevelFileName(lev,false);
  1980.     if levFile.found then
  1981.     begin
  1982.       try
  1983.         LevelData.RasterErzwingen := false;
  1984.         LevelData.LoadFromFile(levFile.fileLocation);
  1985.       except
  1986.         showmessage(Format(SLevelInvalid, [lev]));
  1987.         ResetLevelData;
  1988.       end;
  1989.     end;
  1990.     {$ENDREGION}
  1991.   end;
  1992.   FLevelDataAlreadyLoaded := true; // nicht nochmal NewLevel() aufrufen. Erst wieder wenn man gewonnen hat.
  1993. end;
  1994.  
  1995. var
  1996.   TitleWasPressed: TDxInputState = isButton32;
  1997.  
  1998. procedure TMainForm.SceneTitle;
  1999. var
  2000.   Logo: TPictureCollectionItem;
  2001.   colo1, colo2: TColor;
  2002. begin
  2003.   DXDraw.Surface.Fill(0);
  2004.   Logo := GetSpriteGraphic(smgLogo);
  2005.   {Logo.DrawWaveX(DXDraw.Surface, (dxdraw.surfaceWidth div 2) - 181, 65, Logo.Width, Logo.Height, 0,
  2006.     Trunc(16 - Cos256(FBlink div 60) * 16), 32, -FBlink div 5);}
  2007.   Logo.DrawWaveX(DXDraw.Surface, trunc((dxdraw.surfaceWidth / 2) - (Logo.Width / 2)), 65, Logo.Width, Logo.Height, 0,
  2008.     2, 80, Fangle * 4);
  2009.   inc(Fangle);
  2010.  
  2011.   if FGameMode = gmUnknown then FGameMode := gmLevels;
  2012.  
  2013.   if (isUp in MainForm.DXInput.States) then TitleWasPressed := isUp;
  2014.   if (TitleWasPressed=isUp) and not (isUp in MainForm.DXInput.States) then
  2015.   begin
  2016.     TitleWasPressed := isButton32;
  2017.     if (Ord(FGameMode) <> 1) then
  2018.       FGameMode := TGameMode(Ord(FGameMode)-1);
  2019.   end;
  2020.  
  2021.   if (isDown in MainForm.DXInput.States) then TitleWasPressed := isDown;
  2022.   if (TitleWasPressed=isDown) and not (isDown in MainForm.DXInput.States) then
  2023.   begin
  2024.     TitleWasPressed := isButton32;
  2025.     if (FGameMode <> High(TGameMode)) then
  2026.       FGameMode := TGameMode(Ord(FGameMode)+1);
  2027.   end;
  2028.  
  2029.   DXDraw.Surface.Canvas.Brush.Style := bsClear;
  2030.   DXDraw.Surface.Canvas.Font.Size := 30;
  2031.  
  2032.   {$REGION 'Menu point: Normal Level'}
  2033.   if FGameMode = gmLevels then
  2034.   begin
  2035.     colo1 := clMaroon;
  2036.     colo2 := clRed;
  2037.   end
  2038.   else
  2039.   begin
  2040.     colo1 := clOlive;
  2041.     colo2 := clYellow;
  2042.   end;
  2043.   DXDraw.Surface.Canvas.Font.Color := colo1;
  2044.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)-52, 'Normales Spiel');
  2045.   if FGameMode = gmLevels then
  2046.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)-52, '>');
  2047.   DXDraw.Surface.Canvas.Font.Color := colo2;
  2048.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2)-50, 'Normales Spiel');
  2049.   if FGameMode = gmLevels then
  2050.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)-50, '>');
  2051.   {$ENDREGION}
  2052.  
  2053.   {$REGION 'Menu point: Random Level'}
  2054.   if FGameMode = gmRandom then
  2055.   begin
  2056.     colo1 := clMaroon;
  2057.     colo2 := clRed;
  2058.   end
  2059.   else
  2060.   begin
  2061.     colo1 := clOlive;
  2062.     colo2 := clYellow;
  2063.   end;
  2064.   DXDraw.Surface.Canvas.Font.Color := colo1;
  2065.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)-2, 'Zufallslevel');
  2066.   if FGameMode = gmRandom then
  2067.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, (dxdraw.surfaceheight div 2)-2, '>');
  2068.   DXDraw.Surface.Canvas.Font.Color := colo2;
  2069.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2), 'Zufallslevel');
  2070.   if FGameMode = gmRandom then
  2071.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2), '>');
  2072.   {$ENDREGION}
  2073.  
  2074.   {$REGION 'Menu point: Level Editor'}
  2075.   if FGameMode = gmEditor then
  2076.   begin
  2077.     colo1 := clMaroon;
  2078.     colo2 := clRed;
  2079.   end
  2080.   else
  2081.   begin
  2082.     colo1 := clOlive;
  2083.     colo2 := clYellow;
  2084.   end;
  2085.   DXDraw.Surface.Canvas.Font.Color := colo1;
  2086.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)+48, 'Level-Editor');
  2087.   if FGameMode = gmEditor then
  2088.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)+48, '>');
  2089.   DXDraw.Surface.Canvas.Font.Color := colo2;
  2090.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2)+50, 'Level-Editor');
  2091.   if FGameMode = gmEditor then
  2092.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)+50, '>');
  2093.   {$ENDREGION}
  2094.  
  2095.   { if (FBlink div 300) mod 2=0 then
  2096.   begin
  2097.     DXDraw.Surface.Canvas.Font.Color := clGreen;
  2098.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
  2099.     DXDraw.Surface.Canvas.Font.Color := clLime;
  2100.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
  2101.   end; }
  2102.   BlinkUpdate;
  2103.   DXDraw.Surface.Canvas.Release;
  2104.  
  2105.   // Weiter mit Leertaste oder Enter
  2106.   if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
  2107.   begin
  2108.     FLevel := 1;
  2109.     if FGameMode = gmEditor then
  2110.     begin
  2111.       ShellExecute(0, 'open', PChar(OwnDirectory+LevEditExe), '', PChar(OwnDirectory), SW_NORMAL); // do not localize
  2112.       Close;
  2113.       exit;
  2114.     end;
  2115.     if ((FGameMode=gmLevels) and not GetLevelFileName(FLevel,false).found) or
  2116.        ((FGameMode=gmRandom) and (FLevel > MaxPossibleLevels)) then
  2117.     begin
  2118.       //PlaySound('Frage', False);
  2119.       exit;
  2120.     end;
  2121.     PlaySound(smsSceneMov, False);
  2122.     PalleteAnim(RGBQuad(0, 0, 0), 300);
  2123.     Sleep(200);
  2124.     StartScene(gsMain);
  2125.   end;
  2126. end;
  2127.  
  2128. procedure TMainForm.SceneMain;
  2129. resourcestring
  2130.   SMissionSucsessful = 'Mission erfolgreich!';
  2131.   SMissionFailed = 'Mission gescheitert!';
  2132.   SPunkte = 'Punkte: %s'; // TODO: Is %f or FloatToStrF() better for internationalization?
  2133.   SLevel = 'Level: %d';
  2134.   SLifes = 'Leben: %d';
  2135.   SInfLifes = '';
  2136.   SBossLifes = 'Boss: %d';
  2137.   SEinheiten = 'Einheiten: %d';
  2138. var
  2139.   Enemy: TSprite;
  2140.   spriteClass: TClass;
  2141.   tmpEnemyAnzeige: integer;
  2142. begin
  2143.   case FInterval of
  2144.     giLeicht: SpriteEngine.Move(conleicht);
  2145.     giMittel: SpriteEngine.Move(conmittel);
  2146.     giSchwer: SpriteEngine.Move(conschwer);
  2147.     giMaster: SpriteEngine.Move(conmaster);
  2148.   end;
  2149.   SpriteEngine.Dead;
  2150.   while (FEnemyAdventPos >= Low(LevelData.EnemyAdventTable)) and
  2151.     (FEnemyAdventPos <= High(LevelData.EnemyAdventTable)) and
  2152.     ((LevelData.EnemyAdventTable[FEnemyAdventPos].x / 4) <= FFrame) and
  2153.     (FRestEnemies > 0) do
  2154.   begin
  2155.     Dec(FRestEnemies);
  2156.     with LevelData.EnemyAdventTable[FEnemyAdventPos] do
  2157.     begin
  2158.       spriteClass := nil;
  2159.       case enemyType of
  2160.         //etUnknown: ;
  2161.         etEnemyAttacker:  spriteClass := TEnemyAttacker;
  2162.         etEnemyAttacker2: spriteClass := TEnemyAttacker2;
  2163.         etEnemyAttacker3: spriteClass := TEnemyAttacker3;
  2164.         etEnemyMeteor:    spriteClass := TEnemyMeteor;
  2165.         etEnemyUFO:       spriteClass := TEnemyUFO;
  2166.         etEnemyUFO2:      spriteClass := TEnemyUFO2;
  2167.         etEnemyBoss:      spriteClass := TEnemyBoss;
  2168.         etItemMedikit:    spriteClass := TItemMedikit;
  2169.       end;
  2170.       if spriteClass <> nil then
  2171.       begin
  2172.         Enemy := nil;
  2173.         if spriteClass.InheritsFrom(TEnemy) then
  2174.           Enemy := TEnemyClass(spriteClass).Create(SpriteEngine.Engine, lifes)
  2175.         else if spriteClass.InheritsFrom(TItem) then
  2176.           Enemy := TItemClass(spriteClass).Create(SpriteEngine.Engine)
  2177.         else
  2178.           Assert(False);
  2179.         Enemy.x := dxdraw.surfacewidth;
  2180.         //Enemy.y := y;
  2181.         if y <> 0 then
  2182.           Enemy.y := dxdraw.surfaceheight / (480{maximale Bandbreite im alten Format} / y)
  2183.         else
  2184.           Enemy.y := 0;
  2185.       end;
  2186.     end;
  2187.     Inc(FEnemyAdventPos);
  2188.   end;
  2189.   Inc(FFrame);
  2190.   DXDraw.Surface.Fill(0);
  2191.   if FNextScene=gsNone then
  2192.   begin
  2193.     SpriteEngine.Draw;
  2194.     DXDraw.Surface.Canvas.Brush.Style := bsClear;
  2195.     DXDraw.Surface.Canvas.Font.Size := 20;
  2196.     if flife > 0 then
  2197.     begin
  2198.       {$REGION 'Anzeige Punkte'}
  2199.       DXDraw.Surface.Canvas.Font.Color := clOlive;
  2200.       DXDraw.Surface.Canvas.Textout(9, 9, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
  2201.       DXDraw.Surface.Canvas.Font.Color := clYellow;
  2202.       DXDraw.Surface.Canvas.Textout(10, 10, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
  2203.       {$ENDREGION}
  2204.  
  2205.       {$REGION 'Anzeige Level'}
  2206.       DXDraw.Surface.Canvas.Font.Color := clMaroon;
  2207.       DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, Format(SLevel, [flevel]));
  2208.       DXDraw.Surface.Canvas.Font.Color := clRed;
  2209.       DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, Format(SLevel, [flevel]));
  2210.       {$ENDREGION}
  2211.  
  2212.       {$REGION 'Lebensanzeige'}
  2213.       if FLife<0 then FLife := 0;
  2214.       if FCheat then
  2215.       begin
  2216.         DXDraw.Surface.Canvas.Font.Color := clPurple;
  2217.         DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, SInfLifes);
  2218.         DXDraw.Surface.Canvas.Font.Color := clFuchsia;
  2219.         DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, SInfLifes);
  2220.       end
  2221.       else
  2222.       begin
  2223.         if ((Flife = 1) and ((FBlink div 300) mod 2=0)) or (Flife <> 1) then
  2224.         begin
  2225.           DXDraw.Surface.Canvas.Font.Color := clPurple;
  2226.           DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, Format(SLifes, [flife]));
  2227.           DXDraw.Surface.Canvas.Font.Color := clFuchsia;
  2228.           DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, Format(SLifes, [flife]));
  2229.         end;
  2230.         if Flife = 1 then BlinkUpdate;
  2231.       end;
  2232.       {$ENDREGION}
  2233.  
  2234.       {$REGION 'Anzeige Einheiten und Boss Leben'}
  2235.  
  2236.       tmpEnemyAnzeige := EnemyCounter{Auf Bildschirm} + FRestEnemies{In der Warteschlange};
  2237.       if FBossImLevel and (FBossLife<>0) then Dec(tmpEnemyAnzeige);
  2238.  
  2239.       if FBossLife > 0 then
  2240.       begin
  2241.         if (tmpEnemyAnzeige>0) then
  2242.         begin
  2243.           DXDraw.Surface.Canvas.Font.Color := clGreen;
  2244.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-81, Format(SBossLifes, [FBossLife]));
  2245.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SEinheiten, [tmpEnemyAnzeige]));
  2246.           DXDraw.Surface.Canvas.Font.Color := clLime;
  2247.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-80, Format(SBossLifes, [FBossLife]));
  2248.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SEinheiten, [tmpEnemyAnzeige]));
  2249.         end
  2250.         else
  2251.         begin
  2252.           DXDraw.Surface.Canvas.Font.Color := clGreen;
  2253.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SBossLifes, [FBossLife]));
  2254.           DXDraw.Surface.Canvas.Font.Color := clLime;
  2255.           DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SBossLifes, [FBossLife]));
  2256.         end;
  2257.       end
  2258.       else if (FBossLife<=0) and (tmpEnemyAnzeige>0) then
  2259.       begin
  2260.         DXDraw.Surface.Canvas.Font.Color := clGreen;
  2261.         DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SEinheiten, [tmpEnemyAnzeige]));
  2262.         DXDraw.Surface.Canvas.Font.Color := clLime;
  2263.         DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SEinheiten, [tmpEnemyAnzeige]));
  2264.       end;
  2265.       {$ENDREGION}
  2266.  
  2267.       {$REGION 'Anzeige Mission erfolgreich/gescheitert'}
  2268.       if (EnemyCounter=0) and (FRestEnemies=0) and ((FBossImLevel and (FBossLife=0)) or not FBossImLevel) then
  2269.       begin
  2270.         DXDraw.Surface.Canvas.Font.Color := clGreen;
  2271.         DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionSucsessful);
  2272.         DXDraw.Surface.Canvas.Font.Color := clLime;
  2273.         DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionSucsessful);
  2274.         DXDraw.Surface.Canvas.Release;
  2275.         Sleep(1);
  2276.         inc(FCounter);
  2277.         if FCounter>150{200} then PlayerSprite.FlyAway;
  2278.       end;
  2279.       {$ENDREGION}
  2280.     end
  2281.     else
  2282.     begin
  2283.       DXDraw.Surface.Canvas.Font.Color := clMaroon;
  2284.       DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionFailed);
  2285.       DXDraw.Surface.Canvas.Font.Color := clRed;
  2286.       DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionFailed);
  2287.     end;
  2288.     DXDraw.Surface.Canvas.Release;
  2289.   end;
  2290. end;
  2291.  
  2292. procedure TMainForm.SceneGameOver;
  2293. begin
  2294.   DXDraw.Surface.Fill(0);
  2295.  
  2296.   FNotSave := true;
  2297.   Cheat.enabled := false;
  2298.   GamePause.enabled := false;
  2299.   Neustart.enabled := false;
  2300.   Brush.Style := bsClear;
  2301.   DXDraw.Surface.Canvas.Font.Size := 35;
  2302.   DXDraw.Surface.Canvas.Font.Color := clMaroon;
  2303.   DXDraw.Surface.Canvas.Textout((dxdraw.surfacewidth div 2)-127, 98, 'Game over!');
  2304.   DXDraw.Surface.Canvas.Font.Color := clRed;
  2305.   DXDraw.Surface.Canvas.Textout((dxdraw.surfacewidth div 2)-125, 100, 'Game over!');
  2306.   if (FBlink div 300) mod 2=0 then
  2307.   begin
  2308.     DXDraw.Surface.Canvas.Font.Size := 30;
  2309.     DXDraw.Surface.Canvas.Font.Color := clOlive;
  2310.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
  2311.     DXDraw.Surface.Canvas.Font.Color := clYellow;
  2312.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
  2313.   end;
  2314.   BlinkUpdate;
  2315.   DXDraw.Surface.Canvas.Release;
  2316.  
  2317.   // Weiter mit Leertaste oder Enter
  2318.   if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
  2319.   begin
  2320.     PlaySound(smsSceneMov, False);
  2321.     PalleteAnim(RGBQuad(0, 0, 0), 300);
  2322.     Sleep(200);
  2323.     StartScene(gsTitle);
  2324.   end;
  2325. end;
  2326.  
  2327. procedure TMainForm.SceneWin;
  2328. begin
  2329.   DXDraw.Surface.Fill(0);
  2330.  
  2331.   FNotSave := true;
  2332.   Cheat.enabled := false;
  2333.   GamePause.enabled := false;
  2334.   Neustart.enabled := false;
  2335.  
  2336.   DXDraw.Surface.Canvas.Brush.Style := bsClear;
  2337.   DXDraw.Surface.Canvas.Font.Size := 35;
  2338.   DXDraw.Surface.Canvas.Font.Color := clMaroon;
  2339.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-127, 98, 'Gewonnen!');
  2340.   DXDraw.Surface.Canvas.Font.Color := clRed;
  2341.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-125, 100, 'Gewonnen!');
  2342.   if (FBlink div 300) mod 2=0 then
  2343.   begin
  2344.     DXDraw.Surface.Canvas.Font.Size := 30;
  2345.     DXDraw.Surface.Canvas.Font.Color := clOlive;
  2346.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
  2347.     DXDraw.Surface.Canvas.Font.Color := clYellow;
  2348.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
  2349.   end;
  2350.   BlinkUpdate;
  2351.   DXDraw.Surface.Canvas.Release;
  2352.  
  2353.   // Weiter mit Leertaste oder Enter
  2354.   if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
  2355.   begin
  2356.     PlaySound(smsSceneMov, False);
  2357.     PalleteAnim(RGBQuad(0, 0, 0), 300);
  2358.     Sleep(200);
  2359.     StartScene(gsTitle);
  2360.   end;
  2361. end;
  2362.  
  2363. procedure TMainForm.StartSceneNewLevel;
  2364. begin
  2365.   sleep(500);
  2366.   FNotSave := true; // Wenn man speichert, wĆ¼rde man LevelAdventTable vom vorherigen Level machen, das wƤr mĆ¼ll!
  2367.   Cheat.enabled := false;
  2368.   Neustart.enabled := false;
  2369.   GamePause.enabled := false;
  2370.   GameStart.enabled := true;
  2371.   Spielgeschwindigkeit.enabled := false;
  2372.   Spielgeschwindigkeit.enabled := false;
  2373.   if ((FGameMode=gmLevels) and not GetLevelFileName(FLevel,false).found)
  2374.      // or ((FGameMode=gmRandom) and (FLevel > 25))
  2375.      or (FLevel > MaxPossibleLevels) then
  2376.   begin
  2377.     //PlaySound('SceneMov', False);
  2378.     PalleteAnim(RGBQuad(0, 0, 0), 300);
  2379.     Sleep(200);
  2380.     StartScene(gsWin);
  2381.     exit;
  2382.   end;
  2383.   MusicSwitchTrack(smmScene);
  2384. end;
  2385.  
  2386. procedure TMainForm.EndSceneNewLevel;
  2387. begin
  2388.   {  Ende NewLevel  }
  2389. end;
  2390.  
  2391. procedure TMainForm.SceneNewLevel;
  2392. begin
  2393.   DXDraw.Surface.Fill(0);
  2394.  
  2395.   DXDraw.Surface.Canvas.Brush.Style := bsClear;
  2396.   DXDraw.Surface.Canvas.Font.Size := 40;
  2397.   DXDraw.Surface.Canvas.Font.Color := clMaroon;
  2398.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-(83+(length(inttostr(flevel))*22)), 98, 'Level '+inttostr(flevel));
  2399.   DXDraw.Surface.Canvas.Font.Color := clRed;
  2400.   DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-(81+(length(inttostr(flevel))*22)), 100, 'Level '+inttostr(flevel));
  2401.   if (FBlink div 300) mod 2=0 then
  2402.   begin
  2403.     DXDraw.Surface.Canvas.Font.Size := 30;
  2404.     DXDraw.Surface.Canvas.Font.Color := clOlive;
  2405.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
  2406.     DXDraw.Surface.Canvas.Font.Color := clYellow;
  2407.     DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
  2408.   end;
  2409.   BlinkUpdate;
  2410.   DXDraw.Surface.Canvas.Release;
  2411.  
  2412.   // Weiter mit Leertaste oder Enter
  2413.   if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
  2414.   begin
  2415.     PlaySound(smsSceneMov, False);
  2416.     PalleteAnim(RGBQuad(0, 0, 0), 300);
  2417.     Sleep(200);
  2418.     StartScene(gsMain);
  2419.   end;
  2420. end;
  2421.  
  2422. procedure TMainForm.OptionMusicClick(Sender: TObject);
  2423. begin
  2424.   OptionMusic.Checked := not OptionMusic.Checked;
  2425.   if OptionMusic.Checked then
  2426.   begin
  2427.     MusicSwitchTrack(FMusic)
  2428.   end
  2429.   else
  2430.   begin
  2431.     StopMusic(FMusic);
  2432.   end;
  2433.   WriteOptions;
  2434. end;
  2435.  
  2436. procedure TMainForm.MasterClick(Sender: TObject);
  2437. begin
  2438.   master.checked := true;
  2439.   FInterval := giMaster;
  2440.   writeoptions;
  2441. end;
  2442.  
  2443. procedure TMainForm.PlayMusic(Name: TSpaceMissionMusicTrack);
  2444. begin
  2445.   if not OptionMusic.checked then exit;
  2446.   if Ord(Name) > dxmusic.Midis.Count then exit;
  2447.   dxmusic.Midis.Items[Ord(Name)-1].Play;
  2448. end;
  2449.  
  2450. procedure TMainForm.StopMusic(Name: TSpaceMissionMusicTrack);
  2451. begin
  2452.   if Name = smmNone then exit;
  2453.   if Ord(Name) > dxmusic.Midis.Count then exit;
  2454.   dxmusic.Midis.Items[Ord(Name)-1].Stop;
  2455. end;
  2456.  
  2457. procedure TMainForm.ResumeMusic(Name: TSpaceMissionMusicTrack);
  2458. begin
  2459.   if not OptionMusic.checked then exit;
  2460.   if Ord(Name) > dxmusic.Midis.Count then exit;
  2461.   dxmusic.Midis.Items[Ord(Name)-1].Play; // TODO: how to pause/resume instead play/stop
  2462. end;
  2463.  
  2464. procedure TMainForm.PauseMusic(Name: TSpaceMissionMusicTrack);
  2465. begin
  2466.   if Name = smmNone then exit;
  2467.   if Ord(Name) > dxmusic.Midis.Count then exit;
  2468.   dxmusic.Midis.Items[Ord(Name)-1].Stop; // TODO: how to pause/resume instead play/stop
  2469. end;
  2470.  
  2471. procedure TMainForm.SpielstandClick(Sender: TObject);
  2472. begin
  2473.   speicherungform.showmodal;
  2474. end;
  2475.  
  2476. procedure TMainForm.LevelNeuStarten;
  2477. begin
  2478.   FNextScene := gsNewLevel;
  2479.   FLife := FLifeAtLevelStart;
  2480.   FScore := FScoreAtLevelStart;
  2481. end;
  2482.  
  2483. procedure TMainForm.NeustartClick(Sender: TObject);
  2484. begin
  2485.   LevelNeuStarten;
  2486. end;
  2487.  
  2488. procedure TMainForm.LeichtClick(Sender: TObject);
  2489. begin
  2490.   leicht.checked := true;
  2491.   FInterval := giLeicht;
  2492.   writeoptions;
  2493. end;
  2494.  
  2495. procedure TMainForm.MittelClick(Sender: TObject);
  2496. begin
  2497.   mittel.checked := true;
  2498.   FInterval := giMittel;
  2499.   writeoptions;
  2500. end;
  2501.  
  2502. procedure TMainForm.SchwerClick(Sender: TObject);
  2503. begin
  2504.   schwer.checked := true;
  2505.   FInterval := giSchwer;
  2506.   writeoptions;
  2507. end;
  2508.  
  2509. procedure TMainForm.FormShow(Sender: TObject);
  2510. resourcestring
  2511.   SFileError = 'Die Datei kann von SpaceMission nicht geƶffnet werden!';
  2512. var
  2513.   SavGame: TSaveData;
  2514. begin
  2515.   if Assigned(SplashForm) then
  2516.   begin
  2517.     SplashForm.Hide;
  2518.     FreeAndNil(SplashForm);
  2519.   end;
  2520.  
  2521.   dxtimer.Enabled := true;
  2522.   dxtimer.ActiveOnly := true;
  2523.  
  2524.   ResetLevelData;
  2525.   if (paramcount > 0) and (fileexists(paramstr(1))) and (ExtractFileExt(paramstr(1)).ToLower = '.sav') then
  2526.   begin
  2527.     SavGame := TSaveData.Create;
  2528.     try
  2529.       try
  2530.         SavGame.LoadFromFile(paramstr(1));
  2531.         FScore := SavGame.Score;
  2532.         FLife := SavGame.Life;
  2533.         FLevel := SavGame.Level;
  2534.         FGameMode := SavGame.GameMode;
  2535.         FLevelDataAlreadyLoaded := true; // do not call NewLevel() in StartSceneMain
  2536.         if Assigned(SavGame.LevelData) then
  2537.         begin
  2538.           LevelData.Assign(SavGame.LevelData);
  2539.         end;
  2540.       except
  2541.         on E: Exception do
  2542.         begin
  2543.           showmessage(SFileError + ' ' +E.Message);
  2544.           GameStartClick(GameStart);
  2545.           exit;
  2546.         end;
  2547.       end;
  2548.     finally
  2549.       FreeAndNil(SavGame);
  2550.     end;
  2551.     //FNextScene := gsNewLevel;
  2552.     StartScene(gsNewLevel);
  2553.     exit;
  2554.   end;
  2555. end;
  2556.  
  2557. procedure TMainForm.InformationenClick(Sender: TObject);
  2558. begin
  2559.   dxtimer.enabled := false;
  2560.   InfoForm.showmodal;
  2561.   if not mainform.gamepause.checked then mainform.dxtimer.enabled := true;
  2562. end;
  2563.  
  2564. procedure TMainForm.CheatClick(Sender: TObject);
  2565. begin
  2566.   CheatForm.showmodal;
  2567. end;
  2568.  
  2569. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
  2570. begin
  2571.   if optionMusic.checked then StopMusic(FMusic);
  2572.   SpriteEngine.Engine.Clear;
  2573.   dxsound.Finalize;
  2574.   dxinput.Destroy;
  2575.   DXTimer.Enabled := False;
  2576. end;
  2577.  
  2578. procedure TMainForm.FormDestroy(Sender: TObject);
  2579. begin
  2580.   FreeAndNil(imagelist);
  2581.   FreeAndNil(spriteengine);
  2582.   FreeAndNil(dxdraw);
  2583.   FreeAndNil(wavelist);
  2584.   FreeAndNil(dxmusic);
  2585.   FreeAndNil(dxsound);
  2586.   //FreeAndNil(dxinput);
  2587.   FreeAndNil(dxtimer);
  2588.   DeleteCriticalSection(TimerCS);
  2589.   FreeAndNil(LevelData);
  2590. end;
  2591.  
  2592. procedure PostKeyEx32(key: Word; const shift: TShiftState; specialkey: Boolean);
  2593. {************************************************************
  2594. * Procedure PostKeyEx32
  2595. *
  2596. * Parameters:
  2597. *  key    : virtual keycode of the key to send. For printable
  2598. *           keys this is simply the ANSI code (Ord(character)).
  2599. *  shift  : state of the modifier keys. This is a set, so you
  2600. *           can set several of these keys (shift, control, alt,
  2601. *           mouse buttons) in tandem. The TShiftState type is
  2602. *           declared in the Classes Unit.
  2603. *  specialkey: normally this should be False. Set it to True to
  2604. *           specify a key on the numeric keypad, for example.
  2605. * Description:
  2606. *  Uses keybd_event to manufacture a series of key events matching
  2607. *  the passed parameters. The events go to the control with focus.
  2608. *  Note that for characters key is always the upper-case version of
  2609. *  the character. Sending without any modifier keys will result in
  2610. *  a lower-case character, sending it with [ssShift] will result
  2611. *  in an upper-case character!
  2612. // Code by P. Below
  2613. ************************************************************}
  2614. type
  2615.   TShiftKeyInfo = record
  2616.     shift: Byte;
  2617.     vkey: Byte;
  2618.   end;
  2619.   byteset = set of 0..7;
  2620. const
  2621.   shiftkeys: array [1..3] of TShiftKeyInfo =
  2622.     ((shift: Ord(ssCtrl); vkey: VK_CONTROL),
  2623.     (shift: Ord(ssShift); vkey: VK_SHIFT),
  2624.     (shift: Ord(ssAlt); vkey: VK_MENU));
  2625. var
  2626.   flag: DWORD;
  2627.   bShift: ByteSet absolute shift;
  2628.   i: Integer;
  2629. begin
  2630.   for i := 1 to 3 do
  2631.   begin
  2632.     if shiftkeys[i].shift in bShift then
  2633.       keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
  2634.   end; { For }
  2635.   if specialkey then
  2636.     flag := KEYEVENTF_EXTENDEDKEY
  2637.   else
  2638.     flag := 0;
  2639.  
  2640.   keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  2641.   flag := flag or KEYEVENTF_KEYUP;
  2642.   keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  2643.  
  2644.   for i := 3 downto 1 do
  2645.   begin
  2646.     if shiftkeys[i].shift in bShift then
  2647.       keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0),
  2648.         KEYEVENTF_KEYUP, 0);
  2649.   end; { For }
  2650. end; { PostKeyEx32 }
  2651.  
  2652. procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
  2653.   Shift: TShiftState);
  2654. begin
  2655.   if Key = VK_ESCAPE then
  2656.   begin
  2657.     // TODO: Unfortunately, you cannot see if it is already popup. It would be great if ESC closes the main menu...
  2658.     Key := 0;
  2659.     PostKeyEx32(Ord('S'), [ssAlt], False);
  2660.   end;
  2661. end;
  2662.  
  2663. end.
  2664.  
  2665.