unit main;

interface
uses
CoreX, i2_3d, game_objects, dgSoundEngine;

procedure CoreX_Init;
procedure CoreX_Finit;
procedure CoreX_Render;
function TriIntersect( fMat : TMat4f; fA, fB, fC, fDot : TVec3f ) : Boolean;
procedure ShakeCam( fI : Integer );
procedure Boom;
procedure Hit;

type
TGameState = ( gsIntro, gsMenu, gsContMenu, gsGame );

var
{$region 'models'}
 ship, turbine1, turbine2, turbine3,
 bullet, rocket, bomb,
 enemy1, enemy2, enemy3,
 turretheadG, turretG, turretheadR, turretRL, turretRR,
 bossBody, bossCoverL, bossCoverR, bossHead, bossRotor,
 terrain : TMeshContainer;
{$endregion}
tmp : real;
tmpMat : tmat4f;
tmpVec : tvec3f;
  ScrollSpeed : Real = 300;

  boss : tboss;
  player : TPlayerShip;
  CamShaker : real;
  CamIterator : byte;
  bulleter : byte;
  hitter : byte;
  boomer : byte;
  healther : real = 100;
  gatler : real = 20;
  heaver : real = 10;
  swarmer : real = 5;
  tmpStr : String;

  GS : TGameState = gsIntro;
  spMax : real = 3;
  Credits : Boolean = false;
  Creder : real = -250;

  cur : tvec2f;
  play, exiter : real; 
  IntroName, IntroText, IntroTitle : real;

implementation

procedure CoreX_Init;
var
  p : tvec4f;
  I: Integer;
begin

{  TSubEvent.Add;
  TSubSpawner.Add(0,1,dTop,50,false,0,es.LastEvent);}
  es.Load('../lev/lev1.txt');

//  screen.Resize( screen.Width, screen.Height );
//  screen.FullScreen := true;
  with render, camera do
  begin
    Set3D( 45, {screen.Width / screen.Height}800/600 );
    Angle.x := deg2rad * 90;
    Pos.Y := 450;//}300;
    DepthTest := true;
//  CullFace := cfFront;
  end;

  FileSys.PathAdd('../tex/');

  ttexture.Load( 'text' );

  ship.Load( '../mdl/ship.smd' );
  turbine1.Load('../mdl/turbine1.smd');
  turbine2.Load('../mdl/turbine2.smd');
  turbine3.Load('../mdl/turbine3.smd');
  bullet.Load('../mdl/bullet.smd');
  rocket.Load('../mdl/rocket.smd');
  bomb.Load('../mdl/bomb.smd');
  enemy1.Load('../mdl/enemy1.smd');
  enemy2.Load('../mdl/enemy2.smd');
  enemy3.Load('../mdl/enemy3.smd');
  turretheadG.Load('../mdl/turret_head_g.smd');
  turretG.Load('../mdl/turret_g.smd');
  turretheadR.Load('../mdl/turret_head_r.smd');
  turretRL.Load('../mdl/turret_r_l.smd');
  turretRR.Load('../mdl/turret_r_r.smd');
  bossBody.Load('../mdl/boss_body.smd');
  bossCoverL.Load('../mdl/boss_cover_left.smd');
  bossCoverR.Load('../mdl/boss_cover_right.smd');
  bossHead.Load('../mdl/boss_head.smd');
  bossRotor.Load('../mdl/boss_rotor.smd');
  terrain.Load('../mdl/terrain.smd');

