{* 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
gl,
UThemes,
UTexture;
//////////////////////////////////////////////////////////////
// ATTENTION: //
// Enabled flag does not work atm. This should cause popups //
// not to move and scores to stay until re-enabling. //
// 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 tested 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; // the 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 - 1 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 line bonus popup
PUH: real; // height of the line bonus popup
PUFont: byte; // font for the popups
PUFontSize: integer; // font size for the popups
PUStartX: real; // x start position of the line bonus popup
PUStartY: real; // y start position of the line bonus popup
PUTargetX: real; // x target position of the line bonus popup
PUTargetY: real; // y target position of the line bonus popup
end;
aScorePosition = array [0..MaxPositions-1] of TScorePosition;
//-----------
// TScorePopUp - record containing information about a line bonus 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: integer; // 0 to 8, type of rating (cool, bad, etc.)
ScoreGiven: integer; // score that has already been given to the player
ScoreDiff: integer; // 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;
// only defined during draw, time passed between
// current and previous call of draw
TimePassed: Cardinal;
// draws a popup by pointer
procedure DrawPopUp(const PopUp: PScorePopUp);
// raises players score if RaiseScore was called
// has to be called after DrawPopUp and before
// DrawScore
procedure DoRaiseScore(const Index: integer);
// draws a score by playerindex
procedure DrawScore(const Index: integer);
// draws the rating bar by playerindex
procedure DrawRatingBar(const Index: integer);
// removes a popup w/o destroying the list
procedure KillPopUp(const last, cur: PScorePopUp);
// calculate the amount of points for a player that is
// still in popups and therfore not displayed
function GetPopUpPoints(const Index: integer): integer;
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
// properties 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;
// raises the score of a specified player to the specified score
procedure RaiseScore(Player: byte; Score: integer);
// sets the score of a specified player to the specified score
procedure SetScore(Player: byte; Score: integer);
// spawns a new line bonus popup for the player
procedure SpawnPopUp(const PlayerIndex: byte; const Rating: integer; const Score: integer);
// removes all popups from mem
procedure KillAllPopUps;
// draws scores and line bonus popups
procedure Draw;
end;
implementation
uses
SysUtils,
Math,
SDL,
TextGL,
ULog,
UGraphic;
{**
* 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;
TimePassed := 0;
end;
{**
* procedure deletes positions and playerinformation
*}
procedure TSingScores.Clear;
begin
KillAllPopUps;
oPlayerCount := 0;
oPositionCount := 0;
TimePassed := 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
// player 1:
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);
// player 2:
AddByStatics(2, Theme.Sing.StaticP2RScoreBG, Theme.Sing.StaticP2RSingBar, Theme.Sing.TextP2RScore);
AddByStatics(4, Theme.Sing.StaticP2MScoreBG, Theme.Sing.StaticP2MSingBar, Theme.Sing.TextP2MScore);
// player 3:
AddByStatics(4, Theme.Sing.StaticP3RScoreBG, Theme.Sing.StaticP3SingBar, Theme.Sing.TextP3RScore);
end;
{**
* raises the score of a specified player to the specified score
*}
procedure TSingScores.RaiseScore(Player: byte; Score: integer);
begin
if (Player <= PlayerCount - 1) then
aPlayers[Player].Score := Score;
end;
{**
* sets the score of a specified player to the specified score
*}
procedure TSingScores.SetScore(Player: byte; Score: integer);
var
Diff: Integer;
begin
if (Player <= PlayerCount - 1) then
begin
Diff := Score - Players[Player].Score;
aPlayers[Player].Score := Score;
Inc(aPlayers[Player].ScoreDisplayed, Diff);
end;
end;
{**
* spawns a new line bonus popup for the player
*}
procedure TSingScores.SpawnPopUp(const PlayerIndex: byte; const Rating: integer; const Score: integer);
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 0..8
// a higher value would cause a crash when selecting the bg texture
if (Rating > 8) then
Cur.Rating := 8
else if (Rating < 0) then
Cur.Rating := 0
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 non-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;
{**
* calculate the amount of points for a player that is
* still in popups and therfore not displayed
*}
function TSingScores.GetPopUpPoints(const Index: integer): integer;
var
CurPopUp: PScorePopUp;
begin
Result := 0;
// only check points if there is a difference between actual
// and displayed points
if (Players[Index].Score > Players[Index].ScoreDisplayed) then
begin
CurPopUp := FirstPopUp;
while (CurPopUp <> nil) do
begin
if (CurPopUp.Player = Index) then
begin // add points left "in" popup to result
Inc(Result, CurPopUp.ScoreDiff - CurPopUp.ScoreGiven);
end;
CurPopUp := CurPopUp.Next;
end;
end;
end;
{**
* has to be called after positions and players have been added, before first call of draw
* it gives each 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 screens 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 (TimePassed <> 0) then
TimePassed := CurTime - TimePassed;
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
DoRaiseScore(I);
DrawScore(I);
DrawRatingBar(I);
end
else
// draw players w/o rating bar
for I := 0 to PlayerCount-1 do
begin
DoRaiseScore(I);
DrawScore(I);
end;
end; // eo visible
TimePassed := CurTime;
end;
{**
* raises players score if RaiseScore was called
* has to be called after DrawPopUp and before
* DrawScore
*}
procedure TSingScores.DoRaiseScore(const Index: integer);
var
S: integer;
Diff: integer;
const
RaisePerSecond = 500;
begin
S := (Players[Index].Score - Players[Index].ScoreDisplayed) + GetPopUpPoints(Index);
if (S <> 0) then
begin
if (S > 0) then
Diff := Min(Round(RoundTo((RaisePerSecond * TimePassed) / 1000, 1)), S)
else
Diff := Max(Round(RoundTo((RaisePerSecond * TimePassed) / 1000, 1)), S);
Inc(aPlayers[Index].ScoreDisplayed, Diff);
end;
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 bar positions
if PopUp.ScoreDiff = 0 then
Log.LogError('TSingScores.DrawPopUp', 'PopUp.ScoreDiff is 0 and we want to divide by it. No idea how this happens.')
else
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 font style and size
SetFontStyle(aPositions[PIndex].PUFont);
SetFontItalic(false);
SetFontSize(FontSize);
SetFontReflection(false, 0);
// 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 non-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);
SetFontReflection(false, 0);
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: real;
Size, 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 rating bar
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 rating bar 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 rating bar fg (the 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.