unit star1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  dddd, ddddut, Menus, ddraw;

type
  TForm1 = class(TForm)
    DDDD1: TDDDD;
    MainMenu1: TMainMenu;
    K1: TMenuItem;
    K2: TMenuItem;
    K3: TMenuItem;
    K4: TMenuItem;
    K5: TMenuItem;
    K6: TMenuItem;
    K7: TMenuItem;
    N2: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure DDDD1Init(Sender: TObject; fNeedChange: Boolean);
    procedure K2Click(Sender: TObject);
    procedure K3Click(Sender: TObject);
    procedure K4Click(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure K6Click(Sender: TObject);
    procedure K7Click(Sender: TObject);
    procedure DDDD1ChangeDisplayMode(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
    procedure AppIdle(Sender: TObject; var Done: Boolean);
    procedure InitPos(m:Integer);
    procedure MoveStar(m:Integer);
  public
    { Public 宣言 }
    FFull:Boolean;  //フルスクリーンモードか否か
    Timer:Integer;
    Spr:TDDDDSprite;
    Surf:TDDDDSurface;
    PATH:String;
    METHOD:Integer; //0...下降  1...彗星  2...竜巻  3...放物線  4..桜吹雪
    Depth:Integer;  //画面の色数
  end;

var
  Form1: TForm1;

implementation

type
TComet = record
  Cur:Integer;   //現在の角度
  Grad:Integer;  //傾き
  Long:Integer;  //長辺の長さ
  Small:Integer; //短辺は長さ
  Speed:Integer; //角速度
end;

TCyclone = record
  Cur:Integer;    //現在の角度
  Center:Integer; //中心のX座標
  R  :Integer;    //半径
  T  :Integer;    //出現からの時間
  Speed:Integer;  //角速度
end;

const
  MAX_STAR = 511;

var
  Dy:Array[0..MAX_STAR] of Integer;
  Com:Array[0..MAX_STAR div 8] of TComet;
  Cyc:Array[0..MAX_STAR] of TCyclone;
  SinT:Array[0..1023] of Integer;
  CosT:Array[0..1023] of Integer;

  FAtFirst:Boolean = True;

procedure TForm1.InitPos(m:Integer);
  procedure makeTable;  //サインテーブル作成
  var
    i:Integer;
  begin
    for i:=0 to 1023 do begin
      SinT[i] := Round( Sin(i / 512.0 * Pi) * 1024.0);
      CosT[i] := Round( Cos(i / 512.0 * Pi) * 1024.0);
    end;
  end;
  procedure Kakou;   //下降
  var
    i:Integer;
  begin
    for i:=0 to MAX_STAR do begin
      Spr[i].IShape:=4 + Random(3)*3;
      Spr[i].Y:=random(480);
      Spr[i].X:=random(640);
      Dy[i]:=random(8)+1;
    end;
  end;
  procedure Comet;    //彗星
  var
    i,j,s:Integer;
  begin
    makeTable;
    for i:=0 to MAX_STAR Shr 3 do begin
      s:=4 + Random(3)*3;
      for j:=0 to 7 do begin
        Spr[(i Shl 3) or j].IShape:=s;
      end;
    end;
    for i:=0 to MAX_STAR div 8 do begin
      with Com[i] do begin
        Cur:=random(1024);
        Grad:=random(1024);
        Long:=Random(240);
        Small:=Random(240);
        Speed:=Random(10)+10;
      end;
    end;
  end;
  procedure Cyclone;  //竜巻
  var
    i,x:Integer;
  begin
    makeTable;
    for i:=0 to MAX_STAR do begin
      X:=Random(50);
      with Cyc[i] do begin
        Cur:=Random(1024);
        R:=Random(60)+60;
        T:=X;
        Center:=320;
        Speed:=Random(32)+2;
      end;
      Dy[i]:=Random(8)+1;
      Spr[i].IShape:=4 + Random(3)*3;
      Spr[i].X:=Cyc[i].Center;
      Spr[i].Y:=480-X*Dy[i];
    end;
  end;
begin
  case m of
    0: kakou;
    1: Comet;
    2: Cyclone;
  end;
end;

var
  Frame:Integer;

procedure TForm1.MoveStar(m:Integer);
  procedure Kakou; //下降
  var
    i:Integer;
  begin
    Inc(Frame);
    for i:=0 to MAX_STAR do begin
      if (Frame And 3) = 0 then
        Spr[i].NextFrame;
      Inc(Spr[i].Y,Dy[i]);
      if Spr[i].Y > 480 then begin
        Spr[i].X:=random(640);
        Spr[i].Y:=0;
        Dy[i]:=random(8)+1;
      end;
    end;
  end;
  procedure Comet; //彗星
  var
    i,Xt,Yt:Integer;
  begin
    Inc(Frame);
    for i:=MAX_STAR downto 0 do begin
      if (Frame And 3) = 0 then
        Spr[i].NextFrame;
      if i And 7 <> 0 then begin
        Spr[i].Pos:=Spr[i-1].Pos;
      end else begin
        with Spr[i],Com[i Shr 3] do begin
          Xt := SinT[Cur] * Long div 1024;
          Yt := CosT[Cur] * Small div 1024;
          X := (CosT[Grad] * Xt - SinT[Grad] * Yt) div 1024;
          Y := (SinT[Grad] * Xt + CosT[Grad] * Yt) div 1024;
          Inc(X,320);
          Inc(Y,240);
          Inc(Cur,Speed);
          Cur:=Cur And 1023;
        end;
      end;
    end;
  end;
  procedure cyclone;
  var
    i:Integer;
  begin
    Inc(Frame);
    for i:=0 to MAX_STAR do begin
      if (Frame And 3) = 0 then
        Spr[i].NextFrame;
      with Spr[i],Cyc[i] do begin
        X := Center + SinT[Cur] * R div 1024;
        Y := 480 + (CosT[Cur] * R div 2048) - (T * Dy[i]);
        Inc(Cur,15);
        Cur := Cur And 1023;
        Inc(T);
        if Y < 0 then begin
          Inc(Center,Random(5)-2);
          if (Center < 60) then
            Center:=60;
          if (Center > 420) then
            Center:=420;
          Y:=480;
          Dy[i]:=random(8)+1;
          R:=Random(120)+60;
          T:=0;
          Cur:=Random(1024);
          Speed:=Random(32)+2;
        end;
      end;
    end;
  end;
begin
  case m of
    0: kakou;
    1: comet;
    2: cyclone;
  end;
end;

(*******************************************************************************
  メインループ
*******************************************************************************)
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
begin

  DDDD1.Clear;

  //☆の移動
  MoveStar(METHOD);

  //うぇるだーん
  Spr.Update;
  DDDD1.Flip;
  Inc(Timer);

  Done:=False;
end;

(*******************************************************************************
　イベントハンドラ
*******************************************************************************)

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer:=0;
  FFull:=False;
  PATH:=ExtractFilePath(Application.ExeName);
end;

procedure TForm1.DDDD1Init(Sender: TObject; fNeedChange: Boolean);
var
  i:Integer;
begin

  //初期化
  METHOD:=0;

  Surf:=TDDDDSurface.Create(DDDD1,144,80,0);
  Surf.LoadBMP(PATH+'star.bmp');
  Surf.ColorKey:=Surf.Pixels[0,0]; //左上隅の色をカラーキーに

  //スプライトの初期化
  Spr:=TDDDDSprite.Create(MAX_STAR+1,64);

  //☆
  For i:=0 to 8 do
    Spr.SetShape(i+4, Surf, Rect( (i shl 4),64,((i+1) shl 4),80));
  For i:=0 to MAX_STAR do begin
    Spr[i].minAnim:=0;
    Spr[i].maxAnim:=2;
    Spr[i].IAnim:=Random(3);
    Spr[i].Show;
    Spr[i].RewindAnim:=True;
    InitPos(METHOD);
  end;

  //パレットの設定
  DDDD1.ReadPalette(PATH+'star.bmp');
  DDDD1.UpdatePalette;

  //背景色を黒に
  DDDD1.BackColor:=Surf.ColorMatch(clBlack);

  //メインループの取り付け
  Application.OnIdle:=AppIdle;
end;


//ウィンドウモードで必要な、Adjust
procedure TForm1.K2Click(Sender: TObject);
begin
  METHOD:=0;
  InitPos(0);
end;

procedure TForm1.K3Click(Sender: TObject);
begin
  METHOD:=1;
  InitPos(1);
end;

procedure TForm1.K4Click(Sender: TObject);
begin
  METHOD:=2;
  InitPos(2);
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  //ESCが押されたら終了
  if Key=#$1b then begin
    Application.Terminate;
  end;
end;

procedure TForm1.K6Click(Sender: TObject);
begin
  DDDD1.BackBuffer.SaveBMP(ExtractFilePath(Application.ExeName)+'snap.bmp');
end;

procedure TForm1.DDDD1ChangeDisplayMode(Sender: TObject);
begin
  ClientWidth:=640;
  ClientHeight:=480;

  //色数が変わった場合、カラーキーも変更しなければならない
  Surf.ColorKey:=Surf.Pixels[0,0];

  //背景色を黒に
  DDDD1.BackColor:=Surf.ColorMatch(clBlack);
end;

//ウィンドウモード・全画面モードの切り替え
procedure TForm1.K7Click(Sender: TObject);
begin
  FFull:= Not FFull;

  //全画面モードなら、8ビットカラーに
  if FFull then begin
    DDDD1.FullScreenMode(640,480,8,0,'');
  end else
    DDDD1.WindowMode(640,480);

end;

//右クリックでもウィンドウモード・全画面モードの切り替え
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
    K7Click(K7);
end;

end.
