Subversion Repositories spacemission

Rev

Rev 74 | Rev 79 | 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
74 daniel-mar 1373
  CheckForUpdates('spacemission', ProgramVersion);
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;
78 daniel-mar 1854
  Enemies: array[1..32] of TEnemyType;
40 daniel-mar 1855
  numEnemies: integer;
7 daniel-mar 1856
  e: TEnemyAdvent;
78 daniel-mar 1857
  bossPosition: 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
78 daniel-mar 1869
    Enemies[6] := etEnemyUFO;          // ab Lev 4
1870
    Enemies[7] := etEnemyAttacker;     // ab Lev 5
1871
    Enemies[8] := etEnemyMeteor;       // ab Lev 6
1872
    Enemies[9] := etEnemyUFO;          // ab Lev 7
1873
    Enemies[10] := etEnemyAttacker;    // ab Lev 8
1874
    Enemies[11] := etEnemyMeteor;      // ab Lev 9
1875
    Enemies[12] := etEnemyUFO;         // ab Lev 10
1876
    Enemies[13] := etEnemyAttacker;    // ab Lev 11
1877
    Enemies[14] := etEnemyMeteor;      // ab Lev 12
1878
    Enemies[15] := etEnemyUFO;         // ab Lev 13
1879
    Enemies[16] := etEnemyAttacker3;   // ab Lev 14
1880
    Enemies[17] := etEnemyAttacker;    // ab Lev 15
1881
    Enemies[18] := etEnemyMeteor;      // ab Lev 16
1882
    Enemies[19] := etEnemyUFO;         // ab Lev 17
1883
    Enemies[20] := etEnemyUFO2;        // ab Lev 18
1884
    Enemies[21] := etEnemyAttacker;    // ab Lev 19
1885
    Enemies[22] := etEnemyMeteor;      // ab Lev 20
1886
    Enemies[23] := etEnemyUFO;         // ab Lev 21
1887
    Enemies[24] := etEnemyAttacker2;   // ab Lev 22
1888
    Enemies[25] := etEnemyMeteor;      // ab Lev 23
1889
    Enemies[26] := etEnemyUFO;         // ab Lev 24
1890
    Enemies[27] := etEnemyAttacker;    // ab Lev 25
1891
    Enemies[28] := etEnemyAttacker;    // ab Lev 26
1892
    Enemies[29] := etEnemyAttacker2;   // ab Lev 27
1893
    Enemies[30] := etEnemyAttacker3;   // ab Lev 28
1894
    Enemies[31] := etEnemyUFO;         // ab Lev 29
1895
    Enemies[32] := etEnemyUFO2;        // ab Lev 30
40 daniel-mar 1896
    numEnemies := lev*ADDITIONAL_ENEMIES_PER_LEVEL;
1897
    SetLength(LevelData.EnemyAdventTable, numEnemies);
1898
    for act := 0 to numEnemies-1 do
3 daniel-mar 1899
    begin
14 daniel-mar 1900
      e.enemyType := Enemies[min(random(lev+2)+1, High(Enemies))];
1901
      if e.enemyType = etEnemyAttacker2 then
7 daniel-mar 1902
      begin
49 daniel-mar 1903
        //e.enemyType := Enemies[min(random(lev+2)+1, High(Enemies))];
1904
        if Random(2) = 0 then e.enemyType := etEnemyAttacker3;
7 daniel-mar 1905
      end;
39 daniel-mar 1906
      e.x := 85-(lev+(random(lev))*2){O_o};
1907
      if e.x < 1 then e.x := 1; // passiert bei großen Levels
1908
      e.x := act*30 + random(e.x);
7 daniel-mar 1909
      e.y := random(dxdraw.surfaceheight);
14 daniel-mar 1910
      if e.enemyType = etEnemyAttacker2 then
7 daniel-mar 1911
      begin
1912
        e.lifes := random(6)+1{O_o};
1913
      end
1914
      else
1915
      begin
39 daniel-mar 1916
        if lev > RandomLevelMaxEnemyLives then
37 daniel-mar 1917
        begin
39 daniel-mar 1918
          e.lifes := random(RandomLevelMaxEnemyLives)+1;
37 daniel-mar 1919
        end
1920
        else
1921
        begin
1922
          e.lifes := random(lev)+1;
1923
        end;
7 daniel-mar 1924
      end;
1925
 
78 daniel-mar 1926
      if (act-1) mod 200 = 0 then
1927
      begin
1928
        e.enemyType := etItemMedikit;
1929
        e.lifes := 0;
1930
      end;
1931
 
14 daniel-mar 1932
      LevelData.EnemyAdventTable[act] := e;
3 daniel-mar 1933
    end;
37 daniel-mar 1934
 
1935
    if lev < 5 then
1936
    begin
1937
      // Level 1-4: No boss
1938
      bossPosition := -1;
1939
    end
1940
    else if lev < 10 then
1941
    begin
1942
      // Level 5-9: Boss is at the end of the level
40 daniel-mar 1943
      bossPosition := numEnemies-1;
