diff options
-rw-r--r-- | Game/Code/Classes/UDataBase.pas | 147 | ||||
-rw-r--r-- | Game/Code/Screens/UScreenStatDetail.pas | 81 | ||||
-rw-r--r-- | Game/Code/Screens/UScreenStatMain.pas | 177 |
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; |