Subversion Repositories spacemission

Rev

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

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