Subversion Repositories spacemission

Rev

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