Subversion Repositories spacemission

Rev

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