diff options
Diffstat (limited to 'Game/Code/Classes')
-rw-r--r-- | Game/Code/Classes/TextGL.pas | 106 | ||||
-rw-r--r-- | Game/Code/Classes/UDraw.pas | 367 | ||||
-rw-r--r-- | Game/Code/Classes/UFiles.pas | 2 | ||||
-rw-r--r-- | Game/Code/Classes/UIni.pas | 15 | ||||
-rw-r--r-- | Game/Code/Classes/UMain.pas | 518 | ||||
-rw-r--r-- | Game/Code/Classes/UMusic.pas | 51 | ||||
-rw-r--r-- | Game/Code/Classes/UParty.pas | 6 | ||||
-rw-r--r-- | Game/Code/Classes/USingScores.pas | 18 |
8 files changed, 580 insertions, 503 deletions
diff --git a/Game/Code/Classes/TextGL.pas b/Game/Code/Classes/TextGL.pas index b21a5237..1396ae1b 100644 --- a/Game/Code/Classes/TextGL.pas +++ b/Game/Code/Classes/TextGL.pas @@ -20,23 +20,24 @@ uses SDL_ttf,
ULog;
-procedure BuildFont; // Build Our Bitmap Font
-procedure KillFont; // Delete The Font
-function glTextWidth(text: pchar): real; // Returns Text Width
+procedure BuildFont; // build our bitmap font
+procedure KillFont; // delete the font
+function glTextWidth(text: pchar): real; // returns text width
procedure glPrintDone(text: pchar; Done: real; ColR, ColG, ColB: real);
procedure glPrintLetter(letter: char);
procedure glPrintLetterCut(letter: char; Start, Finish: real);
-procedure glPrint(text: pchar); // Custom GL "Print" Routine
+procedure glPrint(text: pchar); // custom GL "Print" routine
procedure glPrintCut(text: pchar);
-procedure SetFontPos(X, Y: real); // Sets X And Y
+procedure SetFontPos(X, Y: real); // sets X and Y
procedure SetFontSize(Size: real);
-procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc)
-procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts)
+procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc)
+procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts)
procedure SetFontAspectW(Aspect: real);
procedure SetFontReflection(Enable:boolean;Spacing: real); // Enables/Disables text reflection
+
// Start of SDL_ttf
function NextPowerOfTwo(Value: integer): integer;
-//Checks if the ttf exists, if yes then a SDL_ttf is returned
+// Checks if the ttf exists, if yes then a SDL_ttf is returned
function LoadFont(FileName: PAnsiChar; PointSize: integer):PTTF_Font;
// Does the renderstuff, color is in $ffeecc style
@@ -69,7 +70,7 @@ type var
- base: GLuint; // Base Display List For The Font Set
+ base: GLuint; // base display list for the font set
Fonts: array of TFont;
ActFont: integer;
PColR: real; // temps for glPrintDone
@@ -79,6 +80,7 @@ var // Colours for the reflection
TempColor: array[0..3] of GLfloat;
PTempColor: PGLfloat;
+
implementation
uses
@@ -87,26 +89,26 @@ uses SysUtils,
UGraphic;
-procedure BuildFont; // Build Our Bitmap Font
-
- procedure loadfont(aID : integer; const aType, aResourceName: string);
- var
- stream: TStream;
+procedure LoadBitmapFontInfo(aID : integer; const aType, aResourceName: string);
+var
+ stream: TStream;
+begin
+ stream := GetResourceStream(aResourceName, aType);
+ if (not assigned(stream)) then
begin
- stream := GetResourceStream(aResourceName, aType);
- if (not assigned(stream)) then
- begin
- Log.LogError('Unknown font['+ inttostr(aID) +': '+aType+']', 'loadfont');
- Exit;
- end;
- try
- stream.Read(Fonts[ aID ].Width, 256);
- except
- Log.LogError('Error while reading font['+ inttostr(aID) +': '+aType+']', 'loadfont');
- end;
- stream.Free;
+ Log.LogError('Unknown font['+ inttostr(aID) +': '+aType+']', 'loadfont');
+ Exit;
end;
+ try
+ stream.Read(Fonts[ aID ].Width, 256);
+ except
+ Log.LogError('Error while reading font['+ inttostr(aID) +': '+aType+']', 'loadfont');
+ end;
+ stream.Free;
+end;
+// Builds bitmap fonts
+procedure BuildFont;
var
Count: integer;
begin
@@ -150,16 +152,11 @@ begin Fonts[4].Done := -1;
Fonts[4].Outline := 5;}
-
-
- loadfont( 0, 'FNT', 'Font' );
- loadfont( 1, 'FNT', 'FontB' );
- loadfont( 2, 'FNT', 'FontO' );
- loadfont( 3, 'FNT', 'FontO2' );
-
-{ Reg := TResourceStream.Create(HInstance, 'FontO', 'FNT');
- Reg.Read(Fonts[4].Width, 256);
- Reg.Free;}
+ // load font info
+ LoadBitmapFontInfo( 0, 'FNT', 'Font' );
+ LoadBitmapFontInfo( 1, 'FNT', 'FontB' );
+ LoadBitmapFontInfo( 2, 'FNT', 'FontO' );
+ LoadBitmapFontInfo( 3, 'FNT', 'FontO2' );
for Count := 0 to 255 do
Fonts[1].Width[Count] := Fonts[1].Width[Count] div 2;
@@ -175,9 +172,11 @@ begin end;
-procedure KillFont; // Delete The Font
+// Deletes the font
+procedure KillFont;
begin
-// glDeleteLists(base, 256); // Delete All 96 Characters
+ // delete all characters
+ //glDeleteLists(base, 256);
end;
function glTextWidth(text: pchar): real;
@@ -185,13 +184,10 @@ var Letter: char;
i: integer;
begin
-// Log.LogStatus(Text, 'glTextWidth');
Result := 0;
- for i := 0 to Length(text) -1 do // Patched by AlexanderS : bug with wrong sliced text lines
+ for i := 0 to Length(text) -1 do
begin
Letter := Text[i];
- // Bugfix: does not work with FPC, probably because a part of text is assigned to itself
- //text := pchar(Copy(text, 2, Length(text)-1));
Result := Result + Fonts[ActFont].Width[Ord(Letter)] * Fonts[ActFont].Tex.H / 30 * Fonts[ActFont].AspectW;
end;
end;
@@ -316,7 +312,7 @@ begin FWidth := Fonts[ActFont].Width[Ord(Letter)];
W := FWidth * (H/30) * Fonts[ActFont].AspectW;
-// H := 30;
+ //H := 30;
OutTemp := Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW;
// set texture positions
@@ -356,14 +352,14 @@ begin end;
-procedure glPrint(text: pchar); // Custom GL "Print" Routine
+// Custom GL "Print" Routine
+procedure glPrint(text: pchar);
var
-// Letter : char;
+ //Letter : char;
iPos : integer;
-
begin
if (Text = '') then // If There's No Text
- Exit; // Do Nothing
+ Exit; // Do Nothing
(*
while (length(text) > 0) do
@@ -377,9 +373,9 @@ begin end; // while
*)
-//Save the actual color and alpha (for reflection)
+ //Save the actual color and alpha (for reflection)
PTempColor:= @TempColor;
-//I've read that glGetFloat is quite slow, but it seems that there is no alternative
+ //I've read that glGetFloat is quite slow, but it seems that there is no alternative
glGetFloatv(GL_CURRENT_COLOR, PTempColor);
// This code is better, because doing a Copy of for every
@@ -393,9 +389,9 @@ begin end;
-function NextPowerOfTwo(Value: integer): integer;
// tyty to Asphyre
// FIXME: check if the non-asm version is fast enough and use it by default if so
+function NextPowerOfTwo(Value: integer): integer;
begin
Result:= 1;
{$IF Defined(CPUX86_64)}
@@ -465,14 +461,14 @@ begin clrbg.unused := 0;
sText := RenderText(font, 'katzeeeeeee', $fe198e);
-// sText := TTF_RenderText_Blended( font, 'huuuuuuuuuund', clrFG);
+ //sText := TTF_RenderText_Blended( font, 'huuuuuuuuuund', clrFG);
-// Convert the rendered text to a known format
+ // Convert the rendered text to a known format
w := nextpoweroftwo(sText.w);
h := nextpoweroftwo(sText.h);
intermediary := SDL_CreateRGBSurface(0, w, h, 32,
- $000000ff, $0000ff00, $00ff0000, $ff000000);
+ $000000ff, $0000ff00, $00ff0000, $ff000000);
SDL_SetAlpha(intermediary, 0, 255);
SDL_SetAlpha(sText, 0, 255);
@@ -518,8 +514,8 @@ var PDoingNow: real;
S: string;
begin
- if (Text = '') then // If There's No Text
- Exit; // Do Nothing
+ if (Text = '') then // If There's No Text
+ Exit; // Do Nothing
PTotWidth := glTextWidth(Text);
PToDo := Fonts[ActFont].Done;
diff --git a/Game/Code/Classes/UDraw.pas b/Game/Code/Classes/UDraw.pas index 53508baf..d82fef33 100644 --- a/Game/Code/Classes/UDraw.pas +++ b/Game/Code/Classes/UDraw.pas @@ -19,8 +19,8 @@ procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer); procedure SingDrawNoteLines(Left, Top, Right: real; Space: integer);
procedure SingDrawBeatDelimeters(Left, Top, Right: real; NrLines: integer);
procedure SingDrawLine(Left, Top, Right: real; NrLines: integer; Space: integer);
-procedure SingDrawPlayerLine(X, Y, W: real; NrGracza: integer; Space: integer);
-procedure SingDrawPlayerBGLine(Left, Top, Right: real; NrLines, NrGracza: integer; Space: integer);
+procedure SingDrawPlayerLine(X, Y, W: real; PlayerIndex: integer; Space: integer);
+procedure SingDrawPlayerBGLine(Left, Top, Right: real; NrLines, PlayerIndex: integer; Space: integer);
// TimeBar
procedure SingDrawTimeBar();
@@ -338,129 +338,122 @@ end; // draw sung notes
-procedure SingDrawPlayerLine(X, Y, W: real; NrGracza: integer; Space: integer);
+procedure SingDrawPlayerLine(X, Y, W: real; PlayerIndex: integer; Space: integer);
var
- TempR: real;
- Rec: TRecR;
- N: integer;
- R: real;
- G: real;
- B: real;
- A: real;
- NotesH2: real;
- begin
-// Log.LogStatus('Player notes', 'SingDraw');
+ TempR: real;
+ Rec: TRecR;
+ N: integer;
+ R, G, B, A: real;
+ NotesH2: real;
+begin
+ //Log.LogStatus('Player notes', 'SingDraw');
-// if NrGracza = 0 then LoadColor(R, G, B, 'P1Light')
-// else LoadColor(R, G, B, 'P2Light');
+ //if NrGracza = 0 then LoadColor(R, G, B, 'P1Light')
+ //else LoadColor(R, G, B, 'P2Light');
-// R := 71/255;
-// G := 175/255;
-// B := 247/255;
+ //R := 71/255;
+ //G := 175/255;
+ //B := 247/255;
glColor3f(1, 1, 1);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-//// if Player[NrGracza].IlNut > 0 then
+ //if Player[NrGracza].LengthNote > 0 then
+ begin
+ TempR := W / (Lines[0].Line[Lines[0].Current].End_ - Lines[0].Line[Lines[0].Current].Note[0].Start);
+ for N := 0 to Player[PlayerIndex].HighNote do
begin
- TempR := W / (Lines[0].Line[Lines[0].Current].End_ - Lines[0].Line[Lines[0].Current].Note[0].Start);
- for N := 0 to Player[NrGracza].HighNote do
+ with Player[PlayerIndex].Note[N] do
+ begin
+ // Left part of note
+ Rec.Left := X + (Start-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR + 0.5 + 10*ScreenX;
+ Rec.Right := Rec.Left + NotesW;
+
+ // Draw it in half size, if not hit
+ if Hit then
+ begin
+ NotesH2 := NotesH
+ end
+ else
+ begin
+ NotesH2 := int(NotesH * 0.65);
+ end;
+
+ Rec.Top := Y - (Tone-Lines[0].Line[Lines[0].Current].BaseNote)*Space/2 - NotesH2;
+ Rec.Bottom := Rec.Top + 2 *NotesH2;
+
+ // draw the left part
+ glColor3f(1, 1, 1);
+ glBindTexture(GL_TEXTURE_2D, Tex_Left[PlayerIndex+1].TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+
+ // Middle part of the note
+ Rec.Left := Rec.Right;
+ Rec.Right := X + (Start+Length-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR - NotesW - 0.5 + 10*ScreenX;
+
+ // (nowe) - dunno
+ if (Start+Length-1 = LineState.CurrentBeatD) then
+ Rec.Right := Rec.Right - (1-Frac(LineState.MidBeatD)) * TempR;
+ // the left note is more right than the right note itself, sounds weird - so we fix that xD
+ if Rec.Right <= Rec.Left then
+ Rec.Right := Rec.Left;
+
+ // draw the middle part
+ glBindTexture(GL_TEXTURE_2D, Tex_Mid[PlayerIndex+1].TexNum);
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(round((Rec.Right-Rec.Left)/32), 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(round((Rec.Right-Rec.Left)/32), 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+ glColor3f(1, 1, 1);
+
+ // the right part of the note
+ Rec.Left := Rec.Right;
+ Rec.Right := Rec.Right + NotesW;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_Right[PlayerIndex+1].TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+
+ // Perfect note is stored
+ if Perfect and (Ini.EffectSing=1) then
+ begin
+ A := 1 - 2*(LineState.CurrentTime - GetTimeFromBeat(Start+Length));
+ if not (Start+Length-1 = LineState.CurrentBeatD) then
begin
- with Player[NrGracza].Note[N] do
- begin
- // Left part of note
- Rec.Left := X + (Start-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR + 0.5 + 10*ScreenX;
- Rec.Right := Rec.Left + NotesW;
-
- // Draw it in half size, if not hit
- if Hit then
- begin
- NotesH2 := NotesH
- end
- else
- begin
- NotesH2 := int(NotesH * 0.65);
- end;
-
- Rec.Top := Y - (Tone-Lines[0].Line[Lines[0].Current].BaseNote)*Space/2 - NotesH2;
- Rec.Bottom := Rec.Top + 2 *NotesH2;
-
- // draw the left part
- glColor3f(1, 1, 1);
- glBindTexture(GL_TEXTURE_2D, Tex_Left[NrGracza+1].TexNum);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
-
- // Middle part of the note
- Rec.Left := Rec.Right;
- Rec.Right := X + (Start+Length-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR - NotesW - 0.5 + 10*ScreenX;
-
- // (nowe) - dunno
- if (Start+Length-1 = LineState.CurrentBeatD) then
- Rec.Right := Rec.Right - (1-Frac(LineState.MidBeatD)) * TempR;
- // the left note is more right than the right note itself, sounds weird - so we fix that xD
- if Rec.Right <= Rec.Left then Rec.Right := Rec.Left;
-
- // draw the middle part
- glBindTexture(GL_TEXTURE_2D, Tex_Mid[NrGracza+1].TexNum);
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(round((Rec.Right-Rec.Left)/32), 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(round((Rec.Right-Rec.Left)/32), 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
- glColor3f(1, 1, 1);
-
- // the right part of the note
- Rec.Left := Rec.Right;
- Rec.Right := Rec.Right + NotesW;
-
- glBindTexture(GL_TEXTURE_2D, Tex_Right[NrGracza+1].TexNum);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
-
- // Perfect note is stored
- if Perfect and (Ini.EffectSing=1) then
- begin
- A := 1 - 2*(LineState.CurrentTime - GetTimeFromBeat(Start+Length));
- if not (Start+Length-1 = LineState.CurrentBeatD) then
-
- //Star animation counter
- //inc(Starfr);
- //Starfr := Starfr mod 128;
- GoldenRec.SavePerfectNotePos(Rec.Left, Rec.Top);
- end;
- end; // with
- end; // for
- // eigentlich brauchen wir hier einen vergleich, um festzustellen, ob wir mit
- // singen schon weiter wären, als bei Rec.Right, _auch, wenn nicht gesungen wird_
- // English Translation:
- // actually we need a compare here, to determine if the singing process is ahead Rec.Right
- // even if there is no singing
-
-
- // passing on NrGracza... hope this is really something like the player-number, not only
- // some kind of weird index into a colour-table
-
- if (Ini.EffectSing=1) then
- GoldenRec.GoldenNoteTwinkle(Rec.Top,Rec.Bottom,Rec.Right, NrGracza);
+ //Star animation counter
+ //inc(Starfr);
+ //Starfr := Starfr mod 128;
+ GoldenRec.SavePerfectNotePos(Rec.Left, Rec.Top);
+ end;
+ end;
+ end; // with
+ end; // for
+
+ // actually we need a comparison here, to determine if the singing process
+ // is ahead Rec.Right even if there is no singing
+
+ if (Ini.EffectSing = 1) then
+ GoldenRec.GoldenNoteTwinkle(Rec.Top,Rec.Bottom,Rec.Right, PlayerIndex);
end; // if
end;
//draw Note glow
-procedure SingDrawPlayerBGLine(Left, Top, Right: real; NrLines, NrGracza: integer; Space: integer);
+procedure SingDrawPlayerBGLine(Left, Top, Right: real; NrLines, PlayerIndex: integer; Space: integer);
var
Rec: TRecR;
Count: integer;
@@ -472,87 +465,89 @@ var lTmpA ,
lTmpB : real;
begin
- if (Player[NrGracza].ScoreTotalI >= 0) then begin
- glColor4f(1, 1, 1, sqrt((1+sin( AudioPlayback.Position * 3))/4)/ 2 + 0.5 );
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-
- lTmpA := (Right-Left);
- lTmpB := (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start);
-
-
- if ( lTmpA > 0 ) AND
- ( lTmpB > 0 ) THEN
- begin
- TempR := lTmpA / lTmpB;
- end
- else
+ if (Player[PlayerIndex].ScoreTotalInt >= 0) then
begin
- TempR := 0;
- end;
-
- with Lines[NrLines].Line[Lines[NrLines].Current] do begin
- for Count := 0 to HighNote do begin
- with Note[Count] do begin
- if NoteType <> ntFreestyle then begin
- // begin: 14, 20
- // easy: 6, 11
- W := NotesW * 2 + 2;
- H := NotesH * 1.5 + 3.5;
-
- X2 := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX + 4; // wciecie
- X1 := X2-W;
-
- X3 := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - 0.5 + 10*ScreenX - 4; // wciecie
- X4 := X3+W;
-
- // left
- Rec.Left := X1;
- Rec.Right := X2;
- Rec.Top := Top - (Tone-BaseNote)*Space/2 - H;
- Rec.Bottom := Rec.Top + 2 * H;
-
- glBindTexture(GL_TEXTURE_2D, Tex_BG_Left[NrGracza+1].TexNum);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
-
-
- // srodkowa czesc
- Rec.Left := X2;
- Rec.Right := X3;
+ glColor4f(1, 1, 1, sqrt((1+sin( AudioPlayback.Position * 3))/4)/ 2 + 0.5 );
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glBindTexture(GL_TEXTURE_2D, Tex_BG_Mid[NrGracza+1].TexNum);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
+ lTmpA := (Right-Left);
+ lTmpB := (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start);
- // prawa czesc
- Rec.Left := X3;
- Rec.Right := X4;
+ if ( lTmpA > 0 ) and
+ ( lTmpB > 0 ) then
+ begin
+ TempR := lTmpA / lTmpB;
+ end
+ else
+ begin
+ TempR := 0;
+ end;
- glBindTexture(GL_TEXTURE_2D, Tex_BG_Right[NrGracza+1].TexNum);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
- glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
- glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
- glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
- glEnd;
- end; // if not FreeStyle
- end; // with
- end; // for
- end; // with 1
+ with Lines[NrLines].Line[Lines[NrLines].Current] do
+ begin
+ for Count := 0 to HighNote do
+ begin
+ with Note[Count] do
+ begin
+ if NoteType <> ntFreestyle then
+ begin
+ // begin: 14, 20
+ // easy: 6, 11
+ W := NotesW * 2 + 2;
+ H := NotesH * 1.5 + 3.5;
+
+ X2 := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX + 4; // wciecie
+ X1 := X2-W;
+
+ X3 := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - 0.5 + 10*ScreenX - 4; // wciecie
+ X4 := X3+W;
+
+ // left
+ Rec.Left := X1;
+ Rec.Right := X2;
+ Rec.Top := Top - (Tone-BaseNote)*Space/2 - H;
+ Rec.Bottom := Rec.Top + 2 * H;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_BG_Left[PlayerIndex+1].TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+
+ // srodkowa czesc
+ Rec.Left := X2;
+ Rec.Right := X3;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_BG_Mid[PlayerIndex+1].TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+
+ // prawa czesc
+ Rec.Left := X3;
+ Rec.Right := X4;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_BG_Right[PlayerIndex+1].TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+ end; // if not FreeStyle
+ end; // with
+ end; // for
+ end; // with
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
end;
end;
diff --git a/Game/Code/Classes/UFiles.pas b/Game/Code/Classes/UFiles.pas index 6b506574..af434b94 100644 --- a/Game/Code/Classes/UFiles.pas +++ b/Game/Code/Classes/UFiles.pas @@ -47,7 +47,7 @@ begin Lines[Count].Line[0].Lyric := ''; Lines[Count].Line[0].LyricWidth := 0; Player[Count].Score := 0; - Player[Count].IlNut := 0; + Player[Count].LengthNote := 0; Player[Count].HighNote := -1; end; diff --git a/Game/Code/Classes/UIni.pas b/Game/Code/Classes/UIni.pas index 0f31649c..5e651be0 100644 --- a/Game/Code/Classes/UIni.pas +++ b/Game/Code/Classes/UIni.pas @@ -15,6 +15,21 @@ uses SysUtils; type + // TInputDeviceConfig stores the configuration for an input device. + // Configurations will be stored in the InputDeviceConfig array. + // Note that not all devices listed in InputDeviceConfig are active devices. + // Some might be unplugged and hence unavailable. + // Available devices are held in TAudioInputProcessor.DeviceList. Each + // TAudioInputDevice listed there has a CfgIndex field which is the index to + // its configuration in the InputDeviceConfig array. + // Name: + // the name of the input device + // Input: + // the index of the input source to use for recording + // ChannelToPlayerMap: + // mapping of recording channels to players, e.g. ChannelToPlayerMap[0] = 2 + // maps the channel 0 (left) to player 2. A player index of 0 means that + // the channel is not assigned to a player. PInputDeviceConfig = ^TInputDeviceConfig; TInputDeviceConfig = record Name: string; diff --git a/Game/Code/Classes/UMain.pas b/Game/Code/Classes/UMain.pas index 3e1a4ea1..f83830bb 100644 --- a/Game/Code/Classes/UMain.pas +++ b/Game/Code/Classes/UMain.pas @@ -25,6 +25,17 @@ uses UThemes; type + PPLayerNote = ^TPlayerNote; + TPlayerNote = record + Start: integer; + Length: integer; + Detect: real; // accurate place, detected in the note + Tone: real; + Perfect: boolean; // true if the note matches the original one, lit the star + Hit: boolean; // true if the note Hits the Line + end; + + PPLayer = ^TPlayer; TPlayer = record Name: string; @@ -37,10 +48,10 @@ type ScoreLine: real; ScoreGolden: real; - ScoreI: integer; - ScoreLineI: integer; - ScoreGoldenI: integer; - ScoreTotalI: integer; + ScoreInt: integer; + ScoreLineInt: integer; + ScoreGoldenInt: integer; + ScoreTotalInt: integer; // LineBonus Mod ScoreLast: Real;//Last Line Score @@ -50,18 +61,9 @@ type //Meter: real; - HighNote: integer; - IlNut: integer; - Note: array of record - Start: integer; - Length: integer; - Detekt: real; // accurate place, detected in the note - Tone: 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; + HighNote: integer; // index of last note (= High(Note)?) + LengthNote: integer; // number of notes (= Length(Note)?). + Note: array of TPlayerNote; end; @@ -85,10 +87,10 @@ var UserCoversPath: string = ''; UserPlaylistPath: string = ''; - OGL: Boolean; Done: Boolean; Event: TSDL_event; - FileName: string; + // FIXME: ConversionFileName should not be global + ConversionFileName: string; Restart: boolean; // player and music info @@ -97,18 +99,22 @@ var CurrentSong : TSong; +const + MAX_SONG_SCORE = 10000; // max. achievable points per song + MAX_SONG_LINE_BONUS = 1000; // max. achievable line bonus per song + procedure InitializePaths; Procedure Main; procedure MainLoop; procedure CheckEvents; -procedure Sing(Sender: TScreenSing); -procedure NewSentence(Sender: TScreenSing); -procedure NewBeat(Sender: TScreenSing); // executed when on then new beat -procedure NewBeatC(Sender: TScreenSing); // executed when on then new beat for click -procedure NewBeatD(Sender: TScreenSing); // executed when on then new beat for detection +procedure Sing(Screen: TScreenSing); +procedure NewSentence(Screen: TScreenSing); +procedure NewBeat(Screen: TScreenSing); // executed when on then new beat +procedure NewBeatClick(Screen: TScreenSing); // executed when on then new beat for click +procedure NewBeatDetect(Screen: TScreenSing); // executed when on then new beat for detection //procedure NewHalf; // executed when in the half between beats -procedure NewNote(Sender: TScreenSing); // detect note +procedure NewNote(Screen: TScreenSing); // detect note function GetMidBeat(Time: real): real; function GetTimeFromBeat(Beat: integer): real; procedure ClearScores(PlayerNum: integer); @@ -206,7 +212,7 @@ begin Ini := TIni.Create; Ini.Load; - //Load Languagefile + // Load Languagefile if (Params.Language <> -1) then Language.ChangeLanguage(ILanguage[Params.Language]) else @@ -477,30 +483,29 @@ begin glViewPort(0, 0, ScreenW, ScreenH); end - // ScreenShot hack. If Print is pressed-> Make screenshot and Save to Screenshots Path + // if print is pressed -> make screenshot and save to screenshot path else if (Event.key.keysym.sym = SDLK_SYSREQ) or (Event.key.keysym.sym = SDLK_PRINT) then Display.SaveScreenShot - // popup hack... if there is a visible popup then let it handle input instead of underlying screen + // 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, WideChar(Event.key.keysym.unicode), True) else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, WideChar(Event.key.keysym.unicode), True) - // end of popup hack else begin - // check for Screen want to Exit + // check if screen wants to exit done := not Display.CurrentScreen^.ParseInput(Event.key.keysym.sym, WideChar(Event.key.keysym.unicode), True); - // If Screen wants to Exit + // if screen wants to exit if done then begin - // If Question Option is enabled then Show Exit Popup + // if question option is enabled then show exit popup if (Ini.AskbeforeDel = 1) then begin Display.CurrentScreen^.CheckFadeTo(nil,'MSG_QUIT_USDX'); end - else // When asking for exit is disabled then simply exit + else // if ask-for-exit is disabled then simply exit begin Display.Fade := 0; Display.NextScreenWithCheck := nil; @@ -510,18 +515,16 @@ begin end; end; - { SDL_JOYAXISMOTION: begin // not implemented end; - } SDL_JOYBUTTONDOWN: begin // not implemented end; - end; // Case - end; // While + end; // case + end; // while end; function GetTimeForBeats(BPM, Beats: real): real; @@ -570,17 +573,18 @@ function GetMidBeat(Time: real): real; var CurBeat: real; CurBPM: integer; -// TopBeat: real; -// TempBeat: real; -// TempTime: real; + //TopBeat: real; + //TempBeat: real; + //TempTime: real; begin Result := 0; if Length(CurrentSong.BPM) = 1 then Result := Time * CurrentSong.BPM[0].BPM / 60; - (* 2 BPMs *) -{ if Length(CurrentSong.BPM) > 1 then begin - (* new system *) + // 2 BPMs + { + if Length(CurrentSong.BPM) > 1 then begin + // new system CurBeat := 0; TopBeat := GetBeats(CurrentSong.BPM[0].BPM, Time); if TopBeat > CurrentSong.BPM[1].StartBeat then begin @@ -593,12 +597,13 @@ begin end else begin - (* pierwszy przedzial *) + // first part Result := TopBeat; end; - end;} + end; + } - (* more BPMs *) + // more BPMs if Length(CurrentSong.BPM) > 1 then begin CurBeat := 0; @@ -621,7 +626,7 @@ begin if Length(CurrentSong.BPM) = 1 then Result := CurrentSong.GAP / 1000 + Beat * 60 / CurrentSong.BPM[0].BPM; - (* more BPMs *) + // more BPMs if Length(CurrentSong.BPM) > 1 then begin Result := CurrentSong.GAP / 1000; @@ -657,7 +662,7 @@ begin end; // if} end; -procedure Sing(Sender: TScreenSing); +procedure Sing(Screen: TScreenSing); var Count: integer; CountGr: integer; @@ -666,19 +671,22 @@ var N: integer; begin LineState.OldBeat := LineState.CurrentBeat; - LineState.MidBeat := GetMidBeat(LineState.CurrentTime - (CurrentSong.Gap{ + 90 I've forgotten for what it is}) / 1000); // new system with variable BPM in function + // new system with variable BPM in function + LineState.MidBeat := GetMidBeat(LineState.CurrentTime - + (CurrentSong.Gap {+ 90 I've forgotten for what it is}) / 1000); LineState.CurrentBeat := Floor(LineState.MidBeat); -// LineState.OldHalf := LineState.AktHalf; -// LineState.MidHalf := LineState.MidBeat + 0.5; -// LineState.AktHalf := Floor(LineState.MidHalf); + //LineState.OldHalf := LineState.AktHalf; + //LineState.MidHalf := LineState.MidBeat + 0.5; + //LineState.AktHalf := Floor(LineState.MidHalf); LineState.OldBeatC := LineState.CurrentBeatC; LineState.MidBeatC := GetMidBeat(LineState.CurrentTime - (CurrentSong.Gap) / 1000); LineState.CurrentBeatC := Floor(LineState.MidBeatC); LineState.OldBeatD := LineState.CurrentBeatD; - LineState.MidBeatD := -0.5+GetMidBeat(LineState.CurrentTime - (CurrentSong.Gap + 120 + 20) / 1000); // MidBeat with addition GAP + // MidBeat with additional GAP + LineState.MidBeatD := -0.5+GetMidBeat(LineState.CurrentTime - (CurrentSong.Gap + 120 + 20) / 1000); LineState.CurrentBeatD := Floor(LineState.MidBeatD); LineState.FracBeatD := Frac(LineState.MidBeatD); @@ -686,40 +694,40 @@ begin for CountGr := 0 to 0 do //High(Gracz) begin; CP := CountGr; - // ustawianie starej parts + // old parts LineState.OldLine := Lines[CP].Current; - // wybieranie aktualnej parts + // choose current parts for Count := 0 to Lines[CP].High do begin if LineState.CurrentBeat >= Lines[CP].Line[Count].Start then Lines[CP].Current := Count; end; - // czysczenie nut gracza, gdy to jest nowa plansza - // (optymizacja raz na halfbeat jest zla) + // clean player note if there is a new line + // (optimization on halfbeat time) if Lines[CP].Current <> LineState.OldLine then - NewSentence(Sender); + NewSentence(Screen); end; // for CountGr - // wykonuje operacje raz na beat + // execute operations on beat if (LineState.CurrentBeat >= 0) and (LineState.OldBeat <> LineState.CurrentBeat) then - NewBeat(Sender); + NewBeat(Screen); // make some operations on clicks if {(LineState.CurrentBeatC >= 0) and }(LineState.OldBeatC <> LineState.CurrentBeatC) then - NewBeatC(Sender); + NewBeatClick(Screen); // make some operations when detecting new voice pitch if (LineState.CurrentBeatD >= 0) and (LineState.OldBeatD <> LineState.CurrentBeatD) then - NewBeatD(Sender); + NewBeatDetect(Screen); - // wykonuje operacje w polowie beatu + // execute operations on beat field // if (LineState.AktHalf >= 1) and (LineState.OldHalf <> LineState.AktHalf) then // NewHalf; - // plynnie przesuwa text + // remove moving text Done := 1; for N := 0 to Lines[0].Line[Lines[0].Current].HighNote do begin @@ -732,40 +740,41 @@ begin N := Lines[0].Line[Lines[0].Current].HighNote; - // wylacza ostatnia nute po przejsciu + // if last note is used {// todo: Lyrics if (Ini.LyricsEffect = 1) and (Done = 1) and (LineState.MidBeat > Lines[0].Line[Lines[0].Current].Note[N].Start + Lines[0].Line[Lines[0].Current].Note[N].Length) - then Sender.LyricMain.Selected := -1; + then Screen.LyricMain.Selected := -1; if Done > 1 then Done := 1; - Sender.LyricMain.Done := Done; } + Screen.LyricMain.Done := Done; + } // use Done with LCD -{ with ScreenSing do begin + { + with ScreenSing do begin if LyricMain.Selected >= 0 then begin LCD.MoveCursor(1, LyricMain.SelectedLetter + Round((LyricMain.SelectedLength-1) * Done)); LCD.ShowCursor; end; - end;} - - + end; + } end; -procedure NewSentence(Sender: TScreenSing); +procedure NewSentence(Screen: TScreenSing); var -G: Integer; + i: Integer; begin - // czyszczenie nut graczy - for G := 0 to High(Player) do + // clean note of player + for i := 0 to High(Player) do begin - Player[G].IlNut := 0; - Player[G].HighNote := -1; - SetLength(Player[G].Note, 0); + Player[i].LengthNote := 0; + Player[i].HighNote := -1; + SetLength(Player[i].Note, 0); end; - // Add Words to Lyrics - with Sender do + // add words to lyrics + with Screen do begin {LyricMain.AddCzesc(Lines[0].Current); if Lines[0].Current < Lines[0].High then @@ -776,19 +785,19 @@ begin Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); end; - //Sender.UpdateLCD; + //Screen.UpdateLCD; - //On Sentence Change... - Sender.onSentenceChange(Lines[0].Current); + // on sentence change... + Screen.onSentenceChange(Lines[0].Current); end; -procedure NewBeat(Sender: TScreenSing); +procedure NewBeat(Screen: TScreenSing); var Count: integer; -// TempBeat: integer; + //TempBeat: integer; begin - // ustawia zaznaczenie tekstu -// SingScreen.LyricMain.Selected := -1; + // add a text mark + //SingScreen.LyricMain.Selected := -1; for Count := 0 to Lines[0].Line[Lines[0].Current].HighNote do if (Lines[0].Line[Lines[0].Current].Note[Count].Start = LineState.CurrentBeat) then begin @@ -796,45 +805,48 @@ begin //Todo: Lyrics //Sender.LyricMain.Selected := Count; -// LCD.MoveCursor(1, ScreenSing.LyricMain.SelectedLetter); -// LCD.ShowCursor; + //LCD.MoveCursor(1, ScreenSing.LyricMain.SelectedLetter); + //LCD.ShowCursor; //LCD.MoveCursorBR(Sender.LyricMain.SelectedLetter); //LCD.ShowCursor; end; end; -procedure NewBeatC; +procedure NewBeatClick; var Count: integer; -// LPT_1: integer; -// LPT_2: integer; + //LPT_1: integer; + //LPT_2: integer; begin -// LPT_1 := 1; -// LPT_2 := 1; + //LPT_1 := 1; + //LPT_2 := 1; // beat click - if (Ini.BeatClick = 1) and ((LineState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod Lines[0].Resolution = 0) then + if ((Ini.BeatClick = 1) and + ((LineState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod Lines[0].Resolution = 0)) then + begin AudioPlayback.PlaySound(SoundLib.Click); + end; + { // debug system on LPT if ((LineState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod Lines[0].Resolution = 0) then begin - //LPT_1 := 0; -// Light.LightOne(0, 150); + LPT_1 := 0; + Light.LightOne(0, 150); - (* Light.LightOne(1, 200); // beat light if ParamStr(1) = '-doublelights' then Light.LightOne(0, 200); // beat light - *) -{ if ((LineState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod (Lines[0].Resolution * 2) = 0) then + if ((LineState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod (Lines[0].Resolution * 2) = 0) then Light.LightOne(0, 150) else - Light.LightOne(1, 150)} + Light.LightOne(1, 150) end; + } for Count := 0 to Lines[0].Line[Lines[0].Current].HighNote do begin @@ -844,113 +856,127 @@ begin if Ini.ClickAssist = 1 then AudioPlayback.PlaySound(SoundLib.Click); + { //LPT_2 := 0; - (* if ParamStr(1) <> '-doublelights' then Light.LightOne(0, 150); //125 - *) + } // drum machine (* TempBeat := LineState.CurrentBeat;// + 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 = 2) then Music.PlayHihat; if (TempBeat mod 4 <> 0) then Music.PlayHihat; *) end; end; {$IFDEF UseSerialPort} - // PortWriteB($378, LPT_1 + LPT_2 * 2); // 0 zapala + // PortWriteB($378, LPT_1 + LPT_2 * 2); // 0 light {$ENDIF} end; -procedure NewBeatD(Sender: TScreenSing); +procedure NewBeatDetect(Screen: TScreenSing); begin - NewNote(Sender); + NewNote(Screen); end; -procedure NewNote(Sender: TScreenSing); +procedure NewNote(Screen: TScreenSing); var - CP: integer; // current player - S: integer; // sentence - SMin: integer; - SMax: integer; - SDet: integer; // temporary: sentence of detected note - Count: integer; - Mozna: boolean; - New: boolean; - Range: integer; - NoteHit:boolean; - MaxPoints: integer; // maximal points without line bonus + LineFragmentIndex: integer; + CurrentLineFragment: PLineFragment; + PlayerIndex: integer; + CurrentSound: TCaptureBuffer; + CurrentPlayer: PPlayer; + LastPlayerNote: PPLayerNote; + Line: PLine; + SentenceIndex: integer; + SentenceMin: integer; + SentenceMax: integer; + SentenceDetected: integer; // sentence of detected note + NoteAvailable: boolean; + NewNote: boolean; + Range: integer; + NoteHit: boolean; + MaxSongPoints: integer; // max. points for the song (without line bonus) + MaxLinePoints: Real; // max. points for the current line begin - // Log.LogStatus('Beat ' + IntToStr(LineState.CurrentBeat) + ' HalfBeat ' + IntToStr(LineState.AktHalf), 'NewBeat'); - - // On linux we get an AV @ NEWNOTE, line 600 of Classes/UMain.pas - if not assigned( AudioInputProcessor.Sound ) then - exit; - - // analizuje dla obu graczy ten sam sygnal (Sound.OneSrcForBoth) - // albo juz lepiej nie - for CP := 0 to PlayersPlay-1 do - begin - // analyze buffer - AudioInputProcessor.Sound[CP].AnalyzeBuffer; + //Log.LogStatus('Beat ' + IntToStr(LineState.CurrentBeat) + ' HalfBeat ' + IntToStr(LineState.AktHalf), 'NewBeat'); - // adds some noise - //LineState.Tone := LineState.Tone + Round(Random(3)) - 1; + // TODO: add duet mode support + // use Lines[LineSetIndex] with LineSetIndex depending on the current player - // count min and max sentence range for checking (detection is delayed to the notes we see on the screen) - SMin := Lines[0].Current-1; - if SMin < 0 then - SMin := 0; - SMax := Lines[0].Current; + // count min and max sentence range for checking (detection is delayed to the notes we see on the screen) + SentenceMin := Lines[0].Current-1; + if (SentenceMin < 0) then + SentenceMin := 0; + SentenceMax := Lines[0].Current; - // check if we can add new note - Mozna := false; - SDet:=SMin; - for S := SMin to SMax do + // check for an active note at the current time defined in the lyrics + NoteAvailable := false; + SentenceDetected := SentenceMin; + for SentenceIndex := SentenceMin to SentenceMax do + begin + Line := @Lines[0].Line[SentenceIndex]; + for LineFragmentIndex := 0 to Line.HighNote do begin - for Count := 0 to Lines[0].Line[S].HighNote do + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + // check if line is active + if ((CurrentLineFragment.Start <= LineState.CurrentBeatD) and + (CurrentLineFragment.Start + CurrentLineFragment.Length-1 >= LineState.CurrentBeatD)) and + (CurrentLineFragment.NoteType <> ntFreestyle) and // but ignore FreeStyle notes + (CurrentLineFragment.Length > 0) then // and make sure the note lengths is at least 1 begin - if ((Lines[0].Line[S].Note[Count].Start <= LineState.CurrentBeatD) - and (Lines[0].Line[S].Note[Count].Start + Lines[0].Line[S].Note[Count].Length - 1 >= LineState.CurrentBeatD)) - and (Lines[0].Line[S].Note[Count].NoteType <> ntFreestyle) // but don't allow when it's FreeStyle note - and (Lines[0].Line[S].Note[Count].Length > 0) then // and make sure the note lengths is at least 1 - begin - SDet := S; - Mozna := true; - Break; - end; + SentenceDetected := SentenceIndex; + NoteAvailable := true; + Break; end; end; + // TODO: break here, if NoteAvailable is true? We would then use the first instead + // of the last note matching the current beat if notes overlap. But notes + // should not overlap at all. + //if (NoteAvailable) then + // Break; + end; - S := SDet; + // analyze player signals + for PlayerIndex := 0 to PlayersPlay-1 do + begin + CurrentPlayer := @Player[PlayerIndex]; + CurrentSound := AudioInputProcessor.Sound[PlayerIndex]; + LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote]; - //Czas.SzczytJest := true; - //Czas.Tone := 27; + // analyze buffer + CurrentSound.AnalyzeBuffer; + + // add some noise + // TODO: do we need this? + //LineState.Tone := LineState.Tone + Round(Random(3)) - 1; - // gdy moze, to dodaje nute - When Mozna, it adds note (?) - if (AudioInputProcessor.Sound[CP].ToneValid) and (Mozna) then + // add note if possible + if (CurrentSound.ToneValid and NoteAvailable) then begin - // operowanie na ostatniej nucie - for Count := 0 to Lines[0].Line[S].HighNote do + Line := @Lines[0].Line[SentenceDetected]; + + // process until last note + for LineFragmentIndex := 0 to Line.HighNote do begin - if (Lines[0].Line[S].Note[Count].Start <= LineState.OldBeatD+1) and - (Lines[0].Line[S].Note[Count].Start + - Lines[0].Line[S].Note[Count].Length > LineState.OldBeatD+1) then + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + if (CurrentLineFragment.Start <= LineState.OldBeatD+1) and + (CurrentLineFragment.Start + CurrentLineFragment.Length > LineState.OldBeatD+1) then begin - // to robi, tylko dla pary nut (oryginalnej i gracza) + // compare notes (from song-file and from player) - // przesuwanie tonu w odpowiednia game - while (AudioInputProcessor.Sound[CP].Tone - Lines[0].Line[S].Note[Count].Tone > 6) do - AudioInputProcessor.Sound[CP].Tone := AudioInputProcessor.Sound[CP].Tone - 12; + // move players tone to proper octave + while (CurrentSound.Tone - CurrentLineFragment.Tone > 6) do + CurrentSound.Tone := CurrentSound.Tone - 12; - while (AudioInputProcessor.Sound[CP].Tone - Lines[0].Line[S].Note[Count].Tone < -6) do - AudioInputProcessor.Sound[CP].Tone := AudioInputProcessor.Sound[CP].Tone + 12; + while (CurrentSound.Tone - CurrentLineFragment.Tone < -6) do + CurrentSound.Tone := CurrentSound.Tone + 12; - // Half size Notes Patch + // half size notes patch NoteHit := false; //if Ini.Difficulty = 0 then Range := 2; @@ -958,96 +984,115 @@ begin //if Ini.Difficulty = 2 then Range := 0; Range := 2 - Ini.Difficulty; - if abs(Lines[0].Line[S].Note[Count].Tone - AudioInputProcessor.Sound[CP].Tone) <= Range then + // check if the player hit the correct tone within the tolerated range + if (Abs(CurrentLineFragment.Tone - CurrentSound.Tone) <= Range) then begin - AudioInputProcessor.Sound[CP].Tone := Lines[0].Line[S].Note[Count].Tone; + // adjust the players tone to the correct one + // TODO: do we need to do this? + CurrentSound.Tone := CurrentLineFragment.Tone; - // Half size Notes Patch + // half size notes patch NoteHit := true; - - MaxPoints := 10000; - if (Ini.LineBonus <> 0) then - MaxPoints := 9000; - - case Lines[0].Line[S].Note[Count].NoteType of - ntNormal: Player[CP].Score := Player[CP].Score + MaxPoints / Lines[0].ScoreValue; - ntGolden: Player[CP].ScoreGolden := Player[CP].ScoreGolden + MaxPoints / Lines[0].ScoreValue; + + if (Ini.LineBonus > 0) then + MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS + else + MaxSongPoints := MAX_SONG_SCORE; + + // Note: ScoreValue is the sum of all note values of the song + MaxLinePoints := MaxSongPoints / Lines[0].ScoreValue; + + // FIXME: is this correct? Why do we add the points for a whole line + // if just one note is correct? + case CurrentLineFragment.NoteType of + ntNormal: CurrentPlayer.Score := CurrentPlayer.Score + MaxLinePoints; + ntGolden: CurrentPlayer.ScoreGolden := CurrentPlayer.ScoreGolden + MaxLinePoints; end; - Player[CP].ScoreI := Floor(Player[CP].Score / 10) * 10; - Player[CP].ScoreGoldenI := Floor(Player[CP].ScoreGolden / 10) * 10; + CurrentPlayer.ScoreInt := Floor(CurrentPlayer.Score / 10) * 10; + CurrentPlayer.ScoreGoldenInt := Floor(CurrentPlayer.ScoreGolden / 10) * 10; - Player[CP].ScoreTotalI := Player[CP].ScoreI + Player[CP].ScoreGoldenI + Player[CP].ScoreLineI; + CurrentPlayer.ScoreTotalInt := CurrentPlayer.ScoreInt + + CurrentPlayer.ScoreGoldenInt + + CurrentPlayer.ScoreLineInt; end; - end; // operowanie + end; // operation end; // for - // sprawdzanie czy to nowa nuta, czy przedluzenie - if S = SMax then + // check if we have to add a new note or extend the note's length + if (SentenceDetected = SentenceMax) then begin - New := true; + // we will add a new note + NewNote := true; // if last has the same tone - if (Player[CP].IlNut > 0 ) and - (Player[CP].Note[Player[CP].HighNote].Tone = AudioInputProcessor.Sound[CP].Tone) and - (Player[CP].Note[Player[CP].HighNote].Start + Player[CP].Note[Player[CP].HighNote].Length = LineState.CurrentBeatD) then + if ((CurrentPlayer.LengthNote > 0) and + (LastPlayerNote.Tone = CurrentSound.Tone) and + ((LastPlayerNote.Start + LastPlayerNote.Length) = LineState.CurrentBeatD)) then begin - New := false; + NewNote := false; end; - // if is not as new note to control "beacie" (TODO: translate polish "beacie") - for Count := 0 to Lines[0].Line[S].HighNote do + // if is not as new note to control + for LineFragmentIndex := 0 to Line.HighNote do begin - if (Lines[0].Line[S].Note[Count].Start = LineState.CurrentBeatD) then - New := true; + if (Line.Note[LineFragmentIndex].Start = LineState.CurrentBeatD) then + NewNote := true; end; - // dodawanie nowej nuty - if New then + // add new note + if NewNote then begin - // New Note - Player[CP].IlNut := Player[CP].IlNut + 1; - Player[CP].HighNote := Player[CP].HighNote + 1; - SetLength(Player[CP].Note, Player[CP].IlNut); - Player[CP].Note[Player[CP].HighNote].Start := LineState.CurrentBeatD; - Player[CP].Note[Player[CP].HighNote].Length := 1; - Player[CP].Note[Player[CP].HighNote].Tone := AudioInputProcessor.Sound[CP].Tone; // Ton || TonDokl - Player[CP].Note[Player[CP].HighNote].Detekt := LineState.MidBeat; - - // Half Note Patch - Player[CP].Note[Player[CP].HighNote].Hit := NoteHit; - - //Log.LogStatus('New Note ' + IntToStr(Gracz.Note[Gracz.HighNote].Start), 'NewBeat'); + // new note + Inc(CurrentPlayer.LengthNote); + Inc(CurrentPlayer.HighNote); + SetLength(CurrentPlayer.Note, CurrentPlayer.LengthNote); + + // update player's last note + LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote]; + with LastPlayerNote^ do + begin + Start := LineState.CurrentBeatD; + Length := 1; + Tone := CurrentSound.Tone; // Tone || ToneAbs + Detect := LineState.MidBeat; + Hit := NoteHit; // half note patch + end; end else begin - // przedluzenie nuty - Player[CP].Note[Player[CP].HighNote].Length := Player[CP].Note[Player[CP].HighNote].Length + 1; + // extend note length + Inc(LastPlayerNote.Length); end; // check for perfect note and then lit the star (on Draw) - for Count := 0 to Lines[0].Line[S].HighNote do + for LineFragmentIndex := 0 to Line.HighNote do begin - if (Lines[0].Line[S].Note[Count].Start = Player[CP].Note[Player[CP].HighNote].Start) and - (Lines[0].Line[S].Note[Count].Length = Player[CP].Note[Player[CP].HighNote].Length) and - (Lines[0].Line[S].Note[Count].Tone = Player[CP].Note[Player[CP].HighNote].Tone) then + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + if (CurrentLineFragment.Start = LastPlayerNote.Start) and + (CurrentLineFragment.Length = LastPlayerNote.Length) and + (CurrentLineFragment.Tone = LastPlayerNote.Tone) then begin - Player[CP].Note[Player[CP].HighNote].Perfect := true; + LastPlayerNote.Perfect := true; end; end; - end; // if S = SMax + end; // if SentenceDetected = SentenceMax + + end; // if Detected + end; // for PlayerIndex - end; // if moze - end; // for CP - // Log.LogStatus('EndBeat', 'NewBeat'); + //Log.LogStatus('EndBeat', 'NewBeat'); - //On Sentence End -> For LineBonus + SingBar - if (sDet >= low(Lines[0].Line)) and (sDet <= high(Lines[0].Line)) then + // on sentence end -> for LineBonus and display of SingBar (rating pop-up) + if (SentenceDetected >= Low(Lines[0].Line)) and + (SentenceDetected <= High(Lines[0].Line)) then begin - if assigned( Sender ) and - ((Lines[0].Line[SDet].Note[Lines[0].Line[SDet].HighNote].Start + Lines[0].Line[SDet].Note[Lines[0].Line[SDet].HighNote].Length - 1) = LineState.CurrentBeatD) then + Line := @Lines[0].Line[SentenceDetected]; + CurrentLineFragment := @Line.Note[Line.HighNote]; + if ((CurrentLineFragment.Start + CurrentLineFragment.Length - 1) = LineState.CurrentBeatD) then begin - Sender.onSentenceEnd(sDet); + if assigned(Screen) then + Screen.OnSentenceEnd(SentenceDetected); end; end; @@ -1055,22 +1100,25 @@ 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; + with Player[PlayerNum] do + begin + Score := 0; + ScoreInt := 0; + ScoreLine := 0; + ScoreLineInt := 0; + ScoreGolden := 0; + ScoreGoldenInt := 0; + ScoreTotalInt := 0; + end; end; //-------------------- -// Function sets all Absolute Paths e.g. Song Path and makes sure the Directorys exist +// Function sets all absolute paths e.g. song path and makes sure the directorys exist //-------------------- procedure InitializePaths; - // Initialize a Path Variable - // After Setting Paths, make sure that Paths exist + // Initialize a path variable + // After setting paths, make sure that paths exist function initialize_path( out aPathVar : string; const aLocation : string ): boolean; var lWriteable: Boolean; diff --git a/Game/Code/Classes/UMusic.pas b/Game/Code/Classes/UMusic.pas index bad0aa86..35c67ae1 100644 --- a/Game/Code/Classes/UMusic.pas +++ b/Game/Code/Classes/UMusic.pas @@ -15,6 +15,25 @@ uses type TNoteType = (ntFreestyle, ntNormal, ntGolden); + (** + * TLineFragment represents a fragment of a lyrics line. + * This is a text-fragment (e.g. a syllable) assigned to a note pitch, + * represented by a bar in the sing-screen. + *) + PLineFragment = ^TLineFragment; + TLineFragment = record + Color: integer; + Start: integer; // beat the fragment starts at + Length: integer; // length in beats + Tone: integer; // full range tone + Text: string; // text assigned to this fragment (a syllable, word, etc.) + NoteType: TNoteType; // note-type: golden-note/freestyle etc. + end; + + (** + * TLine represents one lyrics line and consists of multiple + * notes. + *) PLine = ^TLine; TLine = record Start: integer; @@ -22,31 +41,31 @@ type LyricWidth: real; End_: integer; BaseNote: integer; - HighNote: integer; - TotalNotes: integer; + HighNote: integer; // index of last note in line (= High(Note)?) + TotalNotes: integer; // value of all notes in the line LastLine: boolean; - Note: array of record - Color: integer; - Start: integer; - Length: integer; - Tone: integer; // full range tone - Text: string; - NoteType: TNoteType; - end; + Note: array of TLineFragment; end; - ALine = array of TLine; // (TODO: rename to TLineArray) + (** + * TLines stores sets of lyric lines and information on them. + * Normally just one set is defined but in duet mode it might for example + * contain two sets. + *) TLines = record - Current: integer; // for drawing of current line - High: integer; + Current: integer; // for drawing of current line + High: integer; // (= High(Line)?) Number: integer; Resolution: integer; NotesGAP: integer; ScoreValue: integer; - Line: ALine; + Line: array of TLine; end; - TLineState = class // all that concerns the current frames + (** + * TLineState contains all information that concerns the current frames + *) + TLineState = class private Timer: TRelativeTimer; // keeps track of the current time public @@ -56,12 +75,14 @@ type // now we use this for super synchronization! // only used when analyzing voice + // TODO: change ...D to ...Detect(ed) OldBeatD: integer; // previous discovered beat CurrentBeatD: integer; MidBeatD: real; // like CurrentBeatD FracBeatD: real; // fractional part of MidBeatD // we use this for audible clicks + // TODO: Change ...C to ...Click OldBeatC: integer; // previous discovered beat CurrentBeatC: integer; MidBeatC: real; // like CurrentBeatC diff --git a/Game/Code/Classes/UParty.pas b/Game/Code/Classes/UParty.pas index 9fdcf7a6..5b9d2400 100644 --- a/Game/Code/Classes/UParty.pas +++ b/Game/Code/Classes/UParty.pas @@ -450,12 +450,12 @@ begin begin
// to-do : recode Percentage stuff
//PlayerInfo.Playerinfo[I].Percentage := PlayerInfo.Playerinfo[I].Score div 9999;
- if (Player[I].ScoreTotalI > MaxScore) then
+ if (Player[I].ScoreTotalInt > MaxScore) then
begin
- MaxScore := Player[I].ScoreTotalI;
+ MaxScore := Player[I].ScoreTotalInt;
Rounds[CurRound].Winner := 1 shl I;
end
- else if (Player[I].ScoreTotalI = MaxScore) AND (Player[I].ScoreTotalI <> 0) then
+ else if (Player[I].ScoreTotalInt = MaxScore) AND (Player[I].ScoreTotalInt <> 0) then
begin
Rounds[CurRound].Winner := Rounds[CurRound].Winner or (1 shl I);
end;
diff --git a/Game/Code/Classes/USingScores.pas b/Game/Code/Classes/USingScores.pas index dd326356..645f0f6e 100644 --- a/Game/Code/Classes/USingScores.pas +++ b/Game/Code/Classes/USingScores.pas @@ -22,7 +22,7 @@ uses UThemes, // but not testet yet // ////////////////////////////////////////////////////////////// -//Some Constances containing Options that could change by time +//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 @@ -853,14 +853,16 @@ var Diff: Real; begin //Only Draw if Player has a Position - If Players[Index].Position <> high(byte) then + 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 + if (((Players[Index].Position and 128) = 0) = (ScreenAct = 1) and + Players[index].RBVisible and + Players[index].Visible) then begin Position := @Positions[Players[Index].Position and 127]; - If (Enabled AND Players[Index].Enabled) then + if (Enabled AND Players[Index].Enabled) then begin //Move Position if Enabled Diff := Players[Index].RBTarget - Players[Index].RBPos; @@ -871,25 +873,25 @@ begin end; //Get Colors for RatingBar - If Players[index].RBPos <=0.22 then + if (Players[index].RBPos <= 0.22) then begin R := 1; G := 0; B := 0; end - Else If Players[index].RBPos <=0.42 then + 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 + else if (Players[index].RBPos <= 0.57) then begin R := 1; G := 1; B := 0; end - Else If Players[index].RBPos <=0.77 then + else if (Players[index].RBPos <= 0.77) then begin R := 1-(Players[index].RBPos-0.57)*5; G := 1; |