unit _Scene;

interface

uses
  _Forms,
  _Resources,   
  _Geometry,
  MainMenu,
  QuadEngine,
  Windows,
  Classes;

const
  MAX_SCENES = 5;
  SM_NONE = -1;
  SM_GAME = 0;
  SM_MENU = 1;
  SM_LOGO = 2;

type
TBasicScene =  class
  public
    procedure SendMessage(mess: String); virtual;
    procedure Render; virtual;
    procedure Update(dt:single); virtual;
    procedure Control; virtual; 
  end;

TLogo = class(TBasicScene)
  private          
    FLogoTexture: IQuadTexture;
    FQuad: IQuadRender;
    FTimer:   Single;
    FMaxTime: Single;
    FNextScene: TBasicScene;
  public
    constructor Create(NextScene: TBasicScene; Quad: IQuadRender; Logo: IQuadTexture; Time: Single = 3.0);
    destructor Destroy;
    procedure Render; override;
    procedure Update(dt:single); override;
    procedure Control; override;
end;

TSceneManager = class(TBasicScene)
  private
    FSceneList:    TList;
    FCurrentScene: TBasicScene;
  public
    constructor Create(DefaultScene: TBasicScene);
    function  AddScene(NewScene: TBasicScene): TBasicScene;
    procedure SetScene(Scene: TBasicScene);
    procedure Render; override;
    procedure Update(dt: single); override;
    procedure Control; override;
    procedure Free;
end;
 
TMainMenu = class(TBasicScene)
  private
    Quad: IQuadRender;
    PrevKeys:array [0..255] of byte;
    MainMenu: TMenu;                
    MouseX, MouseY: Integer;
    Fade: Single;
    MMStartGame: TTopMenuItem;
    MMResumeGame: TTopMenuItem;
    MMOptions: TTopMenuItem;
    MMHotSeat: TTopMenuItem;
    MMDemo: TTopMenuItem;
    MMExitGame: TTopMenuItem;
    FGameMode: Byte;

    LevelMenu: TMenu;
    LMLevel1: TTopMenuItem;
    LMLevel2: TTopMenuItem;
    LMLevel3: TTopMenuItem;
    LMLevel4: TTopMenuItem;
    LMLevel5: TTopMenuItem;

    ResultMenu: TMenu;
    RMREsult: TTopMenuItem;
    Block: Byte;
    SubMenu: TMenu;
    z: Byte;

    FGameScene: TBasicScene;
    procedure StartLevel_1;
    procedure StartLevel_2;
    procedure StartLevel_3;
    procedure StartLevel_4;
    procedure StartLevel_5;
    procedure SelectLevel;
    procedure SelectLevelForPlayers;
    procedure SelectLevelForComputers;
    procedure ResumeGame;
    procedure ReturnToMainMenu;
  public               
    procedure ShowMenu;
    procedure Result(Mess: String);
    constructor Create(Quad: IQuadRender; BasicScene: TBasicScene);
    procedure Render; override;
    procedure Update(dt:single); override;
    procedure Control; override;
    property GameScene: TBasicScene write FGameScene;
end;

var
  Manager: TSceneManager;
  Menu: TMainMenu;

implementation

uses
  _World;

{$REGION 'Basic Scene'}
procedure TBasicScene.SendMessage(mess: String);
begin

end;

procedure TBasicScene.Render;
begin

end;

procedure TBasicScene.Update(dt:single);
begin

end;

procedure TBasicScene.Control;
begin

end;
{$ENDREGION}

//Scene Manager
{$REGION 'Scene Manager'}
constructor TSceneManager.Create(DefaultScene:TBasicScene);
begin
  FSceneList:= TList.Create;
  FCurrentScene:=DefaultScene;
  FSceneList.Add(DefaultScene);
end;

procedure TSceneManager.Render;
begin
  FCurrentScene.Render;   
end;

procedure TSceneManager.Update(dt: single);
begin
  FCurrentScene.Update(dt);
end;

procedure TSceneManager.Control;
begin
  FCurrentScene.Control;
end;

function TSceneManager.AddScene(NewScene: TBasicScene): TBasicScene;
begin
  FSceneList.Add(NewScene);
  Result:= NewScene;
end;

procedure TSceneManager.SetScene(Scene: TBasicScene);
var
  i: Byte;
  inList: Boolean;
begin
  inList:= false;
  for i:=0 to FSceneList.Count - 1 do
    if (FSceneList[i] = Scene) then
      begin
        FCurrentScene:= Scene;
        inList:= true;
        Break;
      end;
  if not inList then
    begin
      FSceneList.Add(Scene);
      FCurrentScene:= Scene;
    end;             
end;

procedure TSceneManager.Free;
var
  i: Byte;
begin
  FCurrentScene.Free;
  for i:=0 to FSceneList.Count - 1 do
    TBasicScene(FSceneList.Items[i]).Free;
  FSceneList.Free;
end;
{$ENDREGION}

