unit SCENE_About;

interface

Uses
  GraphUtils,
  ObjectsUnit,
  SceneUnit,
  CyborgSoundHeaderLite;

TYPE
  TGameSceneAbout = Class(TGameScene)
    protected
    private
      SaveFPS : Single;

      //Модели сцены:
      MeshGround, MeshCursor : TMesh;
      MeshBase, MeshTover : TMesh;
      MeshMonsters : array[1..1] of TMesh;
      MeshBullets : array[1..1] of TMesh;
      //Шрифты:
      Font   : TFont;
      //Тексты:
      FPSStr : TText;
      InfoStr : TText;

      //Объекты сцены:
      Ground1       : TGameObject;
      Cursor        : TGameObject; //Курсор на земле
      Tovers        : TGameObjects; //Здания базы, база и башни
      Objects       : TGameObjects; //Игровые объекты
      Bullets       : TGameObjects; //Пульки


      Sounds : array[0..1] of Pointer;

    public
      Maney          : Longint;
      DiedMonster   : Longint;
      Constructor Create(GameObj : TObject; GameScene : TGameScene); Override;
      Procedure Free; Override;
      Function Process : TGameScene; Override;
      Procedure Draw; Override;
  end;

  TPupsGameObject = class(TGameObject)
    protected
    private

    public
      Procedure Process; Override;
  end;

  TToverGameObject = class(TGameObject)
    protected
      FireTimer : Longint;
    private

    public
      Property SetFireTimer : Longint Write FireTimer;
      Procedure Process; Override;
  end;

  TBulletGameObject = class(TGameObject)
    protected
      PathLength : Single;
    private

    public
      Property SetPathLength : Single Write PathLength;
      Procedure Process; Override;
  end;


implementation

Uses
  SysUtils,
  Windows,
  Direct3D9,
  MathUnit,
  DirectInputUnit;

//============================================================================//
//============================================================================//
//============================================================================//

//Объект монстра, как бы ИИ :)
{ TPupsGameObject }

procedure TPupsGameObject.Process;
Var
  P : PMyObject;
  Ang : Single;
begin
  inherited;
  if not Enabled then Exit;

  //Идём на объекты базы
  P:=(Game.GetCurrentScene as TGameSceneAbout).Tovers.GetStart;
  if P<>nil then
  begin
  //Ну и жопа с этими углами! :)
  Ang := (Game.GetCurrentScene as TGameSceneAbout).Objects.GetAngle(Pos.x,Pos.z,P^.GameObject.Pos.x,P^.GameObject.Pos.z);
  Ang:=RadianToAngle(Ang+(VANG.y)); //В скобках угол из радиан переводится
  if Ang> 180 then Ang:=-(Ang-(180));
  if Ang>15 then Ang:=15;
  if Ang<-15 then Ang:=-15;
  if (Ang<-0.2) or (Ang>0.2) then //Крутим башню:
  RollY(Ang); //Вроде работает :)
  end;


  if VSpeed.x>0 then VSpeed.x:=0; //Если пятится, то остановить
{
  //Столкновение со своими сородичами:
  P:=(Game.GetCurrentScene as TGameSceneAbout).Objects.GetCollision(Self);
  if (P<>nil) then //Есть столкновение с чем-то
  begin
    if (P^.GameObject<>Self) then
    begin
      if Random(4)<>1 then
      Speed(0) else
      Speed(-0.01); //пятимся медленно назад
    end;
  end else}
  begin
    Speed(0.05);
  end;

  //Коллизии с базой и пушками:
  P:=(Game.GetCurrentScene as TGameSceneAbout).Tovers.GetCollision(Self);
  if (P<>nil) then //Есть столкновение с чем-то
  begin
    if (P^.GameObject<>Self) then
    begin
      Life:=0; //Убиваем себя
      With P^.GameObject do
      begin
        SetLife:=GetLife-25;
      end;
    end;
  end;

  if Life<=0 then
  begin
    Inc((Game.GetCurrentScene as TGameSceneAbout).Maney,3);
    Inc((Game.GetCurrentScene as TGameSceneAbout).DiedMonster);
  end;

end;

//============================================================================//
//============================================================================//
//============================================================================//

{ TToverGameObject }

procedure TToverGameObject.Process;
Var
  P,PSave : PMyObject;
  L,LSave : Single;
  Ang : Single;
  Obj : TGameObject;
  tPos : TD3DVector;
