aboutsummaryrefslogblamecommitdiffstats
path: root/Lua/src/base/USingScores.pas
blob: 9ae48548c8e561b243f7354b333a0f304d092a4b (plain) (tree)


































































































































                                                                                            
                                 











































                                                                              
                                                         



























































































                                                                                                                                                           
                                            





































































































































































































































































                                                                                                                                                           
                                                                 











                                                                     
                                                                 



























































































































































                                                                                                                    

                                                           
 

                                                                            
 
                                                                        








                                                                             

                                      
 
                                                                                

                                   
                                                                     
 
                                                                                
                             

                                                                     
 
                                                      




























                                                                                                                                           

                                        
 
                                                                                  



                                 
                                                                   
 
                                                                                  
                                 
                                                

                           
                                                                       
 
                                                        



































                                                                                                                               
                                                  

































                                                                                                  
                                                               

















































                                                                                                                                                     
                                                               












































































































                                                                                       
{* UltraStar Deluxe - Karaoke Game
 *
 * UltraStar Deluxe is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *}

unit USingScores;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}

uses
  UThemes,
  gl,
  UTexture;

//////////////////////////////////////////////////////////////
//                        ATTENTION:                        //
// Enabled Flag does not Work atm. This should cause Popups //
// Not to Move and Scores to stay until Renenabling.        //
// To use e.g. in Pause Mode                                //
// Also InVisible Flag causes Attributes not to change.     //
// This should be fixed after next Draw when Visible = True,//
// but not testet yet                                       //
//////////////////////////////////////////////////////////////

//Some constants containing options that could change by time
const
  MaxPlayers = 6;   //Maximum of Players that could be added
  MaxPositions = 6; //Maximum of Score Positions that could be added