37 daniel-mar 1944
    end
1945
    else
1946
    begin
39 daniel-mar 1947
      // Starting with Level 10: Boss at 75% of the level
40 daniel-mar 1948
      bossPosition := round(0.75 * numEnemies);
37 daniel-mar 1949
    end;
1950
 
78 daniel-mar 1951
    if LevelData.EnemyAdventTable[bossPosition].enemyType = etItemMedikit then
1952
      Inc(bossPosition);
1953
 
37 daniel-mar 1954
    if bossPosition >= 0 then
1955
    begin
1956
      e.enemyType := etEnemyBoss;
39 daniel-mar 1957
      //e.x := lev*75*30{O_o} div lev;
1958
      e.x := LevelData.EnemyAdventTable[bossPosition-1].x;
37 daniel-mar 1959
      e.y := (dxdraw.surfaceheight div 2) - (MainForm.GetSpriteGraphic(smgEnemyBoss).height div 2);
1960
      e.lifes := lev*5;
1961
      LevelData.EnemyAdventTable[bossPosition] := e;
1962
    end;
72 daniel-mar 1963
 
14 daniel-mar 1964
    {$ENDREGION}
3 daniel-mar 1965
  end
1966
  else
1967
  begin
14 daniel-mar 1968
    {$REGION 'Normal game'}
61 daniel-mar 1969
    levFile := GetLevelFileName(lev,false);
1970
    if levFile.found then
3 daniel-mar 1971
    begin
7 daniel-mar 1972
      try
44 daniel-mar 1973
        LevelData.RasterErzwingen := false;
61 daniel-mar 1974
        LevelData.LoadFromFile(levFile.fileLocation);
7 daniel-mar 1975
      except
1976
        showmessage(Format(LNG_LEVEL_INVALID, [lev]));
14 daniel-mar 1977
        ResetLevelData;
3 daniel-mar 1978
      end;
1979
    end;
14 daniel-mar 1980
    {$ENDREGION}
3 daniel-mar 1981
  end;
46 daniel-mar 1982
  FLevelDataAlreadyLoaded := true; // nicht nochmal NewLevel() aufrufen. Erst wieder wenn man gewonnen hat.
3 daniel-mar 1983
end;
1984
 
65 daniel-mar 1985
var
1986
  TitleWasPressed: TDxInputState = isButton32;
1987
 
3 daniel-mar 1988
procedure TMainForm.SceneTitle;
1989
var
1990
  Logo: TPictureCollectionItem;
65 daniel-mar 1991
  colo1, colo2: TColor;
3 daniel-mar 1992
begin
1993
  DXDraw.Surface.Fill(0);
31 daniel-mar 1994
  Logo := GetSpriteGraphic(smgLogo);
3 daniel-mar 1995
  {Logo.DrawWaveX(DXDraw.Surface, (dxdraw.surfaceWidth div 2) - 181, 65, Logo.Width, Logo.Height, 0,
1996
    Trunc(16 - Cos256(FBlink div 60) * 16), 32, -FBlink div 5);}
1997
  Logo.DrawWaveX(DXDraw.Surface, trunc((dxdraw.surfaceWidth / 2) - (Logo.Width / 2)), 65, Logo.Width, Logo.Height, 0,
1998
    2, 80, Fangle * 4);
1999
  inc(Fangle);
23 daniel-mar 2000
 
65 daniel-mar 2001
  if FGameMode = gmUnknown then FGameMode := gmLevels;
2002
 
2003
  if (isUp in MainForm.DXInput.States) then TitleWasPressed := isUp;
2004
  if (TitleWasPressed=isUp) and not (isUp in MainForm.DXInput.States) then
2005
  begin
2006
    TitleWasPressed := isButton32;
2007
    if (Ord(FGameMode) <> 1) then
2008
      FGameMode := TGameMode(Ord(FGameMode)-1);
2009
  end;
2010
 
2011
  if (isDown in MainForm.DXInput.States) then TitleWasPressed := isDown;
2012
  if (TitleWasPressed=isDown) and not (isDown in MainForm.DXInput.States) then
2013
  begin
2014
    TitleWasPressed := isButton32;
2015
    if (FGameMode <> High(TGameMode)) then
2016
      FGameMode := TGameMode(Ord(FGameMode)+1);
2017
  end;
2018
 
23 daniel-mar 2019
  DXDraw.Surface.Canvas.Brush.Style := bsClear;
2020
  DXDraw.Surface.Canvas.Font.Size := 30;
65 daniel-mar 2021
 
2022
  {$REGION 'Menu point: Normal Level'}
23 daniel-mar 2023
  if FGameMode = gmLevels then
3 daniel-mar 2024
  begin
65 daniel-mar 2025
    colo1 := clMaroon;
2026
    colo2 := clRed;
2027
  end
2028
  else
2029
  begin
2030
    colo1 := clOlive;
2031
    colo2 := clYellow;
2032
  end;
2033
  DXDraw.Surface.Canvas.Font.Color := colo1;
2034
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)-52, 'Normales Spiel');
2035
  if FGameMode = gmLevels then