begin
  inherited;
  if not Enabled then Exit;

  P:=nil;
  PSave:=nil;
  L:=0;
  LSave:=100;
  RollY(0);
  Dec(FireTimer);
  //Коллизии с монстрами (узнаём монстра в пределе досягаемости пушки 20 единиц):
  Repeat
    P:=(Game.GetCurrentScene as TGameSceneAbout).Objects.GetCollision(P,Pos,20);
    if P<>nil then
    if PSave=nil then PSave:=P else
    begin
      L:=(Game.GetCurrentScene as TGameSceneAbout).Objects.GetLength(Pos,P^.GameObject.Pos);
      if L<LSave then
      begin
        LSave:=L;
        PSave:=P;
      end;
    end;

  until p=nil;

  P:=PSave;
  if LSave>20 then LSave:=20;

  if (P<>nil) then //Если попался под руку первый монстр, то колбасим его:
  begin
    if (P^.GameObject<>Self) then
    begin
      //Сначала крутим башню к монстру, узнамём угол:
      Ang := (Game.GetCurrentScene as TGameSceneAbout).Tovers.GetAngle(Pos.x,Pos.z,P^.GameObject.Pos.x,P^.GameObject.Pos.z);
      Ang:=RadianToAngle(Ang+(VANG.y)); //В скобках угол из радиан переводится
      if Ang> 180 then Ang:=-(Ang-(180));
      if Ang>5 then Ang:=5;
      if Ang<-5 then Ang:=-5;
      RollY(Ang); //Крутим башню
      if (Ang>-3) and (Ang<3) then
      if FireTimer<=0 then
      begin //Колбасим бомбочкой в место монстра:
        FireTimer:=20;

        Obj:=TBulletGameObject.Create(Game,(Game.GetCurrentScene as TGameSceneAbout).MeshBullets[1],Pos);
        tPos:=Obj.Pos;
        tPos.y:=-Obj.CollisionBox.Down;
        Obj.Pos:=tPos;
        Obj.Scale(0.25,0.25,0.25);
        Obj.Speed(0.5);
        Obj.SetVANG:=VANG;
        (Obj as TBulletGameObject).SetPathLength:=LSave;
        (Game.GetCurrentScene as TGameSceneAbout).Bullets.Add(Obj);
        Obj.Process;
        cbrg_PlaySound((Game.GetCurrentScene as TGameSceneAbout).Sounds[Random(High((Game.GetCurrentScene as TGameSceneAbout).Sounds)+1)],False);

      end;
    end;
  end;

end;

//============================================================================//
//============================================================================//
//============================================================================//

{ TBulletGameObject }

procedure TBulletGameObject.Process;
Var
  P : PMyObject;
begin
  inherited;
  if not Enabled then Exit;

  PathLength:=PathLength+VSpeed.z;
  if PathLength<=0 then //Закончила пулька лететь:
  begin
    Life:=0;
    P:=nil;

    //Повреждаем жизни у всех близконаходящихся монстров:
    Repeat
      P:=(Game.GetCurrentScene as TGameSceneAbout).Objects.GetCollision(P,Pos,1);
      if P<>nil then
      begin
        P^.GameObject.SetLife:=P^.GameObject.GetLife-20;
      end;
    until p=nil;

  end;
end;

//============================================================================//
//============================================================================//
//============================================================================//

Constructor TGameSceneAbout.Create(GameObj : TObject; GameScene : TGameScene);
Var
  Obj : TGameObject;
  i : Longint;
  Pos : TD3DVector;

  VectorPos, VectorLookAt : TD3DVector;
  CursorPos : TD3DVector;
