Subversion Repositories spacemission

Rev

Rev 61 | Rev 64 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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