unit UMain;
interface
uses SDL, UGraphic, UMusic, URecord, UTime, SysUtils, UDisplay, UIni, ULog, ULyrics, UScreenSing,
gl, zlportio {you can disable it and all PortWriteB calls}, UThemes{, UScreenPopup};
type
TPlayer = record
Name: string;
VoiceFile: string; //Recorded Voice
Score: real;
ScoreLine: real;
ScoreGolden: real;
ScoreI: integer;
ScoreLineI: integer;
ScoreGoldenI: integer;
ScoreTotalI: integer;
//SingBar Mod
ScoreLast: Real;//Last Line Score
ScorePercent: integer;//Aktual Fillstate of the SingBar
ScorePercentTarget: integer;//Target Fillstate of the SingBar
//end Singbar Mod
ScoreMax: integer; //max possible score (actual)
//PhrasenBonus - Line Bonus Mod
LineBonus_PosX: Single;
LineBonus_PosY: Single;
LineBonus_Alpha: Single;
LineBonus_Visible: boolean;
LineBonus_Text: string;
LineBonus_Color: TRGB;
LineBonus_Age: Integer;
//Variable vor Positioning -> Set on ScreenShow, different when Playercount Changes
LineBonus_TargetX: integer;
LineBonus_TargetY: integer;
LineBonus_StartX: integer;
LineBonus_StartY: integer;
//PhrasenBonus - Line Bonus Mod End
//PerfectLineTwinkle Mod (effect)
LastSentencePerfect: Boolean;
//PerfectLineTwinkle Mod end
// Meter: real;
HighNut: integer;
IlNut: integer;
Nuta: array of record
Start: integer;
Dlugosc: integer;
Detekt: real; // dokladne miejsce, w ktorym wykryto ta nute
Ton: real;
Perfect: boolean; // true if the note matches the original one, lit the star
// Half size Notes Patch
Hit: boolean; // true if the note Hits the Line
//end Half size Notes Patch
end;
end;
TStats = record
Player: array of TPlayer;
SongArtist: String;
SongTitle: String;
end;
TMedleyPlaylist = record
Song: array of integer;
NumMedleySongs: integer;
CurrentMedleySong: integer;
ApplausePlayed: boolean;
Stats: array of TStats;
NumPlayer: integer;
end;
var
OGL: Boolean;
Done: Boolean;
Event: TSDL_event;
FileName: string;
Restart: boolean;
// gracz i jego nuty
Player: array of TPlayer;
PlayersPlay: integer;
PlaylistMedley: TMedleyPlaylist;
procedure MainLoop;
procedure CheckEvents;
procedure Sing(Sender: TScreenSing);
procedure NewSentence(CP: integer; Sender: TScreenSing);
procedure NewBeat(CP: integer; Sender: TScreenSing); // executed when on then new beat
procedure NewBeatC(CP: integer; Sender: TScreenSing); // executed when on then new beat for click
procedure NewBeatD(CP: integer; Sender: TScreenSing); // executed when on then new beat for detection
//procedure NewHalf; // executed when in the half between beats
procedure NewNote(P: integer; Sender: TScreenSing); // detect note
function GetMidBeat(Time: real): real;
function GetTimeFromBeat(Beat: integer): real;
procedure ClearScores(PlayerNum: integer);
implementation
uses USongs, Math, UCommandLine, UVideo, UWebCam;
procedure MainLoop;
var
Delay: integer;
begin
SDL_EnableKeyRepeat(125, 125);
While not Done do
Begin
PerfLog.CycleStart;
// keyboard events
CheckEvents;
// display
done := not Display.Draw;
SwapBuffers;
// delay
CountMidTime;
Delay := Floor(1000 / 100 - 1000 * TimeMid);
if Delay >= 1 then
SDL_Delay(Delay);
CountSkipTime;
// reinitialization of graphics
if Restart then begin
Reinitialize3D;
Restart := false;
end;
PerfLog.CycleEnd;
End;
wClose;
acClose;
FreeOpenGL;
End;
Procedure CheckEvents;
Begin
if not Assigned(Display.NextScreen) then
While SDL_PollEvent( @event ) = 1 Do
Begin
Case Event.type_ Of
SDL_ACTIVEEVENT: //workaround for alt-tab bug
begin
if (Event.active.gain=1) then
begin
SDL_SetModState(KMOD_NONE);
if (Ini.FullScreen = 1) or (Params.FullScreen) then
SDL_ShowCursor(0);
//EnableVideoDraw := true;
end;
if (Event.active.gain=0) then
begin
if (Ini.FullScreen = 1) or (Params.FullScreen) then
SDL_ShowCursor(1);
//EnableVideoDraw := false;
end;
end;
SDL_QUITEV:
begin
Display.Fade := 0;
Display.NextScreenWithCheck := nil;
Display.CheckOK := True;
end;
{ SDL_MOUSEBUTTONDOWN:
With Event.button Do
Begin
If State = SDL_BUTTON_LEFT Then
Begin
//
End;
End; // With}
SDL_KEYDOWN:
begin
//ScreenShot hack. If Print is pressed-> Make screenshot and Save to Screenshots Path
if (Event.key.keysym.sym = SDLK_SYSREQ) or (Event.key.keysym.sym = SDLK_PRINT) then
begin
// ScreenPopupError.ShowPopup('How dare you press the <Print> key'); //show error message
if (SDL_GetModState and KMOD_LCTRL = KMOD_LCTRL) then
Display.PrintScreen //jpeg
else
Display.ScreenShot; //bmp
end
// popup hack... if there is a visible popup then let it handle input instead of underlying screen
// shoud be done in a way to be sure the topmost popup has preference (maybe error, then check)
else if (ScreenPopupError <> NIL) and (ScreenPopupError.Visible) then
done := not ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True)
else if (ScreenPopupCheck <> NIL) AND (ScreenPopupCheck.Visible) then
done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True)
else if (ScreenPopupHelp <> NIL) AND (ScreenPopupHelp.Visible) then
done := not ScreenPopupHelp.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True)
// end of popup hack
else
begin
// check for Screen want to Exit
done := Not Display.ActualScreen^.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True);
//If Screen wants to Exit
if done then
begin
//If Question Option is enabled then Show Exit Popup
if (Ini.AskbeforeDel = 1) then
begin
Display.ActualScreen^.CheckFadeTo(NIL,'MSG_QUIT_USDX');
end
else //When asking for exit is disabled then simply exit
begin
Display.Fade := 0;
Display.NextScreenWithCheck := nil;
Display.CheckOK := True;
end;
end;
end; // if (Not Display.ActualScreen^.ParseInput(Event.key.keysym.scancode, True)) then
end;
// SDL_JOYAXISMOTION:
// begin
// beep
// end;
SDL_JOYBUTTONDOWN:
begin
beep
end;
End; // Case Event.type_
End; // While
End; // CheckEvents
function GetTimeForBeats(BPM, Beats: real): real;
begin
Result := 60 / BPM * Beats;
end;
function GetBeats(BPM, msTime: real): real;
begin
Result := BPM * msTime / 60;
end;
procedure GetMidBeatSub(BPMNum: integer; var Time: real; var CurBeat: real);
var
NewTime: real;
begin
if High(AktSong.BPM) = BPMNum then begin
// last BPM
CurBeat := AktSong.BPM[BPMNum].StartBeat + GetBeats(AktSong.BPM[BPMNum].BPM, Time);
Time := 0;
end else begin
// not last BPM
// count how much time is it for start of the new BPM and store it in NewTime
NewTime := GetTimeForBeats(AktSong.BPM[BPMNum].BPM, AktSong.BPM[BPMNum+1].StartBeat - AktSong.BPM[BPMNum].StartBeat);
// compare it to remaining time
if (Time - NewTime) > 0 then begin
// there is still remaining time
CurBeat := AktSong.BPM[BPMNum].StartBeat;
Time := Time - NewTime;
end else begin
// there is no remaining time
CurBeat := AktSong.BPM[BPMNum].StartBeat + GetBeats(AktSong.BPM[BPMNum].BPM, Time);
Time := 0;
end; // if
end; // if
end;
function GetMidBeat(Time: real): real;
var
CurBeat: real;
CurBPM: integer;
// TopBeat: real;
// TempBeat: real;
// TempTime: real;
begin
Result := 0;
if Length(AktSong.BPM) = 1 then Result := Time * AktSong.BPM[0].BPM / 60;
(* 2 BPMs *)
{ if Length(AktSong.BPM) > 1 then begin
(* new system *)
CurBeat := 0;
TopBeat := GetBeats(AktSong.BPM[0].BPM, Time);
if TopBeat > AktSong.BPM[1].StartBeat then begin
// analyze second BPM
Time := Time - GetTimeForBeats(AktSong.BPM[0].BPM, AktSong.BPM[1].StartBeat - CurBeat);
CurBeat := AktSong.BPM[1].StartBeat;
TopBeat := GetBeats(AktSong.BPM[1].BPM, Time);
Result := CurBeat + TopBeat;
end else begin
(* pierwszy przedzial *)
Result := TopBeat;
end;
end; // if}
(* more BPMs *)
if Length(AktSong.BPM) > 1 then begin
CurBeat := 0;
CurBPM := 0;
while (Time > 0) do begin
GetMidBeatSub(CurBPM, Time, CurBeat);
Inc(CurBPM);
end;
Result := CurBeat;
end; // if
end;
function GetTimeFromBeat(Beat: integer): real;
var
CurBPM: integer;
begin
Result := 0;
if Length(AktSong.BPM) = 1 then Result := AktSong.GAP / 1000 + Beat * 60 / AktSong.BPM[0].BPM;
(* more BPMs *)
if Length(AktSong.BPM) > 1 then begin
Result := AktSong.GAP / 1000;
CurBPM := 0;
while (CurBPM <= High(AktSong.BPM)) and (Beat > AktSong.BPM[CurBPM].StartBeat) do begin
if (CurBPM < High(AktSong.BPM)) and (Beat >= AktSong.BPM[CurBPM+1].StartBeat) then begin
// full range
Result := Result + (60 / AktSong.BPM[CurBPM].BPM) * (AktSong.BPM[CurBPM+1].StartBeat - AktSong.BPM[CurBPM].StartBeat);
end;
if (CurBPM = High(AktSong.BPM)) or (Beat < AktSong.BPM[CurBPM+1].StartBeat) then begin
// in the middle
Result := Result + (60 / AktSong.BPM[CurBPM].BPM) * (Beat - AktSong.BPM[CurBPM].StartBeat);
end;
Inc(CurBPM);
end;
{ while (Time > 0) do begin
GetMidBeatSub(CurBPM, Time, CurBeat);
Inc(CurBPM);
end;}
end; // if}
end;
procedure Sing(Sender: TScreenSing);
var
Pet: integer;
PetGr: integer;
CP: integer;
Done: real;
N: integer;
begin
//Czas.Teraz := Czas.Teraz + TimeSkip;
Czas.Teraz := Music.Position;
Czas.OldBeat := Czas.AktBeat;
Czas.MidBeat := GetMidBeat(Czas.Teraz - (AktSong.Gap{ + 90 I've forgotten for what it is}) / 1000); // new system with variable BPM in function
Czas.AktBeat := Floor(Czas.MidBeat);
Czas.OldBeatC := Czas.AktBeatC;
Czas.MidBeatC := GetMidBeat(Czas.Teraz - (AktSong.Gap) / 1000);
Czas.AktBeatC := Floor(Czas.MidBeatC);
Czas.OldBeatD := Czas.AktBeatD;
Czas.MidBeatD := -0.5+GetMidBeat(Czas.Teraz - (AktSong.Gap + 120 + 20) / 1000); // MidBeat with addition GAP
Czas.AktBeatD := Floor(Czas.MidBeatD);
Czas.FracBeatD := Frac(Czas.MidBeatD);
// sentences routines
PetGr := 0;
if AktSong.isDuet then
PetGr := 1;
for CP := 0 to PetGr do
begin
// ustawianie starej czesci
Czas.OldCzesc[CP] := Czesci[CP].Akt;
// wybieranie aktualnej czesci
for Pet := 0 to Czesci[CP].High do
begin
if Czas.AktBeat >= Czesci[CP].Czesc[Pet].Start then
begin
if (GetTimeFromBeat(Czesci[CP].Czesc[Pet].StartNote) <= Czas.Teraz+10) then
Czesci[CP].Akt := Pet;
end;
end;
// czysczenie nut gracza, gdy to jest nowa plansza
// (optymizacja raz na halfbeat jest zla)
if Czesci[CP].Akt <> Czas.OldCzesc[CP] then
NewSentence(CP, Sender);
// wykonuje operacje raz na beat
if (Czas.AktBeat >= 0) and (Czas.OldBeat <> Czas.AktBeat) then
NewBeat(CP, Sender);
// make some operations on clicks
if {(Czas.AktBeatC >= 0) and }(Czas.OldBeatC <> Czas.AktBeatC) then
NewBeatC(CP, Sender);
// make some operations when detecting new voice pitch
if (Czas.AktBeatD >= 0) and (Czas.OldBeatD <> Czas.AktBeatD) then
NewBeatD(CP, Sender);
// plynnie przesuwa text
Done := 1;
if (Length(Czesci[CP].Czesc[Czesci[CP].Akt].Nuta)>0) then
begin
for N := 0 to Czesci[CP].Czesc[Czesci[CP].Akt].HighNut do
if (Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Start <= Czas.MidBeat)
and (Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Start + Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Dlugosc >= Czas.MidBeat) then
Done := (Czas.MidBeat - Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Start) / (Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Dlugosc);
N := Czesci[CP].Czesc[Czesci[CP].Akt].HighNut;
// wylacza ostatnia nute po przejsciu
if (Ini.LyricsEffect = 1) and (Done = 1) and
(Czas.MidBeat > Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Start + Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[N].Dlugosc)
then
begin
Sender.LyricMain[CP].Selected := -1
end;
if Done > 1 then
Done := 1;
Sender.LyricMain[CP].Done := Done;
end;
end;
end;
procedure NewSentence(CP: integer; Sender: TScreenSing);
var
G: Integer;
begin
// czyszczenie nut graczy
if AktSong.isDuet then
begin
for G := 0 to High(Player) do
begin
if (G mod 2 = CP) then
begin
Player[G].IlNut := 0;
Player[G].HighNut := -1;
SetLength(Player[G].Nuta, 0);
end;
end;
end else
begin
for G := 0 to High(Player) do
begin
Player[G].IlNut := 0;
Player[G].HighNut := -1;
SetLength(Player[G].Nuta, 0);
end;
end;
// wstawianie tekstow
with Sender do
begin
LyricMain[CP].AddCzesc(CP, Czesci[CP].Akt);
if Czesci[CP].Akt < Czesci[CP].High then
LyricSub[CP].AddCzesc(CP, Czesci[CP].Akt+1)
else
LyricSub[CP].Clear;
end;
//On Sentence Change...
Sender.onSentenceChange(CP, Czesci[CP].Akt);
end;
procedure NewBeat(CP: integer; Sender: TScreenSing);
var
Pet: integer;
// TempBeat: integer;
begin
if (Length(Czesci[CP].Czesc[Czesci[CP].Akt].Nuta)=0) then
Exit;
for Pet := 0 to Czesci[CP].Czesc[Czesci[CP].Akt].HighNut do
begin
if (Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[Pet].Start = Czas.AktBeat) then
begin
// operates on currently beated note
Sender.LyricMain[CP].Selected := Pet
end;
end;
end;
procedure NewBeatC(CP: integer; Sender: TScreenSing);
var
Pet: integer;
// LPT_1: integer;
// LPT_2: integer;
begin
// LPT_1 := 1;
// LPT_2 := 1;
// beat click
if (Ini.BeatClick = 1) and ((Czas.AktBeatC + Czesci[CP].Resolution + Czesci[CP].NotesGAP) mod Czesci[CP].Resolution = 0) then
Music.PlayClick;
if (Length(Czesci[CP].Czesc[Czesci[CP].Akt].Nuta)=0) then
Exit;
for Pet := 0 to Czesci[CP].Czesc[Czesci[CP].Akt].HighNut do
if (Czesci[CP].Czesc[Czesci[CP].Akt].Nuta[Pet].Start = Czas.AktBeatC) then
begin
// click assist
if Ini.ClickAssist = 1 then
Music.PlayClick;
// drum machine
(* TempBeat := Czas.AktBeat;// + 2;
if (TempBeat mod 8 = 0) then Music.PlayDrum;
if (TempBeat mod 8 = 4) then Music.PlayClap;
// if (TempBeat mod 4 = 2) then Music.PlayHihat;
if (TempBeat mod 4 <> 0) then Music.PlayHihat;*)
end;
//PortWriteB($378, LPT_1 + LPT_2 * 2); // 0 zapala
end;
procedure NewBeatD(CP: integer; Sender: TScreenSing);
begin
NewNote(CP, Sender);
end;
//procedure NewHalf;
//begin
// NewNote;
//end;
procedure NewNote(P: integer; Sender: TScreenSing);
const
DEBUG_NOTE_HIT = false;
var
CP: integer; // current player
S: integer; // sentence
N: integer;
SumN: real;
NumS: integer;
tap: integer;
SMin: integer;
SMax: integer;
SDet: integer; // temporary: sentence of detected note
Pet: integer;
Mozna: boolean;
Nowa: boolean;
Range: integer;
NoteHit:boolean;
begin
for CP := 0 to PlayersPlay-1 do
begin
if (not AktSong.isDuet) then
begin
// analyze buffer
Sound[CP].AnalizujBufor;
// 0.5.0: count min and max sentence range for checking (detection is delayed to the notes we see on the screen)
SMin := Czesci[P].Akt-1;
if SMin < 0 then
SMin := 0;
SMax := Czesci[P].Akt;
// check if we can add new note
Mozna := false;
for S := SMin to SMax do
begin
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if ((Czesci[P].Czesc[S].Nuta[Pet].Start <= Czas.AktBeatD)
and (Czesci[P].Czesc[S].Nuta[Pet].Start + Czesci[P].Czesc[S].Nuta[Pet].Dlugosc - 1 >= Czas.AktBeatD))
and (not Czesci[P].Czesc[S].Nuta[Pet].FreeStyle) // but don't allow when it's FreeStyle note
and (Czesci[P].Czesc[S].Nuta[Pet].Dlugosc > 0) // and make sure the note lenghts is at least 1
then
begin
SDet := S;
Mozna := true;
Break;
end;
end;
end;
S := SDet;
if (Sound[CP].SzczytJest or DEBUG_NOTE_HIT) and (Mozna) then
begin
// operowanie na ostatniej nucie
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[Pet].Start <= Czas.OldBeatD+1)
and (Czesci[P].Czesc[S].Nuta[Pet].Start +
Czesci[P].Czesc[S].Nuta[Pet].Dlugosc > Czas.OldBeatD+1) then
begin
// przesuwanie tonu w odpowiednia game
while (Sound[CP].Ton - Czesci[P].Czesc[S].Nuta[Pet].Ton > 6) do
Sound[CP].Ton := Sound[CP].Ton - 12;
while (Sound[CP].Ton - Czesci[P].Czesc[S].Nuta[Pet].Ton < -6) do
Sound[CP].Ton := Sound[CP].Ton + 12;
// Half size Notes Patch
NoteHit := false;
//if Ini.Difficulty = 0 then Range := 2;
//if Ini.Difficulty = 1 then Range := 1;
//if Ini.Difficulty = 2 then Range := 0;
Range := 2 - Ini.Difficulty;
if (abs(Czesci[P].Czesc[S].Nuta[Pet].Ton - Sound[CP].Ton) <= Range) or
DEBUG_NOTE_HIT then
begin
Sound[CP].Ton := Czesci[P].Czesc[S].Nuta[Pet].Ton;
// Half size Notes Patch
NoteHit := true;
if (Ini.LineBonus = 0) then
begin
// add points without LineBonus
case Czesci[P].Czesc[S].Nuta[Pet].Wartosc of
1: Player[CP].Score := Player[CP].Score + 10000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 10000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
end;
end else
begin
// add points with Line Bonus
case Czesci[P].Czesc[S].Nuta[Pet].Wartosc of
1: Player[CP].Score := Player[CP].Score + 9000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 9000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
end;
end;
Player[CP].ScoreI := Floor(Player[CP].Score / 10) * 10;
Player[CP].ScoreGoldenI := Floor(Player[CP].ScoreGolden / 10) * 10;
Player[CP].ScoreTotalI := Player[CP].ScoreI + Player[CP].ScoreGoldenI + Player[CP].ScoreLineI;
end;
end; // operowanie
end;
// sprawdzanie czy to nowa nuta, czy przedluzenie
if S = SMax then
begin
Nowa := true;
// jezeli ostatnia ma ten sam ton
if (Player[CP].IlNut > 0 ) and (Player[CP].Nuta[Player[CP].HighNut].Ton = Sound[CP].Ton)
and (Player[CP].Nuta[Player[CP].HighNut].Start + Player[CP].Nuta[Player[CP].HighNut].Dlugosc = Czas.AktBeatD)
then
Nowa := false;
// jezeli jest jakas nowa nuta na sprawdzanym beacie
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
if (Czesci[P].Czesc[S].Nuta[Pet].Start = Czas.AktBeatD) then
Nowa := true;
// dodawanie nowej nuty
if Nowa then
begin
// nowa nuta
Player[CP].IlNut := Player[CP].IlNut + 1;
Player[CP].HighNut := Player[CP].HighNut + 1;
SetLength(Player[CP].Nuta, Player[CP].IlNut);
Player[CP].Nuta[Player[CP].HighNut].Start := Czas.AktBeatD;
Player[CP].Nuta[Player[CP].HighNut].Dlugosc := 1;
Player[CP].Nuta[Player[CP].HighNut].Ton := Sound[CP].Ton; // Ton || TonDokl
Player[CP].Nuta[Player[CP].HighNut].Detekt := Czas.MidBeat;
// Half Note Patch
Player[CP].Nuta[Player[CP].HighNut].Hit := NoteHit;
end else
begin
// przedluzenie nuty
Player[CP].Nuta[Player[CP].HighNut].Dlugosc := Player[CP].Nuta[Player[CP].HighNut].Dlugosc + 1;
end;
// check for perfect note and then lit the star (on Draw)
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[Pet].Start = Player[CP].Nuta[Player[CP].HighNut].Start)
and (Czesci[P].Czesc[S].Nuta[Pet].Dlugosc = Player[CP].Nuta[Player[CP].HighNut].Dlugosc)
and (Czesci[P].Czesc[S].Nuta[Pet].Ton = Player[CP].Nuta[Player[CP].HighNut].Ton) then
begin
Player[CP].Nuta[Player[CP].HighNut].Perfect := true;
end;
end;// else beep; // if S = SMax
end; //for
end; // if moze
//calc score last
SumN := 0;
NumS := 0;
for S := Czesci[P].Akt to Czesci[P].High do
begin
for N := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[N].Start > Czas.AktBeatD) then
begin
tap := Czesci[P].Czesc[S].Nuta[N].Dlugosc;
if (Czesci[P].Czesc[S].Nuta[N].Start + tap < Czas.AktBeatD) then
tap := Czas.AktBeatD - Czesci[P].Czesc[S].Nuta[N].Start - tap;
if (Ini.LineBonus = 0) then
// add points without LineBonus
SumN := SumN + 10000 / Czesci[P].Wartosc * Czesci[P].Czesc[S].Nuta[N].Wartosc * tap
else
// add points with Line Bonus
SumN := SumN + 9000 / Czesci[P].Wartosc * Czesci[P].Czesc[S].Nuta[N].Wartosc * tap;
end;
end;
if (Czesci[P].Czesc[S].TotalNotes>0) and
(Czesci[P].Czesc[S].Koniec > Czas.AktBeatD) then
Inc(NumS);
end;
N := (Czesci[P].Ilosc - ScreenSing.NumEmptySentences[P]);
if (N>0) and (Ini.LineBonus > 0) then
Player[CP].ScoreMax := Floor((SumN + NumS*1000 / N)/10)*10;
Player[CP].ScoreMax := Player[CP].ScoreTotalI + Player[CP].ScoreMax;
end else
begin //############################ DUET #####################
if (CP mod 2 = P) then
begin
// analyze buffer
Sound[CP].AnalizujBufor;
// 0.5.0: count min and max sentence range for checking (detection is delayed to the notes we see on the screen)
SMin := Czesci[P].Akt-1;
if SMin < 0 then
SMin := 0;
SMax := Czesci[P].Akt;
// check if we can add new note
Mozna := false;
for S := SMin to SMax do
begin
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if ((Czesci[P].Czesc[S].Nuta[Pet].Start <= Czas.AktBeatD)
and (Czesci[P].Czesc[S].Nuta[Pet].Start + Czesci[P].Czesc[S].Nuta[Pet].Dlugosc - 1 >= Czas.AktBeatD))
and (not Czesci[P].Czesc[S].Nuta[Pet].FreeStyle) // but don't allow when it's FreeStyle note
and (Czesci[P].Czesc[S].Nuta[Pet].Dlugosc > 0) // and make sure the note lenghts is at least 1
then
begin
SDet := S;
Mozna := true;
Break;
end;
end;
end;
S := SDet;
if (Sound[CP].SzczytJest or DEBUG_NOTE_HIT) and (Mozna) then
begin
// operowanie na ostatniej nucie
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[Pet].Start <= Czas.OldBeatD+1)
and (Czesci[P].Czesc[S].Nuta[Pet].Start +
Czesci[P].Czesc[S].Nuta[Pet].Dlugosc > Czas.OldBeatD+1) then
begin
// przesuwanie tonu w odpowiednia game
while (Sound[CP].Ton - Czesci[P].Czesc[S].Nuta[Pet].Ton > 6) do
Sound[CP].Ton := Sound[CP].Ton - 12;
while (Sound[CP].Ton - Czesci[P].Czesc[S].Nuta[Pet].Ton < -6) do
Sound[CP].Ton := Sound[CP].Ton + 12;
// Half size Notes Patch
NoteHit := false;
//if Ini.Difficulty = 0 then Range := 2;
//if Ini.Difficulty = 1 then Range := 1;
//if Ini.Difficulty = 2 then Range := 0;
Range := 2 - Ini.Difficulty;
if (abs(Czesci[P].Czesc[S].Nuta[Pet].Ton - Sound[CP].Ton) <= Range) or
DEBUG_NOTE_HIT then
begin
Sound[CP].Ton := Czesci[P].Czesc[S].Nuta[Pet].Ton;
// Half size Notes Patch
NoteHit := true;
if (Ini.LineBonus = 0) then
begin
// add points without LineBonus
case Czesci[P].Czesc[S].Nuta[Pet].Wartosc of
1: Player[CP].Score := Player[CP].Score + 10000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 10000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
end;
end else
begin
// add points with Line Bonus
case Czesci[P].Czesc[S].Nuta[Pet].Wartosc of
1: Player[CP].Score := Player[CP].Score + 9000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 9000 / Czesci[P].Wartosc *
Czesci[P].Czesc[S].Nuta[Pet].Wartosc;
end;
end;
Player[CP].ScoreI := Floor(Player[CP].Score / 10) * 10;
Player[CP].ScoreGoldenI := Floor(Player[CP].ScoreGolden / 10) * 10;
Player[CP].ScoreTotalI := Player[CP].ScoreI + Player[CP].ScoreGoldenI + Player[CP].ScoreLineI;
end;
end; // operowanie
end;
// sprawdzanie czy to nowa nuta, czy przedluzenie
if S = SMax then
begin
Nowa := true;
// jezeli ostatnia ma ten sam ton
if (Player[CP].IlNut > 0 ) and (Player[CP].Nuta[Player[CP].HighNut].Ton = Sound[CP].Ton)
and (Player[CP].Nuta[Player[CP].HighNut].Start + Player[CP].Nuta[Player[CP].HighNut].Dlugosc = Czas.AktBeatD)
then
Nowa := false;
// jezeli jest jakas nowa nuta na sprawdzanym beacie
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
if (Czesci[P].Czesc[S].Nuta[Pet].Start = Czas.AktBeatD) then
Nowa := true;
// dodawanie nowej nuty
if Nowa then
begin
// nowa nuta
Player[CP].IlNut := Player[CP].IlNut + 1;
Player[CP].HighNut := Player[CP].HighNut + 1;
SetLength(Player[CP].Nuta, Player[CP].IlNut);
Player[CP].Nuta[Player[CP].HighNut].Start := Czas.AktBeatD;
Player[CP].Nuta[Player[CP].HighNut].Dlugosc := 1;
Player[CP].Nuta[Player[CP].HighNut].Ton := Sound[CP].Ton; // Ton || TonDokl
Player[CP].Nuta[Player[CP].HighNut].Detekt := Czas.MidBeat;
// Half Note Patch
Player[CP].Nuta[Player[CP].HighNut].Hit := NoteHit;
end else
begin
// przedluzenie nuty
Player[CP].Nuta[Player[CP].HighNut].Dlugosc := Player[CP].Nuta[Player[CP].HighNut].Dlugosc + 1;
end;
// check for perfect note and then lit the star (on Draw)
for Pet := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[Pet].Start = Player[CP].Nuta[Player[CP].HighNut].Start)
and (Czesci[P].Czesc[S].Nuta[Pet].Dlugosc = Player[CP].Nuta[Player[CP].HighNut].Dlugosc)
and (Czesci[P].Czesc[S].Nuta[Pet].Ton = Player[CP].Nuta[Player[CP].HighNut].Ton) then
begin
Player[CP].Nuta[Player[CP].HighNut].Perfect := true;
end;
end;// else beep; // if S = SMax
end; //for
end; // if moze
//calc score last
SumN := 0;
NumS := 0;
for S := Czesci[P].Akt to Czesci[P].High do
begin
for N := 0 to Czesci[P].Czesc[S].HighNut do
begin
if (Czesci[P].Czesc[S].Nuta[N].Start > Czas.AktBeatD) then
begin
tap := Czesci[P].Czesc[S].Nuta[N].Dlugosc;
if (Czesci[P].Czesc[S].Nuta[N].Start + tap < Czas.AktBeatD) then
tap := Czas.AktBeatD - Czesci[P].Czesc[S].Nuta[N].Start - tap;
if (Ini.LineBonus = 0) then
// add points without LineBonus
SumN := SumN + 10000 / Czesci[P].Wartosc * Czesci[P].Czesc[S].Nuta[N].Wartosc * tap
else
// add points with Line Bonus
SumN := SumN + 9000 / Czesci[P].Wartosc * Czesci[P].Czesc[S].Nuta[N].Wartosc * tap;
end;
end;
if (Czesci[P].Czesc[S].TotalNotes>0) and
(Czesci[P].Czesc[S].Koniec > Czas.AktBeatD) then
Inc(NumS);
end;
N := (Czesci[P].Ilosc - ScreenSing.NumEmptySentences[P]);
if (N>0) and (Ini.LineBonus > 0) then
Player[CP].ScoreMax := Floor((SumN + NumS*1000 / N)/10)*10;
Player[CP].ScoreMax := Player[CP].ScoreTotalI + Player[CP].ScoreMax;
end; //if mod 2
end;
end; // for CP
//On Sentence End -> For LineBonus + SingBar
if (sDet >= low(Czesci[P].Czesc)) AND (sDet <= high(Czesci[P].Czesc)) then
begin
if (Length(Czesci[P].Czesc[SDet].Nuta)>0) then
begin
if ((Czesci[P].Czesc[SDet].Nuta[Czesci[P].Czesc[SDet].HighNut].Start +
Czesci[P].Czesc[SDet].Nuta[Czesci[P].Czesc[SDet].HighNut].Dlugosc - 1) = Czas.AktBeatD) then
Sender.onSentenceEnd(P, sDet);
end;
end;
end;
procedure ClearScores(PlayerNum: integer);
begin
Player[PlayerNum].Score := 0;
Player[PlayerNum].ScoreI := 0;
Player[PlayerNum].ScoreLine := 0;
Player[PlayerNum].ScoreLineI := 0;
Player[PlayerNum].ScoreGolden := 0;
Player[PlayerNum].ScoreGoldenI := 0;
Player[PlayerNum].ScoreTotalI := 0;
//SingBar Mod
Player[PlayerNum].ScoreLast := 0;
Player[PlayerNum].ScorePercent := 50;// Sets to 50% when song starts
Player[PlayerNum].ScorePercentTarget := 50;// Sets to 50% when song starts
//end SingBar Mod
Player[PlayerNum].ScoreMax := 9990;
//PhrasenBonus - Line Bonus Mod
Player[PlayerNum].LineBonus_Visible := False; //Hide Line Bonus
Player[PlayerNum].LineBonus_Alpha := 0;
//Player[PlayerNum].LineBonus_TargetX := 70 + PlayerNum*500; //will be done by onShow
//Player[PlayerNum].LineBonus_TargetY := 30; //will be done by onShow
//PhrasenBonus - Line Bonus Mod End
end;
end.