type
  //-----------
  // TScorePlayer - Record Containing Information about a Players Score
  //-----------
  TScorePlayer = record
    Position: Byte;    //Index of the Position where the Player should be Drawn
    Enabled:  Boolean; //Is the Score Display Enabled
    Visible:  Boolean; //Is the Score Display Visible
    Score:    Word;    //Current Score of the Player
    ScoreDisplayed: Word; //Score cur. Displayed(for counting up)
    ScoreBG:  TTexture;//Texture of the Players Scores BG
    Color:    TRGB;    //Teh Players Color
    RBPos:    Real;    //Cur. Percentille of the Rating Bar
    RBTarget: Real;    //Target Position of Rating Bar
    RBVisible:Boolean; //Is Rating bar Drawn
  end;
  aScorePlayer = array[0..MaxPlayers-1] of TScorePlayer;

  //-----------
  // TScorePosition - Record Containing Information about a Score Position, that can be used
  //-----------
  PScorePosition = ^TScorePosition;
  TScorePosition = record
    //The Position is Used for Which Playercount
    PlayerCount: Byte;
    // 1 - One Player per Screen
    // 2 - 2 Players per Screen
    // 4 - 3 Players per Screen
    // 6 would be 2 and 3 Players per Screen

    BGX: Real;     //X Position of the Score BG
    BGY: Real;     //Y Position of the Score BG
    BGW: Real;     //Width of the Score BG
    BGH: Real;     //Height of the Score BG

    RBX: Real;     //X Position of the Rating Bar
    RBY: Real;     //Y Position of the Rating Bar
    RBW: Real;     //Width of the Rating Bar
    RBH: Real;     //Height of the Rating Bar

    TextX: Real;         //X Position of the Score Text
    TextY: Real;         //Y Position of the Score Text
    TextFont: Byte;      //Font of the Score Text
    TextSize: integer;   //Size of the Score Text

    PUW: Real;           //Width of the LineBonus Popup
    PUH: Real;           //Height of the LineBonus Popup
    PUFont: Byte;        //Font for the PopUps
    PUFontSize: integer; //FontSize for the PopUps
    PUStartX: Real;      //X Start Position of the LineBonus Popup
    PUStartY: Real;      //Y Start Position of the LineBonus Popup
    PUTargetX: Real;     //X Target Position of the LineBonus Popup
    PUTargetY: Real;     //Y Target Position of the LineBonus Popup
  end;
  aScorePosition = array[0..MaxPositions-1] of TScorePosition;

  //-----------
  // TScorePopUp - Record Containing Information about a LineBonus Popup
  // List, Next Item is Saved in Next attribute
  //-----------
  PScorePopUp = ^TScorePopUp;
  TScorePopUp = record
    Player:  Byte;          //Index of the PopUps Player
    TimeStamp: Cardinal;    //Timestamp of Popups Spawn
    Rating:    Byte;        //0 to 8, Type of Rating (Cool, bad, etc.)
    ScoreGiven:Word;        //Score that has already been given to the Player
    ScoreDiff: Word;        //Difference Between Cur Score at Spawn and Old Score
    Next:      PScorePopUp; //Next Item in List
  end;
  aScorePopUp = array of TScorePopUp;

  //-----------
  // TSingScores - Class containing Scores Positions and Drawing Scores, Rating Bar + Popups
  //-----------
  TSingScores = class
    private
      aPositions: aScorePosition;
      aPlayers: aScorePlayer;
      oPositionCount: Byte;
      oPlayerCount: Byte;

      //Saves the First and Last Popup of the List
      FirstPopUp: PScorePopUp;
      LastPopUp:  PScorePopUp;

      // Draws a Popup by Pointer
      procedure DrawPopUp(const PopUp: PScorePopUp);

      // Draws a Score by Playerindex
      procedure DrawScore(const Index: Integer);

      // Draws the RatingBar by Playerindex
      procedure DrawRatingBar(const Index: Integer);

      // Removes a PopUp w/o destroying the List
      procedure KillPopUp(const last, cur: PScorePopUp);
    public
      Settings: record //Record containing some Displaying Options
        Phase1Time: Real;     //time for Phase 1 to complete (in msecs)
                              //The Plop Up of the PopUp
        Phase2Time: Real;     //time for Phase 2 to complete (in msecs)
                              //The Moving (mainly Upwards) of the Popup
        Phase3Time: Real;     //time for Phase 3 to complete (in msecs)
                              //The Fade out and Score adding

        PopUpTex:  array [0..8] of TTexture; //Textures for every Popup Rating

        RatingBar_BG_Tex:   TTexture; //Rating Bar Texs
        RatingBar_FG_Tex:   TTexture;
        RatingBar_Bar_Tex:  TTexture;

      end;

      Visible: Boolean;    //Visibility of all Scores
      Enabled: Boolean;    //Scores are changed, PopUps are Moved etc.
      RBVisible: Boolean;  //Visibility of all Rating Bars

      //Propertys for Reading Position and Playercount
      property PositionCount: Byte read oPositionCount;
      property PlayerCount: Byte read oPlayerCount;
      property Players: aScorePlayer read aPlayers;
      property Positions: aScorePosition read aPositions;

      //Constructor just sets some standard Settings
      constructor Create;

      // Adds a Position to Array and Increases Position Count
      procedure AddPosition(const pPosition: PScorePosition);

      // Adds a Player to Array and Increases Player Count
      procedure AddPlayer(const ScoreBG: TTexture; const Color: TRGB; const Score: Word = 0; const Enabled: Boolean = True; const Visible: Boolean = True);

      //Change a Players Visibility, Enable
      procedure ChangePlayerVisibility(const Index: Byte; const pVisible: Boolean);
      procedure ChangePlayerEnabled(const Index: Byte; const pEnabled: Boolean);

      // Deletes all Player Information
      procedure ClearPlayers;

      // Deletes Positions and Playerinformation
      procedure Clear;

      // Loads some Settings and the Positions from Theme
      procedure LoadfromTheme;

      // has to be called after Positions and Players have been added, before first call of Draw
      //It gives every Player a Score Position
      procedure Init;

      //Spawns a new Line Bonus PopUp for the Player
      procedure SpawnPopUp(const PlayerIndex: Byte; const Rating: Byte; const Score: Word);

      //Removes all PopUps from Mem
      procedure KillAllPopUps;

      // Draws Scores and Linebonus PopUps
      procedure Draw;
  end;


implementation

uses SDL,
     SysUtils,
     ULog,
     UGraphic,
     TextGL;

{**
 * Sets some standard Settings
 *}
Constructor TSingScores.Create;
begin
  inherited;

  //Clear PopupList Pointers
  FirstPopUp := nil;
  LastPopUp  := nil;

  //Clear Variables
  Visible := True;
  Enabled := True;
  RBVisible := True;
  
  //Clear Position Index
  oPositionCount  := 0;
  oPlayerCount    := 0;

  Settings.Phase1Time := 350;  // plop it up     . -> [   ]
  Settings.Phase2Time := 550;  // shift it up        ^[   ]^
  Settings.Phase3Time := 200;  // increase score      [s++]

  Settings.PopUpTex[0].TexNum := 0;
  Settings.PopUpTex[1].TexNum := 0;
  Settings.PopUpTex[2].TexNum := 0;
  Settings.PopUpTex[3].TexNum := 0;
  Settings.PopUpTex[4].TexNum := 0;
  Settings.PopUpTex[5].TexNum := 0;
  Settings.PopUpTex[6].TexNum := 0;
  Settings.PopUpTex[7].TexNum := 0;
  Settings.PopUpTex[8].TexNum := 0;

  Settings.RatingBar_BG_Tex.TexNum   := 0;
  Settings.RatingBar_FG_Tex.TexNum   := 0;
  Settings.RatingBar_Bar_Tex.TexNum  := 0;