begin
  Inherited;
  Lights[0]:=InitDirectionalLight(D3DVector(-100,-100,-100), 4, 4, 5, 0);
  Lights[1]:=InitDirectionalLight(D3DVector(-100,-100,100),1.0, 1.0, 1.0,0);
  MeshGround:=TMesh.Create(Game,'Models\ground.x3d','Textures');
  MeshBase:=TMesh.Create(Game,'Models\Беседка.x3d','Textures');
  MeshTover:=TMesh.Create(Game,'Models\Tover.x3d','Textures');
  MeshCursor:=TMesh.Create(Game,'Models\Cube.x3d','Textures');
  For i:=Low(MeshMonsters) to High(MeshMonsters) do MeshMonsters[i]:=nil;
  MeshMonsters[1]:=TMesh.Create(Game,'Models\Man.x3d','Textures');
  For i:=Low(MeshBullets) to High(MeshBullets) do MeshBullets[i]:=nil;
  MeshBullets[1]:=TMesh.Create(Game,'Models\Bullet.x3d','Textures');


  Font   := TFont.Create(Game,'Fonts\MS Sans Serif_512x256.bmp');
  FPSStr := TText.Create(Game,Font,10,10);
  FPSStr.SetTextColor($00FFFFFF,$00AF0F2F,$00FF0F20,$00FF0F20);

  InfoStr := TText.Create(Game,Font,400,10);
  InfoStr.SetTextColor($00FFB000,$0000B0FF,$0000FF00,$0000FF00);

  Cursor := TGameObject.Create(Game,MeshCursor,D3DVector(0,1,0));
  Cursor.Scale(1,2,1);
  Cursor.Process;

  Ground1 := TGameObject.Create(Game,MeshGround,D3DVector(0,0,0));
  Ground1.Scale(20,20,20);
  Ground1.Process;

  Tovers :=TGameObjects.Create(Game);
  Objects:=TGameObjects.Create(Game);
  Bullets:=TGameObjects.Create(Game);

  //БАЗА:
    Obj:=TGameObject.Create(Game,MeshBase,D3DVector(0,0,0));
    Obj.SetLife:=5000;
    Pos:=Obj.Pos;
    Pos.y:=-Obj.CollisionBox.Down;
    Obj.Pos:=Pos;
    Obj.RollY((-100+Random(201))/50);
    Tovers.Add(Obj);
    Obj.Process;

  //Установка камеры на курсоре:
    CursorPos:=Cursor.Pos;
    VectorPos:=Camera.GetPos;
    VectorLookAt:=Camera.GetLookAt;
    VectorPos.x:=CursorPos.x;
    VectorPos.z:=CursorPos.z-20;
    VectorLookAt.x:=CursorPos.x;
    VectorLookAt.z:=CursorPos.z;
  Camera.SetCameraPos(VectorPos);
  Camera.SetLookTo(VectorLookAt);

  Maney:=1000;
  DiedMonster:=0;

  //Звук:
  //Динамическое подключение (загрузка):
  cbrg_LoadSoundLibrary;

  //Инициализация библиотеки:
  cbrg_InitDS;

  //Создание и загрузка музыки и звуков:
  //@EndMusicHandle - адрес вызываемой процедуры по окончании
  //проигрывания музыки
  For i:=Low(Sounds) to High(Sounds) do Sounds[i]:=nil;
  Sounds[0]:=cbrg_CreateSound('SOUND\Fire.wav');
  Sounds[1]:=cbrg_CreateSound('SOUND\Explosion.wav');

  //Установка громкости:
  For i:=Low(Sounds) to High(Sounds) do cbrg_SetVolume(Sounds[i], 70);

end;

//============================================================================//

Procedure TGameSceneAbout.Free;
Var
  i : Longint;
begin
  //Звук:
  //Освобождение занимаемых ресурсов:
  For i:=Low(Sounds) to High(Sounds) do cbrg_FreeSound(Sounds[i]);
  //Освобождение ресурсов занимаемых библиотекой:
  cbrg_CloseDS;
  //Выгрузка библиотеки
//  cbrg_FreeSoundLibrary; //Почему-то ошибка возникает :)

  //Графика:
  Ground1.Free;
  Cursor.Free;

  Objects.Free;
  Tovers.Free;
  Bullets.Free;

  FPSStr.Free;
  InfoStr.Free;

  Font.Free;

  if MeshCursor<>nil then MeshCursor.Free;
  if MeshBase<>nil then MeshBase.Free;
  if MeshTover<>nil then MeshTover.Free;
  if MeshGround<>nil then MeshGround.Free;
  For i:=Low(MeshMonsters) to High(MeshMonsters) do
  if MeshMonsters[i]<>nil then MeshMonsters[i].Free;
  For i:=Low(MeshBullets) to High(MeshBullets) do
  if MeshBullets[i]<>nil then MeshBullets[i].Free;

  Inherited;
end;

//============================================================================//

Function TGameSceneAbout.Process : TGameScene;
Var
  VectorPos, VectorLookAt : TD3DVector;
  CursorPos : TD3DVector;

  i : Longint;
  Obj : TGameObject;
  Pos : TD3DVector;

  P : PMyObject;