2036
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)-52, '>');
2037
  DXDraw.Surface.Canvas.Font.Color := colo2;
2038
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2)-50, 'Normales Spiel');
2039
  if FGameMode = gmLevels then
23 daniel-mar 2040
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)-50, '>');
65 daniel-mar 2041
  {$ENDREGION}
2042
 
2043
  {$REGION 'Menu point: Random Level'}
2044
  if FGameMode = gmRandom then
2045
  begin
2046
    colo1 := clMaroon;
2047
    colo2 := clRed;
23 daniel-mar 2048
  end
2049
  else
2050
  begin
65 daniel-mar 2051
    colo1 := clOlive;
2052
    colo2 := clYellow;
2053
  end;
2054
  DXDraw.Surface.Canvas.Font.Color := colo1;
2055
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)-2, 'Zufallslevel');
2056
  if FGameMode = gmRandom then
23 daniel-mar 2057
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, (dxdraw.surfaceheight div 2)-2, '>');
65 daniel-mar 2058
  DXDraw.Surface.Canvas.Font.Color := colo2;
2059
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2), 'Zufallslevel');
2060
  if FGameMode = gmRandom then
23 daniel-mar 2061
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2), '>');
65 daniel-mar 2062
  {$ENDREGION}
2063
 
2064
  {$REGION 'Menu point: Level Editor'}
2065
  if FGameMode = gmEditor then
2066
  begin
2067
    colo1 := clMaroon;
2068
    colo2 := clRed;
2069
  end
2070
  else
2071
  begin
2072
    colo1 := clOlive;
2073
    colo2 := clYellow;
3 daniel-mar 2074
  end;
65 daniel-mar 2075
  DXDraw.Surface.Canvas.Font.Color := colo1;
2076
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-152, (dxdraw.surfaceheight div 2)+48, 'Level-Editor');
2077
  if FGameMode = gmEditor then
2078
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)+48, '>');
2079
  DXDraw.Surface.Canvas.Font.Color := colo2;
2080
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-150, (dxdraw.surfaceheight div 2)+50, 'Level-Editor');
2081
  if FGameMode = gmEditor then
2082
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, (dxdraw.surfaceheight div 2)+50, '>');
2083
  {$ENDREGION}
2084
 
23 daniel-mar 2085
  { if (FBlink div 300) mod 2=0 then
2086
  begin
2087
    DXDraw.Surface.Canvas.Font.Color := clGreen;
2088
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
2089
    DXDraw.Surface.Canvas.Font.Color := clLime;
2090
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
2091
  end; }
2092
  BlinkUpdate;
2093
  DXDraw.Surface.Canvas.Release;
2094
 
3 daniel-mar 2095
  // Weiter mit Leertaste oder Enter
2096
  if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
2097
  begin
2098
    FLevel := 1;
65 daniel-mar 2099
    if FGameMode = gmEditor then
3 daniel-mar 2100
    begin
65 daniel-mar 2101
      ShellExecute(0, 'open', PChar(OwnDirectory+'LevEdit.exe'), '', PChar(OwnDirectory), SW_NORMAL);
2102
      Close;
2103
      exit;
2104
    end;
2105
    if ((FGameMode=gmLevels) and not GetLevelFileName(FLevel,false).found) or
2106
       ((FGameMode=gmRandom) and (FLevel > MaxPossibleLevels)) then
2107
    begin
3 daniel-mar 2108
      //PlaySound('Frage', False);
2109
      exit;
2110
    end;
31 daniel-mar 2111
    PlaySound(smsSceneMov, False);
3 daniel-mar 2112
    PalleteAnim(RGBQuad(0, 0, 0), 300);
2113
    Sleep(200);
2114
    StartScene(gsMain);
2115
  end;
2116
end;
2117
 
2118
procedure TMainForm.SceneMain;
2119
var
2120
  Enemy: TSprite;
72 daniel-mar 2121
  spriteClass: TClass;
37 daniel-mar 2122
  tmpEnemyAnzeige: integer;
3 daniel-mar 2123
begin
7 daniel-mar 2124
  case FInterval of
32 daniel-mar 2125
    giLeicht: SpriteEngine.Move(conleicht);
2126
    giMittel: SpriteEngine.Move(conmittel);
7 daniel-mar 2127
    giSchwer: SpriteEngine.Move(conschwer);
2128
    giMaster: SpriteEngine.Move(conmaster);
2129
  end;
3 daniel-mar 2130
  SpriteEngine.Dead;
14 daniel-mar 2131
  while (FEnemyAdventPos >= Low(LevelData.EnemyAdventTable)) and
2132
    (FEnemyAdventPos <= High(LevelData.EnemyAdventTable)) and
2133
    ((LevelData.EnemyAdventTable[FEnemyAdventPos].x / 4) <= FFrame) and
7 daniel-mar 2134
    (FRestEnemies > 0) do
3 daniel-mar 2135
  begin
7 daniel-mar 2136
    Dec(FRestEnemies);