end;

{**
 * Adds a Position to Array and Increases Position Count
 *}
Procedure TSingScores.AddPosition(const pPosition: PScorePosition);
begin
  if (PositionCount < MaxPositions) then
  begin
    aPositions[PositionCount] := pPosition^;

    Inc(oPositionCount);
  end;
end;

{**
 * Adds a Player to Array and Increases Player Count
 *}
Procedure TSingScores.AddPlayer(const ScoreBG: TTexture; const Color: TRGB; const Score: Word; const Enabled: Boolean; const Visible: Boolean);
begin
  if (PlayerCount < MaxPlayers) then
  begin
    aPlayers[PlayerCount].Position  := High(byte);
    aPlayers[PlayerCount].Enabled   := Enabled;
    aPlayers[PlayerCount].Visible   := Visible;
    aPlayers[PlayerCount].Score     := Score;
    aPlayers[PlayerCount].ScoreDisplayed     := Score;
    aPlayers[PlayerCount].ScoreBG   := ScoreBG;
    aPlayers[PlayerCount].Color     := Color;
    aPlayers[PlayerCount].RBPos     := 0.5;
    aPlayers[PlayerCount].RBTarget  := 0.5;
    aPlayers[PlayerCount].RBVisible := True;

    Inc(oPlayerCount);
  end;
end;

{**
 * Change a Players Visibility
 *}
Procedure TSingScores.ChangePlayerVisibility(const Index: Byte; const pVisible: Boolean);
begin
  if (Index < MaxPlayers) then
    aPlayers[Index].Visible := pVisible;
end;

{**
 * Change Player Enabled
 *}
Procedure TSingScores.ChangePlayerEnabled(const Index: Byte; const pEnabled: Boolean);
begin
  if (Index < MaxPlayers) then
    aPlayers[Index].Enabled := pEnabled;
end;

{**
 * Procedure Deletes all Player Information
 *}
Procedure TSingScores.ClearPlayers;
begin
  KillAllPopUps;
  oPlayerCount := 0;
end;

{**
 * Procedure Deletes Positions and Playerinformation
 *}
Procedure TSingScores.Clear;
begin
  KillAllPopUps;
  oPlayerCount    := 0;
  oPositionCount  := 0;
end;

{**
 * Procedure Loads some Settings and the Positions from Theme
 *}
Procedure TSingScores.LoadfromTheme;
var I: Integer;
  Procedure AddbyStatics(const PC: Byte; const ScoreStatic, SingBarStatic: TThemeStatic; ScoreText: TThemeText);
    var nPosition: TScorePosition;
  begin
    nPosition.PlayerCount := PC; //Only for one Player Playing

    nPosition.BGX := ScoreStatic.X;
    nPosition.BGY := ScoreStatic.Y;
    nPosition.BGW := ScoreStatic.W;
    nPosition.BGH := ScoreStatic.H;

    nPosition.TextX     := ScoreText.X;
    nPosition.TextY     := ScoreText.Y;
    nPosition.TextFont  := ScoreText.Font;
    nPosition.TextSize  := ScoreText.Size;

    nPosition.RBX := SingBarStatic.X;
    nPosition.RBY := SingBarStatic.Y;
    nPosition.RBW := SingBarStatic.W;
    nPosition.RBH := SingBarStatic.H;

    nPosition.PUW := nPosition.BGW;
    nPosition.PUH := nPosition.BGH;

    nPosition.PUFont     := 2;
    nPosition.PUFontSize := 18;

    nPosition.PUStartX := nPosition.BGX;
    nPosition.PUStartY := nPosition.TextY + 65;

    nPosition.PUTargetX := nPosition.BGX;
    nPosition.PUTargetY := nPosition.TextY;

    AddPosition(@nPosition);
  end;
