aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Game/Code/Classes/UDataBase.pas147
-rw-r--r--Game/Code/Screens/UScreenStatDetail.pas81
-rw-r--r--Game/Code/Screens/UScreenStatMain.pas177
3 files changed, 234 insertions, 171 deletions
diff --git a/Game/Code/Classes/UDataBase.pas b/Game/Code/Classes/UDataBase.pas
index 070a3c38..ff97b739 100644
--- a/Game/Code/Classes/UDataBase.pas
+++ b/Game/Code/Classes/UDataBase.pas
@@ -10,6 +10,7 @@ interface
uses USongs,
USong,
+ Classes,
SQLiteTable3;
//--------------------
@@ -23,52 +24,44 @@ type
stMostPopBand // Most popular Band
);
- TStatResult = record
- case Typ: TStatType of
- stBestScores: (
- Singer: ShortString;
- Score: Word;
- Difficulty: Byte;
- SongArtist: ShortString;
- SongTitle: ShortString
- );
- stBestSingers: (
- Player: ShortString;
- AverageScore: Word
- );
- stMostSungSong: (
- Artist: ShortString;
- Title: ShortString;
- TimesSung: Word
- );
- stMostPopBand: (
- ArtistName: ShortString;
- TimesSungTot: Word
- );
+ // abstract super-class for statistic results
+ TStatResult = class
+ public
+ Typ: TStatType;
end;
- AStatResult = array of TStatResult;
-(*
- 0: (Singer: WideString;
- Score: Word;
- Difficulty: Byte;
- SongArtist: WideString;
- SongTitle: WideString);
+ TStatResultBestScores = class(TStatResult)
+ public
+ Singer: WideString;
+ Score: Word;
+ Difficulty: Byte;
+ SongArtist: WideString;
+ SongTitle: WideString;
+ end;
- 1: (Player: WideString;
- AverageScore: Word);
+ TStatResultBestSingers = class(TStatResult)
+ public
+ Player: WideString;
+ AverageScore: Word;
+ end;
- 2: (Artist: WideString;
- Title: WideString;
- TimesSung: Word);
+ TStatResultMostSungSong = class(TStatResult)
+ public
+ Artist: WideString;
+ Title: WideString;
+ TimesSung: Word;
+ end;
- 3: (ArtistName: WideString;
- TimesSungTot: Word);
-*)
+ TStatResultMostPopBand = class(TStatResult)
+ public
+ ArtistName: WideString;
+ TimesSungTot: Word;
+ end;
+
TDataBaseSystem = class
private
- ScoreDB: TSqliteDatabase;
+ ScoreDB: TSQLiteDatabase;
fFilename: string;
function GetVersion(): integer;
@@ -83,7 +76,8 @@ type
procedure AddScore(Song: TSong; Level: integer; const Name: WideString; Score: integer);
procedure WriteScore(Song: TSong);
- function GetStats(var Stats: AStatResult; Typ: TStatType; Count: Byte; Page: Cardinal; Reversed: Boolean): Boolean;
+ function GetStats(Typ: TStatType; Count: Byte; Page: Cardinal; Reversed: Boolean): TList;
+ procedure FreeStats(StatList: TList);
function GetTotalEntrys(Typ: TStatType): Cardinal;
function GetStatReset: TDateTime;
end;
@@ -352,21 +346,21 @@ end;
(**
* Writes some stats to array.
- * Returns true if choosen page has entrys
+ * Returns nil if the database is not ready or a list with zero or more statistic
+ * entries.
+ * Free the result-list with FreeStats() after usage to avoid memory leaks.
*)
-function TDataBaseSystem.GetStats(var Stats: AStatResult; Typ: TStatType; Count: Byte; Page: Cardinal; Reversed: Boolean): Boolean;
+function TDataBaseSystem.GetStats(Typ: TStatType; Count: Byte; Page: Cardinal; Reversed: Boolean): TList;
var
Query: String;
TableData: TSQLiteUniTable;
+ Stat: TStatResult;
begin
- Result := False;
+ Result := nil;
if not Assigned(ScoreDB) then
Exit;
- if (Length(Stats) < Count) then
- Exit;
-
{Todo: Add Prevention that only players with more than 5 scores are selected at type 2}
// Create query
@@ -406,45 +400,68 @@ begin
end;
end;
- if (TableData.EOF) then
- begin
- TableData.Free;
- Exit;
- end;
+ Result := TList.Create;
// Copy result to stats array
while not TableData.EOF do
begin
- Stats[TableData.Row].Typ := Typ;
-
case Typ of
stBestScores: begin
- Stats[TableData.Row].Singer := UTF8Decode(TableData.Fields[0]);
- Stats[TableData.Row].Difficulty := TableData.FieldAsInteger(1);
- Stats[TableData.Row].Score := TableData.FieldAsInteger(2);
- Stats[TableData.Row].SongArtist := UTF8Decode(TableData.Fields[3]);
- Stats[TableData.Row].SongTitle := UTF8Decode(TableData.Fields[4]);
+ Stat := TStatResultBestScores.Create;
+ with TStatResultBestScores(Stat) do
+ begin
+ Singer := UTF8Decode(TableData.Fields[0]);
+ Difficulty := TableData.FieldAsInteger(1);
+ Score := TableData.FieldAsInteger(2);
+ SongArtist := UTF8Decode(TableData.Fields[3]);
+ SongTitle := UTF8Decode(TableData.Fields[4]);
+ end;
end;
stBestSingers: begin
- Stats[TableData.Row].Player := UTF8Decode(TableData.Fields[0]);
- Stats[TableData.Row].AverageScore := TableData.FieldAsInteger(1);
+ Stat := TStatResultBestSingers.Create;
+ with TStatResultBestSingers(Stat) do
+ begin
+ Player := UTF8Decode(TableData.Fields[0]);
+ AverageScore := TableData.FieldAsInteger(1);
+ end;
end;
stMostSungSong: begin
- Stats[TableData.Row].Artist := UTF8Decode(TableData.Fields[0]);
- Stats[TableData.Row].Title := UTF8Decode(TableData.Fields[1]);
- Stats[TableData.Row].TimesSung := TableData.FieldAsInteger(2);
+ Stat := TStatResultMostSungSong.Create;
+ with TStatResultMostSungSong(Stat) do
+ begin
+ Artist := UTF8Decode(TableData.Fields[0]);
+ Title := UTF8Decode(TableData.Fields[1]);
+ TimesSung := TableData.FieldAsInteger(2);
+ end;
end;
stMostPopBand: begin
- Stats[TableData.Row].ArtistName := UTF8Decode(TableData.Fields[0]);
- Stats[TableData.Row].TimesSungTot := TableData.FieldAsInteger(1);
+ Stat := TStatResultMostPopBand.Create;
+ with TStatResultMostPopBand(Stat) do
+ begin
+ ArtistName := UTF8Decode(TableData.Fields[0]);
+ TimesSungTot := TableData.FieldAsInteger(1);
+ end;
end;
end;
+ Stat.Typ := Typ;
+ Result.Add(Stat);
+
TableData.Next;
end;
TableData.Free;
- Result := True;
+end;
+
+procedure TDataBaseSystem.FreeStats(StatList: TList);
+var
+ I: integer;
+begin
+ if (StatList = nil) then
+ Exit;
+ for I := 0 to StatList.Count-1 do
+ TStatResult(StatList[I]).Free;
+ StatList.Free;
end;
(**
diff --git a/Game/Code/Screens/UScreenStatDetail.pas b/Game/Code/Screens/UScreenStatDetail.pas
index be98e047..891b108d 100644
--- a/Game/Code/Screens/UScreenStatDetail.pas
+++ b/Game/Code/Screens/UScreenStatDetail.pas
@@ -40,7 +40,8 @@ implementation
uses
UGraphic,
ULanguage,
- math,
+ Math,
+ Classes,
ULog;
function TScreenStatDetail.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean;
@@ -171,61 +172,65 @@ end;
procedure TScreenStatDetail.SetPage(NewPage: Cardinal);
var
- Result: AStatResult;
+ StatList: TList;
I: Integer;
FormatStr: String;
PerPage: Byte;
begin
- SetLength(Result, Count);
- if (Database.GetStats(Result, Typ, Count, NewPage, Reversed)) then
+ // fetch statistics
+ StatList := Database.GetStats(Typ, Count, NewPage, Reversed);
+ if ((StatList <> nil) and (StatList.Count > 0)) then
begin
Page := NewPage;
+ // reset texts
+ for I := 0 to Count-1 do
+ Text[I].Text := '';
+
FormatStr := Theme.StatDetail.FormatStr[Ord(Typ)];
//refresh Texts
- for I := 0 to Count-1 do
+ for I := 0 to StatList.Count-1 do
begin
try
case Typ of
stBestScores: begin //Best Scores
- //Set Texts
- if (Result[I].Score > 0) then
- Text[I].Text := Format(FormatStr, [Result[I].Singer,
- Result[I].Score,
- Theme.ILevel[Result[I].Difficulty],
- Result[I].SongArtist,
- Result[I].SongTitle])
- else
- Text[I].Text := '';
+ with TStatResultBestScores(StatList[I]) do
+ begin
+ //Set Texts
+ if (Score > 0) then
+ begin
+ Text[I].Text := Format(FormatStr,
+ [Singer, Score, Theme.ILevel[Difficulty], SongArtist, SongTitle]);
+ end;
+ end;
end;
stBestSingers: begin //Best Singers
- //Set Texts
- if (Result[I].AverageScore > 0) then
- Text[I].Text := Format(FormatStr, [Result[I].Player,
- Result[I].AverageScore])
- else
- Text[I].Text := '';
+ with TStatResultBestSingers(StatList[I]) do
+ begin
+ //Set Texts
+ if (AverageScore > 0) then
+ Text[I].Text := Format(FormatStr, [Player, AverageScore]);
+ end;
end;
stMostSungSong: begin //Popular Songs
- //Set Texts
- if (Result[I].Artist <> '') then
- Text[I].Text := Format(FormatStr, [Result[I].Artist,
- Result[I].Title,
- Result[I].TimesSung])
- else
- Text[I].Text := '';
+ with TStatResultMostSungSong(StatList[I]) do
+ begin
+ //Set Texts
+ if (Artist <> '') then
+ Text[I].Text := Format(FormatStr, [Artist, Title, TimesSung]);
+ end;
end;
stMostPopBand: begin //Popular Bands
- //Set Texts
- if (Result[I].ArtistName <> '') then
- Text[I].Text := Format(FormatStr, [Result[I].ArtistName,
- Result[I].TimesSungtot])
- else
- Text[I].Text := '';
+ with TStatResultMostPopBand(StatList[I]) do
+ begin
+ //Set Texts
+ if (ArtistName <> '') then
+ Text[I].Text := Format(FormatStr, [ArtistName, TimesSungtot]);
+ end;
end;
end;
except
@@ -239,13 +244,19 @@ begin
else
PerPage := Count;
- Text[Count+1].Text := Format(Theme.StatDetail.PageStr,
- [Page + 1, TotPages, PerPage, TotEntrys]);
+ try
+ Text[Count+1].Text := Format(Theme.StatDetail.PageStr,
+ [Page + 1, TotPages, PerPage, TotEntrys]);
+ except
+ on E: EConvertError do
+ Log.LogError('Error Parsing FormatString in UScreenStatDetail: ' + E.Message);
+ end;
//Show correct Title
SetTitle;
end;
+ Database.FreeStats(StatList);
end;
diff --git a/Game/Code/Screens/UScreenStatMain.pas b/Game/Code/Screens/UScreenStatMain.pas
index 9e581a82..bec9d312 100644
--- a/Game/Code/Screens/UScreenStatMain.pas
+++ b/Game/Code/Screens/UScreenStatMain.pas
@@ -21,7 +21,10 @@ type
TScreenStatMain = class(TMenu)
private
//Some Stat Value that don't need to be calculated 2 times
- SongswithVid: Cardinal;
+ SongsWithVid: Cardinal;
+ function FormatOverviewIntro(FormatStr: string): string;
+ function FormatSongOverview(FormatStr: string): string;
+ function FormatPlayerOverview(FormatStr: string): string;
public
TextOverview: integer;
constructor Create; override;
@@ -40,6 +43,7 @@ uses UGraphic,
USong,
ULanguage,
UCommon,
+ Classes,
{$IFDEF win32}
windows,
{$ELSE}
@@ -138,10 +142,10 @@ begin
Interaction := 0;
//Set Songs with Vid
- SongswithVid := 0;
+ SongsWithVid := 0;
For I := 0 to Songs.SongList.Count -1 do
if (TSong(Songs.SongList[I]).Video <> '') then
- Inc(SongswithVid);
+ Inc(SongsWithVid);
end;
procedure TScreenStatMain.onShow;
@@ -152,106 +156,137 @@ begin
SetOverview;
end;
-procedure TScreenStatMain.SetOverview;
-type
- TwSystemTime = record
- wYear,
- wMonth,
- wDayOfWeek,
- wDay,
- wHour,
- wMinute,
- wSecond,
- wMilliseconds: Word;
- end;
+function TScreenStatMain.FormatOverviewIntro(FormatStr: string): string;
var
- Overview, Formatstr: String;
- I: Integer;
- //Some Vars to Save Attributes to
- A1, A2, A3: Integer;
- A4, A5: String;
- Result1, Result2: AStatResult;
- ResetTime: TSystemTime;
-
+ Year, Month, Day: Word;
begin
- //Song Overview
-
- //Introduction
- Formatstr := Language.Translate ('STAT_OVERVIEW_INTRO');
- (*Format:
+ {Format:
%0:d Ultrastar Version
- %1:d Day of Reset (A1)
- %2:d Month of Reset (A2)
- %3:d Year of Reset (A3)*)
-
- DateTimeToSystemTime(Database.GetStatReset, ResetTime);
-// ResetTime := GetFileCreation(Database.Filename);
-
- {$IFDEF MSWINDOWS}
- A1 := ResetTime.wDay;
- A2 := ResetTime.wMonth;
- A3 := ResetTime.wYear;
- {$ELSE}
- A1 := ResetTime.Day;
- A2 := ResetTime.Month;
- A3 := ResetTime.Year;
- {$ENDIF}
-
-
+ %1:d Day of Reset
+ %2:d Month of Reset
+ %3:d Year of Reset}
+
+ Result := '';
+
try
- Overview := Format(Formatstr, [Language.Translate('US_VERSION'), A1, A2, A3]);
+ DecodeDate(Database.GetStatReset(), Year, Month, Day);
+ Result := Format(FormatStr, [Language.Translate('US_VERSION'), Day, Month, Year]);
except
on E: EConvertError do
Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_INTRO": ' + E.Message);
end;
+end;
- Formatstr := Language.Translate ('STAT_OVERVIEW_SONG');
+function TScreenStatMain.FormatSongOverview(FormatStr: string): string;
+var
+ CntSongs, CntSungSongs, CntVidSongs: Integer;
+ MostPopSongArtist, MostPopSongTitle: String;
+ StatList: TList;
+ MostSungSong: TStatResultMostSungSong;
+begin
{Format:
- %0:d Count Songs (A1)
- %1:d Count of Sung Songs (A2)
+ %0:d Count Songs
+ %1:d Count of Sung Songs
%2:d Count of UnSung Songs
- %3:d Count of Songs with Video (A3)
+ %3:d Count of Songs with Video
%4:s Name of the most popular Song}
- A1 := Songs.SongList.Count;
- A2 := Database.GetTotalEntrys(stMostSungSong);
- A3 := SongswithVid;
-
- SetLength(Result1, 1);
- Database.GetStats(Result1, stMostSungSong, 1, 0, False);
- A4 := Result1[0].Artist;
- A5 := Result1[0].Title;
+ CntSongs := Songs.SongList.Count;
+ CntSungSongs := Database.GetTotalEntrys(stMostSungSong);
+ CntVidSongs := SongsWithVid;
+
+ StatList := Database.GetStats(stMostSungSong, 1, 0, False);
+ if ((StatList <> nil) and (StatList.Count > 0)) then
+ begin
+ MostSungSong := StatList[0];
+ MostPopSongArtist := MostSungSong.Artist;
+ MostPopSongTitle := MostSungSong.Title;
+ end
+ else
+ begin
+ MostPopSongArtist := '-';
+ MostPopSongTitle := '-';
+ end;
+ Database.FreeStats(StatList);
+ Result := '';
+
try
- Overview := Overview + '\n \n' + Format(Formatstr, [A1, A2, A1-A2, A3, A4, A5]);
+ Result := Format(FormatStr, [
+ CntSongs, CntSungSongs, CntSongs-CntSungSongs, CntVidSongs,
+ MostPopSongArtist, MostPopSongTitle]);
except
on E: EConvertError do
Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_SONG": ' + E.Message);
end;
+end;
- //Player Overview
- Formatstr := Language.Translate ('STAT_OVERVIEW_PLAYER');
+function TScreenStatMain.FormatPlayerOverview(FormatStr: string): string;
+var
+ CntPlayers: Integer;
+ BestScoreStat: TStatResultBestScores;
+ BestSingerStat: TStatResultBestSingers;
+ BestPlayer, BestScorePlayer: String;
+ BestPlayerScore, BestScore: Integer;
+ SingerStats, ScoreStats: TList;
+begin
{Format:
- %0:d Count Players (A1)
- %1:s Best Player (Result)
+ %0:d Count Players
+ %1:s Best Player
%2:d Best Players Score
- %3:s Best Score Player (Result2)
+ %3:s Best Score Player
%4:d Best Score}
- A1 := Database.GetTotalEntrys(stBestSingers);
- SetLength(Result1, 1);
- Database.GetStats(Result1, stBestSingers, 1, 0, False);
+ CntPlayers := Database.GetTotalEntrys(stBestSingers);
+
+ SingerStats := Database.GetStats(stBestSingers, 1, 0, False);
+ if ((SingerStats <> nil) and (SingerStats.Count > 0)) then
+ begin
+ BestSingerStat := SingerStats[0];
+ BestPlayer := BestSingerStat.Player;
+ BestPlayerScore := BestSingerStat.AverageScore;
+ end
+ else
+ begin
+ BestPlayer := '-';
+ BestPlayerScore := 0;
+ end;
+ Database.FreeStats(SingerStats);
+
+ ScoreStats := Database.GetStats(stBestScores, 1, 0, False);
+ if ((ScoreStats <> nil) and (ScoreStats.Count > 0)) then
+ begin
+ BestScoreStat := ScoreStats[0];
+ BestScorePlayer := BestScoreStat.Singer;
+ BestScore := BestScoreStat.Score;
+ end
+ else
+ begin
+ BestScorePlayer := '-';
+ BestScore := 0;
+ end;
+ Database.FreeStats(ScoreStats);
- SetLength(Result2, 1);
- Database.GetStats(Result2, stBestScores, 1, 0, False);
+ Result := '';
try
- Overview := Overview + '\n \n' + Format(Formatstr, [A1, Result1[0].Player, Result1[0].AverageScore, Result2[0].Singer, Result2[0].Score]);
+ Result := Format(Formatstr, [
+ CntPlayers, BestPlayer, BestPlayerScore,
+ BestScorePlayer, BestScore]);
except
on E: EConvertError do
Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_PLAYER": ' + E.Message);
end;
+end;
+procedure TScreenStatMain.SetOverview;
+var
+ Overview: String;
+begin
+ // Format overview
+ Overview := FormatOverviewIntro(Language.Translate('STAT_OVERVIEW_INTRO')) + '\n \n' +
+ FormatSongOverview(Language.Translate('STAT_OVERVIEW_SONG')) + '\n \n' +
+ FormatPlayerOverview(Language.Translate('STAT_OVERVIEW_PLAYER'));
Text[0].Text := Overview;
end;