14 daniel-mar 2137
    with LevelData.EnemyAdventTable[FEnemyAdventPos] do
3 daniel-mar 2138
    begin
14 daniel-mar 2139
      spriteClass := nil;
2140
      case enemyType of
2141
        //etUnknown: ;
2142
        etEnemyAttacker:  spriteClass := TEnemyAttacker;
2143
        etEnemyAttacker2: spriteClass := TEnemyAttacker2;
2144
        etEnemyAttacker3: spriteClass := TEnemyAttacker3;
2145
        etEnemyMeteor:    spriteClass := TEnemyMeteor;
2146
        etEnemyUFO:       spriteClass := TEnemyUFO;
2147
        etEnemyUFO2:      spriteClass := TEnemyUFO2;
2148
        etEnemyBoss:      spriteClass := TEnemyBoss;
72 daniel-mar 2149
        etItemMedikit:    spriteClass := TItemMedikit;
14 daniel-mar 2150
      end;
2151
      if spriteClass <> nil then
2152
      begin
72 daniel-mar 2153
        Enemy := nil;
2154
        if spriteClass.InheritsFrom(TEnemy) then
2155
          Enemy := TEnemyClass(spriteClass).Create(SpriteEngine.Engine, lifes)
2156
        else if spriteClass.InheritsFrom(TItem) then
2157
          Enemy := TItemClass(spriteClass).Create(SpriteEngine.Engine)
2158
        else
2159
          Assert(False);
14 daniel-mar 2160
        Enemy.x := dxdraw.surfacewidth;
2161
        //Enemy.y := y;
2162
        if y <> 0 then
2163
          Enemy.y := dxdraw.surfaceheight / (480{maximale Bandbreite im alten Format} / y)
2164
        else
2165
          Enemy.y := 0;
2166
      end;
3 daniel-mar 2167
    end;
2168
    Inc(FEnemyAdventPos);
2169
  end;
2170
  Inc(FFrame);
2171
  DXDraw.Surface.Fill(0);
2172
  if FNextScene=gsNone then
2173
  begin
2174
    SpriteEngine.Draw;
40 daniel-mar 2175
    DXDraw.Surface.Canvas.Brush.Style := bsClear;
2176
    DXDraw.Surface.Canvas.Font.Size := 20;
47 daniel-mar 2177
    if flife > 0 then
3 daniel-mar 2178
    begin
40 daniel-mar 2179
      {$REGION 'Anzeige Punkte'}
23 daniel-mar 2180
      DXDraw.Surface.Canvas.Font.Color := clOlive;
2181
      DXDraw.Surface.Canvas.Textout(9, 9, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
2182
      DXDraw.Surface.Canvas.Font.Color := clYellow;
2183
      DXDraw.Surface.Canvas.Textout(10, 10, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
37 daniel-mar 2184
      {$ENDREGION}
2185
 
2186
      {$REGION 'Anzeige Level'}
40 daniel-mar 2187
      DXDraw.Surface.Canvas.Font.Color := clMaroon;
47 daniel-mar 2188
      DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, 'Level: ' + IntToStr(flevel));
23 daniel-mar 2189
      DXDraw.Surface.Canvas.Font.Color := clRed;
47 daniel-mar 2190
      DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, 'Level: ' + IntToStr(flevel));
37 daniel-mar 2191
      {$ENDREGION}
2192
 
2193
      {$REGION 'Lebensanzeige'}
47 daniel-mar 2194
      if FLife<0 then FLife := 0;
23 daniel-mar 2195
      if FCheat then
3 daniel-mar 2196
      begin
23 daniel-mar 2197
        DXDraw.Surface.Canvas.Font.Color := clPurple;
2198
        DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, 'Leben: ?');
2199
        DXDraw.Surface.Canvas.Font.Color := clFuchsia;
2200
        DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ?');
2201
      end
2202
      else
2203
      begin
2204
        if ((Flife = 1) and ((FBlink div 300) mod 2=0)) or (Flife <> 1) then
3 daniel-mar 2205
        begin
23 daniel-mar 2206
          DXDraw.Surface.Canvas.Font.Color := clPurple;
47 daniel-mar 2207
          DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, 'Leben: ' + IntToStr(flife));
23 daniel-mar 2208
          DXDraw.Surface.Canvas.Font.Color := clFuchsia;
47 daniel-mar 2209
          DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ' + IntToStr(flife));
3 daniel-mar 2210
        end;
23 daniel-mar 2211
        if Flife = 1 then BlinkUpdate;
2212
      end;
37 daniel-mar 2213
      {$ENDREGION}
2214
 
2215
      {$REGION 'Anzeige Einheiten und Boss Leben'}
2216
 
2217
      tmpEnemyAnzeige := EnemyCounter{Auf Bildschirm} + FRestEnemies{In der Warteschlange};
71 daniel-mar 2218
      if FBossImLevel and (FBossLife<>0) then Dec(tmpEnemyAnzeige);
37 daniel-mar 2219
 
50 daniel-mar 2220
      if FBossLife > 0 then
23 daniel-mar 2221
      begin