begin
  Clear;

  //Set Textures
  //Popup Tex
  For I := 0 to 8 do
    Settings.PopUpTex[I] := Tex_SingLineBonusBack[I];

  //Rating Bar Tex  
  Settings.RatingBar_BG_Tex   :=  Tex_SingBar_Back;
  Settings.RatingBar_FG_Tex   :=  Tex_SingBar_Front;
  Settings.RatingBar_Bar_Tex  :=  Tex_SingBar_Bar;

  //Load Positions from Theme

  // Player1:
  AddByStatics(1, Theme.Sing.StaticP1ScoreBG, Theme.Sing.StaticP1SingBar, Theme.Sing.TextP1Score);
  AddByStatics(2, Theme.Sing.StaticP1TwoPScoreBG, Theme.Sing.StaticP1TwoPSingBar, Theme.Sing.TextP1TwoPScore);
  AddByStatics(4, Theme.Sing.StaticP1ThreePScoreBG, Theme.Sing.StaticP1ThreePSingBar, Theme.Sing.TextP1ThreePScore);

  // Player2:
  AddByStatics(2, Theme.Sing.StaticP2RScoreBG, Theme.Sing.StaticP2RSingBar, Theme.Sing.TextP2RScore);
  AddByStatics(4, Theme.Sing.StaticP2MScoreBG, Theme.Sing.StaticP2MSingBar, Theme.Sing.TextP2MScore);

  // Player3:
  AddByStatics(4, Theme.Sing.StaticP3RScoreBG, Theme.Sing.StaticP3SingBar, Theme.Sing.TextP3RScore);
end;

{**
 * Spawns a new Line Bonus PopUp for the Player
 *}
Procedure TSingScores.SpawnPopUp(const PlayerIndex: Byte; const Rating: Byte; const Score: Word);
var Cur: PScorePopUp;
begin
  if (PlayerIndex < PlayerCount) then
  begin
    //Get Memory and Add Data
    GetMem(Cur, SizeOf(TScorePopUp));

    Cur.Player  := PlayerIndex;
    Cur.TimeStamp := SDL_GetTicks;

    //limit rating value to 8
    //a higher value would cause a crash when selecting the bg textur
    if (Rating > 8) then
      Cur.Rating := 8
    else
      Cur.Rating := Rating;

    Cur.ScoreGiven:= 0;
    If (Players[PlayerIndex].Score < Score) then
    begin
      Cur.ScoreDiff := Score - Players[PlayerIndex].Score;
      aPlayers[PlayerIndex].Score := Score;
    end
    else
      Cur.ScoreDiff := 0;
    Cur.Next := nil;

    //Log.LogError('TSingScores.SpawnPopUp| Player: ' + InttoStr(PlayerIndex) + ', Score: ' + InttoStr(Score) + ', ScoreDiff: ' + InttoStr(Cur.ScoreDiff));

    //Add it to the Chain
    if (FirstPopUp = nil) then
      //the first PopUp in the List
      FirstPopUp := Cur
    else
    //second or earlier popup
      LastPopUp.Next := Cur;

    //Set new Popup to Last PopUp in the List
    LastPopUp := Cur;
  end
  else
    Log.LogError('TSingScores: Try to add PopUp for not existing player');
end;

{**
 * Removes a PopUp w/o destroying the List
 *}
Procedure TSingScores.KillPopUp(const last, cur: PScorePopUp);
begin
  //Give Player the Last Points that missing till now
  aPlayers[Cur.Player].ScoreDisplayed := aPlayers[Cur.Player].ScoreDisplayed + Cur.ScoreDiff - Cur.ScoreGiven;

  //Change Bars Position
  if (Cur.ScoreDiff > 0) THEN
  begin //Popup w/ scorechange -> give missing Percentille
    aPlayers[Cur.Player].RBTarget := aPlayers[Cur.Player].RBTarget +
                                     (Cur.ScoreDiff - Cur.ScoreGiven) / Cur.ScoreDiff
                                     * (Cur.Rating / 20 - 0.26);
  end
  else
  begin //Popup w/o scorechange -> give complete Percentille
    aPlayers[Cur.Player].RBTarget := aPlayers[Cur.Player].RBTarget +
                                     (Cur.Rating / 20 - 0.26);
  end;

  If (aPlayers[Cur.Player].RBTarget > 1) then
    aPlayers[Cur.Player].RBTarget := 1
  else
  If (aPlayers[Cur.Player].RBTarget < 0) then
    aPlayers[Cur.Player].RBTarget := 0;

  //If this is the First PopUp => Make Next PopUp the First
  If (Cur = FirstPopUp) then
    FirstPopUp := Cur.Next
  //Else => Remove Curent Popup from Chain
  else
    Last.Next := Cur.Next;

  //If this is the Last PopUp, Make PopUp before the Last
  If (Cur = LastPopUp) then
    LastPopUp := Last;

  //Free the Memory
  FreeMem(Cur, SizeOf(TScorePopUp));
