Subversion Repositories spacemission

Rev

Rev 50 | Rev 54 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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