aboutsummaryrefslogtreecommitdiffstats
path: root/src/base/USingScores.pas
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/USingScores.pas')
-rw-r--r--src/base/USingScores.pas1122
1 files changed, 1122 insertions, 0 deletions
diff --git a/src/base/USingScores.pas b/src/base/USingScores.pas
new file mode 100644
index 00000000..26c5dfe8
--- /dev/null
+++ b/src/base/USingScores.pas
@@ -0,0 +1,1122 @@
+{* 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 := ftOutline1;
+ 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;
+
+ 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;
+
+{**
+ * 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
+ Diff := Round(RoundTo((RaisePerSecond * TimePassed) / 1000, 1));
+
+ { minimal raise per frame = 1 }
+ if Abs(Diff) < 1 then
+ Diff := Sign(S);
+
+ if (Abs(Diff) < Abs(S)) then
+ Inc(aPlayers[Index].ScoreDisplayed, Diff)
+ else
+ Inc(aPlayers[Index].ScoreDisplayed, S);
+ 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.