end;

{**
 * Removes all PopUps from Mem
 *}
Procedure TSingScores.KillAllPopUps;
var
  Cur:  PScorePopUp;
  Last: PScorePopUp;
begin
  Cur := FirstPopUp;

  //Remove all PopUps:
  While (Cur <> nil) do
  begin
    Last := Cur;
    Cur  := Cur.Next;
    FreeMem(Last, SizeOf(TScorePopUp));
  end;

  FirstPopUp := nil;
  LastPopUp := nil;
end;

{**
 * Has to be called after Positions and Players have been added, before first call of Draw
 * It gives every Player a Score Position
 *}
Procedure TSingScores.Init;
var
  PlC: Array [0..1] of Byte; //Playercount First Screen and Second Screen
  I, J: Integer;
  MaxPlayersperScreen: Byte;
  CurPlayer:           Byte;

  Function GetPositionCountbyPlayerCount(bPlayerCount: Byte): Byte;
  var I: Integer;
  begin
    Result := 0;
    bPlayerCount := 1 shl (bPlayerCount - 1);

    For I := 0 to PositionCount-1 do
    begin
      If ((aPositions[I].PlayerCount AND bPlayerCount) <> 0) then
        Inc(Result);
    end;
  end;

  Function GetPositionbyPlayernum(bPlayerCount, bPlayer: Byte): Byte;
  var I: Integer;
  begin
    bPlayerCount := 1 shl (bPlayerCount - 1);
    Result := High(Byte);

    For I := 0 to PositionCount-1 do
    begin
      If ((aPositions[I].PlayerCount AND bPlayerCount) <> 0) then
      begin
        If (bPlayer = 0) then
        begin
          Result := I;
          Break;
        end
        else
          Dec(bPlayer);
      end;
    end;
  end;

begin
  MaxPlayersPerScreen := 0;

  For I := 1 to 6 do
  begin
    //If there are enough Positions -> Write to MaxPlayers
    If (GetPositionCountbyPlayerCount(I) = I) then
      MaxPlayersPerScreen := I
    else
      Break;
  end;


  //Split Players to both Screen or Display on One Screen
  if (Screens = 2) and (MaxPlayersPerScreen < PlayerCount) then
  begin
    PlC[0] := PlayerCount div 2 + PlayerCount mod 2;
    PlC[1] := PlayerCount div 2;
  end
  else
  begin
    PlC[0] := PlayerCount;
    PlC[1] := 0;
  end;


  //Check if there are enough Positions for all Players
  For I := 0 to Screens - 1 do
  begin
    if (PlC[I] > MaxPlayersperScreen) then
    begin
      PlC[I] := MaxPlayersperScreen;
      Log.LogError('More Players than available Positions, TSingScores');
    end;
  end;
  
  CurPlayer := 0;
  //Give every Player a Position
  For I := 0 to Screens - 1 do
    For J := 0 to PlC[I]-1 do
    begin
      aPlayers[CurPlayer].Position := GetPositionbyPlayernum(PlC[I], J) OR (I shl 7);
      //Log.LogError('Player ' + InttoStr(CurPlayer) + ' gets Position: ' + InttoStr(aPlayers[CurPlayer].Position));
      Inc(CurPlayer);
    end;
end;

{**
 * Draws Scores and Linebonus PopUps
 *}
Procedure TSingScores.Draw;
var
  I: Integer;
  CurTime: Cardinal;
  CurPopUp, LastPopUp: PScorePopUp;
begin
  CurTime := SDL_GetTicks;

  If Visible then
  begin
    //Draw Popups
    LastPopUp := nil;
    CurPopUp  := FirstPopUp;

    While (CurPopUp <> nil) do
    begin
      if (CurTime - CurPopUp.TimeStamp > Settings.Phase1Time + Settings.Phase2Time + Settings.Phase3Time) then
      begin
        KillPopUp(LastPopUp, CurPopUp);
        if (LastPopUp = nil) then
          CurPopUp := FirstPopUp
        else
          CurPopUp  := LastPopUp.Next;
      end
      else
      begin
        DrawPopUp(CurPopUp);
        LastPopUp := CurPopUp;
        CurPopUp  := LastPopUp.Next;
      end;
    end;


    IF (RBVisible) then
      //Draw Players w/ Rating Bar
      For I := 0 to PlayerCount-1 do
      begin
        DrawScore(I);
        DrawRatingBar(I);
      end
    else
      //Draw Players w/o Rating Bar
      For I := 0 to PlayerCount-1 do
      begin
        DrawScore(I);
      end;

  end; //eo Visible