//Logo
{$REGION 'Logo'}
constructor TLogo.Create;
begin
  FNextScene:= NextScene;
  FLogoTexture:= Logo;
  FTimer:= Time;
  FMaxTime:= Time;
  FQuad:= Quad;
end;

destructor TLogo.Destroy;
begin
  inherited;
  FLogoTexture:= nil; 
  FNextScene:= nil;
  FQuad:= nil;
end;

procedure TLogo.Render;
var
  Color: Cardinal;
  Alpha: Single;
begin
  FQuad.Clear($ff000000);
  Alpha:= 1;
  if (FTimer < 1) then
    Alpha:= FTimer;  
  if (FTimer > FMaxTime - 1) then
    Alpha:= 1 - (FTimer - FMaxTime);
  Color:= Trunc($ff * Alpha) * $1000000 + $ffffff;
  FLogoTexture.DrawRot(
    (Window.Width div 2),
    (Window.Height div 2),
    0,
    1,
    Color);
end;

procedure TLogo.Update(dt:single);
begin
  FTimer:= FTimer - dt;
  if FTimer <= 0 then
    Manager.SetScene(FNextScene);
end;

procedure TLogo.Control;
begin
  if  Window.Mouse.mbl or
      Window.Key[KEY_SPACE] or
      Window.Key[KEY_ENTER] or
      Window.Key[KEY_ESC] or
      Window.Key[KEY_TILDA] or
      Window.Key[KEY_CTRL]
  then
    begin
      Window.Mouse.mbl:=      false;
      Window.Key[KEY_SPACE]:= false;
      Window.Key[KEY_ENTER]:= false;
      Window.Key[KEY_TILDA]:= false;
      Window.Key[KEY_CTRL ]:= false; 
      Window.Key[KEY_ESC  ]:= false;
      Manager.SetScene(FNextScene);
    end;
end;
{$ENDREGION}

//Main Menu
{$REGION 'MainMenu'}
constructor TMainMenu.Create(Quad: IQuadRender; BasicScene: TBasicScene);
begin
  FGameScene:= BasicScene;
  Fade:= 1;
  Self.Quad := Quad;
  MainMenu := TMenu.Create(Quad, Resources.Font);
  MainMenu.Left:= 200;
  MainMenu.OnExit:= Window.Close;
  MMResumeGame:= MainMenu.AddItem;
  MMResumeGame.Caption := 'Resume';
  MMResumeGame.OnEnter := ResumeGame;
  MMResumeGame.Enabled:= false;
  MMStartGame:= MainMenu.AddItem;
  MMStartGame.Caption := 'Missions';
  MMStartGame.OnEnter := SelectLevel;
  MMHotSeat:= MainMenu.AddItem;
  MMHotSeat.Caption := 'Hot seat';
  MMHotSeat.OnEnter := SelectLevelForPlayers;
  MMDemo:= MainMenu.AddItem;
  MMDemo.Caption := 'Demo';
  MMDemo.OnEnter := SelectLevelForComputers;
  MMExitGame := MainMenu.AddItem;
  MMExitGame.Caption := 'Exit';
  MMExitGame.OnEnter := Window.Close;

  MainMenu.SelectedItem:= MMStartGame;

  ResultMenu := TMenu.Create(Quad, Resources.Font);
  ResultMenu.Left:= 470;
  ResultMenu.OnExit:= ReturnToMainMenu;

  RMResult:= ResultMenu.AddItem;
  RMResult.Caption := 'Victory!';
  RMResult.OnEnter:= ReturnToMainMenu;
 {  MMOptions := MainMenu.AddItem;
 MMOptions.Caption := 'Options';
  MMOptions.OnEnter := StartNewGame;    }
                                    
  LevelMenu := TMenu.Create(Quad, Resources.Font);
  LevelMenu.Left:= 470;
  LevelMenu.OnExit:= ReturnToMainMenu;
  LMLevel1:= LevelMenu.AddItem;
  LMLevel1.Caption := 'Level 1';
  LMLevel1.OnEnter := StartLevel_1;
  LMLevel2:= LevelMenu.AddItem;
  LMLevel2.Caption := 'Level 2';
  LMLevel2.OnEnter := StartLevel_2;
  LMLevel3 := LevelMenu.AddItem;
  LMLevel3.Caption := 'Level 3';
  LMLevel3.OnEnter := StartLevel_3;
  LMLevel4 := LevelMenu.AddItem;
  LMLevel4.Caption := 'Level 4';
  LMLevel4.OnEnter := StartLevel_4;    
  LMLevel5 := LevelMenu.AddItem;
  LMLevel5.Caption := 'Level 5';
  LMLevel5.OnEnter := StartLevel_5;

end;

procedure TMainMenu.StartLevel_1;
begin
  World.StartLevel('level1', FGameMode);
  MMResumeGame.Enabled:= true;
  MainMenu.OnExit:= ResumeGame;
end;

