diff options
Diffstat (limited to 'src/screens/UScreenSing.pas')
-rw-r--r-- | src/screens/UScreenSing.pas | 1001 |
1 files changed, 0 insertions, 1001 deletions
diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas deleted file mode 100644 index 0b7dfba4..00000000 --- a/src/screens/UScreenSing.pas +++ /dev/null @@ -1,1001 +0,0 @@ -{* 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 UScreenSing; - -interface - -{$IFDEF FPC} - {$MODE Delphi} -{$ENDIF} - -{$I switches.inc} - -uses - SysUtils, - SDL, - TextGL, - gl, - UFiles, - UGraphicClasses, - UIni, - ULog, - ULyrics, - UMenu, - UMusic, - USingScores, - USongs, - UTexture, - UThemes, - UPath, - UTime; - -type - TLyricsSyncSource = class(TInterfacedObject,ISyncSource) - function GetClock(): real; - end; - -type - TScreenSing = class(TMenu) - protected - VideoLoaded: boolean; - Paused: boolean; // pause mod - LyricsSync: TLyricsSyncSource; - NumEmptySentences: integer; - public - // timebar fields - StaticTimeProgress: integer; - TextTimeText: integer; - - StaticP1: integer; - TextP1: integer; - - // shown when game is in 2/4 player modus - StaticP1TwoP: integer; - TextP1TwoP: integer; - - // shown when game is in 3/6 player modus - StaticP1ThreeP: integer; - TextP1ThreeP: integer; - - StaticP2R: integer; - TextP2R: integer; - - StaticP2M: integer; - TextP2M: integer; - - StaticP3R: integer; - TextP3R: integer; - - StaticPausePopup: integer; - - Tex_Background: TTexture; - FadeOut: boolean; - Lyrics: TLyricEngine; - - // score manager: - Scores: TSingScores; - - //the song was sung to the end - SungToEnd: boolean; - - fShowVisualization: boolean; - fCurrentVideoPlaybackEngine: IVideoPlayback; - - constructor Create; override; - procedure OnShow; override; - procedure OnShowFinish; override; - procedure OnHide; override; - - function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; - PressedDown: boolean): boolean; override; - function Draw: boolean; override; - - procedure Finish; virtual; - procedure Pause; // toggle pause - - procedure OnSentenceEnd(SentenceIndex: cardinal); // for linebonus + singbar - procedure OnSentenceChange(SentenceIndex: cardinal); // for golden notes - end; - -implementation - -uses - Classes, - Math, - UDraw, - UGraphic, - ULanguage, - UNote, - URecord, - USong, - UDisplay, - UUnicodeUtils; - -// method for input parsing. if false is returned, getnextwindow -// should be checked to know the next window to load; - -function TScreenSing.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char; - PressedDown: boolean): boolean; -begin - Result := true; - if (PressedDown) then - begin // key down - // check normal keys - case UCS4UpperCase(CharCode) of - Ord('Q'): - begin - // when not ask before exit then finish now - if (Ini.AskbeforeDel <> 1) then - Finish - // else just pause and let the popup make the work - else if not Paused then - Pause; - - Result := false; - Exit; - end; - Ord('V'): // show visualization - begin - fShowVisualization := not fShowVisualization; - - if fShowVisualization then - fCurrentVideoPlaybackEngine := Visualization - else - fCurrentVideoPlaybackEngine := VideoPlayback; - - if fShowVisualization then - fCurrentVideoPlaybackEngine.play; - - Exit; - end; - Ord('P'): - begin - Pause; - Exit; - end; - end; - - // check special keys - case PressedKey of - SDLK_ESCAPE, - SDLK_BACKSPACE: - begin - // record sound hack: - //Sound[0].BufferLong - - Finish; - AudioPlayback.PlaySound(SoundLib.Back); - FadeTo(@ScreenScore); - end; - - SDLK_SPACE: - begin - Pause; - end; - - SDLK_TAB: // change visualization preset - begin - if fShowVisualization then - fCurrentVideoPlaybackEngine.Position := now; // move to a random position - end; - - SDLK_RETURN: - begin - end; - - // up and down could be done at the same time, - // but i don't want to declare variables inside - // functions like this one, called so many times - SDLK_DOWN: - begin - end; - SDLK_UP: - begin - end; - end; - end; -end; - -// pause mod -procedure TScreenSing.Pause; -var - VideoFile: IPath; -begin - if (not Paused) then // enable pause - begin - // pause time - Paused := true; - - LyricsState.Pause(); - - // pause music - AudioPlayback.Pause; - - // pause video - VideoFile := CurrentSong.Path.Append(CurrentSong.Video); - if (CurrentSong.Video.IsSet) and VideoFile.Exists then - fCurrentVideoPlaybackEngine.Pause; - - end - else // disable pause - begin - LyricsState.Resume(); - - // play music - AudioPlayback.Play; - - // video - VideoFile := CurrentSong.Path.Append(CurrentSong.Video); - if (CurrentSong.Video.IsSet) and VideoFile.Exists then - fCurrentVideoPlaybackEngine.Pause; - - Paused := false; - end; -end; -// pause mod end - -constructor TScreenSing.Create; -begin - inherited Create; - - //too dangerous, a mouse button is quickly pressed by accident - RightMbESC := false; - - fShowVisualization := false; - - fCurrentVideoPlaybackEngine := VideoPlayback; - - // create score class - Scores := TSingScores.Create; - Scores.LoadfromTheme; - - LoadFromTheme(Theme.Sing); - - // timebar - StaticTimeProgress := AddStatic(Theme.Sing.StaticTimeProgress); - TextTimeText := AddText(Theme.Sing.TextTimeText); - - // 1 player | P1 - StaticP1 := AddStatic(Theme.Sing.StaticP1); - TextP1 := AddText(Theme.Sing.TextP1); - - // 2 or 4 players | P1 - StaticP1TwoP := AddStatic(Theme.Sing.StaticP1TwoP); - TextP1TwoP := AddText(Theme.Sing.TextP1TwoP); - - // | P2 - StaticP2R := AddStatic(Theme.Sing.StaticP2R); - TextP2R := AddText(Theme.Sing.TextP2R); - - // 3 or 6 players | P1 - StaticP1ThreeP := AddStatic(Theme.Sing.StaticP1ThreeP); - TextP1ThreeP := AddText(Theme.Sing.TextP1ThreeP); - - // | P2 - StaticP2M := AddStatic(Theme.Sing.StaticP2M); - TextP2M := AddText(Theme.Sing.TextP2M); - - // | P3 - StaticP3R := AddStatic(Theme.Sing.StaticP3R); - TextP3R := AddText(Theme.Sing.TextP3R); - - StaticPausePopup := AddStatic(Theme.Sing.PausePopUp); - - // <note> pausepopup is not visibile at the beginning </note> - Static[StaticPausePopup].Visible := false; - - Lyrics := TLyricEngine.Create( - Theme.LyricBar.UpperX, Theme.LyricBar.UpperY, Theme.LyricBar.UpperW, Theme.LyricBar.UpperH, - Theme.LyricBar.LowerX, Theme.LyricBar.LowerY, Theme.LyricBar.LowerW, Theme.LyricBar.LowerH); - - LyricsSync := TLyricsSyncSource.Create(); -end; - -procedure TScreenSing.OnShow; -var - Index: integer; - V1: boolean; - V1TwoP: boolean; // position of score box in two player mode - V1ThreeP: boolean; // position of score box in three player mode - V2R: boolean; - V2M: boolean; - V3R: boolean; - Color: TRGB; - VideoFile, BgFile: IPath; - success: boolean; -begin - inherited; - - Log.LogStatus('Begin', 'OnShow'); - FadeOut := false; - - //the song was sung to the end - SungToEnd := false; - - // reset video playback engine, to play video clip ... - fCurrentVideoPlaybackEngine := VideoPlayback; - - // setup score manager - Scores.ClearPlayers; // clear old player values - Color.R := 0; - Color.G := 0; - Color.B := 0; // dummy atm <- \(O.o)/? B like bummy? - - // add new players - for Index := 0 to PlayersPlay - 1 do - begin - Scores.AddPlayer(Tex_ScoreBG[Index], Color); - end; - - Scores.Init; // get positions for players - - // prepare players - SetLength(Player, PlayersPlay); - - case PlayersPlay of - 1: - begin - V1 := true; - V1TwoP := false; - V1ThreeP := false; - V2R := false; - V2M := false; - V3R := false; - end; - 2: - begin - V1 := false; - V1TwoP := true; - V1ThreeP := false; - V2R := true; - V2M := false; - V3R := false; - end; - 3: - begin - V1 := false; - V1TwoP := false; - V1ThreeP := true; - V2R := false; - V2M := true; - V3R := true; - end; - 4: - begin // double screen - V1 := false; - V1TwoP := true; - V1ThreeP := false; - V2R := true; - V2M := false; - V3R := false; - end; - 6: - begin // double screen - V1 := false; - V1TwoP := false; - V1ThreeP := true; - V2R := false; - V2M := true; - V3R := true; - end; - - end; - - // this one is shown in 1P mode - Static[StaticP1].Visible := V1; - Text[TextP1].Visible := V1; - - // this one is shown in 2/4P mode - Static[StaticP1TwoP].Visible := V1TwoP; - Text[TextP1TwoP].Visible := V1TwoP; - - Static[StaticP2R].Visible := V2R; - Text[TextP2R].Visible := V2R; - - // this one is shown in 3/6P mode - Static[StaticP1ThreeP].Visible := V1ThreeP; - Text[TextP1ThreeP].Visible := V1ThreeP; - - Static[StaticP2M].Visible := V2M; - Text[TextP2M].Visible := V2M; - - Static[StaticP3R].Visible := V3R; - Text[TextP3R].Visible := V3R; - - // FIXME: sets path and filename to '' - ResetSingTemp; - - CurrentSong := CatSongs.Song[CatSongs.Selected]; - - // FIXME: bad style, put the try-except into loadsong() and not here - try - // check if file is xml - if CurrentSong.FileName.GetExtension.ToUTF8 = '.xml' then - success := CurrentSong.LoadXMLSong() - else - success := CurrentSong.LoadSong(); - except - success := false; - end; - - if (not success) then - begin - // error loading song -> go back to song screen and show some error message - FadeTo(@ScreenSong); - // select new song in party mode - if ScreenSong.Mode = smPartyMode then - ScreenSong.SelectRandomSong(); - if (Length(CurrentSong.LastError) > 0) then - ScreenPopupError.ShowPopup(Format(Language.Translate(CurrentSong.LastError), [CurrentSong.ErrorLineNo])) - else - ScreenPopupError.ShowPopup(Language.Translate('ERROR_CORRUPT_SONG')); - // FIXME: do we need this? - CurrentSong.Path := CatSongs.Song[CatSongs.Selected].Path; - Exit; - end; - - // reset video playback engine, to play video clip ... - fCurrentVideoPlaybackEngine.Close; - fCurrentVideoPlaybackEngine := VideoPlayback; - - {* - * == Background == - * We have four types of backgrounds: - * + Blank : Nothing has been set, this is our fallback - * + Picture : Picture has been set, and exists - otherwise we fallback - * + Video : Video has been set, and exists - otherwise we fallback - * + Visualization: + Off : No visualization - * + WhenNoVideo: Overwrites blank and picture - * + On : Overwrites blank, picture and video - *} - - {* - * set background to: video - *} - VideoLoaded := false; - fShowVisualization := false; - VideoFile := CurrentSong.Path.Append(CurrentSong.Video); - if (CurrentSong.Video.IsSet) and VideoFile.IsFile then - begin - if (fCurrentVideoPlaybackEngine.Open(VideoFile)) then - begin - fShowVisualization := false; - fCurrentVideoPlaybackEngine := VideoPlayback; - fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + CurrentSong.Start; - fCurrentVideoPlaybackEngine.Play; - VideoLoaded := true; - end; - end; - - {* - * set background to: picture - *} - if (CurrentSong.Background.IsSet) and (VideoLoaded = false) - and (TVisualizerOption(Ini.VisualizerOption) = voOff) then - begin - BgFile := CurrentSong.Path.Append(CurrentSong.Background); - try - Tex_Background := Texture.LoadTexture(BgFile); - except - Log.LogError('Background could not be loaded: ' + BgFile.ToNative); - Tex_Background.TexNum := 0; - end - end - else - begin - Tex_Background.TexNum := 0; - end; - - {* - * set background to: visualization (Overwrites all) - *} - if (TVisualizerOption(Ini.VisualizerOption) in [voOn]) then - begin - fShowVisualization := true; - fCurrentVideoPlaybackEngine := Visualization; - if (fCurrentVideoPlaybackEngine <> nil) then - fCurrentVideoPlaybackEngine.Play; - end; - - {* - * set background to: visualization (Videos are still shown) - *} - if ((TVisualizerOption(Ini.VisualizerOption) in [voWhenNoVideo]) and - (VideoLoaded = false)) then - begin - fShowVisualization := true; - fCurrentVideoPlaybackEngine := Visualization; - if (fCurrentVideoPlaybackEngine <> nil) then - fCurrentVideoPlaybackEngine.Play; - end; - - // prepare lyrics timer - LyricsState.Reset(); - LyricsState.SetCurrentTime(CurrentSong.Start); - LyricsState.StartTime := CurrentSong.Gap; - if (CurrentSong.Finish > 0) then - LyricsState.TotalTime := CurrentSong.Finish / 1000 - else - LyricsState.TotalTime := AudioPlayback.Length; - LyricsState.UpdateBeats(); - - // prepare music - AudioPlayback.Stop(); - AudioPlayback.Position := CurrentSong.Start; - // synchronize music to the lyrics - AudioPlayback.SetSyncSource(LyricsSync); - - // prepare and start voice-capture - AudioInput.CaptureStart; - - // clear the scores of all players - - for Index := 0 to High(Player) do - with Player[Index] do - begin - Score := 0; - ScoreLine := 0; - ScoreGolden := 0; - - ScoreInt := 0; - ScoreLineInt := 0; - ScoreGoldenInt := 0; - ScoreTotalInt := 0; - - ScoreLast := 0; - - LastSentencePerfect := false; - end; - - // main text - Lyrics.Clear(CurrentSong.BPM[0].BPM, CurrentSong.Resolution); - - // set custom options - case Ini.LyricsFont of - 0: // normal fonts - begin - Lyrics.FontStyle := 0; - - Lyrics.LineColor_en.R := Skin_FontR; - Lyrics.LineColor_en.G := Skin_FontG; - Lyrics.LineColor_en.B := Skin_FontB; - Lyrics.LineColor_en.A := 1; - - Lyrics.LineColor_dis.R := 0.4; - Lyrics.LineColor_dis.G := 0.4; - Lyrics.LineColor_dis.B := 0.4; - Lyrics.LineColor_dis.A := 1; - - Lyrics.LineColor_act.R := 0.02; - Lyrics.LineColor_act.G := 0.6; - Lyrics.LineColor_act.B := 0.8; - Lyrics.LineColor_act.A := 1; - end; - 1, 2: // outline fonts (is TScalableOutlineFont) - begin - Lyrics.FontStyle := Ini.LyricsFont + 1; - - Lyrics.LineColor_en.R := 0.75; - Lyrics.LineColor_en.G := 0.75; - Lyrics.LineColor_en.B := 1; - Lyrics.LineColor_en.A := 1; - - Lyrics.LineColor_dis.R := 0.8; - Lyrics.LineColor_dis.G := 0.8; - Lyrics.LineColor_dis.B := 0.8; - Lyrics.LineColor_dis.A := 1; - - Lyrics.LineColor_act.R := 0.5; - Lyrics.LineColor_act.G := 0.5; - Lyrics.LineColor_act.B := 1; - Lyrics.LineColor_act.A := 1; - end; - end; // case - - // initialize lyrics by filling its queue - while (not Lyrics.IsQueueFull) and - (Lyrics.LineCounter <= High(Lines[0].Line)) do - begin - Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); - end; - - // deactivate pause - Paused := false; - - // kill all stars not killed yet (goldenstarstwinkle mod) - GoldenRec.SentenceChange; - - // set position of line bonus - line bonus end - // set number of empty sentences for line bonus - NumEmptySentences := 0; - for Index := Low(Lines[0].Line) to High(Lines[0].Line) do - if Lines[0].Line[Index].TotalNotes = 0 then - Inc(NumEmptySentences); - - Log.LogStatus('End', 'OnShow'); -end; - -procedure TScreenSing.onShowFinish; -begin - // hide cursor on singscreen show - Display.SetCursor; - - // start lyrics - LyricsState.Resume(); - - // start music - AudioPlayback.Play(); - - // start timer - CountSkipTimeSet; -end; - -procedure TScreenSing.OnHide; -begin - // background texture - if (Tex_Background.TexNum > 0) then - begin - glDeleteTextures(1, PGLuint(@Tex_Background.TexNum)); - Tex_Background.TexNum := 0; - end; - - Background.OnFinish; - Display.SetCursor; -end; - -function TScreenSing.Draw: boolean; -var - Min: integer; - Sec: integer; - T: integer; - CurLyricsTime: real; - Line: TLyricLine; - LastWord: TLyricWord; -begin - Background.Draw; - - // draw background picture (if any, and if no visualizations) - // when we don't check for visualizations the visualizations would - // be overdrawn by the picture when {UNDEFINED UseTexture} in UVisualizer - if (not fShowVisualization) then - SingDrawBackground; - - // set player names (for 2 screens and only singstar skin) - if ScreenAct = 1 then - begin - Text[TextP1].Text := 'P1'; - Text[TextP1TwoP].Text := 'P1'; - Text[TextP1ThreeP].Text := 'P1'; - Text[TextP2R].Text := 'P2'; - Text[TextP2M].Text := 'P2'; - Text[TextP3R].Text := 'P3'; - end; - - if ScreenAct = 2 then - begin - case PlayersPlay of - 4: - begin - Text[TextP1TwoP].Text := 'P3'; - Text[TextP2R].Text := 'P4'; - end; - 6: - begin - Text[TextP1ThreeP].Text := 'P4'; - Text[TextP2M].Text := 'P5'; - Text[TextP3R].Text := 'P6'; - end; - end; // case - end; // if - - //// - // dual screen, part 1 - //////////////////////// - - // Note: ScreenX is the offset of the current screen in dual-screen mode so we - // will move the statics and texts to the correct screen here. - // FIXME: clean up this weird stuff. Commenting this stuff out, nothing - // was missing on screen w/ 6 players - so do we even need this stuff? - {Static[StaticP1].Texture.X := Static[StaticP1].Texture.X + 10 * ScreenX; - - Text[TextP1].X := Text[TextP1].X + 10 * ScreenX; } - - {Static[StaticP1ScoreBG].Texture.X := Static[StaticP1ScoreBG].Texture.X + 10*ScreenX; - Text[TextP1Score].X := Text[TextP1Score].X + 10*ScreenX;} - - {Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X + 10 * ScreenX; - - Text[TextP2R].X := Text[TextP2R].X + 10 * ScreenX; } - - {Static[StaticP2RScoreBG].Texture.X := Static[StaticP2RScoreBG].Texture.X + 10*ScreenX; - Text[TextP2RScore].X := Text[TextP2RScore].X + 10*ScreenX;} - - // end of weird stuff - { - Static[1].Texture.X := Static[1].Texture.X + 10 * ScreenX; } - - { for T := 0 to 1 do - Text[T].X := Text[T].X + 10 * ScreenX; } - - // retrieve current lyrics time, we have to store the value to avoid - // that min- and sec-values do not match - CurLyricsTime := LyricsState.GetCurrentTime(); - Min := Round(CurLyricsTime) div 60; - Sec := Round(CurLyricsTime) mod 60; - - // update static menu with time ... - Text[TextTimeText].Text := ''; - if Min < 10 then - Text[TextTimeText].Text := '0'; - Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Min) + ':'; - if Sec < 10 then - Text[TextTimeText].Text := Text[TextTimeText].Text + '0'; - Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Sec); - - // draw static menu (BG) - // Note: there is no menu and the animated background brakes the video playback - //DrawBG; - - //the song was sung to the end? - Line := Lyrics.GetUpperLine(); - if Line.LastLine then - begin - LastWord := Line.Words[Length(Line.Words)-1]; - if CurLyricsTime >= GetTimeFromBeat(LastWord.Start+LastWord.Length) then - SungToEnd := true; - end; - - // update and draw movie - if (ShowFinish and (VideoLoaded or fShowVisualization)) then - begin - if assigned(fCurrentVideoPlaybackEngine) then - begin - // Just call this once - // when Screens = 2 - if (ScreenAct = 1) then - fCurrentVideoPlaybackEngine.GetFrame(CurrentSong.VideoGAP + LyricsState.GetCurrentTime()); - - fCurrentVideoPlaybackEngine.DrawGL(ScreenAct); - end; - end; - - // draw static menu (FG) - DrawFG; - - // check for music finish - //Log.LogError('Check for music finish: ' + BoolToStr(Music.Finished) + ' ' + FloatToStr(LyricsState.CurrentTime*1000) + ' ' + IntToStr(CurrentSong.Finish)); - if ShowFinish then - begin - if (not AudioPlayback.Finished) and ((CurrentSong.Finish = 0) or - (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) then - begin - // analyze song if not paused - if (not Paused) then - Sing(Self); - end - else - begin - if (not FadeOut) then - begin - Finish; - FadeOut := true; - FadeTo(@ScreenScore); - end; - end; - end; - - // always draw custom items - SingDraw; - - // goldennotestarstwinkle - GoldenRec.SpawnRec; - - // draw scores - Scores.Draw; - - //// - // dual screen, part 2 - //////////////////////// - - // Note: ScreenX is the offset of the current screen in dual-screen mode so we - // will move the statics and texts to the correct screen here. - // FIXME: clean up this weird stuff - - {Static[StaticP1].Texture.X := Static[StaticP1].Texture.X - 10 * ScreenX; - Text[TextP1].X := Text[TextP1].X - 10 * ScreenX; - - Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X - 10 * ScreenX; - Text[TextP2R].X := Text[TextP2R].X - 10 * ScreenX; - - // end of weird - - Static[1].Texture.X := Static[1].Texture.X - 10 * ScreenX; - - for T := 0 to 1 do - Text[T].X := Text[T].X - 10 * ScreenX; } - - // draw pausepopup - // FIXME: this is a workaround that the static is drawn over the lyrics, lines, scores and effects - // maybe someone could find a better solution - if Paused then - begin - Static[StaticPausePopup].Visible := true; - Static[StaticPausePopup].Draw; - Static[StaticPausePopup].Visible := false; - end; - - Result := true; -end; - -procedure TScreenSing.Finish; -begin - AudioInput.CaptureStop; - AudioPlayback.Stop; - AudioPlayback.SetSyncSource(nil); - - if (VideoPlayback <> nil) then - VideoPlayback.Close; - - if (Visualization <> nil) then - Visualization.Close; - - // to prevent drawing closed video - VideoLoaded := false; - - // kill all stars and effects - GoldenRec.KillAll; - - if (Ini.SavePlayback = 1) then - begin - Log.BenchmarkStart(0); - Log.LogVoice(0); - Log.LogVoice(1); - Log.LogVoice(2); - Log.BenchmarkEnd(0); - Log.LogBenchmark('Creating files', 0); - end; - - SetFontItalic(false); -end; - -procedure TScreenSing.OnSentenceEnd(SentenceIndex: cardinal); -var - PlayerIndex: byte; - CurrentPlayer: PPLayer; - CurrentScore: real; - Line: PLine; - LinePerfection: real; // perfection of singing performance on the current line - Rating: integer; - LineScore: real; - LineBonus: real; - MaxSongScore: integer; // max. points for the song (without line bonus) - MaxLineScore: real; // max. points for the current line -const - // TODO: move this to a better place - MAX_LINE_RATING = 8; // max. rating for singing performance -begin - Line := @Lines[0].Line[SentenceIndex]; - - // check for empty sentence - if (Line.TotalNotes <= 0) then - Exit; - - // set max song score - if (Ini.LineBonus = 0) then - MaxSongScore := MAX_SONG_SCORE - else - MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS; - - // Note: ScoreValue is the sum of all note values of the song - MaxLineScore := MaxSongScore * (Line.TotalNotes / Lines[0].ScoreValue); - - for PlayerIndex := 0 to High(Player) do - begin - CurrentPlayer := @Player[PlayerIndex]; - CurrentScore := CurrentPlayer.Score + CurrentPlayer.ScoreGolden; - - // line bonus - - // points for this line - LineScore := CurrentScore - CurrentPlayer.ScoreLast; - - // check for lines with low points - if (MaxLineScore <= 2) then - LinePerfection := 1 - else - // determine LinePerfection - // Note: the "+2" extra points are a little bonus so the player does not - // have to be that perfect to reach the bonus steps. - LinePerfection := LineScore / (MaxLineScore - 2); - - // clamp LinePerfection to range [0..1] - if (LinePerfection < 0) then - LinePerfection := 0 - else if (LinePerfection > 1) then - LinePerfection := 1; - - // add line-bonus if enabled - if (Ini.LineBonus > 0) then - begin - // line-bonus points (same for each line, no matter how long the line is) - LineBonus := MAX_SONG_LINE_BONUS / (Length(Lines[0].Line) - - NumEmptySentences); - // apply line-bonus - CurrentPlayer.ScoreLine := - CurrentPlayer.ScoreLine + LineBonus * LinePerfection; - CurrentPlayer.ScoreLineInt := Floor(CurrentPlayer.ScoreLine / 10) * 10; - // update total score - CurrentPlayer.ScoreTotalInt := - CurrentPlayer.ScoreInt + - CurrentPlayer.ScoreGoldenInt - + CurrentPlayer.ScoreLineInt; - - // spawn rating pop-up - Rating := Round(LinePerfection * MAX_LINE_RATING); - Scores.SpawnPopUp(PlayerIndex, Rating, CurrentPlayer.ScoreTotalInt); - end - else - Scores.RaiseScore(PlayerIndex, CurrentPlayer.ScoreTotalInt); - - // PerfectLineTwinkle (effect), part 1 - if (Ini.EffectSing = 1) then - CurrentPlayer.LastSentencePerfect := (LinePerfection >= 1); - - // refresh last score - CurrentPlayer.ScoreLast := CurrentScore; - end; - - // PerfectLineTwinkle (effect), part 2 - if (Ini.EffectSing = 1) then - GoldenRec.SpawnPerfectLineTwinkle; -end; - - // Called on sentence change - // SentenceIndex: index of the new active sentence -procedure TScreenSing.OnSentenceChange(SentenceIndex: cardinal); -begin - // goldenstarstwinkle - GoldenRec.SentenceChange; - - // fill lyrics queue and set upper line to the current sentence - while (Lyrics.GetUpperLineIndex() < SentenceIndex) or - (not Lyrics.IsQueueFull) do - begin - // add the next line to the queue or a dummy if no more lines are available - if (Lyrics.LineCounter <= High(Lines[0].Line)) then - Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]) - else - Lyrics.AddLine(nil); - end; -end; - -function TLyricsSyncSource.GetClock(): real; -begin - Result := LyricsState.GetCurrentTime(); -end; - -end. - |