end;

{**
 * Draws a Popup by Pointer
 *}
Procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
var
  Progress: Real;
  CurTime:  Cardinal;
  X, Y, W, H, Alpha: Real;
  FontSize: integer;
  FontOffset: Real;
  TimeDiff: Cardinal;
  PIndex:   Byte;
  TextLen:  Real;
  ScoretoAdd: Word;
  PosDiff:  Real;
begin
  if (PopUp <> nil) then
  begin
    //Only Draw if Player has a Position
    PIndex := Players[PopUp.Player].Position;
    If PIndex <> high(byte) then
    begin
      //Only Draw if Player is on Cur Screen
      If ((Players[PopUp.Player].Position AND 128) = 0) = (ScreenAct = 1) then
      begin
        CurTime := SDL_GetTicks;
        If Not (Enabled AND Players[PopUp.Player].Enabled) then
        //Increase Timestamp with TIem where there is no Movement ...
        begin
          //Inc(PopUp.TimeStamp, LastRender);
        end;
        TimeDiff := CurTime - PopUp.TimeStamp;

        //Get Position of PopUp
        PIndex := PIndex AND 127;

    
        //Check for Phase ...
        If (TimeDiff <= Settings.Phase1Time) then
        begin
          //Phase 1 - The Ploping up
          Progress := TimeDiff / Settings.Phase1Time;


          W := aPositions[PIndex].PUW * Sin(Progress/2*Pi);
          H := aPositions[PIndex].PUH * Sin(Progress/2*Pi);

          X := aPositions[PIndex].PUStartX + (aPositions[PIndex].PUW - W)/2;
          Y := aPositions[PIndex].PUStartY + (aPositions[PIndex].PUH - H)/2;

          FontSize   := Round(Progress * aPositions[PIndex].PUFontSize);
          FontOffset := (H  - FontSize) / 2;
          Alpha := 1;
        end

        Else If (TimeDiff <= Settings.Phase2Time + Settings.Phase1Time) then
        begin
          //Phase 2 - The Moving
          Progress := (TimeDiff - Settings.Phase1Time) / Settings.Phase2Time;

          W := aPositions[PIndex].PUW;
          H := aPositions[PIndex].PUH;

          PosDiff := aPositions[PIndex].PUTargetX - aPositions[PIndex].PUStartX;
          If PosDiff > 0 then
            PosDiff := PosDiff + W;
          X := aPositions[PIndex].PUStartX + PosDiff * sqr(Progress);

          PosDiff := aPositions[PIndex].PUTargetY - aPositions[PIndex].PUStartY;
          If PosDiff < 0 then
            PosDiff := PosDiff + aPositions[PIndex].BGH;
          Y := aPositions[PIndex].PUStartY + PosDiff * sqr(Progress);

          FontSize   := aPositions[PIndex].PUFontSize;
          FontOffset := (H - FontSize) / 2;
          Alpha := 1 - 0.3 * Progress;
        end

        else
        begin
          //Phase 3 - The Fading out + Score adding
          Progress := (TimeDiff - Settings.Phase1Time - Settings.Phase2Time) / Settings.Phase3Time;

          If (PopUp.Rating > 0) then
          begin
            //Add Scores if Player Enabled
            If (Enabled AND Players[PopUp.Player].Enabled) then
            begin
              ScoreToAdd := Round(PopUp.ScoreDiff * Progress) - PopUp.ScoreGiven;
              Inc(PopUp.ScoreGiven, ScoreToAdd);
              aPlayers[PopUp.Player].ScoreDisplayed := Players[PopUp.Player].ScoreDisplayed + ScoreToAdd;

              //Change Bars Position
              aPlayers[PopUp.Player].RBTarget := aPlayers[PopUp.Player].RBTarget + ScoreToAdd/PopUp.ScoreDiff * (PopUp.Rating / 20 - 0.26);
              If (aPlayers[PopUp.Player].RBTarget > 1) then
                aPlayers[PopUp.Player].RBTarget := 1
              else If (aPlayers[PopUp.Player].RBTarget < 0) then
                aPlayers[PopUp.Player].RBTarget := 0;
            end;

            //Set Positions etc.
            Alpha    := 0.7 - 0.7 * Progress;

            W := aPositions[PIndex].PUW;
            H := aPositions[PIndex].PUH;

            PosDiff := aPositions[PIndex].PUTargetX - aPositions[PIndex].PUStartX;
            If (PosDiff > 0) then
              PosDiff := W
            else
              PosDiff := 0;
            X := aPositions[PIndex].PUTargetX + PosDiff * Progress;

            PosDiff := aPositions[PIndex].PUTargetY - aPositions[PIndex].PUStartY;
            If (PosDiff < 0) then
              PosDiff := -aPositions[PIndex].BGH
            else
              PosDiff := 0;
            Y := aPositions[PIndex].PUTargetY - PosDiff * (1-Progress);

            FontSize   := aPositions[PIndex].PUFontSize;
            FontOffset := (H - FontSize) / 2;
          end
          else
          begin
            //Here the Effect that Should be shown if a PopUp without Score is Drawn
            //And or Spawn with the GraphicObjects etc.
            //Some Work for Blindy to do :P

            //ATM: Just Let it Slide in the Scores just like the Normal PopUp
            Alpha := 0;
          end;
        end;

        //Draw PopUp

        if (Alpha > 0) AND (Players[PopUp.Player].Visible) then
        begin
          //Draw BG:
          glEnable(GL_TEXTURE_2D);
          glEnable(GL_BLEND);
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

          glColor4f(1,1,1, Alpha);
          glBindTexture(GL_TEXTURE_2D, Settings.PopUpTex[PopUp.Rating].TexNum);

          glBegin(GL_QUADS);
            glTexCoord2f(0, 0); glVertex2f(X, Y);
            glTexCoord2f(0, Settings.PopUpTex[PopUp.Rating].TexH); glVertex2f(X, Y + H);
            glTexCoord2f(Settings.PopUpTex[PopUp.Rating].TexW, Settings.PopUpTex[PopUp.Rating].TexH); glVertex2f(X + W, Y + H);
            glTexCoord2f(Settings.PopUpTex[PopUp.Rating].TexW, 0); glVertex2f(X + W, Y);
          glEnd;

          glDisable(GL_TEXTURE_2D);
          glDisable(GL_BLEND);

          //Set FontStyle and Size
          SetFontStyle(aPositions[PIndex].PUFont);
          SetFontItalic(False);
          SetFontSize(FontSize);

          //Draw Text
          TextLen := glTextWidth(Theme.Sing.LineBonusText[PopUp.Rating]);

          //Color and Pos
          SetFontPos (X + (W - TextLen) / 2, Y + FontOffset);
          glColor4f(1, 1, 1, Alpha);

          //Draw
          glPrint(Theme.Sing.LineBonusText[PopUp.Rating]);
        end; //eo Alpha check
      end; //eo Right Screen
    end; //eo Player has Position
  end
  else
    Log.LogError('TSingScores: Try to Draw a not existing PopUp');