37 daniel-mar 2222
        if (tmpEnemyAnzeige>0) then
3 daniel-mar 2223
        begin
23 daniel-mar 2224
          DXDraw.Surface.Canvas.Font.Color := clGreen;
2225
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-81, 'Boss: ' + IntToStr(FBossLife));
37 daniel-mar 2226
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
23 daniel-mar 2227
          DXDraw.Surface.Canvas.Font.Color := clLime;
2228
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-80, 'Boss: ' + IntToStr(FBossLife));
37 daniel-mar 2229
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
50 daniel-mar 2230
        end
2231
        else
3 daniel-mar 2232
        begin
23 daniel-mar 2233
          DXDraw.Surface.Canvas.Font.Color := clGreen;
2234
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Boss: ' + IntToStr(FBossLife));
2235
          DXDraw.Surface.Canvas.Font.Color := clLime;
2236
          DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Boss: ' + IntToStr(FBossLife));
3 daniel-mar 2237
        end;
50 daniel-mar 2238
      end
2239
      else if (FBossLife<=0) and (tmpEnemyAnzeige>0) then
23 daniel-mar 2240
      begin
2241
        DXDraw.Surface.Canvas.Font.Color := clGreen;
37 daniel-mar 2242
        DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
23 daniel-mar 2243
        DXDraw.Surface.Canvas.Font.Color := clLime;
37 daniel-mar 2244
        DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
23 daniel-mar 2245
      end;
37 daniel-mar 2246
      {$ENDREGION}
2247
 
2248
      {$REGION 'Anzeige Mission erfolgreich/gescheitert'}
50 daniel-mar 2249
      if (EnemyCounter=0) and (FRestEnemies=0) and ((FBossImLevel and (FBossLife=0)) or not FBossImLevel) then
23 daniel-mar 2250
      begin
2251
        DXDraw.Surface.Canvas.Font.Color := clGreen;
2252
        DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, 'Mission erfolgreich!');
2253
        DXDraw.Surface.Canvas.Font.Color := clLime;
2254
        DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission erfolgreich!');
2255
        DXDraw.Surface.Canvas.Release;
35 daniel-mar 2256
        Sleep(1);
23 daniel-mar 2257
        inc(FCounter);
2258
        if FCounter>150{200} then PlayerSprite.FlyAway;
2259
      end;
37 daniel-mar 2260
      {$ENDREGION}
3 daniel-mar 2261
    end
2262
    else
2263
    begin
23 daniel-mar 2264
      DXDraw.Surface.Canvas.Font.Color := clMaroon;
3 daniel-mar 2265
      DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, 'Mission gescheitert!');
23 daniel-mar 2266
      DXDraw.Surface.Canvas.Font.Color := clRed;
3 daniel-mar 2267
      DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission gescheitert!');
2268
    end;
23 daniel-mar 2269
    DXDraw.Surface.Canvas.Release;
3 daniel-mar 2270
  end;
2271
end;
2272
 
2273
procedure TMainForm.SceneGameOver;
2274
begin
2275
  DXDraw.Surface.Fill(0);
23 daniel-mar 2276
 
2277
  FNotSave := true;
2278
  Cheat.enabled := false;
2279
  GamePause.enabled := false;
2280
  Neustart.enabled := false;
2281
  Brush.Style := bsClear;
2282
  DXDraw.Surface.Canvas.Font.Size := 35;
2283
  DXDraw.Surface.Canvas.Font.Color := clMaroon;
2284
  DXDraw.Surface.Canvas.Textout((dxdraw.surfacewidth div 2)-127, 98, 'Game over!');
2285
  DXDraw.Surface.Canvas.Font.Color := clRed;
2286
  DXDraw.Surface.Canvas.Textout((dxdraw.surfacewidth div 2)-125, 100, 'Game over!');
2287
  if (FBlink div 300) mod 2=0 then
3 daniel-mar 2288
  begin
23 daniel-mar 2289
    DXDraw.Surface.Canvas.Font.Size := 30;
2290
    DXDraw.Surface.Canvas.Font.Color := clOlive;
2291
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
2292
    DXDraw.Surface.Canvas.Font.Color := clYellow;
2293
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
3 daniel-mar 2294
  end;
23 daniel-mar 2295
  BlinkUpdate;
2296
  DXDraw.Surface.Canvas.Release;
2297
 
20 daniel-mar 2298
  // Weiter mit Leertaste oder Enter
2299
  if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
3 daniel-mar 2300
  begin
31 daniel-mar 2301
    PlaySound(smsSceneMov, False);
3 daniel-mar 2302
    PalleteAnim(RGBQuad(0, 0, 0), 300);
2303
    Sleep(200);
2304
    StartScene(gsTitle);
2305
  end;
2306
end;
2307
 
2308
procedure TMainForm.SceneWin;
2309
begin
2310
  DXDraw.Surface.Fill(0);
23 daniel-mar 2311
 
2312
  FNotSave := true;
2313
  Cheat.enabled := false;
2314
  GamePause.enabled := false;
2315
  Neustart.enabled := false;
