Subversion Repositories spacemission

Rev

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