end;

{**
 * Draws a Score by Playerindex
 *}
Procedure TSingScores.DrawScore(const Index: Integer);
var
  Position: PScorePosition;
  ScoreStr: String;
begin
  //Only Draw if Player has a Position
  If Players[Index].Position <> high(byte) then
  begin
    //Only Draw if Player is on Cur Screen
    If (((Players[Index].Position AND 128) = 0) = (ScreenAct = 1)) AND Players[Index].Visible then
    begin
      Position := @aPositions[Players[Index].Position and 127];

      //Draw ScoreBG
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      glColor4f(1,1,1, 1);
      glBindTexture(GL_TEXTURE_2D, Players[Index].ScoreBG.TexNum);

      glBegin(GL_QUADS);
        glTexCoord2f(0, 0); glVertex2f(Position.BGX, Position.BGY);
        glTexCoord2f(0, Players[Index].ScoreBG.TexH); glVertex2f(Position.BGX, Position.BGY + Position.BGH);
        glTexCoord2f(Players[Index].ScoreBG.TexW, Players[Index].ScoreBG.TexH); glVertex2f(Position.BGX + Position.BGW, Position.BGY + Position.BGH);
        glTexCoord2f(Players[Index].ScoreBG.TexW, 0); glVertex2f(Position.BGX + Position.BGW, Position.BGY);
      glEnd;

      glDisable(GL_TEXTURE_2D);
      glDisable(GL_BLEND);

      //Draw Score Text
      SetFontStyle(Position.TextFont);
      SetFontItalic(False);
      SetFontSize(Position.TextSize);
      SetFontPos(Position.TextX, Position.TextY);

      ScoreStr := InttoStr(Players[Index].ScoreDisplayed div 10) + '0';
      While (Length(ScoreStr) < 5) do
        ScoreStr := '0' + ScoreStr;

      glPrint(ScoreStr);

    end; //eo Right Screen
  end; //eo Player has Position