2316
 
2317
  DXDraw.Surface.Canvas.Brush.Style := bsClear;
2318
  DXDraw.Surface.Canvas.Font.Size := 35;
2319
  DXDraw.Surface.Canvas.Font.Color := clMaroon;
2320
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-127, 98, 'Gewonnen!');
2321
  DXDraw.Surface.Canvas.Font.Color := clRed;
2322
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-125, 100, 'Gewonnen!');
2323
  if (FBlink div 300) mod 2=0 then
3 daniel-mar 2324
  begin
23 daniel-mar 2325
    DXDraw.Surface.Canvas.Font.Size := 30;
2326
    DXDraw.Surface.Canvas.Font.Color := clOlive;
2327
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
2328
    DXDraw.Surface.Canvas.Font.Color := clYellow;
2329
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
3 daniel-mar 2330
  end;
23 daniel-mar 2331
  BlinkUpdate;
2332
  DXDraw.Surface.Canvas.Release;
2333
 
25 daniel-mar 2334
  // Weiter mit Leertaste oder Enter
2335
  if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
3 daniel-mar 2336
  begin
31 daniel-mar 2337
    PlaySound(smsSceneMov, False);
3 daniel-mar 2338
    PalleteAnim(RGBQuad(0, 0, 0), 300);
2339
    Sleep(200);
2340
    StartScene(gsTitle);
2341
  end;
2342
end;
2343
 
2344
procedure TMainForm.StartSceneNewLevel;
2345
begin
2346
  sleep(500);
46 daniel-mar 2347
  FNotSave := true; // Wenn man speichert, würde man LevelAdventTable vom vorherigen Level machen, das wär müll!
3 daniel-mar 2348
  Cheat.enabled := false;
2349
  Neustart.enabled := false;
2350
  GamePause.enabled := false;
2351
  GameStart.enabled := true;
2352
  Spielgeschwindigkeit.enabled := false;
2353
  Spielgeschwindigkeit.enabled := false;
61 daniel-mar 2354
  if ((FGameMode=gmLevels) and not GetLevelFileName(FLevel,false).found)
40 daniel-mar 2355
     // or ((FGameMode=gmRandom) and (FLevel > 25))
2356
     or (FLevel > MaxPossibleLevels) then
3 daniel-mar 2357
  begin
2358
    //PlaySound('SceneMov', False);
2359
    PalleteAnim(RGBQuad(0, 0, 0), 300);
2360
    Sleep(200);
2361
    StartScene(gsWin);
2362
    exit;
2363
  end;
31 daniel-mar 2364
  MusicSwitchTrack(smmScene);
3 daniel-mar 2365
end;
2366
 
2367
procedure TMainForm.EndSceneNewLevel;
2368
begin
2369
  {  Ende NewLevel  }
2370
end;
2371
 
2372
procedure TMainForm.SceneNewLevel;
2373
begin
2374
  DXDraw.Surface.Fill(0);
23 daniel-mar 2375
 
2376
  DXDraw.Surface.Canvas.Brush.Style := bsClear;
2377
  DXDraw.Surface.Canvas.Font.Size := 40;
2378
  DXDraw.Surface.Canvas.Font.Color := clMaroon;
2379
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-(83+(length(inttostr(flevel))*22)), 98, 'Level '+inttostr(flevel));
2380
  DXDraw.Surface.Canvas.Font.Color := clRed;
2381
  DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-(81+(length(inttostr(flevel))*22)), 100, 'Level '+inttostr(flevel));
2382
  if (FBlink div 300) mod 2=0 then
3 daniel-mar 2383
  begin
23 daniel-mar 2384
    DXDraw.Surface.Canvas.Font.Size := 30;
2385
    DXDraw.Surface.Canvas.Font.Color := clOlive;
2386
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-187, dxdraw.surfaceheight-117, 'Weiter mit Leertaste');
2387
    DXDraw.Surface.Canvas.Font.Color := clYellow;
2388
    DXDraw.Surface.Canvas.Textout((dxdraw.surfaceWidth div 2)-185, dxdraw.surfaceheight-115, 'Weiter mit Leertaste');
3 daniel-mar 2389
  end;
23 daniel-mar 2390
  BlinkUpdate;
2391
  DXDraw.Surface.Canvas.Release;
2392
 
25 daniel-mar 2393
  // Weiter mit Leertaste oder Enter
2394
  if (isButton1 in DXInput.States) or (isButton2 in DXInput.States) then
3 daniel-mar 2395
  begin
31 daniel-mar 2396
    PlaySound(smsSceneMov, False);
3 daniel-mar 2397
    PalleteAnim(RGBQuad(0, 0, 0), 300);
2398
    Sleep(200);
2399
    StartScene(gsMain);
2400
  end;
2401
end;
2402
 
2403
procedure TMainForm.OptionMusicClick(Sender: TObject);
2404
begin
2405
  OptionMusic.Checked := not OptionMusic.Checked;
2406
  if OptionMusic.Checked then
2407
  begin
