unit yatc_field;

interface

uses  GLObjects,Classes,
      yatc_global,GLTexture,GLThorFX,GLCadencer, GLScene;

type
  //Zur Unterscheidung der eingrenzenden Balken (nur intern verwendet)
  RBarType = (bleft,bmiddle,bright);
  //Speicher für einen Blitz
  TLineFX = class
            public
              cube : TGLDummyCube;
              manager : TGLThorFXManager;
            end;
  //Stellt ein Feld von einzelnen Blöcken und eine
  //Umrandung zur verfügung
  //Sowie Funktionen zum Umgang mit dem Feld
  TBlockField = class (TGLDummyCube)
                private
                  //Größe des Feldes
                  fsizeX,fsizeY : integer;
                  //Rand außen (3 stück)
                  mainBorder : array[RBarType] of TGLCube;
                  //Rand innnen (3 stück)
                  shadedBorder : array[RBarType] of TGLCube;
                public
                   //Dummy der Rand aufnimmt
                  dummyContainer : TGLDummyCube;
                  //Hintergrund
                  background : TGLPlane;
                  //Inhalt der Umrandung
                  Content : TGLDummyCube;
                  //Feld für den Inhalt
                  cubeArray : RCubeArray;

                  //Die Kamera
                  camera : TGLCamera;
                  //Das Licht
                  light : TGLLightSource;

                  //Feldgröße
                  property sizeX : integer read fsizeX;
                  property sizeY : integer read fsizeY;

                  //Ändert die Größe des Feldes von 0 bis _sizeX und 0 bis _sizeY
                  procedure setSize(_sizeX,_sizeY : integer);

                  //Gibt ein Zeiger auf die Material eingenschaften zurück
                  //Rand außen
                  function getMainMaterial : TGLMaterial;
                  //Rand hin zum Feld
                  function getShadedMaterial : TGLMaterial;
                  //Hintergrund des Felds
                  function getBackgroundMaterial : TGLMaterial;

                  //Setzt das Material wieder
                  procedure setMainMaterial(m : TGLMaterial);
                  procedure setShadedMaterial(m : TGLMaterial);
                  procedure setBackgroundMaterial(m : TGLMaterial);

                  //Löscht das feld
                  procedure clear;
                  //Löscht eine Zeile
                  procedure clearline(line : integer);
                  //schiebt Feld zusammen
                  procedure colapsefield;
                  //überprüft ob die Zeile voll ist
                  function checklinefull(line : integer) : boolean;
                  //prüft ob die zeile frei ist
                  function checklinefree(line : integer) : boolean;

                  //erzeugt einen Blitz effekt auf der jeweiligen Spalte, und gibt ihn zurück
                  function createlineFX(line : integer;cadencer : TGLCadencer) : TLineFx;
                  //entfernt den Blitz effekt wieder
                  procedure destroylineFX(fx : TLineFX);

                  constructor create(AOwner : TComponent); override;
                  destructor destroy; override;
               end;

implementation

uses yatc_Block;

constructor TBlockField.create(AOwner : TComponent);

var j : RBarType;
begin
  inherited create(Aowner);
  Content := TGLDummyCube(addNewChild(TGLDummyCube));
  dummyContainer := TGLDummyCube(addNewChild(TGLDummyCube));

  //Kamera und licht erzeugen mit Standard werten
  camera := TGLCamera(addNewChild(TGLCamera));
  camera.DepthOfView := camera_depth;
  light := TGLLightSource(camera.addNewChild(TGLLightSource));
  camera.TargetObject := self;
  camera.position.z := 10;
  camera.Position.x := 0;
  camera.Position.Y := 0;
  light.Diffuse.Initialize(clrGray15);
  light.Position.X := -50;
  light.Position.Y := 10;
  light.Position.Z := 0;

  background := TGLPlane(dummyContainer.AddNewChild(TGLPlane));

  for j := bleft to bright do
  begin
    mainBorder[j] := TGLCube(dummyContainer.AddNewChild(TGLCube));
    shadedBorder[j] := TGLCube(dummyContainer.AddNewChild(TGLCube));
  end;
  mainBorder[bleft].Parts := [cpTop,cpBottom,cpFront,cpLeft];
  mainBorder[bmiddle].Parts := [cpBottom,cpFront];
  mainBorder[bright].Parts := [cpTop,cpBottom,cpFront,cpRight];
  shadedBorder[bleft].Parts := [cpRight];
  shadedBorder[bmiddle].Parts := [cpTop];
  shadedBorder[bright].Parts := [cpLeft];

  setSize(5,5);
end;

procedure TBlockField.setSize(_sizeX,_sizeY : integer);

var i,j : integer;