end;


Procedure TSingScores.DrawRatingBar(const Index: Integer);
var
  Position: PScorePosition;
  R,G,B, Size: Real;
  Diff: Real;
begin
  //Only Draw if Player has a Position
  if Players[Index].Position <> high(byte) then
  begin
    //Only Draw if Player is on Cur Screen
    if (((Players[Index].Position and 128) = 0) = (ScreenAct = 1) and
        Players[index].RBVisible and
        Players[index].Visible) then
    begin
      Position := @aPositions[Players[Index].Position and 127];

      if (Enabled AND Players[Index].Enabled) then
      begin
        //Move Position if Enabled
        Diff := Players[Index].RBTarget - Players[Index].RBPos;
        If(Abs(Diff) < 0.02) then
          aPlayers[Index].RBPos := aPlayers[Index].RBTarget
        else
          aPlayers[Index].RBPos := aPlayers[Index].RBPos + Diff*0.1;
      end;

      //Get Colors for RatingBar
      if (Players[index].RBPos <= 0.22) then
      begin
        R := 1;
        G := 0;
        B := 0;
      end
      else if (Players[index].RBPos <= 0.42) then
      begin
        R := 1;
        G := Players[index].RBPos*5;
        B := 0;
      end
      else if (Players[index].RBPos <= 0.57) then
      begin
        R := 1;
        G := 1;
        B := 0;
      end
      else if (Players[index].RBPos <= 0.77) then
      begin
        R := 1-(Players[index].RBPos-0.57)*5;
        G := 1;
        B := 0;
      end
      else
      begin
        R := 0;
        G := 1;
        B := 0;
      end;

      //Enable all glFuncs Needed
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      //Draw RatingBar BG
      glColor4f(1, 1, 1, 0.8);
      glBindTexture(GL_TEXTURE_2D, Settings.RatingBar_BG_Tex.TexNum);

      glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex2f(Position.RBX, Position.RBY);

        glTexCoord2f(0, Settings.RatingBar_BG_Tex.TexH);
        glVertex2f(Position.RBX, Position.RBY+Position.RBH);

        glTexCoord2f(Settings.RatingBar_BG_Tex.TexW, Settings.RatingBar_BG_Tex.TexH);
        glVertex2f(Position.RBX+Position.RBW, Position.RBY+Position.RBH);

        glTexCoord2f(Settings.RatingBar_BG_Tex.TexW, 0);
        glVertex2f(Position.RBX+Position.RBW, Position.RBY);
      glEnd;

      //Draw Rating bar itself
      Size := Position.RBX + Position.RBW * Players[Index].RBPos;
      glColor4f(R, G, B, 1);
      glBindTexture(GL_TEXTURE_2D, Settings.RatingBar_Bar_Tex.TexNum);
      glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex2f(Position.RBX, Position.RBY);

        glTexCoord2f(0, Settings.RatingBar_Bar_Tex.TexH);
        glVertex2f(Position.RBX, Position.RBY + Position.RBH);

        glTexCoord2f(Settings.RatingBar_Bar_Tex.TexW, Settings.RatingBar_Bar_Tex.TexH);
        glVertex2f(Size, Position.RBY + Position.RBH);

        glTexCoord2f(Settings.RatingBar_Bar_Tex.TexW, 0);
        glVertex2f(Size, Position.RBY);
      glEnd;

      //Draw Ratingbar FG (Teh thing with the 3 lines to get better readability)
      glColor4f(1, 1, 1, 0.6);
      glBindTexture(GL_TEXTURE_2D, Settings.RatingBar_FG_Tex.TexNum);
      glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex2f(Position.RBX, Position.RBY);

        glTexCoord2f(0, Settings.RatingBar_FG_Tex.TexH);
        glVertex2f(Position.RBX, Position.RBY + Position.RBH);

        glTexCoord2f(Settings.RatingBar_FG_Tex.TexW, Settings.RatingBar_FG_Tex.TexH);
        glVertex2f(Position.RBX + Position.RBW, Position.RBY + Position.RBH);

        glTexCoord2f(Settings.RatingBar_FG_Tex.TexW, 0);
        glVertex2f(Position.RBX + Position.RBW, Position.RBY);
      glEnd;

      //Disable all Enabled glFuncs
      glDisable(GL_TEXTURE_2D);
      glDisable(GL_BLEND);
    end; //eo Right Screen
  end; //eo Player has Position
end;

end.