Subversion Repositories spacemission

Rev

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