Subversion Repositories spacemission

Rev

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