procedure TMainMenu.StartLevel_2;
begin
  World.StartLevel('level2', FGameMode);
  MMResumeGame.Enabled:= true;  
  MainMenu.OnExit:= ResumeGame;
end;

procedure TMainMenu.StartLevel_3;
begin
  World.StartLevel('level3', FGameMode);
  MMResumeGame.Enabled:= true; 
  MainMenu.OnExit:= ResumeGame;
end;

procedure TMainMenu.StartLevel_4;
begin
  World.StartLevel('level4', FGameMode);
  MMResumeGame.Enabled:= true;
  MainMenu.OnExit:= ResumeGame;
end;

procedure TMainMenu.StartLevel_5;
begin
  World.StartLevel('level5', FGameMode);
  MMResumeGame.Enabled:= true;
end;

procedure TMainMenu.SelectLevel;
begin
  FGameMode:= 0;
  SubMenu:= LevelMenu;
end;

procedure TMainMenu.SelectLevelForPlayers;
begin               
  FGameMode:= 1;
  SubMenu:= LevelMenu;
end;

procedure TMainMenu.SelectLevelForComputers;
begin              
  FGameMode:= 2;
  SubMenu:= LevelMenu;
end;

procedure TMainMenu.ShowMenu;
begin
  SubMenu:= nil;
  Manager.SetScene(Menu);
end;

procedure TMainMenu.Result(Mess: String);
begin
  RMResult.Caption := Mess;
  SubMenu:= ResultMenu;
  MMREsumeGame.OnEnter:= SelectLevel;
  Block:= 150;
end;

procedure TMainMenu.ReturnToMainMenu;
begin
  SubMenu:= nil;
end;

procedure TMainMenu.ResumeGame;
begin          
  Manager.SetScene(FGameScene); 
end;

procedure TMainMenu.Render;
begin
  Quad.Clear($ff000000);  
  Resources.MapTexture.Draw(0,0);
  Quad.Rectangle(200, 0, 470, Window.Height, $88000000);
  MainMenu.Draw(1);
  if SubMenu <> nil then
    begin                                
      Quad.Rectangle(200, 0, 470, Window.Height, $88000000);
      Quad.Rectangle(470, 0, 740, Window.Height, $88000000);
      SubMenu.Draw(1);
      //Main Menu fade
      //Quad.Rectangle(400, 300,  670, Window.Height, $80000000);
    end;
  if Fade > 0 then
    Quad.Rectangle(0, 0, Window.Width, Window.Height, Round($ff * Fade) * $1000000);
end;

procedure TMainMenu.Update(dt:single);
begin   
  if Fade > 0 then
    Fade:= Fade - dt * 0.5
  else
    Fade:= 0;
end;

procedure TMainMenu.Control;
var
  CurMenu:TMenu;
begin
  if SubMenu <> nil then
    CurMenu:= SubMenu
  else
    CurMenu:= MainMenu;
  if Window.Mouse.mbl then
    begin
      CurMenu.ItemMouseClick(Window.Mouse.x, Window.Mouse.y);
      Window.Mouse.mbl:= false;
    end;
  if not ((MouseX = Window.Mouse.x) and (MouseY = Window.Mouse.y)) then
    CurMenu.ItemMouseHover(Window.Mouse.x, Window.Mouse.y);
  MouseX:= Window.Mouse.x;
  MouseY:= Window.Mouse.y;
  if Block > 0 then dec(Block);
  if Block = 0 then
  begin
  if Window.Key[VK_RIGHT ] or
     Window.Key[KEY_D    ] then CurMenu.KeyPress(VK_RIGHT );
  if Window.Key[VK_LEFT  ] or
     Window.Key[KEY_A    ] then CurMenu.KeyPress(VK_LEFT  );
  if Window.Key[VK_DOWN  ] or
     Window.Key[KEY_S    ] then CurMenu.KeyPress(VK_DOWN  );
  if Window.Key[VK_UP    ] or
     Window.Key[KEY_W    ] then CurMenu.KeyPress(VK_UP    );
  end;
  if Window.Key[VK_ESCAPE] then CurMenu.KeyPress(VK_ESCAPE);
  if Window.Key[KEY_TILDA] then CurMenu.KeyPress(VK_ESCAPE);
  if Window.Key[VK_RETURN] or
     Window.Key[VK_SPACE ] then CurMenu.KeyPress(VK_RETURN);
  Window.Key[VK_RIGHT ]:= false;
  Window.Key[KEY_D    ]:= false;
  Window.Key[VK_LEFT  ]:= false;
  Window.Key[KEY_A    ]:= false;
  Window.Key[VK_DOWN  ]:= false;
  Window.Key[KEY_S    ]:= false;
  Window.Key[VK_UP    ]:= false;
  Window.Key[KEY_W    ]:= false;
  Window.Key[VK_ESCAPE]:= false; 
  Window.Key[KEY_TILDA]:= false;
  Window.Key[VK_RETURN]:= false;
  Window.Key[VK_SPACE ]:= false;
end;
{$ENDREGION}

end.