//  Sounds.AddSound( '../snd/hit' );
  Sounds.AddSoundsFromFolder({seFunc.ExtractFileDir(ParamStr(0)) +} '..\snd\');

  Sounds['hit0'].Gain := 0.25;
  Sounds['expl0_0'].Gain := 0.125;
  Sounds['expl1_0'].Gain := 0.125;

  for I := 1 to 6 - 1 do
  begin
  Sounds.Duplicate('hit'+conv(i), 'hit0');
  Sounds.Duplicate('shot'+conv(i), 'shot0');
  Sounds.Duplicate('expl0_'+conv(i), 'expl0_0');
  Sounds.Duplicate('expl1_'+conv(i), 'expl1_0');
  end;

  with  sounds['E-Cone - Theme1'] do
  begin
    Gain := 0.5;
    loop := true;
  end;

  with  sounds['E-Cone - Theme2'] do
  begin
    Gain := 0.5;
    loop := true;
  end;


  with gl do
  begin
    EnableClientState( gl_vertex_array );
    EnableClientState( gl_normal_array );
    EnableClientState( gl_texture_coord_array );
//    Enable( GL_LIGHTING );
    Enable( GL_LIGHT0 );
    p := vec4f( 0, 0, 1000, 0 );
    Lightfv( GL_LIGHT0, GL_POSITION, @p );
  end;

  player := TPlayerShip.Create;
  player.GunUpgrade := 4;
  TTerrain.Create;
//  boss := TBoss.Create(dbottom, 50, false);

end;

procedure CoreX_Finit;
begin

  with gl do
  begin
    DisableClientState( gl_vertex_array );
    DisableClientState( gl_normal_array );
    DisableClientState( gl_texture_coord_array );
  end;

  input.Capture := false;

end;

procedure CoreX_Render;
var
  I: Integer;
begin

case GS of
gsIntro:
begin
with render, gl do
begin
  ClearColor( 0, 0, 0, 0 );//( 0, 0.1, 0, 1 );
  render.Clear( true, true );

  render.Set2D(800,600);

  IntroName := lerp( IntroName, 1, 2 * DeltaTime );

  if IntroName > 0.95 then
  IntroText := lerp( IntroText, 1, 2 * DeltaTime );

  if IntroText > 0.95 then
  IntroTitle := lerp( IntroTitle, 1, 2 * DeltaTime );

  DepthWrite := false;
  ttexture.Load('text').Bind();
  //E-Cone
  color4f( 1, 1, 1, introname );
  HUDQuad(0, 120, 15, 64, 0, 0/256, 64/256, 15/256 );
  //text
  color4f( 1, 1, 1, Introtext );
  HUDQuad(0, 100, 110-96, 75, 0/256, 96/256, 75/256, 110/256 );
  //title
  color4f( 1, 1, 1, introtitle );
  HUDQuad(0, 80, 15, 241, 0, 16/256, 241/256, 30/256 );

  DepthWrite := true;

  if IntroTitle > 0.95 then
  begin
  sounds['E-Cone - Theme1'].Play();
  gs := gsMenu;
  end;

end;
end;

gsContMenu:
begin
with render, gl do
begin
  ClearColor( 0, 0, 0, 0 );//( 0, 0.1, 0, 1 );
  render.Clear( true, true );

  render.Set2D(800,600);
  with input do
  begin
    capture := true;
    cur := cur + vec2f( Mouse.Delta.X, -Mouse.Delta.Y );
    cur := vec2f( clamp(cur.x, -400, 400), clamp( cur.y, -300, 300 ) );
  play := lerp( play, 0.5, 2.95 * DeltaTime );
  exiter := lerp( exiter, 0.5, 2.95 * DeltaTime );

  if cur.y > 0 then play := 1 else exiter := 1;
  if hit[ikMouseL] then if play = 1 then GS := gsGame else corex.Quit;
  if hit[ikEsc] then gs := gsGame;
  

  end;

  DepthWrite := false;
  ttexture.Load('text').Bind();
  //title
  color4f( 1, 1, 1, 1 );
  HUDQuad(0, 80, 15, 241, 0, 16/256, 241/256, 30/256 );
  //play
  color4f( 1, 1, 1, play );
  HUDQuad(0, 20, 15, 162-89, 89/256, 80/256, 162/256, 94/256 );
  //quit
  color4f( 1, 1, 1, exiter );
  HUDQuad(0, -20, 81-64, 237-192, 192/256, 64/256, 237/256, 81/256 );

  color4f( 1, 1, 1, 1 );
  HUDQuad(cur.x, cur.y, 32, 32, 218/256, 218/256, 1, 1 );
  DepthWrite := true;
end;
end;
gsMenu:
begin
with render, gl do
begin
  ClearColor( 0, 0, 0, 0 );//( 0, 0.1, 0, 1 );
  render.Clear( true, true );

  render.Set2D(800,600);
  with input do
  begin
    capture := true;
    cur := cur + vec2f( Mouse.Delta.X, -Mouse.Delta.Y );
    cur := vec2f( clamp(cur.x, -400, 400), clamp( cur.y, -300, 300 ) );
  play := lerp( play, 0.5, 2.95 * DeltaTime );
  exiter := lerp( exiter, 0.5, 2.95 * DeltaTime );
  IntroName := lerp( IntroName, 0, deltatime );
  IntroText := lerp( IntroText, 0, deltatime );

  if cur.y > 0 then play := 1 else exiter := 1;
  if hit[ikMouseL] then if play = 1 then GS := gsGame else corex.Quit;



  end;

  DepthWrite := false;
  ttexture.Load('text').Bind();
    //E-Cone
  color4f( 1, 1, 1, introname );
  HUDQuad(0, 120, 15, 64, 0, 0/256, 64/256, 15/256 );
  //text
  color4f( 1, 1, 1, Introtext );
  HUDQuad(0, 100, 110-96, 75, 0/256, 96/256, 75/256, 110/256 );

  //title
  color4f( 1, 1, 1, 1 );
  HUDQuad(0, 80, 15, 241, 0, 16/256, 241/256, 30/256 );
  //play
  color4f( 1, 1, 1, play );
  HUDQuad(0, 20, 15, 250-190, 190/256, 0/256, 250/256, 14/256 );
  //quit
  color4f( 1, 1, 1, exiter );
  HUDQuad(0, -20, 81-64, 237-192, 192/256, 64/256, 237/256, 81/256 );

  color4f( 1, 1, 1, 1 );
  HUDQuad(cur.x, cur.y, 32, 32, 218/256, 218/256, 1, 1 );
  DepthWrite := true;
end;
end;

gsGame:
begin
  gl.ClearColor( 1, 1, 1, 1 );//( 0, 0.1, 0, 1 );
  render.Clear( true, true );

  render.Set3D( 45, {screen.Width / screen.Height}800/600 );
{$region 'in game'}
{$region 'input'}
  with input do
  begin
    Capture := true;
    if hit[ ikEsc ] then gs := gsContMenu;
    if hit[ ikQ ] then player.Health := 0;
    if hit[ ikE ] then boss := TBoss.Create(dbottom, 50, false);

//      screen.Caption := 'Health: '+conv(player.health)+' Continues: '+conv(player.Continues);
//        screen.Caption := 'Event: '+conv(es.CurrentEvent);
  end;
{$endregion}
  with render.Camera do
  begin
    UpdateMatrix;
    UpdatePlanes;

    gl.LoadMatrixf(ViewMatrix);
  end;

  tmp := tmp - Render.DeltaTime;

   if boss = nil  then 
  
  if (tmp < 0) then
  begin
    tmp := spMax;
//    tmpVec := vec3f( random(390) - 245,0,-190 );

//    tmpmat.LookAt(tmpvec,gc.Get(0).Matrix.Pos,vec3f(0,-1,0));

//    tmpmat.Pos := tmpvec;
//    tmpMat.Rot.Normal;
//    TEnemy1.Create(tmpmat);
for I := 0 to 4 - 1 do
  
case random(4) of

1:
if random(2) = 0 then
      TEnemy1.Create(tappearance(random(3)),random(100), false).Tactic := random( 2 )
    else
      TEnemy1.Create(tappearance(random(3)),random(25), true).Tactic := 2;
2:
if random(2) = 0 then
      TEnemy2.Create(tappearance(random(3)),random(100),false)
    else
      TEnemy2.Create(dtop,random(100), true);
3:    TEnemy3.Create(tappearance(random(3)),random(100)).Tactic := random(2);
4:    TBomb.Create(dTop,random(100));
end;
  end;

  with render, camera, pos do
  pos := pos.lerp( vec3f( 0, y, 0 ), 0.9 * DeltaTime );

   CamShaker := CamShaker - render.deltatime;

  if (CamIterator > 0) and (CamShaker<0) then
  begin
    dec( CamIterator );
    CamShaker := 0.05;
    with render, camera, pos do
    pos := vec3f( random( 20 ) - 10, y, random( 20 ) - 10 );
  end;
{$endregion}
  gc.Update;
gl.color4f( 1, 1, 1, 1);
render.Set2D(screen.Width, screen.Height);
  ttexture.Load('text').Bind();
  Render.DepthWrite := false;
  healther := lerp( healther, player.Health, 1.95 * render.DeltaTime );
  //health
  if player.Invincibility > 0 then gl.Color4f( 1, 1, 1, 0.5 ) else gl.Color4f( 1, 1, 1, 1 );
  
  HUDQuad(-400,-280,15,69,0,32/256,69/256,46/256,false);//red
  HUDQuad(-400,-280,15,69/100*healther,0,48/256,(69/256)/100*healther,62/256,false);
  //gatling
  with player.Guns[0] do
  begin
    if gunClipLoad < 0 then
    begin
      gl.Color4f( 1, 1, 1, 1 );
      gatler := ( gunClipSize - gunClip ) / gunClipSize * 100;
    end
    else
    begin
      gl.Color4f( 1, 1, 1, 0.5 );
      gatler := 100 - gunClipLoad / gunClipDelay * 100;
    end;
  end;

  HUDQuad(-300,-280,15,81,70/256,32/256,151/256,46/256,false);//red
  HUDQuad(-300,-280,15,81/100*gatler,70/256,48/256,70/256+(81/256)/100*gatler,62/256,false);

  //heavy
  with player.Guns[2] do
  begin
    if gunClipLoad < 0 then
    begin
      gl.Color4f( 1, 1, 1, 1 );
      heaver := ( gunClipSize - gunClip ) / gunClipSize * 100;
    end
    else
    begin
      gl.Color4f( 1, 1, 1, 0.5 );
      heaver := 100 - gunClipLoad / gunClipDelay * 100;
    end;
  end;

  HUDQuad(-200,-280,15,58,153/256,32/256,211/256,46/256,false);//red
  HUDQuad(-200,-280,15,58/100*heaver,153/256,48/256,153/256+(58/256)/100*heaver,62/256,false);

  //rockets
  with player do
  begin
    if rockClipLoader < 0 then
    begin
      gl.Color4f( 1, 1, 1, 1 );
      swarmer := 100 - ( rockClip / rockClipMax ) * 100;
    end
    else
    begin
      gl.Color4f( 1, 1, 1, 0.5 );
      swarmer := 100 - ( rockClipLoader / rockClipDelay) * 100;
    end;


  end;

  HUDQuad(-100,-280,15,87,0,64/256,87/256,78/256,false);//red
  HUDQuad(-100,-280,15,87/100*swarmer,0,80/256,(87/256)/100*swarmer,94/256,false);

  //Deaths
  gl.Color4f( 1, 1, 1, 1 );
  HUDQuad( -400, 260, 15, 76, 75/256, 202/256, 152/256, 217/256, false );
  tmpStr := conv( player.Continues );
  for I := 1 to length( tmpStr ) do
    begin
      HUDQuad( -324 + 11 * i, 260, 15, 10, (conv( tmpStr[i], 0 ))*10/256, 241/256, (conv( tmpStr[i], 0 ))*10/256+11/256, 255/256 );
    end;

//  gl.Color4f( 1, 1, 1, 1 );
  HUDQuad( -400, 280, 15, 68, 0/256, 218/256, 69/256, 232/256, false );
  tmpStr := conv( player.score );
  for I := 1 to length( tmpStr ) do
    begin
      HUDQuad( -332 + 11 * i, 280, 15, 10, (conv( tmpStr[i], 0 ))*10/256, 241/256, (conv( tmpStr[i], 0 ))*10/256+11/256, 255/256 );
    end;

  if credits then
  begin
    gl.color4f( 1, 1, 1, 0.85 );
    creder := creder + 40 * render.DeltaTime;
    HUDQuad(0, creder, 15, 215, 0, 112/256, 216/256, 127/256 );

    //E-Cone
    HUDQuad(0, creder-30, 15, 64, 0, 0/256, 64/256, 15/256 );
    HUDQuad(0, creder-45, 15, 241, 0, 16/256, 241/256, 30/256 );

    HUDQuad(0, creder-60, 15, 188-65, 65/256, 0/256, 188/256, 14/256 );

    HUDQuad(0, creder-105, 18, 125, 0, 128/256, 127/256, 145/256 );

    //XProger
    HUDQuad(0, creder-135, 164-147, 73, 0, 147/256, 72/258, 165/256 );
    //glTrinix
    HUDQuad(0, creder-160, 165-147, 144-75, 75/256, 147/256, 146/256, 165/256 );
    //Duncon
    HUDQuad(0, creder-185, 15, 157-93, 93/256, 186/256, 159/256, 200/256 );
    //Exelord
    HUDQuad(0, creder-210, 15, 191-126, 126/256, 166/256, 193/256, 180/256 );
    //TMonax
    HUDQuad(0, creder-235, 15, 73, 0/256, 202/256, 73/256, 216/256 );
    //DPsStudio
    HUDQuad(0, creder-260, 15, 92, 0/256, 186/256, 91/256, 200/256 );
    //Egor Rezenov
    HUDQuad(0, creder-285, 183-166, 123, 0/256, 166/256, 122/256, 183/256 );
    //Bonny ^^
    HUDQuad(0, creder-310, 164-147, 201-146, 146/256, 147/256, 202/256, 164/256 );

  end;

  Render.DepthWrite := true;
end;
end;

{render.Set2D(screen.Width, screen.Height);
  ttexture.Load('text').Bind();
  HUDQuad(0,0,15,64,0,0,0.25,15/256);
  HUDQuad(0,-15,15,124,65/256,0,189/256,15/256);}

end;

function TriIntersect( fMat : TMat4f; fA, fB, fC, fDot : TVec3f ) : Boolean;
var
  sum : real;
begin
with fMat do//переносим точки в локальные координаты матрицы
begin
  fA := Pos + vec3f( e00, e10, e20 ) * fA.x + vec3f( e02, e12, e22 ) * fA.z;
  fB := Pos + vec3f( e00, e10, e20 ) * fB.x + vec3f( e02, e12, e22 ) * fB.z;
  fC := Pos + vec3f( e00, e10, e20 ) * fC.x + vec3f( e02, e12, e22 ) * fC.z;
end;

  sum := (fDot - fA).Angle( fDot - fB ) + (fDot - fA).Angle( fDot - fC ) + (fDot - fC).Angle( fDot - fB );
  result := round(sum * rad2deg) = 360 ;
end;

procedure ShakeCam( fI : Integer );
begin
  CamIterator := fI;
end;

procedure Boom;
begin
  inc(boomer);
  if boomer > 5 then boomer := 0;
  sounds['expl'+conv(random(2))+'_'+conv(boomer)].Play;
end;

procedure Hit;
begin
  inc( hitter );
  if hitter > 5 then hitter := 0;
  sounds['hit'+conv(hitter)].Play();
  
end;

end.