begin
  if Game.KeyPressed(DIK_ESCAPE) then Exit;
  Result:=Inherited Process;

  //=======КАМЕРА=======//

  //Крутим камеру мышкой:
  VectorPos:=Camera.GetPos;
  VectorLookAt:=Camera.GetLookAt;
  if Game.MousePressed(1) then
  begin
    With VectorPos do
    begin
      x:=x+Game.MouseOfsX / 10;
      z:=z-Game.MouseOfsY / 10;
    end;
    With VectorLookAt do
    begin
      x:=x+Game.MouseOfsX / 10;
      z:=z-Game.MouseOfsY / 10;
    end;
  end else
  begin
    CursorPos:=Cursor.Pos;
    CursorPos.x:=CursorPos.x+Game.MouseOfsX/10;
    CursorPos.z:=CursorPos.z-Game.MouseOfsY/10;
    Cursor.Pos:=CursorPos;
  end;


  //Нажата левая дополнительная кнопка мышки:
  if Game.MousePressed(0) then
  if Maney>=50 then
  begin
    CursorPos:=Cursor.Pos;

    if Objects.GetCollision(CursorPos,MeshTover.CollisionBox.MaxRadius)=nil then
    if Tovers.GetCollision(CursorPos,MeshTover.CollisionBox.MaxRadius)=nil then
    begin
      Obj:=TToverGameObject.Create(Game,MeshTover,CursorPos);
      Pos:=Obj.Pos;
      Pos.y:=-Obj.CollisionBox.Down;
      Obj.Pos:=Pos;
      Obj.Process;
      (Obj as TToverGameObject).SetFireTimer:=0;
      Tovers.Add(Obj);
      Dec(Maney,50);
    end;
  end;

  //Нажата средняя кнопка мышки:
  if Game.MousePressed(2) then
  begin
    CursorPos:=Cursor.Pos;
    VectorPos:=Camera.GetPos;
    VectorLookAt:=Camera.GetLookAt;
    VectorPos.x:=CursorPos.x;
    VectorPos.z:=CursorPos.z-20;
    VectorLookAt.x:=CursorPos.x;
    VectorLookAt.z:=CursorPos.z;
  end;

  //Прокуртка колёсика мышки:
  if  Game.MouseWheel<>0 then VectorPos.y:=VectorPos.y-Game.MouseWheel*0.01;
  if VectorPos.y<1 then VectorPos.y:=1;
  if VectorPos.y>40 then VectorPos.y:=40;
  //Установка позиции камеры:
  Camera.SetCameraPos(VectorPos);
  Camera.SetLookTo(VectorLookAt);

  //=======FPS=======//

  //Расчёт кадров и создание строки:
  if SaveFPS<>Game.GetFPS then
  begin
    FPSStr.Text:='FPS: {'+FloatToStrF(Game.GetFPS, ffFixed, 12, 2)+'}'+#10+
                 'Треугольников на кадр: '+IntToStr(Game.TrianglesNum)+#10+
                 'Треугольников в секунду: '+FloatToStrF(Game.TrianglesNum*Game.GetFPS, ffFixed, 12, 0)
                 ;
    SaveFPS:=Game.GetFPS
  end;


    InfoStr.Text:='{'+IntToStr(DiedMonster)+'} пупков заколбасено.'+#10+
                  'Пупков нападает: {'+IntToStr(Objects.GetCount)+'}'+#10+
                  'Строений базы: {'+IntToStr(Tovers.GetCount)+'}'+#10+
                  'Денег: {'+IntToStr(Maney)+'} рублей.'+#10+
                  'Объектов обрабатывается: {'+IntToStr(Objects.GetCount+Tovers.GetCount+Bullets.GetCount)+'}'
                  ;
  //=======ОБРАБОТКА ИГРОВЫХ ОБЪЕКТОВ=======//

  if Random(100)<1+(DiedMonster div 50) then
  begin
    Case Random(4) of
    0 : begin
          CursorPos.x:=-60;
          CursorPos.z:=-60+Random(121);
        end;
    1 : begin
          CursorPos.x:=60;
          CursorPos.z:=-60+Random(121);
        end;
    2 : begin
          CursorPos.x:=-60+Random(121);
          CursorPos.z:=-60;
        end;
    3 : begin
          CursorPos.x:=-60+Random(121);
          CursorPos.z:=60;
        end;
    end;
    CursorPos.y:=0;

    P:=Objects.GetCollision(CursorPos,MeshMonsters[1].CollisionBox.MaxRadius*0.25);
    if P=nil then
    begin
      Obj:=TPupsGameObject.Create(Game,MeshMonsters[1],CursorPos);
      Pos:=Obj.Pos;
      Obj.Scale(0.25,0.25,0.25);
      Pos.y:=-Obj.CollisionBox.Down;
      Obj.Pos:=Pos;
      Obj.RollY((-100+Random(201))/50);
//      Obj.Speed(-0.1);
      Obj.Process;
      Objects.Add(Obj);
    end;

  end;

  if Game.KeyPressed(DIK_SPACE) then
  begin
    Objects.Clear;
  end;

  Objects.Process;
  Tovers.Process;
  Bullets.Process;

  if Ground1.ReadyToUpdate then
  Ground1.Process;

  Cursor.Process;
end;

//============================================================================//

Procedure TGameSceneAbout.Draw;
Var
  i : Longint;
begin
  Inherited;

  With Game.GetDevice do
  begin
    SetLight(0,Lights[0]);
    SetLight(1,Lights[1]);
    LightEnable(0,True);
    LightEnable(1,True);

    SetLight(0,Lights[0]);
    SetLight(1,Lights[1]);
  end;

  Ground1.Draw;

  Tovers.Draw;
  Objects.Draw;
  Bullets.Draw;

  Cursor.Draw;

  FPSStr.Draw;
  InfoStr.Draw;
end;
//============================================================================//
//============================================================================//
//============================================================================//

end.