19 daniel-mar 2408
    MusicSwitchTrack(FMusic)
3 daniel-mar 2409
  end
2410
  else
2411
  begin
19 daniel-mar 2412
    StopMusic(FMusic);
3 daniel-mar 2413
  end;
2414
  WriteOptions;
2415
end;
2416
 
2417
procedure TMainForm.MasterClick(Sender: TObject);
2418
begin
2419
  master.checked := true;
2420
  FInterval := giMaster;
2421
  writeoptions;
2422
end;
2423
 
31 daniel-mar 2424
procedure TMainForm.PlayMusic(Name: TSpaceMissionMusicTrack);
3 daniel-mar 2425
begin
19 daniel-mar 2426
  if not OptionMusic.checked then exit;
24 daniel-mar 2427
  if Ord(Name) > dxmusic.Midis.Count then exit;
19 daniel-mar 2428
  dxmusic.Midis.Items[Ord(Name)-1].Play;
2429
end;
3 daniel-mar 2430
 
31 daniel-mar 2431
procedure TMainForm.StopMusic(Name: TSpaceMissionMusicTrack);
19 daniel-mar 2432
begin
31 daniel-mar 2433
  if Name = smmNone then exit;
24 daniel-mar 2434
  if Ord(Name) > dxmusic.Midis.Count then exit;
19 daniel-mar 2435
  dxmusic.Midis.Items[Ord(Name)-1].Stop;
2436
end;
2437
 
31 daniel-mar 2438
procedure TMainForm.ResumeMusic(Name: TSpaceMissionMusicTrack);
3 daniel-mar 2439
begin
2440
  if not OptionMusic.checked then exit;
24 daniel-mar 2441
  if Ord(Name) > dxmusic.Midis.Count then exit;
19 daniel-mar 2442
  dxmusic.Midis.Items[Ord(Name)-1].Play; // TODO: how to pause/resume instead play/stop
3 daniel-mar 2443
end;
2444
 
31 daniel-mar 2445
procedure TMainForm.PauseMusic(Name: TSpaceMissionMusicTrack);
19 daniel-mar 2446
begin
31 daniel-mar 2447
  if Name = smmNone then exit;
24 daniel-mar 2448
  if Ord(Name) > dxmusic.Midis.Count then exit;
19 daniel-mar 2449
  dxmusic.Midis.Items[Ord(Name)-1].Stop; // TODO: how to pause/resume instead play/stop
2450
end;
2451
 
3 daniel-mar 2452
procedure TMainForm.SpielstandClick(Sender: TObject);
2453
begin
2454
  speicherungform.showmodal;
2455
end;
2456
 
38 daniel-mar 2457
procedure TMainForm.LevelNeuStarten;
3 daniel-mar 2458
begin
38 daniel-mar 2459
  FNextScene := gsNewLevel;
40 daniel-mar 2460
  FLife := FLifeAtLevelStart;
2461
  FScore := FScoreAtLevelStart;
3 daniel-mar 2462
end;
2463
 
38 daniel-mar 2464
procedure TMainForm.NeustartClick(Sender: TObject);
2465
begin
2466
  LevelNeuStarten;
2467
end;
2468
 
3 daniel-mar 2469
procedure TMainForm.LeichtClick(Sender: TObject);
2470
begin
2471
  leicht.checked := true;
2472
  FInterval := giLeicht;
2473
  writeoptions;
2474
end;
2475
 
2476
procedure TMainForm.MittelClick(Sender: TObject);
2477
begin
2478
  mittel.checked := true;
2479
  FInterval := giMittel;
2480
  writeoptions;
2481
end;
2482
 
2483
procedure TMainForm.SchwerClick(Sender: TObject);
2484
begin
2485
  schwer.checked := true;
2486
  FInterval := giSchwer;
2487
  writeoptions;
2488
end;
2489
 
2490
procedure TMainForm.FormShow(Sender: TObject);
54 daniel-mar 2491
resourcestring
2492
  SFileError = 'Die Datei kann von SpaceMission nicht geöffnet werden!';
2493
var
2494
  SavGame: TSaveData;
3 daniel-mar 2495
begin
7 daniel-mar 2496
  if Assigned(SplashForm) then
2497
  begin
2498
    SplashForm.Hide;
2499
    FreeAndNil(SplashForm);
2500
  end;
3 daniel-mar 2501
 
2502
  dxtimer.Enabled := true;
2503
  dxtimer.ActiveOnly := true;
54 daniel-mar 2504
 
2505
  ResetLevelData;
2506
  if (paramcount > 0) and (fileexists(paramstr(1))) and (ExtractFileExt(paramstr(1)).ToLower = '.sav') then
2507
  begin
2508
    SavGame := TSaveData.Create;
2509
    try
2510
      try
2511
        SavGame.LoadFromFile(paramstr(1));
2512
        FScore := SavGame.Score;
2513
        FLife := SavGame.Life;
2514
        FLevel := SavGame.Level;
2515
        FGameMode := SavGame.GameMode;
2516
        FLevelDataAlreadyLoaded := true; // do not call NewLevel() in StartSceneMain
