Subversion Repositories spacemission

Rev

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