begin
  fsizeX := _sizeX;
  fsizeY := _sizeY;

  dummyContainer.position.X := -((fsizeX+3) / 2);  //Dummycube einstellen
  dummyContainer.Position.Y := ((fsizeY+2) / 2);

  Content.Position.x := -(((fsizex+3)/2)-1);      //Block Dummy Cube
  Content.Position.y := -(((fsizey+2)/2)-1);

  background.Width := fsizeX+2;        //hintergrund
  background.Height := fsizeY+2;
  background.Position.X := (fsizeX+3) / 2;
  background.Position.y := - ( (fsizeY+3) / 2 );
  background.Position.Z := -0.5;

  mainBorder[bleft].Position.y := -((fsizeY+2) / 2);       //linker balken
  mainBorder[bleft].Scale.Y := fsizeY+1;
  shadedBorder[bleft].Position.y := -((fsizeY+2) / 2);  //linker dunkler rand
  shadedBorder[bleft].Scale.Y := fsizeY+1;

  mainBorder[bmiddle].Position.X := (fsizeX+2)/2;         //untere Balken
  mainBorder[bmiddle].Position.y := -(fsizeY+2);
  mainBorder[bmiddle].scale.x := fsizeX+3;
  shadedBorder[bmiddle].Position.X := (fsizeX+2)/2;         //untere dunkler rand
  shadedBorder[bmiddle].Position.y := -(fsizeY+2);
  shadedBorder[bmiddle].scale.x := fsizeX+3;

  mainBorder[bright].Position.X := fsizeX+2;                //rechter Balken
  mainBorder[bright].Position.Y := -((fsizeY+2)/2);
  mainBorder[bright].Scale.Y := fsizeY+1;
  shadedBorder[bright].Position.X := fsizeX+2;                //rechter dunkler Balken
  shadedBorder[bright].Position.Y := -((fsizeY+2)/2);
  shadedBorder[bright].Scale.Y := fsizeY+1;

  //Feld initialisieren
  setlength(cubearray,fsizeX+1);
  for i := 0 to fsizeX do
  begin
    setlength(cubearray[i],fsizeY+1+3);  //+3 = sicherheit nach oben zum objekte erstellen
    for j := 0 to fsizeY do
    begin
      cubearray[i,j] := nil;
    end;
  end;
end;

procedure TBlockField.clear;

var i,j : integer;

begin
  for i := 0 to fsizeX do   //Feld löschen wir nehmen zur sicherheit die tatsächliche als die erwartete größe
  begin
    for j := 0 to fsizeY do
    begin
      if cubearray[i,j] <> nil then
        cubearray[i,j].Free;
      cubearray[i,j] := nil;
    end;
  end;
  content.DeleteChildren;  //eventuelle überbleisel Löschen
end;

procedure TBlockField.clearline(line : integer);

var i : integer;

begin
  for i := 0 to fsizeX do   //Zeile löschen
  begin
     if cubearray[i,line] <> nil then   //Blocks Löschen
        cubearray[i,line].Free;
      cubearray[i,line] := nil;
  end;
end;

function TBlockfield.createlineFX(line : integer;cadencer : TGLCadencer) : TLineFx;

var help : TGlBThorFX;

begin
  result := TLineFx.Create;
  result.cube := TGLDummyCube(dummyContainer.addNewChild(TGLDummyCube));
  result.manager := TGLThorFxManager.Create(self);
  result.manager.Cadencer := cadencer;

  result.cube.Position.X := fsizeX+2;
  result.cube.Position.y := line-fsizeY-1;
  result.cube.Position.Z := 0.5;

  result.manager.Target.X := -(fsizeX+2);
  result.manager.Target.y := 0;
  result.manager.glowsize := 0.5;
  result.manager.glow := true;
  result.manager.Wildness := 1;

  help := TGLBThorFx.create(result.cube.Effects);
  result.cube.effects.add(help);
  help.Manager := result.manager;
  result.manager.disabled := false;
end;

procedure TBlockField.destroylineFX(fx : TLineFX);

begin
  if fx <> nil then
  begin
    fx.manager.free;
    fx.cube.Free;
    fx.Free;
  end;
end;

procedure TBlockfield.colapsefield;

var nomove : boolean;
    i,j : integer;

begin
  repeat                //Schleife um überliegende Blöcke fallen zu lassen
  nomove := true;      //solange bis kein fallen mehr nötig ist
  for i := 0 to fsizeX do
  begin
    for j := 0 to fsizeY do
    begin
      if cubearray[i,j] <> nil then                  //andere blöcke fallen lassen
        if TTcube(cubearray[i,j]).isfree(ddown) then
        begin
          TTcube(cubearray[i,j]).domove(ddown);
          nomove := false;
        end;
    end;
  end;
  until nomove = true;
end;

function TBLockField.checklinefull(line : integer) : boolean;

var i : integer;

begin
  result := true;
  for i := 0 to fsizeX do  //jede spalte
  begin
    if cubearray[i,line] = nil then
    begin
      result := false; //wenn einer frei ist auf false setzen
      break;
    end;
  end;
end;

function TBLockField.checklinefree(line : integer) : boolean;

var i : integer;

begin
  result := true;
  for i := 0 to fsizeX do  //jede spalte
  begin
    if cubearray[i,line] <> nil then
    begin
      result := false; //wenn einer frei ist auf false setzen
      break;
    end;
  end;
end;

function TBlockField.getMainMaterial : TGLMaterial;

begin
  result := mainBorder[bleft].Material;        //da alle 3 gleich sein sollten einen übergeben
end;

function TBlockField.getShadedMaterial : TGLMaterial;

begin
  result := shadedBorder[bleft].Material;
end;

function TBlockField.getBackgroundMaterial : TGLMaterial;

begin
  result := background.Material;
end;

procedure TBlockField.setMainMaterial(m : TGLMaterial);

var j : RBarType;

begin
  for j := bleft to bright do
  begin   //auf alle 3 Blöcke anwenden
    mainBorder[j].Material.Assign(m);
  end;
end;

procedure TBlockField.setShadedMaterial(m : TGLMaterial);

var j : RBarType;

begin
  for j := bleft to bright do
  begin
    shadedBorder[j].Material.Assign(m);
  end;
end;

procedure TBlockField.setBackgroundMaterial(m : TGLMaterial);

begin
  background.Material.Assign(m);
end;


destructor TBlockField.destroy;

begin
  clear;
  dummyContainer.DeleteChildren;
  Content.DeleteChildren;
  dummyContainer.Free;
  Content.Free;
  inherited destroy;
end;

end.
 