2517
        if Assigned(SavGame.LevelData) then
2518
        begin
2519
          LevelData.Assign(SavGame.LevelData);
2520
        end;
2521
      except
2522
        on E: Exception do
2523
        begin
2524
          showmessage(SFileError + ' ' +E.Message);
2525
          GameStartClick(GameStart);
2526
          exit;
2527
        end;
2528
      end;
2529
    finally
2530
      FreeAndNil(SavGame);
2531
    end;
2532
    //FNextScene := gsNewLevel;
2533
    StartScene(gsNewLevel);
2534
    exit;
2535
  end;
3 daniel-mar 2536
end;
2537
 
2538
procedure TMainForm.InformationenClick(Sender: TObject);
2539
begin
2540
  dxtimer.enabled := false;
2541
  InfoForm.showmodal;
2542
  if not mainform.gamepause.checked then mainform.dxtimer.enabled := true;
2543
end;
2544
 
2545
procedure TMainForm.CheatClick(Sender: TObject);
2546
begin
2547
  CheatForm.showmodal;
2548
end;
2549
 
2550
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
2551
begin
19 daniel-mar 2552
  if optionMusic.checked then StopMusic(FMusic);
3 daniel-mar 2553
  SpriteEngine.Engine.Clear;
2554
  dxsound.Finalize;
2555
  dxinput.Destroy;
2556
  DXTimer.Enabled := False;
2557
end;
2558
 
2559
procedure TMainForm.FormDestroy(Sender: TObject);
2560
begin
23 daniel-mar 2561
  FreeAndNil(imagelist);
2562
  FreeAndNil(spriteengine);
2563
  FreeAndNil(dxdraw);
2564
  FreeAndNil(wavelist);
56 daniel-mar 2565
  FreeAndNil(dxmusic);
23 daniel-mar 2566
  FreeAndNil(dxsound);
2567
  //FreeAndNil(dxinput);
2568
  FreeAndNil(dxtimer);
7 daniel-mar 2569
  DeleteCriticalSection(TimerCS);
23 daniel-mar 2570
  FreeAndNil(LevelData);
3 daniel-mar 2571
end;
2572
 
36 daniel-mar 2573
procedure PostKeyEx32(key: Word; const shift: TShiftState; specialkey: Boolean);
2574
{************************************************************
2575
* Procedure PostKeyEx32
2576
*
2577
* Parameters:
2578
*  key    : virtual keycode of the key to send. For printable
2579
*           keys this is simply the ANSI code (Ord(character)).
2580
*  shift  : state of the modifier keys. This is a set, so you
2581
*           can set several of these keys (shift, control, alt,
2582
*           mouse buttons) in tandem. The TShiftState type is
2583
*           declared in the Classes Unit.
2584
*  specialkey: normally this should be False. Set it to True to
2585
*           specify a key on the numeric keypad, for example.
2586
* Description:
2587
*  Uses keybd_event to manufacture a series of key events matching
2588
*  the passed parameters. The events go to the control with focus.
2589
*  Note that for characters key is always the upper-case version of
2590
*  the character. Sending without any modifier keys will result in
2591
*  a lower-case character, sending it with [ssShift] will result
2592
*  in an upper-case character!
2593
// Code by P. Below
2594
************************************************************}
2595
type
2596
  TShiftKeyInfo = record
2597
    shift: Byte;
2598
    vkey: Byte;
2599
  end;
2600
  byteset = set of 0..7;
2601
const
2602
  shiftkeys: array [1..3] of TShiftKeyInfo =
2603
    ((shift: Ord(ssCtrl); vkey: VK_CONTROL),
2604
    (shift: Ord(ssShift); vkey: VK_SHIFT),
2605
    (shift: Ord(ssAlt); vkey: VK_MENU));
2606
var
2607
  flag: DWORD;
2608
  bShift: ByteSet absolute shift;
2609
  i: Integer;
2610
begin
2611
  for i := 1 to 3 do
2612
  begin
2613
    if shiftkeys[i].shift in bShift then
2614
      keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
2615
  end; { For }
2616
  if specialkey then
2617
    flag := KEYEVENTF_EXTENDEDKEY
2618
  else
2619
    flag := 0;
2620
 
2621
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
2622
  flag := flag or KEYEVENTF_KEYUP;
2623
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
2624
 
2625
  for i := 3 downto 1 do
2626
  begin
2627
    if shiftkeys[i].shift in bShift then
2628
      keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0),
2629
        KEYEVENTF_KEYUP, 0);
2630
  end; { For }
2631
end; { PostKeyEx32 }
2632
 
2633
procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
2634
  Shift: TShiftState);
2635
begin
2636
  if Key = VK_ESCAPE then
2637
  begin
2638
    // TODO: Unfortunately, you cannot see if it is already popup. It would be great if ESC closes the main menu...
2639
    Key := 0;
2640
    PostKeyEx32(Ord('S'), [ssAlt], False);
2641
  end;
2642
end;
2643
 
3 daniel-mar 2644
end.
2645