aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Classes
diff options
context:
space:
mode:
authorbrunzelchen <brunzelchen@b956fd51-792f-4845-bead-9b4dfca2ff2c>2010-02-19 17:18:42 +0000
committerbrunzelchen <brunzelchen@b956fd51-792f-4845-bead-9b4dfca2ff2c>2010-02-19 17:18:42 +0000
commit51ed8fe6f2ea9892e905e81cf5bad3960537eb40 (patch)
treea4dcb099343762dcb7bd7988f73de68c1959d3a5 /Game/Code/Classes
downloadusdx-51ed8fe6f2ea9892e905e81cf5bad3960537eb40.tar.gz
usdx-51ed8fe6f2ea9892e905e81cf5bad3960537eb40.tar.xz
usdx-51ed8fe6f2ea9892e905e81cf5bad3960537eb40.zip
Challenge MOD r7 alpha based on Ultrastar Deluxe v1.0.1a
for changes read Changelog.txt in folder Game git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/1.0.1 Challenge MOD@2107 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'Game/Code/Classes')
-rw-r--r--Game/Code/Classes/TextGL.pas345
-rw-r--r--Game/Code/Classes/UCatCovers.pas143
-rw-r--r--Game/Code/Classes/UCommandLine.pas280
-rw-r--r--Game/Code/Classes/UCovers.pas226
-rw-r--r--Game/Code/Classes/UDLLManager.pas226
-rw-r--r--Game/Code/Classes/UDataBase.pas500
-rw-r--r--Game/Code/Classes/UDraw.pas1715
-rw-r--r--Game/Code/Classes/UFiles.pas1153
-rw-r--r--Game/Code/Classes/UGraphic.pas564
-rw-r--r--Game/Code/Classes/UGraphicClasses.pas655
-rw-r--r--Game/Code/Classes/UHelp.pas401
-rw-r--r--Game/Code/Classes/UIni.pas820
-rw-r--r--Game/Code/Classes/UJoystick.pas273
-rw-r--r--Game/Code/Classes/ULCD.pas289
-rw-r--r--Game/Code/Classes/ULanguage.pas222
-rw-r--r--Game/Code/Classes/ULight.pas116
-rw-r--r--Game/Code/Classes/ULog.pas227
-rw-r--r--Game/Code/Classes/ULyrics.pas389
-rw-r--r--Game/Code/Classes/UMain.pas735
-rw-r--r--Game/Code/Classes/UMusic.pas951
-rw-r--r--Game/Code/Classes/UParty.pas433
-rw-r--r--Game/Code/Classes/UPartyM2.pas693
-rw-r--r--Game/Code/Classes/UPlaylist.pas453
-rw-r--r--Game/Code/Classes/UPliki.pas833
-rw-r--r--Game/Code/Classes/URecord.pas371
-rw-r--r--Game/Code/Classes/USkins.pas162
-rw-r--r--Game/Code/Classes/USongs.pas794
-rw-r--r--Game/Code/Classes/UTexture.pas884
-rw-r--r--Game/Code/Classes/UThemes.pas2611
-rw-r--r--Game/Code/Classes/UTime.pas81
-rw-r--r--Game/Code/Classes/UVideo.pas737
31 files changed, 18282 insertions, 0 deletions
diff --git a/Game/Code/Classes/TextGL.pas b/Game/Code/Classes/TextGL.pas
new file mode 100644
index 00000000..7ebe1151
--- /dev/null
+++ b/Game/Code/Classes/TextGL.pas
@@ -0,0 +1,345 @@
+unit TextGL;
+
+interface
+
+uses gl, SDL, UTexture, Classes, ULog;
+
+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 glPrintCut(text: pchar);
+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 SetFontAspectW(Aspect: real);
+
+type
+ TTextGL = record
+ X: real;
+ Y: real;
+ Text: string;
+ Size: real;
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ end;
+
+ TFont = record
+ Tex: TTexture;
+ Width: array[0..255] of byte;
+ AspectW: real;
+ Centered: boolean;
+ Done: real;
+ Outline: real;
+ Italic: boolean;
+ end;
+
+
+var
+ base: GLuint; // Base Display List For The Font Set
+ Fonts: array of TFont;
+ ActFont: integer;
+ PColR: real; // temps for glPrintDone
+ PColG: real;
+ PColB: real;
+
+implementation
+
+uses UMain, Windows, SysUtils, UGraphic;
+
+procedure BuildFont; // Build Our Bitmap Font
+var
+ font: HFONT; // Windows Font ID
+ h_dc: hdc;
+ Rejestr: TResourceStream;
+ Pet: integer;
+begin
+ ActFont := 0;
+
+ SetLength(Fonts, 5);
+ Fonts[0].Tex := Texture.LoadTexture(true, 'Font', 'PNG', 'Font', 0);
+ Fonts[0].Tex.H := 30;
+ Fonts[0].AspectW := 0.9;
+ Fonts[0].Done := -1;
+ Fonts[0].Outline := 0;
+
+ Fonts[1].Tex := Texture.LoadTexture(true, 'FontB', 'PNG', 'Font', 0);
+ Fonts[1].Tex.H := 30;
+ Fonts[1].AspectW := 1;
+ Fonts[1].Done := -1;
+ Fonts[1].Outline := 0;
+
+ Fonts[2].Tex := Texture.LoadTexture(true, 'FontO', 'PNG', 'Font Outline', 0);
+ Fonts[2].Tex.H := 30;
+ Fonts[2].AspectW := 0.95;
+ Fonts[2].Done := -1;
+ Fonts[2].Outline := 5;
+
+ Fonts[3].Tex := Texture.LoadTexture(true, 'FontO2', 'PNG', 'Font Outline 2', 0);
+ Fonts[3].Tex.H := 30;
+ Fonts[3].AspectW := 0.95;
+ Fonts[3].Done := -1;
+ Fonts[3].Outline := 4;
+
+{ Fonts[4].Tex := Texture.LoadTexture('FontO', 'BMP', 'Arrow', 0); // for score screen
+ Fonts[4].Tex.H := 30;
+ Fonts[4].AspectW := 0.95;
+ Fonts[4].Done := -1;
+ Fonts[4].Outline := 5;}
+
+
+ Rejestr := TResourceStream.Create(HInstance, 'Font', 'FNT');
+ Rejestr.Read(Fonts[0].Width, 256);
+ Rejestr.Free;
+
+ Rejestr := TResourceStream.Create(HInstance, 'FontB', 'FNT');
+ Rejestr.Read(Fonts[1].Width, 256);
+ Rejestr.Free;
+
+ Rejestr := TResourceStream.Create(HInstance, 'FontO', 'FNT');
+ Rejestr.Read(Fonts[2].Width, 256);
+ Rejestr.Free;
+
+ Rejestr := TResourceStream.Create(HInstance, 'FontO2', 'FNT');
+ Rejestr.Read(Fonts[3].Width, 256);
+ Rejestr.Free;
+
+{ Rejestr := TResourceStream.Create(HInstance, 'FontO', 'FNT');
+ Rejestr.Read(Fonts[4].Width, 256);
+ Rejestr.Free;}
+
+ for Pet := 0 to 255 do
+ Fonts[1].Width[Pet] := Fonts[1].Width[Pet] div 2;
+
+ for Pet := 0 to 255 do
+ Fonts[2].Width[Pet] := Fonts[2].Width[Pet] div 2 + 2;
+
+ for Pet := 0 to 255 do
+ Fonts[3].Width[Pet] := Fonts[3].Width[Pet] + 1;
+
+{ for Pet := 0 to 255 do
+ Fonts[4].Width[Pet] := Fonts[4].Width[Pet] div 2 + 2;}
+
+end;
+
+procedure KillFont; // Delete The Font
+begin
+// glDeleteLists(base, 256); // Delete All 96 Characters
+end;
+
+function glTextWidth(text: pchar): real;
+var
+ Letter: char;
+begin
+// Log.LogStatus(Text, 'glTextWidth');
+ Result := 0;
+ while (length(text) > 0) do begin
+ Letter := Text[0];
+ text := pchar(Copy(text, 2, Length(text)-1));
+ Result := Result + Fonts[ActFont].Width[Ord(Letter)] * Fonts[ActFont].Tex.H / 30 * Fonts[ActFont].AspectW;
+ end; // while
+end;
+
+procedure glPrintDone(text: pchar; Done: real; ColR, ColG, ColB: real);
+begin
+ Fonts[ActFont].Done := Done;
+ PColR := ColR;
+ PColG := ColG;
+ PColB := ColB;
+ glPrintCut(text);
+ Fonts[ActFont].Done := -1;
+end;
+
+procedure glPrintLetter(Letter: char);
+var
+ TexX, TexY: real;
+ TexR, TexB: real;
+ FWidth: real;
+ PL, PT: real;
+ PR, PB: real;
+ XItal: real; // X shift for italic type letter
+begin
+ with Fonts[ActFont].Tex do begin
+ FWidth := Fonts[ActFont].Width[Ord(Letter)];
+
+ W := FWidth * (H/30) * Fonts[ActFont].AspectW;
+// H := 30;
+
+ // set texture positions
+ TexX := (ord(Letter) mod 16) * 1/16 + 1/32 - FWidth/1024 - Fonts[ActFont].Outline/1024;
+ TexY := (ord(Letter) div 16) * 1/16 + 2/1024; // 2/1024
+ TexR := (ord(Letter) mod 16) * 1/16 + 1/32 + FWidth/1024 + Fonts[ActFont].Outline/1024;
+ TexB := (1 + ord(Letter) div 16) * 1/16 - 2/1024;
+
+ // set vector positions
+ PL := X - Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW /2;
+ PT := Y;
+ PR := PL + W + Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW;
+ PB := PT + H;
+ if Fonts[ActFont].Italic = false then
+ XItal := 0
+ else
+ XItal := 12;
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(TexX, TexY); glVertex2f(PL+XItal, PT);
+ glTexCoord2f(TexX, TexB); glVertex2f(PL, PB);
+ glTexCoord2f(TexR, TexB); glVertex2f(PR, PB);
+ glTexCoord2f(TexR, TexY); glVertex2f(PR+XItal, PT);
+ glEnd;
+ X := X + W;
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ end; // with
+end;
+
+procedure glPrintLetterCut(letter: char; Start, Finish: real);
+var
+ TexX, TexY: real;
+ TexR, TexB: real;
+ TexTemp: real;
+ FWidth: real;
+ PL, PT: real;
+ PR, PB: real;
+ OutTemp: real;
+ XItal: real;
+begin
+ with Fonts[ActFont].Tex do begin
+ FWidth := Fonts[ActFont].Width[Ord(Letter)];
+
+ W := FWidth * (H/30) * Fonts[ActFont].AspectW;
+// H := 30;
+ OutTemp := Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW;
+
+ // set texture positions
+ TexX := (ord(Letter) mod 16) * 1/16 + 1/32 - FWidth/1024 - Fonts[ActFont].Outline/1024;
+ TexY := (ord(Letter) div 16) * 1/16 + 2/1024; // 2/1024
+ TexR := (ord(Letter) mod 16) * 1/16 + 1/32 + FWidth/1024 + Fonts[ActFont].Outline/1024;
+ TexB := (1 + ord(Letter) div 16) * 1/16 - 2/1024;
+
+ TexTemp := TexX + Start * (TexR - TexX);
+ TexR := TexX + Finish * (TexR - TexX);
+ TexX := TexTemp;
+
+ // set vector positions
+ PL := X - OutTemp / 2 + OutTemp * Start;
+ PT := Y;
+ PR := PL + (W + OutTemp) * (Finish - Start);
+ PB := PT + H;
+ if Fonts[ActFont].Italic = false then
+ XItal := 0
+ else
+ XItal := 12;
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(TexX, TexY); glVertex2f(PL+XItal, PT);
+ glTexCoord2f(TexX, TexB); glVertex2f(PL, PB);
+ glTexCoord2f(TexR, TexB); glVertex2f(PR, PB);
+ glTexCoord2f(TexR, TexY); glVertex2f(PR+XItal, PT); // not tested with XItal
+ glEnd;
+ X := X + W * (Finish - Start);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ end; // with
+
+end;
+
+procedure glPrint(text: pchar); // Custom GL "Print" Routine
+var
+ Letter: char;
+begin
+ if (Text = '') then // If There's No Text
+ Exit; // Do Nothing
+
+ while (length(text) > 0) do begin
+ // cut
+ Letter := Text[0];
+ Text := pchar(Copy(Text, 2, Length(Text)-1));
+
+ // print
+ glPrintLetter(Letter);
+ end; // while
+end;
+
+procedure glPrintCut(text: pchar);
+var
+ Letter: char;
+ PToDo: real;
+ PTotWidth: real;
+ PDoingNow: real;
+ S: string;
+begin
+ if (Text = '') then // If There's No Text
+ Exit; // Do Nothing
+
+ PTotWidth := glTextWidth(Text);
+ PToDo := Fonts[ActFont].Done;
+
+ while (length(text) > 0) do begin
+ // cut
+ Letter := Text[0];
+ Text := pchar(Copy(Text, 2, Length(Text)-1));
+
+ // analyze
+ S := Letter;
+ PDoingNow := glTextWidth(pchar(S)) / PTotWidth;
+
+ // drawing
+ if (PToDo > 0) and (PDoingNow <= PToDo) then
+ glPrintLetter(Letter);
+
+ if (PToDo > 0) and (PDoingNow > PToDo) then begin
+ glPrintLetterCut(Letter, 0, PToDo / PDoingNow);
+ glColor3f(PColR, PColG, PColB);
+ glPrintLetterCut(Letter, PToDo / PDoingNow, 1);
+ end;
+
+ if (PToDo <= 0) then
+ glPrintLetter(Letter);
+
+ PToDo := PToDo - PDoingNow;
+
+ end; // while
+end;
+
+
+procedure SetFontPos(X, Y: real);
+begin
+ Fonts[ActFont].Tex.X := X;
+ Fonts[ActFont].Tex.Y := Y;
+end;
+
+procedure SetFontSize(Size: real);
+begin
+ Fonts[ActFont].Tex.H := 30 * (Size/10);
+end;
+
+procedure SetFontStyle(Style: integer);
+begin
+ ActFont := Style;
+end;
+
+procedure SetFontItalic(Enable: boolean);
+begin
+ Fonts[ActFont].Italic := Enable;
+end;
+
+procedure SetFontAspectW(Aspect: real);
+begin
+ Fonts[ActFont].AspectW := Aspect;
+end;
+
+end.
diff --git a/Game/Code/Classes/UCatCovers.pas b/Game/Code/Classes/UCatCovers.pas
new file mode 100644
index 00000000..34742902
--- /dev/null
+++ b/Game/Code/Classes/UCatCovers.pas
@@ -0,0 +1,143 @@
+unit UCatCovers;
+/////////////////////////////////////////////////////////////////////////
+// UCatCovers by Whiteshark //
+// Class for listing and managing the Category Covers //
+/////////////////////////////////////////////////////////////////////////
+
+interface
+uses UIni;
+
+type
+ TCatCovers = class
+ protected
+ cNames: array [low(ISorting)..high(ISorting)] of array of string;
+ cFiles: array [low(ISorting)..high(ISorting)] of array of string;
+ public
+ constructor Create;
+ procedure Load; //Load Cover aus Cover.ini and Cover Folder
+ procedure Add(Sorting: integer; Name, Filename: string); //Add a Cover
+ function CoverExists(Sorting: integer; Name: string): boolean; //Returns True when a cover with the given Name exists
+ function GetCover(Sorting: integer; Name: string): string; //Returns the Filename of a Cover
+ end;
+
+var
+CatCovers: TCatCovers;
+
+implementation
+uses IniFiles, SysUtils, Classes, UFiles, ULog;
+
+constructor TCatCovers.Create;
+begin
+ Load;
+end;
+
+ //Load Cover aus Cover.ini and Cover Folder
+procedure TCatCovers.Load;
+var
+ Ini: TMemIniFile;
+ SR: TSearchRec;
+ List: TStringlist;
+ I, J: Integer;
+ Name, Filename, Temp: string;
+begin
+try
+ Ini := TMemIniFile.Create(CoversPath + 'covers.ini');
+ List := TStringlist.Create;
+
+ //Add every Cover in Covers Ini for Every Sorting option
+ for I := low(ISorting) to high(ISorting) do
+ begin
+ Ini.ReadSection(ISorting[I], List);
+
+ for J := 0 to List.Count - 1 do
+ Add(I, List.Strings[J], CoversPath + Ini.ReadString(ISorting[I], List.Strings[J], 'NoCover.jpg'));
+ end;
+
+finally
+ Ini.Free;
+ List.Free;
+end;
+
+try
+ //Add Covers from Folder
+ if (FindFirst (CoversPath + '*.jpg', faAnyFile, SR) = 0) then
+ repeat
+ //Add Cover if it doesn't exist for every Section
+ Name := SR.Name;
+ Filename := CoversPath + Name;
+ Delete (Name, length(Name) - 3, 4);
+
+ for I := low(ISorting) to high(ISorting) do
+ begin
+ Temp := Name;
+ if ((I = sTitle) or (I = sTitle2)) and (Pos ('Title', Temp) <> 0) then
+ Delete (Temp, Pos ('Title', Temp), 5)
+ else if (I = sArtist) or (I = sArtist2) and (Pos ('Artist', Temp) <> 0) then
+ Delete (Temp, Pos ('Artist', Temp), 6);
+
+ if not CoverExists(I, Temp) then
+ Add (I, Temp, Filename);
+ end;
+ until FindNext (SR) <> 0;
+
+finally
+ FindClose (SR);
+end;
+
+end;
+
+ //Add a Cover
+procedure TCatCovers.Add(Sorting: integer; Name, Filename: string);
+begin
+if FileExists (Filename) then //If Exists -> Add
+begin
+SetLength (CNames[Sorting], Length(CNames[Sorting]) + 1);
+SetLength (CFiles[Sorting], Length(CNames[Sorting]) + 1);
+
+CNames[Sorting][high(cNames[Sorting])] := Uppercase(Name);
+CFiles[Sorting][high(cNames[Sorting])] := FileName;
+end;
+end;
+
+ //Returns True when a cover with the given Name exists
+function TCatCovers.CoverExists(Sorting: integer; Name: string): boolean;
+var
+I: Integer;
+begin
+Result := False;
+Name := Uppercase(Name); //Case Insensitiv
+
+for I := low(cNames[Sorting]) to high(cNames[Sorting]) do
+begin
+ if (cNames[Sorting][I] = Name) then //Found Name
+ begin
+ Result := true;
+ break; //Break For Loop
+ end;
+end;
+end;
+
+ //Returns the Filename of a Cover
+function TCatCovers.GetCover(Sorting: integer; Name: string): string;
+var
+I: Integer;
+begin
+Result := '';
+Name := Uppercase(Name);
+
+for I := low(cNames[Sorting]) to high(cNames[Sorting]) do
+begin
+ if cNames[Sorting][I] = Name then
+ begin
+ Result := cFiles[Sorting][I];
+ Break;
+ end;
+end;
+
+//No Cover
+if (Result = '') AND (FileExists(CoversPath + 'NoCover.jpg')) then
+ Result := CoversPath + 'NoCover.jpg';
+
+end;
+
+end.
diff --git a/Game/Code/Classes/UCommandLine.pas b/Game/Code/Classes/UCommandLine.pas
new file mode 100644
index 00000000..03229721
--- /dev/null
+++ b/Game/Code/Classes/UCommandLine.pas
@@ -0,0 +1,280 @@
+unit UCommandLine;
+
+interface
+
+type
+ //-----------
+ // TCMDParams - Class Reaads Infos from ParamStr and set some easy Interface Variables
+ //-----------
+ TCMDParams = class
+ private
+ sLanguage: String;
+ sResolution: String;
+ public
+ //Some Boolean Variables Set when Reading Infos
+ Debug: Boolean;
+ Benchmark: Boolean;
+ NoLog: Boolean;
+ FullScreen: Boolean;
+ Joypad: Boolean;
+
+ //Some Value Variables Set when Reading Infos {-1: Not Set, others: Value}
+ Depth: Integer;
+ Screens: Integer;
+
+ //Some Strings Set when Reading Infos {Length=0 Not Set}
+ SongPath: String;
+ ConfigFile: String;
+ ScoreFile: String;
+
+ //Pseudo Integer Values
+ Function GetLanguage: Integer;
+ Property Language: Integer read GetLanguage;
+
+ Function GetResolution: Integer;
+ Property Resolution: Integer read GetResolution;
+
+ //Some Procedures for Reading Infos
+ Constructor Create;
+
+ Procedure ResetVariables;
+ Procedure ReadParamInfo;
+ end;
+
+var
+ Params: TCMDParams;
+
+implementation
+uses SysUtils, UIni;
+
+//-------------
+// Constructor - Create class, Reset Variables and Read Infos
+//-------------
+Constructor TCMDParams.Create;
+begin
+ ResetVariables;
+ ReadParamInfo;
+end;
+
+//-------------
+// ResetVariables - Reset Class Variables
+//-------------
+Procedure TCMDParams.ResetVariables;
+begin
+ Debug := False;
+ Benchmark := False;
+ NoLog := False;
+ FullScreen := False;
+ Joypad := False;
+
+ //Some Value Variables Set when Reading Infos {-1: Not Set, others: Value}
+ sResolution := '';
+ sLanguage := '';
+ Depth := -1;
+ Screens := -1;
+
+ //Some Strings Set when Reading Infos {Length=0 Not Set}
+ SongPath := '';
+ ConfigFile := '';
+ ScoreFile := '';
+end;
+
+//-------------
+// ReadParamInfo - Read Infos from Parameters
+//-------------
+Procedure TCMDParams.ReadParamInfo;
+var
+ I: Integer;
+ PCount: Integer;
+ Command: String;
+begin
+ PCount := ParamCount;
+ //Log.LogError('ParamCount: ' + Inttostr(PCount));
+
+ //Check all Parameters
+ For I := 1 to PCount do
+ begin
+ Command := Paramstr(I);
+ //Log.LogError('Start parsing Command: ' + Command);
+ //Is String Parameter ?
+ if (Length(Command) > 1) AND (Command[1] = '-') then
+ begin
+ //Remove - from Command
+ Command := Lowercase(Trim(Copy(Command, 2, Length(Command) - 1)));
+ //Log.LogError('Command prepared: ' + Command);
+
+ //Check Command
+
+ // Boolean Triggers:
+ if (Command = 'debug') then
+ Debug := True
+ else if (Command = 'benchmark') then
+ Benchmark := True
+ else if (Command = 'nolog') then
+ NoLog := True
+ else if (Command = 'fullscreen') then
+ Fullscreen := True
+ else if (Command = 'joypad') then
+ Joypad := True
+
+ //Integer Variables
+ else if (Command = 'depth') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ Command := ParamStr(I + 1);
+
+ //Check for valid Value
+ If (Command = '16') then
+ Depth := 0
+ Else If (Command = '32') then
+ Depth := 1;
+ end;
+ end
+
+ else if (Command = 'screens') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ Command := ParamStr(I + 1);
+
+ //Check for valid Value
+ If (Command = '1') then
+ Screens := 0
+ Else If (Command = '2') then
+ Screens := 1;
+ end;
+ end
+
+ //Pseudo Integer Values
+ else if (Command = 'language') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ //Write Value to String
+ sLanguage := Lowercase(ParamStr(I + 1));
+ end;
+ end
+
+ else if (Command = 'resolution') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ //Write Value to String
+ sResolution := Lowercase(ParamStr(I + 1));
+ end;
+ end
+
+ //String Values
+ else if (Command = 'songpath') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ //Write Value to String
+ SongPath := ParamStr(I + 1);
+ end;
+ end
+
+ else if (Command = 'configfile') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ //Write Value to String
+ ConfigFile := ParamStr(I + 1);
+
+ //is this a relative PAth -> then add Gamepath
+ if Not ((Length(ConfigFile) > 2) AND (ConfigFile[2] = ':')) then
+ ConfigFile := ExtractFilePath(ParamStr(0)) + Configfile;
+ end;
+ end
+
+ else if (Command = 'scorefile') then
+ begin
+ //Check if there is another Parameter to get the Value from
+ if (PCount > I) then
+ begin
+ //Write Value to String
+ ScoreFile := ParamStr(I + 1);
+ end;
+ end;
+
+ end;
+
+ end;
+
+{ Log.LogError('Values: ');
+
+ if Debug then
+ Log.LogError('Debug');
+
+ if Benchmark then
+ Log.LogError('Benchmark');
+
+ if NoLog then
+ Log.LogError('NoLog');
+
+ if Fullscreen then
+ Log.LogError('FullScreen');
+
+ if JoyStick then
+ Log.LogError('Joystick');
+
+
+ Log.LogError('Screens: ' + Inttostr(Screens));
+ Log.LogError('Depth: ' + Inttostr(Depth));
+
+ Log.LogError('Resolution: ' + Inttostr(Resolution));
+ Log.LogError('Resolution: ' + Inttostr(Language));
+
+ Log.LogError('sResolution: ' + sResolution);
+ Log.LogError('sLanguage: ' + sLanguage);
+
+ Log.LogError('ConfigFile: ' + ConfigFile);
+ Log.LogError('SongPath: ' + SongPath);
+ Log.LogError('ScoreFile: ' + ScoreFile); }
+
+end;
+
+//-------------
+// GetLanguage - Get Language ID from saved String Information
+//-------------
+Function TCMDParams.GetLanguage: Integer;
+var
+ I: integer;
+begin
+ Result := -1;
+
+ //Search for Language
+ For I := 0 to high(ILanguage) do
+ if (LowerCase(ILanguage[I]) = sLanguage) then
+ begin
+ Result := I;
+ Break;
+ end;
+end;
+
+//-------------
+// GetResolution - Get Resolution ID from saved String Information
+//-------------
+Function TCMDParams.GetResolution: Integer;
+var
+ I: integer;
+begin
+ Result := -1;
+
+ //Search for Resolution
+ For I := 0 to high(IResolution) do
+ if (LowerCase(IResolution[I]) = sResolution) then
+ begin
+ Result := I;
+ Break;
+ end;
+end;
+
+end. \ No newline at end of file
diff --git a/Game/Code/Classes/UCovers.pas b/Game/Code/Classes/UCovers.pas
new file mode 100644
index 00000000..b7bef8e6
--- /dev/null
+++ b/Game/Code/Classes/UCovers.pas
@@ -0,0 +1,226 @@
+unit UCovers;
+
+interface
+uses gl, Windows, Math, Classes, SysUtils, Graphics, UThemes, UTexture;
+
+type
+ TCover = record
+ Name: string;
+ W: word;
+ H: word;
+ Size: integer;
+ Position: integer; // position of picture in the cache file
+// Data: array of byte;
+ end;
+
+ TCovers = class
+ Cover: array of TCover;
+ W: word;
+ H: word;
+ Size: integer;
+ Data: array of byte;
+ WritetoFile: Boolean;
+
+ constructor Create;
+ procedure Load;
+ procedure Save;
+ procedure AddCover(Name: string);
+ function CoverExists(Name: string): boolean;
+ function CoverNumber(Name: string): integer;
+ procedure PrepareData(Name: string);
+ end;
+
+var
+ Covers: TCovers;
+
+implementation
+uses UFiles, ULog, DateUtils;
+
+constructor TCovers.Create;
+begin
+ W := 128;
+ H := 128;
+ Size := W*H*3;
+ Load;
+ WritetoFile := True;
+end;
+
+procedure TCovers.Load;
+var
+ F: File;
+ C: integer; // cover number
+ W: word;
+ H: word;
+ Bits: byte;
+ NLen: word;
+ Name: string;
+// Data: array of byte;
+begin
+ if FileExists(GamePath + 'covers.cache') then begin
+ AssignFile(F, GamePath + 'covers.cache');
+ Reset(F, 1);
+
+ WritetoFile := not FileIsReadOnly(GamePath + 'covers.cache');
+
+ SetLength(Cover, 0);
+
+ while not EOF(F) do begin
+ SetLength(Cover, Length(Cover)+1);
+
+ BlockRead(F, W, 2);
+ Cover[High(Cover)].W := W;
+
+ BlockRead(F, H, 2);
+ Cover[High(Cover)].H := H;
+
+ BlockRead(F, Bits, 1);
+
+ Cover[High(Cover)].Size := W * H * (Bits div 8);
+
+ // test
+// W := 128;
+// H := 128;
+// Bits := 24;
+// Seek(F, FilePos(F) + 3);
+
+ BlockRead(F, NLen, 2);
+ SetLength(Name, NLen);
+
+ BlockRead(F, Name[1], NLen);
+ Cover[High(Cover)].Name := Name;
+
+ Cover[High(Cover)].Position := FilePos(F);
+ Seek(F, FilePos(F) + W*H*(Bits div 8));
+
+// SetLength(Cover[High(Cover)].Data, W*H*(Bits div 8));
+// BlockRead(F, Cover[High(Cover)].Data[0], W*H*(Bits div 8));
+
+ end;
+
+ CloseFile(F);
+ end; // fileexists
+end;
+
+procedure TCovers.Save;
+var
+ F: File;
+ C: integer; // cover number
+ W: word;
+ H: word;
+ NLen: word;
+ Bits: byte;
+begin
+{ AssignFile(F, GamePath + 'covers.cache');
+ Rewrite(F, 1);
+
+ Bits := 24;
+ for C := 0 to High(Cover) do begin
+ W := Cover[C].W;
+ H := Cover[C].H;
+
+ BlockWrite(F, W, 2);
+ BlockWrite(F, H, 2);
+ BlockWrite(F, Bits, 1);
+
+ NLen := Length(Cover[C].Name);
+ BlockWrite(F, NLen, 2);
+ BlockWrite(F, Cover[C].Name[1], NLen);
+ BlockWrite(F, Cover[C].Data[0], W*H*(Bits div 8));
+ end;
+
+ CloseFile(F);}
+end;
+
+procedure TCovers.AddCover(Name: string);
+var
+ B: integer;
+ F: File;
+ C: integer; // cover number
+ NLen: word;
+ Bits: byte;
+begin
+ if not CoverExists(Name) then begin
+ SetLength(Cover, Length(Cover)+1);
+ Cover[High(Cover)].Name := Name;
+
+ Cover[High(Cover)].W := W;
+ Cover[High(Cover)].H := H;
+ Cover[High(Cover)].Size := Size;
+
+ // do not copy data. write them directly to file
+// SetLength(Cover[High(Cover)].Data, Size);
+// for B := 0 to Size-1 do
+// Cover[High(Cover)].Data[B] := CacheMipmap[B];
+
+ if WritetoFile then
+ begin
+ AssignFile(F, GamePath + 'covers.cache');
+ if FileExists(GamePath + 'covers.cache') then begin
+ Reset(F, 1);
+ Seek(F, FileSize(F));
+ end else
+ Rewrite(F, 1);
+
+ Bits := 24;
+
+ BlockWrite(F, W, 2);
+ BlockWrite(F, H, 2);
+ BlockWrite(F, Bits, 1);
+
+ NLen := Length(Name);
+ BlockWrite(F, NLen, 2);
+ BlockWrite(F, Name[1], NLen);
+
+ Cover[High(Cover)].Position := FilePos(F);
+ BlockWrite(F, CacheMipmap[0], W*H*(Bits div 8));
+
+ CloseFile(F);
+ end;
+ end
+ else
+ Cover[High(Cover)].Position := 0;
+end;
+
+function TCovers.CoverExists(Name: string): boolean;
+var
+ C: integer; // cover
+begin
+ Result := false;
+ C := 0;
+ while (C <= High(Cover)) and (Result = false) do begin
+ if Cover[C].Name = Name then Result := true;
+ Inc(C);
+ end;
+end;
+
+function TCovers.CoverNumber(Name: string): integer;
+var
+ C: integer;
+begin
+ Result := -1;
+ C := 0;
+ while (C <= High(Cover)) and (Result = -1) do begin
+ if Cover[C].Name = Name then Result := C;
+ Inc(C);
+ end;
+end;
+
+procedure TCovers.PrepareData(Name: string);
+var
+ F: File;
+ C: integer;
+begin
+ if FileExists(GamePath + 'covers.cache') then begin
+ AssignFile(F, GamePath + 'covers.cache');
+ Reset(F, 1);
+
+ C := CoverNumber(Name);
+ SetLength(Data, Cover[C].Size);
+ if Length(Data) < 6 then beep;
+ Seek(F, Cover[C].Position);
+ BlockRead(F, Data[0], Cover[C].Size);
+ CloseFile(F);
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/UDLLManager.pas b/Game/Code/Classes/UDLLManager.pas
new file mode 100644
index 00000000..4b8838b9
--- /dev/null
+++ b/Game/Code/Classes/UDLLManager.pas
@@ -0,0 +1,226 @@
+unit UDLLManager;
+
+interface
+uses ModiSDK, UFiles;
+
+type
+ TDLLMan = class
+ private
+ hLib: THandle;
+ P_Init: fModi_Init;
+ P_Draw: fModi_Draw;
+ P_Finish: fModi_Finish;
+ P_RData: pModi_RData;
+ public
+ Plugins: array of TPluginInfo;
+ PluginPaths: array of String;
+ Selected: ^TPluginInfo;
+
+ constructor Create;
+
+ procedure GetPluginList;
+ procedure ClearPluginInfo(No: Cardinal);
+ function LoadPluginInfo(Filename: String; No: Cardinal): boolean;
+
+ function LoadPlugin(No: Cardinal): boolean;
+ procedure UnLoadPlugin;
+
+ function PluginInit (const TeamInfo: TTeamInfo; var Playerinfo: TPlayerinfo; const Sentences: TSentences; const LoadTex: fModi_LoadTex; const Print: fModi_Print; LoadSound: fModi_LoadSound; PlaySound: pModi_PlaySound): boolean;
+ function PluginDraw (var Playerinfo: TPlayerinfo; const CurSentence: Cardinal): boolean;
+ function PluginFinish (var Playerinfo: TPlayerinfo): byte;
+ procedure PluginRData (handle: HSTREAM; buffer: Pointer; len: DWORD; user: DWORD);
+ end;
+
+var
+ DLLMan: TDLLMan;
+
+const DLLPath = 'Plugins\';
+
+implementation
+uses Windows, ULog, SysUtils;
+
+
+constructor TDLLMan.Create;
+begin
+ SetLength(Plugins, 0);
+ SetLength(PluginPaths, Length(Plugins));
+ GetPluginList;
+end;
+
+procedure TDLLMan.GetPluginList;
+var
+ SR: TSearchRec;
+begin
+
+ if FindFirst(DLLPath + '*.dll', faAnyFile , SR) = 0 then
+ begin
+ repeat
+ SetLength(Plugins, Length(Plugins)+1);
+ SetLength(PluginPaths, Length(Plugins));
+
+ if LoadPluginInfo(SR.Name, High(Plugins)) then //Loaded succesful
+ begin
+ PluginPaths[High(PluginPaths)] := SR.Name;
+ end
+ else //Error Loading
+ begin
+ SetLength(Plugins, Length(Plugins)-1);
+ SetLength(PluginPaths, Length(Plugins));
+ end;
+
+ until FindNext(SR) <> 0;
+ FindClose(SR);
+ end;
+end;
+
+procedure TDLLMan.ClearPluginInfo(No: Cardinal);
+begin
+ //Set to Party Modi Plugin
+ Plugins[No].Typ := 8;
+
+ Plugins[No].Name := 'unknown';
+ Plugins[No].NumPlayers := 0;
+
+ Plugins[No].Creator := 'Nobody';
+ Plugins[No].PluginDesc := 'NO_PLUGIN_DESC';
+
+ Plugins[No].LoadSong := True;
+ Plugins[No].ShowScore := True;
+ Plugins[No].ShowBars := False;
+ Plugins[No].ShowNotes := True;
+ Plugins[No].LoadVideo := True;
+ Plugins[No].LoadBack := True;
+
+ Plugins[No].TeamModeOnly := False;
+ Plugins[No].GetSoundData := False;
+ Plugins[No].Dummy := False;
+
+
+ Plugins[No].BGShowFull := False;
+ Plugins[No].BGShowFull_O := True;
+
+ Plugins[No].ShowRateBar:= False;
+ Plugins[No].ShowRateBar_O := True;
+
+ Plugins[No].EnLineBonus := False;
+ Plugins[No].EnLineBonus_O := True;
+end;
+
+function TDLLMan.LoadPluginInfo(Filename: String; No: Cardinal): boolean;
+var
+ hLibg: THandle;
+ Info: pModi_PluginInfo;
+ I: Integer;
+begin
+ Result := False;
+ //Clear Plugin Info
+ ClearPluginInfo(No);
+
+ {//Workaround Plugins Loaded 2 Times
+ For I := low(PluginPaths) to high(PluginPaths) do
+ if (PluginPaths[I] = Filename) then
+ exit; }
+
+ //Load Libary
+ hLibg := LoadLibrary(PChar(DLLPath + Filename));
+ //If Loaded
+ if (hLibg <> 0) then
+ begin
+ //Load Info Procedure
+ @Info := GetProcAddress (hLibg, PChar('PluginInfo'));
+
+ //If Loaded
+ if (@Info <> nil) then
+ begin
+ //Load PluginInfo
+ Info (Plugins[No]);
+ Result := True;
+ end
+ else
+ Log.LogError('Could not Load Plugin "' + Filename + '": Info Procedure not Found');
+
+ FreeLibrary (hLibg);
+ end
+ else
+ Log.LogError('Could not Load Plugin "' + Filename + '": Libary not Loaded');
+end;
+
+function TDLLMan.LoadPlugin(No: Cardinal): boolean;
+begin
+ Result := False;
+ //Load Libary
+ hLib := LoadLibrary(PChar(DLLPath + PluginPaths[No]));
+ //If Loaded
+ if (hLib <> 0) then
+ begin
+ //Load Info Procedure
+ @P_Init := GetProcAddress (hLib, PChar('Init'));
+ @P_Draw := GetProcAddress (hLib, PChar('Draw'));
+ @P_Finish := GetProcAddress (hLib, PChar('Finish'));
+
+ //If Loaded
+ if (@P_Init <> nil) And (@P_Draw <> nil) And (@P_Finish <> nil) then
+ begin
+ Selected := @Plugins[No];
+ Result := True;
+ end
+ else
+ begin
+ Log.LogError('Could not Load Plugin "' + PluginPaths[No] + '": Procedures not Found');
+
+ end;
+ end
+ else
+ Log.LogError('Could not Load Plugin "' + PluginPaths[No] + '": Libary not Loaded');
+end;
+
+procedure TDLLMan.UnLoadPlugin;
+begin
+if (hLib <> 0) then
+ FreeLibrary (hLib);
+
+//Selected := nil;
+@P_Init := nil;
+@P_Draw := nil;
+@P_Finish := nil;
+@P_RData := nil;
+end;
+
+function TDLLMan.PluginInit (const TeamInfo: TTeamInfo; var Playerinfo: TPlayerinfo; const Sentences: TSentences; const LoadTex: fModi_LoadTex; const Print: fModi_Print; LoadSound: fModi_LoadSound; PlaySound: pModi_PlaySound): boolean;
+var
+ Methods: TMethodRec;
+begin
+ Methods.LoadTex := LoadTex;
+ Methods.Print := Print;
+ Methods.LoadSound := LoadSound;
+ Methods.PlaySound := PlaySound;
+
+ if (@P_Init <> nil) then
+ Result := P_Init (TeamInfo, PlayerInfo, Sentences, Methods)
+ else
+ Result := False
+end;
+
+function TDLLMan.PluginDraw (var Playerinfo: TPlayerinfo; const CurSentence: Cardinal): boolean;
+begin
+if (@P_Draw <> nil) then
+ Result := P_Draw (PlayerInfo, CurSentence)
+else
+ Result := False
+end;
+
+function TDLLMan.PluginFinish (var Playerinfo: TPlayerinfo): byte;
+begin
+if (@P_Finish <> nil) then
+ Result := P_Finish (PlayerInfo)
+else
+ Result := 0;
+end;
+
+procedure TDLLMan.PluginRData (handle: HSTREAM; buffer: Pointer; len: DWORD; user: DWORD);
+begin
+if (@P_RData <> nil) then
+ P_RData (handle, buffer, len, user);
+end;
+
+end.
diff --git a/Game/Code/Classes/UDataBase.pas b/Game/Code/Classes/UDataBase.pas
new file mode 100644
index 00000000..580f7144
--- /dev/null
+++ b/Game/Code/Classes/UDataBase.pas
@@ -0,0 +1,500 @@
+unit UDataBase;
+
+interface
+
+uses USongs, SQLiteTable3;
+
+//--------------------
+//DataBaseSystem - Class including all DB Methods
+//--------------------
+type
+ THandicapResult = record
+ P1m: real;
+ P2m: real;
+ end;
+
+ TStatResult = record
+ Case Typ: Byte of
+ 0: (Singer: ShortString; //best scores
+ Score: Word;
+ Difficulty: Byte;
+ SongArtist: ShortString;
+ SongTitle: ShortString;
+ Date: ShortString);
+
+ 1: (Player: ShortString; //best singers
+ AverageScore: Word;
+ SungTimes: Word);
+
+ 2: (Artist: ShortString; //most sung song
+ Title: ShortString;
+ TimesSung: Word);
+
+ 3: (ArtistName: ShortString; //most sung band
+ TimesSungtot: Word);
+ end;
+ AStatResult = Array of TStatResult;
+
+ TDataBaseSystem = class
+ private
+ ScoreDB: TSqliteDatabase;
+ sFilename: string;
+ public
+
+
+ property Filename: String read sFilename;
+
+ Destructor Free;
+
+ Procedure Init(const Filename: string);
+ procedure ReadScore(var Song: TSong);
+ procedure AddScore(var Song: TSong; Level: integer; Name: string; Score: integer; TimeStamp: integer);
+ procedure WriteScore(var Song: TSong);
+
+ Function GetStats(var Stats: AStatResult; const Typ, Count: Byte; const Page: Cardinal; const Reversed: Boolean): Boolean;
+ Function GetTotalEntrys(const Typ: Byte): Cardinal;
+ function FormatDate(time_stamp: integer): String;
+ function GetHandicap(P1: string; P2: string): THandicapResult; //for Handicap-Mode
+ function GetAspect(Artist, Title: string; def: integer): integer;
+ procedure SetAspect(Artist, Title: string; aspect: integer);
+ end;
+
+var
+ DataBase: TDataBaseSystem;
+
+implementation
+
+uses IniFiles, SysUtils, DateUtils, ULanguage;
+
+function TDataBaseSystem.GetHandicap(P1: string; P2: string): THandicapResult;
+const
+ min = 3;
+var
+ P1m, P2m, temp: real;
+ P1c, P2c: integer;
+begin
+ if not Assigned(ScoreDB) then
+ Exit;
+
+ //init
+ Result.P1m := 1;
+ Result.P2m := 1;
+ P1m := 0;
+ P2m := 0;
+ P1c := 0;
+ P2c := 0;
+
+ try
+ P1c := ScoreDB.GetTableValue('SELECT COUNT(`SongID`) FROM `US_Scores` '+
+ 'WHERE `Player` = "' + P1 + '";');
+ P2c := ScoreDB.GetTableValue('SELECT COUNT(`SongID`) FROM `US_Scores` '+
+ 'WHERE `Player` = "' + P2 + '";');
+
+ if (P1c>min) and (P2c>min) then
+ begin
+ P1m := ScoreDB.GetTableFloat('SELECT AVG(`Score`) FROM `US_Scores` '+
+ 'WHERE `Score` IN ('+
+ 'SELECT Score FROM `US_Scores` '+
+ 'WHERE `Player` = "' + P1 + '" ORDER BY `rowid` DESC LIMIT 10);');
+
+ P2m := ScoreDB.GetTableFloat('SELECT AVG(`Score`) FROM `US_Scores` '+
+ 'WHERE `Score` IN ('+
+ 'SELECT Score FROM `US_Scores` '+
+ 'WHERE `Player` = "' + P2 + '" ORDER BY `rowid` DESC LIMIT 10);');
+ end;
+ except
+ P1m := 0;
+ P2m := 0;
+ end;
+
+ if (P1m>0) and (P2m>0) then
+ begin
+ if (P1m>P2m) then
+ begin
+ temp := (P2m/P1m) + (P2m/P1m)*0.2;
+ if temp<=1 then
+ Result.P1m := temp
+ else
+ Result.P1m := 1;
+ end else
+ begin
+ temp := (P1m/P2m) + (P1m/P2m)*0.2;
+ if temp<=1 then
+ Result.P2m := temp
+ else
+ Result.P2m := 1;
+ end;
+ end;
+end;
+
+function TDataBaseSystem.GetAspect(Artist, Title: string; def: integer): integer;
+var
+ ID: Integer;
+
+begin
+ try
+ ID := ScoreDB.GetTableValue('SELECT `ID` FROM `US_Songs` WHERE `Artist` = "' +
+ Artist + '" AND `Title` = "' + Title + '"');
+
+ if ID = 0 then //Song doesn't exist -> Create
+ begin
+ ScoreDB.ExecSQL ('INSERT INTO `US_Songs` ( `ID` , `Artist` , `Title` , `TimesPlayed`, `Aspect` ) '+
+ 'VALUES (NULL , "' + Artist + '", "' + Title + '", "0", "'+ IntToStr(def) +'");');
+ Result := def;
+ end else
+ begin
+ Result := ScoreDB.GetTableValue('SELECT `Aspect` FROM `US_Songs` WHERE `ID` = "' +
+ IntToStr(ID) + '"');
+ end;
+ except
+ Result := def;
+ end;
+end;
+
+procedure TDataBaseSystem.SetAspect(Artist, Title: string; aspect: integer);
+var
+ ID: Integer;
+
+begin
+ try
+ ID := ScoreDB.GetTableValue('SELECT `ID` FROM `US_Songs` WHERE `Artist` = "' +
+ Artist + '" AND `Title` = "' + Title + '"');
+
+ if ID = 0 then //Song doesn't exist -> Create
+ begin
+ ScoreDB.ExecSQL ('INSERT INTO `US_Songs` ( `ID` , `Artist` , `Title` , `TimesPlayed`, `Aspect` ) '+
+ 'VALUES (NULL , "' + Artist + '", "' + Title + '", "0", "'+ IntToStr(Aspect) +'");');
+ end else
+ begin
+
+ //Create new Entry
+ ScoreDB.ExecSQL ('UPDATE `Us_Songs` SET `Aspect` = "' + IntToStr(aspect) + '" WHERE `ID` = "' +
+ IntToStr(ID) + '"');
+ end;
+ except
+
+ end;
+end;
+
+(**
+ * Format a UNIX-Timestamp into DATE (If 0 then '')
+ *)
+function TDataBaseSystem.FormatDate(time_stamp: integer): String;
+var
+ Year, Month, Day: word;
+begin
+ Result:='';
+ try
+ if time_stamp<>0 then
+ begin
+ DecodeDate(UnixToDateTime(time_stamp), Year, Month, Day);
+ Result := Format(Language.Translate('STAT_FORMAT_DATE'), [Day, Month, Year]);
+ end;
+ except
+ on E: EConvertError do
+ //Log.LogError('Error Parsing FormatString "STAT_FORMAT_DATE": ' + E.Message); TODO
+ end;
+end;
+
+
+
+//--------------------
+//Create - Opens Database and Create Tables if not Exist
+//--------------------
+
+Procedure TDataBaseSystem.Init(const Filename: string);
+begin
+ //Open Database
+ ScoreDB := TSqliteDatabase.Create(Filename);
+ sFilename := Filename;
+
+ try
+ //Look for Tables => When not exist Create them
+ if not ScoreDB.TableExists('US_Scores') then
+ ScoreDB.execsql('CREATE TABLE `US_Scores` (`SongID` INT( 11 ) NOT NULL , '+
+ '`Difficulty` INT( 1 ) NOT NULL , `Player` VARCHAR( 150 ) NOT NULL , '+
+ '`Score` INT( 5 ) NOT NULL , `Date` INT NULL)');
+
+ if not ScoreDB.TableExists('US_Songs') then
+ ScoreDB.execsql('CREATE TABLE `US_Songs` (`ID` INTEGER PRIMARY KEY, '+
+ '`Artist` VARCHAR( 255 ) NOT NULL , `Title` VARCHAR( 255 ) NOT NULL , `TimesPlayed` int(5) NOT NULL );');
+
+ //add column date to cUS-Scores
+ if not ScoreDB.ContainsColumn('US_Scores', 'Date') then
+ begin
+ //Log.LogInfo('adding column date to "' + cUS_Scores + '"', 'TDataBaseSystem.Init'); TODO
+ ScoreDB.ExecSQL('ALTER TABLE ' + '`US_Scores`' + ' ADD COLUMN `Date` INT NULL');
+ end;
+
+ //add column aspect to cUS-Songs
+ if not ScoreDB.ContainsColumn('US_Songs', 'Aspect') then
+ begin
+ //0=acoStretch; 1=acoCrop; 2=acoLetterBox
+ ScoreDB.ExecSQL('ALTER TABLE ' + '`US_Songs`' + ' ADD COLUMN `Aspect` INT NULL');
+ end;
+ finally
+ //ScoreDB.Free;
+ end;
+
+end;
+
+//--------------------
+//Free - Frees Database
+//--------------------
+Destructor TDataBaseSystem.Free;
+begin
+ ScoreDB.Free;
+end;
+
+//--------------------
+//ReadScore - Read Scores into SongArray
+//--------------------
+procedure TDataBaseSystem.ReadScore(var Song: TSong);
+var
+ TableData: TSqliteTable;
+ Difficulty: Byte;
+ I: integer;
+ PlayerListed: boolean;
+ DateStr: string;
+
+begin
+ if not Assigned(ScoreDB) then
+ Exit;
+
+ try
+ //Search Song in DB
+ TableData := ScoreDB.GetTable('SELECT `Difficulty`, `Player`, `Score`, `Date` '+
+ 'FROM `us_scores` WHERE '+
+ '`SongID` = (SELECT `ID` FROM `us_songs` WHERE `Artist` = "' +
+ Song.Artist + '" AND `Title` = "' + Song.Title +
+ '" LIMIT 1) ORDER BY `Score` DESC;');
+ //Empty Old Scores
+ SetLength (Song.Score[0], 0); //easy
+ SetLength (Song.Score[1], 0); //medium
+ SetLength (Song.Score[2], 0); //hard
+
+ // Go through all Entrys
+ while (not TableData.EOF) do
+ begin
+ // Add one Entry to Array
+ Difficulty := StrToInt(TableData.FieldAsString(TableData.FieldIndex['Difficulty']));
+ if ((Difficulty >= 0) and (Difficulty <= 2)) and
+ (Length(Song.Score[Difficulty]) < 8) then
+ begin
+ //filter player
+ PlayerListed:=false;
+ if (Length(Song.Score[Difficulty])>0) then
+ begin
+ for I := 0 to Length(Song.Score[Difficulty]) - 1 do
+ begin
+ if (Song.Score[Difficulty, I].Name = TableData.FieldAsString(TableData.FieldIndex['Player'])) then
+ begin
+ PlayerListed:=true;
+ break;
+ end;
+ end;
+ end;
+
+ if not PlayerListed then
+ begin
+ SetLength(Song.Score[Difficulty], Length(Song.Score[Difficulty]) + 1);
+
+ Song.Score[Difficulty, High(Song.Score[Difficulty])].Name :=
+ TableData.FieldAsString(TableData.FieldIndex['Player']);
+ Song.Score[Difficulty, High(Song.Score[Difficulty])].Score :=
+ StrtoInt(TableData.FieldAsString(TableData.FieldIndex['Score']));
+ DateStr := TableData.FieldAsString(TableData.FieldIndex['Date']);
+ if DateStr<>'' then
+ Song.Score[Difficulty, High(Song.Score[Difficulty])].Date :=
+ FormatDate(StrToInt(DateStr))
+ else
+ Song.Score[Difficulty, High(Song.Score[Difficulty])].Date := '??.??.20??';
+ end;
+ end;
+
+ TableData.Next;
+ end; // while
+
+ except
+ for Difficulty := 0 to 2 do
+ begin
+ SetLength(Song.Score[Difficulty], 1);
+ Song.Score[Difficulty, 1].Name := 'Error Reading ScoreDB';
+ end;
+ end;
+
+end;
+
+//--------------------
+//AddScore - Add one new Score to DB
+//--------------------
+procedure TDataBaseSystem.AddScore(var Song: TSong; Level: integer; Name: string; Score: integer; TimeStamp: integer);
+var
+ID: Integer;
+TableData: TSqliteTable;
+begin
+ //ScoreDB := TSqliteDatabase.Create(sFilename);
+ try
+ //Prevent 0 Scores from being added
+ if (Score > 0) then
+ begin
+ try //todo : wrapper shouldn't throw exceptions at all - this fixed a wine bug, thanks linnex! (11.11.07)
+ ID := ScoreDB.GetTableValue('SELECT `ID` FROM `US_Songs` WHERE `Artist` = "' + Song.Artist + '" AND `Title` = "' + Song.Title + '"');
+ if ID = 0 then //Song doesn't exist -> Create
+ begin
+ ScoreDB.ExecSQL ('INSERT INTO `US_Songs` ( `ID` , `Artist` , `Title` , `TimesPlayed` ) '+
+ 'VALUES (NULL , "' + Song.Artist + '", "' + Song.Title + '", "0");');
+ ID := ScoreDB.GetTableValue('SELECT `ID` FROM `US_Songs` WHERE `Artist` = "' + Song.Artist + '" AND `Title` = "' + Song.Title + '"');
+
+ if ID = 0 then //Could not Create Table
+ exit;
+ end;
+
+ //Create new Entry
+ ScoreDB.ExecSQL('INSERT INTO `US_Scores` ( `SongID` , `Difficulty` , `Player` , `Score` , `Date` ) '+
+ 'VALUES ("' + InttoStr(ID) + '", "' + InttoStr(Level) + '", "' +
+ Name + '", "' + InttoStr(Score) + '","' + InttoStr(TimeStamp) + '");');
+
+ {
+ //Delete Last Position when there are more than 5 Entrys
+ if ScoreDB.GetTableValue('SELECT COUNT(`SongID`) FROM `US_Scores` WHERE `SongID` = "' + InttoStr(ID) + '" AND `Difficulty` = "' + InttoStr(Level) +'"') > 5 then
+ begin
+ TableData := ScoreDB.GetTable('SELECT `Player`, `Score` FROM `US_Scores` WHERE SongID = "' + InttoStr(ID) + '" AND `Difficulty` = "' + InttoStr(Level) +'" ORDER BY `Score` ASC LIMIT 1');
+ ScoreDB.ExecSQL('DELETE FROM `US_Scores` WHERE SongID = "' + InttoStr(ID) + '" AND `Difficulty` = "' + InttoStr(Level) +'" AND `Player` = "' + TableData.FieldAsString(TableData.FieldIndex['Player']) + '" AND `Score` = "' + TableData.FieldAsString(TableData.FieldIndex['Score']) + '"');
+ end; }
+ except
+ // katze!
+ end;
+ end;
+ finally
+ //ScoreDB.Free;
+ end;
+end;
+
+//--------------------
+//WriteScore - Not needed with new System; But used for Increment Played Count
+//--------------------
+procedure TDataBaseSystem.WriteScore(var Song: TSong);
+begin
+ try
+ //Increase TimesPlayed
+ ScoreDB.ExecSQL ('UPDATE `us_songs` SET `TimesPlayed` = `TimesPlayed` + "1" WHERE `Title` = "' + Song.Title + '" AND `Artist` = "' + Song.Artist + '";');
+ except
+
+ end;
+end;
+
+//--------------------
+//GetStats - Write some Stats to Array, Returns True if Chossen Page has Entrys
+//Case Typ of
+//0 - Best Scores
+//1 - Best Singers
+//2 - Most sung Songs
+//3 - Most popular Band
+//--------------------
+Function TDataBaseSystem.GetStats(var Stats: AStatResult; const Typ, Count: Byte; const Page: Cardinal; const Reversed: Boolean): Boolean;
+var
+ Query: String;
+ TableData: TSqliteTable;
+ DateStr: String;
+begin
+ Result := False;
+
+ if (Length(Stats) < Count) then
+ Exit;
+
+ {Todo:
+ Add Prevention that only Players with more than 5 Scores are Selected at Typ 2}
+
+ //Create Query
+ Case Typ of
+ 0: Query := 'SELECT `Player` , `Difficulty` , `Score` , `Artist` , `Title` , `Date` FROM `US_Scores` INNER JOIN `US_Songs` ON (`SongID` = `ID`) ORDER BY `Score`';
+ 1: Query := 'SELECT `Player` , ROUND (Sum(`Score`) / COUNT(`Score`)), COUNT(`rowid`) FROM `US_Scores` GROUP BY `Player` ORDER BY (Sum(`Score`) / COUNT(`Score`))';
+ 2: Query := 'SELECT `Artist` , `Title` , `TimesPlayed` FROM `US_Songs` ORDER BY `TimesPlayed`';
+ 3: Query := 'SELECT `Artist` , Sum(`TimesPlayed`) FROM `US_Songs` GROUP BY `Artist` ORDER BY Sum(`TimesPlayed`)';
+ end;
+
+ //Add Order Direction
+ If Reversed then
+ Query := Query + ' ASC'
+ else
+ Query := Query + ' DESC';
+
+ //Add Limit
+ Query := Query + ' LIMIT ' + InttoStr(Count * Page) + ', ' + InttoStr(Count) + ';';
+
+ //Execute Query
+ //try
+ TableData := ScoreDB.GetTable(Query);
+ {except
+ exit;
+ end;}
+
+ //if Result empty -> Exit
+ if (TableData.RowCount < 1) then
+ exit;
+
+ //Copy Result to Stats Array
+ while not TableData.Eof do
+ begin
+ Stats[TableData.Row].Typ := Typ;
+
+ Case Typ of
+ 0:begin
+ Stats[TableData.Row].Singer := TableData.Fields[0];
+
+ Stats[TableData.Row].Difficulty := StrtoIntDef(TableData.Fields[1], 0);
+
+ Stats[TableData.Row].Score := StrtoIntDef(TableData.Fields[2], 0){TableData.FieldAsInteger(2)};
+ Stats[TableData.Row].SongArtist := TableData.Fields[3];
+ Stats[TableData.Row].SongTitle := TableData.Fields[4];
+ DateStr := TableData.Fields[5];
+ if DateStr<>'' then
+ Stats[TableData.Row].Date := FormatDate(StrToInt(DateStr))
+ else
+ Stats[TableData.Row].Date := '??.??.20??';
+ end;
+
+ 1:begin
+ Stats[TableData.Row].Player := TableData.Fields[0];
+ Stats[TableData.Row].AverageScore := StrtoIntDef(TableData.Fields[1], 0);
+ Stats[TableData.Row].SungTimes := StrtoIntDef(TableData.Fields[2], 0);
+ end;
+
+ 2:begin
+ Stats[TableData.Row].Artist := TableData.Fields[0];
+ Stats[TableData.Row].Title := TableData.Fields[1];
+ Stats[TableData.Row].TimesSung := StrtoIntDef(TableData.Fields[2], 0);
+ end;
+
+ 3:begin
+ Stats[TableData.Row].ArtistName := TableData.Fields[0];
+ Stats[TableData.Row].TimesSungtot := StrtoIntDef(TableData.Fields[1], 0);
+ end;
+
+ end;
+
+ TableData.Next;
+ end;
+
+ Result := True;
+end;
+
+//--------------------
+//GetTotalEntrys - Get Total Num of entrys for a Stats Query
+//--------------------
+Function TDataBaseSystem.GetTotalEntrys(const Typ: Byte): Cardinal;
+var Query: String;
+begin
+ //Create Query
+ Case Typ of
+ 0: Query := 'SELECT COUNT(`SongID`) FROM `US_Scores`;';
+ 1: Query := 'SELECT COUNT(DISTINCT `Player`) FROM `US_Scores`;';
+ 2: Query := 'SELECT COUNT(`ID`) FROM `US_Songs`;';
+ 3: Query := 'SELECT COUNT(DISTINCT `Artist`) FROM `US_Songs`;';
+ end;
+
+ Result := ScoreDB.GetTableValue(Query);
+end;
+
+end.
diff --git a/Game/Code/Classes/UDraw.pas b/Game/Code/Classes/UDraw.pas
new file mode 100644
index 00000000..5b0a284c
--- /dev/null
+++ b/Game/Code/Classes/UDraw.pas
@@ -0,0 +1,1715 @@
+unit UDraw;
+
+interface
+uses UThemes, ModiSDK, UGraphicClasses;
+
+procedure SingDraw;
+procedure SingModiDraw (PlayerInfo: TPlayerInfo);
+procedure SingDrawBackground;
+procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer);
+procedure SingDrawNoteLines(Left, Top, Right: real; Space: integer);
+procedure SingDrawBeatDelimeters(Left, Top, Right: real; NrCzesci: integer);
+procedure SingDrawCzesc(Left, Top, Right: real; NrCzesci: integer; Space: integer);
+procedure SingDrawPlayerCzesc(X, Y, W: real; NrGracza: integer; Space: integer);
+procedure SingDrawPlayerBGCzesc(Left, Top, Right: real; NrCzesci, NrGracza: integer; Space: integer);
+
+// TimeBar mod
+procedure SingDrawTimeBar();
+// eoa TimeBar mod
+
+{ for no use since we have UGraphicClasses
+procedure SingDrawStar(X, Y, A: real);
+procedure SingGoldenStar(X, Y, A: real);
+}
+// The Singbar
+procedure SingDrawSingbar(X, Y, W, H: real; Percent: integer);
+
+//Phrasen Bonus - Line Bonus
+procedure SingDrawLineBonus( const X, Y: Single; Color: TRGB; Alpha: Single; Text: string; Age: Integer);
+
+//Draw Editor NoteLines
+procedure EditDrawCzesc(Left, Top, Right: real; NrCzesci: integer; Space: integer);
+
+
+type
+ TRecR = record
+ Top: real;
+ Left: real;
+ Right: real;
+ Bottom: real;
+
+ Width: real;
+ WMid: real;
+ Height: real;
+ HMid: real;
+
+ Mid: real;
+ end;
+
+var
+ NotesW: real;
+ NotesH: real;
+ Starfr: integer;
+ StarfrG: integer;
+
+
+
+ //SingBar Mod
+ TickOld: cardinal;
+ TickOld2:cardinal;
+ //end Singbar Mod
+
+
+
+
+const
+ Przedz = 32;
+
+implementation
+
+uses
+ Windows,
+ gl,
+ UGraphic,
+ SysUtils,
+ UMusic,
+ URecord,
+ ULog,
+ UScreenSing,
+ UScreenSingModi,
+ ULyrics,
+ UMain,
+ TextGL,
+ UTexture,
+ UDrawTexture,
+ UIni,
+ USongs,
+ Math,
+ UDLLManager;
+
+procedure SingDrawBackground;
+var
+ Rec: TRecR;
+ TexRec: TRecR;
+begin
+ if ScreenSing.Tex_Background.TexNum >= 1 then begin
+
+ glClearColor (1, 1, 1, 1);
+ glColor4f (1, 1, 1, 1);
+
+ if (Ini.MovieSize < 1) then //HalfSize BG
+ begin
+ (* half screen + gradient *)
+ Rec.Top := 110; // 80
+ Rec.Bottom := Rec.Top + 20;
+ Rec.Left := 0;
+ Rec.Right := 800;
+
+ TexRec.Top := (Rec.Top / 600) * ScreenSing.Tex_Background.TexH;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenSing.Tex_Background.TexH;
+ TexRec.Left := 0;
+ TexRec.Right := ScreenSing.Tex_Background.TexW;
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, ScreenSing.Tex_Background.TexNum);
+ glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+ (* gradient draw *)
+ (* top *)
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glColor4f(1, 1, 1, 1);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+ (* mid *)
+ Rec.Top := Rec.Bottom;
+ Rec.Bottom := 490 - 20; // 490 - 20
+ TexRec.Top := TexRec.Bottom;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenSing.Tex_Background.TexH;
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ (* bottom *)
+ Rec.Top := Rec.Bottom;
+ Rec.Bottom := 490; // 490
+ TexRec.Top := TexRec.Bottom;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenSing.Tex_Background.TexH;
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+
+ glEnd;
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ end
+ else //Full Size BG
+ begin
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, ScreenSing.Tex_Background.TexNum);
+ //glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0); glVertex2f(0, 0);
+ glTexCoord2f(0, ScreenSing.Tex_Background.TexH); glVertex2f(0, 600);
+ glTexCoord2f( ScreenSing.Tex_Background.TexW, ScreenSing.Tex_Background.TexH); glVertex2f(800, 600);
+ glTexCoord2f( ScreenSing.Tex_Background.TexW, 0); glVertex2f(800, 0);
+
+ glEnd;
+ glDisable(GL_TEXTURE_2D);
+ //glDisable(GL_BLEND);
+ end;
+ end;
+end;
+
+procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer);
+var
+ Pet: integer;
+begin;
+// Log.LogStatus('Oscilloscope', 'SingDraw');
+ glColor3f(Skin_OscR, Skin_OscG, Skin_OscB);
+ {if (ParamStr(1) = '-black') or (ParamStr(1) = '-fsblack') then
+ glColor3f(1, 1, 1); }
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(X, -Sound[NrSound].BufferArray[1] / $10000 * H + Y + H/2);
+ for Pet := 2 to Sound[NrSound].n div 1 do begin
+ glVertex2f(X + (Pet-1) * W / (Sound[NrSound].n - 1),
+ -Sound[NrSound].BufferArray[Pet] / $10000 * H + Y + H/2);
+ end;
+ glEnd;
+end;
+
+procedure SingDrawNoteLines(Left, Top, Right: real; Space: integer);
+var
+ Pet: integer;
+begin
+ glEnable(GL_BLEND);
+ glColor4f(Skin_P1_LinesR, Skin_P1_LinesG, Skin_P1_LinesB, 0.4);
+ glBegin(GL_LINES);
+ for Pet := 0 to 9 do begin
+ glVertex2f(Left, Top + Pet * Space);
+ glVertex2f(Right, Top + Pet * Space);
+ end;
+ glEnd;
+ glDisable(GL_BLEND);
+end;
+
+procedure SingDrawBeatDelimeters(Left, Top, Right: real; NrCzesci: integer);
+var
+ Pet: integer;
+ TempR: real;
+begin
+ TempR := (Right-Left) / (Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote);
+ glEnable(GL_BLEND);
+ glBegin(GL_LINES);
+ for Pet := Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote to Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec do begin
+ if (Pet mod Czesci[NrCzesci].Resolution) = Czesci[NrCzesci].NotesGAP then
+ glColor4f(0, 0, 0, 1)
+ else
+ glColor4f(0, 0, 0, 0.3);
+ glVertex2f(Left + TempR * (Pet - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote), Top);
+ glVertex2f(Left + TempR * (Pet - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote), Top + 135);
+ end;
+ glEnd;
+ glDisable(GL_BLEND);
+end;
+
+// draw blank Notebars
+procedure SingDrawCzesc(Left, Top, Right: real; NrCzesci: integer; Space: integer);
+var
+ Rec: TRecR;
+ Pet: integer;
+ TempR: real;
+ R,G,B: real;
+
+ GoldenStarPos : real;
+begin
+ glColor3f(1, 1, 1);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ TempR := (Right-Left) / (Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote);
+ with Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt] do begin
+ for Pet := 0 to HighNut do begin
+ with Nuta[Pet] do begin
+ if not FreeStyle then begin
+
+
+ if Ini.EffectSing = 0 then
+ // If Golden note Effect of then Change not Color
+ begin
+ case Wartosc of
+ 1: glColor4f(1, 1, 1, 0.85);
+ 2: glColor4f(1, 1, 0.3, 0.85); // no stars, paint yellow -> glColor4f(1, 1, 0.3, 0.85);
+ end; // case
+ end //Else all Notes same Color
+ else
+ glColor4f(1, 1, 1, 0.85);
+
+ // lewa czesc - left part
+ Rec.Left := (Start-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left + 0.5 + 10*ScreenX;
+ Rec.Right := Rec.Left + NotesW;
+ Rec.Top := Top - (Ton-BaseNote)*Space/2 - NotesH;
+ Rec.Bottom := Rec.Top + 2 * NotesH;
+ glBindTexture(GL_TEXTURE_2D, Tex_Left[Color].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;
+
+ //We keep the postion of the top left corner b4 it's overwritten
+ GoldenStarPos := Rec.Left;
+ //done
+
+
+ // srodkowa czesc - middle part
+ Rec.Left := Rec.Right;
+ Rec.Right := (Start+Dlugosc-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left - NotesW - 0.5 + 10*ScreenX;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_Mid[Color].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 - right part
+ Rec.Left := Rec.Right;
+ Rec.Right := Rec.Right + NotesW;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_Right[Color].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;
+
+ // Golden Star Patch
+ if (Wartosc = 2) AND (Ini.EffectSing=1) then
+ begin
+ GoldenRec.SaveGoldenStarsRec(GoldenStarPos, Rec.Top, Rec.Right, Rec.Bottom);
+ end;
+
+ end; // if not FreeStyle
+ end; // with
+ end; // for
+ end; // with
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
+
+// draw sung notes
+procedure SingDrawPlayerCzesc(X, Y, W: real; NrGracza: 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');
+
+// if NrGracza = 0 then LoadColor(R, G, B, 'P1Light')
+// else LoadColor(R, G, B, 'P2Light');
+
+// 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 begin
+ TempR := W / (Czesci[0].Czesc[Czesci[0].Akt].Koniec - Czesci[0].Czesc[Czesci[0].Akt].StartNote);
+ for N := 0 to Player[NrGracza].HighNut do begin
+ with Player[NrGracza].Nuta[N] do begin
+ // lewa czesc
+ Rec.Left := X + (Start-Czesci[0].Czesc[Czesci[0].Akt].StartNote) * TempR + 0.5 + 10*ScreenX;
+ Rec.Right := Rec.Left + NotesW;
+
+
+ // Half size Notes Patch
+ if Hit then begin
+ NotesH2 := NotesH
+ end else begin
+ NotesH2 := int(NotesH * 0.65);
+ end; //if
+
+
+
+ // if True then
+ Rec.Top := Y - (Ton-Czesci[0].Czesc[Czesci[0].Akt].BaseNote)*Space/2 - NotesH2;
+ Rec.Bottom := Rec.Top + 2 *NotesH2;
+
+ 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;
+
+ // srodkowa czesc
+ Rec.Left := Rec.Right;
+ Rec.Right := X + (Start+Dlugosc-Czesci[0].Czesc[Czesci[0].Akt].StartNote) * TempR - NotesW - 0.5 + 10*ScreenX;
+ // (nowe)
+ if (Start+Dlugosc-1 = Czas.AktBeatD) then
+ Rec.Right := Rec.Right - (1-Frac(Czas.MidBeatD)) * TempR;
+
+ if Rec.Right <= Rec.Left then Rec.Right := Rec.Left;
+
+
+// glColor3f(R, G, B);
+// glBindTexture(GL_TEXTURE_2D, Tex_MidGray.TexNum);
+ glBindTexture(GL_TEXTURE_2D, Tex_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;
+ glColor3f(1, 1, 1);
+
+ // prawa czesc
+ 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;
+
+
+
+ //Rec.Right := X + (Start+Dlugosc-Czesci[0].Czesc[Czesci[0].Akt].StartNote) * TempR - NotesW - 0.5 + 10*ScreenX;
+ //if (Start+Dlugosc-1 = Czas.AktBeatD) then
+ if Perfect and (Ini.EffectSing=1) then begin
+// A := sqrt((1+sin(Music.Position * 3))/2);
+ A := 1 - 2*(Czas.Teraz - GetTimeFromBeat(Start+Dlugosc));
+ if not (Start+Dlugosc-1 = Czas.AktBeatD) then
+
+ //Star animation counter
+ //inc(Starfr);
+ //Starfr := Starfr mod 128;
+ GoldenRec.SavePerfectNotePos(Rec.Left, Rec.Top);
+ { SingDrawStar(Rec.Left+2, Rec.Top+4, A);}
+ end;
+
+ // detekt
+{ Rec.Left := Round((Detekt-Czesci.Czesc[Czesci.Akt].Start) * TempR) + 130;
+ glColor3f(1, 0.2, 0.2);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUADS);
+ glVertex(Rec.Left, Rec.Top-5);
+ glVertex(Rec.Left, Rec.Bottom+5);
+ glVertex(Rec.Left+1, Rec.Bottom+5);
+ glVertex(Rec.Left+1, Rec.Top-5);
+ glEnd;
+ glColor3f(1, 1, 1);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);}
+
+ // detekt + FFT length
+{ Rec.Right := (Detekt-Czesci.Czesc[Czesci.Akt].Start) * TempR + 130;
+ // TempR = dlugosc 1 kostki
+ // 60 * 4 / BPM = czas w sekundach na 1 kostke, np. 0,4s
+ // 4096 / 44100 = czas jednego sampla FFT, np. 0,1s
+ // ile to ma kostek? np. 0.25
+ // (4096 / 44100) / (60 * 4 / BPM), np. 0,1s / 0,4s = 0.25
+ // * TempR = dlugosc sampla FFT
+ Rec.Left := Rec.Right - (Sound.n / 44100) / (60 * 4 / Muzyka.BPM) * TempR;
+
+ glColor3f(1, 0.2, 0.2);
+ glVertex(Rec.Left, Rec.Top-4);
+ glVertex(Rec.Left, Rec.Bottom+4);
+ glVertex(Rec.Right, Rec.Bottom+4);
+ glVertex(Rec.Right, Rec.Top-4);}
+
+ 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_
+
+ // 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);
+ end; // if
+end;
+
+//draw Note glow
+procedure SingDrawPlayerBGCzesc(Left, Top, Right: real; NrCzesci, NrGracza: integer; Space: integer);
+var
+ Rec: TRecR;
+ Pet: integer;
+ TempR: real;
+ R,G,B: real;
+ X1, X2, X3, X4: real;
+ W, H: real;
+begin
+ if (Player[NrGracza].ScoreTotalI >= 0) then begin
+ glColor4f(1, 1, 1, sqrt((1+sin(Music.Position * 3))/4)/ 2 + 0.5 );
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ TempR := (Right-Left) / (Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote);
+ with Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt] do begin
+ for Pet := 0 to HighNut do begin
+ with Nuta[Pet] do begin
+ if not FreeStyle then begin
+ // begin: 14, 20
+ // easy: 6, 11
+ W := NotesW * 2 + 2;
+ H := NotesH * 1.5 + 3.5;
+
+ X2 := (Start-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left + 0.5 + 10*ScreenX + 4; // wciecie
+ X1 := X2-W;
+
+ X3 := (Start+Dlugosc-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left - 0.5 + 10*ScreenX - 4; // wciecie
+ X4 := X3+W;
+
+ // left
+ Rec.Left := X1;
+ Rec.Right := X2;
+ Rec.Top := Top - (Ton-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;
+
+ 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;
+
+ // prawa czesc
+ Rec.Left := X3;
+ Rec.Right := X4;
+
+ 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
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ end;
+end;
+
+{not used anymore tough we have UGraphicClasses
+procedure SingDrawStar(X, Y, A: real);
+var
+ TempR: real;
+ W, H: real;
+ Starframe: real;
+ begin
+ W := 32;
+ H := 32;
+
+// Golden Star Patch
+// case Z of
+// 1: glColor4f(1, 1, 1, A);
+// 2: glColor4f(1, 1, 0.3, A);
+// end; // case
+
+ glColor4f(1, 1, 1, A);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_Note_Star.TexNum);
+
+ Starframe := 15 - ((GetTickCount div 33) mod 16);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f((1/16) * Starframe, 0); glVertex2f(X-W, Y-H);
+ glTexCoord2f((1/16) * Starframe + (1/16), 0); glVertex2f(X-W, Y+H);
+ glTexCoord2f((1/16) * Starframe + (1/16), 1); glVertex2f(X+W, Y+H);
+ glTexCoord2f((1/16) * Starframe, 1); glVertex2f(X+W, Y-H);
+ glEnd;
+end;
+}
+
+{not used anymore tough we have UGraphicClasses
+procedure SingGoldenStar(X, Y, A: real);
+var
+ TempR: real;
+ W, H: real;
+ StarfrG2: real;
+ begin
+ W := 16;
+ H := 16;
+ glColor4f(1, 1, 0.3, A);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_Note_Star.TexNum);
+ StarfrG2 := 15 - ((GetTickCount div 67) mod 16);
+ glBegin(GL_QUADS);
+ //x1
+ glTexCoord2f((1/16) * StarfrG2, 0); glVertex2f(X-W, Y-H);
+ glTexCoord2f((1/16) * StarfrG2 + (1/16), 0); glVertex2f(X-W, Y+H);
+ glTexCoord2f((1/16) * StarfrG2 + (1/16), 1); glVertex2f(X+W, Y+H);
+ glTexCoord2f((1/16) * StarfrG2, 1); glVertex2f(X+W, Y-H);
+ glEnd;
+end;
+}
+
+procedure SingDraw;
+var
+ Pet: integer;
+ Pet2: integer;
+ TempR: real;
+ Rec: TRecR;
+ TexRec: TRecR;
+ NR: TRecR;
+ FS: real;
+ BarFrom: integer;
+ BarAlpha: real;
+ BarWspol: real;
+ TempCol: real;
+ Tekst: string;
+ LyricTemp: string;
+ PetCz: integer;
+
+
+
+ //SingBar Mod
+ A: Integer;
+ E: Integer;
+ I: Integer;
+ //end Singbar Mod
+
+
+
+begin
+ // positions
+ if Ini.SingWindow = 0 then begin
+ NR.Left := 120;
+ end else begin
+ NR.Left := 20;
+ end;
+ NR.Right := 780;
+
+ NR.Width := NR.Right - NR.Left;
+ NR.WMid := NR.Width / 2;
+ NR.Mid := NR.Left + NR.WMid;
+
+ // background //BG Fullsize Mod
+ //SingDrawBackground;
+
+ //TimeBar mod
+ SingDrawTimeBar();
+ //eoa TimeBar mod
+
+ // rysuje paski pod nutami
+ if PlayersPlay = 1 then
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ if (PlayersPlay = 2) or (PlayersPlay = 4) then begin
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P1_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ end;
+
+ if (PlayersPlay = 3) or (PlayersPlay = 6) then begin
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 120, Nr.Right + 10*ScreenX, 12);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 245, Nr.Right + 10*ScreenX, 12);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 370, Nr.Right + 10*ScreenX, 12);
+ end;
+
+ // rysuje tekst - new Lyric engine
+ ScreenSing.LyricMain.Draw;
+ ScreenSing.LyricSub.Draw;
+
+ // rysuje pasek, podpowiadajacy poczatek spiwania w scenie
+ FS := 1.3;
+ BarFrom := Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czesci[0].Czesc[Czesci[0].Akt].Start;
+ if BarFrom > 40 then BarFrom := 40;
+ if (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czesci[0].Czesc[Czesci[0].Akt].Start > 8) and // dluga przerwa //16->12 for more help bars and then 12->8 for even more
+ (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czas.MidBeat > 0) and // przed tekstem
+ (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czas.MidBeat < 40) then begin // ale nie za wczesnie
+ BarWspol := (Czas.MidBeat - (Czesci[0].Czesc[Czesci[0].Akt].StartNote - BarFrom)) / BarFrom;
+ Rec.Left := NR.Left + BarWspol *
+// (NR.WMid - Czesci[0].Czesc[Czesci[0].Akt].LyricWidth / 2 * FS - 50);
+ (ScreenSing.LyricMain.ClientX - NR.Left - 50) + 10*ScreenX;
+ Rec.Right := Rec.Left + 50;
+ Rec.Top := Skin_LyricsT + 3;
+ Rec.Bottom := Rec.Top + 33;//SingScreen.LyricMain.Size * 3;
+{ // zapalanie
+ BarAlpha := (BarWspol*10) * 0.5;
+ if BarAlpha > 0.5 then BarAlpha := 0.5;
+
+ // gaszenie
+ if BarWspol > 0.95 then BarAlpha := 0.5 * (1 - (BarWspol - 0.95) * 20);}
+
+ //Change fuer Crazy Joker
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_Lyric_Help_Bar.TexNum);
+ glBegin(GL_QUADS);
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glColor4f(1, 1, 1, 0.5);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+ glDisable(GL_BLEND);
+
+ end;
+
+ // oscilloscope
+ if Ini.Oscilloscope = 1 then begin
+ if PlayersPlay = 1 then
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+
+ if PlayersPlay = 2 then begin
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1);
+ end;
+
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 2);
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 3);
+ end;
+ end;
+
+ if PlayersPlay = 3 then begin
+ SingDrawOscilloscope(75 + 10*ScreenX, 95, 100, 20, 0);
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1);
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2);
+ end;
+
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0);
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1);
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 3);
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 4);
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 5);
+ end;
+ end;
+
+ end
+
+ //SingBar Mod
+ //modded again to make it moveable: it's working, so why try harder
+ else if Ini.Oscilloscope = 2 then begin
+ A := GetTickCount div 33;
+ if A <> Tickold then begin
+ Tickold := A;
+ for E := 0 to (PlayersPlay - 1) do begin //Set new Pos + Alpha
+ I := Player[E].ScorePercentTarget - Player[E].ScorePercent;
+ if I > 0 then Inc(Player[E].ScorePercent)
+ else if I < 0 then Dec(Player[E].ScorePercent);
+ end; //for
+ end; //if
+ if PlayersPlay = 1 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1SingBar.x, Theme.Sing.StaticP1SingBar.y, Theme.Sing.StaticP1SingBar.w, Theme.Sing.StaticP1SingBar.h , Player[0].ScorePercent);
+ end;
+ if PlayersPlay = 2 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[1].ScorePercent);
+ end;
+ if PlayersPlay = 3 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[2].ScorePercent);
+ end;
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[1].ScorePercent);
+ end;
+ if ScreenAct = 2 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[3].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[3].ScorePercent);
+ end;
+ end;
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[2].ScorePercent);
+ end;
+ if ScreenAct = 2 then begin
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[3].ScorePercent);
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[4].ScorePercent);
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[5].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[3].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[4].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[5].ScorePercent);
+ end;
+ end;
+ end;
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ if Ini.LineBonus > 0 then begin
+ A := GetTickCount div 33;
+ if (A <> Tickold2) AND (Player[0].LineBonus_Visible) then begin
+ Tickold2 := A;
+ for E := 0 to (PlayersPlay - 1) do begin
+ //Change Alpha
+ Player[E].LineBonus_Alpha := Player[E].LineBonus_Alpha - 0.02;
+ if Player[E].LineBonus_Alpha <= 0 then
+ begin
+ Player[E].LineBonus_Age := 0;
+ Player[E].LineBonus_Visible := False
+ end
+ else
+ begin
+ inc(Player[E].LineBonus_Age, 1);
+ //Change Position
+ if (Player[E].LineBonus_PosX < Player[E].LineBonus_TargetX) then
+ Player[E].LineBonus_PosX := Player[E].LineBonus_PosX + (2 - Player[E].LineBonus_Alpha * 1.5)
+ else if (Player[E].LineBonus_PosX > Player[E].LineBonus_TargetX) then
+ Player[E].LineBonus_PosX := Player[E].LineBonus_PosX - (2 - Player[E].LineBonus_Alpha * 1.5);
+
+ if (Player[E].LineBonus_PosY < Player[E].LineBonus_TargetY) then
+ Player[E].LineBonus_PosY := Player[E].LineBonus_PosY + (2 - Player[E].LineBonus_Alpha * 1.5)
+ else if (Player[E].LineBonus_PosY > Player[E].LineBonus_TargetY) then
+ Player[E].LineBonus_PosY := Player[E].LineBonus_PosY - (2 - Player[E].LineBonus_Alpha * 1.5);
+
+ end;
+ end;
+ end; //if
+
+ if PlayersPlay = 1 then begin
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ end
+ else if PlayersPlay = 2 then begin
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ end
+ else if PlayersPlay = 3 then begin
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ end
+ else if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ SingDrawLineBonus( Player[3].LineBonus_PosX, Player[3].LineBonus_PosY, Player[3].LineBonus_Color, Player[3].LineBonus_Alpha, Player[3].LineBonus_Text, Player[3].LineBonus_Age);
+ end;
+ end;
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawLineBonus( Player[3].LineBonus_PosX, Player[3].LineBonus_PosY, Player[3].LineBonus_Color, Player[3].LineBonus_Alpha, Player[3].LineBonus_Text, Player[3].LineBonus_Age);
+ SingDrawLineBonus( Player[4].LineBonus_PosX, Player[4].LineBonus_PosY, Player[4].LineBonus_Color, Player[4].LineBonus_Alpha, Player[4].LineBonus_Text, Player[4].LineBonus_Age);
+ SingDrawLineBonus( Player[5].LineBonus_PosX, Player[5].LineBonus_PosY, Player[5].LineBonus_Color, Player[5].LineBonus_Alpha, Player[5].LineBonus_Text, Player[5].LineBonus_Age);
+ end;
+ end;
+ end;
+ //PhrasenBonus - Line Bonus Mod End
+
+
+ // rysuje paski
+// Log.LogStatus('Original notes', 'SingDraw');
+ case Ini.Difficulty of
+ 0:
+ begin
+ NotesH := 11; // 9
+ NotesW := 6; // 5
+ end;
+ 1:
+ begin
+ NotesH := 8; // 7
+ NotesW := 4; // 4
+ end;
+ 2:
+ begin
+ NotesH := 5;
+ NotesW := 3;
+ end;
+ end;
+
+ if PlayersPlay = 1 then begin
+ SingDrawPlayerBGCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 0, 15);
+ end;
+
+ if (PlayersPlay = 2) then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15);
+
+ SingDrawCzesc(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15);
+ end;
+
+ if PlayersPlay = 3 then begin
+ NotesW := NotesW * 0.8;
+ NotesH := NotesH * 0.8;
+
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12);
+
+ SingDrawCzesc(NR.Left + 20, 120+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 245+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 370+95, NR.Right - 20, 0, 12);
+
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12);
+ end;
+
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 2, 15);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 3, 15);
+ end;
+
+ SingDrawCzesc(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 2, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 3, 15);
+ end;
+ end;
+
+ if PlayersPlay = 6 then begin
+ NotesW := NotesW * 0.8;
+ NotesH := NotesH * 0.8;
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 3, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 4, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 5, 12);
+ end;
+
+ SingDrawCzesc(NR.Left + 20, 120+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 245+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 370+95, NR.Right - 20, 0, 12);
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 3, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 4, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 5, 12);
+ end;
+ end;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
+procedure SingModiDraw (PlayerInfo: TPlayerInfo);
+var
+ Pet: integer;
+ Pet2: integer;
+ TempR: real;
+ Rec: TRecR;
+ TexRec: TRecR;
+ NR: TRecR;
+ FS: real;
+ BarFrom: integer;
+ BarAlpha: real;
+ BarWspol: real;
+ TempCol: real;
+ Tekst: string;
+ LyricTemp: string;
+ PetCz: integer;
+
+
+
+ //SingBar Mod
+ A: Integer;
+ E: Integer;
+ I: Integer;
+ //end Singbar Mod
+
+
+
+begin
+ // positions
+ if Ini.SingWindow = 0 then begin
+ NR.Left := 120;
+ end else begin
+ NR.Left := 20;
+ end;
+ NR.Right := 780;
+
+ NR.Width := NR.Right - NR.Left;
+ NR.WMid := NR.Width / 2;
+ NR.Mid := NR.Left + NR.WMid;
+
+ // background //BG Fullsize Mod
+ //SingDrawBackground;
+
+ // time bar
+// Log.LogStatus('Time Bar', 'SingDraw');
+ SingDrawTimeBar();
+
+ if DLLMan.Selected.ShowNotes then
+ begin
+ // rysuje paski pod nutami
+ if PlayersPlay = 1 then
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ if (PlayersPlay = 2) or (PlayersPlay = 4) then begin
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P1_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15);
+ end;
+
+ if (PlayersPlay = 3) or (PlayersPlay = 6) then begin
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 120, Nr.Right + 10*ScreenX, 12);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 245, Nr.Right + 10*ScreenX, 12);
+ SingDrawNoteLines(Nr.Left + 10*ScreenX, 370, Nr.Right + 10*ScreenX, 12);
+ end;
+ end;
+
+ // rysuje tekst - new Lyric engine
+ ScreenSingModi.LyricMain.Draw;
+ ScreenSingModi.LyricSub.Draw;
+
+ // rysuje pasek, podpowiadajacy poczatek spiwania w scenie
+ FS := 1.3;
+ BarFrom := Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czesci[0].Czesc[Czesci[0].Akt].Start;
+ if BarFrom > 40 then BarFrom := 40;
+ if (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czesci[0].Czesc[Czesci[0].Akt].Start > 8) and // dluga przerwa //16->12 for more help bars and then 12->8 for even more
+ (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czas.MidBeat > 0) and // przed tekstem
+ (Czesci[0].Czesc[Czesci[0].Akt].StartNote - Czas.MidBeat < 40) then begin // ale nie za wczesnie
+ BarWspol := (Czas.MidBeat - (Czesci[0].Czesc[Czesci[0].Akt].StartNote - BarFrom)) / BarFrom;
+ Rec.Left := NR.Left + BarWspol *
+ // (NR.WMid - Czesci[0].Czesc[Czesci[0].Akt].LyricWidth / 2 * FS - 50);
+ (ScreenSingModi.LyricMain.ClientX - NR.Left - 50) + 10*ScreenX;
+ Rec.Right := Rec.Left + 50;
+ Rec.Top := Skin_LyricsT + 3;
+ Rec.Bottom := Rec.Top + 33;//SingScreen.LyricMain.Size * 3;
+{ // zapalanie
+ BarAlpha := (BarWspol*10) * 0.5;
+ if BarAlpha > 0.5 then BarAlpha := 0.5;
+
+ // gaszenie
+ if BarWspol > 0.95 then BarAlpha := 0.5 * (1 - (BarWspol - 0.95) * 20);}
+
+ //Change fuer Crazy Joker
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_Lyric_Help_Bar.TexNum);
+ glBegin(GL_QUADS);
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom);
+ glColor4f(1, 1, 1, 0.5);
+ glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top);
+ glEnd;
+ glDisable(GL_BLEND);
+ end;
+
+ // oscilloscope
+ if (((Ini.Oscilloscope = 1) AND (DLLMan.Selected.ShowRateBar_O)) AND (NOT DLLMan.Selected.ShowRateBar)) then begin
+ if PlayersPlay = 1 then
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+
+ if PlayersPlay = 2 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1);
+ end;
+
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 2);
+ if PlayerInfo.Playerinfo[3].Enabled then
+ SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 3);
+ end;
+ end;
+
+ if PlayersPlay = 3 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawOscilloscope(75 + 10*ScreenX, 95, 100, 20, 0);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2);
+ end;
+
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[3].Enabled then
+ SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 3);
+ if PlayerInfo.Playerinfo[4].Enabled then
+ SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 4);
+ if PlayerInfo.Playerinfo[5].Enabled then
+ SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 5);
+ end;
+ end;
+
+ end
+
+ //SingBar Mod
+ // was fürn sinn hattn der quark hier?
+ else if ((Ini.Oscilloscope = 2) AND (DLLMan.Selected.ShowRateBar_O)) OR (DLLMan.Selected.ShowRateBar) then begin
+ A := GetTickCount div 33;
+ if A <> Tickold then begin
+ Tickold := A;
+ for E := 0 to (PlayersPlay - 1) do begin //Set new Pos + Alpha
+ I := Player[E].ScorePercentTarget - Player[E].ScorePercent;
+ if I > 0 then Inc(Player[E].ScorePercent)
+ else if I < 0 then Dec(Player[E].ScorePercent);
+ end; //for
+ end; //if
+ if PlayersPlay = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1SingBar.x, Theme.Sing.StaticP1SingBar.y, Theme.Sing.StaticP1SingBar.w, Theme.Sing.StaticP1SingBar.h , Player[0].ScorePercent);
+ end;
+ if PlayersPlay = 2 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[0].ScorePercent);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[1].ScorePercent);
+ end;
+ if PlayersPlay = 3 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[0].ScorePercent);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[1].ScorePercent);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[2].ScorePercent);
+ end;
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[0].ScorePercent);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[1].ScorePercent);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[2].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1TwoPSingBar.x, Theme.Sing.StaticP1TwoPSingBar.y, Theme.Sing.StaticP1TwoPSingBar.w, Theme.Sing.StaticP1TwoPSingBar.h , Player[2].ScorePercent);
+ if PlayerInfo.Playerinfo[3].Enabled then
+ //SingDrawSingbar(620 + 10*ScreenX, 95, 100, 8, Player[3].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2RSingBar.x, Theme.Sing.StaticP2RSingBar.y, Theme.Sing.StaticP2RSingBar.w, Theme.Sing.StaticP2RSingBar.h , Player[3].ScorePercent);
+ end;
+ end;
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[0].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[0].ScorePercent);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[1].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[1].ScorePercent);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[2].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[2].ScorePercent);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[3].Enabled then
+ //SingDrawSingbar( 75 + 10*ScreenX, 95, 100, 8, Player[3].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP1ThreePSingBar.x, Theme.Sing.StaticP1ThreePSingBar.y, Theme.Sing.StaticP1ThreePSingBar.w, Theme.Sing.StaticP1ThreePSingBar.h , Player[3].ScorePercent);
+ if PlayerInfo.Playerinfo[4].Enabled then
+ //SingDrawSingbar(370 + 10*ScreenX, 95, 100, 8, Player[4].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP2MSingBar.x, Theme.Sing.StaticP2MSingBar.y, Theme.Sing.StaticP2MSingBar.w, Theme.Sing.StaticP2MSingBar.h , Player[4].ScorePercent);
+ if PlayerInfo.Playerinfo[5].Enabled then
+ //SingDrawSingbar(670 + 10*ScreenX, 95, 100, 8, Player[5].ScorePercent);
+ SingDrawSingbar(Theme.Sing.StaticP3SingBar.x, Theme.Sing.StaticP3SingBar.y, Theme.Sing.StaticP3SingBar.w, Theme.Sing.StaticP3SingBar.h , Player[5].ScorePercent);
+ end;
+ end;
+ end;
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ if ((Ini.LineBonus > 0) AND (DLLMan.Selected.EnLineBonus_O)) OR (DLLMan.Selected.EnLineBonus) then begin
+ A := GetTickCount div 33;
+ if (A <> Tickold2) AND (Player[0].LineBonus_Visible) then begin
+ Tickold2 := A;
+ for E := 0 to (PlayersPlay - 1) do begin
+ //Change Alpha
+ Player[E].LineBonus_Alpha := Player[E].LineBonus_Alpha - 0.02;
+
+
+ if Player[E].LineBonus_Alpha <= 0 then
+ begin
+ Player[E].LineBonus_Age := 0;
+ Player[E].LineBonus_Visible := False
+
+ end
+ else
+ begin
+ inc(Player[E].LineBonus_Age, 1);
+
+ //Change Position
+ if (Player[E].LineBonus_PosX < Player[E].LineBonus_TargetX) then
+ Player[E].LineBonus_PosX := Player[E].LineBonus_PosX + (2 - Player[E].LineBonus_Alpha * 1.5)
+ else if (Player[E].LineBonus_PosX > Player[E].LineBonus_TargetX) then
+ Player[E].LineBonus_PosX := Player[E].LineBonus_PosX - (2 - Player[E].LineBonus_Alpha * 1.5);
+
+ if (Player[E].LineBonus_PosY < Player[E].LineBonus_TargetY) then
+ Player[E].LineBonus_PosY := Player[E].LineBonus_PosY + (2 - Player[E].LineBonus_Alpha * 1.5)
+ else if (Player[E].LineBonus_PosY > Player[E].LineBonus_TargetY) then
+ Player[E].LineBonus_PosY := Player[E].LineBonus_PosY - (2 - Player[E].LineBonus_Alpha * 1.5);
+
+ end;
+ end;
+ end; //if
+
+ if PlayersPlay = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ end
+ else if PlayersPlay = 2 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ end
+ else if PlayersPlay = 3 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ end
+ else if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ if PlayerInfo.Playerinfo[3].Enabled then
+ SingDrawLineBonus( Player[3].LineBonus_PosX, Player[3].LineBonus_PosY, Player[3].LineBonus_Color, Player[3].LineBonus_Alpha, Player[3].LineBonus_Text, Player[3].LineBonus_Age);
+ end;
+ end;
+ if PlayersPlay = 6 then begin
+ if ScreenAct = 1 then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ SingDrawLineBonus( Player[0].LineBonus_PosX, Player[0].LineBonus_PosY, Player[0].LineBonus_Color, Player[0].LineBonus_Alpha, Player[0].LineBonus_Text, Player[0].LineBonus_Age);
+ if PlayerInfo.Playerinfo[1].Enabled then
+ SingDrawLineBonus( Player[1].LineBonus_PosX, Player[1].LineBonus_PosY, Player[1].LineBonus_Color, Player[1].LineBonus_Alpha, Player[1].LineBonus_Text, Player[1].LineBonus_Age);
+ if PlayerInfo.Playerinfo[2].Enabled then
+ SingDrawLineBonus( Player[2].LineBonus_PosX, Player[2].LineBonus_PosY, Player[2].LineBonus_Color, Player[2].LineBonus_Alpha, Player[2].LineBonus_Text, Player[2].LineBonus_Age);
+ end;
+ if ScreenAct = 2 then begin
+ if PlayerInfo.Playerinfo[3].Enabled then
+ SingDrawLineBonus( Player[3].LineBonus_PosX, Player[3].LineBonus_PosY, Player[3].LineBonus_Color, Player[3].LineBonus_Alpha, Player[3].LineBonus_Text, Player[3].LineBonus_Age);
+ if PlayerInfo.Playerinfo[4].Enabled then
+ SingDrawLineBonus( Player[4].LineBonus_PosX, Player[4].LineBonus_PosY, Player[4].LineBonus_Color, Player[4].LineBonus_Alpha, Player[4].LineBonus_Text, Player[4].LineBonus_Age);
+ if PlayerInfo.Playerinfo[5].Enabled then
+ SingDrawLineBonus( Player[5].LineBonus_PosX, Player[5].LineBonus_PosY, Player[5].LineBonus_Color, Player[5].LineBonus_Alpha, Player[5].LineBonus_Text, Player[5].LineBonus_Age);
+ end;
+ end;
+ end;
+ //PhrasenBonus - Line Bonus Mod End
+
+
+ // rysuje paski
+// Log.LogStatus('Original notes', 'SingDraw');
+ case Ini.Difficulty of
+ 0:
+ begin
+ NotesH := 11; // 9
+ NotesW := 6; // 5
+ end;
+ 1:
+ begin
+ NotesH := 8; // 7
+ NotesW := 4; // 4
+ end;
+ 2:
+ begin
+ NotesH := 5;
+ NotesW := 3;
+ end;
+ end;
+
+ if (DLLMAn.Selected.ShowNotes And DLLMan.Selected.LoadSong) then
+ begin
+ if (PlayersPlay = 1) And PlayerInfo.Playerinfo[0].Enabled then begin
+ SingDrawPlayerBGCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 0, 15);
+ end;
+
+ if (PlayersPlay = 2) then begin
+ if PlayerInfo.Playerinfo[0].Enabled then
+ begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15);
+ end;
+ if PlayerInfo.Playerinfo[1].Enabled then
+ begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15);
+ end;
+
+ end;
+
+ if PlayersPlay = 3 then begin
+ NotesW := NotesW * 0.8;
+ NotesH := NotesH * 0.8;
+
+ if PlayerInfo.Playerinfo[0].Enabled then
+ begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 120+95, NR.Right - 20, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12);
+ end;
+
+ if PlayerInfo.Playerinfo[1].Enabled then
+ begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12);
+ SingDrawCzesc(NR.Left + 20, 245+95, NR.Right - 20, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12);
+ end;
+
+ if PlayerInfo.Playerinfo[2].Enabled then
+ begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12);
+ SingDrawCzesc(NR.Left + 20, 370+95, NR.Right - 20, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12);
+ end;
+ end;
+
+ if PlayersPlay = 4 then begin
+ if ScreenAct = 1 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 2, 15);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 3, 15);
+ end;
+
+ SingDrawCzesc(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15);
+ SingDrawCzesc(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15);
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 2, 15);
+ SingDrawPlayerCzesc(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 3, 15);
+ end;
+ end;
+
+ if PlayersPlay = 6 then begin
+ NotesW := NotesW * 0.8;
+ NotesH := NotesH * 0.8;
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 3, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 4, 12);
+ SingDrawPlayerBGCzesc(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 5, 12);
+ end;
+
+ SingDrawCzesc(NR.Left + 20, 120+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 245+95, NR.Right - 20, 0, 12);
+ SingDrawCzesc(NR.Left + 20, 370+95, NR.Right - 20, 0, 12);
+
+ if ScreenAct = 1 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12);
+ end;
+ if ScreenAct = 2 then begin
+ SingDrawPlayerCzesc(Nr.Left + 20, 120+95, Nr.Width - 40, 3, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 245+95, Nr.Width - 40, 4, 12);
+ SingDrawPlayerCzesc(Nr.Left + 20, 370+95, Nr.Width - 40, 5, 12);
+ end;
+ end;
+ end;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
+
+//SingBar Mod
+procedure SingDrawSingbar(X, Y, W, H: real; Percent: integer);
+var
+ R: Real;
+ G: Real;
+ B: Real;
+ A: cardinal;
+ I: Integer;
+
+begin;
+
+ //SingBar Background
+ glColor4f(1, 1, 1, 0.8);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_SingBar_Back.TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(X, Y);
+ glTexCoord2f(0, 1); glVertex2f(X, Y+H);
+ glTexCoord2f(1, 1); glVertex2f(X+W, Y+H);
+ glTexCoord2f(1, 0); glVertex2f(X+W, Y);
+ glEnd;
+
+ //SingBar coloured Bar
+ Case Percent of
+ 0..22: begin
+ R := 1;
+ G := 0;
+ B := 0;
+ end;
+ 23..42: begin
+ R := 1;
+ G := ((Percent-23)/100)*5;
+ B := 0;
+ end;
+ 43..57: begin
+ R := 1;
+ G := 1;
+ B := 0;
+ end;
+ 58..77: begin
+ R := 1-(Percent - 58)/100*5;
+ G := 1;
+ B := 0;
+ end;
+ 78..99: begin
+ R := 0;
+ G := 1;
+ B := 0;
+ end;
+ End; //Case
+
+ glColor4f(R, G, B, 1);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_SingBar_Bar.TexNum);
+ //Size= Player[PlayerNum].ScorePercent of W
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(X, Y);
+ glTexCoord2f(0, 1); glVertex2f(X, Y+H);
+ glTexCoord2f(1, 1); glVertex2f(X+(W/100 * (Percent +1)), Y+H);
+ glTexCoord2f(1, 0); glVertex2f(X+(W/100 * (Percent +1)), Y);
+ glEnd;
+
+ //SingBar Front
+ glColor4f(1, 1, 1, 0.6);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, Tex_SingBar_Front.TexNum);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(X, Y);
+ glTexCoord2f(0, 1); glVertex2f(X, Y+H);
+ glTexCoord2f(1, 1); glVertex2f(X+W, Y+H);
+ glTexCoord2f(1, 0); glVertex2f(X+W, Y);
+ glEnd;
+end;
+//end Singbar Mod
+
+//PhrasenBonus - Line Bonus Mod
+procedure SingDrawLineBonus( const X, Y: Single; Color: TRGB; Alpha: Single; Text: string; Age: Integer);
+var
+Length, X2: Real; //Length of Text
+Size: Integer; //Size of Popup
+begin
+if Alpha <> 0 then
+begin
+
+//Set Font Propertys
+SetFontStyle(2); //Font: Outlined1
+if Age < 5 then SetFontSize(Age + 1) else SetFontSize(6);
+SetFontItalic(False);
+
+//Check Font Size
+Length := glTextWidth ( PChar(Text)) + 3; //Little Space for a Better Look ^^
+
+//Text
+SetFontPos (X + 50 - (Length / 2), Y + 12); //Position
+
+
+if Age < 5 then Size := Age * 10 else Size := 50;
+
+ //Draw Background
+ glColor4f(Color.R, Color.G, Color.B, Alpha); //Set Color
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+
+ //New Method, Not Variable
+ glBindTexture(GL_TEXTURE_2D, Tex_SingLineBonusBack.TexNum);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(X + 50 - Size, Y + 25 - (Size/2));
+ glTexCoord2f(0, 1); glVertex2f(X + 50 - Size, Y + 25 + (Size/2));
+ glTexCoord2f(1, 1); glVertex2f(X + 50 + Size, Y + 25 + (Size/2));
+ glTexCoord2f(1, 0); glVertex2f(X + 50 + Size, Y + 25 - (Size/2));
+ glEnd;
+
+ glColor4f(1, 1, 1, Alpha); //Set Color
+ //Draw Text
+ glPrint (PChar(Text));
+end;
+end;
+//PhrasenBonus - Line Bonus Mod
+
+// Draw Note Bars for Editor
+//There are 11 Resons for a new Procdedure:
+// 1. It don't look good when you Draw the Golden Note Star Effect in the Editor
+// 2. You can see the Freestyle Notes in the Editor SemiTransparent
+// 3. Its easier and Faster then changing the old Procedure
+procedure EditDrawCzesc(Left, Top, Right: real; NrCzesci: integer; Space: integer);
+var
+ Rec: TRecR;
+ Pet: integer;
+ TempR: real;
+begin
+ glColor3f(1, 1, 1);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ TempR := (Right-Left) / (Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].Koniec - Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote);
+ with Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt] do begin
+ for Pet := 0 to HighNut do begin
+ with Nuta[Pet] do begin
+
+ // Golden Note Patch
+ if isMedley or isStartPreview then
+ begin
+ case Wartosc of
+ 0: glColor4f(0, 1, 1, 0.35);
+ 1: glColor4f(0, 1, 1, 0.85);
+ 2: glColor4f(0, 1, 0.3, 0.85);
+ end; // case
+ end else
+ begin
+ case Wartosc of
+ 0: glColor4f(1, 1, 1, 0.35); //freestyle
+ 1: glColor4f(1, 1, 1, 0.85); //normal
+ 2: glColor4f(1, 1, 0.3, 0.85); //golden (green)
+ end; // case
+ end;
+
+
+
+ // lewa czesc - left part
+ Rec.Left := (Start-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left + 0.5 + 10*ScreenX;
+ Rec.Right := Rec.Left + NotesW;
+ Rec.Top := Top - (Ton-BaseNote)*Space/2 - NotesH;
+ Rec.Bottom := Rec.Top + 2 * NotesH;
+ glBindTexture(GL_TEXTURE_2D, Tex_Left[Color].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 - middle part
+ Rec.Left := Rec.Right;
+ Rec.Right := (Start+Dlugosc-Czesci[NrCzesci].Czesc[Czesci[NrCzesci].Akt].StartNote) * TempR + Left - NotesW - 0.5 + 10*ScreenX;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_Mid[Color].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 - right part
+ Rec.Left := Rec.Right;
+ Rec.Right := Rec.Right + NotesW;
+
+ glBindTexture(GL_TEXTURE_2D, Tex_Right[Color].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; // with
+ end; // for
+ end; // with
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
+procedure SingDrawTimeBar();
+var x,y: real;
+ width, height: real;
+ CurTime, TotalTime: real;
+ progress: real;
+begin
+ x := Theme.Sing.StaticTimeProgress.x;
+ y := Theme.Sing.StaticTimeProgress.y;
+ width:= Theme.Sing.StaticTimeProgress.w;
+ height:= Theme.Sing.StaticTimeProgress.h;
+
+ if (ScreenSong.Mode = smMedley) then
+ begin
+ CurTime := Czas.Teraz - ScreenSing.MedleyStart;
+ TotalTime := ScreenSing.MedleyEnd - ScreenSing.MedleyStart;
+ end else if ScreenSong.PartyMedley then
+ begin
+ CurTime := Czas.Teraz - ScreenSingModi.MedleyStart;
+ TotalTime := ScreenSingModi.MedleyEnd - ScreenSingModi.MedleyStart;
+ end else
+ begin
+ CurTime := Czas.Teraz - AktSong.Start;
+ TotalTime := Czas.Razem - AktSong.Start;
+ end;
+
+ progress := CurTime/TotalTime;
+
+ glColor4f(Theme.Sing.StaticTimeProgress.ColR,
+ Theme.Sing.StaticTimeProgress.ColG,
+ Theme.Sing.StaticTimeProgress.ColB, 1); //Set Color
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+
+ glBindTexture(GL_TEXTURE_2D, Tex_TimeProgress.TexNum);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(x,y);
+ glTexCoord2f(0, 1); glVertex2f(x+width*progress, y);
+ glTexCoord2f(1, 1); glVertex2f(x+width*progress, y+height);
+ glTexCoord2f(1, 0); glVertex2f(x, y+height);
+ glEnd;
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glcolor4f(1,1,1,1);
+end;
+
+end.
+
diff --git a/Game/Code/Classes/UFiles.pas b/Game/Code/Classes/UFiles.pas
new file mode 100644
index 00000000..3f450979
--- /dev/null
+++ b/Game/Code/Classes/UFiles.pas
@@ -0,0 +1,1153 @@
+unit UFiles;
+
+interface
+
+uses USongs,
+ SysUtils,
+ ULog,
+ UMusic;
+
+const
+ DEFAULT_FADE_IN_TIME = 8; //TODO in INI
+ DEFAULT_FADE_OUT_TIME = 2;
+
+procedure InitializePaths; //Function sets All Absolute Paths eg. for Songs
+function ReadTXTHeader(var Song: TSong): boolean; //Reads Standard TXT Header
+function AnalyseFile(var Song: TSong): boolean; //Analyse Song File and Read Header
+procedure ClearSong(var Song: TSong); //Clears Song Header values
+
+//Methodes Loading and Saving Songfiles
+procedure ResetSingTemp;
+procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string);
+procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer; LoadFullFile: boolean);
+function LoadSong(Name: string; LoadFullFile: boolean): boolean;
+function SaveSong(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+procedure FindRefrainStart(var Song: TSong);
+procedure SetMedleyMode;
+
+
+
+var
+ //Absolute Paths
+ GamePath: string;
+ SoundPath: string;
+ SongPath: string;
+ LogPath: string;
+ ThemePath: string;
+ ScreenshotsPath: string;
+ CoversPath: string;
+ LanguagesPath: string;
+ PluginPath: string;
+ PlayListPath: string;
+
+ SongFile: TextFile; // all procedures in this unit operates on this file
+ FileLineNo: integer; //Line which is readed at Last, for error reporting
+
+ // variables available for all procedures
+ Base: array[0..1] of integer;
+ Rel: array[0..1] of integer;
+ Mult: integer = 1;
+ MultBPM: integer = 4;
+
+implementation
+uses TextGL, UIni, UMain;
+
+
+//--------------------
+// Function sets all Absolute Paths e.g. Song Path and makes sure the Directorys exist
+//--------------------
+procedure InitializePaths;
+var
+ Writeable: Boolean;
+begin
+ GamePath := ExtractFilePath(ParamStr(0));
+
+ SoundPath := GamePath + 'Sounds\';
+ SongPath := GamePath + 'Songs\';
+ LogPath := GamePath;
+ ThemePath := GamePath + 'Themes\';
+ ScreenshotsPath := GamePath + 'Screenshots\';
+ CoversPath := GamePath + 'Covers\';
+ LanguagesPath := GamePath + 'Languages\';
+ PluginPath := GamePath + 'Plugins\';
+ PlaylistPath := GamePath + 'Playlists\';
+
+ Writeable := true;
+
+ //After Setting Paths, make sure that Paths exist
+ If not DirectoryExists(SoundPath) then
+ Writeable := ForceDirectories(SoundPath);
+
+ If Writeable And (not DirectoryExists(SongPath)) then
+ Writeable := ForceDirectories(SongPath);
+
+ If Writeable And (not DirectoryExists(ThemePath)) then
+ Writeable := ForceDirectories(ThemePath);
+
+ If Writeable And (not DirectoryExists(ScreenshotsPath)) then
+ Writeable := ForceDirectories(ScreenshotsPath);
+
+ If Writeable And (not DirectoryExists(CoversPath)) then
+ Writeable := ForceDirectories(CoversPath);
+
+ If Writeable And (not DirectoryExists(LanguagesPath)) then
+ Writeable := ForceDirectories(LanguagesPath);
+
+ If Writeable And (not DirectoryExists(PluginPath)) then
+ Writeable := ForceDirectories(PluginPath);
+
+ If Writeable And (not DirectoryExists(PlaylistPath)) then
+ Writeable := ForceDirectories(PlaylistPath);
+
+ if not Writeable then
+ Log.LogError('Error: Dir is Readonly');
+
+ DecimalSeparator := ',';
+end;
+
+//--------------------
+// Clears Song Header values
+//--------------------
+procedure ClearSong(var Song: TSong);
+begin
+ //Main Information
+ Song.Title := '';
+ Song.Artist := '';
+
+ //Sortings:
+ Song.Genre := 'Unknown';
+ Song.Edition := 'Unknown';
+ Song.Language := 'Unknown'; //Language Patch
+
+ //Required Information
+ Song.Mp3 := '';
+ Song.BPM := 0;
+ Song.GAP := 0;
+ Song.Start := 0;
+ Song.Finish := 0;
+
+ //Additional Information
+ Song.Background := '';
+ Song.Cover := '';
+ Song.Video := '';
+ Song.VideoGAP := 0;
+ Song.NotesGAP := 0;
+ Song.Resolution := 4;
+ Song.Creator := '';
+ Song.Medley.Source:=msNone;
+ Song.PreviewStart := 0;
+ SetLength(Song.CustomTags, 0);
+end;
+
+//--------------------
+// Reads Standard TXT Header
+//--------------------
+function ReadTXTHeader(var Song: TSong): boolean;
+var
+ Line, Identifier, Value: String;
+ Temp: word;
+ Done: byte;
+ MedleyFlags: byte; //bit-vector for medley/preview tags
+ lWarnIfTagsNotFound : Boolean;
+
+ { adds a custom header tag to the song
+ if there is no ':' in the read line, Tag should be empty
+ and the whole line should be in Content } //from usdx 1.1
+ procedure AddCustomTag(const Tag, Content: String);
+ var Len: Integer;
+ begin
+ Len := Length(Song.CustomTags);
+ SetLength(Song.CustomTags, Len + 1);
+ Song.CustomTags[Len].Tag := Tag;
+ Song.CustomTags[Len].Content := Content;
+ end;
+
+begin
+ Result := true;
+ Done := 0;
+ MedleyFlags := 0;
+
+ lWarnIfTagsNotFound := ( lowercase( Song.Filename ) <> 'license.txt' ) AND
+ ( lowercase( Song.Filename ) <> 'readme.txt' ) ;
+
+
+ //Read first Line
+ ReadLn (SongFile, Line);
+
+ if (Length(Line)<=0) then
+ begin
+ Log.LogError('File Starts with Empty Line: ' + Song.FileName);
+ Result := False;
+ Exit;
+ end;
+
+ //Read Lines while Line starts with #
+ While (Length(Line) = 0) OR (Line[1] = '#') do
+ begin
+ //Increase Line Number
+ Inc (FileLineNo);
+ Temp := Pos(':', Line);
+
+ //Line has a Seperator-> Headerline
+ if (Temp <> 0) then
+ begin
+ //Read Identifier and Value
+ Identifier := Uppercase(Trim(Copy(Line, 2, Temp - 2))); //Uppercase is for Case Insensitive Checks
+ Value := Trim(Copy(Line, Temp + 1,Length(Line) - Temp));
+
+ //Check the Identifier (If Value is given)
+ if (Length(Value) <> 0) then
+ begin
+
+ //-----------
+ //Required Attributes
+ //-----------
+
+ //Title
+ if (Identifier = 'TITLE') then
+ begin
+ Song.Title := Value;
+
+ //Add Title Flag to Done
+ Done := Done or 1;
+ end
+
+ //Artist
+ else if (Identifier = 'ARTIST') then
+ begin
+ Song.Artist := Value;
+
+ //Add Artist Flag to Done
+ Done := Done or 2;
+ end
+
+ //MP3 File //Test if Exists
+ else if (Identifier = 'MP3') AND (FileExists(Song.Path + Value)) then
+ begin
+ Song.Mp3 := Value;
+
+ //Add Mp3 Flag to Done
+ Done := Done or 4;
+ end
+
+ //Beats per Minute
+ else if (Identifier = 'BPM') then
+ begin
+ // Replace . with ,
+ if (Pos('.', Value) <> 0) then
+ Value[Pos('.', Value)] := ',';
+
+ SetLength(Song.BPM, 1);
+ Song.BPM[0].StartBeat := 0;
+
+ Song.BPM[0].BPM := StrtoFloatDef(Value, 0) * Mult * MultBPM;
+
+ if Song.BPM[0].BPM <> 0 then
+ begin
+ //Add BPM Flag to Done
+ Done := Done or 8;
+ end;
+ end
+
+ //---------
+ //Additional Header Information
+ //---------
+
+ // Video Gap
+ else if (Identifier = 'GAP') then
+ begin
+ // Replace . with ,
+ if (Pos('.', Value) <> 0) then
+ Value[Pos('.', Value)] := ',';
+
+ Song.GAP := StrtoFloatDef (Value, 0);
+ end
+
+ //Cover Picture
+ else if (Identifier = 'COVER') then
+ begin
+ Song.Cover := Value;
+ end
+
+ //Background Picture
+ else if (Identifier = 'BACKGROUND') then
+ begin
+ Song.Background := Value;
+ end
+
+ // Video File
+ else if (Identifier = 'VIDEO') then
+ begin
+ if (FileExists(Song.Path + Value)) then
+ Song.Video := Value
+ else
+ Log.LogError('Can''t find Video File in Song: ' + Song.Path + Song.FileName);
+ end
+
+ // Video Gap
+ else if (Identifier = 'VIDEOGAP') then
+ begin
+ // Replace . with ,
+ if (Pos('.', Value) <> 0) then
+ Value[Pos('.', Value)] := ',';
+
+ Song.VideoGAP := StrtoFloatDef (Value, 0);
+ end
+
+ //Genre Sorting
+ else if (Identifier = 'GENRE') then
+ begin
+ Song.Genre := Value;
+ end
+
+ //Edition Sorting
+ else if (Identifier = 'EDITION') then
+ begin
+ Song.Edition := Value;
+ end
+
+ //Creator Tag
+ else if (Identifier = 'CREATOR') then
+ begin
+ Song.Creator := Value;
+ end
+
+ //Language Sorting
+ else if (Identifier = 'LANGUAGE') then
+ begin
+ Song.Language := Value;
+ end
+
+ // Song Start
+ else if (Identifier = 'START') then
+ begin
+ // Replace . with ,
+ if (Pos('.', Value) <> 0) then
+ Value[Pos('.', Value)] := ',';
+
+ Song.Start := StrtoFloatDef(Value, 0);
+ end
+
+ // Song Ending
+ else if (Identifier = 'END') then
+ begin
+ TryStrtoInt(Value, Song.Finish);
+ end
+
+ // Resolution
+ else if (Identifier = 'RESOLUTION') then
+ begin
+ TryStrtoInt(Value, Song.Resolution);
+ end
+
+ // Notes Gap
+ else if (Identifier = 'NOTESGAP') then
+ begin
+ TryStrtoInt(Value, Song.NotesGAP);
+ end
+
+ // Relative Notes
+ else if (Identifier = 'RELATIVE') AND (uppercase(Value) = 'YES') then
+ begin
+ Song.Relative := True;
+ end
+
+ // PreviewStart
+ else if (Identifier = 'PREVIEWSTART') then
+ begin
+ Song.PreviewStart := StrToFloatDef(Value, 0);
+ if (Song.PreviewStart>0) then
+ MedleyFlags := MedleyFlags or 1;
+ end
+
+ // MedleyStartBeat
+ else if (Identifier = 'MEDLEYSTARTBEAT') and not Song.Relative then
+ begin
+ if TryStrtoInt(Value, Song.Medley.StartBeat) then
+ MedleyFlags := MedleyFlags or 2;
+ end
+
+ // MedleyEndBeat
+ else if (Identifier = 'MEDLEYENDBEAT') and not Song.Relative then
+ begin
+ if TryStrtoInt(Value, Song.Medley.EndBeat) then
+ MedleyFlags := MedleyFlags or 4;
+ end
+
+ // unsupported tag
+ else
+ begin
+ AddCustomTag(Identifier, Value);
+ end;
+
+ end;
+ end;
+
+ if not EOf(SongFile) then
+ ReadLn (SongFile, Line)
+ else
+ begin
+ Result := False;
+
+ if lWarnIfTagsNotFound then
+ begin
+ Log.LogError('File Incomplete or not Ultrastar TxT: ' + Song.FileName);
+ end;
+
+ break;
+ end;
+
+ {//End on first empty Line
+ if (Length(Line) = 0) then
+ break;}
+ end;
+
+ //Check if all Required Values are given
+ if (Done <> 15) then
+ begin
+ Result := False;
+ If lWarnIfTagsNotFound then
+ begin
+ if (Done and 8) = 0 then //No BPM Flag
+ Log.LogError('BPM Tag Missing: ' + Song.FileName)
+ else if (Done and 4) = 0 then //No MP3 Flag
+ Log.LogError('MP3 Tag/File Missing: ' + Song.FileName)
+ else if (Done and 2) = 0 then //No Artist Flag
+ Log.LogError('Artist Tag Missing: ' + Song.FileName)
+ else if (Done and 1) = 0 then //No Title Flag
+ Log.LogError('Title Tag Missing: ' + Song.FileName)
+ else //unknown Error
+ Log.LogError('File Incomplete or not Ultrastar TxT: ' + Song.FileName);
+ end;
+ end else
+ begin //check medley tags
+ if (MedleyFlags and 6)=6 then //MedleyStartBeat and MedleyEndBeat are both set
+ begin
+ if Song.Medley.StartBeat >= Song.Medley.EndBeat then
+ MedleyFlags := MedleyFlags - 6;
+ end;
+
+ if ((MedleyFlags and 1)=0) or (Song.PreviewStart<=0) then //PreviewStart is not set or <=0
+ begin
+ if (MedleyFlags and 2)=2 then
+ Song.PreviewStart := GetTimeFromBeat(Song.Medley.StartBeat) //fallback to MedleyStart
+ else
+ Song.PreviewStart := 0; //else set it to 0, it will be set in FindRefrainStart
+ end;
+
+ if (MedleyFlags and 6)=6 then
+ begin
+ Song.Medley.Source := msTag;
+
+ //calculate fade time
+ Song.Medley.FadeIn_time := DEFAULT_FADE_IN_TIME;
+
+ Song.Medley.FadeOut_time := DEFAULT_FADE_OUT_TIME;
+ end else
+ Song.Medley.Source := msNone;
+ end;
+
+end;
+
+//--------------------
+// Analyse Song File and Read Header
+//--------------------
+function AnalyseFile(var Song: TSong): boolean;
+begin
+Result := False;
+{try }
+ //Reset LineNo
+ FileLineNo := 0;
+
+ //Open File and set File Pointer to the beginning
+ AssignFile(SongFile, Song.Path + Song.FileName);
+ Reset(SongFile);
+
+ //Clear old Song Header
+ ClearSong(Song);
+
+ //Read Header
+ Result := ReadTxTHeader(Song);
+
+ //And Close File
+ CloseFile(SongFile);
+{except
+ CloseFile(SongFile);
+
+ Result := False;
+ //Error Reporting
+ Log.LogError('An Error occured reading Line ' + inttostr(FileLineNo) + ' from SongHeader: ' + Song.FileName);
+end;}
+end;
+
+//--------------------
+// Resets the temporary Sentence Arrays for each Player and some other Variables
+//--------------------
+procedure ResetSingTemp;
+var
+ Pet: integer;
+begin
+ SetLength(Czesci, Length(Player));
+ SetLength(AktSong.BPM, 0);
+ for Pet := 0 to High(Player) do begin
+ SetLength(Czesci[Pet].Czesc, 1);
+ SetLength(Czesci[Pet].Czesc[0].Nuta, 0);
+ Czesci[Pet].Czesc[0].Lyric := '';
+ Czesci[Pet].Czesc[0].LyricWidth := 0;
+ Player[pet].Score := 0;
+ Player[pet].IlNut := 0;
+ Player[pet].HighNut := -1;
+ end;
+ //Reset Path and Filename Values to Prevent Errors in Editor
+ AktSong.Path := '';
+ AktSong.FileName := '';
+end;
+
+//--------------------
+// Parses Note Infos and save them to Array
+//--------------------
+procedure ParseNote(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string);
+var
+ Space: boolean;
+begin
+ case Ini.Solmization of
+ 1: // european
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' sol ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' si ';
+ end;
+ end;
+ 2: // japanese
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' so ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' shi ';
+ end;
+ end;
+ 3: // american
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' sol ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' ti ';
+ end;
+ end;
+ end; // case
+
+ with Czesci[NrCzesci].Czesc[Czesci[NrCzesci].High] do begin
+ SetLength(Nuta, Length(Nuta) + 1);
+ IlNut := IlNut + 1;
+ HighNut := HighNut + 1;
+ Muzyka.IlNut := Muzyka.IlNut + 1;
+
+ Nuta[HighNut].Start := StartP;
+ if IlNut = 1 then begin
+ StartNote := Nuta[HighNut].Start;
+ if Czesci[NrCzesci].Ilosc = 1 then
+ Start := -100;
+// Start := Nuta[HighNut].Start;
+ end;
+
+ Nuta[HighNut].Dlugosc := DurationP;
+ Muzyka.DlugoscNut := Muzyka.DlugoscNut + Nuta[HighNut].Dlugosc;
+
+ // back to the normal system with normal, golden and now freestyle notes
+ case TypeP of
+ 'F': Nuta[HighNut].Wartosc := 0;
+ ':': Nuta[HighNut].Wartosc := 1;
+ '*': Nuta[HighNut].Wartosc := 2;
+ end;
+
+ Czesci[NrCzesci].Wartosc := Czesci[NrCzesci].Wartosc + Nuta[HighNut].Dlugosc * Nuta[HighNut].Wartosc;
+
+ Nuta[HighNut].Ton := NoteP;
+ if Nuta[HighNut].Ton < Base[NrCzesci] then Base[NrCzesci] := Nuta[HighNut].Ton;
+ Nuta[HighNut].TonGamy := Nuta[HighNut].TonGamy mod 12;
+
+ Nuta[HighNut].Tekst := Copy(LyricS, 2, 100);
+ Lyric := Lyric + Nuta[HighNut].Tekst;
+
+ if TypeP = 'F' then
+ Nuta[HighNut].FreeStyle := true;
+
+ Koniec := Nuta[HighNut].Start + Nuta[HighNut].Dlugosc;
+ end; // with
+end;
+
+//--------------------
+// Called when a new Sentence is found in the TXT File
+//--------------------
+procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer; LoadFullFile: boolean);
+var
+I: Integer;
+begin
+
+ // stara czesc //Alter Satz //Update Old Part
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].BaseNote := Base[NrCzesciP];
+ if LoadFullFile then
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].LyricWidth := glTextWidth(PChar(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Lyric));
+
+ //Total Notes Patch
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := 0;
+ for I := low(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) to high(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) do
+ begin
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes + Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Dlugosc * Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Wartosc;
+ end;
+ //Total Notes Patch End
+
+
+ // nowa czesc //Neuer Satz //Update New Part
+ SetLength(Czesci[NrCzesciP].Czesc, Czesci[NrCzesciP].Ilosc + 1);
+ Czesci[NrCzesciP].High := Czesci[NrCzesciP].High + 1;
+ Czesci[NrCzesciP].Ilosc := Czesci[NrCzesciP].Ilosc + 1;
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].HighNut := -1;
+
+ if not AktSong.Relative then
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1;
+
+ if AktSong.Relative then begin
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1;
+ Rel[NrCzesciP] := Rel[NrCzesciP] + Param2;
+ end;
+
+ Base[NrCzesciP] := 100; // high number
+end;
+
+//--------------------
+// Load a Song
+//--------------------
+function LoadSong(Name: string; LoadFullFile: boolean): boolean;
+var
+ TempC: char;
+ Tekst: string;
+ CP: integer; // Current Player (0 or 1)
+ Pet: integer;
+ Both: boolean;
+ Param1: integer;
+ Param2: integer;
+ Param3: integer;
+ ParamS: string;
+ I: Integer;
+ isNewSentence: boolean;
+begin
+ Result := false;
+
+ if not FileExists(Name) then begin
+ Log.LogError('File not found: "' + Name + '"', 'LoadSong');
+ exit;
+ end;
+
+ try
+ MultBPM := 4; // 4 - mnoznik dla czasu nut
+ Mult := 1; // 4 - dokladnosc pomiaru nut
+ Base[0] := 100; // high number
+// Base[1] := 100; // high number
+ Czesci[0].Wartosc := 0;
+// Czesci[1].Wartosc := 0; // here was the error in 0.3.2
+ if LoadFullFile then
+ AktSong.Relative := false;
+
+ Rel[0] := 0;
+// Rel[1] := 0;
+ CP := 0;
+ Both := false;
+ if Length(Player) = 2 then Both := true;
+
+ FileMode := fmOpenRead;
+ AssignFile(SongFile, Name);
+
+ if LoadFullFile then
+ begin
+ Reset(SongFile);
+
+ //Clear old Song Header
+ ClearSong(AktSong);
+
+ if (AktSong.Path = '') then
+ AktSong.Path := ExtractFilePath(Name);
+
+ if (AktSong.FileName = '') then
+ AktSong.Filename := ExtractFileName(Name);
+ //Read Header
+ Result := ReadTxTHeader(AktSong);
+ if not Result then
+ begin
+ CloseFile(SongFile);
+ FileMode := fmOpenReadWrite;
+ Log.LogError('Error Loading SongHeader, abort Song Loading. File: ' + Name);
+ Exit;
+ end;
+ end;
+
+ Result := False;
+
+ Reset(SongFile);
+ FileLineNo := 0;
+ //Search for Note Begining
+ repeat
+ ReadLn(SongFile, Tekst);
+ Inc(FileLineNo);
+
+ if (EoF(SongFile)) then
+ begin //Song File Corrupted - No Notes
+ CloseFile(SongFile);
+ FileMode := fmOpenReadWrite;
+ Log.LogError('Could not load txt File, no Notes found: ' + Name);
+ Result := False;
+ Exit;
+ end;
+ Read(SongFile, TempC);
+ until ((TempC = ':') or (TempC = 'F') or (TempC = '*'));
+
+ SetLength(Czesci, 2);
+ for Pet := 0 to High(Czesci) do begin
+ SetLength(Czesci[Pet].Czesc, 1);
+ Czesci[Pet].High := 0;
+ Czesci[Pet].Ilosc := 1;
+ Czesci[Pet].Akt := 0;
+ Czesci[Pet].Resolution := AktSong.Resolution;
+ Czesci[Pet].NotesGAP := AktSong.NotesGAP;
+ Czesci[Pet].Czesc[0].IlNut := 0;
+ Czesci[Pet].Czesc[0].HighNut := -1;
+ end;
+
+// TempC := ':';
+// TempC := Tekst[1]; // read from backup variable, don't use default ':' value
+ isNewSentence := false;
+ while (TempC <> 'E') AND (not EOF(SongFile)) do begin
+ if (TempC = ':') or (TempC = '*') or (TempC = 'F') then begin
+ // wczytuje nute
+ Read(SongFile, Param1);
+ Read(SongFile, Param2);
+ Read(SongFile, Param3);
+ Read(SongFile, ParamS);
+
+ // dodaje nute
+ if not Both then
+ // P1
+ ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS)
+ else begin
+ // P1 + P2
+ ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS);
+ ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS);
+ end;
+ isNewSentence := false;
+ end; // if
+ if TempC = '-' then begin
+ if isNewSentence then
+ begin
+ Log.LogError('Double sentence break in file: "' + Name + '" (LoadSong)');
+ Result := False;
+ Exit;
+ end;
+ // reads sentence
+ Read(SongFile, Param1);
+ if AktSong.Relative then Read(SongFile, Param2); // read one more data for relative system
+
+ // new sentence
+ if not Both then
+ // P1
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2, LoadFullFile)
+ else begin
+ // P1 + P2
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2, LoadFullFile);
+ NewSentence(1, (Param1 + Rel[1]) * Mult, Param2, LoadFullFile);
+ end;
+ isNewSentence := true;
+ end; // if
+
+ if TempC = 'B' then begin
+ SetLength(AktSong.BPM, Length(AktSong.BPM) + 1);
+ Read(SongFile, AktSong.BPM[High(AktSong.BPM)].StartBeat);
+ AktSong.BPM[High(AktSong.BPM)].StartBeat := AktSong.BPM[High(AktSong.BPM)].StartBeat + Rel[0];
+
+ Read(SongFile, Tekst);
+ AktSong.BPM[High(AktSong.BPM)].BPM := StrToFloat(Tekst);
+ AktSong.BPM[High(AktSong.BPM)].BPM := AktSong.BPM[High(AktSong.BPM)].BPM * Mult * MultBPM;
+ end;
+
+
+ if not Both then begin
+ Czesci[CP].Czesc[Czesci[CP].High].BaseNote := Base[CP];
+ if LoadFullFile then
+ Czesci[CP].Czesc[Czesci[CP].High].LyricWidth := glTextWidth(PChar(Czesci[CP].Czesc[Czesci[CP].High].Lyric));
+ //Total Notes Patch
+ Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := 0;
+ for I := low(Czesci[CP].Czesc[Czesci[CP].High].Nuta) to high(Czesci[CP].Czesc[Czesci[CP].High].Nuta) do
+ begin
+ Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := Czesci[CP].Czesc[Czesci[CP].High].TotalNotes + Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Dlugosc * Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Wartosc;
+ end;
+ //Total Notes Patch End
+ end else begin
+ for Pet := 0 to High(Czesci) do begin
+ Czesci[Pet].Czesc[Czesci[Pet].High].BaseNote := Base[Pet];
+ if LoadFullFile then
+ Czesci[Pet].Czesc[Czesci[Pet].High].LyricWidth := glTextWidth(PChar(Czesci[Pet].Czesc[Czesci[Pet].High].Lyric));
+ //Total Notes Patch
+ Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := 0;
+ for I := low(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) to high(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) do
+ begin
+ Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes + Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Dlugosc * Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Wartosc;
+ end;
+ //Total Notes Patch End
+ end;
+ end;
+
+ Read(SongFile, TempC);
+ Inc(FileLineNo);
+ end; // while}
+
+ CloseFile(SongFile);
+ FileMode := fmOpenReadWrite;
+ except
+ try
+ CloseFile(SongFile);
+ FileMode := fmOpenReadWrite;
+ except
+
+ end;
+ Result := false;
+ Log.LogError('Error Loading File: "' + Name + '" in Line ' + inttostr(FileLineNo+1));
+ exit;
+ end;
+
+ Result := true;
+end;
+
+//--------------------
+// Saves a Song
+//--------------------
+function SaveSong(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+var
+ C: integer;
+ N: integer;
+ S: string;
+ B: integer;
+ RelativeSubTime: integer;
+ NoteState: String;
+
+ procedure WriteCustomTags; //from 1.1 (modified)
+ var
+ I: integer;
+ Line: String;
+ begin
+ for I := 0 to High(Song.CustomTags) do
+ begin
+ Line := Song.CustomTags[I].Content;
+ if (Length(Song.CustomTags[I].Tag) > 0) then
+ Line := Song.CustomTags[I].Tag + ':' + Line;
+
+ WriteLn(SongFile, '#' + Line);
+ end;
+
+ end;
+begin
+// Relative := true; // override (idea - use shift+S to save with relative)
+ Result := true;
+ AssignFile(SongFile, Name);
+ Rewrite(SongFile);
+
+ WriteLn(SongFile, '#TITLE:' + Song.Title + '');
+ WriteLn(SongFile, '#ARTIST:' + Song.Artist);
+
+ if Song.Creator <> '' then WriteLn(SongFile, '#CREATOR:' + Song.Creator);
+ if Song.Edition <> 'Unknown' then WriteLn(SongFile, '#EDITION:' + Song.Edition);
+ if Song.Genre <> 'Unknown' then WriteLn(SongFile, '#GENRE:' + Song.Genre);
+ if Song.Language <> 'Unknown' then WriteLn(SongFile, '#LANGUAGE:' + Song.Language);
+
+ WriteLn(SongFile, '#MP3:' + Song.Mp3);
+
+ if Song.Cover <> '' then WriteLn(SongFile, '#COVER:' + Song.Cover);
+ if Song.Background <> '' then WriteLn(SongFile, '#BACKGROUND:' + Song.Background);
+ if Song.Video <> '' then WriteLn(SongFile, '#VIDEO:' + Song.Video);
+ if Song.VideoGAP <> 0 then WriteLn(SongFile, '#VIDEOGAP:' + FloatToStr(Song.VideoGAP));
+ if Song.Resolution <> 4 then WriteLn(SongFile, '#RESOLUTION:' + IntToStr(Song.Resolution));
+ if Song.NotesGAP <> 0 then WriteLn(SongFile, '#NOTESGAP:' + IntToStr(Song.NotesGAP));
+ if Song.Start <> 0 then WriteLn(SongFile, '#START:' + FloatToStr(Song.Start));
+ if Song.Finish <> 0 then WriteLn(SongFile, '#END:' + IntToStr(Song.Finish));
+ if Song.PreviewStart<> 0 then WriteLn(SongFile, '#PREVIEWSTART:'+ FloatToStr(Song.PREVIEWSTART));
+
+ if (Song.Medley.Source=msTag) and not Relative then
+ begin
+ WriteLn(SongFile, '#MedleyStartBeat:' + IntToStr(Song.Medley.StartBeat));
+ WriteLn(SongFile, '#MedleyEndBeat:' + IntToStr(Song.Medley.EndBeat));
+ end;
+
+ if Relative then WriteLn(SongFile, '#RELATIVE:yes');
+
+ WriteLn(SongFile, '#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
+ WriteLn(SongFile, '#GAP:' + FloatToStr(Song.GAP));
+
+ RelativeSubTime := 0;
+ for B := 1 to High(AktSong.BPM) do
+ WriteLn(SongFile, 'B ' + FloatToStr(AktSong.BPM[B].StartBeat) + ' ' + FloatToStr(AktSong.BPM[B].BPM/4));
+
+ // write custom header tags (from 1.1)
+ WriteCustomTags;
+
+ for C := 0 to Czesc.High do begin
+ for N := 0 to Czesc.Czesc[C].HighNut do begin
+ with Czesc.Czesc[C].Nuta[N] do begin
+
+
+ //Golden + Freestyle Note Patch
+ case Czesc.Czesc[C].Nuta[N].Wartosc of
+ 0: NoteState := 'F ';
+ 1: NoteState := ': ';
+ 2: NoteState := '* ';
+ end; // case
+ S := NoteState + IntToStr(Start-RelativeSubTime) + ' ' + IntToStr(Dlugosc) + ' ' + IntToStr(Ton) + ' ' + Tekst;
+
+
+ WriteLn(SongFile, S);
+ end; // with
+ end; // N
+
+ if C < Czesc.High then begin // don't write end of last sentence
+ if not Relative then
+ S := '- ' + IntToStr(Czesc.Czesc[C+1].Start)
+ else begin
+ S := '- ' + IntToStr(Czesc.Czesc[C+1].Start - RelativeSubTime) +
+ ' ' + IntToStr(Czesc.Czesc[C+1].Start - RelativeSubTime);
+ RelativeSubTime := Czesc.Czesc[C+1].Start;
+ end;
+ WriteLn(SongFile, S);
+ end;
+
+ end; // C
+
+
+ WriteLn(SongFile, 'E');
+ CloseFile(SongFile);
+end;
+
+{* new procedure for preview
+ tries find out the beginning of a refrain
+ and the end... *}
+procedure FindRefrainStart(var Song: TSong);
+Const
+ MEDLEY_MIN_DURATION = 40; //minimum duration of a medley-song in seconds
+
+Type
+ TSeries = record
+ start: integer; //Start sentence of series
+ end_: integer; //End sentence of series
+ len: integer; //Length of sentence series
+ end;
+
+var
+ I, J, K, num_lines: integer;
+ sentences: array of String;
+ series: array of TSeries;
+ temp_series: TSeries;
+ max: integer;
+ len_lines, len_notes: integer;
+ found_end: boolean;
+begin
+ if AktSong.Medley.Source = msTag then //will be deleted soon
+ Exit;
+
+ //relative is not supported for medley by now!
+ if AktSong.Relative then
+ begin
+ Log.LogError('Song '+Song.Artist+'-'+Song.Title+' contains #Relative, this is not supported by medley-function!');
+ Song.Medley.Source := msNone;
+ Exit;
+ end;
+
+ num_lines := Length(Czesci[0].Czesc);
+ SetLength(sentences, num_lines);
+
+ //build sentences array
+ for I := 0 to num_lines - 1 do
+ begin
+ sentences[I] := '';
+ for J := 0 to Length(Czesci[0].Czesc[I].Nuta) - 1 do
+ begin
+ if not Czesci[0].Czesc[I].Nuta[J].FreeStyle then
+ sentences[I] := sentences[I] + Czesci[0].Czesc[I].Nuta[J].Tekst;
+ end;
+ end;
+
+ //find equal sentences series
+ SetLength(series, 0);
+
+ for I := 0 to num_lines - 2 do
+ begin
+ for J := I+1 to num_lines - 1 do
+ begin
+ if sentences[I]=sentences[J] then
+ begin
+ temp_series.start := I;
+ temp_series.end_ := I;
+
+ if (J+J-I-1>num_lines-1) then
+ max:=num_lines-1-J
+ else
+ max:=J-I-1;
+
+ for K := 1 to max do
+ begin
+ if sentences[I+K]=sentences[J+K] then
+ temp_series.end_ := I+K
+ else
+ break;
+ end;
+ temp_series.len := temp_series.end_ - temp_series.start + 1;
+ SetLength(series, Length(series)+1);
+ series[Length(series)-1] := temp_series;
+ end;
+ end;
+ end;
+
+ //search for longest sequence
+ if Length(series)>0 then
+ begin
+ max := 0;
+ for I := 0 to Length(series) - 1 do
+ begin
+ if series[I].len > series[max].len then
+ max := I;
+ end;
+ end;
+
+ len_lines := length(Czesci[0].Czesc);
+
+ if (Length(series)>0) and (series[max].len > 3) then
+ begin
+ Song.Medley.StartBeat := Czesci[0].Czesc[series[max].start].Nuta[0].Start;
+ len_notes := length(Czesci[0].Czesc[series[max].end_].Nuta);
+ Song.Medley.EndBeat := Czesci[0].Czesc[series[max].end_].Nuta[len_notes-1].Start +
+ Czesci[0].Czesc[series[max].end_].Nuta[len_notes-1].Dlugosc;
+
+ found_end := false;
+
+ //set end if duration > MEDLEY_MIN_DURATION
+ if GetTimeFromBeat(Song.Medley.StartBeat)+ MEDLEY_MIN_DURATION >
+ GetTimeFromBeat(Song.Medley.EndBeat) then
+ begin
+ found_end := true;
+ end;
+
+ //estimate the end: just go MEDLEY_MIN_DURATION
+ //ahead an set to a line end (if possible)
+ if not found_end then
+ begin
+ for I := series[max].start+1 to len_lines-1 do
+ begin
+ len_notes := length(Czesci[0].Czesc[I].Nuta);
+ for J := 0 to len_notes - 1 do
+ begin
+ if GetTimeFromBeat(Song.Medley.StartBeat)+ MEDLEY_MIN_DURATION >
+ GetTimeFromBeat(Czesci[0].Czesc[I].Nuta[J].Start+
+ Czesci[0].Czesc[I].Nuta[J].Dlugosc) then
+ begin
+ found_end := true;
+ Song.Medley.EndBeat := Czesci[0].Czesc[I].Nuta[len_notes-1].Start+
+ Czesci[0].Czesc[I].Nuta[len_notes-1].Dlugosc;
+ break;
+ end;
+ end;
+ end;
+ end;
+
+
+ if found_end then
+ begin
+ Song.Medley.Source := msCalculated;
+
+ //calculate fade time
+ Song.Medley.FadeIn_time := DEFAULT_FADE_IN_TIME; //TODO in INI
+ Song.Medley.FadeOut_time := DEFAULT_FADE_OUT_TIME; //TODO in INI
+ end;
+ end;
+
+ //set PreviewStart if not set
+ if Song.PreviewStart=0 then
+ begin
+ len_notes := length(Czesci[0].Czesc[len_lines-1].Nuta);
+ if Song.Medley.Source = msCalculated then
+ Song.PreviewStart := GetTimeFromBeat(Song.Medley.StartBeat);{
+ else
+ Song.PreviewStart := (GetTimeFromBeat(Czesci[0].Czesc[len_lines-1].Nuta[len_notes-1].start+
+ Czesci[0].Czesc[len_lines-1].Nuta[len_notes-1].Dlugosc))/4; //TODO}
+ end;
+end;
+
+//sets a song to medley-mod:
+//converts all unneeded notes into freestyle
+//updates score values
+procedure SetMedleyMode;
+var
+ pl, line, note: integer;
+ cut_line: array of integer;
+ foundcut: array of boolean;
+ start: integer;
+ end_: integer;
+
+begin
+ start := AktSong.Medley.StartBeat;
+ end_ := AktSong.Medley.EndBeat;
+ SetLength(cut_line, Length(Czesci));
+ SetLength(foundcut, Length(Czesci));
+
+ for pl := 0 to Length(Czesci) - 1 do
+ begin
+ foundcut[pl] := false;
+ cut_line[pl] := high(Integer);
+ Czesci[pl].Wartosc := 0;
+ for line := 0 to Length(Czesci[pl].Czesc) - 1 do
+ begin
+ Czesci[pl].Czesc[line].TotalNotes := 0;
+ for note := 0 to Length(Czesci[pl].Czesc[line].Nuta) - 1 do
+ begin
+ if Czesci[pl].Czesc[line].Nuta[note].Start < start then //check start
+ Czesci[pl].Czesc[line].Nuta[note].FreeStyle := true
+ else if Czesci[pl].Czesc[line].Nuta[note].Start>= end_ then //check end
+ begin
+ Czesci[pl].Czesc[line].Nuta[note].FreeStyle := true;
+ if not foundcut[pl] then
+ begin
+ if (note=0) then
+ cut_line[pl] := line
+ else
+ cut_line[pl] := line+1;
+ end;
+ foundcut[pl] := true;
+ end else
+ begin
+ //add this notes value ("notes length" * "notes scorefactor") to the current songs entire value
+ Inc(Czesci[pl].Wartosc, Czesci[pl].Czesc[line].Nuta[note].Dlugosc * Czesci[pl].Czesc[line].Nuta[note].Wartosc);
+ //and to the current lines entire value
+ Inc(Czesci[pl].Czesc[line].TotalNotes, Czesci[pl].Czesc[line].Nuta[note].Dlugosc * Czesci[pl].Czesc[line].Nuta[note].Wartosc);
+ end;
+ end;
+ end;
+ end;
+
+ for pl := 0 to Length(Czesci) - 1 do
+ begin
+ if (foundcut[pl]) and (Length(Czesci[pl].Czesc)>cut_line[pl]) then
+ begin
+ SetLength(Czesci[pl].Czesc, cut_line[pl]);
+ Czesci[pl].high := cut_line[pl]-1;
+ end;
+ end;
+end;
+
+end. \ No newline at end of file
diff --git a/Game/Code/Classes/UGraphic.pas b/Game/Code/Classes/UGraphic.pas
new file mode 100644
index 00000000..bcb2aa65
--- /dev/null
+++ b/Game/Code/Classes/UGraphic.pas
@@ -0,0 +1,564 @@
+unit UGraphic;
+
+interface
+uses
+ SDL, gl, glext, UTexture, TextGL, ULog, SysUtils, ULyrics, UScreenLoading,
+ UScreenWelcome, UScreenMain, UScreenName, UScreenLevel, UScreenOptions, UScreenOptionsGame,
+ UScreenOptionsGraphics, UScreenOptionsSound, UScreenOptionsLyrics, UScreenOptionsThemes, UScreenOptionsRecord, UScreenOptionsAdvanced,
+ UScreenSong, UScreenSing, UScreenScore, UScreenTop, UScreenEditSub,
+ UScreenEdit, UScreenEditConvert, UScreenEditHeader, UScreenOpen, UThemes, USkins, UScreenSongMenu, UScreenSongJumpto,
+ {Party Screens} UScreenSingModi, UScreenPartyNewRound, UScreenPartyScore, UScreenPartyOptions, UScreenPartyWin, UScreenPartyPlayer,
+ {Stats Screens} UScreenStatMain, UScreenStatDetail,
+ {CreditsScreen} UScreenCredits,
+ {Popup for errors, etc.} UScreenPopup,
+ UScreenPartyOptionsM2, UScreenPartyPlayerM2, UScreenPartyNewRoundM2;
+
+type
+ TRecR = record
+ Top: real;
+ Left: real;
+ Right: real;
+ Bottom: real;
+ end;
+
+var
+ Screen: PSDL_Surface;
+
+ RenderW: integer;
+ RenderH: integer;
+ ScreenW: integer;
+ ScreenH: integer;
+ Screens: integer;
+ ScreenAct: integer;
+ ScreenX: integer;
+
+ ScreenLoading: TScreenLoading;
+ ScreenWelcome: TScreenWelcome;
+ ScreenMain: TScreenMain;
+ ScreenName: TScreenName;
+ ScreenLevel: TScreenLevel;
+ ScreenSong: TScreenSong;
+ ScreenSing: TScreenSing;
+ ScreenScore: TScreenScore;
+ ScreenTop: TScreenTop;
+ ScreenOptions: TScreenOptions;
+ ScreenOptionsGame: TScreenOptionsGame;
+ ScreenOptionsGraphics: TScreenOptionsGraphics;
+ ScreenOptionsSound: TScreenOptionsSound;
+ ScreenOptionsLyrics: TScreenOptionsLyrics;
+ ScreenOptionsThemes: TScreenOptionsThemes;
+ ScreenOptionsRecord: TScreenOptionsRecord;
+ ScreenOptionsAdvanced: TScreenOptionsAdvanced;
+ ScreenEditSub: TScreenEditSub;
+ ScreenEdit: TScreenEdit;
+ ScreenEditConvert: TScreenEditConvert;
+ ScreenEditHeader: TScreenEditHeader;
+ ScreenOpen: TScreenOpen;
+
+ ScreenSongMenu: TScreenSongMenu;
+ ScreenSongJumpto: TScreenSongJumpto;
+
+ //Party Screens
+ ScreenSingModi: TScreenSingModi;
+ ScreenPartyNewRound: TScreenPartyNewRound;
+ ScreenPartyScore: TScreenPartyScore;
+ ScreenPartyWin: TScreenPartyWin;
+ ScreenPartyOptions: TScreenPartyOptions;
+ ScreenPartyPlayer: TScreenPartyPlayer;
+
+ //PartyM2 Screens
+ //ScreenSingModi: TScreenSingModi;
+ ScreenPartyNewRoundM2: TScreenPartyNewRoundM2;
+ //ScreenPartyScore: TScreenPartyScore;
+ //ScreenPartyWin: TScreenPartyWin;
+ ScreenPartyOptionsM2: TScreenPartyOptionsM2;
+ ScreenPartyPlayerM2: TScreenPartyPlayerM2;
+
+ //StatsScreens
+ ScreenStatMain: TScreenStatMain;
+ ScreenStatDetail: TScreenStatDetail;
+
+ //CreditsScreen
+ ScreenCredits: TScreenCredits;
+
+ //popup mod
+ ScreenPopupCheck: TScreenPopupCheck;
+ ScreenPopupError: TScreenPopupError;
+
+ //popup Help-System
+ ScreenPopupHelp: TScreenPopupHelp;
+
+ //Notes
+ Tex_Left: array[0..6] of TTexture;
+ Tex_Mid: array[0..6] of TTexture;
+ Tex_Right: array[0..6] of TTexture;
+
+ Tex_BG_Left: array[1..6] of TTexture;
+ Tex_BG_Mid: array[1..6] of TTexture;
+ Tex_BG_Right: array[1..6] of TTexture;
+
+ Tex_Note_Star: TTexture;
+ Tex_Note_Perfect_Star: TTexture;
+
+
+ Tex_Ball: TTexture;
+ Tex_Lyric_Help_Bar: TTexture;
+ FullScreen: boolean;
+
+ Tex_TimeProgress: TTexture;
+
+ //Sing Bar Mod
+ Tex_SingBar_Back: TTexture;
+ Tex_SingBar_Bar: TTexture;
+ Tex_SingBar_Front: TTexture;
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ Tex_SingLineBonusBack: TTexture;
+ //End PhrasenBonus - Line Bonus Mod
+
+const
+ Skin_BGColorR = 1;
+ Skin_BGColorG = 1;
+ Skin_BGColorB = 1;
+
+ Skin_SpectrumR = 0;
+ Skin_SpectrumG = 0;
+ Skin_SpectrumB = 0;
+
+ Skin_Spectograph1R = 0.6;
+ Skin_Spectograph1G = 0.8;
+ Skin_Spectograph1B = 1;
+
+ Skin_Spectograph2R = 0;
+ Skin_Spectograph2G = 0;
+ Skin_Spectograph2B = 0.2;
+
+ Skin_SzczytR = 0.8;
+ Skin_SzczytG = 0;
+ Skin_SzczytB = 0;
+
+ Skin_SzczytLimitR = 0;
+ Skin_SzczytLimitG = 0.8;
+ Skin_SzczytLimitB = 0;
+
+ Skin_FontR = 0;
+ Skin_FontG = 0;
+ Skin_FontB = 0;
+
+ Skin_FontHighlightR = 0.3; // 0.3
+ Skin_FontHighlightG = 0.3; // 0.3
+ Skin_FontHighlightB = 1; // 1
+
+ Skin_TimeR = 0.25; //0,0,0
+ Skin_TimeG = 0.25;
+ Skin_TimeB = 0.25;
+
+ Skin_OscR = 0;
+ Skin_OscG = 0;
+ Skin_OscB = 0;
+
+ Skin_LyricsT = 494; // 500 / 510 / 400
+ Skin_SpectrumT = 470;
+ Skin_SpectrumBot = 570;
+ Skin_SpectrumH = 100;
+
+ Skin_P1_LinesR = 0.5; // 0.6 0.6 1
+ Skin_P1_LinesG = 0.5;
+ Skin_P1_LinesB = 0.5;
+
+ Skin_P2_LinesR = 0.5; // 1 0.6 0.6
+ Skin_P2_LinesG = 0.5;
+ Skin_P2_LinesB = 0.5;
+
+ Skin_P1_NotesB = 250;
+ Skin_P2_NotesB = 430; // 430 / 300
+
+ Skin_P1_ScoreT = 50;
+ Skin_P1_ScoreL = 20;
+
+ Skin_P2_ScoreT = 50;
+ Skin_P2_ScoreL = 640;
+
+procedure Initialize3D (Title: string);
+procedure Reinitialize3D;
+procedure SwapBuffers;
+
+procedure LoadTextures;
+procedure InitializeScreen;
+procedure LoadScreens( aShowLoading : boolean = true );
+procedure UnLoadScreens;
+
+
+implementation
+uses UMain, UIni, UDisplay, UCommandLine, Graphics, Classes, Windows;
+
+procedure LoadTextures;
+var
+ P: integer;
+ R, G, B: real;
+ Col: integer;
+begin
+ // zaladowanie tekstur
+ Log.LogStatus('Loading Textures', 'LoadTextures');
+ Tex_Left[0] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayLeft')), 'BMP', 'Transparent', 0);
+ Tex_Mid[0] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayMid')), 'BMP', 'Plain', 0);
+ Tex_Right[0] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayRight')), 'BMP', 'Transparent', 0);
+
+ // P1-6
+ for P := 1 to 6 do begin
+ LoadColor(R, G, B, 'P' + IntToStr(P) + 'Light');
+ Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
+ Tex_Left[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayLeft')), 'BMP', 'Note Transparent', Col);
+ Tex_Mid[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayMid')), 'BMP', 'Note Plain', Col);
+ Tex_Right[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('GrayRight')), 'BMP', 'Note Transparent', Col);
+
+ Tex_BG_Left[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('NoteBGLeft')), 'BMP', 'Alpha Black Colored', Col);
+ Tex_BG_Mid[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('NoteBGMid')), 'BMP', 'Alpha Black Colored', Col);
+ Tex_BG_Right[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('NoteBGRight')), 'BMP', 'Alpha Black Colored', Col);
+ end;
+
+ Tex_Note_Perfect_Star := Texture.LoadTexture(pchar(Skin.GetTextureFileName('NotePerfectStar')), 'JPG', 'Font Black', 0);
+ Tex_Note_Star := Texture.LoadTexture(pchar(Skin.GetTextureFileName('NoteStar')) , 'JPG', 'Alpha Black Colored', $FFFFFF);
+ Tex_Ball := Texture.LoadTexture(pchar(Skin.GetTextureFileName('Ball')), 'BMP', 'Transparent', $FF00FF);
+ Tex_Lyric_Help_Bar := Texture.LoadTexture(pchar(Skin.GetTextureFileName('LyricHelpBar')), 'BMP', 'Transparent', $FF00FF);
+
+
+ //TimeBar mod
+ Tex_TimeProgress := Texture.LoadTexture(pchar(Skin.GetTextureFileName('TimeBar')));
+ //eoa TimeBar mod
+
+ //SingBar Mod
+ Tex_SingBar_Back := Texture.LoadTexture(pchar(Skin.GetTextureFileName('SingBarBack')), 'JPG', 'Plain', 0);
+ Tex_SingBar_Bar := Texture.LoadTexture(pchar(Skin.GetTextureFileName('SingBarBar')), 'JPG', 'Plain', 0);
+ Tex_SingBar_Front := Texture.LoadTexture(pchar(Skin.GetTextureFileName('SingBarFront')), 'JPG', 'Font', 0);
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ Tex_SingLineBonusBack := Texture.LoadTexture(pchar(Skin.GetTextureFileName('LineBonusBack')), 'JPG', 'Font Black', 0);
+ {//Set Texture to Font High
+ Tex_SingLineBonusL.H := 32; Tex_SingLineBonusL.W := 8;
+ Tex_SingLineBonusM.H := 32; //Tex_SingLineBonusM.TexW := Tex_SingLineBonusM.TexW/2;
+ Tex_SingLineBonusR.H := 32; Tex_SingLineBonusR.W := 8; }
+ //PhrasenBonus - Line Bonus Mod End
+
+ // tworzenie czcionek
+ Log.LogStatus('Building Fonts', 'LoadTextures');
+ BuildFont;
+end;
+
+procedure Initialize3D (Title: string);
+var
+ Icon: TIcon;
+ Res: TResourceStream;
+ ISurface: PSDL_Surface;
+ Pixel: PByteArray;
+begin
+ Log.LogStatus('LoadOpenGL', 'Initialize3D');
+ Log.BenchmarkStart(2);
+
+ LoadOpenGL( GLLibName );
+
+ Log.LogStatus('SDL_Init', 'Initialize3D');
+ if ( SDL_Init(SDL_INIT_VIDEO or SDL_INIT_AUDIO)= -1 ) then begin
+ Log.LogError('SDL_Init Failed', 'Initialize3D');
+ exit;
+ end;
+
+ { //Load Icon
+ Res := TResourceStream.CreateFromID(HInstance, 3, RT_ICON);
+ Icon := TIcon.Create;
+ Icon.LoadFromStream(Res);
+ Res.Free;
+ Icon.
+ //Create icon Surface
+ SDL_CreateRGBSurfaceFrom (
+ SDL_SWSURFACE,
+ Icon.Width,
+ Icon.Height,
+ 32,
+ 128 or 64,
+ 32 or 16,
+ 8 or 4,
+ 2 or 1);
+ //SDL_BlitSurface(
+
+
+ SDL_WM_SetIcon(SDL_LoadBMP('DEFAULT_WINDOW_ICON'), 0); //}
+
+ SDL_WM_SetCaption(PChar(Title), nil);
+
+ InitializeScreen;
+
+ Log.BenchmarkEnd(2);
+ Log.LogBenchmark('--> Setting Screen', 2);
+
+ // ladowanie tekstur
+ Log.BenchmarkStart(2);
+ Texture := TTextureUnit.Create;
+ Texture.Limit := 1024*1024;
+
+ LoadTextures;
+ Log.BenchmarkEnd(2);
+ Log.LogBenchmark('--> Loading Textures', 2);
+
+ Log.BenchmarkStart(2);
+ Lyric := TLyric.Create;
+ Log.BenchmarkEnd(2);
+ Log.LogBenchmark('--> Loading Fonts', 2);
+
+ Log.BenchmarkStart(2);
+ Display := TDisplay.Create;
+ SDL_EnableUnicode(1);
+ Log.BenchmarkEnd(2); Log.LogBenchmark('====> Creating Display', 2);
+
+ Log.LogStatus('Loading Screens', 'Initialize3D');
+ Log.BenchmarkStart(3);
+
+ LoadScreens;
+ Display.ActualScreen^.FadeTo(@ScreenMain);
+
+ Log.BenchmarkEnd(2);
+ Log.LogBenchmark('--> Loading Screens', 2);
+
+ Log.LogStatus('Finish', 'Initialize3D');
+end;
+
+procedure SwapBuffers;
+begin
+ SDL_GL_SwapBuffers;
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity;
+ glOrtho(0, 800, 600, 0, -1, 100);
+ glMatrixMode(GL_MODELVIEW);
+end;
+
+procedure Reinitialize3D;
+begin
+// InitializeScreen;
+// LoadTextures;
+// LoadScreens;
+end;
+
+procedure InitializeScreen;
+var
+ S: string;
+ I: integer;
+ W, H: integer;
+ Depth: Integer;
+begin
+ if (Params.Screens <> -1) then
+ Screens := Params.Screens + 1
+ else
+ Screens := Ini.Screens + 1;
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ // If there is a resolution in Parameters, use it, else use the Ini value
+ I := Params.Resolution;
+ if (I <> -1) then
+ S := IResolution[I]
+ else
+ S := IResolution[Ini.Resolution];
+
+ I := Pos('x', S);
+ W := StrToInt(Copy(S, 1, I-1)) * Screens;
+ H := StrToInt(Copy(S, I+1, 1000));
+
+ {if ParamStr(1) = '-fsblack' then begin
+ W := 800;
+ H := 600;
+ end;
+ if ParamStr(1) = '-320x240' then begin
+ W := 320;
+ H := 240;
+ end; }
+
+ If (Params.Depth <> -1) then
+ Depth := Params.Depth
+ else
+ Depth := Ini.Depth;
+
+
+ Log.LogStatus('SDL_SetVideoMode', 'Initialize3D');
+// SDL_SetRefreshrate(85);
+// SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ if (Ini.FullScreen = 0) and (Not Params.FullScreen) then
+ screen := SDL_SetVideoMode(W, H, (Depth+1) * 16, SDL_OPENGL)
+ else begin
+ screen := SDL_SetVideoMode(W, H, (Depth+1) * 16, SDL_OPENGL or SDL_FULLSCREEN or SDL_HWSURFACE);
+ SDL_ShowCursor(0);
+ end;
+ if (screen = nil) then begin
+ Log.LogError('SDL_SetVideoMode Failed', 'Initialize3D');
+ exit;
+ end;
+
+ // clear screen once window is being shown
+ glClearColor(1, 1, 1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ SwapBuffers;
+
+ // zmienne
+ RenderW := 800;
+ RenderH := 600;
+ ScreenW := W;
+ ScreenH := H;
+end;
+
+procedure LoadScreens( aShowLoading : boolean = true );
+begin
+
+ ScreenLoading := TScreenLoading.Create;
+ if aShowLoading then
+ begin
+ ScreenLoading.onShow;
+ Display.ActualScreen := @ScreenLoading;
+ ScreenLoading.Draw;
+ Display.Draw;
+ SwapBuffers;
+ end;
+
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Loading', 3); Log.BenchmarkStart(3);
+{ ScreenWelcome := TScreenWelcome.Create; //'BG', 4, 3);
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Welcome', 3); Log.BenchmarkStart(3);}
+ ScreenMain := TScreenMain.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Main', 3); Log.BenchmarkStart(3);
+ ScreenName := TScreenName.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Name', 3); Log.BenchmarkStart(3);
+ ScreenLevel := TScreenLevel.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Level', 3); Log.BenchmarkStart(3);
+ ScreenSong := TScreenSong.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Song', 3); Log.BenchmarkStart(3);
+ ScreenSongMenu := TScreenSongMenu.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Song Menu', 3); Log.BenchmarkStart(3);
+ ScreenSing := TScreenSing.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Sing', 3); Log.BenchmarkStart(3);
+ ScreenScore := TScreenScore.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Score', 3); Log.BenchmarkStart(3);
+ ScreenTop := TScreenTop.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Top5', 3); Log.BenchmarkStart(3);
+ ScreenOptions := TScreenOptions.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options', 3); Log.BenchmarkStart(3);
+ ScreenOptionsGame := TScreenOptionsGame.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Game', 3); Log.BenchmarkStart(3);
+ ScreenOptionsGraphics := TScreenOptionsGraphics.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Graphics', 3); Log.BenchmarkStart(3);
+ ScreenOptionsSound := TScreenOptionsSound.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Sound', 3); Log.BenchmarkStart(3);
+ ScreenOptionsLyrics := TScreenOptionsLyrics.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Lyrics', 3); Log.BenchmarkStart(3);
+ ScreenOptionsThemes := TScreenOptionsThemes.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Themes', 3); Log.BenchmarkStart(3);
+ ScreenOptionsRecord := TScreenOptionsRecord.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Record', 3); Log.BenchmarkStart(3);
+ ScreenOptionsAdvanced := TScreenOptionsAdvanced.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Options Advanced', 3); Log.BenchmarkStart(3);
+ ScreenEditSub := TScreenEditSub.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Edit Sub', 3); Log.BenchmarkStart(3);
+ ScreenEdit := TScreenEdit.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Edit', 3); Log.BenchmarkStart(3);
+ ScreenEditConvert := TScreenEditConvert.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen EditConvert', 3); Log.BenchmarkStart(3);
+// ScreenEditHeader := TScreenEditHeader.Create(Skin.ScoreBG);
+// Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Edit Header', 3); Log.BenchmarkStart(3);
+ ScreenOpen := TScreenOpen.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Open', 3); Log.BenchmarkStart(3);
+ ScreenSingModi := TScreenSingModi.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Sing with Modi support', 3); Log.BenchmarkStart(3);
+ ScreenSongMenu := TScreenSongMenu.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen SongMenu', 3); Log.BenchmarkStart(3);
+ ScreenSongJumpto := TScreenSongJumpto.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen SongJumpto', 3); Log.BenchmarkStart(3);
+ ScreenPopupCheck := TScreenPopupCheck.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Check)', 3); Log.BenchmarkStart(3);
+ ScreenPopupError := TScreenPopupError.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Error)', 3); Log.BenchmarkStart(3);
+ ScreenPopupHelp := TScreenPopupHelp.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Help)', 3); Log.BenchmarkStart(3);
+ ScreenPartyNewRound := TScreenPartyNewRound.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyNewRound', 3); Log.BenchmarkStart(3);
+ ScreenPartyScore := TScreenPartyScore.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyScore', 3); Log.BenchmarkStart(3);
+ ScreenPartyWin := TScreenPartyWin.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyWin', 3); Log.BenchmarkStart(3);
+ ScreenPartyOptions := TScreenPartyOptions.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyOptions', 3); Log.BenchmarkStart(3);
+ ScreenPartyPlayer := TScreenPartyPlayer.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyPlayer', 3); Log.BenchmarkStart(3);
+ ScreenStatMain := TScreenStatMain.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Stat Main', 3); Log.BenchmarkStart(3);
+ ScreenStatDetail := TScreenStatDetail.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Stat Detail', 3); Log.BenchmarkStart(3);
+ //Now Created when needed
+ //ScreenCredits := TScreenCredits.Create;
+ //Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Credits', 3); Log.BenchmarkStart(3);
+
+ //PartyM2 Screens
+ ScreenPartyOptionsM2 := TScreenPartyOptionsM2.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyOptionsM2', 3); Log.BenchmarkStart(3);
+ ScreenPartyPlayerM2 := TScreenPartyPlayerM2.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyPlayerM2', 3); Log.BenchmarkStart(3);
+ ScreenPartyNewRoundM2 := TScreenPartyNewRoundM2.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyNewRoundM2', 3); Log.BenchmarkStart(3);
+ end;
+
+procedure UnLoadScreens;
+begin
+(*
+ ScreenLoading := TScreenLoading.Create;
+ ScreenLoading.onShow;
+
+ Display.ActualScreen := @ScreenLoading;
+
+ ScreenLoading.Draw;
+ Display.Draw;
+ SwapBuffers;
+*)
+
+ freeandnil( ScreenMain );
+ freeandnil( ScreenName );
+ freeandnil( ScreenLevel);
+ freeandnil( ScreenSong );
+ freeandnil( ScreenSongMenu );
+ freeandnil( ScreenSing );
+ freeandnil( ScreenScore);
+ freeandnil( ScreenTop );
+ freeandnil( ScreenOptions );
+ freeandnil( ScreenOptionsGame );
+ freeandnil( ScreenOptionsGraphics );
+ freeandnil( ScreenOptionsSound );
+ freeandnil( ScreenOptionsLyrics );
+// freeandnil( ScreenOptionsThemes );
+ freeandnil( ScreenOptionsRecord );
+ freeandnil( ScreenOptionsAdvanced );
+ freeandnil( ScreenEditSub );
+ freeandnil( ScreenEdit );
+ freeandnil( ScreenEditConvert );
+ freeandnil( ScreenOpen );
+ freeandnil( ScreenSingModi );
+ freeandnil( ScreenSongMenu );
+ freeandnil( ScreenSongJumpto);
+ freeandnil( ScreenPopupCheck );
+ freeandnil( ScreenPopupError );
+ freeandnil( ScreenPartyNewRound );
+ freeandnil( ScreenPartyScore );
+ freeandnil( ScreenPartyWin );
+ freeandnil( ScreenPartyOptions );
+ freeandnil( ScreenPartyPlayer );
+ freeandnil( ScreenStatMain );
+ freeandnil( ScreenStatDetail );
+
+ //Party M2 Screens
+ freeandnil( ScreenPartyNewRoundM2 );
+ //freeandnil( ScreenPartyScoreM2 );
+ //freeandnil( ScreenPartyWinM2 );
+ freeandnil( ScreenPartyOptionsM2 );
+ freeandnil( ScreenPartyPlayerM2 );
+end;
+
+end.
diff --git a/Game/Code/Classes/UGraphicClasses.pas b/Game/Code/Classes/UGraphicClasses.pas
new file mode 100644
index 00000000..6d1cd36e
--- /dev/null
+++ b/Game/Code/Classes/UGraphicClasses.pas
@@ -0,0 +1,655 @@
+// notes:
+unit UGraphicClasses;
+
+interface
+uses UTexture;
+const DelayBetweenFrames : Cardinal = 60;
+type
+
+ TParticleType=(GoldenNote, PerfectNote, NoteHitTwinkle, PerfectLineTwinkle, ColoredStar, Flare);
+
+ TColour3f = Record
+ r, g, b: Real;
+ end;
+
+ TParticle = Class
+ X, Y : Real; //Position
+ Screen : Integer;
+ W, H : Cardinal; //dimensions of particle
+ Col : array of TColour3f; // Colour(s) of particle
+ Scale : array of Real; // Scaling factors of particle layers
+ Frame : Byte; //act. Frame
+ Tex : Cardinal; //Tex num from Textur Manager
+ Live : Byte; //How many Cycles before Kill
+ RecIndex : Integer; //To which rectangle this particle belongs (only GoldenNote)
+ StarType : TParticleType; // GoldenNote | PerfectNote | NoteHitTwinkle | PerfectLineTwinkle
+ Alpha : Real; // used for fading...
+ mX, mY : Real; // movement-vector for PerfectLineTwinkle
+ SizeMod : Real; // experimental size modifier
+ SurviveSentenceChange : Boolean;
+
+ Constructor Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
+ Destructor Destroy();
+ procedure Draw;
+ procedure LiveOn;
+ end;
+
+ RectanglePositions = Record
+ xTop, yTop, xBottom, yBottom : Real;
+ TotalStarCount : Integer;
+ CurrentStarCount : Integer;
+ Screen : Integer;
+ end;
+
+ PerfectNotePositions = Record
+ xPos, yPos : Real;
+ Screen : Integer;
+ end;
+
+ TEffectManager = Class
+ Particle : array of TParticle;
+ LastTime : Cardinal;
+ RecArray : Array of RectanglePositions;
+ TwinkleArray : Array[0..5] of Real; // store x-position of last twinkle for every player
+ PerfNoteArray : Array of PerfectNotePositions;
+
+ FlareTex: TTexture;
+
+ constructor Create;
+ destructor Destroy; override;
+ procedure Draw;
+ function Spawn(X, Y: Real;
+ Screen: Integer;
+ Live: Byte;
+ StartFrame: Integer;
+ RecArrayIndex: Integer; // this is only used with GoldenNotes
+ StarType: TParticleType;
+ Player: Cardinal // for PerfectLineTwinkle
+ ): Cardinal;
+ procedure SpawnRec();
+ procedure Kill(index: Cardinal);
+ procedure KillAll();
+ procedure SentenceChange();
+ procedure SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
+ procedure SavePerfectNotePos(Xtop, Ytop: Real);
+ procedure GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
+ procedure SpawnPerfectLineTwinkle();
+ end;
+
+var GoldenRec : TEffectManager;
+
+implementation
+uses sysutils, Windows, gl, UIni, UMain, UThemes, USkins, UGraphic, UDrawTexture, math, dialogs;
+
+//TParticle
+Constructor TParticle.Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
+begin
+ inherited Create;
+ // in this constructor we set all initial values for our particle
+ X := cX;
+ Y := cY;
+ Screen := cScreen;
+ Live := cLive;
+ Frame:= cFrame;
+ RecIndex := cRecArrayIndex;
+ StarType := cStarType;
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ SetLength(Scale,1);
+ Scale[0] := 1;
+ SurviveSentenceChange := False;
+ SizeMod := 1;
+ case cStarType of
+ GoldenNote:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := 20;
+ H := 20;
+ SetLength(Scale,4);
+ Scale[1]:=0.8;
+ Scale[2]:=0.4;
+ Scale[3]:=0.3;
+ SetLength(Col,4);
+ Col[0].r := 1;
+ Col[0].g := 0.7;
+ Col[0].b := 0.1;
+
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+
+ Col[2].r := 1;
+ Col[2].g := 1;
+ Col[2].b := 1;
+
+ Col[3].r := 1;
+ Col[3].g := 1;
+ Col[3].b := 1;
+ end;
+ PerfectNote:
+ begin
+ Tex := Tex_Note_Perfect_Star.TexNum;
+ W := 30;
+ H := 30;
+ SetLength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := 0.95;
+ end;
+ NoteHitTwinkle:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ Alpha := (Live/16); // linear fade-out
+ W := 15;
+ H := 15;
+ Setlength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := RandomRange(10*Live,100)/90; //0.9;
+ end;
+ PerfectLineTwinkle:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := RandomRange(10,20);
+ H := W;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ SurviveSentenceChange:=True;
+ // assign colours according to player given
+ SetLength(Scale,3);
+ Scale[1]:=0.3;
+ Scale[2]:=0.2;
+ SetLength(Col,3);
+ case Player of
+ 0: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
+ 1: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P2Light');
+ 2: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P3Light');
+ 3: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P4Light');
+ 4: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P5Light');
+ 5: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P6Light');
+ else LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
+ end;
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+ Col[2].r:=Col[0].r+0.5;
+ Col[2].g:=Col[0].g+0.5;
+ Col[2].b:=Col[0].b+0.5;
+ mX := RandomRange(-5,5);
+ mY := RandomRange(-5,5);
+ end;
+ ColoredStar:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := RandomRange(10,20);
+ H := W;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ SurviveSentenceChange:=True;
+ // assign colours according to player given
+ SetLength(Scale,1);
+ SetLength(Col,1);
+ Col[0].b := (Player and $ff)/255;
+ Col[0].g := ((Player shr 8) and $ff)/255;
+ Col[0].r := ((Player shr 16) and $ff)/255;
+ mX := 0;
+ mY := 0;
+ end;
+ Flare:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := 7;
+ H := 7;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ mX := RandomRange(-5,5);
+ mY := RandomRange(-5,5);
+ SetLength(Scale,4);
+ Scale[1]:=0.8;
+ Scale[2]:=0.4;
+ Scale[3]:=0.3;
+ SetLength(Col,4);
+ Col[0].r := 1;
+ Col[0].g := 0.7;
+ Col[0].b := 0.1;
+
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+
+ Col[2].r := 1;
+ Col[2].g := 1;
+ Col[2].b := 1;
+
+ Col[3].r := 1;
+ Col[3].g := 1;
+ Col[3].b := 1;
+
+ end;
+ else // just some random default values
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ Alpha := 1;
+ W := 20;
+ H := 20;
+ SetLength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := 1;
+ end;
+ end;
+end;
+
+Destructor TParticle.Destroy();
+begin
+ SetLength(Scale,0);
+ SetLength(Col,0);
+ inherited;
+end;
+
+procedure TParticle.LiveOn;
+begin
+ //Live = 0 => Live forever <blindy> ?? die werden doch aber im Manager bei Draw getötet, wenns 0 is
+ if (Live > 0) then
+ Dec(Live);
+
+ // animate frames
+ Frame := ( Frame + 1 ) mod 16;
+
+ // make our particles do funny stuff (besides being animated)
+ // changes of any particle-values throughout its life are done here
+ case StarType of
+ GoldenNote:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ PerfectNote:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ NoteHitTwinkle:
+ begin
+ Alpha := (Live/10); // linear fade-out
+ end;
+ PerfectLineTwinkle:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ // move around
+ X := X + mX;
+ Y := Y + mY;
+ end;
+ ColoredStar:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ Flare:
+ begin
+ Alpha := (-cos((Frame+1)/16*1.7*pi+0.3*pi)+1); // neat fade-in-and-out
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ // move around
+ X := X + mX;
+ Y := Y + mY;
+ mY:=mY+1.8;
+// mX:=mX/2;
+ end;
+ end;
+end;
+
+procedure TParticle.Draw;
+var L: Cardinal;
+begin
+ if ScreenAct = Screen then
+ // this draws (multiple) texture(s) of our particle
+ for L:=0 to High(Col) do
+ begin
+ glColor4f(Col[L].r, Col[L].g, Col[L].b, Alpha);
+
+ glBindTexture(GL_TEXTURE_2D, Tex);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ begin
+ glBegin(GL_QUADS);
+ glTexCoord2f((1/16) * Frame, 0); glVertex2f(X-W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame + (1/16), 0); glVertex2f(X-W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame + (1/16), 1); glVertex2f(X+W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame, 1); glVertex2f(X+W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
+ glEnd;
+ end;
+ end;
+ glcolor4f(1,1,1,1);
+end;
+// end of TParticle
+
+// TEffectManager
+
+constructor TEffectManager.Create;
+var c: Cardinal;
+begin
+ inherited;
+ LastTime := GetTickCount;
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0;
+ end;
+end;
+
+destructor TEffectManager.Destroy;
+begin
+ Killall;
+ inherited;
+end;
+
+
+procedure TEffectManager.Draw;
+var
+ I: Integer;
+ CurrentTime: Cardinal;
+//const
+// DelayBetweenFrames : Cardinal = 100;
+begin
+
+ CurrentTime := GetTickCount;
+ //Manage particle life
+ if (CurrentTime - LastTime) > DelayBetweenFrames then
+ begin
+ LastTime := CurrentTime;
+ for I := 0 to high(Particle) do
+ Particle[I].LiveOn;
+ end;
+
+ I := 0;
+ //Kill dead particles
+ while (I <= High(Particle)) do
+ begin
+ if (Particle[I].Live <= 0) then
+ begin
+ kill(I);
+ end
+ else
+ begin
+ inc(I);
+ end;
+ end;
+
+ //Draw
+ for I := 0 to high(Particle) do
+ begin
+ Particle[I].Draw;
+ end;
+end;
+
+// this method creates just one particle
+function TEffectManager.Spawn(X, Y: Real; Screen: Integer; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : TParticleType; Player: Cardinal): Cardinal;
+begin
+ Result := Length(Particle);
+ SetLength(Particle, (Result + 1));
+ Particle[Result] := TParticle.Create(X, Y, Screen, Live, StartFrame, RecArrayIndex, StarType, Player);
+end;
+
+// manage Sparkling of GoldenNote Bars
+procedure TEffectManager.SpawnRec();
+Var
+ Xkatze, Ykatze : Real;
+ RandomFrame : Integer;
+ P : Integer; // P as seen on TV as Positionman
+begin
+//Spawn a random amount of stars within the given coordinates
+//RandomRange(0,14) <- this one starts at a random frame, 16 is our last frame - would be senseless to start a particle with 16, cause it would be dead at the next frame
+for P:= 0 to high(RecArray) do
+ begin
+ while (RecArray[P].TotalStarCount > RecArray[P].CurrentStarCount) do
+ begin
+ Xkatze := RandomRange(Ceil(RecArray[P].xTop), Ceil(RecArray[P].xBottom));
+ Ykatze := RandomRange(Ceil(RecArray[P].yTop), Ceil(RecArray[P].yBottom));
+ RandomFrame := RandomRange(0,14);
+ // Spawn a GoldenNote Particle
+ Spawn(Xkatze, Ykatze, RecArray[P].Screen, 16 - RandomFrame, RandomFrame, P, GoldenNote, 0);
+ inc(RecArray[P].CurrentStarCount);
+ end;
+ end;
+ draw;
+end;
+
+// kill one particle (with given index in our particle array)
+procedure TEffectManager.Kill(Index: Cardinal);
+var
+ LastParticleIndex : Integer;
+begin
+// delete particle indexed by Index,
+// overwrite it's place in our particle-array with the particle stored at the last array index,
+// shorten array
+ LastParticleIndex := high(Particle);
+ if not(LastParticleIndex = -1) then // is there still a particle to delete?
+ begin
+ if not(Particle[Index].RecIndex = -1) then // if it is a GoldenNote particle...
+ dec(RecArray[Particle[Index].RecIndex].CurrentStarCount); // take care of its associated GoldenRec
+ // now get rid of that particle
+ Particle[Index].Destroy;
+ Particle[Index] := Particle[LastParticleIndex];
+ SetLength(Particle, LastParticleIndex);
+ end;
+end;
+
+// clean up all particles and management structures
+procedure TEffectManager.KillAll();
+var c: Cardinal;
+begin
+//It's the kill all kennies rotuine
+ while Length(Particle) > 0 do // kill all existing particles
+ Kill(0);
+ SetLength(RecArray,0); // remove GoldenRec positions
+ SetLength(PerfNoteArray,0); // remove PerfectNote positions
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0; // reset GoldenNoteHit memory
+ end;
+end;
+
+procedure TEffectManager.SentenceChange();
+var c: Cardinal;
+begin
+ c:=0;
+ while c <= High(Particle) do
+ begin
+ if Particle[c].SurviveSentenceChange then
+ inc(c)
+ else
+ Kill(c);
+ end;
+ SetLength(RecArray,0); // remove GoldenRec positions
+ SetLength(PerfNoteArray,0); // remove PerfectNote positions
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0; // reset GoldenNoteHit memory
+ end;
+end;
+
+procedure TeffectManager.GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
+//Twinkle stars while golden note hit
+// this is called from UDraw.pas, SingDrawPlayerCzesc
+var
+ C, P, XKatze, YKatze, LKatze: Integer;
+ H: Real;
+begin
+ // make sure we spawn only one time at one position
+ if (TwinkleArray[Player] < Right) then
+ For P := 0 to high(RecArray) do // Are we inside a GoldenNoteRectangle?
+ begin
+ H := (Top+Bottom)/2; // helper...
+ with RecArray[P] do
+ if ((xBottom >= Right) and (xTop <= Right) and
+ (yTop <= H) and (yBottom >= H))
+ and (Screen = ScreenAct) then
+ begin
+ TwinkleArray[Player] := Right; // remember twinkle position for this player
+ for C := 1 to 10 do
+ begin
+ Ykatze := RandomRange(ceil(Top) , ceil(Bottom));
+ XKatze := RandomRange(-7,3);
+ LKatze := RandomRange(7,13);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Top)-6 , ceil(Top));
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(4,7);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Bottom), ceil(Bottom)+6);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(4,7);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Top)-10 , ceil(Top)-6);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(1,4);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Bottom)+6 , ceil(Bottom)+10);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(1,4);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+
+ exit; // found a matching GoldenRec, did spawning stuff... done
+ end;
+ end;
+end;
+
+procedure TEffectManager.SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
+var
+ P : Integer; // P like used in Positions
+ NewIndex : Integer;
+begin
+ For P := 0 to high(RecArray) do // Do we already have that "new" position?
+ begin
+ if (ceil(RecArray[P].xTop) = ceil(Xtop)) and
+ (ceil(RecArray[P].yTop) = ceil(Ytop)) and
+ (ScreenAct = RecArray[p].Screen) then
+ exit; // it's already in the array, so we don't have to create a new one
+ end;
+
+ // we got a new position, add the new positions to our array
+ NewIndex := Length(RecArray);
+ SetLength(RecArray, NewIndex + 1);
+ RecArray[NewIndex].xTop := Xtop;
+ RecArray[NewIndex].yTop := Ytop;
+ RecArray[NewIndex].xBottom := Xbottom;
+ RecArray[NewIndex].yBottom := Ybottom;
+ RecArray[NewIndex].TotalStarCount := ceil(Xbottom - Xtop) div 12 + 3;
+ RecArray[NewIndex].CurrentStarCount := 0;
+ RecArray[NewIndex].Screen := ScreenAct;
+end;
+
+procedure TEffectManager.SavePerfectNotePos(Xtop, Ytop: Real);
+var
+ P : Integer; // P like used in Positions
+ NewIndex : Integer;
+ RandomFrame : Integer;
+ Xkatze, Ykatze : Integer;
+begin
+ For P := 0 to high(PerfNoteArray) do // Do we already have that "new" position?
+ begin
+ with PerfNoteArray[P] do
+ if (ceil(xPos) = ceil(Xtop)) and (ceil(yPos) = ceil(Ytop)) and
+ (Screen = ScreenAct) then
+ exit; // it's already in the array, so we don't have to create a new one
+ end; //for
+
+ // we got a new position, add the new positions to our array
+ NewIndex := Length(PerfNoteArray);
+ SetLength(PerfNoteArray, NewIndex + 1);
+ PerfNoteArray[NewIndex].xPos := Xtop;
+ PerfNoteArray[NewIndex].yPos := Ytop;
+ PerfNoteArray[NewIndex].Screen := ScreenAct;
+
+ for P:= 0 to 2 do
+ begin
+ Xkatze := RandomRange(ceil(Xtop) - 5 , ceil(Xtop) + 10);
+ Ykatze := RandomRange(ceil(Ytop) - 5 , ceil(Ytop) + 10);
+ RandomFrame := RandomRange(0,14);
+ Spawn(Xkatze, Ykatze, ScreenAct, 16 - RandomFrame, RandomFrame, -1, PerfectNote, 0);
+ end; //for
+
+end;
+
+procedure TEffectManager.SpawnPerfectLineTwinkle();
+var
+ P,I,Life: Cardinal;
+ Left, Right, Top, Bottom: Cardinal;
+ cScreen: Integer;
+begin
+// calculation of coordinates done with hardcoded values like in UDraw.pas
+// might need to be adjusted if drawing of SingScreen is modified
+// coordinates may still be a bit weird and need adjustment
+ if Ini.SingWindow = 0 then begin
+ Left := 130;
+ end else begin
+ Left := 30;
+ end;
+ Right := 770;
+ // spawn effect for every player with a perfect line
+ for P:=0 to PlayersPlay-1 do
+ if Player[P].LastSentencePerfect then
+ begin
+ // calculate area where notes of this player are drawn
+ case PlayersPlay of
+ 1: begin
+ Bottom:=Skin_P2_NotesB+10;
+ Top:=Bottom-105;
+ cScreen:=1;
+ end;
+ 2,4: begin
+ case P of
+ 0,2: begin
+ Bottom:=Skin_P1_NotesB+10;
+ Top:=Bottom-105;
+ end;
+ else begin
+ Bottom:=Skin_P2_NotesB+10;
+ Top:=Bottom-105;
+ end;
+ end;
+ case P of
+ 0,1: cScreen:=1;
+ else cScreen:=2;
+ end;
+ end;
+ 3,6: begin
+ case P of
+ 0,3: begin
+ Top:=130;
+ Bottom:=Top+85;
+ end;
+ 1,4: begin
+ Top:=255;
+ Bottom:=Top+85;
+ end;
+ 2,5: begin
+ Top:=380;
+ Bottom:=Top+85;
+ end;
+ end;
+ case P of
+ 0,1,2: cScreen:=1;
+ else cScreen:=2;
+ end;
+ end;
+ end;
+ // spawn Sparkling Stars inside calculated coordinates
+ for I:= 0 to 80 do
+ begin
+ Life:=RandomRange(8,16);
+ Spawn(RandomRange(Left,Right), RandomRange(Top,Bottom), cScreen, Life, 16-Life, -1, PerfectLineTwinkle, P);
+ end;
+ end;
+end;
+
+end.
+
diff --git a/Game/Code/Classes/UHelp.pas b/Game/Code/Classes/UHelp.pas
new file mode 100644
index 00000000..4691858c
--- /dev/null
+++ b/Game/Code/Classes/UHelp.pas
@@ -0,0 +1,401 @@
+unit UHelp;
+
+interface
+uses
+ IniFiles,
+ ULog,
+ SysUtils;
+
+type
+ TKeymap = record
+ Key: array of string; //key-combination translated
+ Text: string; //description text
+ end;
+
+ TSection = record
+ name: string;
+ Keys: array of TKeymap;
+ end;
+
+ TSub = record
+ title: string;
+ text: array of string;
+ end;
+
+ TKeyNames = record
+ Key: array of string;
+ end;
+
+ TTextResultSection = record
+ name: string;
+ Keys: array of TKeyNames;
+ KeyDescription: array of string;
+ end;
+
+ TTextResult = record
+ Title: String;
+ Description: String;
+ Subs: array of TSub;
+ Sections: array of TTextResultSection;
+ end;
+
+ TKeys = record
+ Key: string;
+ Translation: string;
+ end;
+
+ TEntry = record
+ ID: string;
+ Title: string;
+ Description: string;
+ Subs: array of TSub;
+ Sections: array of TSection;
+ end;
+
+ TLanguageList = record
+ Name: string;
+ end;
+
+ THelp = class
+ private
+ ScrollPos: double;
+ Entry: array of TEntry;
+ SEntry: array of TEntry;
+ AEntry: TEntry;
+ List: array of TLanguageList;
+ Implode_Glue1, Implode_Glue2: String;
+ public
+ MaxLines: integer;
+ constructor Create;
+ procedure LoadList;
+
+ procedure ChangeLanguage(Language: String);
+ //procedure LoadKeys;
+ function SetHelpID(ID: String):boolean;
+ function GetHelpStr(): TTextResult;
+ procedure SetScrollPos(pos: double);
+ function GetScrollPos(): double;
+ end;
+
+
+var
+ Help: THelp;
+
+
+implementation
+uses UFiles, SDL, Classes, ULanguage;
+
+//----------
+//Create - Construct Class then LoadList + Standard Language + Set Standard Implode Glues
+//----------
+constructor THelp.Create;
+var
+ I, J, K: Integer;
+begin
+ LoadList;
+ MaxLines := 0;
+ //LoadKeys;
+ //Set Implode Glues for Backward Compatibility
+ Implode_Glue1 := ', ';
+ Implode_Glue2 := ' and ';
+
+ if (Length(List) = 0) then //No Language Files Loaded -> Abort Loading
+ Log.CriticalError('Could not load any Language File (Help System)');
+
+ //Standard Language (If a Language File is Incomplete)
+ //Then use English Language
+ for I := 0 to high(List) do //Search for English Language
+ begin
+ //English Language Found -> Load
+ if Uppercase(List[I].Name) = 'ENGLISH' then
+ begin
+ ChangeLanguage('English');
+
+ SetLength(SEntry, Length(Entry));
+
+ for J := low(Entry) to high(Entry) do
+ begin
+ SetLength(SEntry[J].Sections, Length(Entry[J].Sections));
+ SEntry[J].ID := Entry[J].ID;
+ SEntry[J].Title := Entry[J].Title;
+ SEntry[J].Description := Entry[J].Description;
+ for K := low(Entry[J].Sections) to high(Entry[J].Sections) do
+ SEntry[J].Sections[K] := Entry[J].Sections[K];
+ end;
+
+ SetLength(List, 0);
+
+ Break;
+ end;
+
+ if (I = high(List)) then
+ Log.LogError('English Languagefile missing! No standard Translation loaded (Help System)');
+ end;
+ //Standard Language END
+
+end;
+
+//----------
+//LoadList - Parse the Help Dir searching Translations
+//----------
+procedure THelp.LoadList;
+var
+ SR: TSearchRec; // for parsing directory
+begin
+ SetLength(List, 0);
+
+ if FindFirst(LanguagesPath + '*.ini', 0, SR) = 0 then begin
+ repeat
+ SetLength(List, Length(List)+1);
+ SR.Name := ChangeFileExt(SR.Name, '');
+ List[High(List)].Name := SR.Name;
+ until FindNext(SR) <> 0;
+ SysUtils.FindClose(SR);
+ end; // if FindFirst
+end;
+
+//----------
+//ChangeLanguage - Load the specified LanguageFile
+//----------
+procedure THelp.ChangeLanguage(Language: String);
+var
+ IniFile: TIniFile;
+ E: integer; // entry
+ S: TStringList;
+ SL : TStringList;
+ num: Integer;
+ I, J: Integer;
+ Keys: array of TKeys;
+ tempStr: string;
+ ActSection: integer;
+ ActSub: integer;
+ ActKey: integer;
+ ActSubEntry: integer;
+
+ function GetIDStr(ID: integer):string;
+ var
+ S: string;
+ begin
+ S := IntToStr(ID);
+ while (Length(S)<3) do S := '0' + S;
+ Result := 'ID_' + S;
+ end;
+
+ function GetKeyTranslation(Key: string):string;
+ var
+ I: Integer;
+ begin
+ Result := 'Error';
+ for I := 0 to Length(Keys) - 1 do
+ begin
+ if Keys[I].Key=Key then
+ begin
+ Result := Keys[I].Translation;
+ break;
+ end;
+ end;
+ end;
+
+begin
+ IniFile := TIniFile.Create(LanguagesPath + Language + '.ini');
+
+ SetLength(Keys, 0);
+ //read keys
+ S := TStringList.Create;
+ IniFile.ReadSectionValues('Keymap', S);
+
+ SetLength(Keys, S.Count);
+ for E := 0 to high(Keys) do
+ begin
+ if S.Names[E] = 'IMPLODE_GLUE1' then
+ Implode_Glue1 := S.ValueFromIndex[E]+ ' '
+ else if S.Names[E] = 'IMPLODE_GLUE2' then
+ Implode_Glue2 := ' ' + S.ValueFromIndex[E] + ' ';
+
+ Keys[E].Key := S.Names[E];
+ Keys[E].Translation := S.ValueFromIndex[E];
+ end;
+
+ SetLength(Entry, 0);
+ num := IniFile.ReadInteger('config', 'NumIDs', 0);
+
+ if num>0 then
+ begin
+ SetLength(Entry, num);
+ for I:=1 to num do
+ begin
+
+ Entry[I-1].ID:= GetIDStr(I);
+ Entry[I-1].Title := IniFile.ReadString(GetIDStr(I), 'Title', 'error title: ' + GetIDStr(I));
+ Entry[I-1].Description := IniFile.ReadString(GetIDStr(I), 'Description', 'error description: ' + GetIDStr(I));
+
+ //read subs, sections and keymapping
+ S := TStringList.Create;
+ IniFile.ReadSectionValues(GetIDStr(I), S);
+ ActSub := -1;
+ ActSubEntry := -1;
+ ActSection := -1;
+ ActKey := -1;
+
+ //SetLength(Entry[I-1].Keys, S.Count-2);
+ for E := 0 to S.Count-1 do
+ begin
+ if S.Names[E] = 'IMPLODE_GLUE1' then
+ Implode_Glue1 := S.ValueFromIndex[E]+ ' '
+ else if S.Names[E] = 'IMPLODE_GLUE2' then
+ Implode_Glue2 := ' ' + S.ValueFromIndex[E] + ' ';
+
+ if (S.Names[E] <> 'Title') and (S.Names[E] <> 'Description') then
+ begin
+ tempStr := S.Names[E];
+
+ SL:=TStringList.Create;
+ try
+ ExtractStrings(['_'], [], PChar(tempStr), SL);
+ //check new Sub
+ if SL[0]='SUB' then
+ begin
+ inc(ActSub);
+ ActSubEntry := -1;
+ SetLength(Entry[I-1].Subs, ActSub+1);
+ Entry[I-1].Subs[ActSub].title := S.ValueFromIndex[E];
+
+ end
+
+ //check sub entry
+ else if SL[0]='ENT' then
+ begin
+ inc(ActSubEntry);
+ SetLength(Entry[I-1].Subs[ActSub].text, ActSubEntry+1);
+ Entry[I-1].Subs[ActSub].text[ActSubEntry] := S.ValueFromIndex[E];
+ end
+
+ //check new section
+ else if SL[0]='SEC' then
+ begin
+ inc(ActSection);
+ ActKey := -1;
+ SetLength(Entry[I-1].Sections, ActSection+1);
+ Entry[I-1].Sections[ActSection].name := S.ValueFromIndex[E];
+ end
+
+ //read keymap
+ else if ActSection=-1 then
+ begin
+ Log.LogError('No section in keymapping of ' + GetIDStr(I) + ' in ' + language + '.ini');
+ end else
+ begin
+ inc(ActKey);
+ SetLength(Entry[I-1].Sections[ActSection].Keys, ActKey +1);
+ Entry[I-1].Sections[ActSection].Keys[ActKey].Text := S.ValueFromIndex[E];
+
+ SetLength(Entry[I-1].Sections[ActSection].Keys[ActKey].Key, SL.Count);
+ for J := 0 to SL.Count-1 do
+ Entry[I-1].Sections[ActSection].Keys[ActKey].Key[J] := GetKeyTranslation(SL[J]);
+ end;
+
+ Finally
+ SL.Free;
+ end;
+
+ end;
+ end;
+
+ S.Free;
+ end;
+ end;
+
+ IniFile.Free;
+end;
+
+function THelp.SetHelpID(ID: String):boolean;
+var
+ E, J: integer; // entry
+begin
+ Result := false;
+ ScrollPos := 0.0;
+
+ for E := 0 to high(Entry) do
+ begin
+ if ID = Entry[E].ID then
+ begin
+ Result := true;
+ AEntry := Entry[E];
+ {
+ SetLength(AEntry.Keys, Length(Entry[E].Keys));
+ AEntry.ID := Entry[E].ID;
+ AEntry.Title := Entry[E].Title;
+ AEntry.Description := Entry[E].Description;
+ for J := low(Entry[E].Keys) to high(Entry[E].Keys) do
+ AEntry.Keys[J] := Entry[E].Keys[J];}
+ exit;
+ end;
+ end;
+
+ //Standard Language (If a Language File is Incomplete)
+ //Then use Standard Language
+ for E := low(SEntry) to high(SEntry) do
+ begin
+ if ID = SEntry[E].ID then
+ begin
+ Result := true;
+ AEntry := SEntry[E];
+ {
+ SetLength(AEntry.Keys, Length(SEntry[E].Keys));
+ AEntry.ID := SEntry[E].ID;
+ AEntry.Title := SEntry[E].Title;
+ AEntry.Description := SEntry[E].Description;
+ for J := low(SEntry[E].Keys) to high(SEntry[E].Keys) do
+ AEntry.Keys[J] := SEntry[E].Keys[J]; }
+
+ exit;
+ end;
+ end;
+ //Standard Language END
+end;
+
+function THelp.GetHelpStr(): TTextResult;
+var
+ K, I, J: Integer;
+ w: real;
+begin
+ SetLength(Result.Sections, Length(AEntry.Sections));
+ for K := 0 to Length(AEntry.Sections) - 1 do
+ begin
+ SetLength(Result.Sections[K].Keys, Length(AEntry.Sections[K].Keys));
+ SetLength(Result.Sections[K].KeyDescription, Length(AEntry.Sections[K].Keys));
+ Result.Sections[K].name := AEntry.Sections[K].name;
+
+ for I := 0 to Length(AEntry.Sections[K].Keys)-1 do
+ begin
+ SetLength(Result.Sections[K].Keys[I].Key, Length(AEntry.Sections[K].Keys[I].Key));
+ for J := 0 to Length(AEntry.Sections[K].Keys[I].Key) - 1 do
+ begin
+ Result.Sections[K].Keys[I].Key[J] := '[' + AEntry.Sections[K].Keys[I].Key[J] + ']';
+ end;
+ Result.Sections[K].KeyDescription[I] := AEntry.Sections[K].Keys[I].Text;
+ end;
+ end;
+
+ SetLength(Result.Subs, Length(AEntry.Subs));
+ for K := 0 to Length(AEntry.Subs) - 1 do
+ begin
+ Result.Subs[K].title := AEntry.Subs[K].title;
+ Result.Subs[K].text := AEntry.Subs[K].text;
+ end;
+
+ Result.Title := AEntry.Title;
+ Result.Description := AEntry.Description;
+end;
+
+procedure THelp.SetScrollPos(pos: double);
+begin
+ ScrollPos := pos;
+end;
+
+function THelp.GetScrollPos(): double;
+begin
+ Result := ScrollPos;
+end;
+
+end.
diff --git a/Game/Code/Classes/UIni.pas b/Game/Code/Classes/UIni.pas
new file mode 100644
index 00000000..8e452dd5
--- /dev/null
+++ b/Game/Code/Classes/UIni.pas
@@ -0,0 +1,820 @@
+unit UIni;
+
+interface
+uses IniFiles, ULog, SysUtils;
+
+type
+ TIni = class
+ Name: array[0..11] of string;
+
+ // Templates for Names Mod
+ NameTeam: array[0..2] of string;
+ NameTemplate: array[0..11] of string;
+
+ //Filename of the opened iniFile
+ Filename: string;
+
+ // Game
+ Players: integer;
+ Difficulty: integer;
+ Language: integer;
+ Tabs: integer;
+ Tabs_at_startup:integer; //Tabs at Startup fix
+ Sorting: integer;
+ Debug: integer;
+
+ // Graphics
+ Screens: integer;
+ Resolution: integer;
+ Depth: integer;
+ FullScreen: integer;
+ TextureSize: integer;
+ SingWindow: integer;
+ Oscilloscope: integer;
+ Spectrum: integer;
+ Spectrograph: integer;
+ MovieSize: integer;
+ MoviePreview: integer;
+ AspectCorrect: integer;
+
+ // Sound
+ MicBoost: integer;
+ ClickAssist: integer;
+ BeatClick: integer;
+ SavePlayback: integer;
+ Threshold: integer;
+
+ //Song Preview
+ PreviewVolume: integer;
+ PreviewFading: integer;
+
+ // Lyrics
+ LyricsFont: integer;
+ LyricsEffect: integer;
+ Solmization: integer;
+
+ // Themes
+ Theme: integer;
+ SkinNo: integer;
+ Color: integer;
+
+ // Record
+ Card: integer; // not saved in config.ini
+
+ CardList: array of record
+ Name: string;
+ Input: integer;
+ ChannelL: integer;
+ ChannelR: integer;
+ end;
+
+ // Advanced
+ LoadAnimation: integer;
+ EffectSing: integer;
+ ScreenFade: integer;
+ AskbeforeDel: integer;
+ OnSongClick: integer;
+ LineBonus: integer;
+ PartyPopup: integer;
+
+ // Controller
+ Joypad: integer;
+
+ // Soundcards
+ SoundCard: array[0..7, 1..2] of integer;
+
+ // Devices
+ LPT: integer;
+
+ procedure Load;
+ procedure Save;
+ procedure SaveNames;
+ procedure SaveLevel;
+ end;
+
+
+var
+ Ini: TIni;
+ IResolution: array of string;
+ ILanguage: array of string;
+ ITheme: array of string;
+ ISkin: array of string;
+ ICard: array of string;
+ IInput: array of string;
+
+const
+ IPlayers: array[0..4] of string = ('1', '2', '3', '4', '6');
+ IDifficulty: array[0..2] of string = ('Easy', 'Medium', 'Hard');
+ ITabs: array[0..1] of string = ('Off', 'On');
+
+ ISorting: array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
+ sEdition = 0;
+ sGenre = 1;
+ sLanguage = 2;
+ sFolder = 3;
+ sTitle = 4;
+ sArtist = 5;
+ sTitle2 = 6;
+ sArtist2 = 7;
+
+ IDebug: array[0..1] of string = ('Off', 'On');
+
+ IScreens: array[0..1] of string = ('1', '2');
+ IFullScreen: array[0..1] of string = ('Off', 'On');
+ IDepth: array[0..1] of string = ('16 bit', '32 bit');
+ ITextureSize: array[0..2] of string = ('128', '256', '512');
+ ISingWindow: array[0..1] of string = ('Small', 'Big');
+
+ //SingBar Mod
+ IOscilloscope: array[0..2] of string = ('Off', 'Osci', 'Bar');
+ //IOscilloscope: array[0..1] of string = ('Off', 'On');
+
+ ISpectrum: array[0..1] of string = ('Off', 'On');
+ ISpectrograph: array[0..1] of string = ('Off', 'On');
+ IMovieSize: array[0..2] of string = ('Half', 'Full', 'Off');
+ IMoviePreview: array[0..1] of string = ('Off', 'On');
+ IAspectCorrect: array[0..2] of String = ('Stretch', 'Crop', 'LetterBox');
+
+ IMicBoost: array[0..3] of string = ('Off', '+6dB', '+12dB', '+18dB');
+ IClickAssist: array[0..1] of string = ('Off', 'On');
+ IBeatClick: array[0..1] of string = ('Off', 'On');
+ ISavePlayback: array[0..1] of string = ('Off', 'On');
+ IThreshold: array[0..3] of string = ('5%', '10%', '15%', '20%');
+ //Song Preview
+ IPreviewVolume: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
+ IPreviewFading: array[0..5] of string = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');
+
+
+ ILyricsFont: array[0..2] of string = ('Plain', 'OLine1', 'OLine2');
+ ILyricsEffect: array[0..3] of string = ('Simple', 'Zoom', 'Slide', 'Ball');
+ ISolmization: array[0..3] of string = ('Off', 'Euro', 'Jap', 'American');
+
+ IColor: array[0..8] of string = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
+
+ // Advanced
+ ILoadAnimation: array[0..1] of string = ('Off', 'On');
+ IEffectSing: array[0..1] of string = ('Off', 'On');
+ IScreenFade: array [0..1] of String =('Off', 'On');
+ IAskbeforeDel: array[0..1] of string = ('Off', 'On');
+ IOnSongClick: array[0..2] of string = ('Sing', 'Select Players', 'Open Menu');
+ ILineBonus: array[0..2] of string = ('Off', 'At Score', 'At Notes');
+ IPartyPopup: array[0..1] of string = ('Off', 'On');
+
+ IJoypad: array[0..1] of string = ('Off', 'On');
+ ILPT: array[0..2] of string = ('Off', 'LCD', 'Lights');
+
+ IChannel: array[0..6] of string = ('Off', '1', '2', '3', '4', '5', '6');
+
+implementation
+uses UFiles, SDL, ULanguage, USkins, URecord, UCommandLine;
+
+procedure TIni.Load;
+var
+ IniFile: TMemIniFile;
+ ThemeIni: TMemIniFile;
+ Tekst: string;
+ Pet: integer;
+ B: boolean;
+ I, I2, I3: integer;
+ S: string;
+ Modes: PPSDL_Rect;
+ SR: TSearchRec; //Skin List Patch
+ found: boolean;
+
+ function GetFileName (S: String):String;
+ begin
+ //Result := copy (S,0,StrRScan (PChar(S),char('.'))+1);
+ Result := copy (S,0,Pos ('.ini',S)-1);
+ end;
+
+begin
+ GamePath := ExtractFilePath(ParamStr(0));
+
+ if (Params.ConfigFile <> '') then
+ try
+ IniFile := TMemIniFile.Create(Params.ConfigFile);
+ except
+ IniFile := TMemIniFile.Create(GamePath + 'config.ini');
+ end
+ else
+ IniFile := TMemIniFile.Create(GamePath + 'config.ini');
+
+
+ // Name
+ for I := 0 to 11 do
+ Ini.Name[I] := IniFile.ReadString('Name', 'P'+IntToStr(I+1), 'Player'+IntToStr(I+1));
+
+
+ // Templates for Names Mod
+ for I := 0 to 2 do
+ Ini.NameTeam[I] := IniFile.ReadString('NameTeam', 'T'+IntToStr(I+1), 'Team'+IntToStr(I+1));
+ for I := 0 to 11 do
+ Ini.NameTemplate[I] := IniFile.ReadString('NameTemplate', 'Name'+IntToStr(I+1), 'Template'+IntToStr(I+1));
+
+ // Players
+ Tekst := IniFile.ReadString('Game', 'Players', IPlayers[0]);
+ for Pet := 0 to High(IPlayers) do
+ if Tekst = IPlayers[Pet] then Ini.Players := Pet;
+
+ // Difficulty
+ Tekst := IniFile.ReadString('Game', 'Difficulty', 'Easy');
+ for Pet := 0 to High(IDifficulty) do
+ if Tekst = IDifficulty[Pet] then Ini.Difficulty := Pet;
+
+ // Language
+ Tekst := IniFile.ReadString('Game', 'Language', 'English');
+ for Pet := 0 to High(ILanguage) do
+ if Tekst = ILanguage[Pet] then Ini.Language := Pet;
+
+// Language.ChangeLanguage(ILanguage[Ini.Language]);
+
+ // Tabs
+ Tekst := IniFile.ReadString('Game', 'Tabs', ITabs[0]);
+ for Pet := 0 to High(ITabs) do
+ if Tekst = ITabs[Pet] then Ini.Tabs := Pet;
+
+ //Tabs at Startup fix
+ Ini.Tabs_at_startup := Ini.Tabs;
+
+ // Sorting
+ Tekst := IniFile.ReadString('Game', 'Sorting', ISorting[0]);
+ for Pet := 0 to High(ISorting) do
+ if Tekst = ISorting[Pet] then Ini.Sorting := Pet;
+
+ // Debug
+ Tekst := IniFile.ReadString('Game', 'Debug', IDebug[0]);
+ for Pet := 0 to High(IDebug) do
+ if Tekst = IDebug[Pet] then Ini.Debug := Pet;
+
+ //if Ini.Debug = 1 then SongPath := 'E:\UltraStar 03\Songs\';
+
+ // Screens
+ Tekst := IniFile.ReadString('Graphics', 'Screens', IScreens[0]);
+ for Pet := 0 to High(IScreens) do
+ if Tekst = IScreens[Pet] then Ini.Screens := Pet;
+
+ // Resolution
+ SetLength(IResolution, 0);
+ Modes := SDL_ListModes(nil, SDL_OPENGL or SDL_FULLSCREEN); // Check if there are any modes available
+
+ //this should solve the biggest wine problem | THANKS Linnex (11.11.07)
+ // if no modes were set, then fallback to 800x600
+ // as per http://sourceforge.net/forum/message.php?msg_id=4544965
+ // THANKS : linnex at users.sourceforge.net
+
+ if (modes = PPSDL_Rect( 0 ) ) then
+ begin //NO modes available => Fallback to 800x600
+ SetLength(IResolution, 1);
+ IResolution[High(IResolution)] := '800x600';
+ end
+ {Else If (modes = PPSDL_Rect(-1)) then
+ begin
+ //All Resolutions are Available
+ //This may be handled, too
+ // to-do : for future Version
+ end}
+ Else //Add all valid Modes
+ begin
+ I := 0;
+ Repeat
+ SetLength(IResolution, I + 1);
+ IResolution[I] := IntToStr((modes^)^.w) + 'x' + IntToStr((modes^)^.h);
+ Inc(I);
+ Inc(modes);
+ Until (modes^)=nil;
+ end;
+
+ // reverse order
+ for I := 0 to (Length(IResolution) div 2) - 1 do begin
+ S := IResolution[I];
+ IResolution[I] := IResolution[High(IResolution)-I];
+ IResolution[High(IResolution)-I] := S;
+ end;
+
+ Tekst := IniFile.ReadString('Graphics', 'Resolution', '800x600');
+ for Pet := 0 to High(IResolution) do
+ if Tekst = IResolution[Pet] then Ini.Resolution := Pet;
+
+ // FullScreen
+ Tekst := IniFile.ReadString('Graphics', 'FullScreen', 'On');
+ for Pet := 0 to High(IFullScreen) do
+ if Tekst = IFullScreen[Pet] then Ini.FullScreen := Pet;
+
+ // Resolution
+ Tekst := IniFile.ReadString('Graphics', 'Depth', '32 bit');
+ for Pet := 0 to High(IDepth) do
+ if Tekst = IDepth[Pet] then Ini.Depth := Pet;
+
+ // Texture Size
+ Tekst := IniFile.ReadString('Graphics', 'TextureSize', ITextureSize[1]);
+ for Pet := 0 to High(ITextureSize) do
+ if Tekst = ITextureSize[Pet] then Ini.TextureSize := Pet;
+
+ // SingWindow
+ Tekst := IniFile.ReadString('Graphics', 'SingWindow', 'Big');
+ for Pet := 0 to High(ISingWindow) do
+ if Tekst = ISingWindow[Pet] then Ini.SingWindow := Pet;
+
+ // Oscilloscope
+ Tekst := IniFile.ReadString('Graphics', 'Oscilloscope', 'Bar');
+ for Pet := 0 to High(IOscilloscope) do
+ if Tekst = IOscilloscope[Pet] then Ini.Oscilloscope := Pet;
+
+ // Spectrum
+ Tekst := IniFile.ReadString('Graphics', 'Spectrum', 'Off');
+ for Pet := 0 to High(ISpectrum) do
+ if Tekst = ISpectrum[Pet] then Ini.Spectrum := Pet;
+
+ // Spectrograph
+ Tekst := IniFile.ReadString('Graphics', 'Spectrograph', 'Off');
+ for Pet := 0 to High(ISpectrograph) do
+ if Tekst = ISpectrograph[Pet] then Ini.Spectrograph := Pet;
+
+ // MovieSize
+ Tekst := IniFile.ReadString('Graphics', 'MovieSize', IMovieSize[1]);
+ found := false;
+ for Pet := 0 to High(IMovieSize) do
+ begin
+ if Tekst = IMovieSize[Pet] then
+ begin
+ Ini.MovieSize := Pet;
+ found := true;
+ end;
+ end;
+
+ // MoviePreview
+ Tekst := IniFile.ReadString('Graphics', 'MoviePreview', IMoviePreview[1]);
+ for Pet := 0 to High(IMoviePreview) do
+ if Tekst = IMoviePreview[Pet] then Ini.MoviePreview := Pet;
+
+ // AspectCorrection
+ Tekst := IniFile.ReadString('Graphics', 'AspectCorrect', IAspectCorrect[2]);
+ for Pet := 0 to High(IAspectCorrect) do
+ if Tekst = IAspectCorrect[Pet] then Ini.AspectCorrect := Pet;
+
+ // MicBoost
+ Tekst := IniFile.ReadString('Sound', 'MicBoost', 'Off');
+ for Pet := 0 to High(IMicBoost) do
+ if Tekst = IMicBoost[Pet] then Ini.MicBoost := Pet;
+
+ // ClickAssist
+ Tekst := IniFile.ReadString('Sound', 'ClickAssist', 'Off');
+ for Pet := 0 to High(IClickAssist) do
+ if Tekst = IClickAssist[Pet] then Ini.ClickAssist := Pet;
+
+ // BeatClick
+ Tekst := IniFile.ReadString('Sound', 'BeatClick', IBeatClick[0]);
+ for Pet := 0 to High(IBeatClick) do
+ if Tekst = IBeatClick[Pet] then Ini.BeatClick := Pet;
+
+ // SavePlayback
+ Tekst := IniFile.ReadString('Sound', 'SavePlayback', ISavePlayback[0]);
+ for Pet := 0 to High(ISavePlayback) do
+ if Tekst = ISavePlayback[Pet] then Ini.SavePlayback := Pet;
+
+ // Threshold
+ Tekst := IniFile.ReadString('Sound', 'Threshold', IThreshold[2]);
+ for Pet := 0 to High(IThreshold) do
+ if Tekst = IThreshold[Pet] then Ini.Threshold := Pet;
+
+ //Song Preview
+ Tekst := IniFile.ReadString('Sound', 'PreviewVolume', IPreviewVolume[7]);
+ for Pet := 0 to High(IPreviewVolume) do
+ if Tekst = IPreviewVolume[Pet] then Ini.PreviewVolume := Pet;
+
+ Tekst := IniFile.ReadString('Sound', 'PreviewFading', IPreviewFading[1]);
+ for Pet := 0 to High(IPreviewFading) do
+ if Tekst = IPreviewFading[Pet] then Ini.PreviewFading := Pet;
+
+ // Lyrics Font
+ Tekst := IniFile.ReadString('Lyrics', 'LyricsFont', ILyricsFont[1]);
+ for Pet := 0 to High(ILyricsFont) do
+ if Tekst = ILyricsFont[Pet] then Ini.LyricsFont := Pet;
+
+ // Lyrics Effect
+ Tekst := IniFile.ReadString('Lyrics', 'LyricsEffect', ILyricsEffect[1]);
+ for Pet := 0 to High(ILyricsEffect) do
+ if Tekst = ILyricsEffect[Pet] then Ini.LyricsEffect := Pet;
+
+ // Solmization
+ Tekst := IniFile.ReadString('Lyrics', 'Solmization', ISolmization[0]);
+ for Pet := 0 to High(ISolmization) do
+ if Tekst = ISolmization[Pet] then Ini.Solmization := Pet;
+
+ // Theme
+
+ //Theme List Patch
+
+ //I2 Saves the no of the Deluxe (Standard-) Theme
+ I2 := 0;
+ //I counts is the cur. Theme no
+ I := 0;
+
+ SetLength(ITheme, 0);
+ FindFirst('Themes\*.ini',faAnyFile,SR);
+ Repeat
+ //Read Themename from Theme
+ ThemeIni := TMemIniFile.Create(SR.Name);
+ Tekst := UpperCase(ThemeIni.ReadString('Theme','Name',GetFileName(SR.Name)));
+ ThemeIni.Free;
+
+ //if Deluxe Theme then save Themeno to I2
+ if (Tekst = 'DELUXE') then
+ I2 := I;
+
+ //Search for Skins for this Theme
+ for Pet := low(Skin.Skin) to high(Skin.Skin) do
+ begin
+ if UpperCase(Skin.Skin[Pet].Theme) = Tekst then
+ begin
+ SetLength(ITheme, Length(ITheme)+1);
+ ITheme[High(ITheme)] := GetFileName(SR.Name);
+ break;
+ end;
+ end;
+
+ Inc(I);
+ Until FindNext(SR) <> 0;
+ FindClose(SR);
+ //Theme List Patch End }
+
+ //No Theme Found
+ if (Length(ITheme)=0) then
+ begin
+ Log.CriticalError('Could not find any valid Themes.');
+ end;
+
+
+ Tekst := IniFile.ReadString('Themes', 'Theme', ITheme[I2]);
+ Ini.Theme := 0;
+ for Pet := 0 to High(ITheme) do
+ if Uppercase(Tekst) = Uppercase(ITheme[Pet]) then Ini.Theme := Pet;
+
+ // Skin
+ Skin.onThemeChange;
+ Ini.SkinNo := 0;
+
+ Tekst := IniFile.ReadString('Themes', 'Skin', ISkin[0]);
+ for Pet := 0 to High(ISkin) do
+ if Tekst = ISkin[Pet] then Ini.SkinNo := Pet;
+
+ // Color
+ Tekst := IniFile.ReadString('Themes', 'Color', IColor[0]);
+ for Pet := 0 to High(IColor) do
+ if Tekst = IColor[Pet] then Ini.Color := Pet;
+
+ // Record - load ini list
+ SetLength(CardList, 0);
+ I := 1;
+ while (IniFile.ValueExists('Record', 'DeviceName' + IntToStr(I)) = true) do begin
+ //Automatically Delete not Existing Sound Cards
+ S := IniFile.ReadString('Record', 'DeviceName' + IntToStr(I), '');
+ //{
+ B := False;
+ //Look for Soundcard
+ for I2 := 0 to High(Recording.SoundCard) do
+ begin
+ if (S = Trim(Recording.SoundCard[I2].Description)) then
+ begin
+ B := True;
+ Break;
+ end;
+ end;
+
+ if B then
+ begin //}
+ I3 := Length(CardList);
+ SetLength(CardList, I3+1);
+ Ini.CardList[I3].Name := S;
+ Ini.CardList[I3].Input := IniFile.ReadInteger('Record', 'Input' + IntToStr(I), 0);
+ Ini.CardList[I3].ChannelL := IniFile.ReadInteger('Record', 'ChannelL' + IntToStr(I), 0);
+ Ini.CardList[I3].ChannelR := IniFile.ReadInteger('Record', 'ChannelR' + IntToStr(I), 0);
+ end;
+ Inc(I);
+ end;
+
+ // Record - append detected soundcards
+ for I := 0 to High(Recording.SoundCard) do
+ begin
+ B := False;
+ For I2 := 0 to High(CardList) do
+ begin //Search for Card in List
+ if (CardList[I2].Name = Trim(Recording.SoundCard[I].Description)) then
+ begin
+ B := True;
+ Break;
+ end;
+ end;
+
+ //If not in List -> Add
+ If not B then
+ begin
+ I3 := Length(CardList);
+ SetLength(CardList, I3+1);
+ CardList[I3].Name := Trim(Recording.SoundCard[I].Description);
+ CardList[I3].Input := 0;
+ CardList[I3].ChannelL := 0;
+ CardList[I3].ChannelR := 0;
+ // default for new users
+ if (Length(CardList) = 1) then
+ CardList[I].ChannelL := 1;
+ end;
+ end;
+
+ //Advanced Settings
+
+ // LoadAnimation
+ Tekst := IniFile.ReadString('Advanced', 'LoadAnimation', 'On');
+ for Pet := 0 to High(ILoadAnimation) do
+ if Tekst = ILoadAnimation[Pet] then Ini.LoadAnimation := Pet;
+
+ // ScreenFade
+ Tekst := IniFile.ReadString('Advanced', 'ScreenFade', 'On');
+ for Pet := 0 to High(IScreenFade) do
+ if Tekst = IScreenFade[Pet] then Ini.ScreenFade := Pet;
+
+ // EffectSing
+ Tekst := IniFile.ReadString('Advanced', 'EffectSing', 'On');
+ for Pet := 0 to High(IEffectSing) do
+ if Tekst = IEffectSing[Pet] then Ini.EffectSing := Pet;
+
+ // AskbeforeDel
+ Tekst := IniFile.ReadString('Advanced', 'AskbeforeDel', 'On');
+ for Pet := 0 to High(IAskbeforeDel) do
+ if Tekst = IAskbeforeDel[Pet] then Ini.AskbeforeDel := Pet;
+
+ // OnSongClick
+ Tekst := IniFile.ReadString('Advanced', 'OnSongClick', 'Sing');
+ for Pet := 0 to High(IOnSongClick) do
+ if Tekst = IOnSongClick[Pet] then Ini.OnSongClick := Pet;
+
+ // Linebonus
+ Tekst := IniFile.ReadString('Advanced', 'LineBonus', 'At Score');
+ for Pet := 0 to High(ILineBonus) do
+ if Tekst = ILineBonus[Pet] then Ini.LineBonus := Pet;
+
+ // PartyPopup
+ Tekst := IniFile.ReadString('Advanced', 'PartyPopup', 'On');
+ for Pet := 0 to High(IPartyPopup) do
+ if Tekst = IPartyPopup[Pet] then Ini.PartyPopup := Pet;
+
+
+ // Joypad
+ Tekst := IniFile.ReadString('Controller', 'Joypad', IJoypad[0]);
+ for Pet := 0 to High(IJoypad) do
+ if Tekst = IJoypad[Pet] then Ini.Joypad := Pet;
+
+ // LCD
+ Tekst := IniFile.ReadString('Devices', 'LPT', ILPT[0]);
+ for Pet := 0 to High(ILPT) do
+ if Tekst = ILPT[Pet] then Ini.LPT := Pet;
+
+
+ // SongPath
+ if (Params.SongPath <> '') then
+ SongPath := IncludeTrailingPathDelimiter(Params.SongPath)
+ else
+ SongPath := IncludeTrailingPathDelimiter(IniFile.ReadString('Path', 'Songs', SongPath));
+
+ Filename := IniFile.FileName;
+ IniFile.Free;
+ if not found then
+ begin
+ Ini.MovieSize := 1;
+ Save;
+ end;
+end;
+
+procedure TIni.Save;
+var
+ IniFile: TIniFile;
+ Tekst: string;
+ I: Integer;
+ S: String;
+begin
+ //if not (FileExists(GamePath + 'config.ini') and FileIsReadOnly(GamePath + 'config.ini')) then begin
+ if not (FileExists(Filename) and FileIsReadOnly(Filename)) then begin
+
+ IniFile := TIniFile.Create(Filename);
+
+ // Players
+ Tekst := IPlayers[Ini.Players];
+ IniFile.WriteString('Game', 'Players', Tekst);
+
+ // Difficulty
+ Tekst := IDifficulty[Ini.Difficulty];
+ IniFile.WriteString('Game', 'Difficulty', Tekst);
+
+ // Language
+ Tekst := ILanguage[Ini.Language];
+ IniFile.WriteString('Game', 'Language', Tekst);
+
+ // Tabs
+ Tekst := ITabs[Ini.Tabs];
+ IniFile.WriteString('Game', 'Tabs', Tekst);
+
+ // Sorting
+ Tekst := ISorting[Ini.Sorting];
+ IniFile.WriteString('Game', 'Sorting', Tekst);
+
+ // Debug
+ Tekst := IDebug[Ini.Debug];
+ IniFile.WriteString('Game', 'Debug', Tekst);
+
+ // Screens
+ Tekst := IScreens[Ini.Screens];
+ IniFile.WriteString('Graphics', 'Screens', Tekst);
+
+ // FullScreen
+ Tekst := IFullScreen[Ini.FullScreen];
+ IniFile.WriteString('Graphics', 'FullScreen', Tekst);
+
+ // Resolution
+ Tekst := IResolution[Ini.Resolution];
+ IniFile.WriteString('Graphics', 'Resolution', Tekst);
+
+ // Depth
+ Tekst := IDepth[Ini.Depth];
+ IniFile.WriteString('Graphics', 'Depth', Tekst);
+
+ // Resolution
+ Tekst := ITextureSize[Ini.TextureSize];
+ IniFile.WriteString('Graphics', 'TextureSize', Tekst);
+
+ // Sing Window
+ Tekst := ISingWindow[Ini.SingWindow];
+ IniFile.WriteString('Graphics', 'SingWindow', Tekst);
+
+ // Oscilloscope
+ Tekst := IOscilloscope[Ini.Oscilloscope];
+ IniFile.WriteString('Graphics', 'Oscilloscope', Tekst);
+
+ // Spectrum
+ Tekst := ISpectrum[Ini.Spectrum];
+ IniFile.WriteString('Graphics', 'Spectrum', Tekst);
+
+ // Spectrograph
+ Tekst := ISpectrograph[Ini.Spectrograph];
+ IniFile.WriteString('Graphics', 'Spectrograph', Tekst);
+
+ // Movie Size
+ Tekst := IMovieSize[Ini.MovieSize];
+ IniFile.WriteString('Graphics', 'MovieSize', Tekst);
+
+ // Movie Size
+ Tekst := IMoviePreview[Ini.MoviePreview];
+ IniFile.WriteString('Graphics', 'MoviePreview', Tekst);
+
+ // AspectCorrect
+ Tekst := IAspectCorrect[Ini.AspectCorrect];
+ IniFile.WriteString('Graphics', 'AspectCorrect', Tekst);
+
+ // MicBoost
+ Tekst := IMicBoost[Ini.MicBoost];
+ IniFile.WriteString('Sound', 'MicBoost', Tekst);
+
+ // ClickAssist
+ Tekst := IClickAssist[Ini.ClickAssist];
+ IniFile.WriteString('Sound', 'ClickAssist', Tekst);
+
+ // BeatClick
+ Tekst := IBeatClick[Ini.BeatClick];
+ IniFile.WriteString('Sound', 'BeatClick', Tekst);
+
+ // Threshold
+ Tekst := IThreshold[Ini.Threshold];
+ IniFile.WriteString('Sound', 'Threshold', Tekst);
+
+ // Song Preview
+ Tekst := IPreviewVolume[Ini.PreviewVolume];
+ IniFile.WriteString('Sound', 'PreviewVolume', Tekst);
+
+ Tekst := IPreviewFading[Ini.PreviewFading];
+ IniFile.WriteString('Sound', 'PreviewFading', Tekst);
+
+ // SavePlayback
+ Tekst := ISavePlayback[Ini.SavePlayback];
+ IniFile.WriteString('Sound', 'SavePlayback', Tekst);
+
+ // Lyrics Font
+ Tekst := ILyricsFont[Ini.LyricsFont];
+ IniFile.WriteString('Lyrics', 'LyricsFont', Tekst);
+
+ // Lyrics Effect
+ Tekst := ILyricsEffect[Ini.LyricsEffect];
+ IniFile.WriteString('Lyrics', 'LyricsEffect', Tekst);
+
+ // Solmization
+ Tekst := ISolmization[Ini.Solmization];
+ IniFile.WriteString('Lyrics', 'Solmization', Tekst);
+
+ // Theme
+ Tekst := ITheme[Ini.Theme];
+ IniFile.WriteString('Themes', 'Theme', Tekst);
+
+ // Skin
+ Tekst := ISkin[Ini.SkinNo];
+ IniFile.WriteString('Themes', 'Skin', Tekst);
+
+ // Color
+ Tekst := IColor[Ini.Color];
+ IniFile.WriteString('Themes', 'Color', Tekst);
+
+ // Record
+ for I := 0 to High(CardList) do begin
+ S := IntToStr(I+1);
+
+ Tekst := CardList[I].Name;
+ IniFile.WriteString('Record', 'DeviceName' + S, Tekst);
+
+ Tekst := IntToStr(CardList[I].Input);
+ IniFile.WriteString('Record', 'Input' + S, Tekst);
+
+ Tekst := IntToStr(CardList[I].ChannelL);
+ IniFile.WriteString('Record', 'ChannelL' + S, Tekst);
+
+ Tekst := IntToStr(CardList[I].ChannelR);
+ IniFile.WriteString('Record', 'ChannelR' + S, Tekst);
+ end;
+
+ //Log.LogError(InttoStr(Length(CardList)) + ' Cards Saved');
+
+ //Advanced Settings
+
+ //LoadAnimation
+ Tekst := ILoadAnimation[Ini.LoadAnimation];
+ IniFile.WriteString('Advanced', 'LoadAnimation', Tekst);
+
+ //EffectSing
+ Tekst := IEffectSing[Ini.EffectSing];
+ IniFile.WriteString('Advanced', 'EffectSing', Tekst);
+
+ //ScreenFade
+ Tekst := IScreenFade[Ini.ScreenFade];
+ IniFile.WriteString('Advanced', 'ScreenFade', Tekst);
+
+ //AskbeforeDel
+ Tekst := IAskbeforeDel[Ini.AskbeforeDel];
+ IniFile.WriteString('Advanced', 'AskbeforeDel', Tekst);
+
+ //OnSongClick
+ Tekst := IOnSongClick[Ini.OnSongClick];
+ IniFile.WriteString('Advanced', 'OnSongClick', Tekst);
+
+ //Line Bonus
+ Tekst := ILineBonus[Ini.LineBonus];
+ IniFile.WriteString('Advanced', 'LineBonus', Tekst);
+
+ //Party Popup
+ Tekst := IPartyPopup[Ini.PartyPopup];
+ IniFile.WriteString('Advanced', 'PartyPopup', Tekst);
+
+ // Joypad
+ Tekst := IJoypad[Ini.Joypad];
+ IniFile.WriteString('Controller', 'Joypad', Tekst);
+
+ IniFile.Free;
+ end;
+end;
+
+procedure TIni.SaveNames;
+var
+ IniFile: TIniFile;
+ I: integer;
+begin
+ //if not FileIsReadOnly(GamePath + 'config.ini') then begin
+ //IniFile := TIniFile.Create(GamePath + 'config.ini');
+ if not FileIsReadOnly(Filename) then begin
+ IniFile := TIniFile.Create(Filename);
+
+ //Name
+ // Templates for Names Mod
+ for I := 1 to 12 do
+ IniFile.WriteString('Name', 'P' + IntToStr(I), Ini.Name[I-1]);
+ for I := 1 to 3 do
+ IniFile.WriteString('NameTeam', 'T' + IntToStr(I), Ini.NameTeam[I-1]);
+ for I := 1 to 12 do
+ IniFile.WriteString('NameTemplate', 'Name' + IntToStr(I), Ini.NameTemplate[I-1]);
+
+ IniFile.Free;
+ end;
+end;
+
+procedure TIni.SaveLevel;
+var
+ IniFile: TIniFile;
+ I: integer;
+begin
+ //if not FileIsReadOnly(GamePath + 'config.ini') then begin
+ //IniFile := TIniFile.Create(GamePath + 'config.ini');
+ if not FileIsReadOnly(Filename) then begin
+ IniFile := TIniFile.Create(Filename);
+
+ // Difficulty
+ IniFile.WriteString('Game', 'Difficulty', IDifficulty[Ini.Difficulty]);
+
+ IniFile.Free;
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/UJoystick.pas b/Game/Code/Classes/UJoystick.pas
new file mode 100644
index 00000000..b0c7b8cc
--- /dev/null
+++ b/Game/Code/Classes/UJoystick.pas
@@ -0,0 +1,273 @@
+unit UJoystick;
+
+interface
+
+uses SDL;
+
+type
+ TJoyButton = record
+ State: integer;
+ Enabled: boolean;
+ Type_: byte;
+ Sym: cardinal;
+ end;
+
+ TJoyHatState = record
+ State: Boolean;
+ LastTick: Cardinal;
+ Enabled: boolean;
+ Type_: byte;
+ Sym: cardinal;
+ end;
+
+ TJoyUnit = record
+ Button: array[0..15] of TJoyButton;
+ HatState: Array[0..3] of TJoyHatState;
+ end;
+
+ TJoy = class
+ constructor Create;
+ procedure Update;
+ end;
+
+var
+ Joy: TJoy;
+ JoyUnit: TJoyUnit;
+ SDL_Joy: PSDL_Joystick;
+ JoyEvent: TSDL_Event;
+
+implementation
+
+uses SysUtils, Windows, ULog;
+
+constructor TJoy.Create;
+var
+ B, N: integer;
+begin
+ //Old Corvus5 Method
+ {// joystick support
+ SDL_JoystickEventState(SDL_IGNORE);
+ SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+ if SDL_NumJoysticks <> 1 then beep;
+
+ SDL_Joy := SDL_JoystickOpen(0);
+ if SDL_Joy = nil then beep;
+
+ if SDL_JoystickNumButtons(SDL_Joy) <> 16 then beep;
+
+// SDL_JoystickEventState(SDL_ENABLE);
+ // Events don't work - thay hang the whole application with SDL_JoystickEventState(SDL_ENABLE)
+
+ // clear states
+ for B := 0 to 15 do
+ JoyUnit.Button[B].State := 1;
+
+ // mapping
+ JoyUnit.Button[1].Enabled := true;
+ JoyUnit.Button[1].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[1].Sym := SDLK_RETURN;
+ JoyUnit.Button[2].Enabled := true;
+ JoyUnit.Button[2].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[2].Sym := SDLK_ESCAPE;
+
+ JoyUnit.Button[12].Enabled := true;
+ JoyUnit.Button[12].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[12].Sym := SDLK_LEFT;
+ JoyUnit.Button[13].Enabled := true;
+ JoyUnit.Button[13].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[13].Sym := SDLK_DOWN;
+ JoyUnit.Button[14].Enabled := true;
+ JoyUnit.Button[14].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[14].Sym := SDLK_RIGHT;
+ JoyUnit.Button[15].Enabled := true;
+ JoyUnit.Button[15].Type_ := SDL_KEYDOWN;
+ JoyUnit.Button[15].Sym := SDLK_UP;
+ }
+ //New Sarutas method
+ SDL_JoystickEventState(SDL_IGNORE);
+ SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+ if SDL_NumJoysticks < 1 then
+ begin
+ Log.LogError('No Joystick found');
+ exit;
+ end;
+
+
+ SDL_Joy := SDL_JoystickOpen(0);
+ if SDL_Joy = nil then
+ begin
+ Log.LogError('Could not Init Joystick');
+ exit;
+ end;
+ N := SDL_JoystickNumButtons(SDL_Joy);
+ //if N < 6 then beep;
+
+ for B := 0 to 5 do begin
+ JoyUnit.Button[B].Enabled := true;
+ JoyUnit.Button[B].State := 1;
+ JoyUnit.Button[B].Type_ := SDL_KEYDOWN;
+ end;
+
+ JoyUnit.Button[0].Sym := SDLK_Return;
+ JoyUnit.Button[1].Sym := SDLK_Escape;
+ JoyUnit.Button[2].Sym := SDLK_M;
+ JoyUnit.Button[3].Sym := SDLK_R;
+
+ JoyUnit.Button[4].Sym := SDLK_RETURN;
+ JoyUnit.Button[5].Sym := SDLK_ESCAPE;
+
+ //Set HatState
+ for B := 0 to 3 do begin
+ JoyUnit.HatState[B].Enabled := true;
+ JoyUnit.HatState[B].State := False;
+ JoyUnit.HatState[B].Type_ := SDL_KEYDOWN;
+ end;
+
+ JoyUnit.HatState[0].Sym := SDLK_UP;
+ JoyUnit.HatState[1].Sym := SDLK_RIGHT;
+ JoyUnit.HatState[2].Sym := SDLK_DOWN;
+ JoyUnit.HatState[3].Sym := SDLK_LEFT;
+end;
+
+procedure TJoy.Update;
+var
+ B: integer;
+ State: UInt8;
+ Tick: Cardinal;
+ Axes: Smallint;
+begin
+ SDL_JoystickUpdate;
+
+ //Manage Buttons
+ for B := 0 to 15 do begin
+ if (JoyUnit.Button[B].Enabled) and (JoyUnit.Button[B].State <> SDL_JoystickGetButton(SDL_Joy, B)) and (JoyUnit.Button[B].State = 0) then begin
+ JoyEvent.type_ := JoyUnit.Button[B].Type_;
+ JoyEvent.key.keysym.sym := JoyUnit.Button[B].Sym;
+ SDL_PushEvent(@JoyEvent);
+ end;
+ end;
+
+
+ for B := 0 to 15 do begin
+ JoyUnit.Button[B].State := SDL_JoystickGetButton(SDL_Joy, B);
+ end;
+
+ //Get Tick
+ Tick := Gettickcount;
+
+ //Get CoolieHat
+ if (SDL_JoystickNumHats(SDL_Joy)>=1) then
+ State := SDL_JoystickGetHat(SDL_Joy, 0)
+ else
+ State := 0;
+
+ //Get Axis
+ if (SDL_JoystickNumAxes(SDL_Joy)>=2) then
+ begin
+ //Down - Up (X- Axis)
+ Axes := SDL_JoystickGetAxis(SDL_Joy, 1);
+ If Axes >= 15000 then
+ State := State or SDL_HAT_Down
+ Else If Axes <= -15000 then
+ State := State or SDL_HAT_UP;
+
+ //Left - Right (Y- Axis)
+ Axes := SDL_JoystickGetAxis(SDL_Joy, 0);
+ If Axes >= 15000 then
+ State := State or SDL_HAT_Right
+ Else If Axes <= -15000 then
+ State := State or SDL_HAT_Left;
+ end;
+
+ //Manage Hat and joystick Events
+ if (SDL_JoystickNumHats(SDL_Joy)>=1) OR (SDL_JoystickNumAxes(SDL_Joy)>=2) then
+ begin
+
+ //Up Button
+ If (JoyUnit.HatState[0].Enabled) and ((SDL_HAT_UP AND State) = SDL_HAT_UP) then
+ begin //IF Button is newly Pressed or if he is Pressed longer than 500 msecs
+ if (JoyUnit.HatState[0].State = False) OR (JoyUnit.HatState[0].Lasttick < Tick) then
+ begin
+ //Set Tick and State
+ if JoyUnit.HatState[0].State then
+ JoyUnit.HatState[0].Lasttick := Tick + 200
+ else
+ JoyUnit.HatState[0].Lasttick := Tick + 500;
+
+ JoyUnit.HatState[0].State := True;
+
+ JoyEvent.type_ := JoyUnit.HatState[0].Type_;
+ JoyEvent.key.keysym.sym := JoyUnit.HatState[0].Sym;
+ SDL_PushEvent(@JoyEvent);
+ end;
+ end
+ else
+ JoyUnit.HatState[0].State := False;
+
+ //Right Button
+ If (JoyUnit.HatState[1].Enabled) and ((SDL_HAT_RIGHT AND State) = SDL_HAT_RIGHT) then
+ begin //IF Button is newly Pressed or if he is Pressed longer than 500 msecs
+ if (JoyUnit.HatState[1].State = False) OR (JoyUnit.HatState[1].Lasttick < Tick) then
+ begin
+ //Set Tick and State
+ if JoyUnit.HatState[1].State then
+ JoyUnit.HatState[1].Lasttick := Tick + 200
+ else
+ JoyUnit.HatState[1].Lasttick := Tick + 500;
+
+ JoyUnit.HatState[1].State := True;
+
+ JoyEvent.type_ := JoyUnit.HatState[1].Type_;
+ JoyEvent.key.keysym.sym := JoyUnit.HatState[1].Sym;
+ SDL_PushEvent(@JoyEvent);
+ end;
+ end
+ else
+ JoyUnit.HatState[1].State := False;
+
+ //Down button
+ If (JoyUnit.HatState[2].Enabled) and ((SDL_HAT_DOWN AND State) = SDL_HAT_DOWN) then
+ begin //IF Button is newly Pressed or if he is Pressed longer than 230 msecs
+ if (JoyUnit.HatState[2].State = False) OR (JoyUnit.HatState[2].Lasttick < Tick) then
+ begin
+ //Set Tick and State
+ if JoyUnit.HatState[2].State then
+ JoyUnit.HatState[2].Lasttick := Tick + 200
+ else
+ JoyUnit.HatState[2].Lasttick := Tick + 500;
+
+ JoyUnit.HatState[2].State := True;
+
+ JoyEvent.type_ := JoyUnit.HatState[2].Type_;
+ JoyEvent.key.keysym.sym := JoyUnit.HatState[2].Sym;
+ SDL_PushEvent(@JoyEvent);
+ end;
+ end
+ else
+ JoyUnit.HatState[2].State := False;
+
+ //Left Button
+ If (JoyUnit.HatState[3].Enabled) and ((SDL_HAT_LEFT AND State) = SDL_HAT_LEFT) then
+ begin //IF Button is newly Pressed or if he is Pressed longer than 230 msecs
+ if (JoyUnit.HatState[3].State = False) OR (JoyUnit.HatState[3].Lasttick < Tick) then
+ begin
+ //Set Tick and State
+ if JoyUnit.HatState[3].State then
+ JoyUnit.HatState[3].Lasttick := Tick + 200
+ else
+ JoyUnit.HatState[3].Lasttick := Tick + 500;
+
+ JoyUnit.HatState[3].State := True;
+
+ JoyEvent.type_ := JoyUnit.HatState[3].Type_;
+ JoyEvent.key.keysym.sym := JoyUnit.HatState[3].Sym;
+ SDL_PushEvent(@JoyEvent);
+ end;
+ end
+ else
+ JoyUnit.HatState[3].State := False;
+ end;
+
+end;
+
+end.
diff --git a/Game/Code/Classes/ULCD.pas b/Game/Code/Classes/ULCD.pas
new file mode 100644
index 00000000..abdf3584
--- /dev/null
+++ b/Game/Code/Classes/ULCD.pas
@@ -0,0 +1,289 @@
+unit ULCD;
+
+interface
+
+type
+ TLCD = class
+ private
+ Enabled: boolean;
+ Text: array[1..6] of string;
+ StartPos: integer;
+ LineBR: integer;
+ Position: integer;
+ procedure WriteCommand(B: byte);
+ procedure WriteData(B: byte);
+ procedure WriteString(S: string);
+ public
+ HalfInterface: boolean;
+ constructor Create;
+ procedure Enable;
+ procedure Clear;
+ procedure WriteText(Line: integer; S: string);
+ procedure MoveCursor(Line, Pos: integer);
+ procedure ShowCursor;
+ procedure HideCursor;
+
+ // for 2x16
+ procedure AddTextBR(S: string);
+ procedure MoveCursorBR(Pos: integer);
+ procedure ScrollUpBR;
+ procedure AddTextArray(Line:integer; S: string);
+ end;
+
+var
+ LCD: TLCD;
+
+const
+ Data = $378; // domyœlny adres portu
+ Status = Data + 1;
+ Control = Data + 2;
+
+implementation
+
+uses
+ SysUtils,
+ zlportio,
+ UTime;
+
+procedure TLCD.WriteCommand(B: Byte);
+// Wysylanie komend sterujacych
+begin
+ if not HalfInterface then begin
+ zlioportwrite(Control, 0, $02);
+ zlioportwrite(Data, 0, B);
+ zlioportwrite(Control, 0, $03);
+ end else begin
+ zlioportwrite(Control, 0, $02);
+ zlioportwrite(Data, 0, B and $F0);
+ zlioportwrite(Control, 0, $03);
+
+ TimeSleep(0.1);
+
+ zlioportwrite(Control, 0, $02);
+ zlioportwrite(Data, 0, (B * 16) and $F0);
+ zlioportwrite(Control, 0, $03);
+ end;
+
+ if (B=1) or (B=2) then
+ Sleep(2)
+ else
+ TimeSleep(0.1);
+end;
+
+procedure TLCD.WriteData(B: Byte);
+// Wysylanie danych
+begin
+ if not HalfInterface then begin
+ zlioportwrite(Control, 0, $06);
+ zlioportwrite(Data, 0, B);
+ zlioportwrite(Control, 0, $07);
+ end else begin
+ zlioportwrite(Control, 0, $06);
+ zlioportwrite(Data, 0, B and $F0);
+ zlioportwrite(Control, 0, $07);
+
+ TimeSleep(0.1);
+
+ zlioportwrite(Control, 0, $06);
+ zlioportwrite(Data, 0, (B * 16) and $F0);
+ zlioportwrite(Control, 0, $07);
+ end;
+
+ TimeSleep(0.1);
+ Inc(Position);
+end;
+
+procedure TLCD.WriteString(S: string);
+// Wysylanie slow
+var
+ I: integer;
+begin
+ for I := 1 to Length(S) do
+ WriteData(Ord(S[I]));
+end;
+
+constructor TLCD.Create;
+begin
+//
+end;
+
+procedure TLCD.Enable;
+var
+ A: byte;
+ B: byte;
+begin
+ Enabled := true;
+ if not HalfInterface then
+ WriteCommand($38)
+ else begin
+ WriteCommand($33);
+ WriteCommand($32);
+ WriteCommand($28);
+ end;
+
+// WriteCommand($06);
+// WriteCommand($0C);
+// sleep(10);
+end;
+
+procedure TLCD.Clear;
+begin
+ if Enabled then begin
+ WriteCommand(1);
+ WriteCommand(2);
+ Text[1] := '';
+ Text[2] := '';
+ Text[3] := '';
+ Text[4] := '';
+ Text[5] := '';
+ Text[6] := '';
+ StartPos := 1;
+ LineBR := 1;
+ end;
+end;
+
+procedure TLCD.WriteText(Line: integer; S: string);
+begin
+ if Enabled then begin
+ if Line <= 2 then begin
+ MoveCursor(Line, 1);
+ WriteString(S);
+ end;
+
+ Text[Line] := '';
+ AddTextArray(Line, S);
+ end;
+end;
+
+procedure TLCD.MoveCursor(Line, Pos: integer);
+var
+ I: integer;
+begin
+ if Enabled then begin
+ Pos := Pos + (Line-1) * 40;
+
+ if Position > Pos then begin
+ WriteCommand(2);
+ for I := 1 to Pos-1 do
+ WriteCommand(20);
+ end;
+
+ if Position < Pos then
+ for I := 1 to Pos - Position do
+ WriteCommand(20);
+
+ Position := Pos;
+ end;
+end;
+
+procedure TLCD.ShowCursor;
+begin
+ if Enabled then begin
+ WriteCommand(14);
+ end;
+end;
+
+procedure TLCD.HideCursor;
+begin
+ if Enabled then begin
+ WriteCommand(12);
+ end;
+end;
+
+procedure TLCD.AddTextBR(S: string);
+var
+ Word: string;
+ W: integer;
+ P: integer;
+ L: integer;
+begin
+ if Enabled then begin
+ if LineBR <= 6 then begin
+ L := LineBR;
+ P := Pos(' ', S);
+
+ if L <= 2 then
+ MoveCursor(L, 1);
+
+ while (L <= 6) and (P > 0) do begin
+ Word := Copy(S, 1, P);
+ if (Length(Text[L]) + Length(Word)-1) > 16 then begin
+ L := L + 1;
+ if L <= 2 then
+ MoveCursor(L, 1);
+ end;
+
+ if L <= 6 then begin
+ if L <= 2 then
+ WriteString(Word);
+ AddTextArray(L, Word);
+ end;
+
+ Delete(S, 1, P);
+ P := Pos(' ', S)
+ end;
+
+ LineBR := L + 1;
+ end;
+ end;
+end;
+
+procedure TLCD.MoveCursorBR(Pos: integer);
+var
+ I: integer;
+ L: integer;
+begin
+ if Enabled then begin
+ Pos := Pos - (StartPos-1);
+ if Pos <= Length(Text[1]) then
+ MoveCursor(1, Pos);
+
+ if Pos > Length(Text[1]) then begin
+ // bez zawijania
+// Pos := Pos - Length(Text[1]);
+// MoveCursor(2, Pos);
+
+ // z zawijaniem
+ Pos := Pos - Length(Text[1]);
+ ScrollUpBR;
+ MoveCursor(1, Pos);
+ end;
+ end;
+end;
+
+procedure TLCD.ScrollUpBR;
+var
+ T: array[1..5] of string;
+ SP: integer;
+ LBR: integer;
+begin
+ if Enabled then begin
+ T[1] := Text[2];
+ T[2] := Text[3];
+ T[3] := Text[4];
+ T[4] := Text[5];
+ T[5] := Text[6];
+ SP := StartPos + Length(Text[1]);
+ LBR := LineBR;
+
+ Clear;
+
+ StartPos := SP;
+ WriteText(1, T[1]);
+ WriteText(2, T[2]);
+ WriteText(3, T[3]);
+ WriteText(4, T[4]);
+ WriteText(5, T[5]);
+ LineBR := LBR-1;
+ end;
+end;
+
+procedure TLCD.AddTextArray(Line: integer; S: string);
+begin
+ if Enabled then begin
+ Text[Line] := Text[Line] + S;
+ end;
+end;
+
+end.
+
diff --git a/Game/Code/Classes/ULanguage.pas b/Game/Code/Classes/ULanguage.pas
new file mode 100644
index 00000000..10fa1387
--- /dev/null
+++ b/Game/Code/Classes/ULanguage.pas
@@ -0,0 +1,222 @@
+unit ULanguage;
+
+interface
+
+type
+ TLanguageEntry = record
+ ID: string;
+ Text: string;
+ end;
+
+ TLanguageList = record
+ Name: string;
+ {FileName: string; }
+ end;
+
+ TLanguage = class
+ public
+ Entry: array of TLanguageEntry; //Entrys of Chosen Language
+ SEntry: array of TLanguageEntry; //Entrys of Standard Language
+ CEntry: array of TLanguageEntry; //Constant Entrys e.g. Version
+ Implode_Glue1, Implode_Glue2: String;
+ //public
+ List: array of TLanguageList;
+
+ constructor Create;
+ procedure LoadList;
+ function Translate(Text: String): String;
+ procedure ChangeLanguage(Language: String);
+ procedure AddConst(ID, Text: String);
+ procedure ChangeConst(ID, Text: String);
+ function Implode(Pieces: Array of String): String;
+ end;
+
+var
+ Language: TLanguage;
+
+implementation
+
+uses UFiles, UIni, IniFiles, Classes, SysUtils, Windows, ULog;
+
+//----------
+//Create - Construct Class then LoadList + Standard Language + Set Standard Implode Glues
+//----------
+constructor TLanguage.Create;
+var
+ I, J: Integer;
+begin
+ LoadList;
+
+ //Set Implode Glues for Backward Compatibility
+ Implode_Glue1 := ', ';
+ Implode_Glue2 := ' and ';
+
+ if (Length(List) = 0) then //No Language Files Loaded -> Abort Loading
+ Log.CriticalError('Could not load any Language File');
+
+ //Standard Language (If a Language File is Incomplete)
+ //Then use English Language
+ for I := 0 to high(List) do //Search for English Language
+ begin
+ //English Language Found -> Load
+ if Uppercase(List[I].Name) = 'ENGLISH' then
+ begin
+ ChangeLanguage('English');
+
+ SetLength(SEntry, Length(Entry));
+ for J := low(Entry) to high(Entry) do
+ SEntry[J] := Entry[J];
+
+ SetLength(Entry, 0);
+
+ Break;
+ end;
+
+ if (I = high(List)) then
+ Log.LogError('English Languagefile missing! No standard Translation loaded');
+ end;
+ //Standard Language END
+
+end;
+
+//----------
+//LoadList - Parse the Language Dir searching Translations
+//----------
+procedure TLanguage.LoadList;
+var
+ SR: TSearchRec; // for parsing directory
+begin
+ SetLength(List, 0);
+ SetLength(ILanguage, 0);
+
+ if FindFirst(LanguagesPath + '*.ini', 0, SR) = 0 then begin
+ repeat
+ SetLength(List, Length(List)+1);
+ SetLength(ILanguage, Length(ILanguage)+1);
+ SR.Name := ChangeFileExt(SR.Name, '');
+
+ List[High(List)].Name := SR.Name;
+ ILanguage[High(ILanguage)] := SR.Name;
+
+ until FindNext(SR) <> 0;
+ SysUtils.FindClose(SR);
+ end; // if FindFirst
+end;
+
+//----------
+//ChangeLanguage - Load the specified LanguageFile
+//----------
+procedure TLanguage.ChangeLanguage(Language: String);
+var
+ IniFile: TIniFile;
+ E: integer; // entry
+ S: TStringList;
+begin
+ SetLength(Entry, 0);
+ IniFile := TIniFile.Create(LanguagesPath + Language + '.ini');
+ S := TStringList.Create;
+
+ IniFile.ReadSectionValues('Text', S);
+ SetLength(Entry, S.Count);
+ for E := 0 to high(Entry) do
+ begin
+ if S.Names[E] = 'IMPLODE_GLUE1' then
+ Implode_Glue1 := S.ValueFromIndex[E]+ ' '
+ else if S.Names[E] = 'IMPLODE_GLUE2' then
+ Implode_Glue2 := ' ' + S.ValueFromIndex[E] + ' ';
+
+ Entry[E].ID := S.Names[E];
+ Entry[E].Text := S.ValueFromIndex[E];
+ end;
+
+ S.Free;
+ IniFile.Free;
+end;
+
+//----------
+//Translate - Translate the Text
+//----------
+Function TLanguage.Translate(Text: String): String;
+var
+ E: integer; // entry
+begin
+ Result := Text;
+ Text := Uppercase(Result);
+
+ //Const Mod
+ for E := 0 to high(CEntry) do
+ if Text = CEntry[E].ID then
+ begin
+ Result := CEntry[E].Text;
+ exit;
+ end;
+ //Const Mod End
+
+ for E := 0 to high(Entry) do
+ if Text = Entry[E].ID then
+ begin
+ Result := Entry[E].Text;
+ exit;
+ end;
+
+ //Standard Language (If a Language File is Incomplete)
+ //Then use Standard Language
+ for E := low(SEntry) to high(SEntry) do
+ if Text = SEntry[E].ID then
+ begin
+ Result := SEntry[E].Text;
+ Break;
+ end;
+ //Standard Language END
+end;
+
+//----------
+//AddConst - Add a Constant ID that will be Translated but not Loaded from the LanguageFile
+//----------
+procedure TLanguage.AddConst (ID, Text: String);
+begin
+ SetLength (CEntry, Length(CEntry) + 1);
+ CEntry[high(CEntry)].ID := ID;
+ CEntry[high(CEntry)].Text := Text;
+end;
+
+//----------
+//ChangeConst - Change a Constant Value by ID
+//----------
+procedure TLanguage.ChangeConst(ID, Text: String);
+var
+ I: Integer;
+begin
+ for I := 0 to high(CEntry) do
+ begin
+ if CEntry[I].ID = ID then
+ begin
+ CEntry[I].Text := Text;
+ Break;
+ end;
+ end;
+end;
+
+//----------
+//Implode - Connect an Array of Strings with ' and ' or ', ' to one String
+//----------
+function TLanguage.Implode(Pieces: Array of String): String;
+var
+ I: Integer;
+begin
+ Result := '';
+ //Go through Pieces
+ for I := low(Pieces) to high(Pieces) do
+ begin
+ //Add Value
+ Result := Result + Pieces[I];
+
+ //Add Glue
+ if (I < high(Pieces) - 1) then
+ Result := Result + Implode_Glue1
+ else if (I < high(Pieces)) then
+ Result := Result + Implode_Glue2;
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/ULight.pas b/Game/Code/Classes/ULight.pas
new file mode 100644
index 00000000..967d2ea1
--- /dev/null
+++ b/Game/Code/Classes/ULight.pas
@@ -0,0 +1,116 @@
+unit ULight;
+interface
+
+type
+ TLight = class
+ private
+ Enabled: boolean;
+ Light: array[0..7] of boolean;
+ LightTime: array[0..7] of real; // time to stop, need to call update to change state
+ LastTime: real;
+ public
+ constructor Create;
+ procedure Enable;
+ procedure SetState(State: integer);
+ procedure AutoSetState;
+ procedure TurnOn;
+ procedure TurnOff;
+ procedure LightOne(Number: integer; Time: real);
+ procedure Refresh;
+ end;
+
+var
+ Light: TLight;
+
+const
+ Data = $378; // default port address
+ Status = Data + 1;
+ Control = Data + 2;
+
+implementation
+
+uses
+ SysUtils, zlportio, UTime;
+
+constructor TLight.Create;
+begin
+ Enabled := false;
+end;
+
+procedure TLight.Enable;
+begin
+ Enabled := true;
+ LastTime := GetTime;
+end;
+
+procedure TLight.SetState(State: integer);
+begin
+ if Enabled then
+ PortWriteB($378, State);
+end;
+
+procedure TLight.AutoSetState;
+var
+ State: integer;
+begin
+ if Enabled then begin
+ State := 0;
+ if Light[0] then State := State + 2;
+ if Light[1] then State := State + 1;
+ // etc
+ SetState(State);
+ end;
+end;
+
+procedure TLight.TurnOn;
+begin
+ if Enabled then
+ SetState(3);
+end;
+
+procedure TLight.TurnOff;
+begin
+ if Enabled then
+ SetState(0);
+end;
+
+procedure TLight.LightOne(Number: integer; Time: real);
+begin
+ if Enabled then begin
+ if Light[Number] = false then begin
+ Light[Number] := true;
+ AutoSetState;
+ end;
+
+ LightTime[Number] := GetTime + Time/1000; // [s]
+ end;
+end;
+
+procedure TLight.Refresh;
+var
+ Time: real;
+ TimeSkip: real;
+ L: integer;
+begin
+ if Enabled then begin
+ Time := GetTime;
+ TimeSkip := Time - LastTime;
+ for L := 0 to 7 do begin
+ if Light[L] = true then begin
+ if LightTime[L] > Time then begin
+ // jest jeszcze zapas - bez zmian
+ //LightTime[L] := LightTime[L] - TimeSkip;
+ end else begin
+ // czas minal
+ Light[L] := false;
+ end;
+ end;
+ end;
+ LastTime := Time;
+ AutoSetState;
+ end;
+end;
+
+end.
+
+
diff --git a/Game/Code/Classes/ULog.pas b/Game/Code/Classes/ULog.pas
new file mode 100644
index 00000000..9d20d2f1
--- /dev/null
+++ b/Game/Code/Classes/ULog.pas
@@ -0,0 +1,227 @@
+unit ULog;
+
+interface
+
+uses Classes;
+
+type
+ TLog = class
+ BenchmarkTimeStart: array[0..7] of real;
+ BenchmarkTimeLength: array[0..7] of real;//TDateTime;
+
+ FileBenchmark: TextFile;
+ FileBenchmarkO: boolean; // opened
+ FileError: TextFile;
+ FileErrorO: boolean; // opened
+
+ Title: String; //Application Title
+
+ //Should Log Files be written
+ Enabled: Boolean;
+
+ // destuctor
+ destructor Free;
+
+ // benchmark
+ procedure BenchmarkStart(Number: integer);
+ procedure BenchmarkEnd(Number: integer);
+ procedure LogBenchmark(Text: string; Number: integer);
+
+ // error
+ procedure LogError(Text: string); overload;
+
+ //Critical Error (Halt + MessageBox)
+ procedure CriticalError(Text: string);
+
+ // voice
+ procedure LogVoice(SoundNr: integer);
+
+ // compability
+ procedure LogStatus(Log1, Log2: string);
+ procedure LogError(Log1, Log2: string); overload;
+ end;
+
+var
+ Log: TLog;
+
+implementation
+uses UFiles, SysUtils, DateUtils, URecord, UTime, UIni, Windows, UCommandLine;
+
+destructor TLog.Free;
+begin
+ if FileBenchmarkO then CloseFile(FileBenchmark);
+// if FileAnalyzeO then CloseFile(FileAnalyze);
+ if FileErrorO then CloseFile(FileError);
+end;
+
+procedure TLog.BenchmarkStart(Number: integer);
+begin
+ BenchmarkTimeStart[Number] := USTime.GetTime; //Time;
+end;
+
+procedure TLog.BenchmarkEnd(Number: integer);
+begin
+ BenchmarkTimeLength[Number] := USTime.GetTime {Time} - BenchmarkTimeStart[Number];
+end;
+
+procedure TLog.LogBenchmark(Text: string; Number: integer);
+var
+ Minutes: integer;
+ Seconds: integer;
+ Miliseconds: integer;
+
+ MinutesS: string;
+ SecondsS: string;
+ MilisecondsS: string;
+
+ ValueText: string;
+begin
+ if Enabled AND (Params.Benchmark) then begin
+ if not FileBenchmarkO then begin
+ FileBenchmarkO := true;
+ AssignFile(FileBenchmark, LogPath + 'Benchmark.log');
+ {$I-}
+ Rewrite(FileBenchmark);
+ if IOResult = 0 then FileBenchmarkO := true;
+ {$I+}
+
+ //If File is opened write Date to Benchmark File
+ If (FileBenchmarkO) then
+ begin
+ WriteLn(FileBenchmark, Title + ' Benchmark File');
+ WriteLn(FileBenchmark, 'Date: ' + DatetoStr(Now) + ' Time: ' + TimetoStr(Now));
+ WriteLn(FileBenchmark, '-------------------');
+
+ Flush(FileBenchmark);
+ end;
+ end;
+
+ if FileBenchmarkO then begin
+ Miliseconds := Trunc(Frac(BenchmarkTimeLength[Number]) * 1000);
+ Seconds := Trunc(BenchmarkTimeLength[Number]) mod 60;
+ Minutes := Trunc((BenchmarkTimeLength[Number] - Seconds) / 60);
+// ValueText := FloatToStr(BenchmarkTimeLength[Number]);
+
+{ ValueText := FloatToStr(
+ SecondOf(BenchmarkTimeLength[Number]) + MilliSecondOf(BenchmarkTimeLength[Number])/1000
+ );
+ if MinuteOf(BenchmarkTimeLength[Number]) >= 1 then
+ ValueText := IntToStr(MinuteOf(BenchmarkTimeLength[Number])) + ':' + ValueText;
+ WriteLn(FileBenchmark, Text + ': ' + ValueText + ' seconds');}
+
+ if (Minutes = 0) and (Seconds = 0) then begin
+ MilisecondsS := IntToStr(Miliseconds);
+ ValueText := MilisecondsS + ' miliseconds';
+ end;
+
+ if (Minutes = 0) and (Seconds >= 1) then begin
+ MilisecondsS := IntToStr(Miliseconds);
+ while Length(MilisecondsS) < 3 do MilisecondsS := '0' + MilisecondsS;
+
+ SecondsS := IntToStr(Seconds);
+
+ ValueText := SecondsS + ',' + MilisecondsS + ' seconds';
+ end;
+
+ if Minutes >= 1 then begin
+ MilisecondsS := IntToStr(Miliseconds);
+ while Length(MilisecondsS) < 3 do MilisecondsS := '0' + MilisecondsS;
+
+ SecondsS := IntToStr(Seconds);
+ while Length(SecondsS) < 2 do SecondsS := '0' + SecondsS;
+
+ MinutesS := IntToStr(Minutes);
+
+ ValueText := MinutesS + ':' + SecondsS + ',' + MilisecondsS + ' minutes';
+ end;
+
+ WriteLn(FileBenchmark, Text + ': ' + ValueText);
+ Flush(FileBenchmark);
+ end;
+ end;
+end;
+
+procedure TLog.LogError(Text: string);
+begin
+ if Enabled AND (not FileErrorO) then begin
+ FileErrorO := true;
+ AssignFile(FileError, LogPath + 'Error.log');
+ {$I-}
+ Rewrite(FileError);
+ if IOResult = 0 then FileErrorO := true;
+ {$I+}
+
+ //If File is opened write Date to Error File
+ If (FileErrorO) then
+ begin
+ WriteLn(FileError, Title + ' Error Log');
+ WriteLn(FileError, 'Date: ' + DatetoStr(Now) + ' Time: ' + TimetoStr(Now));
+ WriteLn(FileError, '-------------------');
+
+ Flush(FileError);
+ end;
+ end;
+
+ if FileErrorO then begin
+ try
+ WriteLn(FileError, Text);
+ Flush(FileError);
+ except
+ FileErrorO := false;
+ end;
+ end;
+end;
+
+procedure TLog.LogVoice(SoundNr: integer);
+var
+ FileVoice: File;
+ FS: TFileStream;
+ FileName: string;
+ Num: integer;
+ BL: integer;
+begin
+ for Num := 1 to 9999 do begin
+ FileName := IntToStr(Num);
+ while Length(FileName) < 4 do FileName := '0' + FileName;
+ FileName := LogPath + 'Voice' + FileName + '.raw';
+ if not FileExists(FileName) then break
+ end;
+
+
+ FS := TFileStream.Create(FileName, fmCreate);
+
+ for BL := 0 to High(Sound[SoundNr].BufferLong) do begin
+ Sound[SoundNr].BufferLong[BL].Seek(0, soBeginning);
+ FS.CopyFrom(Sound[SoundNr].BufferLong[BL], Sound[SoundNr].BufferLong[BL].Size);
+ end;
+
+ FS.Free;
+end;
+
+procedure TLog.LogStatus(Log1, Log2: string);
+begin
+ //Just for Debugging
+ //Comment for Release
+ //LogAnalyze (Log2 + ': ' + Log1);
+end;
+
+procedure TLog.LogError(Log1, Log2: string);
+begin
+//asd
+end;
+
+procedure TLog.CriticalError(Text: string);
+begin
+ //Write Error to Logfile:
+ LogError (Text);
+
+ //Show Errormessage
+ Messagebox(0, PChar(Text), PChar(Title), MB_ICONERROR or MB_OK);
+
+ //Exit Application
+ Halt;
+end;
+
+end.
+
+
diff --git a/Game/Code/Classes/ULyrics.pas b/Game/Code/Classes/ULyrics.pas
new file mode 100644
index 00000000..07ecccac
--- /dev/null
+++ b/Game/Code/Classes/ULyrics.pas
@@ -0,0 +1,389 @@
+unit ULyrics;
+
+interface
+uses SysUtils, gl, glext, UMusic;
+
+type
+ TWord = record
+ X: real;
+ Y: real;
+ Size: real;
+ Width: real;
+ Text: string;
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ Scale: real;
+ Done: real;
+ FontStyle: integer;
+ Italic: boolean;
+ Selected: boolean;
+ end;
+
+ TLyric = class
+ private
+ AlignI: integer;
+ XR: real;
+ YR: real;
+ SizeR: real;
+ SelectedI: integer;
+ ScaleR: real;
+ StyleI: integer; // 0 - one selection, 1 - long selection, 2 - one selection with fade to normal text, 3 - long selection with fade with color from left
+ FontStyleI: integer; // font number
+ Word: array of TWord;
+ procedure SetX(Value: real);
+ procedure SetY(Value: real);
+ function GetClientX: real;
+ procedure SetAlign(Value: integer);
+ function GetSize: real;
+ procedure SetSize(Value: real);
+ procedure SetSelected(Value: integer);
+ procedure SetDone(Value: real);
+ procedure SetScale(Value: real);
+ procedure SetStyle(Value: integer);
+ procedure SetFStyle(Value: integer);
+ procedure Refresh;
+ procedure DrawNormal(W: integer);
+ procedure DrawPlain(W: integer);
+ procedure DrawScaled(W: integer);
+ procedure DrawSlide(W: integer);
+ public
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ ColSR: real;
+ ColSG: real;
+ ColSB: real;
+ Italic: boolean;
+ Text: string; // LCD
+
+ published
+ property X: real write SetX;
+ property Y: real write SetY;
+ property ClientX: real read GetClientX;
+ property Align: integer write SetAlign;
+ property Size: real read GetSize write SetSize;
+ property Selected: integer read SelectedI write SetSelected;
+ property Done: real write SetDone;
+ property Scale: real write SetScale;
+ property Style: integer write SetStyle;
+ property FontStyle: integer write SetFStyle;
+ procedure AddWord(Text: string);
+ procedure AddCzesc(NrCzesci: integer); //AddLine?
+ procedure ChangeCurText(Text: String);
+
+ function SelectedLetter: integer; // LCD
+ function SelectedLength: integer; // LCD
+
+ procedure Clear;
+ procedure Draw;
+
+ end;
+
+var
+ Lyric: TLyric;
+
+implementation
+uses TextGL, UGraphic, UDrawTexture;
+
+procedure TLyric.SetX(Value: real);
+begin
+ XR := Value;
+end;
+
+procedure TLyric.SetY(Value: real);
+begin
+ YR := Value;
+end;
+
+function TLyric.GetClientX: real;
+begin
+ Result := Word[0].X;
+end;
+
+procedure TLyric.SetAlign(Value: integer);
+begin
+ AlignI := Value;
+// if AlignInt = 0 then beep;
+end;
+
+function TLyric.GetSize: real;
+begin
+ Result := SizeR;
+end;
+
+procedure TLyric.SetSize(Value: real);
+begin
+ SizeR := Value;
+end;
+
+procedure TLyric.SetSelected(Value: integer);
+var
+ W: integer;
+begin
+ if (StyleI = 0) or (StyleI = 2) or (StyleI = 4) then begin
+ if (SelectedI > -1) and (SelectedI <= High(Word)) then begin
+ Word[SelectedI].Selected := false;
+ Word[SelectedI].ColR := ColR;
+ Word[SelectedI].ColG := ColG;
+ Word[SelectedI].ColB := ColB;
+ Word[SelectedI].Done := 0;
+ end;
+
+ SelectedI := Value;
+ if (Value > -1) and (Value <= High(Word)) then begin
+ Word[Value].Selected := true;
+ Word[Value].ColR := ColSR;
+ Word[Value].ColG := ColSG;
+ Word[Value].ColB := ColSB;
+ Word[Value].Scale := ScaleR;
+ end;
+ end;
+
+ if (StyleI = 1) or (StyleI = 3) then begin
+ if (SelectedI > -1) and (SelectedI <= High(Word)) then begin
+ for W := SelectedI to High(Word) do begin
+ Word[W].Selected := false;
+ Word[W].ColR := ColR;
+ Word[W].ColG := ColG;
+ Word[W].ColB := ColB;
+ Word[W].Done := 0;
+ end;
+ end;
+
+ SelectedI := Value;
+ if (Value > -1) and (Value <= High(Word)) then begin
+ for W := 0 to Value do begin
+ Word[W].Selected := true;
+ Word[W].ColR := ColSR;
+ Word[W].ColG := ColSG;
+ Word[W].ColB := ColSB;
+ Word[W].Scale := ScaleR;
+ Word[W].Done := 1;
+ end;
+ end;
+ end;
+
+ Refresh;
+end;
+
+procedure TLyric.SetDone(Value: real);
+var
+ W: integer;
+begin
+ W := SelectedI;
+ if W > -1 then
+ Word[W].Done := Value;
+end;
+
+procedure TLyric.SetScale(Value: real);
+begin
+ ScaleR := Value;
+end;
+
+procedure TLyric.SetStyle(Value: integer);
+begin
+ StyleI := Value;
+end;
+
+procedure TLyric.SetFStyle(Value: integer);
+begin
+ FontStyleI := Value;
+end;
+
+procedure TLyric.AddWord(Text: string);
+var
+ WordNum: integer;
+begin
+ WordNum := Length(Word);
+ SetLength(Word, WordNum + 1);
+ if WordNum = 0 then begin
+ Word[WordNum].X := XR;
+ end else begin
+ Word[WordNum].X := Word[WordNum - 1].X + Word[WordNum - 1].Width;
+ end;
+
+ Word[WordNum].Y := YR;
+ Word[WordNum].Size := SizeR;
+ Word[WordNum].FontStyle := FontStyleI; // new
+ SetFontStyle(FontStyleI);
+ SetFontSize(SizeR);
+ Word[WordNum].Width := glTextWidth(pchar(Text));
+ Word[WordNum].Text := Text;
+ Word[WordNum].ColR := ColR;
+ Word[WordNum].ColG := ColG;
+ Word[WordNum].ColB := ColB;
+ Word[WordNum].Scale := 1;
+ Word[WordNum].Done := 0;
+ Word[WordNum].Italic := Italic;
+
+ Refresh;
+end;
+
+procedure TLyric.AddCzesc(NrCzesci: integer);
+var
+ N: integer;
+begin
+ Clear;
+ for N := 0 to Czesci[0].Czesc[NrCzesci].HighNut do begin
+ Italic := Czesci[0].Czesc[NrCzesci].Nuta[N].FreeStyle;
+ AddWord(Czesci[0].Czesc[NrCzesci].Nuta[N].Tekst);
+ Text := Text + Czesci[0].Czesc[NrCzesci].Nuta[N].Tekst;
+ end;
+ Selected := -1;
+end;
+
+procedure TLyric.Clear;
+begin
+{ ColR := Skin_FontR;
+ ColG := Skin_FontG;
+ ColB := Skin_FontB;}
+ SetLength(Word, 0);
+ Text := '';
+ SelectedI := -1;
+end;
+
+procedure TLyric.Refresh;
+var
+ W: integer;
+ TotWidth: real;
+begin
+ if AlignI = 1 then begin
+ TotWidth := 0;
+ for W := 0 to High(Word) do
+ TotWidth := TotWidth + Word[W].Width;
+
+ Word[0].X := XR - TotWidth / 2;
+ for W := 1 to High(Word) do
+ Word[W].X := Word[W - 1].X + Word[W - 1].Width;
+ end;
+end;
+
+procedure TLyric.Draw;
+var
+ W: integer;
+begin
+ case StyleI of
+ 0:
+ begin
+ for W := 0 to High(Word) do
+ DrawNormal(W);
+ end;
+ 1:
+ begin
+ for W := 0 to High(Word) do
+ DrawPlain(W);
+ end;
+ 2: // zoom
+ begin
+ for W := 0 to High(Word) do
+ if not Word[W].Selected then
+ DrawNormal(W);
+
+ for W := 0 to High(Word) do
+ if Word[W].Selected then
+ DrawScaled(W);
+ end;
+ 3: // slide
+ begin
+ for W := 0 to High(Word) do begin
+ if not Word[W].Selected then
+ DrawNormal(W)
+ else
+ DrawSlide(W);
+ end;
+ end;
+ 4: // ball
+ begin
+ for W := 0 to High(Word) do
+ DrawNormal(W);
+
+ for W := 0 to High(Word) do
+ if Word[W].Selected then begin
+ Tex_Ball.X := (Word[W].X - 10) + Word[W].Done * Word[W].Width;
+ Tex_Ball.Y := 480 - 10*sin(Word[W].Done * pi);
+ Tex_Ball.W := 20;
+ Tex_Ball.H := 20;
+ DrawTexture(Tex_Ball);
+ end;
+ end;
+ end; // case
+end;
+
+procedure TLyric.DrawNormal(W: integer);
+begin
+ SetFontStyle(Word[W].FontStyle);
+ SetFontPos(Word[W].X+ 10*ScreenX, Word[W].Y);
+ SetFontSize(Word[W].Size);
+ SetFontItalic(Word[W].Italic);
+ glColor3f(Word[W].ColR, Word[W].ColG, Word[W].ColB);
+ glPrint(pchar(Word[W].Text));
+end;
+
+procedure TLyric.DrawPlain(W: integer);
+var
+ D: real;
+begin
+ D := Word[W].Done; // przyrost
+
+ SetFontStyle(Word[W].FontStyle);
+ SetFontPos(Word[W].X, Word[W].Y);
+ SetFontSize(Word[W].Size);
+ SetFontItalic(Word[W].Italic);
+
+ if D = 0 then
+ glColor3f(ColR, ColG, ColB)
+ else
+ glColor3f(ColSR, ColSG, ColSB);
+
+ glPrint(pchar(Word[W].Text));
+end;
+
+procedure TLyric.DrawScaled(W: integer);
+var
+ D: real;
+begin
+ // previous plus dynamic scaling effect
+ D := 1-Word[W].Done; // przyrost
+ SetFontStyle(Word[W].FontStyle);
+ SetFontPos(Word[W].X - D * Word[W].Width * (Word[W].Scale - 1) / 2 + (D+1)*10*ScreenX, Word[W].Y - D * 1.5 * Word[W].Size *(Word[W].Scale - 1));
+ SetFontSize(Word[W].Size + D * (Word[W].Size * Word[W].Scale - Word[W].Size));
+ SetFontItalic(Word[W].Italic);
+ glColor3f(Word[W].ColR, Word[W].ColG, Word[W].ColB);
+ glPrint(pchar(Word[W].Text))
+end;
+
+procedure TLyric.DrawSlide(W: integer);
+var
+ D: real;
+begin
+ D := Word[W].Done; // przyrost
+ SetFontStyle(Word[W].FontStyle);
+ SetFontPos(Word[W].X, Word[W].Y);
+ SetFontSize(Word[W].Size);
+ SetFontItalic(Word[W].Italic);
+ glColor3f(Word[W].ColR, Word[W].ColG, Word[W].ColB);
+ glPrintDone(pchar(Word[W].Text), D, ColR, ColG, ColB);
+end;
+
+function TLyric.SelectedLetter; // LCD
+var
+ W: integer;
+begin
+ Result := 1;
+
+ for W := 0 to SelectedI-1 do
+ Result := Result + Length(Word[W].Text);
+end;
+
+function TLyric.SelectedLength: integer; // LCD
+begin
+ Result := Length(Word[SelectedI].Text);
+end;
+
+procedure TLyric.ChangeCurText(Text: String);
+begin
+ Word[Selected].Text := Text;
+end;
+
+end.
diff --git a/Game/Code/Classes/UMain.pas b/Game/Code/Classes/UMain.pas
new file mode 100644
index 00000000..feaaedf1
--- /dev/null
+++ b/Game/Code/Classes/UMain.pas
@@ -0,0 +1,735 @@
+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}, ULCD, ULight, UThemes{, UScreenPopup};
+
+type
+ TPlayer = record
+ Name: string;
+
+ 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
+
+ //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: UTF8String;
+ SongTitle: UTF8String;
+ 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(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 NewHalf; // executed when in the half between beats
+procedure NewNote(Sender: TScreenSing); // detect note
+function GetMidBeat(Time: real): real;
+function GetTimeFromBeat(Beat: integer): real;
+procedure ClearScores(PlayerNum: integer);
+
+implementation
+uses USongs, UJoystick, math, UCommandLine;
+
+procedure MainLoop;
+var
+ Delay: integer;
+begin
+ SDL_EnableKeyRepeat(125, 125);
+ While not Done do
+ Begin
+ // joypad
+ if (Ini.Joypad = 1) OR (Params.Joypad) then
+ Joy.Update;
+
+ // keyboard events
+ CheckEvents;
+
+ // display
+ done := not Display.Draw;
+ SwapBuffers;
+
+ // light
+ Light.Refresh;
+
+ // delay
+ CountMidTime;
+// if 1000*TimeMid > 100 then beep;
+ Delay := Floor(1000 / 100 - 1000 * TimeMid);
+ if Delay >= 1 then
+ SDL_Delay(Delay); // dynamic, maximum is 100 fps
+ CountSkipTime;
+
+ // reinitialization of graphics
+ if Restart then begin
+ Reinitialize3D;
+ Restart := false;
+ end;
+
+ End;
+ FreeOpenGL;
+End;
+
+Procedure CheckEvents;
+//var
+// p: pointer;
+Begin
+ if not Assigned(Display.NextScreen) then
+ While SDL_PollEvent( @event ) = 1 Do
+ Begin
+// beep;
+ Case Event.type_ Of
+ 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
+ Display.ScreenShot;
+ 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.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.OldHalf := Czas.AktHalf;
+// Czas.MidHalf := Czas.MidBeat + 0.5;
+// Czas.AktHalf := Floor(Czas.MidHalf);
+
+ 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
+ for PetGr := 0 to 0 do begin;//High(Gracz) do begin
+ CP := PetGr;
+ // ustawianie starej czesci
+ Czas.OldCzesc := Czesci[CP].Akt;
+
+ // wybieranie aktualnej czesci
+ for Pet := 0 to Czesci[CP].High do
+ begin
+ if Czas.AktBeat >= Czesci[CP].Czesc[Pet].Start then
+ Czesci[CP].Akt := Pet;
+ end;
+
+ // czysczenie nut gracza, gdy to jest nowa plansza
+ // (optymizacja raz na halfbeat jest zla)
+ if Czesci[CP].Akt <> Czas.OldCzesc then NewSentence(Sender);
+
+ end; // for PetGr
+
+ // wykonuje operacje raz na beat
+ if (Czas.AktBeat >= 0) and (Czas.OldBeat <> Czas.AktBeat) then
+ NewBeat(Sender);
+
+ // make some operations on clicks
+ if {(Czas.AktBeatC >= 0) and }(Czas.OldBeatC <> Czas.AktBeatC) then
+ NewBeatC(Sender);
+
+ // make some operations when detecting new voice pitch
+ if (Czas.AktBeatD >= 0) and (Czas.OldBeatD <> Czas.AktBeatD) then
+ NewBeatD(Sender);
+
+ // wykonuje operacje w polowie beatu
+// if (Czas.AktHalf >= 1) and (Czas.OldHalf <> Czas.AktHalf) then
+// NewHalf;
+
+ // plynnie przesuwa text
+ Done := 1;
+ for N := 0 to Czesci[0].Czesc[Czesci[0].Akt].HighNut do
+ if (Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Start <= Czas.MidBeat)
+ and (Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Start + Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Dlugosc >= Czas.MidBeat) then
+ Done := (Czas.MidBeat - Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Start) / (Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Dlugosc);
+
+ N := Czesci[0].Czesc[Czesci[0].Akt].HighNut;
+
+ // wylacza ostatnia nute po przejsciu
+ if (Ini.LyricsEffect = 1) and (Done = 1) and
+ (Czas.MidBeat > Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Start + Czesci[0].Czesc[Czesci[0].Akt].Nuta[N].Dlugosc)
+ then Sender.LyricMain.Selected := -1;
+
+ if Done > 1 then Done := 1;
+ Sender.LyricMain.Done := Done;
+
+ // use Done with LCD
+{ 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;
+
+procedure NewSentence(Sender: TScreenSing);
+var
+G: Integer;
+begin
+ // czyszczenie nut graczy
+ for G := 0 to High(Player) do begin
+ Player[G].IlNut := 0;
+ Player[G].HighNut := -1;
+ SetLength(Player[G].Nuta, 0);
+ end;
+
+ // wstawianie tekstow
+ with Sender do begin
+ LyricMain.AddCzesc(Czesci[0].Akt);
+ if Czesci[0].Akt < Czesci[0].High then
+ LyricSub.AddCzesc(Czesci[0].Akt+1)
+ else
+ LyricSub.Clear;
+ end;
+
+ Sender.UpdateLCD;
+
+ //On Sentence Change...
+ Sender.onSentenceChange(Czesci[0].Akt);
+end;
+
+procedure NewBeat(Sender: TScreenSing);
+var
+ Pet: integer;
+// TempBeat: integer;
+begin
+ // ustawia zaznaczenie tekstu
+// SingScreen.LyricMain.Selected := -1;
+ for Pet := 0 to Czesci[0].Czesc[Czesci[0].Akt].HighNut do
+ if (Czesci[0].Czesc[Czesci[0].Akt].Nuta[Pet].Start = Czas.AktBeat) then begin
+ // operates on currently beated note
+ Sender.LyricMain.Selected := Pet;
+
+// LCD.MoveCursor(1, ScreenSing.LyricMain.SelectedLetter);
+// LCD.ShowCursor;
+
+ LCD.MoveCursorBR(Sender.LyricMain.SelectedLetter);
+ LCD.ShowCursor;
+
+ end;
+end;
+
+procedure NewBeatC;
+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[0].Resolution + Czesci[0].NotesGAP) mod Czesci[0].Resolution = 0) then
+ Music.PlayClick;
+
+ // debug system on LPT
+ if ((Czas.AktBeatC + Czesci[0].Resolution + Czesci[0].NotesGAP) mod Czesci[0].Resolution = 0) then begin
+ //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 ((Czas.AktBeatC + Czesci[0].Resolution + Czesci[0].NotesGAP) mod (Czesci[0].Resolution * 2) = 0) then
+ Light.LightOne(0, 150)
+ else
+ Light.LightOne(1, 150)}
+ end;
+
+ for Pet := 0 to Czesci[0].Czesc[Czesci[0].Akt].HighNut do
+ if (Czesci[0].Czesc[Czesci[0].Akt].Nuta[Pet].Start = Czas.AktBeatC) then begin
+ // click assist
+ if Ini.ClickAssist = 1 then
+ Music.PlayClick;
+
+ //LPT_2 := 0;
+ if ParamStr(1) <> '-doublelights' then
+ Light.LightOne(0, 150); //125
+
+
+ // 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(Sender: TScreenSing);
+begin
+ NewNote(Sender);
+end;
+
+//procedure NewHalf;
+//begin
+// NewNote;
+//end;
+
+procedure NewNote(Sender: TScreenSing);
+var
+ CP: integer; // current player
+ S: integer; // sentence
+ SMin: integer;
+ SMax: integer;
+ SDet: integer; // temporary: sentence of detected note
+ Pet: integer;
+ Mozna: boolean;
+ Nowa: boolean;
+ Range: integer;
+ NoteHit:boolean;
+begin
+// Log.LogStatus('Beat ' + IntToStr(Czas.AktBeat) + ' HalfBeat ' + IntToStr(Czas.AktHalf), 'NewBeat');
+// beep;
+
+ // analizuje dla obu graczy ten sam sygnal (Sound.OneSrcForBoth)
+ // albo juz lepiej nie
+ for CP := 0 to PlayersPlay-1 do begin
+
+ // analyze buffer
+ Sound[CP].AnalizujBufor;
+
+ // adds some noise
+// Czas.Ton := Czas.Ton + Round(Random(3)) - 1;
+
+ // 0.5.0: count min and max sentence range for checking (detection is delayed to the notes we see on the screen)
+ SMin := Czesci[0].Akt-1;
+ if SMin < 0 then SMin := 0;
+ SMax := Czesci[0].Akt;
+
+ // check if we can add new note
+ Mozna := false;
+ for S := SMin to SMax do
+ for Pet := 0 to Czesci[0].Czesc[S].HighNut do
+ if ((Czesci[0].Czesc[S].Nuta[Pet].Start <= Czas.AktBeatD)
+ and (Czesci[0].Czesc[S].Nuta[Pet].Start + Czesci[0].Czesc[S].Nuta[Pet].Dlugosc - 1 >= Czas.AktBeatD))
+ and (not Czesci[0].Czesc[S].Nuta[Pet].FreeStyle) // but don't allow when it's FreeStyle note
+ and (Czesci[0].Czesc[S].Nuta[Pet].Dlugosc > 0) // and make sure the note lenghts is at least 1
+ then begin
+ SDet := S;
+ Mozna := true;
+ Break;
+ end;
+
+ S := SDet;
+
+
+
+
+
+// Czas.SzczytJest := true;
+// Czas.Ton := 27;
+
+ // gdy moze, to dodaje nute
+ if (Sound[CP].SzczytJest) and (Mozna) then begin
+ // operowanie na ostatniej nucie
+ for Pet := 0 to Czesci[0].Czesc[S].HighNut do
+ if (Czesci[0].Czesc[S].Nuta[Pet].Start <= Czas.OldBeatD+1)
+ and (Czesci[0].Czesc[S].Nuta[Pet].Start +
+ Czesci[0].Czesc[S].Nuta[Pet].Dlugosc > Czas.OldBeatD+1) then begin
+ // to robi, tylko dla pary nut (oryginalnej i gracza)
+
+ // przesuwanie tonu w odpowiednia game
+ while (Sound[CP].Ton - Czesci[0].Czesc[S].Nuta[Pet].Ton > 6) do
+ Sound[CP].Ton := Sound[CP].Ton - 12;
+ while (Sound[CP].Ton - Czesci[0].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[0].Czesc[S].Nuta[Pet].Ton - Sound[CP].Ton) <= Range then begin
+ Sound[CP].Ton := Czesci[0].Czesc[S].Nuta[Pet].Ton;
+
+
+ // Half size Notes Patch
+ NoteHit := true;
+
+
+ if (Ini.LineBonus = 0) then
+ begin
+ // add points without LineBonus
+ case Czesci[0].Czesc[S].Nuta[Pet].Wartosc of
+ 1: Player[CP].Score := Player[CP].Score + 10000 / Czesci[0].Wartosc *
+ Czesci[0].Czesc[S].Nuta[Pet].Wartosc;
+ 2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 10000 / Czesci[0].Wartosc *
+ Czesci[0].Czesc[S].Nuta[Pet].Wartosc;
+ end;
+ end
+ else
+ begin
+ // add points with Line Bonus
+ case Czesci[0].Czesc[S].Nuta[Pet].Wartosc of
+ 1: Player[CP].Score := Player[CP].Score + 9000 / Czesci[0].Wartosc *
+ Czesci[0].Czesc[S].Nuta[Pet].Wartosc;
+ 2: Player[CP].ScoreGolden := Player[CP].ScoreGolden + 9000 / Czesci[0].Wartosc *
+ Czesci[0].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
+
+ // 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[0].Czesc[S].HighNut do
+ if (Czesci[0].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;
+
+
+ // Log.LogStatus('Nowa Nuta ' + IntToStr(Gracz.Nuta[Gracz.HighNut].Start), 'NewBeat');
+
+ 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[0].Czesc[S].HighNut do
+ if (Czesci[0].Czesc[S].Nuta[Pet].Start = Player[CP].Nuta[Player[CP].HighNut].Start)
+ and (Czesci[0].Czesc[S].Nuta[Pet].Dlugosc = Player[CP].Nuta[Player[CP].HighNut].Dlugosc)
+ and (Czesci[0].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; // if moze
+ end; // for CP
+// Log.LogStatus('EndBeat', 'NewBeat');
+
+//On Sentence End -> For LineBonus + SingBar
+if (sDet >= low(Czesci[0].Czesc)) AND (sDet <= high(Czesci[0].Czesc)) then
+if ((Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Start + Czesci[0].Czesc[SDet].Nuta[Czesci[0].Czesc[SDet].HighNut].Dlugosc - 1) = Czas.AktBeatD) then
+ Sender.onSentenceEnd(sDet);
+
+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
+
+ //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.
+
diff --git a/Game/Code/Classes/UMusic.pas b/Game/Code/Classes/UMusic.pas
new file mode 100644
index 00000000..c4f80235
--- /dev/null
+++ b/Game/Code/Classes/UMusic.pas
@@ -0,0 +1,951 @@
+unit UMusic;
+
+interface
+
+uses Classes, MPlayer, Windows, Messages, SysUtils, Forms, ULog, USongs, Bass;//, DXSounds;
+
+procedure InitializeSound;
+
+type
+ TPos = record
+ line: integer;
+ note: integer;
+ end;
+
+ TSongMode = (smNormal, smParty, smChallenge, smMedley);
+
+ TSoundCard = record
+ Name: string;
+ Source: array of string;
+ end;
+
+ TFFTData = array [0..256] of Single;
+
+ TCustomSoundEntry = record
+ Filename: String;
+ Handle: hStream;
+ end;
+
+ TMusic = class
+ private
+// MediaPlayer: TMediaPlayer; // It will be replaced by another component;
+{ MediaPlayerStart: TMediaPlayer; // or maybe not if done this way ;)
+ MediaPlayerBack: TMediaPlayer;
+ MediaPlayerSwoosh: TMediaPlayer;
+ MediaPlayerChange: TMediaPlayer;
+ MediaPlayerOption: TMediaPlayer;
+ MediaPlayerClick: TMediaPlayer;
+ MediaPlayerDrum: TMediaPlayer;
+ MediaPlayerHihat: TMediaPlayer;
+ MediaPlayerClap: TMediaPlayer;
+ MediaPlayerShuffle: TMediaPlayer;}
+ BassStart: hStream; // Wait, I've replaced this with BASS
+ BassBack: hStream; // It has almost all features we need
+ BassSwoosh: hStream;
+ BassChange: hStream; // Almost? It aleady has them all :)
+ BassOption: hStream;
+ BassClick: hStream;
+ BassDrum: hStream;
+ BassHihat: hStream;
+ BassClap: hStream;
+ BassShuffle: hStream;
+ BassApplause: hStream;
+
+ //Custom Sounds
+ CustomSounds: array of TCustomSoundEntry;
+
+
+ Loaded: boolean;
+ Loop: boolean;
+// DXSound: TDXSound;
+// Player: TcmxMp3;
+ DSP_VocalRemover: HDSP;
+ public
+ Bass: hStream;
+
+// SoundCard: array of TSoundCard;
+ procedure InitializePlayback;
+ procedure InitializeRecord;
+ procedure SetVolume(Volume: integer);
+ procedure SetMusicVolume(Volume: integer);
+ procedure Fade(InitVolume, TargetVolume: Integer; FadeTime: real);
+ procedure FadeStop(FadeTime: real);
+ procedure SetLoop(Enabled: boolean);
+ function Open(Name: string): boolean; // true if succeed
+ procedure Rewind;
+ procedure MoveTo(Time: real);
+ procedure Play;
+ procedure Pause; //Pause Mod
+ procedure Stop;
+ procedure Close;
+ function Finished: boolean;
+ function Length: real;
+ function Position: real;
+ procedure PlayStart;
+ procedure PlayBack;
+ procedure PlaySwoosh;
+ procedure PlayChange;
+ procedure PlayOption;
+ procedure PlayClick;
+ procedure PlayDrum;
+ procedure PlayHihat;
+ procedure PlayClap;
+ procedure PlayShuffle;
+ procedure StopShuffle;
+ procedure PlayApplause;
+ procedure CaptureStart;
+ procedure CaptureStop;
+ procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte);
+ procedure StopCard(Card: byte);
+ function LoadPlayerFromFile(var MediaPlayer: TMediaPlayer; Name: string): boolean;
+ function LoadSoundFromFile(var hStream: hStream; Name: string): boolean;
+
+ //Equalizer
+ function GetFFTData: TFFTData;
+
+ //Custom Sounds
+ function LoadCustomSound(const Filename: String): Cardinal;
+ procedure PlayCustomSound(const Index: Cardinal);
+
+ procedure EnableVocalRemover;
+ procedure DisableVocalRemover;
+ function VocalRemoverActivated(): boolean;
+
+end;
+
+const
+ RecordSystem = 1;
+
+function FindNote(beat: integer): TPos;
+
+type
+ TMuzyka = record
+ Path: string;
+ Start: integer; // start of song in ms
+// BPM: array of TBPM;
+// Gap: real;
+ IlNut: integer;
+ DlugoscNut: integer;
+// WartoscNut: integer;
+ end;
+
+ TCzesci = record //Lines
+ Akt: integer; // aktualna czesc utworu do rysowania
+ High: integer;
+ Ilosc: integer;
+ Resolution: integer;
+ NotesGAP: integer;
+ Wartosc: integer;
+ Czesc: array of record //Line
+ Start: integer;
+ StartNote: integer;
+ Lyric: string;
+ LyricWidth: real;
+ Koniec: integer; //Ende?
+ BaseNote: integer;
+ HighNut: integer;
+ IlNut: integer;
+ TotalNotes: integer;
+ Nuta: array of record //Note
+ Color: integer;
+ Start: integer;
+ Dlugosc: integer;
+ Ton: integer;
+ TonGamy: integer;
+ Tekst: string; //Silbe?
+ FreeStyle: boolean;
+ Wartosc: integer; // zwykla nuta x1, zlota nuta x2
+ IsMedley: boolean; //just for editor
+ IsStartPreview: boolean; //just for editor
+
+
+
+
+ end;
+ end;
+ end;
+
+ TCzas = record // wszystko, co dotyczy aktualnej klatki
+// BajtowTotal: integer;
+// BajtowTeraz: integer;
+// BajtowNaSek: integer;
+ OldBeat: integer; // poprzednio wykryty beat w utworze
+ AktBeat: integer; // aktualny beat w utworze
+ MidBeat: real; // dokladny AktBeat
+
+ // should not be used
+// OldHalf: integer; // poprzednio wykryta polowka
+// AktHalf: integer; // aktualna polowka w utworze
+// MidHalf: real; // dokladny AktHalf
+
+ // now we use this for super synchronization!
+ // only used when analyzing voice
+ OldBeatD: integer; // poprzednio wykryty beat w utworze
+ AktBeatD: integer; // aktualny beat w utworze
+ MidBeatD: real; // dokladny AktBeatD
+ FracBeatD: real; // fractional part of MidBeatD
+
+ // we use this for audiable clicks
+ OldBeatC: integer; // poprzednio wykryty beat w utworze
+ AktBeatC: integer; // aktualny beat w utworze
+ MidBeatC: real; // dokladny AktBeatC
+ FracBeatC: real; // fractional part of MidBeatC
+
+
+ OldCzesc: integer; // poprzednio wyswietlana czesc
+ // akt jest w czesci.akt
+
+ Teraz: real; // aktualny czas w utworze
+ Razem: real; // caly czas utworu
+// TerazSek: integer;
+ end;
+
+var
+ Form: TForm;
+ Music: TMusic;
+
+ // muzyka
+ Muzyka: TMuzyka;
+
+ // czesci z nutami;
+ Czesci: array of TCzesci;
+
+ // czas
+ Czas: TCzas;
+
+ fHWND: Thandle;
+
+const
+ ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open');
+
+implementation
+uses UGraphic, URecord, UFiles, UIni, UMain, UThemes, UTime;
+
+//from http://www.un4seen.com/forum/?topic=5943.0;hl=sbvocalcut16
+procedure SBVocalCut16(handle: DWORD; channel: DWORD; buffer: Pointer; length: DWORD; user: DWORD); stdcall;
+var
+ i, k: DWORD;
+ dmch: Smallint;
+ lch, rch: PSmallint;
+
+begin
+ i := 0;
+ lch := buffer;
+ rch := buffer;
+ Inc(rch);
+
+ while (i < length) do
+ begin
+ dmch := round((((0 - lch^) + (rch^)) div 2)*1.5);
+
+ lch^ := dmch;
+ rch^ := dmch;
+
+ Inc(lch, 2);
+ Inc(rch, 2);
+ Inc(i, SizeOf(SmallInt) * 2);
+ end;
+end;
+
+function FindNote(beat: integer): TPos;
+var
+ I, J: integer;
+ found: boolean;
+ min: integer;
+ diff: integer;
+begin
+ found := false;
+ for I := 0 to length(Czesci[0].Czesc) - 1 do
+ begin
+ for J := 0 to length(Czesci[0].Czesc[I].Nuta) - 1 do
+ begin
+ if (beat>=Czesci[0].Czesc[I].Nuta[J].Start) and
+ (beat<=Czesci[0].Czesc[I].Nuta[J].Start + Czesci[0].Czesc[I].Nuta[J].Dlugosc) then
+ begin
+ Result.line := I;
+ Result.note := J;
+ found:=true;
+ break;
+ end;
+ end;
+ end;
+
+ if found then //found exactly
+ exit;
+
+ min := high(integer);
+ //second try (approximating)
+ for I := 0 to length(Czesci[0].Czesc) - 1 do
+ begin
+ for J := 0 to length(Czesci[0].Czesc[I].Nuta) - 1 do
+ begin
+ diff := abs(Czesci[0].Czesc[I].Nuta[J].Start - beat);
+ if diff<min then
+ begin
+ Result.line := I;
+ Result.note := J;
+ min := diff;
+ end;
+ end;
+ end;
+end;
+
+procedure InitializeSound;
+begin
+ Log.LogStatus('Initializing Playback', 'InitializeSound'); Music.InitializePlayback;
+ Log.LogStatus('Initializing Record', 'InitializeSound'); Music.InitializeRecord;
+end;
+
+procedure TMusic.InitializePlayback;
+var
+ Pet: integer;
+ S: integer;
+begin
+ Log.BenchmarkStart(4);
+ Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize');
+ Loaded := false;
+ Loop := false;
+ fHWND := AllocateHWND( nil);
+
+ if BASS_Init(1, 44100, 0, fHWND, nil) = false then
+ begin
+ Application.MessageBox ('Could not initialize BASS', 'Error');
+ Exit;
+ end;
+ DSP_VocalRemover := 0;
+ Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4);
+
+ // config playing buffer
+ //BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 0);
+ //BASS_SetConfig(BASS_CONFIG_BUFFER, 100);
+
+{ MediaPlayer := TMediaPlayer.Create( nil );
+ MediaPlayer.ParentWindow := fHWND;
+ MediaPlayer.Wait := true;}
+
+ Log.LogStatus('Loading Sounds', 'Music Initialize');
+
+{ LoadPlayerFromFile(MediaPlayerStart, SoundPath + 'Common Start.mp3');
+ LoadPlayerFromFile(MediaPlayerBack, SoundPath + 'Common Back.mp3');
+ LoadPlayerFromFile(MediaPlayerSwoosh, SoundPath + 'menu swoosh.mp3');
+ LoadPlayerFromFile(MediaPlayerChange, SoundPath + 'select music change music.mp3');
+ LoadPlayerFromFile(MediaPlayerOption, SoundPath + 'option change col.mp3');
+ LoadPlayerFromFile(MediaPlayerClick, SoundPath + 'rimshot022b.mp3');
+
+ LoadPlayerFromFile(MediaPlayerDrum, SoundPath + 'bassdrumhard076b.mp3');
+ LoadPlayerFromFile(MediaPlayerHihat, SoundPath + 'hihatclosed068b.mp3');
+ LoadPlayerFromFile(MediaPlayerClap, SoundPath + 'claps050b.mp3');
+
+ LoadPlayerFromFile(MediaPlayerShuffle, SoundPath + 'Shuffle.mp3');}
+
+ Log.BenchmarkStart(4);
+ LoadSoundFromFile(BassStart, SoundPath + 'Common Start.mp3');
+ LoadSoundFromFile(BassBack, SoundPath + 'Common Back.mp3');
+ LoadSoundFromFile(BassSwoosh, SoundPath + 'menu swoosh.mp3');
+ LoadSoundFromFile(BassChange, SoundPath + 'select music change music 50.mp3');
+ LoadSoundFromFile(BassOption, SoundPath + 'option change col.mp3');
+ LoadSoundFromFile(BassClick, SoundPath + 'rimshot022b.mp3');
+
+// LoadSoundFromFile(BassDrum, SoundPath + 'bassdrumhard076b.mp3');
+// LoadSoundFromFile(BassHihat, SoundPath + 'hihatclosed068b.mp3');
+// LoadSoundFromFile(BassClap, SoundPath + 'claps050b.mp3');
+
+// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3');
+ LoadSoundFromFile(BassApplause, SoundPath + 'Applause.mp3');
+ Log.BenchmarkEnd(4); Log.LogBenchmark('--> Loading Sounds', 4);
+end;
+
+procedure TMusic.InitializeRecord;
+var
+ S: integer;
+ device: integer;
+ descr: string;
+ input: integer;
+ input2: integer;
+ flags: integer;
+ mic: array[0..15] of integer;
+ SC: integer; // soundcard
+ SCI: integer; // soundcard input
+begin
+ if RecordSystem = 1 then begin
+ SetLength(Sound, 6 {max players});//Ini.Players+1);
+ for S := 0 to High(Sound) do begin //Ini.Players do begin
+ Sound[S] := TSound.Create;
+ Sound[S].Num := S;
+ Sound[S].BufferNew := TMemoryStream.Create;
+ SetLength(Sound[S].BufferLong, 1);
+ Sound[S].BufferLong[0] := TMemoryStream.Create;
+ Sound[S].n := 4*1024;
+ end;
+
+
+ // check for recording devices;
+ {device := 0;
+ descr := BASS_RecordGetDeviceDescription(device);
+
+ SetLength(SoundCard, 0);
+ while (descr <> '') do begin
+ SC := High(SoundCard) + 1;
+ SetLength(SoundCard, SC+1);
+
+ Log.LogAnalyze('Device #'+IntToStr(device)+': '+ descr);
+ SoundCard[SC].Description := Descr;
+
+ // check for recording inputs
+ mic[device] := -1; // default to no change
+ input := 0;
+ BASS_RecordInit(device);
+ Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input));
+ flags := BASS_RecordGetInput(input);
+
+ SetLength(SoundCard[SC].Input, 0);
+ while (flags <> -1) do begin
+ SCI := High(SoundCard[SC].Input) + 1;
+ SetLength(SoundCard[SC].Input, SCI+1);
+
+ Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input));
+ SoundCard[SC].Input[SCI].Name := BASS_RecordGetInputName(Input);
+
+ if (flags and BASS_INPUT_TYPE_MASK) = BASS_INPUT_TYPE_MIC then begin
+ mic[device] := input; // auto set microphone
+ end;
+ Inc(Input);
+ flags := BASS_RecordGetInput(input);
+ end;
+
+ if mic[device] <> -1 then begin
+ Log.LogAnalyze('Found the mic at input ' + IntToStr(Mic[device]))
+ end else begin
+ Log.LogAnalyze('Mic not found');
+ mic[device] := 0; // setting to the first one (for kxproject)
+ end;
+ SoundCard[SC].InputSeleceted := Mic[Device];
+
+
+ BASS_RecordFree;
+
+ inc(Device);
+ descr := BASS_RecordGetDeviceDescription(Device);
+ end; // while}
+ end; // if
+end;
+
+procedure TMusic.SetVolume(Volume: integer);
+begin
+ //Old Sets Wave Volume
+ //BASS_SetVolume(Volume);
+ //New: Sets Volume only for this Application
+ BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume);
+ BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume);
+ BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume);
+end;
+
+procedure TMusic.SetMusicVolume(Volume: Integer);
+begin
+ //Max Volume Prevention
+ if Volume > 100 then
+ Volume := 100;
+
+ //Set Volume
+ BASS_ChannelSetAttributes (Bass, -1, Volume, -101);
+end;
+
+procedure TMusic.Fade(InitVolume, TargetVolume: Integer; FadeTime: real);
+var
+ time: dword;
+begin
+ //Max Volume Prevention
+ if TargetVolume > 100 then
+ TargetVolume := 100
+ else if TargetVolume<0 then
+ TargetVolume := 0;
+
+ BASS_ChannelSetAttributes (Bass, -1, InitVolume, -101);
+ time := round(FadeTime*1000);
+ BASS_ChannelSlideAttributes (Bass, -1, TargetVolume, -101, time);
+end;
+
+procedure TMusic.FadeStop(FadeTime: real);
+var
+ time: dword;
+begin
+ time := round(FadeTime*1000);
+ BASS_ChannelSlideAttributes (Bass, -1, -2, -101, time); //fade out and stop
+end;
+
+procedure TMusic.SetLoop(Enabled: boolean);
+begin
+ Loop := Enabled;
+end;
+
+function TMusic.Open(Name: string): boolean;
+begin
+ Loaded := false;
+
+ if FileExists(Name) then begin
+{ MediaPlayer.FileName := Name;
+ MediaPlayer.Open;}
+
+ Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0);
+ Loaded := true;
+ DSP_VocalRemover:=0;
+ //Set Max Volume
+ SetMusicVolume (100);
+ end;
+
+ Result := Loaded;
+
+// Player := TcmxMp3.Create(Name);
+end;
+
+procedure TMusic.Rewind;
+begin
+ if Loaded then begin
+// MediaPlayer.Position := 0;
+
+ end;
+end;
+
+procedure TMusic.MoveTo(Time: real);
+var
+ bytes: integer;
+begin
+// if Loaded then begin
+// MediaPlayer.StartPos := Round(Time);
+ bytes := BASS_ChannelSeconds2Bytes(Bass, Time);
+ BASS_ChannelSetPosition(Bass, bytes);
+// end;
+end;
+
+procedure TMusic.Play;
+begin
+ if Loaded then begin
+// MediaPlayer.Play;
+ if Loop then BASS_ChannelPlay(Bass, True); // start from beginning... actually bass itself does not loop, nor does this TMusic Class
+ BASS_ChannelPlay(Bass, False); // for setting position before playing
+ end;
+end;
+
+procedure TMusic.Pause; //Pause Mod
+begin
+ if Loaded then begin
+ BASS_ChannelPause(Bass); // Pauses Song
+ end;
+end;
+
+procedure TMusic.Stop;
+begin
+ Bass_ChannelStop(Bass);
+// Bass_StreamFree(Bass);
+// if ModeStr[MediaPlayer.Mode] = 'Playing' then begin
+// MediaPlayer.Stop;
+// end;
+end;
+
+procedure TMusic.Close;
+begin
+ Bass_StreamFree(Bass);
+ DSP_VocalRemover:=0;
+// Player.Free;
+// MediaPlayer.Close;
+end;
+
+function TMusic.Length: real;
+var
+ bytes: integer;
+begin
+ Result := 60;
+
+ bytes := BASS_ChannelGetLength( Bass );
+ Result := BASS_ChannelBytes2Seconds(Bass, bytes);
+
+{ if Assigned(MediaPlayer) then begin
+ if Loaded then Result := MediaPlayer.Length / 1000;
+ end;}
+// if Assigned(Player) then
+// Result := Player.LengthInSeconds;
+end;
+
+function TMusic.Position: real;
+var
+ bytes: integer;
+begin
+ Result := 0;//MediaPlayer.Position / 1000;
+ bytes := BASS_ChannelGetPosition(BASS);
+ Result := BASS_ChannelBytes2Seconds(BASS, bytes);
+end;
+
+function TMusic.Finished: boolean;
+begin
+ Result := false;
+// if ModeStr[MediaPlayer.Mode] = 'Stopped' then Result := true;
+ if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then begin
+// beep;
+ Result := true;
+ end;
+end;
+
+{function myeffect( chan : integer; stream : Pointer; len : integer; udata : Pointer ): Pointer; cdecl;
+var
+ dane: pwordarray;
+ pet: integer;
+ Prev: smallint;
+ PrevNew: smallint;
+begin
+ dane := stream;
+ Prev := 0;
+ for pet := 0 to len div 2 -1 do begin
+ PrevNew := Dane[Pet];
+
+// Dane[pet] := Round(PrevNew*1/8 + Prev*7/8);
+
+ Prev := Dane[Pet];
+ end;
+end;}
+
+procedure TMusic.PlayStart;
+{var
+ Music: PMix_Chunk;}
+begin
+{ Mix_OpenAudio(44100, 16, 1, 16*1024);
+ Music := Mix_LoadWAV('D:\Rozne\UltraStar\Old\Boys - Hej Sokoly 30s.wav');
+ Mix_RegisterEffect(0, myeffect, nil, 0);
+ Mix_PlayChannel(0, Music, 0);}
+
+// MediaPlayerStart.Rewind;
+// MediaPlayerStart.Play;
+ BASS_ChannelPlay(BassStart, True);
+end;
+
+procedure TMusic.PlayBack;
+begin
+// MediaPlayerBack.Rewind;
+// MediaPlayerBack.Play;
+// if not
+ BASS_ChannelPlay(BassBack, True);// then
+// Application.MessageBox ('Error playing stream!', 'Error');
+end;
+
+procedure TMusic.PlaySwoosh;
+begin
+// MediaPlayerSwoosh.Rewind;
+// MediaPlayerSwoosh.Play;
+ BASS_ChannelPlay(BassSwoosh, True);
+end;
+
+procedure TMusic.PlayChange;
+begin
+// MediaPlayerChange.Rewind;
+// MediaPlayerChange.Play;
+ BASS_ChannelPlay(BassChange, True);
+end;
+
+procedure TMusic.PlayOption;
+begin
+// MediaPlayerOption.Rewind;
+// MediaPlayerOption.Play;
+ BASS_ChannelPlay(BassOption, True);
+end;
+
+procedure TMusic.PlayClick;
+begin
+// MediaPlayerClick.Rewind;
+// MediaPlayerClick.Play;
+ BASS_ChannelPlay(BassClick, True);
+end;
+
+procedure TMusic.PlayDrum;
+begin
+// MediaPlayerDrum.Rewind;
+// MediaPlayerDrum.Play;
+ BASS_ChannelPlay(BassDrum, True);
+end;
+
+procedure TMusic.PlayHihat;
+begin
+// MediaPlayerHihat.Rewind;
+// MediaPlayerHihat.Play;
+ BASS_ChannelPlay(BassHihat, True);
+end;
+
+procedure TMusic.PlayClap;
+begin
+// MediaPlayerClap.Rewind;
+// MediaPlayerClap.Play;
+ BASS_ChannelPlay(BassClap, True);
+end;
+
+procedure TMusic.PlayShuffle;
+begin
+// MediaPlayerShuffle.Rewind;
+// MediaPlayerShuffle.Play;
+ BASS_ChannelPlay(BassShuffle, True);
+end;
+
+procedure TMusic.StopShuffle;
+begin
+ BASS_ChannelStop(BassShuffle);
+end;
+
+procedure TMusic.PlayApplause;
+begin
+// MediaPlayerShuffle.Rewind;
+// MediaPlayerShuffle.Play;
+ BASS_ChannelPlay(BassApplause, True);
+end;
+
+procedure TMusic.CaptureStart;
+var
+ S: integer;
+ SC: integer;
+ P1: integer;
+ P2: integer;
+begin
+ for S := 0 to High(Sound) do
+ Sound[S].BufferLong[0].Clear;
+
+{ case PlayersPlay of
+ 1: begin
+ CaptureCard(0, 0, 1, 0);
+ end;
+ 2: begin
+ if Ini.TwoPlayerMode = 0 then begin
+ CaptureCard(0, 0, 1, 2);
+ end else begin
+ CaptureCard(0, 0, 1, 0);
+ CaptureCard(1, 1, 2, 0);
+ end;
+ end;
+ 3: begin
+ CaptureCard(0, 0, 1, 2);
+ CaptureCard(1, 1, 3, 0);
+ end;
+ end; // case}
+
+// CaptureCard(0, 0, 0, 0);
+// end;
+
+ {for SC := 0 to High(SoundCard) do begin
+ P1 := Ini.SoundCard[SC, 1];
+ P2 := Ini.SoundCard[SC, 2];
+ if P1 > PlayersPlay then P1 := 0;
+ if P2 > PlayersPlay then P2 := 0;
+ CaptureCard(SC, P1, P2);
+ end; }
+ // 0.5.2: new
+ for SC := 0 to High(Ini.CardList) do begin
+ P1 := Ini.CardList[SC].ChannelL;
+ P2 := Ini.CardList[SC].ChannelR;
+ if P1 > PlayersPlay then P1 := 0;
+ if P2 > PlayersPlay then P2 := 0;
+ if (P1 > 0) or (P2 > 0) then
+ CaptureCard(SC, P1, P2);
+ end;
+end;
+
+procedure TMusic.CaptureStop;
+var
+ SC: integer;
+ P1: integer;
+ P2: integer;
+begin
+{ if RecordSystem = 1 then begin
+ case PlayersPlay of
+ 1: begin
+ StopCard(0);
+ end;
+ 2: begin
+ if Ini.TwoPlayerMode = 0 then begin
+ StopCard(0);
+ end else begin
+ StopCard(0);
+ StopCard(1);
+ end;
+ end;
+ 3: begin
+ StopCard(0);
+ StopCard(1);
+ end;
+ end;
+ end;}
+
+ {for SC := 0 to High(SoundCard) do begin
+ StopCard(SC);
+ end; }
+
+ // 0.5.2
+ for SC := 0 to High(Ini.CardList) do begin
+ P1 := Ini.CardList[SC].ChannelL;
+ P2 := Ini.CardList[SC].ChannelR;
+ if P1 > PlayersPlay then P1 := 0;
+ if P2 > PlayersPlay then P2 := 0;
+ if (P1 > 0) or (P2 > 0) then StopCard(SC);
+ end;
+
+end;
+
+//procedure TMusic.CaptureCard(RecordI, SoundNum, PlayerLeft, PlayerRight: byte);
+procedure TMusic.CaptureCard(RecordI, PlayerLeft, PlayerRight: byte);
+var
+ Error: integer;
+ ErrorMsg: string;
+begin
+ if not BASS_RecordInit(RecordI) then begin
+ Error := BASS_ErrorGetCode;
+
+ ErrorMsg := IntToStr(Error);
+ if Error = BASS_ERROR_DX then ErrorMsg := 'No DX5';
+ if Error = BASS_ERROR_ALREADY then ErrorMsg := 'The device has already been initialized';
+ if Error = BASS_ERROR_DEVICE then ErrorMsg := 'The device number specified is invalid';
+ if Error = BASS_ERROR_DRIVER then ErrorMsg := 'There is no available device driver';
+
+ {Log.LogAnalyze('Error initializing record [' + IntToStr(RecordI) + ', '
+ + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: '
+ + ErrorMsg);}
+ Log.LogError('Error initializing record [' + IntToStr(RecordI) + ', '
+ + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: '
+ + ErrorMsg);
+ Log.LogError('Music -> CaptureCard: Error initializing record: ' + ErrorMsg);
+
+
+ end else begin
+
+ //SoundCard[RecordI].BassRecordStream := BASS_RecordStart(44100, 2, MakeLong(0, 20) , @GetMicrophone, PlayerLeft + PlayerRight*256);
+ Recording.SoundCard[RecordI].BassRecordStream := BASS_RecordStart(44100, 2, MakeLong(0, 20) , @GetMicrophone, PlayerLeft + PlayerRight*256);
+
+ {if SoundCard[RecordI].BassRecordStream = 0 then begin
+ Error := BASS_ErrorGetCode;
+
+ ErrorMsg := IntToStr(Error);
+ if Error = BASS_ERROR_INIT then ErrorMsg := 'Not successfully called';
+ if Error = BASS_ERROR_ALREADY then ErrorMsg := 'Recording is already in progress';
+ if Error = BASS_ERROR_NOTAVAIL then ErrorMsg := 'The recording device is not available';
+ if Error = BASS_ERROR_FORMAT then ErrorMsg := 'The specified format is not supported';
+ if Error = BASS_ERROR_MEM then ErrorMsg := 'There is insufficent memory';
+ if Error = BASS_ERROR_UNKNOWN then ErrorMsg := 'Unknown';
+
+ Log.LogError('Error creating record stream [' + IntToStr(RecordI) + ', '
+ + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: '
+ + ErrorMsg);
+ end; }
+ end;
+end;
+
+procedure TMusic.StopCard(Card: byte);
+begin
+ BASS_RecordSetDevice(Card);
+ BASS_RecordFree;
+end;
+
+function TMusic.LoadPlayerFromFile(var MediaPlayer: TMediaPlayer; Name: string): boolean;
+begin
+ Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadPlayerFromFile');
+ if FileExists(Name) then begin
+ try
+ MediaPlayer := TMediaPlayer.Create( nil );
+ except
+ Log.LogError('Failed to create MediaPlayer', 'LoadPlayerFromFile');
+ end;
+ try
+ MediaPlayer.ParentWindow := fHWND;
+ MediaPlayer.Wait := true;
+ MediaPlayer.FileName := Name;
+ MediaPlayer.DeviceType := dtAutoSelect;
+ MediaPlayer.Display := nil;
+ except
+ Log.LogError('Failed setting MediaPlayer: ' + MediaPlayer.ErrorMessage, 'LoadPlayerFromFile');
+ end;
+ try
+ MediaPlayer.Open;
+ except
+ Log.LogError('Failed to open using MediaPlayer', 'LoadPlayerFromFile');
+ end;
+ end else begin
+ Log.LogError('Sound not found: "' + Name + '"', 'LoadPlayerFromFile');
+ exit;
+ end;
+end;
+
+function TMusic.LoadSoundFromFile(var hStream: hStream; Name: string): boolean;
+var
+ L: Integer;
+begin
+ if FileExists(Name) then begin
+ Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadPlayerFromFile');
+ try
+ hStream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0);
+ //Add CustomSound
+ L := High(CustomSounds) + 1;
+ SetLength (CustomSounds, L + 1);
+ CustomSounds[L].Filename := Name;
+ CustomSounds[L].Handle := hStream;
+ except
+ Log.LogError('Failed to open using BASS', 'LoadPlayerFromFile');
+ end;
+ end else begin
+ Log.LogError('Sound not found: "' + Name + '"', 'LoadPlayerFromFile');
+ exit;
+ end;
+end;
+
+//Equalizer
+function TMusic.GetFFTData: TFFTData;
+var
+Data: TFFTData;
+begin
+ //Get Channel Data Mono and 256 Values
+ BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512);
+ //Result := Data;
+end;
+
+function TMusic.LoadCustomSound(const Filename: String): Cardinal;
+var
+ S: hStream;
+ I: Integer;
+ F: String;
+begin
+ //Search for Sound in already loaded Sounds
+ F := UpperCase(SoundPath + FileName);
+ For I := 0 to High(CustomSounds) do
+ begin
+ if (UpperCase(CustomSounds[I].Filename) = F) then
+ begin
+ Result := I;
+ Exit;
+ end;
+ end;
+
+ if LoadSoundFromFile(S, SoundPath + Filename) then
+ Result := High(CustomSounds)
+ else
+ Result := 0;
+end;
+
+procedure TMusic.PlayCustomSound(const Index: Cardinal);
+begin
+if Index <= High(CustomSounds) then
+ BASS_ChannelPlay(CustomSounds[Index].Handle, True);
+end;
+
+procedure TMusic.EnableVocalRemover;
+begin
+ if DSP_VocalRemover=0 then
+ DSP_VocalRemover := Bass_ChannelSetDSP(Bass, @SBVocalCut16, 0, 0);
+
+end;
+
+procedure TMusic.DisableVocalRemover;
+begin
+ if DSP_VocalRemover<>0 then
+ begin
+ BASS_ChannelRemoveDSP(Bass, DSP_VocalRemover);
+ DSP_VocalRemover := 0;
+ end;
+end;
+
+function TMusic.VocalRemoverActivated(): boolean;
+begin
+ Result := (DSP_VocalRemover <> 0);
+end;
+
+end.
diff --git a/Game/Code/Classes/UParty.pas b/Game/Code/Classes/UParty.pas
new file mode 100644
index 00000000..2887f68c
--- /dev/null
+++ b/Game/Code/Classes/UParty.pas
@@ -0,0 +1,433 @@
+unit UParty;
+
+interface
+
+uses ModiSDK;
+
+type
+ TRoundInfo = record
+ Plugin: Word;
+ PluginNr: Integer;
+ Medley: boolean;
+ MedleySurprise: boolean;
+ Winner: Byte;
+ end;
+
+ TeamOrderEntry = record
+ Teamnum: Byte;
+ Score: Byte;
+ end;
+
+ TeamOrderArray = Array[0..5] of Byte;
+
+ TPartyPlugin = record
+ ID: byte;
+ TimesPlayed: byte;
+ Medley: boolean;
+ MedleySurprise: boolean;
+ Selected: boolean;
+ Name: string;
+ Desc: string;
+ end;
+
+ TParty_Session = class
+ private
+ function GetRandomPlayer(Team: Byte): Byte;
+ function GetRandomPlugin(var medley: boolean; var surprise: boolean; var nr: integer): byte;
+ function IsWinner(Player, Winner: Byte): boolean;
+ procedure GenScores;
+ public
+ Plugins: array of TPartyPlugin;
+ Teams: TTeamInfo;
+ Rounds: array of TRoundInfo;
+ CurRound: Byte;
+
+ constructor Create;
+
+ procedure StartNewParty(NumRounds: Byte);
+ procedure StartRound;
+ procedure EndRound;
+ function GetTeamOrder: TeamOrderArray;
+ function GetWinnerString(Round: Byte): String;
+ end;
+
+var
+ PartySession: TParty_Session;
+
+implementation
+
+uses UDLLManager, UGraphic, UMain, ULanguage, ULog;
+
+//----------
+//Constructor - Prepares the Class
+//----------
+constructor TParty_Session.Create;
+begin
+// - Nothing in here atm
+end;
+
+//----------
+// Returns a number of a random plugin (New Version)
+//----------
+function TParty_Session.GetRandomPlugin(var medley: boolean; var surprise: boolean; var nr: integer): byte;
+Type
+ TOrder = record
+ ID: integer;
+ medley: boolean;
+ surprise: boolean;
+ Nr: integer;
+ end;
+
+ function getTimesPlayed(order: TOrder): integer;
+ var
+ I: integer;
+ begin
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if (order.ID = Plugins[I].ID) and (order.medley = Plugins[I].medley) then
+ begin
+ Result:=Plugins[I].TimesPlayed;
+ break;
+ end;
+ end;
+ end;
+
+var
+ I, J, K, num: Integer;
+ plugin_order: array of TOrder;
+ temp: TOrder;
+ min: integer;
+
+begin
+ min := high(min);
+ SetLength(plugin_order, Length(Plugins));
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ plugin_order[I].ID := Plugins[I].ID;
+ plugin_order[I].medley := Plugins[I].Medley;
+ plugin_order[I].surprise := Plugins[I].MedleySurprise;
+ plugin_order[I].Nr := I;
+ if Plugins[I].TimesPlayed < min then
+ min := Plugins[I].TimesPlayed;
+ end;
+
+ //sort ASC by TimesPlayed
+ for J := 0 to Length(Plugins) - 2 do
+ begin
+ for K := J+1 to Length(Plugins) - 1 do
+ begin
+ if getTimesPlayed(plugin_order[J]) > getTimesPlayed(plugin_order[K]) then
+ begin
+ temp := plugin_order[J];
+ plugin_order[J] := plugin_order[K];
+ plugin_order[K] := temp;
+ end;
+ end;
+ end;
+
+ //set filter
+ num := 0;
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if Plugins[I].TimesPlayed <= min then
+ Inc(num);
+ end;
+
+ K := random(num);
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if (plugin_order[K].ID = Plugins[I].ID) and
+ (plugin_order[K].medley = Plugins[I].medley) then
+ begin
+ Inc(Plugins[I].TimesPlayed);
+ break;
+ end;
+ end;
+ medley := plugin_order[K].medley;
+ nr := plugin_order[K].Nr;
+ surprise := plugin_order[K].surprise;
+ Result := plugin_order[K].ID;
+end;
+
+//----------
+//StartNewParty - Clears the Class and Prepares for new Party
+//----------
+procedure TParty_Session.StartNewParty(NumRounds: Byte);
+var
+ TeamMode: Boolean;
+ Len: Integer;
+ I, J: Integer;
+ NumMedleys: Integer;
+
+begin
+ //Set cur Round to Round 1
+ CurRound := 255;
+
+ //Set Rounds
+ NumMedleys := 0;
+ If (Length(Plugins) >= 1) then
+ begin
+ SetLength (Rounds, NumRounds);
+ For I := 0 to NumRounds-1 do
+ begin
+ PartySession.Rounds[I].Plugin := GetRandomPlugin(PartySession.Rounds[I].Medley,
+ PartySession.Rounds[I].MedleySurprise,
+ PartySession.Rounds[I].PluginNr);
+ PartySession.Rounds[I].Winner := 255;
+
+ if PartySession.Rounds[I].Medley then
+ inc(NumMedleys);
+ end;
+ end
+ else SetLength (Rounds, 0);
+
+ PlayersPlay := Teams.NumTeams;
+
+ //Get Teammode and Set Joker, also set TimesPlayed
+ TeamMode := True;
+ For I := 0 to Teams.NumTeams-1 do
+ begin
+ if Teams.Teaminfo[I].NumPlayers < 2 then
+ begin
+ TeamMode := False;
+ end;
+ //Set Player Attributes
+ For J := 0 to Teams.TeamInfo[I].NumPlayers-1 do
+ begin
+ Teams.TeamInfo[I].Playerinfo[J].TimesPlayed := 0;
+ end;
+ Teams.Teaminfo[I].Joker := Round(NumRounds*0.7)+NumMedleys;
+ Teams.Teaminfo[I].Score := 0;
+ end;
+end;
+
+//----------
+//GetRandomPlayer - Gives back a Random Player to Play next Round
+//----------
+function TParty_Session.GetRandomPlayer(Team: Byte): Byte;
+var
+ I, R: Integer;
+ lowestTP: Byte;
+ NumPwithLTP: Byte;
+begin
+ LowestTP := high(Byte);
+ NumPwithLTP := 0;
+ Result := 0;
+
+ //Search for Players that have not often played yet
+ For I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do
+ begin
+ if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed < lowestTP) then
+ begin
+ lowestTP := Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed;
+ NumPwithLTP := 1;
+ end
+ else if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP) then
+ begin
+ Inc(NumPwithLTP);
+ end;
+ end;
+
+ //Create Random No
+ R := Random(NumPwithLTP);
+
+ //Search for Random Player
+ For I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do
+ begin
+ if Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP then
+ begin
+ //Player Found
+ if (R = 0) then
+ begin
+ Result := I;
+ Break;
+ end;
+
+ Dec(R);
+ end;
+ end;
+end;
+
+//----------
+//StartNextRound - Prepares ScreenSingModi for Next Round And Load Plugin
+//----------
+procedure TParty_Session.StartRound;
+var
+ I: Integer;
+begin
+ if ((CurRound < high(Rounds)) OR (CurRound = high(CurRound))) then
+ begin
+ //Increase Current Round
+ Inc (CurRound);
+
+ Rounds[CurRound].Winner := 255;
+ DllMan.LoadPlugin(Rounds[CurRound].Plugin);
+
+ //Select Players
+ for I := 0 to Teams.NumTeams-1 do
+ Teams.Teaminfo[I].CurPlayer := GetRandomPlayer(I);
+
+ //Set ScreenSingModie Variables
+ ScreenSingModi.TeamInfo := Teams;
+
+ //Set
+ end;
+end;
+
+//----------
+//IsWinner - Returns True if the Players Bit is set in the Winner Byte
+//----------
+function TParty_Session.IsWinner(Player, Winner: Byte): boolean;
+var
+ Bit: Byte;
+begin
+ Case Player of
+ 0: Bit := 1;
+ 1: Bit := 2;
+ 2: Bit := 4;
+ 3: Bit := 8;
+ 4: Bit := 16;
+ 5: Bit := 32;
+ end;
+
+ Result := ((Winner AND Bit) = Bit);
+end;
+
+//----------
+//GenScores - Inc Scores for Cur. Round
+//----------
+procedure TParty_Session.GenScores;
+var
+ I: Byte;
+begin
+ for I := 0 to Teams.NumTeams-1 do
+ begin
+ if isWinner(I, Rounds[CurRound].Winner) then
+ Inc(Teams.Teaminfo[I].Score);
+ end;
+end;
+
+//----------
+//GetWinnerString - Get String with WinnerTeam Name, when there is more than one Winner than Connect with and or ,
+//----------
+function TParty_Session.GetWinnerString(Round: Byte): String;
+var
+ Winners: Array of String;
+ I: Integer;
+begin
+ Result := Language.Translate('PARTY_NOBODY');
+
+ if (Round > High(Rounds)) then
+ exit;
+
+ if (Rounds[Round].Winner = 0) then
+ begin
+ exit;
+ end;
+
+ if (Rounds[Round].Winner = 255) then
+ begin
+ Result := Language.Translate('PARTY_NOTPLAYEDYET');
+ exit;
+ end;
+
+ SetLength(Winners, 0);
+ for I := 0 to Teams.NumTeams-1 do
+ begin
+ if isWinner(I, Rounds[Round].Winner) then
+ begin
+ SetLength(Winners, Length(Winners) + 1);
+ Winners[high(Winners)] := Teams.TeamInfo[I].Name;
+ end;
+ end;
+ Result := Language.Implode(Winners);
+end;
+
+//----------
+//EndRound - Get Winner from ScreenSingModi and Save Data to RoundArray
+//----------
+procedure TParty_Session.EndRound;
+var
+ I, MaxScore: Integer;
+begin
+ //Copy Winner
+ if Rounds[CurRound].Medley then
+ begin
+ Rounds[CurRound].Winner := 0;
+ MaxScore := 0;
+ for I := 0 to ScreenSingModi.PlayerInfo.NumPlayers-1 do
+ begin
+ ScreenSingModi.PlayerInfo.Playerinfo[I].Percentage :=
+ ScreenSingModi.PlayerInfo.Playerinfo[I].Score div 9999;
+ if (ScreenSingModi.PlayerInfo.Playerinfo[I].Score > MaxScore) then
+ begin
+ MaxScore := ScreenSingModi.PlayerInfo.Playerinfo[I].Score;
+ Case I of
+ 0: Rounds[CurRound].Winner := 1;
+ 1: Rounds[CurRound].Winner := 2;
+ 2: Rounds[CurRound].Winner := 4;
+ 3: Rounds[CurRound].Winner := 8;
+ 4: Rounds[CurRound].Winner := 16;
+ 5: Rounds[CurRound].Winner := 32;
+ end;
+ end
+ else if (ScreenSingModi.PlayerInfo.Playerinfo[I].Score = MaxScore) AND
+ (ScreenSingModi.PlayerInfo.Playerinfo[I].Score <> 0) then
+ begin
+ Case I of
+ 0: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 1;
+ 1: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 2;
+ 2: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 4;
+ 3: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 8;
+ 4: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 16;
+ 5: Rounds[CurRound].Winner := Rounds[CurRound].Winner OR 32;
+ end;
+ end;
+ end;
+
+ //When nobody has Points -> Everybody loose
+ if (MaxScore = 0) then
+ Rounds[CurRound].Winner := 0;
+ end else
+ Rounds[CurRound].Winner := ScreenSingModi.Winner;
+ //Set Scores
+ GenScores;
+
+ //Increase TimesPlayed 4 all Players
+ For I := 0 to Teams.NumTeams-1 do
+ Inc(Teams.Teaminfo[I].Playerinfo[Teams.Teaminfo[I].CurPlayer].TimesPlayed);
+
+end;
+
+//----------
+//GetTeamOrder - Gives back the Placing of eacb Team [First Position of Array is Teamnum of first placed Team, ...]
+//----------
+function TParty_Session.GetTeamOrder: TeamOrderArray;
+var
+ I, J: Integer;
+ ATeams: array [0..5] of TeamOrderEntry;
+ TempTeam: TeamOrderEntry;
+begin
+ //Fill Team Array
+ For I := 0 to Teams.NumTeams-1 do
+ begin
+ ATeams[I].Teamnum := I;
+ ATeams[I].Score := Teams.Teaminfo[I].Score;
+ end;
+
+ //Sort Teams
+ for J := 0 to Teams.NumTeams-1 do
+ for I := 1 to Teams.NumTeams-1 do
+ if ATeams[I].Score > ATeams[I-1].Score then
+ begin
+ TempTeam := ATeams[I-1];
+ ATeams[I-1] := ATeams[I];
+ ATeams[I] := TempTeam;
+ end;
+
+ //Copy to Result
+ For I := 0 to Teams.NumTeams-1 do
+ Result[I] := ATeams[I].TeamNum;
+end;
+
+end.
diff --git a/Game/Code/Classes/UPartyM2.pas b/Game/Code/Classes/UPartyM2.pas
new file mode 100644
index 00000000..0b7dd3bd
--- /dev/null
+++ b/Game/Code/Classes/UPartyM2.pas
@@ -0,0 +1,693 @@
+unit UPartyM2;
+
+interface
+
+uses
+ ModiSDK, UDatabase;
+
+type
+ TRoundInfo = record
+ Winner: byte;
+ Plugin: word;
+ Medley: boolean;
+ MedleySurprise: boolean;
+ PluginNr: Integer;
+ Player1: byte;
+ Player2: byte;
+ ScoreP: Integer;
+ ScoreN: Integer;
+ end;
+
+ TPair = record
+ Player1: byte;
+ Player2: byte;
+ played: integer;
+ origin: integer;
+ end;
+
+ TSongsPlayed = record
+ cat: integer;
+ Played: array of integer;
+ end;
+
+ PlayerOrderArray = array[0..8] of byte;
+
+ TPartyPlugin = record
+ ID: byte;
+ TimesPlayed: byte;
+ Medley: boolean;
+ MedleySurprise: boolean;
+ Selected: boolean;
+ Name: string;
+ Desc: string;
+ end;
+
+ TPartySessionM2 = class
+ private
+ Pairs: array of TPair;
+ SongsPlayed: array of TSongsPlayed;
+ function GetRandomPlugin(var medley: boolean; var surprise: boolean; var nr: integer): byte;
+
+ public
+ Rounds: array of TRoundInfo;
+
+ Plugins: array of TPartyPlugin;
+
+ Handicap: THandicapResult;
+ HandicapMode: boolean;
+
+ NumRounds: byte;
+ CurRound: byte;
+ Players: TPlayersInfo;
+ Teams: TTeamInfo;
+ Order: PlayerOrderArray;
+ Option_Plugins: boolean;
+ constructor Create;
+
+ procedure GenScores;
+ procedure StartNewParty(NumPlayers: byte; nRounds: byte);
+ procedure StartRound;
+ procedure EndRound;
+ procedure BuildOrder;
+ procedure AddSongPlayed(cat: Integer; SongNr: integer);
+ procedure ResetSongsPlayed(cat: Integer);
+ function SongPlayed(cat: Integer; SongNr: integer): boolean;
+ function GetSongsPlayed(cat: Integer): integer;
+ function GetCatIndex(cat: Integer): Integer;
+ end;
+
+var
+ PartySessionM2: TPartySessionM2;
+
+implementation
+
+uses
+ UDLLManager,
+ UGraphic,
+ ULanguage,
+ UMain,
+ Math,
+ ULog;
+
+constructor TPartySessionM2.Create;
+begin
+ inherited;
+end;
+
+function TPartySessionM2.SongPlayed(cat: integer; SongNr: integer): boolean;
+var
+ i: integer;
+ played :boolean;
+ catIndex: integer;
+begin
+ played := false;
+ catIndex:=GetCatIndex(cat);
+ for i := 0 to Length(PartySessionM2.SongsPlayed[catIndex].Played) - 1 do
+ begin
+ if (SongNr=PartySessionM2.SongsPlayed[catIndex].Played[i]) then
+ begin
+ played:=true;
+ break;
+ end;
+ end;
+ Result:=played;
+end;
+
+function TPartySessionM2.GetSongsPlayed(cat: integer): Integer;
+var
+ CatIndex: integer;
+begin
+ CatIndex := GetCatIndex(cat);
+ Result := Length(PartySessionM2.SongsPlayed[CatIndex].Played);
+end;
+
+procedure TPartySessionM2.ResetSongsPlayed(cat: Integer);
+var
+ CatIndex: integer;
+begin
+ CatIndex := GetCatIndex(cat);
+ SetLength(SongsPlayed[CatIndex].Played, 0);
+end;
+
+
+procedure TPartySessionM2.AddSongPlayed(cat: integer; SongNr: integer);
+var
+ catIndex: integer;
+begin
+ catIndex:=GetCatIndex(cat);
+ SetLength(PartySessionM2.SongsPlayed[catIndex].Played, Length(PartySessionM2.SongsPlayed[catIndex].Played)+1);
+ PartySessionM2.SongsPlayed[catIndex].Played[Length(PartySessionM2.SongsPlayed[catIndex].Played)-1]:=SongNr;
+end;
+
+function TPartySessionM2.GetCatIndex(cat: Integer): Integer;
+var
+ i: integer;
+ found: boolean;
+begin
+ found:=false;
+ for i := 0 to length(SongsPlayed) - 1 do
+ begin
+ if SongsPlayed[i].cat = cat then
+ begin
+ Result:=i;
+ found:=true;
+ break;
+ end;
+ end;
+ if not found then
+ begin
+ SetLength(SongsPlayed, Length(SongsPlayed)+1);
+ SongsPlayed[Length(SongsPlayed)-1].cat:=cat;
+ Result:=Length(SongsPlayed)-1;
+ end;
+end;
+
+procedure TPartySessionM2.BuildOrder();
+var
+ I,J: integer;
+ cache: byte;
+begin
+ for I := 0 to Players.NumPlayer-2 do
+ begin
+ for J := I+1 to Players.NumPlayer - 1 do
+ begin
+ if (Players.Playerinfo[Order[I]].Points < Players.Playerinfo[Order[J]].Points) then
+ begin
+ cache:=Order[I];
+ Order[I]:=Order[J];
+ Order[J]:=cache;
+ end else if (Players.Playerinfo[Order[I]].Points = Players.Playerinfo[Order[J]].Points) and
+ ((Players.Playerinfo[Order[I]].ScoreP-Players.Playerinfo[Order[I]].ScoreN) <
+ (Players.Playerinfo[Order[J]].ScoreP - Players.Playerinfo[Order[J]].ScoreN)) then
+ begin
+ cache:=Order[I];
+ Order[I]:=Order[J];
+ Order[J]:=cache;
+ end;
+ end;
+ end;
+end;
+
+
+//----------
+//StartNewParty - Reset and prepares for new party
+//----------
+procedure TPartySessionM2.StartNewParty(NumPlayers: byte; nRounds: byte);
+type
+ TFields = record
+ x: byte;
+ y: byte;
+ end;
+
+ TPlayer = record
+ Player: byte;
+ played: integer;
+ end;
+
+ TRN = record
+ rounds: array of integer;
+ end;
+
+ //if the player has played the last 2 rounds
+ function HasPlayed(Pair: TPair; ar: array of TFields; r: integer; num: integer): boolean;
+ begin
+ //first round
+ if r<2 then
+ Result:=false
+
+ //exactly the same combination in last round
+ else if (ar[r-2].x=Pair.Player1) and (ar[r-2].y=Pair.Player2) then
+ Result:=true
+
+ //only two Players => there are no other combinations
+ else if num<3 then
+ Result:=false
+
+ //reversed combination before
+ else if (ar[r-2].x=Pair.Player2) and (ar[r-2].y=Pair.Player1) then
+ Result:=true
+
+ //it is the second round
+ else if r<3 then
+ Result:=false
+
+ //
+ else if
+ ((ar[r-2].x = Pair.Player1) and (ar[r-3].x = Pair.Player1)) or
+ ((ar[r-2].x = Pair.Player1) and (ar[r-3].y = Pair.Player1)) or
+ ((ar[r-2].y = Pair.Player1) and (ar[r-3].x = Pair.Player1)) or
+ ((ar[r-2].y = Pair.Player1) and (ar[r-3].y = Pair.Player1)) or
+ ((ar[r-2].x = Pair.Player2) and (ar[r-3].x = Pair.Player2)) or
+ ((ar[r-2].x = Pair.Player2) and (ar[r-3].y = Pair.Player2)) or
+ ((ar[r-2].y = Pair.Player2) and (ar[r-3].x = Pair.Player2)) or
+ ((ar[r-2].y = Pair.Player2) and (ar[r-3].y = Pair.Player2))then
+
+ Result:=true
+
+ else
+ Result:=false;
+ end;
+
+var
+ Player: array of TPlayer;
+ PlayerOrder: array of integer;
+ Len: integer;
+ I, J, K: integer;
+ arr: array of TFields;
+ temp_pairs: array of TPair;
+ season: integer;
+ num: integer;
+ max_played: integer;
+ max_flag: boolean;
+ must_sing: integer;
+
+ //debug
+ rn: array of TRN;
+
+begin
+ //Set current round to 1
+ CurRound := 255;
+ NumRounds:= nRounds;
+ for I := 0 to 8 do
+ begin
+ Order[I]:=I;
+ end;
+
+ //build all possible pairs
+ SetLength(Pairs, 0);
+ SetLength(Player, NumPlayers);
+ num:=0;
+
+ for I := 0 to NumPlayers - 1 do
+ begin
+ Player[I].Player:=I;
+ Player[I].played:=0;
+ end;
+
+ for I := 1 to NumPlayers - 1 do
+ begin
+ for J := I+1 to NumPlayers do
+ begin
+ SetLength(Pairs, Length(Pairs)+1);
+ Pairs[Length(Pairs)-1].Player1:=I-1;
+ Pairs[Length(Pairs)-1].Player2:=J-1;
+ Pairs[Length(Pairs)-1].played:=0;
+ Pairs[Length(Pairs)-1].origin:=num;
+ inc(num);
+ SetLength(Pairs, Length(Pairs)+1);
+ Pairs[Length(Pairs)-1].Player1:=J-1;
+ Pairs[Length(Pairs)-1].Player2:=I-1;
+ Pairs[Length(Pairs)-1].played:=0;
+ Pairs[Length(Pairs)-1].origin:=num;
+ inc(num);
+ end;
+ end;
+
+ //build the playlist
+ SetLength (arr, 0);
+ SetLength (arr, NumRounds);
+ Randomize;
+
+ for I := 0 to NumRounds - 1 do
+ begin
+ //filter pairs
+ season:=Floor((I)/(NumPlayers*NumPlayers-NumPlayers))+1; //complete season
+
+ SetLength(temp_pairs, 0);
+
+ max_flag := false;
+ max_played := 0;
+
+
+ for K := 0 to NumPlayers - 1 do
+ begin
+ if (max_played<Player[K].played) then
+ max_played := Player[K].played;
+ end;
+
+ J := 0;
+ for K := 0 to NumPlayers - 1 do
+ begin
+ if (max_played>Player[K].played) then
+ inc(J);
+ end;
+
+ must_sing := -1;
+ if J>1 then
+ max_flag := true
+ else if J=1 then
+ begin
+ for K := 0 to NumPlayers - 1 do
+ begin
+ if (max_played>Player[K].played) then
+ must_sing:=K;
+ end;
+ end;
+
+ for J := 0 to Length(Pairs) - 1 do
+ begin
+ if (not HasPlayed(Pairs[J], arr, I+1, NumPlayers)) and
+ (Pairs[J].played<season) then
+ begin
+ if (not max_flag and (must_sing=-1)) or
+ ((must_sing>=0) and (
+ (Pairs[J].Player1=must_sing) or
+ (Pairs[J].Player2=must_sing))) or
+ (max_flag and (
+ (Player[Pairs[J].Player1].played<max_played) and
+ (Player[Pairs[J].Player2].played<max_played))) then
+ begin
+ SetLength(temp_pairs, Length(temp_pairs)+1);
+ temp_pairs[Length(temp_pairs)-1]:=Pairs[J];
+ end;
+ end;
+ end;
+
+ //first fallback
+ if Length(temp_pairs)=0 then
+ begin
+ for J := 0 to Length(Pairs) - 1 do
+ begin
+ if (max_flag and (
+ (Player[Pairs[J].Player1].played<max_played) and
+ (Player[Pairs[J].Player2].played<max_played))) then
+ begin
+ SetLength(temp_pairs, Length(temp_pairs)+1);
+ temp_pairs[Length(temp_pairs)-1]:=Pairs[J];
+ end;
+ end;
+ end;
+
+ //second fallback
+ if Length(temp_pairs)=0 then
+ begin
+ for J := 0 to Length(Pairs) - 1 do
+ begin
+ if (not HasPlayed(Pairs[J], arr, I+1, NumPlayers)) and
+ (Pairs[J].played<season) then
+ begin
+ SetLength(temp_pairs, Length(temp_pairs)+1);
+ temp_pairs[Length(temp_pairs)-1]:=Pairs[J];
+ end;
+ end;
+ end;
+
+ //last fallback
+ if Length(temp_pairs)=0 then
+ begin
+ for J := 0 to Length(Pairs) - 1 do
+ begin
+ SetLength(temp_pairs, Length(temp_pairs)+1);
+ temp_pairs[Length(temp_pairs)-1]:=Pairs[J];
+ end;
+ end;
+
+ num:=Random(Length(temp_pairs));
+
+ inc(Pairs[temp_pairs[num].origin].played);
+ arr[I].x:=temp_pairs[num].Player1;
+ arr[I].y:=temp_pairs[num].Player2;
+
+ inc(Player[arr[I].x].played);
+ inc(Player[arr[I].y].played);
+ end;
+
+ //debug
+ SetLength(rn, NumRounds+1);
+ SetLength(rn[0].rounds, NumPlayers);
+ for I := 1 to NumRounds do
+ begin
+ SetLength(rn[I].rounds, NumPlayers);
+ for J := 0 to NumPlayers - 1 do
+ begin
+ if (arr[I-1].x = J) or (arr[I-1].y = J) then
+ rn[I].rounds[J] := rn[I-1].rounds[J] + 1
+ else
+ rn[I].rounds[J] := rn[I-1].rounds[J];
+ end;
+ end;
+
+ Players.NumPlayer := NumPlayers;
+
+ //Set player attributes
+ for I := 0 to NumPlayers-1 do
+ begin
+ Players.Playerinfo[I].Points := 0;
+ Players.Playerinfo[I].ScoreP:= 0;
+ Players.Playerinfo[I].ScoreN:= 0;
+ Players.Playerinfo[I].Wins:= 0;
+ Players.Playerinfo[I].Defeats:= 0;
+ Players.Playerinfo[I].Draws:= 0;
+ Players.Playerinfo[I].Joker:= 0;
+ end;
+
+ //Set rounds
+ if (Length(Plugins) >= 1) then
+ begin
+ for I := 0 to NumRounds - 1 do
+ begin
+ SetLength (Rounds, I+1);
+ PartySessionM2.Rounds[I].Plugin := GetRandomPlugin(PartySessionM2.Rounds[I].Medley,
+ PartySessionM2.Rounds[I].MedleySurprise,
+ PartySessionM2.Rounds[I].PluginNr);
+
+ PartySessionM2.Rounds[I].Player1:=arr[I].x;
+ PartySessionM2.Rounds[I].Player2:=arr[I].y;
+ PartySessionM2.Rounds[I].ScoreP:=0;
+ PartySessionM2.Rounds[I].ScoreN:=0;
+ end;
+ end
+ else
+ SetLength (Rounds, 0);
+
+ //Reset SongsPlayed-Array
+ SetLength (PartySessionM2.SongsPlayed, 0);
+end;
+
+//----------
+// Returns a number of a random plugin (New Version)
+//----------
+function TPartySessionM2.GetRandomPlugin(var medley: boolean; var surprise: boolean; var nr: integer): byte;
+Type
+ TOrder = record
+ ID: integer;
+ medley: boolean;
+ surprise: boolean;
+ Nr: integer;
+ end;
+
+ function getTimesPlayed(order: TOrder): integer;
+ var
+ I: integer;
+ begin
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if (order.ID = Plugins[I].ID) and (order.medley = Plugins[I].medley) then
+ begin
+ Result:=Plugins[I].TimesPlayed;
+ break;
+ end;
+ end;
+ end;
+
+var
+ I, J, K, num: Integer;
+ plugin_order: array of TOrder;
+ temp: TOrder;
+ min: integer;
+
+begin
+ min := high(min);
+ SetLength(plugin_order, Length(Plugins));
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ plugin_order[I].ID := Plugins[I].ID;
+ plugin_order[I].medley := Plugins[I].Medley;
+ plugin_order[I].surprise := Plugins[I].MedleySurprise;
+ plugin_order[I].Nr := I;
+ if Plugins[I].TimesPlayed < min then
+ min := Plugins[I].TimesPlayed;
+ end;
+
+ //sort ASC by TimesPlayed
+ for J := 0 to Length(Plugins) - 2 do
+ begin
+ for K := J+1 to Length(Plugins) - 1 do
+ begin
+ if getTimesPlayed(plugin_order[J]) > getTimesPlayed(plugin_order[K]) then
+ begin
+ temp := plugin_order[J];
+ plugin_order[J] := plugin_order[K];
+ plugin_order[K] := temp;
+ end;
+ end;
+ end;
+
+ //set filter
+ num := 0;
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if Plugins[I].TimesPlayed <= min then
+ Inc(num);
+ end;
+
+ K := random(num);
+ for I := 0 to Length(Plugins) - 1 do
+ begin
+ if (plugin_order[K].ID = Plugins[I].ID) and
+ (plugin_order[K].medley = Plugins[I].medley) then
+ begin
+ Inc(Plugins[I].TimesPlayed);
+ break;
+ end;
+ end;
+ medley := plugin_order[K].medley;
+ surprise := plugin_order[K].surprise;
+ nr := plugin_order[K].Nr;
+ Result := plugin_order[K].ID;
+end;
+
+{**
+ * Prepares ScreenSingModiM2 for next round and loads plugin
+ *}
+procedure TPartySessionM2.StartRound;
+begin
+ if ((CurRound < Length(Rounds)) or (CurRound = high(CurRound))) then
+ begin
+ // Increase Current Round but not beyond its limit
+ // CurRound is set to 255 to begin with!
+ // Ugly solution if you ask me.
+ if CurRound < Length(Rounds) then
+ Inc(CurRound)
+ else
+ CurRound := 0;
+ BuildOrder;
+
+ if CurRound< Length(Rounds) then
+ begin
+ Rounds[CurRound].Winner := 255;
+ DllMan.LoadPlugin(Rounds[CurRound].Plugin);
+
+ //Select Players
+ Teams.NumTeams:=2;
+
+ Teams.Teaminfo[0].Name := 'T1';
+ Teams.Teaminfo[0].Score:=0;
+ Teams.Teaminfo[0].Joker:=5;
+ Teams.Teaminfo[0].CurPlayer:=0;
+ Teams.Teaminfo[0].NumPlayers:=1;
+ Teams.Teaminfo[0].Playerinfo[0].Name:=Players.Playerinfo[Rounds[CurRound].Player1].Name;
+ Teams.Teaminfo[0].Playerinfo[0].TimesPlayed:=0;
+
+ Teams.Teaminfo[1].Name := 'T2';
+ Teams.Teaminfo[1].Score:=0;
+ Teams.Teaminfo[1].Joker:=0;
+ Teams.Teaminfo[1].CurPlayer:=0;
+ Teams.Teaminfo[1].NumPlayers:=1;
+ Teams.Teaminfo[1].Playerinfo[0].Name:=Players.Playerinfo[Rounds[CurRound].Player2].Name;
+ Teams.Teaminfo[1].Playerinfo[0].TimesPlayed:=0;
+
+ if HandicapMode then
+ Handicap := DataBase.GetHandicap(Players.Playerinfo[Rounds[CurRound].Player1].Name,
+ Players.Playerinfo[Rounds[CurRound].Player2].Name)
+ else
+ begin
+ Handicap.P1m := 1;
+ Handicap.P2m := 1;
+ end;
+
+ //Set ScreenSingModi Variables
+ ScreenSingModi.TeamInfo := Teams;
+ end;
+ end;
+
+end;
+
+//----------
+//EndRound - Get Winner from ScreenSingModi and Save Data to RoundArray
+//----------
+procedure TPartySessionM2.EndRound;
+begin
+ //Copy Winner
+ if Rounds[CurRound].Medley then
+ begin
+ if (PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[0].ScoreTotalI>
+ PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[1].ScoreTotalI) then
+ Rounds[CurRound].Winner := 1
+ else if (PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[0].ScoreTotalI<
+ PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[1].ScoreTotalI) then
+ Rounds[CurRound].Winner := 2
+ else
+ Rounds[CurRound].Winner := 0;
+
+ ScreenSingModi.PlayerInfo.Playerinfo[0].Score := PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[0].ScoreTotalI;
+ ScreenSingModi.PlayerInfo.Playerinfo[1].Score := PlaylistMedley.Stats[Length(PlaylistMedley.Stats)-1].Player[1].ScoreTotalI;
+
+ end else
+ Rounds[CurRound].Winner := ScreenSingModi.Winner;
+
+ //Set Scores
+ GenScores;
+
+ //Update Player Stats
+
+end;
+
+//----------
+//GenScores - increase scores for current round
+//----------
+procedure TPartySessionM2.GenScores;
+begin
+ //Filter "Hau den Lukas"
+ if (DLLMan.Plugins[Rounds[CurRound].Plugin].Name='PLUGIN_HAUDENLUKAS_NAME') then
+ begin
+ ScreenSingModi.PlayerInfo.Playerinfo[0].Score := ScreenSingModi.PlayerInfo.Playerinfo[0].Score*1000;
+ ScreenSingModi.PlayerInfo.Playerinfo[1].Score := ScreenSingModi.PlayerInfo.Playerinfo[1].Score*1000;
+ end;
+
+
+ //Copy Scores to Rounds
+ Rounds[CurRound].ScoreP:=round(ScreenSingModi.PlayerInfo.Playerinfo[0].Score*Handicap.P1m);
+ Rounds[CurRound].ScoreN:=round(ScreenSingModi.PlayerInfo.Playerinfo[1].Score*Handicap.P2m);
+
+ //Update PlayerStats
+ Players.Playerinfo[Rounds[CurRound].Player1].ScoreP := Rounds[CurRound].ScoreP +
+ Players.Playerinfo[Rounds[CurRound].Player1].ScoreP;
+ Players.Playerinfo[Rounds[CurRound].Player1].ScoreN := Rounds[CurRound].ScoreN +
+ Players.Playerinfo[Rounds[CurRound].Player1].ScoreN;
+
+ Players.Playerinfo[Rounds[CurRound].Player2].ScoreP := Rounds[CurRound].ScoreN +
+ Players.Playerinfo[Rounds[CurRound].Player2].ScoreP;
+ Players.Playerinfo[Rounds[CurRound].Player2].ScoreN := Rounds[CurRound].ScoreP +
+ Players.Playerinfo[Rounds[CurRound].Player2].ScoreN;
+
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].NumPlayed);
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].NumPlayed);
+
+ if (HandicapMode and (Rounds[CurRound].ScoreP>Rounds[CurRound].ScoreN)) or
+ (not HandicapMode and (Rounds[CurRound].Winner = 1)) then //Player1 is the winner
+ begin
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Wins);
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Defeats);
+
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Points);
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Points);
+ end else if (HandicapMode and (Rounds[CurRound].ScoreP<Rounds[CurRound].ScoreN)) or
+ (not HandicapMode and (Rounds[CurRound].Winner = 2)) then //Player2 is the winner
+ begin
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Wins);
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Defeats);
+
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Points);
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Points);
+ end else //Draw
+ begin
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Draws);
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Draws);
+
+ inc(Players.Playerinfo[Rounds[CurRound].Player1].Points);
+ inc(Players.Playerinfo[Rounds[CurRound].Player2].Points);
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/UPlaylist.pas b/Game/Code/Classes/UPlaylist.pas
new file mode 100644
index 00000000..e3f68239
--- /dev/null
+++ b/Game/Code/Classes/UPlaylist.pas
@@ -0,0 +1,453 @@
+unit UPlaylist;
+
+interface
+
+type
+ TPlaylistItem = record
+ Artist: String;
+ Title: String;
+ SongID: Integer;
+ end;
+
+ APlaylistItem = array of TPlaylistItem;
+
+ TPlaylist = record
+ Name: String;
+ Filename: String;
+ Items: APlaylistItem;
+ end;
+
+ APlaylist = array of TPlaylist;
+
+ //----------
+ //TPlaylistManager - Class for Managing Playlists (Loading, Displaying, Saving)
+ //----------
+ TPlaylistManager = class
+ private
+
+ public
+ Mode: Byte; //Current Playlist Mode for SongScreen
+ CurPlayList: Cardinal;
+ CurItem: Cardinal;
+
+ Playlists: APlaylist;
+
+ constructor Create;
+ Procedure LoadPlayLists;
+ Function LoadPlayList(Index: Cardinal; Filename: String): Boolean;
+ Procedure SavePlayList(Index: Cardinal);
+
+ Procedure SetPlayList(Index: Cardinal);
+
+ Function AddPlaylist(Name: String): Cardinal;
+ Procedure DelPlaylist(const Index: Cardinal);
+
+ Procedure AddItem(const SongID: Cardinal; const iPlaylist: Integer = -1);
+ Procedure DelItem(const iItem: Cardinal; const iPlaylist: Integer = -1);
+
+ Procedure GetNames(var PLNames: array of String);
+ Function GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer = -1): Integer;
+ end;
+
+ {Modes:
+ 0: Standard Mode
+ 1: Category Mode
+ 2: PlayList Mode}
+
+ var
+ PlayListMan: TPlaylistManager;
+
+
+implementation
+uses USongs, ULog, UFiles, UGraphic, UThemes, SysUtils;
+
+//----------
+//Create - Construct Class - Dummy for now
+//----------
+constructor TPlayListManager.Create;
+begin
+ LoadPlayLists;
+end;
+
+//----------
+//LoadPlayLists - Load list of Playlists from PlayList Folder
+//----------
+Procedure TPlayListManager.LoadPlayLists;
+var
+ SR: TSearchRec;
+ Len: Integer;
+begin
+ SetLength(Playlists, 0);
+
+ if FindFirst(PlayListPath + '*.upl', 0, SR) = 0 then
+ begin
+ repeat
+ Len := Length(Playlists);
+ SetLength(Playlists, Len +1);
+
+ if not LoadPlayList (Len, Sr.Name) then
+ SetLength(Playlists, Len);
+
+ until FindNext(SR) <> 0;
+ FindClose(SR);
+ end;
+end;
+
+//----------
+//LoadPlayList - Load a Playlist in the Array
+//----------
+Function TPlayListManager.LoadPlayList(Index: Cardinal; Filename: String): Boolean;
+ var
+ F: TextFile;
+ Line: String;
+ PosDelimiter: Integer;
+ SongID: Integer;
+ Len: Integer;
+
+ Function FindSong(Artist, Title: String): Integer;
+ var I: Integer;
+ begin
+ Result := -1;
+
+ For I := low(CatSongs.Song) to high(CatSongs.Song) do
+ begin
+ if (CatSongs.Song[I].Title = Title) AND (CatSongs.Song[I].Artist = Artist) then
+ begin
+ Result := I;
+ Break;
+ end;
+ end;
+ end;
+begin
+ if not FileExists(PlayListPath + Filename) then
+ begin
+ Log.LogError('Could not load Playlist: ' + Filename);
+ Result := False;
+ Exit;
+ end;
+ Result := True;
+
+ //Load File
+ AssignFile(F, PlayListPath + FileName);
+ Reset(F);
+
+ //Set Filename
+ PlayLists[Index].Filename := Filename;
+ PlayLists[Index].Name := '';
+
+ //Read Until End of File
+ While not Eof(F) do
+ begin
+ //Read Curent Line
+ Readln(F, Line);
+
+ if (Length(Line) > 0) then
+ begin
+ PosDelimiter := Pos(':', Line);
+ if (PosDelimiter <> 0) then
+ begin
+ //Comment or Name String
+ if (Line[1] = '#') then
+ begin
+ //Found Name Value
+ if (Uppercase(Trim(copy(Line, 2, PosDelimiter - 2))) = 'NAME') then
+ PlayLists[Index].Name := Trim(copy(Line, PosDelimiter + 1,Length(Line) - PosDelimiter))
+
+ end
+ //Song Entry
+ else
+ begin
+ SongID := FindSong(Trim(copy(Line, 1, PosDelimiter - 1)), Trim(copy(Line, PosDelimiter + 1, Length(Line) - PosDelimiter)));
+ if (SongID <> -1) then
+ begin
+ Len := Length(PlayLists[Index].Items);
+ SetLength(PlayLists[Index].Items, Len + 1);
+
+ PlayLists[Index].Items[Len].SongID := SongID;
+
+ PlayLists[Index].Items[Len].Artist := Trim(copy(Line, 1, PosDelimiter - 1));
+ PlayLists[Index].Items[Len].Title := Trim(copy(Line, PosDelimiter + 1, Length(Line) - PosDelimiter));
+ end
+ else Log.LogError('Could not find Song in Playlist: ' + PlayLists[Index].Filename + ', ' + Line);
+ end;
+ end;
+ end;
+ end;
+
+ //If no special name is given, use Filename
+ if PlayLists[Index].Name = '' then
+ begin
+ PlayLists[Index].Name := ChangeFileExt(FileName, '');
+ end;
+
+ //Finish (Close File)
+ CloseFile(F);
+end;
+
+//----------
+//SavePlayList - Saves the specified Playlist
+//----------
+Procedure TPlayListManager.SavePlayList(Index: Cardinal);
+var
+ F: TextFile;
+ I: Integer;
+begin
+ if (Not FileExists(PlaylistPath + Playlists[Index].Filename)) OR (Not FileisReadOnly(PlaylistPath + Playlists[Index].Filename)) then
+ begin
+
+ //open File for Rewriting
+ AssignFile(F, PlaylistPath + Playlists[Index].Filename);
+ try
+ try
+ Rewrite(F);
+
+ //Write Version (not nessecary but helpful)
+ WriteLn(F, '######################################');
+ WriteLn(F, '#Ultrastar Deluxe Playlist Format v1.0');
+ WriteLn(F, '#Playlist "' + Playlists[Index].Name + '" with ' + InttoStr(Length(Playlists[Index].Items)) + ' Songs.');
+ WriteLn(F, '######################################');
+
+ //Write Name Information
+ WriteLn(F, '#Name: ' + Playlists[Index].Name);
+
+ //Write Song Information
+ WriteLn(F, '#Songs:');
+
+ For I := 0 to high(Playlists[Index].Items) do
+ begin
+ WriteLn(F, Playlists[Index].Items[I].Artist + ' : ' + Playlists[Index].Items[I].Title);
+ end;
+ except
+ log.LogError('Could not write Playlistfile "' + Playlists[Index].Name + '"');
+ end;
+ finally
+ CloseFile(F);
+ end;
+ end;
+end;
+
+//----------
+//SetPlayList - Display a Playlist in CatSongs
+//----------
+Procedure TPlayListManager.SetPlayList(Index: Cardinal);
+var
+ I: Integer;
+begin
+ If (Index > High(PlayLists)) then
+ exit;
+
+ //Hide all Songs
+ For I := 0 to high(CatSongs.Song) do
+ CatSongs.Song[I].Visible := False;
+
+ //Show Songs in PL
+ For I := 0 to high(PlayLists[Index].Items) do
+ begin
+ CatSongs.Song[PlayLists[Index].Items[I].SongID].Visible := True;
+ end;
+
+ //Set CatSongsMode + Playlist Mode
+ CatSongs.CatNumShow := -3;
+ Mode := 2;
+
+ //Set CurPlaylist
+ CurPlaylist := Index;
+
+ //Show Cat in Topleft:
+ ScreenSong.ShowCatTLCustom(Format(Theme.Playlist.CatText,[Playlists[Index].Name]));
+
+ //Fix SongSelection
+ ScreenSong.Interaction := 0;
+ ScreenSong.SelectNext;
+ ScreenSong.FixSelected;
+
+ //Play correct Music
+ ScreenSong.ChangeMusic;
+end;
+
+//----------
+//AddPlaylist - Adds a Playlist and Returns the Index
+//----------
+Function TPlayListManager.AddPlaylist(Name: String): Cardinal;
+var I: Integer;
+begin
+ Result := Length(Playlists);
+ SetLength(Playlists, Result + 1);
+
+ Playlists[Result].Name := Name;
+
+ I := 1;
+
+ if (not FileExists(PlaylistPath + Name + '.upl')) then
+ Playlists[Result].Filename := Name + '.upl'
+ else
+ begin
+ repeat
+ Inc(I);
+ until not FileExists(PlaylistPath + Name + InttoStr(I) + '.upl');
+ Playlists[Result].Filename := Name + InttoStr(I) + '.upl';
+ end;
+
+ //Save new Playlist
+ SavePlayList(Result);
+end;
+
+//----------
+//DelPlaylist - Deletes a Playlist
+//----------
+Procedure TPlayListManager.DelPlaylist(const Index: Cardinal);
+var
+ I: Integer;
+ Filename: String;
+begin
+ If Index > High(Playlists) then
+ Exit;
+
+ Filename := PlaylistPath + Playlists[Index].Filename;
+
+ //If not FileExists or File is not Writeable then exit
+ If (Not FileExists(Filename)) OR (FileisReadOnly(Filename)) then
+ Exit;
+
+
+ //Delete Playlist from FileSystem
+ if Not DeleteFile(Filename) then
+ Exit;
+
+ //Delete Playlist from Array
+ //move all PLs to the Hole
+ For I := Index to High(Playlists)-1 do
+ PlayLists[I] := PlayLists[I+1];
+
+ //Delete last Playlist
+ SetLength (Playlists, High(Playlists));
+
+ //If Playlist is Displayed atm
+ //-> Display Songs
+ if (CatSongs.CatNumShow = -3) and (Index = CurPlaylist) then
+ begin
+ ScreenSong.UnLoadDetailedCover;
+ ScreenSong.HideCatTL;
+ CatSongs.SetFilter('', 0);
+ ScreenSong.Interaction := 0;
+ ScreenSong.FixSelected;
+ ScreenSong.ChangeMusic;
+ end;
+end;
+
+//----------
+//AddItem - Adds an Item to a specific Playlist
+//----------
+Procedure TPlayListManager.AddItem(const SongID: Cardinal; const iPlaylist: Integer);
+var
+ P: Cardinal;
+ Len: Cardinal;
+begin
+ if iPlaylist = -1 then
+ P := CurPlaylist
+ else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then
+ P := iPlaylist
+ else
+ exit;
+
+ if (SongID <= High(CatSongs.Song)) AND (NOT CatSongs.Song[SongID].Main) then
+ begin
+ Len := Length(Playlists[P].Items);
+ SetLength(Playlists[P].Items, Len + 1);
+
+ Playlists[P].Items[Len].SongID := SongID;
+ Playlists[P].Items[Len].Title := CatSongs.Song[SongID].Title;
+ Playlists[P].Items[Len].Artist := CatSongs.Song[SongID].Artist;
+
+ //Save Changes
+ SavePlayList(P);
+
+ //Correct Display when Editing current Playlist
+ if (CatSongs.CatNumShow = -3) and (P = CurPlaylist) then
+ SetPlaylist(P);
+ end;
+end;
+
+//----------
+//DelItem - Deletes an Item from a specific Playlist
+//----------
+Procedure TPlayListManager.DelItem(const iItem: Cardinal; const iPlaylist: Integer);
+var
+ I: Integer;
+ P: Cardinal;
+begin
+ if iPlaylist = -1 then
+ P := CurPlaylist
+ else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then
+ P := iPlaylist
+ else
+ exit;
+
+ if (iItem <= high(Playlists[P].Items)) then
+ begin
+ //Move all entrys behind deleted one to Front
+ For I := iItem to High(Playlists[P].Items) - 1 do
+ Playlists[P].Items[I] := Playlists[P].Items[I + 1];
+
+ //Delete Last Entry
+ SetLength(PlayLists[P].Items, Length(PlayLists[P].Items) - 1);
+
+ //Save Changes
+ SavePlayList(P);
+ end;
+
+ //Delete Playlist if Last Song is deleted
+ if (Length(PlayLists[P].Items) = 0) then
+ begin
+ DelPlaylist(P);
+ end
+ //Correct Display when Editing current Playlist
+ else if (CatSongs.CatNumShow = -3) and (P = CurPlaylist) then
+ SetPlaylist(P);
+end;
+
+//----------
+//GetNames - Writes Playlist Names in a Array
+//----------
+Procedure TPlayListManager.GetNames(var PLNames: array of String);
+var
+ I: Integer;
+ Len: Integer;
+begin
+ Len := High(Playlists);
+
+ if (Length(PLNames) <> Len + 1) then
+ exit;
+
+ For I := 0 to Len do
+ PLNames[I] := Playlists[I].Name;
+end;
+
+//----------
+//GetIndexbySongID - Returns Index in the specified Playlist of the given Song
+//----------
+Function TPlayListManager.GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer): Integer;
+var
+ P: Integer;
+ I: Integer;
+begin
+ if iPlaylist = -1 then
+ P := CurPlaylist
+ else if (iPlaylist >= 0) AND (iPlaylist <= high(Playlists)) then
+ P := iPlaylist
+ else
+ exit;
+
+ Result := -1;
+
+ For I := 0 to high(Playlists[P].Items) do
+ begin
+ if (Playlists[P].Items[I].SongID = SongID) then
+ begin
+ Result := I;
+ Break;
+ end;
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/UPliki.pas b/Game/Code/Classes/UPliki.pas
new file mode 100644
index 00000000..f7692990
--- /dev/null
+++ b/Game/Code/Classes/UPliki.pas
@@ -0,0 +1,833 @@
+unit UPliki;
+
+interface
+
+uses USongs, SysUtils, ULog, UMusic;
+
+procedure InitializePaths;
+function ReadHeader(var Song: TSong): boolean;
+function SkanujPlik(var Song: TSong): boolean;
+procedure CzyscNuty;
+function WczytajCzesci(Name: string): boolean;
+function SaveSong(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+function SaveSongDebug(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+
+var
+ GamePath: string;
+ SoundPath: string;
+ SongPath: string;
+ LogPath: string;
+ ThemePath: string;
+ ScreenshotsPath: string;
+ CoversPath: string;
+ LanguagesPath: string;
+ PluginPath: string;
+ PlayListPath: string;
+
+ Plik: TextFile; // all procedures in this unit operates on this file
+ PlikC: char;
+ Lineno: integer;
+
+ // variables available for all procedures
+ Base: array[0..1] of integer;
+ Rel: array[0..1] of integer;
+ Mult: integer;
+ MultBPM: integer;
+
+implementation
+uses TextGL, UIni, UMain, math;
+
+procedure InitializePaths;
+begin
+ GamePath := ExtractFilePath(ParamStr(0));
+ SoundPath := GamePath + 'Sounds\';
+ SongPath := GamePath + 'Songs\';
+ LogPath := GamePath;
+ ThemePath := GamePath + 'Themes\';
+ ScreenshotsPath := GamePath + 'Screenshots\';
+ CoversPath := GamePath + 'Covers\';
+ LanguagesPath := GamePath + 'Languages\';
+ //Modi Loader
+ PluginPath := GamePath + 'Plugins\';
+
+ PlaylistPath := GamePath + 'Playlists\';
+
+ DecimalSeparator := ',';
+end;
+
+function ReadHeader(var Song: TSong): boolean;
+var
+ TempC: char;
+ Tekst: string;
+ Done: integer;
+begin
+ // clear
+ Song.Title := '';
+ Song.Artist := '';
+ Song.Genre := 'Unknown';
+ Song.Edition := 'Unknown';
+ Song.Language := 'Unknown'; //Language Patch
+ Song.Mp3 := '';
+ Song.BPM := 0;
+ Song.GAP := 0;
+ Song.Start := 0;
+ Song.Finish := 0;
+ Song.Background := '';
+ Song.Video := '';
+ Song.VideoGAP := 0;
+ Song.NotesGAP := 0;
+ Song.Resolution := 4;
+
+ //Creator Patch
+ Song.Creator := '';
+
+ Done := 0;
+
+ //Editor Error Reporting Hack
+ LineNo := 0;
+ try
+
+ // read
+ Read(Plik, PlikC);
+ while (PlikC = '#') do begin
+ ReadLn(Plik, Tekst);
+
+ //Editor Error Reporting Hack
+ Inc (LineNo);
+
+ //Header Improvements Patch
+
+ if UpperCase(Copy(Tekst, 1, 6)) = 'TITLE:' then begin
+ Delete(Tekst, 1, 6);
+ Song.Title := Trim(Tekst);
+ Tekst := '';
+ Done := Done or 1;
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 7)) = 'ARTIST:' then begin
+ Delete(Tekst, 1, 7);
+ Song.Artist := Trim(Tekst);
+ Tekst := '';
+ Done := Done or 2;
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 4)) = 'MP3:' then begin
+ Delete(Tekst, 1, 4);
+ Song.Mp3 := Trim(Tekst);
+ Tekst := '';
+ Done := Done or 4;
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 8)) = 'CREATOR:' then begin // this goes for edit
+ Delete(Tekst, 1, 8);
+ Song.Creator := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 6)) = 'GENRE:' then begin // this goes for edit
+ Delete(Tekst, 1, 6);
+ Song.Genre := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 8)) = 'EDITION:' then begin // this goes for edit
+ Delete(Tekst, 1, 8);
+ Song.Edition := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 9)) = 'LANGUAGE:' then begin // this goes for edit
+ Delete(Tekst, 1, 9);
+ Song.Language := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 6)) = 'COVER:' then begin
+ Delete(Tekst, 1, 6);
+ Song.Cover := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 11)) = 'BACKGROUND:' then begin
+ Delete(Tekst, 1, 11);
+ Song.Background := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 6)) = 'VIDEO:' then begin
+ Delete(Tekst, 1, 6);
+ Song.Video := Trim(Tekst);
+ Tekst := '';
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 9)) = 'VIDEOGAP:' then begin
+ Delete(Tekst, 1, 9);
+
+ //Change . to , Mod by Whiteshark :P
+ if (Pos('.',Tekst) <> 0) then
+ begin
+ Tekst[Pos('.',Tekst)] := ',';
+ //Little Annonce for the User
+ Log.LogError('VideoGap Seperator wrong in SongHeader: ' + Song.FileName + ' [Corrected for this Session]');
+ end;
+
+ Song.VideoGAP := StrToFloat(Tekst);
+ Tekst := ''
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 9)) = 'NOTESGAP:' then begin
+ Delete(Tekst, 1, 9);
+ Song.NotesGAP := StrToInt(Tekst);
+ Tekst := ''
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 9)) = 'RELATIVE:' then begin
+ Delete(Tekst, 1, 9);
+ if LowerCase(Tekst) = 'yes' then Song.Relative := true;
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 6)) = 'START:' then begin
+ Delete(Tekst, 1, 6);
+ Song.Start := StrToFloat(Tekst);
+// Muzyka.Start := StrToInt(Tekst);
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 4)) = 'END:' then begin
+ Delete(Tekst, 1, 4);
+ Song.Finish := StrToInt(Tekst);
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 11)) = 'RESOLUTION:' then begin
+ Delete(Tekst, 1, 11);
+ Song.Resolution := StrToInt(Tekst);
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 4)) = 'BPM:' then begin
+ Delete(Tekst, 1, 4);
+
+// Muzyka.BPMOld := StrToFloat(Tekst) * Mult * MultBPM; // old system
+
+ (* new system with variable BPM *)
+// Muzyka.BPMOld := 50;
+
+ //Change . to , Mod by Whiteshark :P
+ if (Pos('.',Tekst) <> 0) then
+ begin
+ Tekst[Pos('.',Tekst)] := ',';
+ //Little Annonce for the User
+ Log.LogError('BPM Seperator wrong in SongHeader: ' + Song.FileName + ' [Corrected for this Session]');
+ end;
+
+ SetLength(Song.BPM, 1);
+ Song.BPM[0].StartBeat := 0;
+ Song.BPM[0].BPM := StrToFloat(Tekst) * Mult * MultBPM;
+ Tekst := '';
+ Done := Done or 8;
+ end
+
+ else if UpperCase(Copy(Tekst, 1, 4)) = 'GAP:' then begin
+ Delete(Tekst, 1, 4);
+ Song.GAP := StrToFloat(Tekst);
+ Tekst := '';
+// Muzyka.GAP := StrToFloat(Tekst);
+// Done := Done or 16;
+ end;
+
+ //Header Improvements Patch Ende
+
+ Read(Plik, PlikC);
+ end;
+
+ //Editor Error Reporting Hack
+ except //An Error happened<- bad english :P
+ Log.LogError('An Error occured reading Line ' + inttostr(LineNo) + ' from SongHeader: ' + Song.FileName);
+ Halt;
+ end;
+ //Editor Error Reporting Hack End
+
+ if Song.Background = '' then begin
+ Song.Background := Songs.FindSongFile(Song.Path, '*[BG].jpg');
+ end;
+
+ if (Done and 15) = 15 then Result := true
+ else Result := false;
+end;
+
+function SkanujPlik(var Song: TSong): boolean;
+var
+ Done: integer;
+ Tekst: string;
+ C: integer; // category
+ P: integer; // position
+begin
+// try
+ AssignFile(Plik, Song.Path + Song.FileName);
+ Reset(Plik);
+
+ Result := ReadHeader(Song);
+
+{ ReadLn(Plik, Tekst);
+ while (Copy(Tekst, 1, 1) = '#') do begin
+ if Copy(Tekst, 1, 10) = '#CATEGORY:' then begin
+ Delete(Tekst, 1, 10);
+
+ Trim(Tekst);
+ while (Length(Tekst) > 0) do begin
+ C := Length(Song.Category);
+ SetLength(Song.Category, C+1);
+
+ P := Pos(',', Tekst);
+ if P = 0 then P := Length(Tekst);
+ Song.Category[C] := Copy(Tekst, 1, P);
+
+ Delete(Tekst, 1, P);
+ Trim(Tekst);
+ end;
+
+ end;}
+
+
+end;
+
+procedure CzyscNuty;
+var
+ Pet: integer;
+begin
+ SetLength(Czesci, Length(Player));
+ SetLength(AktSong.BPM, 0);
+ for Pet := 0 to High(Player) do begin
+ SetLength(Czesci[Pet].Czesc, 1);
+ SetLength(Czesci[Pet].Czesc[0].Nuta, 0);
+ Czesci[Pet].Czesc[0].Lyric := '';
+ Czesci[Pet].Czesc[0].LyricWidth := 0;
+ Player[pet].Score := 0;
+ Player[pet].IlNut := 0;
+ Player[pet].HighNut := -1;
+ end;
+end;
+
+procedure DodajNute(NrCzesci: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string);
+var
+ Space: boolean;
+begin
+ case Ini.Solmization of
+ 1: // european
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' sol ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' si ';
+ end;
+ end;
+ 2: // japanese
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' so ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' shi ';
+ end;
+ end;
+ 3: // american
+ begin
+ case (NoteP mod 12) of
+ 0..1: LyricS := ' do ';
+ 2..3: LyricS := ' re ';
+ 4: LyricS := ' mi ';
+ 5..6: LyricS := ' fa ';
+ 7..8: LyricS := ' sol ';
+ 9..10: LyricS := ' la ';
+ 11: LyricS := ' ti ';
+ end;
+ end;
+ end; // case
+
+// Log.LogStatus('Czesc: ' + IntToStr(Czesci[NrCzesci].High), 'DodajNute');
+// Log.LogStatus('Dodano: [' + IntToStr(NrCzesci) + '] ' + IntToStr(StartP) + ' '
+// + IntToStr(DurationP) + ' '+ IntToStr(NoteP) + ' ' + LyricS, 'DodajNute');
+
+{ Delete(LyricS, 1, 1);
+ Space := false;
+ if Copy(LyricS, Length(LyricS), 1) = ' ' then begin
+ Space := true;
+ Delete(LyricS, Length(LyricS), 1);
+ end;
+ if LyricS = 'a' then LyricS := chr($B1);
+ if LyricS = 'i' then LyricS := chr($B2);
+ if LyricS = 'u' then LyricS := chr($B3);
+ if LyricS = 'e' then LyricS := chr($B4);
+ if LyricS = 'o' then LyricS := chr($B5);
+
+ if LyricS = 'ka' then LyricS := chr($B6);
+ if LyricS = 'ki' then LyricS := chr($B7);
+ if LyricS = 'ku' then LyricS := chr($B8);
+ if LyricS = 'ke' then LyricS := chr($B9);
+ if LyricS = 'ko' then LyricS := chr($BA);
+
+ if LyricS = 'ga' then LyricS := chr($B6) + chr($DE);
+ if LyricS = 'gi' then LyricS := chr($B7) + chr($DE);
+ if LyricS = 'gu' then LyricS := chr($B8) + chr($DE);
+ if LyricS = 'ge' then LyricS := chr($B9) + chr($DE);
+ if LyricS = 'go' then LyricS := chr($BA) + chr($DE);
+
+ if LyricS = 'sa' then LyricS := chr($BB);
+ if LyricS = 'shi' then LyricS := chr($BC);
+ if LyricS = 'su' then LyricS := chr($BD);
+ if LyricS = 'se' then LyricS := chr($BE);
+ if LyricS = 'so' then LyricS := chr($BF);
+
+ if LyricS = 'za' then LyricS := chr($BB) + chr($DE);
+ if LyricS = 'ji' then LyricS := chr($BC) + chr($DE);
+ if LyricS = 'zu' then LyricS := chr($BD) + chr($DE);
+ if LyricS = 'ze' then LyricS := chr($BE) + chr($DE);
+ if LyricS = 'zo' then LyricS := chr($BF) + chr($DE);
+
+ if LyricS = 'ta' then LyricS := chr($C0);
+ if LyricS = 'chi' then LyricS := chr($C1);
+ if LyricS = 'tsu' then LyricS := chr($C2);
+ if LyricS = 'te' then LyricS := chr($C3);
+ if LyricS = 'to' then LyricS := chr($C4);
+
+ if LyricS = 'da' then LyricS := chr($C0) + chr($DE);
+// if LyricS = 'ji' then LyricS := chr($C1) + chr($DE);
+// if LyricS = 'zu' then LyricS := chr($C2) + chr($DE);
+ if LyricS = 'de' then LyricS := chr($C3) + chr($DE);
+ if LyricS = 'do' then LyricS := chr($C4) + chr($DE);
+
+ if LyricS = 'na' then LyricS := chr($C5);
+ if LyricS = 'ni' then LyricS := chr($C6);
+ if LyricS = 'nu' then LyricS := chr($C7);
+ if LyricS = 'ne' then LyricS := chr($C8);
+ if LyricS = 'no' then LyricS := chr($C9);
+
+ if LyricS = 'ha' then LyricS := chr($CA);
+ if LyricS = 'hi' then LyricS := chr($CB);
+ if LyricS = 'hu' then LyricS := chr($CC);
+ if LyricS = 'he' then LyricS := chr($CD);
+ if LyricS = 'ho' then LyricS := chr($CE);
+
+ if LyricS = 'ba' then LyricS := chr($CA) + chr($DE);
+ if LyricS = 'bi' then LyricS := chr($CB) + chr($DE);
+ if LyricS = 'bu' then LyricS := chr($CC) + chr($DE);
+ if LyricS = 'be' then LyricS := chr($CD) + chr($DE);
+ if LyricS = 'bo' then LyricS := chr($CE) + chr($DE);
+
+ if LyricS = 'pa' then LyricS := chr($CA) + chr($DF);
+ if LyricS = 'pi' then LyricS := chr($CB) + chr($DF);
+ if LyricS = 'pu' then LyricS := chr($CC) + chr($DF);
+ if LyricS = 'pe' then LyricS := chr($CD) + chr($DF);
+ if LyricS = 'po' then LyricS := chr($CE) + chr($DF);
+
+ if LyricS = 'ma' then LyricS := chr($CF);
+ if LyricS = 'mi' then LyricS := chr($D0);
+ if LyricS = 'mu' then LyricS := chr($D1);
+ if LyricS = 'me' then LyricS := chr($D2);
+ if LyricS = 'mo' then LyricS := chr($D3);
+
+ if LyricS = 'ya' then LyricS := chr($D4);
+ if LyricS = 'yu' then LyricS := chr($D5);
+ if LyricS = 'yo' then LyricS := chr($D6);
+
+ if LyricS = 'ra' then LyricS := chr($D7);
+ if LyricS = 'ri' then LyricS := chr($D8);
+ if LyricS = 'ru' then LyricS := chr($D9);
+ if LyricS = 're' then LyricS := chr($DA);
+ if LyricS = 'ro' then LyricS := chr($DB);
+
+ if LyricS = 'wa' then LyricS := chr($DC);
+ if LyricS = 'n' then LyricS := chr($DD);
+
+ LyricS := ' ' + LyricS;
+ if Space then LyricS := LyricS + ' ';}
+
+
+
+ with Czesci[NrCzesci].Czesc[Czesci[NrCzesci].High] do begin
+ SetLength(Nuta, Length(Nuta) + 1);
+ IlNut := IlNut + 1;
+ HighNut := HighNut + 1;
+ Muzyka.IlNut := Muzyka.IlNut + 1;
+
+ Nuta[HighNut].Start := StartP;
+ if IlNut = 1 then begin
+ StartNote := Nuta[HighNut].Start;
+ if Czesci[NrCzesci].Ilosc = 1 then
+ Start := -100;
+// Start := Nuta[HighNut].Start;
+ end;
+
+ Nuta[HighNut].Dlugosc := DurationP;
+ Muzyka.DlugoscNut := Muzyka.DlugoscNut + Nuta[HighNut].Dlugosc;
+
+ // back to the normal system with normal, golden and now freestyle notes
+ case TypeP of
+ 'F': Nuta[HighNut].Wartosc := 0;
+ ':': Nuta[HighNut].Wartosc := 1;
+ '*': Nuta[HighNut].Wartosc := 2;
+ end;
+ Czesci[NrCzesci].Wartosc := Czesci[NrCzesci].Wartosc + Nuta[HighNut].Dlugosc * Nuta[HighNut].Wartosc;
+
+ Nuta[HighNut].Ton := NoteP;
+ if Nuta[HighNut].Ton < Base[NrCzesci] then Base[NrCzesci] := Nuta[HighNut].Ton;
+ Nuta[HighNut].TonGamy := Nuta[HighNut].TonGamy mod 12;
+
+ Nuta[HighNut].Tekst := Copy(LyricS, 2, 100);
+ Lyric := Lyric + Nuta[HighNut].Tekst;
+
+ if TypeP = 'F' then
+ Nuta[HighNut].FreeStyle := true;
+
+ Koniec := Nuta[HighNut].Start + Nuta[HighNut].Dlugosc;
+ end; // with
+end;
+
+procedure NewSentence(NrCzesciP: integer; Param1, Param2: integer);
+var
+I: Integer;
+begin
+// Log.LogStatus('IlCzesci: ' + IntToStr(Czesci[NrCzesciP].Ilosc), 'NewSentece');
+// Log.LogStatus('Dane: ' + IntToStr(NrCzesciP) + ' ' + IntToStr(Param1) + ' ' + IntToStr(Param2) , 'NewSentece');
+
+ // stara czesc //Alter Satz //Update Old Part
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].BaseNote := Base[NrCzesciP];
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].LyricWidth := glTextWidth(PChar(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Lyric));
+
+ //Total Notes Patch
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := 0;
+ for I := low(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) to high(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta) do
+ begin
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes := Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes + Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Dlugosc * Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Nuta[I].Wartosc;
+ end;
+ //Log.LogError('Total Notes(' + inttostr(Czesci[NrCzesciP].High) +'): ' + inttostr(Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].TotalNotes));
+ //Total Notes Patch End
+
+
+ // nowa czesc //Neuer Satz //Update New Part
+ SetLength(Czesci[NrCzesciP].Czesc, Czesci[NrCzesciP].Ilosc + 1);
+ Czesci[NrCzesciP].High := Czesci[NrCzesciP].High + 1;
+ Czesci[NrCzesciP].Ilosc := Czesci[NrCzesciP].Ilosc + 1;
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].HighNut := -1;
+
+ if not AktSong.Relative then
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1;
+
+ if AktSong.Relative then begin
+ Czesci[NrCzesciP].Czesc[Czesci[NrCzesciP].High].Start := Param1;
+ Rel[NrCzesciP] := Rel[NrCzesciP] + Param2;
+ end;
+
+ Base[NrCzesciP] := 100; // high number
+end;
+
+function WczytajCzesci(Name: string): boolean;
+var
+ TempC: char;
+ Tekst: string;
+ CP: integer; // Current Player (0 or 1)
+ Pet: integer;
+ Both: boolean;
+ Param1: integer;
+ Param2: integer;
+ Param3: integer;
+ ParamS: string;
+ I: Integer;
+begin
+ Result := false;
+
+ if not FileExists(Name) then begin
+ Log.LogError('File not found: "' + Name + '"', 'WczytajCzesci');
+ exit;
+ end;
+
+ try
+ MultBPM := 4; // 4 - mnoznik dla czasu nut
+ Mult := 1; // 4 - dokladnosc pomiaru nut
+ Base[0] := 100; // high number
+// Base[1] := 100; // high number
+ Czesci[0].Wartosc := 0;
+// Czesci[1].Wartosc := 0; // here was the error in 0.3.2
+ AktSong.Relative := false;
+
+ Rel[0] := 0;
+// Rel[1] := 0;
+ CP := 0;
+ Both := false;
+ if Length(Player) = 2 then Both := true;
+
+ FileMode := fmOpenRead;
+ AssignFile(Plik, Name);
+ Reset(Plik);
+
+ ReadHeader(AktSong);
+(* if AktSong.Title = 'Hubba Hubba Zoot Zoot' then begin
+ Mult := 2;
+ AktSong.BPM[0].BPM := AktSong.BPM[0].BPM * 2;
+ end;*)
+
+ SetLength(Czesci, 2);
+ for Pet := 0 to High(Czesci) do begin
+ SetLength(Czesci[Pet].Czesc, 1);
+ Czesci[Pet].High := 0;
+ Czesci[Pet].Ilosc := 1;
+ Czesci[Pet].Akt := 0;
+ Czesci[Pet].Resolution := AktSong.Resolution;
+ Czesci[Pet].NotesGAP := AktSong.NotesGAP;
+ Czesci[Pet].Czesc[0].IlNut := 0;
+ Czesci[Pet].Czesc[0].HighNut := -1;
+ end;
+
+// TempC := ':';
+ TempC := PlikC; // read from backup variable, don't use default ':' value
+
+ while (TempC <> 'E') do begin
+ Inc(LineNo);
+ if (TempC = ':') or (TempC = '*') or (TempC = 'F') then begin
+ // wczytuje nute
+ Read(Plik, Param1);
+ Read(Plik, Param2);
+ Read(Plik, Param3);
+ Read(Plik, ParamS);
+
+ // dodaje nute
+ if not Both then
+ // P1
+ DodajNute(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS)
+ else begin
+ // P1 + P2
+ DodajNute(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS);
+ DodajNute(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS);
+ end;
+ end; // if
+ if TempC = '-' then begin
+ // reads sentence
+ Read(Plik, Param1);
+ if AktSong.Relative then Read(Plik, Param2); // read one more data for relative system
+
+ // new sentence
+ if not Both then
+ // P1
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2)
+ else begin
+ // P1 + P2
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2);
+ NewSentence(1, (Param1 + Rel[1]) * Mult, Param2);
+ end;
+
+ end; // if
+
+ if TempC = 'B' then begin
+ SetLength(AktSong.BPM, Length(AktSong.BPM) + 1);
+ Read(Plik, AktSong.BPM[High(AktSong.BPM)].StartBeat);
+ AktSong.BPM[High(AktSong.BPM)].StartBeat := AktSong.BPM[High(AktSong.BPM)].StartBeat + Rel[0];
+
+ Read(Plik, Tekst);
+ AktSong.BPM[High(AktSong.BPM)].BPM := StrToFloat(Tekst);
+ AktSong.BPM[High(AktSong.BPM)].BPM := AktSong.BPM[High(AktSong.BPM)].BPM * Mult * MultBPM;
+ end;
+
+
+ if not Both then begin
+ Czesci[CP].Czesc[Czesci[CP].High].BaseNote := Base[CP];
+ Czesci[CP].Czesc[Czesci[CP].High].LyricWidth := glTextWidth(PChar(Czesci[CP].Czesc[Czesci[CP].High].Lyric));
+ //Total Notes Patch
+ Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := 0;
+ for I := low(Czesci[CP].Czesc[Czesci[CP].High].Nuta) to high(Czesci[CP].Czesc[Czesci[CP].High].Nuta) do
+ begin
+ Czesci[CP].Czesc[Czesci[CP].High].TotalNotes := Czesci[CP].Czesc[Czesci[CP].High].TotalNotes + Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Dlugosc * Czesci[CP].Czesc[Czesci[CP].High].Nuta[I].Wartosc;
+ end;
+ //Total Notes Patch End
+ end else begin
+ for Pet := 0 to High(Czesci) do begin
+ Czesci[Pet].Czesc[Czesci[Pet].High].BaseNote := Base[Pet];
+ Czesci[Pet].Czesc[Czesci[Pet].High].LyricWidth := glTextWidth(PChar(Czesci[Pet].Czesc[Czesci[Pet].High].Lyric));
+ //Total Notes Patch
+ Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := 0;
+ for I := low(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) to high(Czesci[Pet].Czesc[Czesci[Pet].High].Nuta) do
+ begin
+ Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes := Czesci[Pet].Czesc[Czesci[Pet].High].TotalNotes + Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Dlugosc * Czesci[Pet].Czesc[Czesci[Pet].High].Nuta[I].Wartosc;
+ end;
+ //Total Notes Patch End
+ end;
+ end;
+
+ Read(Plik, TempC);
+ end; // while}
+
+ CloseFile(Plik);
+ except
+ Log.LogError('Error Loading File: "' + Name + '" in Line ' + inttostr(LineNo));
+ exit;
+ end;
+
+ Result := true;
+end;
+
+function SaveSong(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+var
+ C: integer;
+ N: integer;
+ S: string;
+ B: integer;
+ RelativeSubTime: integer;
+ NoteState: String;
+
+begin
+// Relative := true; // override (idea - use shift+S to save with relative)
+ AssignFile(Plik, Name);
+ Rewrite(Plik);
+
+ WriteLn(Plik, '#TITLE:' + Song.Title + '');
+ WriteLn(Plik, '#ARTIST:' + Song.Artist);
+
+ if Song.Creator <> '' then WriteLn(Plik, '#CREATOR:' + Song.Creator);
+ if Song.Edition <> 'Unknown' then WriteLn(Plik, '#EDITION:' + Song.Edition);
+ if Song.Genre <> 'Unknown' then WriteLn(Plik, '#GENRE:' + Song.Genre);
+ if Song.Language <> 'Unknown' then WriteLn(Plik, '#LANGUAGE:' + Song.Language);
+ if Song.Cover <> '' then WriteLn(Plik, '#COVER:' + Song.Cover);
+
+ WriteLn(Plik, '#MP3:' + Song.Mp3);
+
+ if Song.Background <> '' then WriteLn(Plik, '#BACKGROUND:' + Song.Background);
+ if Song.Video <> '' then WriteLn(Plik, '#VIDEO:' + Song.Video);
+ if Song.VideoGAP <> 0 then WriteLn(Plik, '#VIDEOGAP:' + FloatToStr(Song.VideoGAP));
+ if Song.Resolution <> 4 then WriteLn(Plik, '#RESOLUTION:' + IntToStr(Song.Resolution));
+ if Song.NotesGAP <> 0 then WriteLn(Plik, '#NOTESGAP:' + IntToStr(Song.NotesGAP));
+ if Song.Start <> 0 then WriteLn(Plik, '#START:' + FloatToStr(Song.Start));
+ if Song.Finish <> 0 then WriteLn(Plik, '#END:' + IntToStr(Song.Finish));
+ if Relative then WriteLn(Plik, '#RELATIVE:yes');
+
+ WriteLn(Plik, '#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
+ WriteLn(Plik, '#GAP:' + FloatToStr(Song.GAP));
+
+ RelativeSubTime := 0;
+ for B := 1 to High(AktSong.BPM) do
+ WriteLn(Plik, 'B ' + FloatToStr(AktSong.BPM[B].StartBeat) + ' ' + FloatToStr(AktSong.BPM[B].BPM/4));
+
+ for C := 0 to Czesc.High do begin
+ for N := 0 to Czesc.Czesc[C].HighNut do begin
+ with Czesc.Czesc[C].Nuta[N] do begin
+
+
+ //Golden + Freestyle Note Patch
+ case Czesc.Czesc[C].Nuta[N].Wartosc of
+ 0: NoteState := 'F ';
+ 1: NoteState := ': ';
+ 2: NoteState := '* ';
+ end; // case
+ S := NoteState + IntToStr(Start-RelativeSubTime) + ' ' + IntToStr(Dlugosc) + ' ' + IntToStr(Ton) + ' ' + Tekst;
+
+
+ WriteLn(Plik, S);
+ end; // with
+ end; // N
+
+ if C < Czesc.High then begin // don't write end of last sentence
+ if not Relative then
+ S := '- ' + IntToStr(Czesc.Czesc[C+1].Start)
+ else begin
+ S := '- ' + IntToStr(Czesc.Czesc[C+1].Start - RelativeSubTime) +
+ ' ' + IntToStr(Czesc.Czesc[C+1].Start - RelativeSubTime);
+ RelativeSubTime := Czesc.Czesc[C+1].Start;
+ end;
+ WriteLn(Plik, S);
+ end;
+
+ end; // C
+
+
+ WriteLn(Plik, 'E');
+ CloseFile(Plik);
+end;
+
+function SaveSongDebug(Song: TSong; Czesc: TCzesci; Name: string; Relative: boolean): boolean;
+var
+ C: integer;
+ N: integer;
+ S: string;
+ STon: integer;
+ SLen: integer;
+ NTot: integer;
+ PlikB: TextFile;
+ LastTime: integer;
+begin
+ AssignFile(Plik, Name);
+ Rewrite(Plik);
+
+ AssignFile(PlikB, 'C:\song db.asm');
+ Rewrite(PlikB);
+
+ NTot := 0;
+ LastTime := 0;
+
+ for C := 0 to Czesc.High do begin
+ WriteLn(Plik, '; ' + IntToStr(C));
+
+ for N := 0 to Czesc.Czesc[C].HighNut do begin
+ with Czesc.Czesc[C].Nuta[N] do begin
+
+ // timespace
+ if LastTime < Start then begin
+ STon := 0;
+ SLen := Round((Start - LastTime) * 16320 / 255 / 12);
+ WriteLn(PlikB, ' .dw ' + IntToStr(STon + SLen*256) + ' ; timespace (0, ' + IntToStr(SLen) + ')');
+
+ end;
+
+
+
+ // ton
+ STon := Round(98940/(2*261.62*Power(1.05946309436, Ton)));
+ S := ' ldi R18, ' + IntToStr(STon);
+ if STon > 255 then begin
+ beep;
+ S := '!!!!' + S;
+ end;
+ WriteLn(Plik, S);
+
+ // length
+ //ldi R19, 43
+ SLen := Round(Dlugosc * 16320 / STon / 12);
+ S := ' ldi R19, ' + IntToStr(SLen);
+ if SLen > 255 then begin
+ beep;
+ S := '!!!!' + S;
+ end;
+ WriteLn(Plik, S);
+
+ // function
+ S := ' rcall playtone';
+ WriteLn(Plik, S);
+
+ // song dw
+ WriteLn(PlikB, ' .dw ' + IntToStr(STon + SLen*256));
+
+
+ LastTime := Start + Dlugosc;
+ Inc(NTot);
+
+ end; // with
+ end; // N
+ WriteLn(Plik, '');
+ WriteLn(PlikB, '');
+ end; // C
+
+ WriteLn(Plik, '; nut ' + IntToStr(NTot));
+ WriteLn(Plik, '; bajtów ' + IntToStr(8*NTot));
+
+ WriteLn(PlikB, ' .dw 0');
+ WriteLn(PlikB, '; nut ' + IntToStr(NTot));
+ WriteLn(PlikB, '; bajtów ' + IntToStr(2*NTot));
+
+
+ CloseFile(Plik);
+ CloseFile(PlikB);
+end;
+
+end.
diff --git a/Game/Code/Classes/URecord.pas b/Game/Code/Classes/URecord.pas
new file mode 100644
index 00000000..2ec5439a
--- /dev/null
+++ b/Game/Code/Classes/URecord.pas
@@ -0,0 +1,371 @@
+unit URecord;
+
+interface
+uses Classes, Math, SysUtils, {DXSounds, Wave, }UMusic, UIni, BASS;
+
+type
+ TSound = class
+ BufferNew: TMemoryStream; // buffer for newest sample
+ BufferArray: array[1..4096] of smallint; // (Signal) newest 4096 samples
+ BufferLong: array of TMemoryStream; // full buffer
+
+ Num: integer;
+ n: integer; // length of Signal to analyze
+// Spectrum: array[1..8192] of single; // sound buffer from above as FFT
+// Spektogram: array[0..100] of TSpekt; // FFT(t)
+
+ // pitch detection
+ SzczytJest: boolean; // czy jest szczyt
+ Szczyt: integer; // pozycja szczytu na osi poziomej
+ TonDokl: real; // ton aktualnego szczytu
+ Ton: integer; // ton bez ulamka
+ TonGamy: integer; // ton w gamie. wartosci: 0-11
+ Skala: real; // skala FFT
+
+ // procedures
+ procedure ProcessNewBuffer;
+ procedure AnalizujBufor; // use to analyze sound from buffers to get new pitch
+ procedure AnalizujByAutocorrelation; // we call it to analyze sound by checking Autocorrelation
+ function AnalyzeAutocorrelationFreq(Freq: real): real; // use this to check one frequency by Autocorrelation
+ end;
+
+ TSoundCardInput = record
+ Name: string;
+ end;
+
+ TSoundCard = record
+ // here can be the soundcard information - whole database from which user will select recording source
+ Description: string;
+ Input: array of TSoundCardInput;
+ InputSeleceted: integer;
+
+ // bass record
+ BassRecordStream: hStream;
+ end;
+
+ TRecord = class
+ SoundCard: array of TSoundCard;
+ constructor Create;
+ end;
+
+ smallintarray = array [0..maxInt shr 1-1] of smallInt;
+ psmallintarray = ^smallintarray;
+
+ // procedures - bass record
+ function GetMicrophone(handle: HSTREAM; buffer: Pointer; len: DWORD; user: DWORD): boolean; stdcall;
+
+
+var
+ Sound: array of TSound;
+ SoundCard: array of TSoundCard;
+ Poz: integer;
+ Recording: TRecord;
+
+implementation
+uses UMain, ULog;
+
+procedure TSound.ProcessNewBuffer;
+var
+ S: integer;
+ L: integer;
+ A: integer;
+begin
+ // process BufferArray
+ S := 0;
+ L := BufferNew.Size div 2;
+ if L > n then begin
+ S := L - n;
+ L := n;
+ end;
+
+ // copy to array
+ for A := L+1 to n do
+ BufferArray[A-L] := BufferArray[A];
+
+ BufferNew.Seek(2*S, soBeginning);
+ BufferNew.ReadBuffer(BufferArray[1+n-L], 2*L);
+
+ // process BufferLong
+ if Ini.SavePlayback = 1 then begin
+ BufferNew.Seek(0, soBeginning);
+ BufferLong[0].CopyFrom(BufferNew, BufferNew.Size);
+ end;
+end;
+
+procedure TSound.AnalizujBufor;
+begin
+ AnalizujByAutocorrelation;
+end;
+
+procedure TSound.AnalizujByAutocorrelation;
+var
+ T: integer; // tone
+ F: real; // freq
+ Wages: array[0..35] of real; // wages
+ MaxT: integer; // max tone
+ MaxW: real; // max wage
+ V: real; // volume
+ MaxV: real; // max volume
+ S: integer; // Signal
+ Threshold: real; // threshold
+begin
+// Log.LogAnalyze('[Analyze by Autocorrelation]');
+ SzczytJest := false;
+
+ // find maximum volume of first 1024 words of signal
+ MaxV := 0;
+ for S := 1 to 1024 do begin // 0.5.2: fix. was from 0 to 1023
+// Log.LogDebug('1');
+// Log.LogDebug(IntTostr(S));
+ V := Abs(BufferArray[S]) / $10000;
+// Log.LogDebug('2');
+// Log.LogDebug(IntTostr(S) + ': ' + FloatToStr(V) + ', MaxV='+floattostr(maxv)+', buf='+inttostr(length(BufferArray)));
+ if V > MaxV then MaxV := V;
+// Log.LogDebug('3');
+// Log.LogDebug(IntTostr(S) + ': ' + FloatToStr(V) + ', MaxV='+floattostr(maxv)+', buf='+inttostr(length(BufferArray)));
+ end;
+
+
+ // prepare to analyze
+ MaxW := 0;
+
+ // analyze all 12 halftones
+ for T := 0 to 35 do begin // to 11, then 23, now 35 (for Whitney and my high voice)
+ F := 130.81*Power(1.05946309436, T)/2; // let's analyze below 130.81
+ Wages[T] := AnalyzeAutocorrelationFreq(F);
+
+ if Wages[T] > MaxW then begin // this frequency has better wage
+ MaxW := Wages[T];
+ MaxT := T;
+ end;
+ end; // for T
+
+ Threshold := 0.1;
+ case Ini.Threshold of
+ 0: Threshold := 0.05;
+ 1: Threshold := 0.1;
+ 2: Threshold := 0.15;
+ 3: Threshold := 0.2;
+ end;
+
+ //Log.LogDebug('Sound -> AnalyzeByAutocorrelation: MaxV='+floattostr(maxv)+', Threshold='+floattostr(threshold));
+ if MaxV >= Threshold then begin // found acceptable volume // 0.1
+ SzczytJest := true;
+ TonGamy := MaxT mod 12;
+ Ton := MaxT mod 12;
+ end;
+
+// Log.LogAnalyze('--> Weight: ')
+// Log.LogAnalyze('--> Selected: ' + BoolToStr(SzczytJest, true) +
+// ', TonGamy: ' + IntToStr(Ton) +
+// ', MaxV: ' + FloatToStr(MaxV));
+// Log.LogAnalyze('');
+
+
+end;
+
+function TSound.AnalyzeAutocorrelationFreq(Freq: real): real; // result medium difference
+var
+ Count: real;
+ Src: integer;
+ Dst: integer;
+ Move: integer;
+ Il: integer; // how many counts were done
+begin
+ // we use Signal as source
+ Count := 0;
+ Il := 0;
+ Src := 1;
+ Move := Round(44100/Freq);
+ Dst := Src + Move;
+
+ // ver 1 - sample 1 and compare n-times
+{ while (Src <= Move) do begin // process by moving Src by one
+ while (Dst < n) do begin // process up to n (4KB) of Signal
+ Count := Count + Abs(Signal[Src] - Signal[Dst]) / $10000;
+ Inc(Dst, Move);
+ Inc(Il);
+ end;
+
+ Inc(Src);
+ Dst := Src + Move;
+ end;}
+
+ // ver 2 - compare in vertical
+ while (Dst < n) do begin // process up to n (4KB) of Signal
+ Count := Count + Abs(BufferArray[Src] - BufferArray[Dst]) / $10000;
+ Inc(Src);
+ Inc(Dst);
+ Inc(Il);
+ end;
+
+ Result := 1 - Count / Il;
+end;
+
+function GetMicrophone(handle: HSTREAM; buffer: Pointer; len: DWORD; user: DWORD): boolean; stdcall;
+var
+ L: integer;
+ S: integer;
+ PB: pbytearray;
+ PW: pwordarray;
+ SI: smallintarray;
+ PSI: psmallintarray;
+ I: integer;
+ Skip: integer;
+ P1: integer;
+ P2: integer;
+ Boost: byte;
+begin
+// Log.LogDebug('Record -> GetMicrophone: len='+inttstr(len));
+
+ // set boost
+ case Ini.MicBoost of
+ 0: Boost := 1;
+ 1: Boost := 2;
+ 2: Boost := 4;
+ 3: Boost := 8;
+ end;
+
+ // boost buffer
+ L := Len div 2; // number of samples
+ PSI := Buffer;
+ for S := 0 to L-1 do begin
+ I := PSI^[S] * Boost;
+ if I > 32767 then I := 32767; // 0.5.0: limit
+ if I < -32768 then I := -32768; // 0.5.0: limit
+ PSI^[S] := I;
+ end;
+
+ // decode user
+ P1 := (user and 255) - 1;
+ P2 := (user div 256) - 1;
+
+// Log.LogDebug('Record -> GetMicrophone: P1='+inttostr(p1)+', P2='+inttostr(p2));
+
+ // 2 players USB mic, left channel
+ if P1 >= 0 then begin
+ L := Len div 4; // number of samples
+ PB := Buffer;
+// Log.LogDebug('Record -> GetMicrophone -> Sound[P1].BufferNew.Clear');
+ Sound[P1].BufferNew.Clear; // 0.5.2: problem on exiting
+ for S := 1 to L do begin
+ Sound[P1].BufferNew.Write(PB[(S-1)*4], 2);
+ end;
+ Sound[P1].ProcessNewBuffer;
+ end;
+
+ // 2 players USB mic, right channel
+// if Ini.Debug = 0 then Skip := 2
+// else Skip := 0;
+ Skip := 2;
+
+ if P2 >= 0 then begin
+ L := Len div 4; // number of samples
+ PB := Buffer;
+ Sound[P2].BufferNew.Clear;
+ for S := 1 to L do begin
+ Sound[P2].BufferNew.Write(PB[Skip + (S-1)*4], 2);
+ end;
+ Sound[P2].ProcessNewBuffer;
+ end;
+
+// Log.LogDebug('Record -> GetMicrophone -> Finish');
+
+ Result := true;
+end;
+
+constructor TRecord.Create;
+var
+ SC: integer; // soundcard
+ SCI: integer; // soundcard input
+ Descr: string;
+ InputName: string;
+ Flags: integer;
+ No: integer;
+ function isDuplicate(Desc: String): Boolean;
+ var
+ I: Integer;
+ begin
+ Result := False;
+ //Check for Soundcard with same Description
+ For I := 0 to SC-1 do
+ begin
+ if (SoundCard[I].Description = Desc) then
+ begin
+ Result := True;
+ Break;
+ end;
+ end;
+ end;
+
+// mic: array[0..15] of integer;
+begin
+ // checks for recording devices and puts them into array;
+ SetLength(SoundCard, 0);
+
+ SC := 0;
+ Descr := BASS_RecordGetDeviceDescription(SC);
+
+ while (Descr <> '') do begin
+
+ //If there is another SoundCard with the Same ID, Search an available Name
+ if (IsDuplicate(Descr)) then
+ begin
+ No:= 1; //Count of SoundCards with same Name
+ Repeat
+ Inc(No)
+ Until not IsDuplicate(Descr + ' (' + InttoStr(No) + ')');
+ //Set Description
+ Descr := Descr + ' (' + InttoStr(No) + ')';
+ end;
+
+ SetLength(SoundCard, SC+1);
+// Log.LogError('Device #' + IntToStr(SC+1) + ': ' + Descr);
+ SoundCard[SC].Description := Descr;
+
+ // check for recording inputs
+// mic[device] := -1; // default to no change
+ SCI := 0;
+ BASS_RecordInit(SC);
+ Flags := BASS_RecordGetInput(SCI);
+ InputName := BASS_RecordGetInputName(SCI);
+// Log.LogError('Input #' + IntToStr(SCI) + ' (' + IntToStr(Flags) + '): ' + InputName);
+
+ SetLength(SoundCard[SC].Input, 1);
+ SoundCard[SC].Input[SCI].Name := InputName;
+
+ // process each input
+ while (Flags <> -1) do begin
+ if SCI >= 1 then begin
+ SetLength(SoundCard[SC].Input, SCI+1);
+ InputName := BASS_RecordGetInputName(SCI);
+ SoundCard[SC].Input[SCI].Name := InputName;
+// Log.LogError('Input #' + IntToStr(SCI) + ' (' + IntToStr(Flags) + '): ' + InputName);
+ end;
+
+{ if (flags and BASS_INPUT_TYPE_MASK) = BASS_INPUT_TYPE_MIC then begin
+ mic[device] := input; // auto set microphone
+ end;}
+
+ Inc(SCI);
+ Flags := BASS_RecordGetInput(SCI);
+ end;
+
+{ if mic[device] <> -1 then begin
+ Log.LogAnalyze('Found the mic at input ' + IntToStr(Mic[device]))
+ end else begin
+ Log.LogAnalyze('Mic not found');
+ mic[device] := 0; // setting to the first one (for kxproject)
+ end;
+ SoundCard[SC].InputSeleceted := Mic[Device];}
+
+
+ BASS_RecordFree;
+
+ Inc(SC);
+ Descr := BASS_RecordGetDeviceDescription(SC);
+ end; // while
+end;
+end.
+
+
diff --git a/Game/Code/Classes/USkins.pas b/Game/Code/Classes/USkins.pas
new file mode 100644
index 00000000..547f4c2c
--- /dev/null
+++ b/Game/Code/Classes/USkins.pas
@@ -0,0 +1,162 @@
+unit USkins;
+
+interface
+
+type
+ TSkinTexture = record
+ Name: string;
+ FileName: string;
+ end;
+
+ TSkinEntry = record
+ Theme: string;
+ Name: string;
+ Path: string;
+ FileName: string;
+ Creator: string; // not used yet
+ end;
+
+ TSkin = class
+ Skin: array of TSkinEntry;
+ SkinTexture: array of TSkinTexture;
+ SkinPath: string;
+ Color: integer;
+ constructor Create;
+ procedure LoadList;
+ procedure ParseDir(Dir: string);
+ procedure LoadHeader(FileName: string);
+ procedure LoadSkin(Name: string);
+ function GetTextureFileName(TextureName: string): string;
+ function GetSkinNumber(Name: string): integer;
+ procedure onThemeChange;
+ end;
+
+var
+ Skin: TSkin;
+
+implementation
+
+uses IniFiles,
+ Classes,
+ SysUtils,
+ ULog,
+ UIni;
+
+constructor TSkin.Create;
+begin
+ LoadList;
+// LoadSkin('Lisek');
+// SkinColor := Color;
+end;
+
+procedure TSkin.LoadList;
+var
+ SR: TSearchRec;
+ SR2: TSearchRec;
+ SLen: integer;
+begin
+ if FindFirst('Skins\*', faDirectory, SR) = 0 then begin
+ repeat
+ if (SR.Name <> '.') and (SR.Name <> '..') then
+ ParseDir('Skins\' + SR.Name + '\');
+ until FindNext(SR) <> 0;
+ end; // if
+ FindClose(SR);
+end;
+
+procedure TSkin.ParseDir(Dir: string);
+var
+ SR: TSearchRec;
+ SLen: integer;
+begin
+ if FindFirst(Dir + '*.ini', faAnyFile, SR) = 0 then begin
+ repeat
+ if (SR.Name <> '.') and (SR.Name <> '..') then
+ LoadHeader(Dir + SR.Name);
+ //Log.LogError(SR.Name);
+ until FindNext(SR) <> 0;
+ end;
+end;
+
+procedure TSkin.LoadHeader(FileName: string);
+var
+ SkinIni: TMemIniFile;
+ S: integer;
+begin
+ SkinIni := TMemIniFile.Create(FileName);
+
+ S := Length(Skin);
+ SetLength(Skin, S+1);
+ Skin[S].Path := IncludeTrailingBackslash(ExtractFileDir(FileName));
+ Skin[S].FileName := ExtractFileName(FileName);
+ Skin[S].Theme := SkinIni.ReadString('Skin', 'Theme', '');
+ Skin[S].Name := SkinIni.ReadString('Skin', 'Name', '');
+ Skin[S].Creator := SkinIni.ReadString('Skin', 'Creator', '');
+
+ SkinIni.Free;
+end;
+
+procedure TSkin.LoadSkin(Name: string);
+var
+ SkinIni: TMemIniFile;
+ SL: TStringList;
+ T: integer;
+ S: integer;
+begin
+ S := GetSkinNumber(Name);
+ SkinPath := Skin[S].Path;
+
+ SkinIni := TMemIniFile.Create(SkinPath + Skin[S].FileName);
+
+ SL := TStringList.Create;
+ SkinIni.ReadSection('Textures', SL);
+
+ SetLength(SkinTexture, SL.Count);
+ for T := 0 to SL.Count-1 do begin
+ SkinTexture[T].Name := SL.Strings[T];
+ SkinTexture[T].FileName := SkinIni.ReadString('Textures', SL.Strings[T], '');
+ end;
+
+ SL.Free;
+ SkinIni.Free;
+end;
+
+function TSkin.GetTextureFileName(TextureName: string): string;
+var
+ T: integer;
+begin
+ Result := '';
+ for T := 0 to High(SkinTexture) do
+ if SkinTexture[T].Name = TextureName then Result := SkinPath + SkinTexture[T].FileName;
+
+{ Result := SkinPath + 'Bar.jpg';
+ if TextureName = 'Ball' then Result := SkinPath + 'Ball.bmp';
+ if Copy(TextureName, 1, 4) = 'Gray' then Result := SkinPath + 'Ball.bmp';
+ if Copy(TextureName, 1, 6) = 'NoteBG' then Result := SkinPath + 'Ball.bmp';}
+end;
+
+function TSkin.GetSkinNumber(Name: string): integer;
+var
+ S: integer;
+begin
+ Result := 0; // set default to the first available skin
+ for S := 0 to High(Skin) do
+ if Skin[S].Name = Name then Result := S;
+end;
+
+procedure TSkin.onThemeChange;
+var
+ S: integer;
+ Name: String;
+begin
+ Ini.SkinNo:=0;
+ SetLength(ISkin, 0);
+ Name := Uppercase(ITheme[Ini.Theme]);
+ for S := 0 to High(Skin) do
+ if Name = Uppercase(Skin[S].Theme) then begin
+ SetLength(ISkin, Length(ISkin)+1);
+ ISkin[High(ISkin)] := Skin[S].Name;
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas
new file mode 100644
index 00000000..39aeba31
--- /dev/null
+++ b/Game/Code/Classes/USongs.pas
@@ -0,0 +1,794 @@
+unit USongs;
+
+interface
+uses SysUtils, ULog, UTexture, UCatCovers;
+
+const
+ SONG_LOAD_COMPLETE = true;
+ SONG_LOAD_NOTES = false;
+
+type
+ TMedleySource = ( msNone, msCalculated, msTag );
+
+ TMedley = record
+ Source: TMedleySource; //source of the information
+ StartBeat: integer; //start beat of medley
+ EndBeat: integer; //end beat of medley
+ FadeIn_time: real; //FadeIn-Time in seconds
+ FadeOut_time: real; //FadeOut-Time in seconds
+ end;
+
+ { used to hold header tags that are not supported by this version of
+ usdx (e.g. some tags from ultrastar 0.7.0) when songs are loaded in
+ songeditor. They will be written the end of the song header } //from usdx 1.1
+ TCustomHeaderTag = record
+ Tag: String;
+ Content: String;
+ end;
+
+ TBPM = record
+ BPM: real;
+ StartBeat: real;
+ end;
+
+ TScore = record
+ Name: string;
+ Score: integer;
+ Length: string;
+ Date: string;
+ end;
+
+ TSong = record
+ Path: string;
+ Folder: string; // for sorting by folder
+ FileName: string;
+
+ Medley: TMedley;
+ PreviewStart: real; //in seconds
+ CustomTags: array of TCustomHeaderTag; // from 1.1
+
+ // sorting methods
+ Category: array of string; // I think I won't need this
+ Genre: string;
+ Edition: string;
+ Language: string; // 0.5.0: new
+
+ Title: string;
+ Artist: string;
+
+ Text: string;
+ Creator: string;
+
+ Cover: string;
+ CoverTex: TTexture;
+ Mp3: string;
+ Background: string;
+ Video: string;
+ VideoGAP: real;
+ VideoLoaded: boolean; // 0.5.0: true if the video has been loaded
+ NotesGAP: integer;
+ Start: real; // in seconds
+ Finish: integer; // in miliseconds
+ Relative: boolean;
+ Resolution: integer;
+ BPM: array of TBPM;
+ GAP: real; // in miliseconds
+
+ Score: array[0..2] of array of TScore;
+
+ // these are used when sorting is enabled
+ Visible: boolean; // false if hidden, true if visible
+ Main: boolean; // false for songs, true for category buttons
+ OrderNum: integer; // has a number of category for category buttons and songs
+ OrderTyp: integer; // type of sorting for this button (0=name)
+ CatNumber: integer; // Count of Songs in Category for Cats and Number of Song in Category for Songs
+ end;
+
+ TSongs = class
+ private
+ BrowsePos: Cardinal; //Actual Pos in Song Array
+ public
+ Song: array of TSong; // array of songs
+ Selected: integer; // selected song index
+ procedure LoadSongList; // load all songs
+ procedure BrowseDir(Dir: string); // should return number of songs in the future
+ procedure Sort(Order: integer);
+ function FindSongFile(Dir, Mask: string): string;
+ end;
+
+ TCatSongs = class
+ Song: array of TSong; // array of categories with songs
+ Selected: integer; // selected song index
+ Order: integer; // order type (0=title)
+ CatNumShow: integer; // Category Number being seen
+ CatCount: integer; //Number of Categorys
+
+ procedure Refresh; // refreshes arrays by recreating them from Songs array
+// procedure Sort(Order: integer);
+ procedure ShowCategory(Index: integer); // expands all songs in category
+ procedure HideCategory(Index: integer); // hides all songs in category
+ procedure ClickCategoryButton(Index: integer); // uses ShowCategory and HideCategory when needed
+ procedure ShowCategoryList; //Hides all Songs And Show the List of all Categorys
+ function FindNextVisible(SearchFrom:integer): integer; //Find Next visible Song
+ function VisibleSongs: integer; // returns number of visible songs (for tabs)
+ function VisibleIndex(Index: integer): integer; // returns visible song index (skips invisible)
+
+ function SetFilter(FilterStr: String; const fType: Byte): Cardinal;
+ end;
+
+var
+ Songs: TSongs; // all songs
+ CatSongs: TCatSongs; // categorized songs
+ AktSong: TSong; // one song *unknown use)
+
+implementation
+
+uses UFiles, UIni, StrUtils, Umusic;
+
+procedure TSongs.LoadSongList;
+begin
+ Log.LogStatus('Initializing', 'LoadSongList');
+
+ // clear
+ Setlength(Song, 50);
+
+ BrowsePos := 0;
+ // browse directories
+ BrowseDir(SongPath);
+
+ //Set Correct SongArray Length
+ SetLength(Song, BrowsePos);
+// if Ini.Debug = 1 then BrowseDir('D:\Extract\Songs\');
+end;
+
+procedure TSongs.BrowseDir(Dir: string);
+var
+ SR: TSearchRec; // for parsing Songs Directory
+ SLen: integer;
+ res: boolean;
+begin
+ if FindFirst(Dir + '*', faDirectory, SR) = 0 then begin
+ repeat
+ if (SR.Name <> '.') and (SR.Name <> '..') then
+ BrowseDir(Dir + Sr.Name + '\');
+ until FindNext(SR) <> 0;
+ end; // if
+ FindClose(SR);
+
+// Log.LogStatus('Parsing directory: ' + Dir + SR.Name, 'LoadSongList');
+
+ if FindFirst(Dir + '*.txt', 0, SR) = 0 then begin
+// Log.LogStatus('Parsing file: ' + Dir + SR.Name + '\' + SRD.Name, 'LoadSongList');
+ repeat
+ //New Mod for better Memory Management
+
+ SLen := BrowsePos;
+ {//Old
+ SLen := Length(Song);
+ SetLength(Song, SLen + 1);//}
+
+ Song[SLen].Path := Dir;
+ Song[SLen].Folder := Copy(Dir, Length(SongPath)+1, 10000);
+ Song[SLen].Folder := Copy(Song[SLen].Folder, 1, Pos('\', Song[SLen].Folder)-1);
+ Song[SLen].FileName := SR.Name;
+
+ res := AnalyseFile(Song[SLen]); //TODO Hash?
+
+ if res and (Song[SLen].Medley.Source=msNone) then
+ begin
+ SetLength(Czesci, 1);
+ AktSong := Song[SLen];
+ res := LoadSong(Song[SLen].Path + Song[SLen].FileName, SONG_LOAD_NOTES); //TODO Hash?
+
+ if res then
+ begin
+ Song[SLen]:=AktSong;
+ FindRefrainStart(Song[SLen]);
+ end;
+ end;
+
+ if (not res) then Dec(BrowsePos)
+ else begin
+ // scanning complete, file is good
+ // if there is no cover then try to find it
+ if Song[SLen].Cover = '' then Song[SLen].Cover := FindSongFile(Dir, '*[CO].jpg');
+// if Song[SLen].Background = '' then begin
+// Song[SLen].Background := FindSongFile(Dir, '*[BG].jpg');
+// end; // no needed here}
+
+ // fix by adding path. no, don't fix it.
+// if Song[SLen].Cover <> '' then
+// Song[SLen].Cover := Song[SLen].Path + Song[SLen].Cover;
+ end;
+
+ //Change Length Only every 50 Entrys
+ Inc(BrowsePos);
+
+ if (BrowsePos mod 50 = 0) AND (BrowsePos <> 0) then
+ begin
+ SetLength(Song, Length(Song) + 50);
+ end;
+
+ until FindNext(SR) <> 0;
+ end; // if FindFirst
+ FindClose(SR);
+end;
+
+procedure TSongs.Sort(Order: integer);
+var
+ S: integer;
+ S2: integer;
+ TempSong: TSong;
+begin
+ case Order of
+ sEdition: // by edition
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Edition, Song[S-1].Edition) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+ sGenre: // by genre
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Genre, Song[S-1].Genre) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+ sTitle: // by title
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Title, Song[S-1].Title) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+
+ end;
+ sArtist: // by artist
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Artist, Song[S-1].Artist) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+ sFolder: // by folder
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Folder, Song[S-1].Folder) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+ sTitle2: // by title2
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Title, Song[S-1].Title) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+
+ end;
+ sArtist2: // by artist2
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Artist, Song[S-1].Artist) < 0 then begin
+ // zamiana miejscami
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+ sLanguage: // by Language
+ begin
+ for S2 := 0 to Length(Song)-1 do
+ for S := 1 to Length(Song)-1 do
+ if CompareText(Song[S].Language, Song[S-1].Language) < 0 then begin
+ TempSong := Song[S-1];
+ Song[S-1] := Song[S];
+ Song[S] := TempSong;
+ end;
+ end;
+
+ end; // case
+end;
+
+function TSongs.FindSongFile(Dir, Mask: string): string;
+var
+ SR: TSearchRec; // for parsing song directory
+begin
+ Result := '';
+ if FindFirst(Dir + Mask, faDirectory, SR) = 0 then begin
+ Result := SR.Name;
+ end; // if
+ FindClose(SR);
+end;
+
+procedure TCatSongs.Refresh;
+var
+ S: integer; // temporary song index
+ CatLen: integer; // length of CatSongs.Song
+ Letter: char; // current letter for sorting using letter
+ SS: string; // current edition for sorting using edition, genre etc.
+ Order: integer; // number used for ordernum
+ Letter2: char; //
+ CatNumber:integer; // Number of Song in Category
+begin
+ CatNumShow := -1;
+// Songs.Sort(0); // by title
+
+case Ini.Sorting of
+ sEdition: begin
+ Songs.Sort(sArtist);
+ Songs.Sort(sEdition);
+ end;
+ sGenre: begin
+ Songs.Sort(sArtist);
+ Songs.Sort(sGenre);
+ end;
+ sLanguage: begin
+ Songs.Sort(sArtist);
+ Songs.Sort(sLanguage);
+ end;
+ sFolder: begin
+ Songs.Sort(sArtist);
+ Songs.Sort(sFolder);
+ end;
+ sTitle: Songs.Sort(sTitle);
+ sArtist: Songs.Sort(sArtist);
+ sTitle2: Songs.Sort(sTitle2); // by title2
+ sArtist2: Songs.Sort(sArtist2); // by artist2
+
+ end; // case
+
+
+ Letter := ' ';
+ SS := '';
+ Order := 0;
+ CatNumber := 0;
+
+ //Songs leeren
+ SetLength (Song, 0);
+
+ for S := Low(Songs.Song) to High(Songs.Song) do begin
+ if (Ini.Tabs = 1) then
+ if (Ini.Sorting = sEdition) and (CompareText(SS, Songs.Song[S].Edition) <> 0) then begin
+ // add Category Button
+ Inc(Order);
+ SS := Songs.Song[S].Edition;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := '[' + SS + ']';
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+
+
+ // 0.4.3
+ // if SS = 'Singstar' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar Part 2' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar German' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar Spanish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar Italian' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar French' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg';
+ // if SS = 'Singstar Party' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Party.jpg';
+ // if SS = 'Singstar Popworld' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Popworld.jpg';
+ // if SS = 'Singstar 80s' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg';
+ // if SS = 'Singstar 80s Polish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg';
+ // if SS = 'Singstar Rocks' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Rocks.jpg';
+ // if SS = 'Singstar Anthems' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Anthems.jpg';
+
+ {// cover-patch
+ if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';//}
+
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS);
+
+ //CatNumber Patch
+ if (SS <> '') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sGenre) and (CompareText(SS, Songs.Song[S].Genre) <> 0) then begin
+ // add Genre Button
+ Inc(Order);
+ SS := Songs.Song[S].Genre;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := SS;
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS);
+
+ //CatNumber Patch
+ if (SS <> '') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sLanguage) and (CompareText(SS, Songs.Song[S].Language) <> 0) then begin
+ // add Language Button
+ Inc(Order);
+ SS := Songs.Song[S].Language;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := SS;
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS);
+
+ //CatNumber Patch
+ if (SS <> '') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sTitle) and (Length(Songs.Song[S].Title)>=1) and (Letter <> UpCase(Songs.Song[S].Title[1])) then begin
+ // add a letter Category Button
+ Inc(Order);
+ Letter := UpCase(Songs.Song[S].Title[1]);
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := '[' + Letter + ']';
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+// Order := ord(Letter);
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+
+ {// cover-patch
+ if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter);
+
+ //CatNumber Patch
+ if (Letter <> ' ') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sArtist) and (Length(Songs.Song[S].Artist)>=1) and (Letter <> UpCase(Songs.Song[S].Artist[1])) then begin
+ // add a letter Category Button
+ Inc(Order);
+ Letter := UpCase(Songs.Song[S].Artist[1]);
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := '[' + Letter + ']';
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+// Order := ord(Letter);
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter);
+
+ //CatNumber Patch
+ if (Letter <> ' ') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sFolder) and (CompareText(SS, Songs.Song[S].Folder) <> 0) then begin
+ // 0.5.0: add folder tab
+ Inc(Order);
+ SS := Songs.Song[S].Folder;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := SS;
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS);
+
+ //CatNumber Patch
+ if (SS <> '') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end
+
+ else if (Ini.Sorting = sTitle2) AND (Length(Songs.Song[S].Title)>=1) then begin
+ if (ord(Songs.Song[S].Title[1]) > 47) and (ord(Songs.Song[S].Title[1]) < 58) then Letter2 := '#' else Letter2 := UpCase(Songs.Song[S].Title[1]);
+ if (Letter <> Letter2) then begin
+ // add a letter Category Button
+ Inc(Order);
+ Letter := Letter2;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := '[' + Letter + ']';
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+// Order := ord(Letter);
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter);
+
+ //CatNumber Patch
+ if (Letter <> ' ') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end;
+ end
+
+ else if (Ini.Sorting = sArtist2) AND (Length(Songs.Song[S].Artist)>=1) then begin
+ if (ord(Songs.Song[S].Artist[1]) > 47) and (ord(Songs.Song[S].Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpCase(Songs.Song[S].Artist[1]);
+ if (Letter <> Letter2) then begin
+ // add a letter Category Button
+ Inc(Order);
+ Letter := Letter2;
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+ CatSongs.Song[CatLen].Artist := '[' + Letter + ']';
+ CatSongs.Song[CatLen].Main := true;
+ CatSongs.Song[CatLen].OrderTyp := 0;
+// Order := ord(Letter);
+ CatSongs.Song[CatLen].OrderNum := Order;
+
+ {// cover-patch
+ if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg'
+ else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';}
+ CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter);
+
+ //CatNumber Patch
+ if (Letter <> ' ') then
+ begin
+ if (CatLen - CatNumber - 1>=0) then
+ Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy
+ CatNumber := 0;
+ end;
+
+ CatSongs.Song[CatLen].Visible := true;
+ end;
+ end;
+
+
+ CatLen := Length(CatSongs.Song);
+ SetLength(CatSongs.Song, CatLen+1);
+
+ Inc (CatNumber); //Increase Number in Cat
+
+ CatSongs.Song[CatLen] := Songs.Song[S];
+ CatSongs.Song[CatLen].OrderNum := Order; // assigns category
+ CatSongs.Song[CatLen].CatNumber := CatNumber;
+
+ if (Ini.Tabs = 0) then CatSongs.Song[CatLen].Visible := true
+ else if (Ini.Tabs = 1) then CatSongs.Song[CatLen].Visible := false;
+// if (Ini.Tabs = 1) and (Order = 1) then CatSongs.Song[CatLen].Visible := true; // open first tab
+//CatSongs.Song[CatLen].Visible := true;
+
+ end;
+//CatNumber Patch - Set CatNumber of Last Category
+if (ini.Tabs_at_startup = 1) And (high(Song) >=1) then
+ Song[CatLen - CatNumber].CatNumber := CatNumber;//Set CatNumber of Categroy
+//CatCount Patch
+CatCount := Order;
+end;
+
+procedure TCatSongs.ShowCategory(Index: integer);
+var
+ S: integer; // song
+begin
+ CatNumShow := Index;
+ for S := 0 to high(CatSongs.Song) do
+ begin
+ if (CatSongs.Song[S].OrderNum = Index) AND (Not CatSongs.Song[S].Main) then
+ CatSongs.Song[S].Visible := true
+ else
+ CatSongs.Song[S].Visible := false;
+ end;
+end;
+
+procedure TCatSongs.HideCategory(Index: integer); // hides all songs in category
+var
+ S: integer; // song
+begin
+ for S := 0 to high(CatSongs.Song) do begin
+ if not CatSongs.Song[S].Main then
+ CatSongs.Song[S].Visible := false // hides all at now
+ end;
+end;
+
+procedure TCatSongs.ClickCategoryButton(Index: integer);
+var
+ Num, S: integer;
+begin
+ Num := CatSongs.Song[Index].OrderNum;
+ if Num <> CatNumShow then
+ begin
+ ShowCategory(Num);
+ end
+ else begin
+ ShowCategoryList;
+ end;
+end;
+
+//Hide Categorys when in Category Hack
+procedure TCatSongs.ShowCategoryList;
+var
+ Num, S: integer;
+begin
+ //Hide All Songs Show All Cats
+ for S := 0 to high(CatSongs.Song) do begin
+ if CatSongs.Song[S].Main then
+ CatSongs.Song[S].Visible := true
+ else
+ CatSongs.Song[S].Visible := false
+ end;
+ CatSongs.Selected := CatNumShow; //Show last shown Category
+ CatNumShow := -1;
+end;
+//Hide Categorys when in Category Hack End
+
+//Wrong song selected when tabs on bug
+function TCatSongs.FindNextVisible(SearchFrom:integer): integer;//Find next Visible Song
+var
+ I: Integer;
+ begin
+ Result := -1;
+ I := SearchFrom + 1;
+ while not CatSongs.Song[I].Visible do
+ begin
+ Inc (I);
+ if (I>high(CatSongs.Song)) then
+ I := low(CatSongs.Song);
+ if (I = SearchFrom) then //Make One Round and no song found->quit
+ break;
+ end;
+ end;
+//Wrong song selected when tabs on bug End
+
+function TCatSongs.VisibleSongs: integer;
+var
+ S: integer; // song
+begin
+ Result := 0;
+ for S := 0 to high(CatSongs.Song) do
+ if CatSongs.Song[S].Visible = true then Inc(Result);
+end;
+
+function TCatSongs.VisibleIndex(Index: integer): integer;
+var
+ S: integer; // song
+begin
+ Result := 0;
+ for S := 0 to Index-1 do
+ if CatSongs.Song[S].Visible = true then Inc(Result);
+end;
+
+function TCatSongs.SetFilter(FilterStr: String; const fType: Byte): Cardinal;
+var
+ I, J: Integer;
+ cString: String;
+ SearchStr: Array of String;
+begin
+ {fType: 0: All
+ 1: Title
+ 2: Artist}
+ FilterStr := Trim(FilterStr);
+ if FilterStr<>'' then begin
+ Result := 0;
+ //Create Search Array
+ SetLength(SearchStr, 1);
+ I := Pos (' ', FilterStr);
+ While (I <> 0) do
+ begin
+ SetLength (SearchStr, Length(SearchStr) + 1);
+ cString := Copy(FilterStr, 1, I-1);
+ if (cString <> ' ') AND (cString <> '') then
+ SearchStr[High(SearchStr)-1] := cString;
+ Delete (FilterStr, 1, I);
+
+ I := Pos (' ', FilterStr);
+ end;
+ //Copy last Word
+ if (FilterStr <> ' ') AND (FilterStr <> '') then
+ SearchStr[High(SearchStr)] := FilterStr;
+
+ for I:=0 to High(Song) do begin
+ if not Song[i].Main then
+ begin
+ case fType of
+ 0: cString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder;
+ 1: cString := Song[I].Title;
+ 2: cString := Song[I].Artist;
+ end;
+ Song[i].Visible:=True;
+ //Look for every Searched Word
+ For J := 0 to High(SearchStr) do
+ begin
+ Song[i].Visible := Song[i].Visible AND AnsiContainsText(cString, SearchStr[J])
+ end;
+ if Song[i].Visible then
+ Inc(Result);
+ end
+ else
+ Song[i].Visible:=False;
+ end;
+ CatNumShow := -2;
+ end
+ else begin
+ for i:=0 to High(Song) do begin
+ Song[i].Visible:=(Ini.Tabs=1)=Song[i].Main;
+ CatNumShow := -1;
+ end;
+ Result := 0;
+ end;
+end;
+
+end.
diff --git a/Game/Code/Classes/UTexture.pas b/Game/Code/Classes/UTexture.pas
new file mode 100644
index 00000000..f5f47ed9
--- /dev/null
+++ b/Game/Code/Classes/UTexture.pas
@@ -0,0 +1,884 @@
+unit UTexture;
+
+// Plain (alpha = 1)
+// Transparent
+// Transparent Range
+// Font (white is drawn, black is transparent)
+// Font Outline (Font with darker outline)
+// Font Outline 2 (Font with darker outline)
+// Font Black (black is drawn, white is transparent)
+// Font Gray (gray is drawn, white is transparent)
+// Arrow (for arrows, white is white, gray has color, black is transparent);
+
+interface
+uses gl, glu, glext, Windows, Math, Classes, SysUtils, Graphics, JPEG, UThemes, PNGImage;
+
+procedure glGenTextures(n: GLsizei; var textures: GLuint); stdcall; external opengl32;
+//procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;
+//function gluBuild2DMipmaps (target: GLenum; components, width, height: GLint;
+// format, atype: GLenum; data: Pointer): Integer; stdcall; external glu32;
+//procedure glCopyTexImage2D(target: GLenum; level: GLint; internalFormat: GLenum; x, y: GLint; width, height: GLsizei; border: GLint); stdcall; external opengl32;
+
+
+type
+ TTexture = record
+ TexNum: integer;
+ X: real;
+ Y: real;
+ Z: real; // new
+ W: real;
+ H: real;
+ ScaleW: real; // for dynamic scalling while leaving width constant
+ ScaleH: real; // for dynamic scalling while leaving height constant
+ Rot: real; // 0 - 2*pi
+ Int: real; // intensity
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ TexW: real; // used?
+ TexH: real; // used?
+ TexX1: real;
+ TexY1: real;
+ TexX2: real;
+ TexY2: real;
+ Alpha: real;
+ Name: string; // 0.5.0: experimental for handling cache images. maybe it's useful for dynamic skins
+ end;
+
+ TTextureEntry = record
+ Name: string;
+ Typ: string;
+
+ // we use normal TTexture, it's easier to implement and if needed - we copy ready data
+ Texture: TTexture;
+ TextureCache: TTexture; // 0.5.0
+ end;
+
+ TTextureDatabase = record
+ Texture: array of TTextureEntry;
+ end;
+
+ TTextureUnit = class
+ Limit: integer;
+ CreateCacheMipmap: boolean;
+
+// function GetNumberFor
+ function GetTexture(Name, Typ: string): TTexture; overload;
+ function GetTexture(Name, Typ: string; FromCache: boolean): TTexture; overload;
+ function FindTexture(Name: string): integer;
+ function LoadTexture(FromRegistry: boolean; Nazwa, Format, Typ: PChar; Col: LongWord): TTexture; overload;
+ function LoadTexture(Nazwa, Format, Typ: PChar; Col: LongWord): TTexture; overload;
+ function LoadTexture(Nazwa: string): TTexture; overload;
+ function CreateTexture(var Data: array of byte; Name: string; W, H: word; Bits: byte): TTexture;
+ procedure UnloadTexture(Name: string; FromCache: boolean);
+ end;
+
+var
+ Texture: TTextureUnit;
+ TextureDatabase: TTextureDatabase;
+
+
+ // for print screens
+// PrintScreenTex: GLuint;
+// PrintScreenData: array[0..480-1, 0..640-1] of longword;
+ PrintScreenData: array[0..1024*768-1] of longword;
+
+// Tekstur: Gluint;
+ ActTex: GLuint;//integer;
+
+{ Tekstura: array[1..32] of TTekstura;
+ Mipmapping: boolean = true;}
+
+ TexOrygW: integer;
+ TexOrygH: integer;
+ TexNewW: integer;
+ TexNewH: integer;
+{ RLE: array[1..128*128] of byte;
+ RLE2: array[1..128*128] of byte;}
+
+ TexFitW: integer;
+ TexFitH: integer; // new for limit
+
+ TextureD8: array[1..1024*1024] of byte; // 1MB
+ TextureD16: array[1..1024*1024, 1..2] of byte; // luminance/alpha tex (2MB)
+ TextureD24: array[1..1024*1024, 1..3] of byte; // normal 24-bit tex (3MB)
+ TextureD242: array[1..512*512, 1..3] of byte; // normal 24-bit tex (0,75MB)
+ TextureD32: array[1..1024*1024, 1..4] of byte; // transparent 32-bit tex (4MB)
+ // total 40MB at 2048*2048
+ // total 10MB at 1024*1024
+
+{ Paleta: array[0..255, 1..4] of byte;
+ Len: integer;}
+ Mipmapping: Boolean;
+
+ CacheMipmap: array[0..256*256*3-1] of byte; // 3KB
+
+
+implementation
+uses ULog, DateUtils, UCovers;
+
+function TTextureUnit.GetTexture(Name, Typ: string): TTexture;
+begin
+ Result := GetTexture(Name, Typ, true);
+end;
+
+function TTextureUnit.GetTexture(Name, Typ: string; FromCache: boolean): TTexture;
+var
+ T: integer; // texture
+ C: integer; // cover
+ Data: array of byte;
+begin
+ // find texture entry
+ T := FindTexture(Name);
+
+ if T = -1 then begin
+ // create texture entry
+ T := Length(TextureDatabase.Texture);
+ SetLength(TextureDatabase.Texture, T+1);
+ TextureDatabase.Texture[T].Name := Name;
+ TextureDatabase.Texture[T].Typ := Typ;
+
+ // inform database that not textures has been loaded into memory
+ TextureDatabase.Texture[T].Texture.TexNum := -1;
+ TextureDatabase.Texture[T].TextureCache.TexNum := -1;
+ end;
+
+ // use preloaded texture
+ if (not FromCache) or (FromCache and not Covers.CoverExists(Name)) then begin
+ // use full texture
+ if TextureDatabase.Texture[T].Texture.TexNum = -1 then begin
+ // load texture
+ TextureDatabase.Texture[T].Texture := LoadTexture(false, pchar(Name), 'JPG', pchar(Typ), $0);
+ end;
+
+ // use texture
+ Result := TextureDatabase.Texture[T].Texture;
+
+ end;
+
+ if FromCache and Covers.CoverExists(Name) then begin
+ // use cache texture
+ C := Covers.CoverNumber(Name);
+
+ if TextureDatabase.Texture[T].TextureCache.TexNum = -1 then begin
+ // load texture
+ Covers.PrepareData(Name);
+{ Covers.Data[0] := 0;
+ Covers.Data[1] := 0;
+ Covers.Data[2] := 0;
+ Covers.Data[3] := 255;
+ Covers.Data[4] := 255;
+ Covers.Data[5] := 255;}
+ TextureDatabase.Texture[T].TextureCache := CreateTexture(Covers.Data, Name, Covers.Cover[C].W, Covers.Cover[C].H, 24);
+ end;
+
+ // use texture
+ Result := TextureDatabase.Texture[T].TextureCache;
+ end;
+end;
+
+function TTextureUnit.FindTexture(Name: string): integer;
+var
+ T: integer; // texture
+begin
+ Result := -1;
+ for T := 0 to high(TextureDatabase.Texture) do
+ if TextureDatabase.Texture[T].Name = Name then
+ Result := T;
+end;
+
+function TTextureUnit.LoadTexture(FromRegistry: boolean; Nazwa, Format, Typ: PChar; Col: LongWord): TTexture;
+var
+
+// a patch from Linnex, that solves the font problem in wine which causes chrashes
+ ChangeFormatBMP: TBitmap;
+// end of patch (11.11.07)
+
+
+ Res: TResourceStream;
+ TextureB: TBitmap;
+ TextureJ: TJPEGImage;
+ TexturePNG: TPNGObject;
+ TextureAlpha: array of byte;
+ AlphaPtr: PByte;
+ TransparentColor: TColor;
+ PixelColor: TColor;
+
+ Pet: integer;
+ Pet2: integer;
+ Pix: integer;
+ ColInt: real;
+ PPix: PByteArray;
+ TempA: integer;
+ Error: integer;
+ SkipX: integer;
+ myAlpha: Real;
+begin
+ Log.BenchmarkStart(4);
+ Mipmapping := true;
+
+ if FromRegistry then begin
+ try
+ Res := TResourceStream.Create(HInstance, Nazwa, Format);
+ except
+ beep;
+ Exit;
+ end;
+ end;
+
+ if FromRegistry or ((not FromRegistry) and FileExists(Nazwa)) then begin
+ TextureB := TBitmap.Create;
+
+ if Format = 'BMP' then begin
+ if FromRegistry then TextureB.LoadFromStream(Res)
+ else TextureB.LoadFromFile(Nazwa);
+ end
+
+ else if Format = 'JPG' then begin
+ TextureJ := TJPEGImage.Create;
+ if FromRegistry then TextureJ.LoadFromStream(Res)
+ else begin
+ if FileExists(Nazwa) then
+ TextureJ.LoadFromFile(Nazwa)
+ else
+ Exit;
+ end;
+ TextureB.Assign(TextureJ);
+ TextureJ.Free;
+ end
+
+ else if Format = 'PNG' then begin
+ TexturePNG := TPNGObject.Create;
+ if FromRegistry then TexturePNG.LoadFromStream(Res)
+ else begin
+ if FileExists(Nazwa) then
+ TexturePNG.LoadFromFile(Nazwa)
+ else
+ Exit;
+ end;
+ TextureB.Assign(TexturePNG);
+ // transparent png hack start (part 1 of 2)
+ if (Typ = 'Transparent') and (TexturePNG.TransparencyMode = ptmPartial) then
+ begin
+ setlength(TextureAlpha, TextureB.Width*TextureB.Height);
+ if (TexturePNG.Header.ColorType = COLOR_GRAYSCALEALPHA) or
+ (TexturePNG.Header.ColorType = COLOR_RGBALPHA) then
+ begin
+ // i would have preferred english variables here but i use Pet because i'm lazy
+ for Pet := 0 to TextureB.Height - 1 do
+ begin
+ AlphaPtr := PByte(TexturePNG.AlphaScanline[Pet]);
+ for Pet2 := 0 to TextureB.Width - 1 do
+ begin
+ TextureAlpha[Pet*TextureB.Width+Pet2]:= AlphaPtr^;
+ Inc(AlphaPtr);
+ end;
+ end;
+ end;
+ end else
+ setlength(TextureAlpha,0); // just no special transparency for unimplemented transparency types (ptmBit)
+ // transparent png hack end
+ TexturePNG.Free;
+ end;
+
+ if FromRegistry then Res.Free;
+
+ if (TextureB.Width > 1024) or (TextureB.Height > 1024) then begin // will be fixed in 0.5.1 and dynamically extended to 8192x8192 depending on the driver
+ Log.LogError('Image ' + Nazwa + ' is too big (' + IntToStr(TextureB.Width) + 'x' + IntToStr(TextureB.Height) + ')');
+ Result.TexNum := -1;
+ end else begin
+
+ glGenTextures(1, ActTex);
+ glBindTexture(GL_TEXTURE_2D, ActTex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if Typ = 'Plain' then begin
+ // wymiary
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+
+ // kopiowanie
+ TextureB.PixelFormat := pf24bit;
+{ if (TextureB.PixelFormat = pf8bit) then begin
+ for Pet := 0 to TexOrygH-1 do begin
+ for Pet2 := 0 to TexOrygW-1 do begin
+ Pix := TextureB.Canvas.Pixels[Pet2, Pet];
+ TextureD24[Pet*TexNewW + Pet2+1, 1] := Pix;
+ TextureD24[Pet*TexNewW + Pet2+1, 2] := Pix div 256;
+ TextureD24[Pet*TexNewW + Pet2+1, 3] := Pix div (256*256);
+ end;
+ end;
+ end;}
+ if (TexOrygW <= Limit) and (TexOrygW <= Limit) then begin
+ if (TextureB.PixelFormat = pf24bit) then begin
+ for Pet := 0 to TexOrygH-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TexOrygW-1 do begin
+ TextureD24[Pet*TexNewW + Pet2+1, 1] := PPix[Pet2*3+2];
+ TextureD24[Pet*TexNewW + Pet2+1, 2] := PPix[Pet2*3+1];
+ TextureD24[Pet*TexNewW + Pet2+1, 3] := PPix[Pet2*3];
+ end;
+ end;
+ end;
+ end else begin
+ // limit
+ TexFitW := 4 * (TexOrygW div 4); // fix for bug in gluScaleImage
+ TexFitH := TexOrygH;
+ if (TextureB.PixelFormat = pf24bit) then begin
+ for Pet := 0 to TexOrygH-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TexOrygW-1 do begin
+ TextureD24[Pet*TexFitW + Pet2+1, 1] := PPix[Pet2*3+2];
+ TextureD24[Pet*TexFitW + Pet2+1, 2] := PPix[Pet2*3+1];
+ TextureD24[Pet*TexFitW + Pet2+1, 3] := PPix[Pet2*3];
+ end;
+ end;
+ end;
+ gluScaleImage(GL_RGB, TexFitW, TexFitH, GL_UNSIGNED_BYTE, @TextureD24,
+ Limit, Limit, GL_UNSIGNED_BYTE, @TextureD24); // takes some time
+
+ TexNewW := Limit;
+ TexNewH := Limit;
+ TexOrygW := Limit;
+ TexOrygH := Limit;
+ end;
+
+ // creating cache mipmap
+ if CreateCacheMipmap then begin
+ if (TexOrygW <> TexNewW) or (TexOrygH <> TexNewH) then begin
+ // texture only uses some of it's space. there's a need for resize to fit full size
+ // and get best quality
+ TexFitW := 4 * (TexOrygW div 4); // 0.5.0: fix for bug in gluScaleImage
+ SkipX := (TexOrygW div 2) mod 2; // 0.5.0: try to center image
+
+ TexFitH := TexOrygH;
+ for Pet := 0 to TexOrygH-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TexOrygW-1 do begin
+ TextureD242[Pet*TexFitW + Pet2+1, 1] := PPix[(Pet2+SkipX)*3+2];
+ TextureD242[Pet*TexFitW + Pet2+1, 2] := PPix[(Pet2+SkipX)*3+1];
+ TextureD242[Pet*TexFitW + Pet2+1, 3] := PPix[(Pet2+SkipX)*3];
+ end;
+ end;
+ gluScaleImage(GL_RGB, TexFitW, TexFitH, GL_UNSIGNED_BYTE, @TextureD242,
+ Covers.W, Covers.H, GL_UNSIGNED_BYTE, @CacheMipmap[0]); // takes some time
+
+ end else begin
+ // texture fits perfectly
+ gluScaleImage(GL_RGB, TexOrygW, TexOrygH, GL_UNSIGNED_BYTE, @TextureD24,
+ Covers.W, Covers.H, GL_UNSIGNED_BYTE, @CacheMipmap[0]); // takes some time
+ end;
+ end;
+
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, TexNewW, TexNewH, 0, GL_RGB, GL_UNSIGNED_BYTE, @TextureD24);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TexNewW, TexNewH, GL_RGB, GL_UNSIGNED_BYTE, @TextureD24);
+ if Error > 0 then beep;
+ end
+ end;
+
+ if Typ = 'Transparent' then begin
+ // wymiary
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+ TextureB.Width := TexNewW;
+ TextureB.Height := TexNewH;
+
+ // kopiowanie
+ for Pet := 0 to TexOrygH-1 do begin
+ for Pet2 := 0 to TexOrygW-1 do begin
+ Pix := TextureB.Canvas.Pixels[Pet2, Pet];
+ // ,- part of transparent png hack
+ if ((Pix = $fefefe) or (Pix = Col)) and (length(TextureAlpha)=0) then begin //Small fix, that caused artefacts to be drawn (#fe == dec254)
+ TextureD32[Pet*TexNewW + Pet2 + 1, 1] := 0;
+ TextureD32[Pet*TexNewW + Pet2 + 1, 2] := 0;
+ TextureD32[Pet*TexNewW + Pet2 + 1, 3] := 0;
+ TextureD32[Pet*TexNewW + Pet2 + 1, 4] := 0;
+ end else begin
+ TextureD32[Pet*TexNewW + Pet2+1, 1] := Pix;
+ TextureD32[Pet*TexNewW + Pet2+1, 2] := Pix div 256;
+ TextureD32[Pet*TexNewW + Pet2+1, 3] := Pix div (256*256);
+ // transparent png hack start (part 2 of 2)
+ if (Format = 'PNG') and (length(TextureAlpha) <> 0) then begin
+ myAlpha:=TextureAlpha[Pet*TexOrygW+Pet2];
+
+ // the following calculations tweak transparency so that it really looks transparent
+ myAlpha:=myAlpha-75;
+ if myAlpha < 0 then myAlpha:=0;
+ myAlpha:=myAlpha/180;
+ myAlpha:=myAlpha*myAlpha*myAlpha;
+ myAlpha:=myAlpha*255;
+
+ TextureD32[Pet*TexNewW+Pet2+1,4]:=floor(myAlpha);
+ end else
+ // transparent png hack end
+ TextureD32[Pet*TexNewW + Pet2+1, 4] := 255;
+ end;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TexNewW, TexNewH, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+{ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 4, TextureB.Width, TextureB.Height, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ if Error > 0 then beep;
+ end;}
+ end;
+
+ if Typ = 'Transparent Range' then begin
+ // wymiary
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+ TextureB.Width := TexNewW;
+ TextureB.Height := TexNewH;
+ // kopiowanie
+ for Pet := 0 to TexOrygH-1 do begin
+ for Pet2 := 0 to TexOrygW-1 do begin
+ Pix := TextureB.Canvas.Pixels[Pet2, Pet];
+ TextureD32[Pet*TexNewW + Pet2+1, 1] := Pix;
+ TextureD32[Pet*TexNewW + Pet2+1, 2] := Pix div 256;
+ TextureD32[Pet*TexNewW + Pet2+1, 3] := Pix div (256*256);
+ TextureD32[Pet*TexNewW + Pet2+1, 4] := 256 - Pix div 256;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TexNewW, TexNewH, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+{ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 4, TextureB.Width, TextureB.Height, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ if Error > 0 then beep;
+ end;}
+ end;
+
+ if Typ = 'Font' then begin
+
+// a patch from Linnex, that solves the font problem in wine which causes chrashes
+ //TextureB.PixelFormat := pf24bit;
+ ChangeFormatBMP := TBitmap.Create();
+ ChangeFormatBMP.Assign(TextureB);
+ TextureB.PixelFormat := pf24bit;
+ TextureB.Width := ChangeFormatBMP.Width;
+ TextureB.Height := ChangeFormatBMP.Height;
+ TextureB.Canvas.Draw(0, 0, ChangeFormatBMP);
+ ChangeFormatBMP.Free;
+// end of patch (11.11.07)
+
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2 * 3];
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 1] := 255;
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 2] := Pix;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 2, TextureB.Width, TextureB.Height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+
+ if Mipmapping then glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 2, TextureB.Width, TextureB.Height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+ if Error > 0 then beep;
+ end;
+ end;
+
+ if Typ = 'Font Outline' then begin
+ TextureB.PixelFormat := pf24bit;
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2 * 3];
+
+ Col := Pix;
+ if Col < 127 then Col := 127;
+
+ TempA := Pix;
+ if TempA >= 95 then TempA := 255;
+ if TempA >= 31 then TempA := 255;
+ if Pix < 95 then TempA := (Pix * 256) div 96;
+
+
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 1] := Col;
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 2] := TempA;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 2, TextureB.Width, TextureB.Height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+
+ if Mipmapping then glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 2, TextureB.Width, TextureB.Height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+ if Error > 0 then beep;
+ end;
+ end;
+
+ if Typ = 'Font Outline 2' then begin
+ TextureB.PixelFormat := pf24bit;
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2 * 3];
+
+ Col := Pix;
+ if Col < 31 then Col := 31;
+
+ TempA := Pix;
+ if TempA >= 31 then TempA := 255;
+ if Pix < 31 then TempA := Pix * (256 div 32);
+
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 1] := Col;
+ TextureD16[Pet*TextureB.Width + Pet2 + 1, 2] := TempA;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 2, TextureB.Width, TextureB.Height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+
+ if Mipmapping then glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 2, TextureB.Width, TextureB.Height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @TextureD16);
+ if Error > 0 then beep;
+ end;
+ end;
+
+ if Typ = 'Font Black' then begin
+ // normalnie 0,125s bez niczego 0,015s - 0,030s z pix 0,125s
+ // wymiary
+ TextureB.PixelFormat := pf24bit;
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+ TextureB.Width := TexNewW;
+ TextureB.Height := TexNewH;
+ // kopiowanie
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2*3];
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 1] := 255;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 2] := 255;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 3] := 255;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 4] := 255 - (Pix mod 256);
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureB.Width, TextureB.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ end;
+
+ if Typ = 'Alpha Black Colored' then begin
+ TextureB.PixelFormat := pf24bit;
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+ TextureB.Width := TexNewW;
+ TextureB.Height := TexNewH;
+ // kopiowanie
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2*3];
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 1] := (Col div $10000) and $FF;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 2] := (Col div $100) and $FF;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 3] := Col and $FF;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 4] := 255 - (Pix mod 256);
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureB.Width, TextureB.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ end;
+
+ if Typ = 'Font Gray' then begin
+ // wymiary
+ TexOrygW := TextureB.Width;
+ TexOrygH := TextureB.Height;
+ TexNewW := Round(Power(2, Ceil(Log2(TexOrygW))));
+ TexNewH := Round(Power(2, Ceil(Log2(TexOrygH))));
+ TextureB.Width := TexNewW;
+ TextureB.Height := TexNewH;
+ // kopiowanie
+ for Pet := 0 to TextureB.Height-1 do begin
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := TextureB.Canvas.Pixels[Pet2, Pet];
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 1] := 127;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 2] := 127;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 3] := 127;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 4] := 255 - (Pix mod 256);
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureB.Width, TextureB.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+{ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 4, TextureB.Width, TextureB.Height, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ if Error > 0 then beep;
+ end;}
+ end;
+
+ if Typ = 'Arrow' then begin
+ TextureB.PixelFormat := pf24bit;
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ Pix := PPix[Pet2 * 3];
+
+ // transparency
+ if Pix >= 127 then TempA := 255;
+ if Pix < 127 then TempA := Pix * 2;
+
+ // ColInt = color intensity
+ if Pix < 127 then ColInt := 1;
+ if Pix >= 127 then ColInt := 2 - Pix / 128;
+ //0.75, 0.6, 0.25
+
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 1] := Round(ColInt * 0.75 * 255 + (1 - ColInt) * 255);
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 2] := Round(ColInt * 0.6 * 255 + (1 - ColInt) * 255);
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 3] := Round(ColInt * 0.25 * 255 + (1 - ColInt) * 255);
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 4] := TempA;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureB.Width, TextureB.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+
+ if Mipmapping then glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 4, TextureB.Width, TextureB.Height, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ if Error > 0 then beep;
+ end;
+ end;
+
+ if Typ = 'Note Plain' then begin
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+
+
+
+ // Skin Patch
+ // 0-191= Fade Black to Col, 192= Col, 193-254 Fade Col to White, 255= White
+ case PPix[Pet2*3] of
+ 0..191: Pix := $10000 * ((((Col div $10000) and $FF) * PPix[Pet2*3]) div $Bf) + $100 * ((((Col div $100) and $FF) * PPix[Pet2*3]) div $Bf) + (((Col and $FF) * PPix[Pet2*3]) div $Bf);
+ 192: Pix := Col;
+ 193..254: Pix := Col + ($10000 * ((($FF - ((Col div $10000) and $FF)) * ((PPix[Pet2*3] - $C0) * 4) ) div $FF) + $100 * ((($FF - ((Col div $100) and $FF)) * ((PPix[Pet2*3] - $C0) * 4)) div $FF) + ((($FF - (Col and $FF)) * ((PPix[Pet2*3] - $C0) * 4)) div $FF));
+ 255: Pix := $FFFFFF;
+ end;
+// 0.5.0. Original
+// case PPix[Pet2*3] of
+// 128: Pix := $10000 * ((Col div $10000) div 2) + $100 * (((Col div $100) and $FF) div 2) + (Col and $FF) div 2;
+// 192: Pix := Col;
+// 255: Pix := $FFFFFF;
+// end;
+
+
+
+
+
+ TextureD24[Pet*TextureB.Width + Pet2 + 1, 1] := Pix div $10000;
+ TextureD24[Pet*TextureB.Width + Pet2 + 1, 2] := (Pix div $100) and $FF;
+ TextureD24[Pet*TextureB.Width + Pet2 + 1, 3] := Pix and $FF;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureB.Width, TextureB.Height, 0, GL_RGB, GL_UNSIGNED_BYTE, @TextureD24);
+ end;
+
+ if Typ = 'Note Transparent' then begin
+ for Pet := 0 to TextureB.Height-1 do begin
+ PPix := TextureB.ScanLine[Pet];
+ for Pet2 := 0 to TextureB.Width-1 do begin
+ TempA := 255;
+
+
+
+ //Skin Patch
+ // 0= Transparent, 1-191= Fade Black to Col, 192= Col, 193-254 Fade Col to White, 255= White
+ case PPix[Pet2*3] of
+ 0: TempA := 0;
+ 1..191: Pix := $10000 * ((((Col div $10000) and $FF) * PPix[Pet2*3]) div $Bf) + $100 * ((((Col div $100) and $FF) * PPix[Pet2*3]) div $Bf) + (((Col and $FF) * PPix[Pet2*3]) div $Bf);
+ 192: Pix := Col;
+ 193..254: Pix := Col + ($10000 * ((($FF - ((Col div $10000) and $FF)) * ((PPix[Pet2*3] - $C0) * 4) ) div $FF) + $100 * ((($FF - ((Col div $100) and $FF)) * ((PPix[Pet2*3] - $C0) * 4)) div $FF) + ((($FF - (Col and $FF)) * ((PPix[Pet2*3] - $C0) * 4)) div $FF));
+ 255: Pix := $FFFFFF;
+ end;
+// 0.5.0 Original
+// case PPix[Pet2*3] of
+// 0: TempA := 0;
+// 128: Pix := $10000 * ((Col div $10000) div 2) + $100 * (((Col div $100) and $FF) div 2) + (Col and $FF) div 2;
+// 192: Pix := Col;
+// 255: Pix := $FFFFFF;
+// end;
+
+
+
+
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 1] := Pix div $10000;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 2] := (Pix div $100) and $FF;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 3] := Pix and $FF;
+ TextureD32[Pet*TextureB.Width + Pet2 + 1, 4] := TempA;
+ end;
+ end;
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureB.Width, TextureB.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @TextureD32);
+ end;
+
+
+
+
+ TextureB.Free;
+// Inc(ActTex);
+{ Tekst.Tekstura := ActTex;
+ Tekst.W := TexOrygW;
+ Tekst.H := TexOrygH;
+ Tekst.X2 := TexOrygW/TexNewW;
+ Tekst.Y2 := TexOrygH/TexNewH;}
+ Result.X := 0;
+ Result.Y := 0;
+ Result.W := 0;
+ Result.H := 0;
+ Result.ScaleW := 1;
+ Result.ScaleH := 1;
+ Result.Rot := 0;
+ Result.TexNum := ActTex;
+ Result.TexW := TexOrygW / TexNewW;
+ Result.TexH := TexOrygH / TexNewH;
+
+ Result.Int := 1;
+ Result.ColR := 1;
+ Result.ColG := 1;
+ Result.ColB := 1;
+ Result.Alpha := 1;
+
+ // 0.4.2 new test - default use whole texure, taking TexW and TexH as const and changing these
+ Result.TexX1 := 0;
+ Result.TexY1 := 0;
+ Result.TexX2 := 1;
+ Result.TexY2 := 1;
+
+ // 0.5.0
+ Result.Name := Nazwa;
+
+ end;
+
+ Log.BenchmarkEnd(4);
+ if Log.BenchmarkTimeLength[4] >= 1 then
+ Log.LogBenchmark('**********> Texture Load Time Warning - ' + Format + '/' + Nazwa + '/' + Typ, 4);
+
+ end; // logerror
+end;
+
+{procedure ResizeTexture(s: pbytearray; d: pbytearray);
+var
+ Pet: integer;
+ Pet2: integer;
+begin
+ for Pet := 0 to TexNewH*4-1 do
+ for Pet2 := 0 to TexNewW-1 do
+ d[Pet*TexNewW + Pet2] := 0;
+
+ for Pet := 0 to TexOrygH-1 do begin
+ for Pet2 := 0 to TexOrygW-1 do begin
+ d[(Pet*TexNewW + Pet2)*4] := Paleta[s[Pet*TexOrygW + Pet2], 1];
+ d[(Pet*TexNewW + Pet2)*4+1] := Paleta[s[Pet*TexOrygW + Pet2], 2];
+ d[(Pet*TexNewW + Pet2)*4+2] := Paleta[s[Pet*TexOrygW + Pet2], 3];
+ d[(Pet*TexNewW + Pet2)*4+3] := Paleta[s[Pet*TexOrygW + Pet2], 4];
+ end;
+ end;
+end;}
+
+{procedure SetTexture(p: pointer);
+begin
+ glGenTextures(1, Tekstur);
+ glBindTexture(GL_TEXTURE_2D, Tekstur);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, TexNewW, TexNewH, 0, GL_RGBA, GL_UNSIGNED_BYTE, p);
+end;}
+
+function TTextureUnit.LoadTexture(Nazwa, Format, Typ: PChar; Col: LongWord): TTexture;
+begin
+ Result := LoadTexture(false, Nazwa, Format, Typ, Col);
+// Result := LoadTexture(SkinReg, Nazwa, Format, Typ, Col); // default to SkinReg
+
+end;
+
+function TTextureUnit.LoadTexture(Nazwa: string): TTexture;
+begin
+ Result := LoadTexture(false, pchar(Nazwa), 'JPG', 'Plain', 0);
+end;
+
+function TTextureUnit.CreateTexture(var Data: array of byte; Name: string; W, H: word; Bits: byte): TTexture;
+var
+ Pet: integer;
+ Pet2: integer;
+ Pix: integer;
+ ColInt: real;
+ PPix: PByteArray;
+ TempA: integer;
+ Error: integer;
+begin
+ Mipmapping := false;
+
+ glGenTextures(1, ActTex); // ActText = new texture number
+ glBindTexture(GL_TEXTURE_2D, ActTex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, W, H, 0, GL_RGB, GL_UNSIGNED_BYTE, @Data[0]);
+ if Mipmapping then begin
+ Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 3, W, H, GL_RGB, GL_UNSIGNED_BYTE, @Data[0]);
+ if Error > 0 then beep;
+ end;
+
+
+// Inc(ActTex);
+{ Tekst.Tekstura := ActTex;
+ Tekst.W := TexOrygW;
+ Tekst.H := TexOrygH;
+ Tekst.X2 := TexOrygW/TexNewW;
+ Tekst.Y2 := TexOrygH/TexNewH;}
+ Result.X := 0;
+ Result.Y := 0;
+ Result.W := 0;
+ Result.H := 0;
+ Result.ScaleW := 1;
+ Result.ScaleH := 1;
+ Result.Rot := 0;
+ Result.TexNum := ActTex;
+ Result.TexW := 1;
+ Result.TexH := 1;
+
+ Result.Int := 1;
+ Result.ColR := 1;
+ Result.ColG := 1;
+ Result.ColB := 1;
+ Result.Alpha := 1;
+
+ // 0.4.2 new test - default use whole texure, taking TexW and TexH as const and changing these
+ Result.TexX1 := 0;
+ Result.TexY1 := 0;
+ Result.TexX2 := 1;
+ Result.TexY2 := 1;
+
+ // 0.5.0
+ Result.Name := Name;
+end;
+
+procedure TTextureUnit.UnloadTexture(Name: string; FromCache: boolean);
+var
+ T: integer;
+ TexNum: GLuint;
+begin
+ T := FindTexture(Name);
+
+ if not FromCache then begin
+ TexNum := TextureDatabase.Texture[T].Texture.TexNum;
+ if TexNum >= 0 then begin
+ glDeleteTextures(1, @TexNum);
+ TextureDatabase.Texture[T].Texture.TexNum := -1;
+// Log.LogError('Unload texture no '+IntToStr(TexNum));
+ end;
+ end else begin
+ TexNum := TextureDatabase.Texture[T].TextureCache.TexNum;
+ if TexNum >= 0 then begin
+ glDeleteTextures(1, @TexNum);
+ TextureDatabase.Texture[T].TextureCache.TexNum := -1;
+// Log.LogError('Unload texture cache no '+IntToStr(TexNum));
+ end;
+ end;
+end;
+
+end. \ No newline at end of file
diff --git a/Game/Code/Classes/UThemes.pas b/Game/Code/Classes/UThemes.pas
new file mode 100644
index 00000000..c83e70c5
--- /dev/null
+++ b/Game/Code/Classes/UThemes.pas
@@ -0,0 +1,2611 @@
+unit UThemes;
+
+interface
+
+uses
+IniFiles, SysUtils, Classes;
+
+type
+ TRGB = record
+ R: single;
+ G: single;
+ B: single;
+ end;
+
+ {TSkin = record
+ GrayLeft: string;
+ GrayMid: string;
+ GrayRight: string;
+
+ NoteBGLeft: string;
+ NoteBGMid: string;
+ NoteBGRight: string;
+
+ NoteStar: string;
+
+ Ball: string;
+
+
+
+ //SingBar Mod
+ SingBarBack: string;
+ SingBarBar: string;
+ SingBarFront: string;
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ SingLineBonusBack: string;
+ //PhrasenBonus - Line Bonus Mod
+
+
+
+ WelcomeBG: string;
+
+ Background: string;
+ ScoreBG: string;
+ MainStart: string;
+ MainEditor: string;
+ MainOptions: string;
+ MainExit: string;
+ MainBar: string;
+ Cursor: string;
+
+ SongFade: string;
+ SongCover: string;
+ SongSelection: string;
+
+ SelectSong: string;
+ Button: string;
+ Bar: string;
+ P: string;
+ Arrow: string;
+ Arrow2: string;
+ ButtonF: string;
+ Star: string;
+ Line: string;
+
+// ThemePath: string;
+ SkinReg: boolean;
+ SkinName: string;
+ SkinPath: string;
+ SkinColor: integer;
+ end;}
+
+ TThemeBackground = record
+ Tex: string;
+ end;
+
+ TThemeStatic = record
+ X: integer;
+ Y: integer;
+ Z: real;
+ W: integer;
+ H: integer;
+ Color: string;
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ Tex: string;
+ Typ: string;
+ TexX1: real;
+ TexY1: real;
+ TexX2: real;
+ TexY2: real;
+ //Reflection Mod
+ Reflection: boolean;
+ Reflectionspacing: Real;
+ end;
+ AThemeStatic = array of TThemeStatic;
+
+ TThemeText = record
+ X: integer;
+ Y: integer;
+ W: integer;
+ Color: string;
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ Font: integer;
+ Size: integer;
+ Align: integer;
+ Text: string;
+ end;
+ AThemeText = array of TThemeText;
+
+ TThemeButton = record
+ Text: AThemeText;
+ X: integer;
+ Y: integer;
+ Z: Real;
+ W: integer;
+ H: integer;
+ Color: string;
+ ColR: real;
+ ColG: real;
+ ColB: real;
+ Int: real;
+ DColor: string;
+ DColR: real;
+ DColG: real;
+ DColB: real;
+ DInt: real;
+ Tex: string;
+ Typ: string;
+
+ Visible: Boolean;
+
+ //Reflection Mod
+ Reflection: boolean;
+ Reflectionspacing: Real;
+ //Fade Mod
+ SelectH: integer;
+ SelectW: integer;
+ Fade: boolean;
+ FadeText: boolean;
+ DeSelectReflectionspacing : Real;
+ FadeTex: string;
+ FadeTexPos: integer;
+
+ //Button Collection Mod
+ Parent: Byte; //Number of the Button Collection this Button is assigned to. IF 0: No Assignement
+ end;
+
+ //Button Collection Mod
+ TThemeButtonCollection = record
+ Style: TThemeButton;
+ ChildCount: Byte; //No of assigned Childs
+ FirstChild: Byte; //No of Child on whose Interaction Position the Button should be
+ end;
+
+ AThemeButtonCollection = array of TThemeButtonCollection;
+ PAThemeButtonCollection = ^AThemeButtonCollection;
+
+ TThemeSelect = record
+ Tex: string;
+ TexSBG: string;
+ X: integer;
+ Y: integer;
+ W: integer;
+ H: integer;
+ Text: string;
+ ColR, ColG, ColB, Int: real;
+ DColR, DColG, DColB, DInt: real;
+ TColR, TColG, TColB, TInt: real;
+ TDColR, TDColG, TDColB, TDInt: real;
+ SBGColR, SBGColG, SBGColB, SBGInt: real;
+ SBGDColR, SBGDColG, SBGDColB, SBGDInt: real;
+ STColR, STColG, STColB, STInt: real;
+ STDColR, STDColG, STDColB, STDInt: real;
+ SkipX: integer;
+ end;
+
+ TThemeSelectSlide = record
+ Tex: string;
+ TexSBG: string;
+ X: integer;
+ Y: integer;
+ W: integer;
+ H: integer;
+ Z: real;
+
+ TextSize: integer;
+
+ //SBGW Mod
+ SBGW: integer;
+
+ Text: string;
+ ColR, ColG, ColB, Int: real;
+ DColR, DColG, DColB, DInt: real;
+ TColR, TColG, TColB, TInt: real;
+ TDColR, TDColG, TDColB, TDInt: real;
+ SBGColR, SBGColG, SBGColB, SBGInt: real;
+ SBGDColR, SBGDColG, SBGDColB, SBGDInt: real;
+ STColR, STColG, STColB, STInt: real;
+ STDColR, STDColG, STDColB, STDInt: real;
+ SkipX: integer;
+ end;
+
+ PThemeBasic = ^TThemeBasic;
+ TThemeBasic = class
+ Background: TThemeBackground;
+ Text: AThemeText;
+ Static: AThemeStatic;
+
+ //Button Collection Mod
+ ButtonCollection: AThemeButtonCollection;
+ end;
+
+ TThemeLoading = class(TThemeBasic)
+ StaticAnimation: TThemeStatic;
+ TextLoading: TThemeText;
+ end;
+
+ TThemeMain = class(TThemeBasic)
+ ButtonSolo: TThemeButton;
+ ButtonMulti: TThemeButton;
+ ButtonMultiM2: TThemeButton; //for M2-MOD
+ ButtonStat: TThemeButton;
+ ButtonEditor: TThemeButton;
+ ButtonOptions: TThemeButton;
+ ButtonExit: TThemeButton;
+
+ TextDescription: TThemeText;
+ TextDescriptionLong: TThemeText;
+ Description: array[0..6] of string;
+ DescriptionLong: array[0..6] of string;
+ end;
+
+ TThemeName = class(TThemeBasic)
+ ButtonPlayer: array[1..6] of TThemeButton;
+ end;
+
+ TThemeLevel = class(TThemeBasic)
+ ButtonEasy: TThemeButton;
+ ButtonMedium: TThemeButton;
+ ButtonHard: TThemeButton;
+ end;
+
+ TThemeSong = class(TThemeBasic)
+ TextArtist: TThemeText;
+ TextTitle: TThemeText;
+ TextNumber: TThemeText;
+
+ TextPlugin: TThemeText;
+ TextP1: TThemeText;
+ TextP2: TThemeText;
+
+ TextMedley: array[1..4] of TThemeText;
+
+ //Video Icon Mod
+ VideoIcon: TThemeStatic;
+
+ //Medley Icons
+ MedleyIcon: TThemeStatic;
+ CalculatedMedleyIcon: TThemeStatic;
+
+ //Show Cat in TopLeft Mod
+ TextCat: TThemeText;
+ StaticCat: TThemeStatic;
+
+ //Cover Mod
+ Cover: record
+ Reflections: Boolean;
+ X: Integer;
+ Y: Integer;
+ Z: Integer;
+ W: Integer;
+ H: Integer;
+ Style: Integer;
+ end;
+
+ //Equalizer Mod
+ Equalizer: record
+ Visible: Boolean;
+ Direction: Boolean;
+ Alpha: real;
+ X: Integer;
+ Y: Integer;
+ Z: Real;
+ W: Integer;
+ H: Integer;
+ Space: Integer;
+ Bands: Integer;
+ Length: Integer;
+ ColR, ColG, ColB: Real;
+ end;
+
+
+ //Party and Non Party specific Statics and Texts
+ StaticParty: AThemeStatic;
+ TextParty: AThemeText;
+
+ StaticM2Party: AThemeStatic;
+ TextM2Party: AThemeText;
+
+ StaticNonParty: AThemeStatic;
+ TextNonParty: AThemeText;
+
+ //Party Mode
+ StaticTeam1Joker1: TThemeStatic;
+ StaticTeam1Joker2: TThemeStatic;
+ StaticTeam1Joker3: TThemeStatic;
+ StaticTeam1Joker4: TThemeStatic;
+ StaticTeam1Joker5: TThemeStatic;
+ StaticTeam2Joker1: TThemeStatic;
+ StaticTeam2Joker2: TThemeStatic;
+ StaticTeam2Joker3: TThemeStatic;
+ StaticTeam2Joker4: TThemeStatic;
+ StaticTeam2Joker5: TThemeStatic;
+ StaticTeam3Joker1: TThemeStatic;
+ StaticTeam3Joker2: TThemeStatic;
+ StaticTeam3Joker3: TThemeStatic;
+ StaticTeam3Joker4: TThemeStatic;
+ StaticTeam3Joker5: TThemeStatic;
+
+ SongTextPartyTeam1NumJoker: TThemeText;
+ SongTextPartyTeam2NumJoker: TThemeText;
+ SongTextPartyTeam3NumJoker: TThemeText;
+
+ end;
+
+ TThemeSing = class(TThemeBasic)
+ //Show actual SongName for Medley-Mode
+ StaticSongName : TThemeStatic;
+ TextSongName : TThemeText;
+
+ //TimeBar mod
+ StaticTimeProgress: TThemeStatic;
+ TextTimeText : TThemeText;
+ //eoa TimeBar mod
+
+ StaticP1: TThemeStatic;
+ TextP1: TThemeText;
+ StaticP1ScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP1Score: TThemeText;
+
+ //moveable singbar mod
+ StaticP1SingBar: TThemeStatic;
+ StaticP1ThreePSingBar: TThemeStatic;
+ StaticP1TwoPSingBar: TThemeStatic;
+ StaticP2RSingBar: TThemeStatic;
+ StaticP2MSingBar: TThemeStatic;
+ StaticP3SingBar: TThemeStatic;
+ //eoa moveable singbar
+
+ //added for ps3 skin
+ //game in 2/4 player modi
+ StaticP1TwoP: TThemeStatic;
+ StaticP1TwoPScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP1TwoP: TThemeText;
+ TextP1TwoPScore: TThemeText;
+ //game in 3/6 player modi
+ StaticP1ThreeP: TThemeStatic;
+ StaticP1ThreePScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP1ThreeP: TThemeText;
+ TextP1ThreePScore: TThemeText;
+ //eoa
+
+ StaticP2R: TThemeStatic;
+ StaticP2RScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP2R: TThemeText;
+ TextP2RScore: TThemeText;
+
+ StaticP2M: TThemeStatic;
+ StaticP2MScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP2M: TThemeText;
+ TextP2MScore: TThemeText;
+
+ StaticP3R: TThemeStatic;
+ StaticP3RScoreBG: TThemeStatic; //Static for ScoreBG
+ TextP3R: TThemeText;
+ TextP3RScore: TThemeText;
+
+ //Linebonus Translations
+ LineBonusText: Array [0..8] of String;
+
+ VideoAspectText: TThemeText;
+ VideoAspectStatic: TThemeStatic;
+ end;
+
+ TThemeScore = class(TThemeBasic)
+ TextArtist: TThemeText;
+ TextTitle: TThemeText;
+
+ TextArtistTitle: TThemeText;
+
+ StaticMedleyNav: TThemeStatic;
+ TextMedleyNav: TThemeText;
+
+ PlayerStatic: array[1..6] of AThemeStatic;
+ PlayerTexts: array[1..6] of AThemeText;
+
+ TextName: array[1..6] of TThemeText;
+ TextScore: array[1..6] of TThemeText;
+
+ TextNotes: array[1..6] of TThemeText;
+ TextNotesScore: array[1..6] of TThemeText;
+ TextLineBonus: array[1..6] of TThemeText;
+ TextLineBonusScore: array[1..6] of TThemeText;
+ TextGoldenNotes: array[1..6] of TThemeText;
+ TextGoldenNotesScore: array[1..6] of TThemeText;
+ TextTotal: array[1..6] of TThemeText;
+ TextTotalScore: array[1..6] of TThemeText;
+
+ StaticBoxLightest: array[1..6] of TThemeStatic;
+ StaticBoxLight: array[1..6] of TThemeStatic;
+ StaticBoxDark: array[1..6] of TThemeStatic;
+
+ StaticBackLevel: array[1..6] of TThemeStatic;
+ StaticBackLevelRound: array[1..6] of TThemeStatic;
+ StaticLevel: array[1..6] of TThemeStatic;
+ StaticLevelRound: array[1..6] of TThemeStatic;
+
+// Description: array[0..5] of string;}
+ end;
+
+ TThemeTop = class(TThemeBasic)
+ TextLevel: TThemeText;
+ TextArtistTitle: TThemeText;
+
+ StaticNumber: AThemeStatic;
+ TextNumber: AThemeText;
+ TextName: AThemeText;
+ TextScore: AThemeText;
+ TextDate: AThemeText;
+ end;
+
+ TThemeOptions = class(TThemeBasic)
+ ButtonGame: TThemeButton;
+ ButtonGraphics: TThemeButton;
+ ButtonSound: TThemeButton;
+ ButtonLyrics: TThemeButton;
+ ButtonThemes: TThemeButton;
+ ButtonRecord: TThemeButton;
+ ButtonAdvanced: TThemeButton;
+ ButtonExit: TThemeButton;
+
+ TextDescription: TThemeText;
+ Description: array[0..7] of string;
+ end;
+
+ TThemeOptionsGame = class(TThemeBasic)
+ SelectPlayers: TThemeSelect;
+ SelectDifficulty: TThemeSelect;
+ SelectLanguage: TThemeSelectSlide;
+ SelectTabs: TThemeSelect;
+ SelectSorting: TThemeSelectSlide;
+ SelectDebug: TThemeSelect;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsGraphics = class(TThemeBasic)
+ SelectFullscreen: TThemeSelect;
+ SelectSlideResolution: TThemeSelectSlide;
+ SelectDepth: TThemeSelect;
+ SelectOscilloscope: TThemeSelect;
+ SelectLineBonus: TThemeSelect;
+ SelectMovieSize: TThemeSelect;
+ SelectMoviePreview: TThemeSelect;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsSound = class(TThemeBasic)
+ SelectMicBoost: TThemeSelect;
+ SelectClickAssist: TThemeSelect;
+ SelectBeatClick: TThemeSelect;
+ SelectThreshold: TThemeSelect;
+ //Song Preview
+ SelectSlidePreviewVolume: TThemeSelectSlide;
+ SelectSlidePreviewFading: TThemeSelectSlide;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsLyrics = class(TThemeBasic)
+ SelectLyricsFont: TThemeSelect;
+ SelectLyricsEffect: TThemeSelect;
+ SelectSolmization: TThemeSelect;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsThemes = class(TThemeBasic)
+ SelectTheme: TThemeSelectSlide;
+ SelectSkin: TThemeSelectSlide;
+ SelectColor: TThemeSelectSlide;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsRecord = class(TThemeBasic)
+ SelectSlideCard: TThemeSelectSlide;
+ SelectSlideInput: TThemeSelectSlide;
+ SelectSlideChannelL: TThemeSelectSlide;
+ SelectSlideChannelR: TThemeSelectSlide;
+ ButtonExit: TThemeButton;
+ end;
+
+ TThemeOptionsAdvanced = class(TThemeBasic)
+ SelectLoadAnimation: TThemeSelect;
+ SelectEffectSing: TThemeSelect;
+ SelectScreenFade: TThemeSelect;
+ SelectLineBonus: TThemeSelect;
+ SelectAskbeforeDel: TThemeSelect;
+ SelectOnSongClick: TThemeSelectSlide;
+ SelectPartyPopup: TThemeSelect;
+ ButtonExit: TThemeButton;
+ end;
+
+ //Error- and Check-Popup
+ TThemeError = class(TThemeBasic)
+ Button1: TThemeButton;
+ TextError: TThemeText;
+ end;
+
+ TThemeCheck = class(TThemeBasic)
+ Button1: TThemeButton;
+ Button2: TThemeButton;
+ TextCheck: TThemeText;
+ end;
+
+ //Help- Popup
+ TThemeHelp = class(TThemeBasic)
+ Button1: TThemeButton;
+ end;
+
+
+ //ScreenSong Menue
+ TThemeSongMenu = class(TThemeBasic)
+ Button1: TThemeButton;
+ Button2: TThemeButton;
+ Button3: TThemeButton;
+ Button4: TThemeButton;
+
+ SelectSlide3: TThemeSelectSlide;
+
+ TextMenu: TThemeText;
+ end;
+
+ TThemeSongJumpTo = class(TThemeBasic)
+ ButtonSearchText: TThemeButton;
+ SelectSlideType: TThemeSelectSlide;
+ TextFound: TThemeText;
+
+ //Translated Texts
+ Songsfound: String;
+ NoSongsfound: String;
+ CatText: String;
+ IType: array [0..2] of String;
+ end;
+
+ //Party Screens
+ TThemePartyNewRound = class(TThemeBasic)
+ TextRound1: TThemeText;
+ TextRound2: TThemeText;
+ TextRound3: TThemeText;
+ TextRound4: TThemeText;
+ TextRound5: TThemeText;
+ TextRound6: TThemeText;
+ TextRound7: TThemeText;
+ TextWinner1: TThemeText;
+ TextWinner2: TThemeText;
+ TextWinner3: TThemeText;
+ TextWinner4: TThemeText;
+ TextWinner5: TThemeText;
+ TextWinner6: TThemeText;
+ TextWinner7: TThemeText;
+ TextNextRound: TThemeText;
+ TextNextRoundNo: TThemeText;
+ TextNextPlayer1: TThemeText;
+ TextNextPlayer2: TThemeText;
+ TextNextPlayer3: TThemeText;
+
+ StaticRound1: TThemeStatic;
+ StaticRound2: TThemeStatic;
+ StaticRound3: TThemeStatic;
+ StaticRound4: TThemeStatic;
+ StaticRound5: TThemeStatic;
+ StaticRound6: TThemeStatic;
+ StaticRound7: TThemeStatic;
+
+ TextScoreTeam1: TThemeText;
+ TextScoreTeam2: TThemeText;
+ TextScoreTeam3: TThemeText;
+ TextNameTeam1: TThemeText;
+ TextNameTeam2: TThemeText;
+ TextNameTeam3: TThemeText;
+ TextTeam1Players: TThemeText;
+ TextTeam2Players: TThemeText;
+ TextTeam3Players: TThemeText;
+
+ StaticTeam1: TThemeStatic;
+ StaticTeam2: TThemeStatic;
+ StaticTeam3: TThemeStatic;
+ StaticNextPlayer1: TThemeStatic;
+ StaticNextPlayer2: TThemeStatic;
+ StaticNextPlayer3: TThemeStatic;
+ end;
+
+ //PartyNewRoundM2
+ TThemePartyNewRoundM2 = class(TThemeBasic)
+ TextRound: array [1..9] of TThemeText;
+ TextWinner: array [1..9] of TThemeText;
+
+ TextNextRound: TThemeText;
+ TextNextRoundNo: TThemeText;
+ TextNextPlayer1: TThemeText;
+ TextNextPlayer2: TThemeText;
+ TextHandicap: TThemeText;
+
+ StaticRound: array [1..9] of TThemeStatic;
+ StaticTable: array [1..9] of TThemeStatic;
+
+ TextScoreTeam1: TThemeText;
+ TextScoreTeam2: TThemeText;
+
+ StaticNextPlayer1: TThemeStatic;
+ StaticNextPlayer2: TThemeStatic;
+ StaticHandicap: TThemeStatic;
+
+ TextTableName: array[1..9, 1..7] of TThemeText;
+ end;
+
+ TThemePartyScore = class(TThemeBasic)
+ TextScoreTeam1: TThemeText;
+ TextScoreTeam2: TThemeText;
+ TextScoreTeam3: TThemeText;
+ TextNameTeam1: TThemeText;
+ TextNameTeam2: TThemeText;
+ TextNameTeam3: TThemeText;
+ StaticTeam1: TThemeStatic;
+ StaticTeam1BG: TThemeStatic;
+ StaticTeam1Deco: TThemeStatic;
+ StaticTeam2: TThemeStatic;
+ StaticTeam2BG: TThemeStatic;
+ StaticTeam2Deco: TThemeStatic;
+ StaticTeam3: TThemeStatic;
+ StaticTeam3BG: TThemeStatic;
+ StaticTeam3Deco: TThemeStatic;
+
+ DecoTextures: record
+ ChangeTextures: Boolean;
+
+ FirstTexture: String;
+ FirstTyp: String;
+ FirstColor: String;
+
+ SecondTexture: String;
+ SecondTyp: String;
+ SecondColor: String;
+
+ ThirdTexture: String;
+ ThirdTyp: String;
+ ThirdColor: String;
+ end;
+
+
+ TextWinner: TThemeText;
+ end;
+
+ TThemePartyWin = class(TThemeBasic)
+ TextScoreTeam1: TThemeText;
+ TextScoreTeam2: TThemeText;
+ TextScoreTeam3: TThemeText;
+ TextNameTeam1: TThemeText;
+ TextNameTeam2: TThemeText;
+ TextNameTeam3: TThemeText;
+ StaticTeam1: TThemeStatic;
+ StaticTeam1BG: TThemeStatic;
+ StaticTeam1Deco: TThemeStatic;
+ StaticTeam2: TThemeStatic;
+ StaticTeam2BG: TThemeStatic;
+ StaticTeam2Deco: TThemeStatic;
+ StaticTeam3: TThemeStatic;
+ StaticTeam3BG: TThemeStatic;
+ StaticTeam3Deco: TThemeStatic;
+
+ TextWinner: TThemeText;
+ end;
+
+ TThemePartyOptions = class(TThemeBasic)
+ SelectLevel: TThemeSelectSlide;
+ SelectPlayList: TThemeSelectSlide;
+ SelectPlayList2: TThemeSelectSlide;
+ SelectRounds: TThemeSelectSlide;
+ SelectTeams: TThemeSelectSlide;
+ SelectPlayers1: TThemeSelectSlide;
+ SelectPlayers2: TThemeSelectSlide;
+ SelectPlayers3: TThemeSelectSlide;
+
+ {ButtonNext: TThemeButton;
+ ButtonPrev: TThemeButton;}
+ end;
+
+ TThemePartyOptionsM2 = class(TThemeBasic)
+ SelectLevel: TThemeSelectSlide;
+ SelectPlayList: TThemeSelectSlide;
+ SelectPlayList2: TThemeSelectSlide;
+ SelectRounds: TThemeSelectSlide;
+ SelectPlayers1: TThemeSelectSlide;
+ SelectOptionPlugin: TThemeSelectSlide;
+ SelectOptionHandicap: TThemeSelectSlide;
+ end;
+
+ TThemePartyPlayer = class(TThemeBasic)
+ Team1Name: TThemeButton;
+ Player1Name: TThemeButton;
+ Player2Name: TThemeButton;
+ Player3Name: TThemeButton;
+ Player4Name: TThemeButton;
+
+ Team2Name: TThemeButton;
+ Player5Name: TThemeButton;
+ Player6Name: TThemeButton;
+ Player7Name: TThemeButton;
+ Player8Name: TThemeButton;
+
+ Team3Name: TThemeButton;
+ Player9Name: TThemeButton;
+ Player10Name: TThemeButton;
+ Player11Name: TThemeButton;
+ Player12Name: TThemeButton;
+
+ {ButtonNext: TThemeButton;
+ ButtonPrev: TThemeButton;}
+ end;
+
+ TThemePartyPlayerM2 = class(TThemeBasic)
+ Player1Name: TThemeButton;
+ Player2Name: TThemeButton;
+ Player3Name: TThemeButton;
+ Player4Name: TThemeButton;
+ Player5Name: TThemeButton;
+ Player6Name: TThemeButton;
+ Player7Name: TThemeButton;
+ Player8Name: TThemeButton;
+ Player9Name: TThemeButton;
+ end;
+
+ //Stats Screens
+ TThemeStatMain = class(TThemeBasic)
+ ButtonScores: TThemeButton;
+ ButtonSingers: TThemeButton;
+ ButtonSongs: TThemeButton;
+ ButtonBands: TThemeButton;
+ ButtonExit: TThemeButton;
+
+ TextOverview: TThemeText;
+ end;
+
+ TThemeStatDetail = class(TThemeBasic)
+ ButtonNext: TThemeButton;
+ ButtonPrev: TThemeButton;
+ ButtonReverse: TThemeButton;
+ ButtonExit: TThemeButton;
+
+ TextDescription: TThemeText;
+ TextPage: TThemeText;
+ TextList: AThemeText;
+
+ Description: array[0..3] of string;
+ DescriptionR: array[0..3] of string;
+ FormatStr: array[0..3] of string;
+ PageStr: String;
+ end;
+
+ //Playlist Translations
+ TThemePlaylist = record
+ CatText: string;
+ end;
+
+ TTheme = class
+ private
+ {$IFDEF THEMESAVE}
+ ThemeIni: TIniFile;
+ {$ELSE}
+ ThemeIni: TMemIniFile;
+ {$ENDIF}
+
+ LastThemeBasic: TThemeBasic;
+ procedure create_theme_objects();
+ public
+
+ Loading: TThemeLoading;
+ Main: TThemeMain;
+ Name: TThemeName;
+ Level: TThemeLevel;
+ Song: TThemeSong;
+ Sing: TThemeSing;
+ Score: TThemeScore;
+ Top: TThemeTop;
+ Options: TThemeOptions;
+ OptionsGame: TThemeOptionsGame;
+ OptionsGraphics: TThemeOptionsGraphics;
+ OptionsSound: TThemeOptionsSound;
+ OptionsLyrics: TThemeOptionsLyrics;
+ OptionsThemes: TThemeOptionsThemes;
+ OptionsRecord: TThemeOptionsRecord;
+ OptionsAdvanced: TThemeOptionsAdvanced;
+ //error and check popup
+ ErrorPopup: TThemeError;
+ CheckPopup: TThemeCheck;
+ //help popup
+ HelpPopup: TThemeHelp;
+ //ScreenSong extensions
+ SongMenu: TThemeSongMenu;
+ SongJumpto: TThemeSongJumpTo;
+ //Party Screens:
+ PartyNewRound: TThemePartyNewRound;
+ PartyScore: TThemePartyScore;
+ PartyWin: TThemePartyWin;
+ PartyOptions: TThemePartyOptions;
+ PartyPlayer: TThemePartyPlayer;
+
+ //Party M2 Screens
+ PartyOptionsM2: TThemePartyOptionsM2;
+ PartyPlayerM2: TThemePartyPlayerM2;
+ PartyNewRoundM2: TThemePartyNewRoundM2;
+
+ //Stats Screens:
+ StatMain: TThemeStatMain;
+ StatDetail: TThemeStatDetail;
+
+ Playlist: TThemePlaylist;
+
+ ILevel: array[0..2] of String;
+
+ constructor Create(FileName: string); overload; // Initialize theme system
+ constructor Create(FileName: string; Color: integer); overload; // Initialize theme system with color
+ function LoadTheme(FileName: string; sColor: integer): boolean; // Load some theme settings from file
+
+ procedure LoadColors;
+
+ procedure ThemeLoadBasic(Theme: TThemeBasic; Name: string);
+ procedure ThemeLoadBackground(var ThemeBackground: TThemeBackground; Name: string);
+ procedure ThemeLoadText(var ThemeText: TThemeText; Name: string);
+ procedure ThemeLoadTexts(var ThemeText: AThemeText; Name: string);
+ procedure ThemeLoadStatic(var ThemeStatic: TThemeStatic; Name: string);
+ procedure ThemeLoadStatics(var ThemeStatic: AThemeStatic; Name: string);
+ procedure ThemeLoadButton(var ThemeButton: TThemeButton; Name: string; const Collections: PAThemeButtonCollection = nil);
+ procedure ThemeLoadButtonCollection(var Collection: TThemeButtonCollection; Name: string);
+ procedure ThemeLoadButtonCollections(var Collections: AThemeButtonCollection; Name: string);
+ procedure ThemeLoadSelect(var ThemeSelect: TThemeSelect; Name: string);
+ procedure ThemeLoadSelectSlide(var ThemeSelectS: TThemeSelectSlide; Name: string);
+
+ procedure ThemeSave(FileName: string);
+ procedure ThemeSaveBasic(Theme: TThemeBasic; Name: string);
+ procedure ThemeSaveBackground(ThemeBackground: TThemeBackground; Name: string);
+ procedure ThemeSaveStatic(ThemeStatic: TThemeStatic; Name: string);
+ procedure ThemeSaveStatics(ThemeStatic: AThemeStatic; Name: string);
+ procedure ThemeSaveText(ThemeText: TThemeText; Name: string);
+ procedure ThemeSaveTexts(ThemeText: AThemeText; Name: string);
+ procedure ThemeSaveButton(ThemeButton: TThemeButton; Name: string);
+
+ end;
+
+ TColor = record
+ Name: string;
+ RGB: TRGB;
+ end;
+
+function ColorExists(Name: string): integer;
+procedure LoadColor(var R, G, B: real; ColorName: string);
+function GetSystemColor(Color: integer): TRGB;
+function ColorSqrt(RGB: TRGB): TRGB;
+
+var
+ //Skin: TSkin;
+ Theme: TTheme;
+ Color: array of TColor;
+
+implementation
+
+uses
+{{$IFDEF TRANSLATE}
+ ULanguage,
+{{$ENDIF}
+USkins, UIni, Dialogs;
+
+constructor TTheme.Create(FileName: string);
+begin
+ Create(FileName, 0);
+end;
+
+constructor TTheme.Create(FileName: string; Color: integer);
+begin
+(*
+ Loading := TThemeLoading.Create;
+ Main := TThemeMain.Create;
+ Name := TThemeName.Create;
+ Level := TThemeLevel.Create;
+ Song := TThemeSong.Create;
+ Sing := TThemeSing.Create;
+ Score := TThemeScore.Create;
+ Top := TThemeTop.Create;
+ Options := TThemeOptions.Create;
+ OptionsGame := TThemeOptionsGame.Create;
+ OptionsGraphics := TThemeOptionsGraphics.Create;
+ OptionsSound := TThemeOptionsSound.Create;
+ OptionsLyrics := TThemeOptionsLyrics.Create;
+ OptionsThemes := TThemeOptionsThemes.Create;
+ OptionsRecord := TThemeOptionsRecord.Create;
+ OptionsAdvanced := TThemeOptionsAdvanced.Create;
+
+ ErrorPopup := TThemeError.Create;
+ CheckPopup := TThemeCheck.Create;
+
+ SongMenu := TThemeSongMenu.Create;
+ SongJumpto := TThemeSongJumpto.Create;
+ //Party Screens
+ PartyNewRound := TThemePartyNewRound.Create;
+ PartyWin := TThemePartyWin.Create;
+ PartyScore := TThemePartyScore.Create;
+ PartyOptions := TThemePartyOptions.Create;
+ PartyPlayer := TThemePartyPlayer.Create;
+
+ //Stats Screens:
+ StatMain := TThemeStatMain.Create;
+ StatDetail := TThemeStatDetail.Create;
+*)
+
+ LoadTheme(FileName, Color);
+
+
+ {Skin.GrayLeft := 'Left Gray.bmp';
+ Skin.GrayMid := 'Mid Gray.bmp';
+ Skin.GrayRight := 'Right Gray.bmp';
+
+ Skin.NoteBGLeft := 'Note BG Left.bmp';
+ Skin.NoteBGMid := 'Note BG Mid.bmp';
+ Skin.NoteBGRight := 'Note BG Right.bmp';
+
+ Skin.NoteStar := 'Note Star.jpg';
+
+
+
+ //SingBar Mod
+ Skin.SingBarBack := 'Sing Bar Back.jpg';
+ Skin.SingBarBar := 'Sing Bar Bar.jpg';
+ Skin.SingBarFront := 'Sing Bar Front.jpg';
+ //end Singbar Mod
+
+ //PhrasenBonus - Line Bonus Mod
+ Skin.SingLineBonusBack := 'Line Bonus PopUp.jpg';
+
+
+
+
+{ Skin.WelcomeBG := SkinPath + 'Welcome BG.jpg';
+// Skin.Background := SkinPath + 'Background.jpg';
+ Skin.ScoreBG := SkinPath + 'Score BG.jpg';
+// Skin.GameStart := SkinPath + 'Game Start.jpg';
+// Skin.Editor := SkinPath + 'Editor.jpg';
+// Skin.Options := SkinPath + 'Options.jpg';
+// Skin.Exit := SkinPath + 'Exit.jpg';
+
+ Skin.MainStart := SkinPath + 'Main Solo.jpg';
+ Skin.MainEditor := SkinPath + 'Main Multi.jpg';
+ Skin.MainOptions := SkinPath + 'Main Options.jpg';
+ Skin.MainExit := SkinPath + 'Main Exit.jpg';
+ Skin.MainBar := SkinPath + 'Main Bar.jpg';
+ Skin.Cursor := SkinPath + 'Main Cursor.jpg';
+
+ Skin.SongFade := SkinPath + 'Song Fade.jpg';}{
+ Skin.SongCover := 'Song Cover.jpg';
+ {Skin.SongSelection := SkinPath + 'Song Selection.jpg';
+
+ Skin.SelectSong := SkinPath + 'Select Song.jpg';}{
+// Skin.Button := SkinPath + 'MusicWheelItem song.jpg';
+ Skin.Bar := 'Bar.jpg';
+{ Skin.P := SkinPath + 'P.jpg';
+ Skin.Arrow := SkinPath + 'Arrow.jpg';
+ Skin.Arrow2 := SkinPath + 'Arrow 2.jpg';}{
+ Skin.ButtonF := 'Button.jpg';
+ Skin.Ball := 'Ball3.bmp';
+{ Skin.Star := SkinPath + 'Star.bmp';
+ Skin.Line := SkinPath + 'Line.jpg';}
+end;
+
+
+function TTheme.LoadTheme(FileName: string; sColor: integer): boolean;
+var
+ I, J: integer;
+ Path: string;
+begin
+ create_theme_objects();
+
+ Result := false;
+ if FileExists(FileName) then begin
+ Result := true;
+
+ {$IFDEF THEMESAVE}
+ ThemeIni := TIniFile.Create(FileName);
+ {$ELSE}
+ ThemeIni := TMemIniFile.Create(FileName);
+ {$ENDIF}
+
+ if ThemeIni.ReadString('Theme', 'Name', '') <> '' then
+ begin
+
+ {Skin.SkinName := ThemeIni.ReadString('Theme', 'Name', 'Singstar');
+ Skin.SkinPath := 'Skins\' + Skin.SkinName + '\';
+ Skin.SkinReg := false; }
+ Skin.Color := sColor;
+
+ Skin.LoadSkin(ISkin[Ini.SkinNo]);
+
+ LoadColors;
+
+// ThemeIni.Free;
+// ThemeIni := TIniFile.Create('Themes\Singstar\Main.ini');
+
+ // Loading
+ ThemeLoadBasic(Loading, 'Loading');
+ ThemeLoadText(Loading.TextLoading, 'LoadingTextLoading');
+ ThemeLoadStatic(Loading.StaticAnimation, 'LoadingStaticAnimation');
+
+ // Main
+ ThemeLoadBasic(Main, 'Main');
+
+ ThemeLoadText(Main.TextDescription, 'MainTextDescription');
+ ThemeLoadText(Main.TextDescriptionLong, 'MainTextDescriptionLong');
+ ThemeLoadButton(Main.ButtonSolo, 'MainButtonSolo');
+ ThemeLoadButton(Main.ButtonMulti, 'MainButtonMulti');
+ ThemeLoadButton(Main.ButtonMultiM2, 'MainButtonMultiM2'); // for M2-MOD
+ ThemeLoadButton(Main.ButtonStat, 'MainButtonStats');
+ ThemeLoadButton(Main.ButtonEditor, 'MainButtonEditor');
+ ThemeLoadButton(Main.ButtonOptions, 'MainButtonOptions');
+ ThemeLoadButton(Main.ButtonExit, 'MainButtonExit');
+
+ //Main Desc Text Translation Start
+
+ {{$IFDEF TRANSLATE}
+ Main.Description[0] := Language.Translate('SING_SING');
+ Main.DescriptionLong[0] := Language.Translate('SING_SING_DESC');
+ Main.Description[1] := Language.Translate('SING_MULTI');
+ Main.DescriptionLong[1] := Language.Translate('SING_MULTI_DESC');
+ Main.Description[2] := Language.Translate('SING_MULTI_M2');
+ Main.DescriptionLong[2] := Language.Translate('SING_MULTI_M2_DESC');
+ Main.Description[3] := Language.Translate('SING_STATS');
+ Main.DescriptionLong[3] := Language.Translate('SING_STATS_DESC');
+ Main.Description[4] := Language.Translate('SING_EDITOR');
+ Main.DescriptionLong[4] := Language.Translate('SING_EDITOR_DESC');
+ Main.Description[5] := Language.Translate('SING_GAME_OPTIONS');
+ Main.DescriptionLong[5] := Language.Translate('SING_GAME_OPTIONS_DESC');
+ Main.Description[6] := Language.Translate('SING_EXIT');
+ Main.DescriptionLong[6] := Language.Translate('SING_EXIT_DESC');
+ {{$ENDIF}
+
+ //Main Desc Text Translation End
+
+ Main.TextDescription.Text := Main.Description[0];
+ Main.TextDescriptionLong.Text := Main.DescriptionLong[0];
+
+ // Name
+ ThemeLoadBasic(Name, 'Name');
+
+ for I := 1 to 6 do
+ ThemeLoadButton(Name.ButtonPlayer[I], 'NameButtonPlayer'+IntToStr(I));
+
+ // Level
+ ThemeLoadBasic(Level, 'Level');
+
+ ThemeLoadButton(Level.ButtonEasy, 'LevelButtonEasy');
+ ThemeLoadButton(Level.ButtonMedium, 'LevelButtonMedium');
+ ThemeLoadButton(Level.ButtonHard, 'LevelButtonHard');
+
+
+ // Song
+ ThemeLoadBasic(Song, 'Song');
+
+ ThemeLoadText(Song.TextArtist, 'SongTextArtist');
+ ThemeLoadText(Song.TextTitle, 'SongTextTitle');
+ ThemeLoadText(Song.TextNumber, 'SongTextNumber');
+
+ ThemeLoadText(Song.TextPlugin, 'SongTextPlugin');
+ ThemeLoadText(Song.TextP1, 'SongTextM2P1');
+ ThemeLoadText(Song.TextP2, 'SongTextM2P2');
+
+ for I := 1 to 4 do
+ ThemeLoadText(Song.TextMedley[I], 'SongTextMedley' + IntToStr(I));
+
+ //Video Icon Mod
+ ThemeLoadStatic(Song.VideoIcon, 'SongVideoIcon');
+
+ //Medley Icons
+ ThemeLoadStatic(Song.MedleyIcon, 'SongMedleyIcon');
+ ThemeLoadStatic(Song.CalculatedMedleyIcon, 'SongCalculatedMedleyIcon');
+
+ //Show Cat in TopLeft Mod
+ ThemeLoadStatic(Song.StaticCat, 'SongStaticCat');
+ ThemeLoadText(Song.TextCat, 'SongTextCat');
+
+ //Load Cover Pos and Size from Theme Mod
+ Song.Cover.X := ThemeIni.ReadInteger('SongCover', 'X', 300);
+ Song.Cover.Y := ThemeIni.ReadInteger('SongCover', 'Y', 190);
+ Song.Cover.W := ThemeIni.ReadInteger('SongCover', 'W', 300);
+ Song.Cover.H := ThemeIni.ReadInteger('SongCover', 'H', 200);
+ Song.Cover.Style := ThemeIni.ReadInteger('SongCover', 'Style', 4);
+ Song.Cover.Reflections := (ThemeIni.ReadInteger('SongCover', 'Reflections', 0) = 1);
+ //Load Cover Pos and Size from Theme Mod End
+
+ //Load Equalizer Pos and Size from Theme Mod
+ Song.Equalizer.Visible := (ThemeIni.ReadInteger('SongEqualizer', 'Visible', 0) = 1);
+ Song.Equalizer.Direction := (ThemeIni.ReadInteger('SongEqualizer', 'Direction', 0) = 1);
+ Song.Equalizer.Alpha := ThemeIni.ReadInteger('SongEqualizer', 'Alpha', 1);
+ Song.Equalizer.Space := ThemeIni.ReadInteger('SongEqualizer', 'Space', 1);
+ Song.Equalizer.X := ThemeIni.ReadInteger('SongEqualizer', 'X', 0);
+ Song.Equalizer.Y := ThemeIni.ReadInteger('SongEqualizer', 'Y', 0);
+ Song.Equalizer.Z := ThemeIni.ReadInteger('SongEqualizer', 'Z', 1);
+ Song.Equalizer.W := ThemeIni.ReadInteger('SongEqualizer', 'PieceW', 8);
+ Song.Equalizer.H := ThemeIni.ReadInteger('SongEqualizer', 'PieceH', 8);
+ Song.Equalizer.Bands := ThemeIni.ReadInteger('SongEqualizer', 'Bands', 5);
+ Song.Equalizer.Length := ThemeIni.ReadInteger('SongEqualizer', 'Length', 12);
+
+ //Color
+ I := ColorExists(ThemeIni.ReadString('SongEqualizer', 'Color', 'Black'));
+ if I >= 0 then begin
+ Song.Equalizer.ColR := Color[I].RGB.R;
+ Song.Equalizer.ColG := Color[I].RGB.G;
+ Song.Equalizer.ColB := Color[I].RGB.B;
+ end
+ else begin
+ Song.Equalizer.ColR := 0;
+ Song.Equalizer.ColG := 0;
+ Song.Equalizer.ColB := 0;
+ end;
+ //Load Equalizer Pos and Size from Theme Mod End
+
+ //Party and Non Party specific Statics and Texts
+ ThemeLoadStatics (Song.StaticParty, 'SongStaticParty');
+ ThemeLoadTexts (Song.TextParty, 'SongTextParty');
+
+ ThemeLoadStatics (Song.StaticNonParty, 'SongStaticNonParty');
+ ThemeLoadTexts (Song.TextNonParty, 'SongTextNonParty');
+
+ ThemeLoadStatics (Song.StaticM2Party, 'SongStaticM2Party');
+ ThemeLoadTexts (Song.TextM2Party, 'SongTextM2Party');
+
+ //Party Mode
+ ThemeLoadStatic(Song.StaticTeam1Joker1, 'SongStaticTeam1Joker1');
+ ThemeLoadStatic(Song.StaticTeam1Joker2, 'SongStaticTeam1Joker2');
+ ThemeLoadStatic(Song.StaticTeam1Joker3, 'SongStaticTeam1Joker3');
+ ThemeLoadStatic(Song.StaticTeam1Joker4, 'SongStaticTeam1Joker4');
+ ThemeLoadStatic(Song.StaticTeam1Joker5, 'SongStaticTeam1Joker5');
+
+ ThemeLoadStatic(Song.StaticTeam2Joker1, 'SongStaticTeam2Joker1');
+ ThemeLoadStatic(Song.StaticTeam2Joker2, 'SongStaticTeam2Joker2');
+ ThemeLoadStatic(Song.StaticTeam2Joker3, 'SongStaticTeam2Joker3');
+ ThemeLoadStatic(Song.StaticTeam2Joker4, 'SongStaticTeam2Joker4');
+ ThemeLoadStatic(Song.StaticTeam2Joker5, 'SongStaticTeam2Joker5');
+
+ ThemeLoadStatic(Song.StaticTeam3Joker1, 'SongStaticTeam3Joker1');
+ ThemeLoadStatic(Song.StaticTeam3Joker2, 'SongStaticTeam3Joker2');
+ ThemeLoadStatic(Song.StaticTeam3Joker3, 'SongStaticTeam3Joker3');
+ ThemeLoadStatic(Song.StaticTeam3Joker4, 'SongStaticTeam3Joker4');
+ ThemeLoadStatic(Song.StaticTeam3Joker5, 'SongStaticTeam3Joker5');
+
+ ThemeLoadText(Song.SongTextPartyTeam1NumJoker, 'SongTextPartyTeam1NumJoker');
+ ThemeLoadText(Song.SongTextPartyTeam2NumJoker, 'SongTextPartyTeam2NumJoker');
+ ThemeLoadText(Song.SongTextPartyTeam3NumJoker, 'SongTextPartyTeam3NumJoker');
+
+ // Sing
+ ThemeLoadBasic(Sing, 'Sing');
+
+ //Song name for Medley
+ ThemeLoadStatic(Sing.StaticSongName, 'SingSongNameStatic');
+ ThemeLoadText(Sing.TextSongName, 'SingSongNameText');
+
+ //TimeBar mod
+ ThemeLoadStatic(Sing.StaticTimeProgress, 'SingTimeProgress');
+ ThemeLoadText(Sing.TextTimeText, 'SingTimeText');
+ //eoa TimeBar mod
+
+ //moveable singbar mod
+ ThemeLoadStatic(Sing.StaticP1SingBar, 'SingP1SingBar');
+ ThemeLoadStatic(Sing.StaticP1TwoPSingBar, 'SingP1TwoPSingBar');
+ ThemeLoadStatic(Sing.StaticP1ThreePSingBar, 'SingP1ThreePSingBar');
+ ThemeLoadStatic(Sing.StaticP2RSingBar, 'SingP2RSingBar');
+ ThemeLoadStatic(Sing.StaticP2MSingBar, 'SingP2MSingBar');
+ ThemeLoadStatic(Sing.StaticP3SingBar, 'SingP3SingBar');
+ //eoa moveable singbar
+
+ ThemeLoadStatic(Sing.StaticP1, 'SingP1Static');
+ ThemeLoadText(Sing.TextP1, 'SingP1Text');
+ ThemeLoadStatic(Sing.StaticP1ScoreBG, 'SingP1Static2');
+ ThemeLoadText(Sing.TextP1Score, 'SingP1TextScore');
+ //Added for ps3 skin
+ //This one is shown in 2/4P mode
+ //if it exists, otherwise the one Player equivaltents are used
+ if (ThemeIni.SectionExists('SingP1TwoPTextScore')) then
+ begin
+ ThemeLoadStatic(Sing.StaticP1TwoP, 'SingP1TwoPStatic');
+ ThemeLoadText(Sing.TextP1TwoP, 'SingP1TwoPText');
+ ThemeLoadStatic(Sing.StaticP1TwoPScoreBG, 'SingP1TwoPStatic2');
+ ThemeLoadText(Sing.TextP1TwoPScore, 'SingP1TwoPTextScore');
+ end
+ else
+ begin
+ Sing.StaticP1TwoP := Sing.StaticP1;
+ Sing.TextP1TwoP := Sing.TextP1;
+ Sing.StaticP1TwoPScoreBG := Sing.StaticP1ScoreBG;
+ Sing.TextP1TwoPScore := Sing.TextP1Score;
+ end;
+
+ //This one is shown in 3/6P mode
+ //if it exists, otherwise the one Player equivaltents are used
+ if (ThemeIni.SectionExists('SingP1TwoPTextScore')) then
+ begin
+ ThemeLoadStatic(Sing.StaticP1ThreeP, 'SingP1ThreePStatic');
+ ThemeLoadText(Sing.TextP1ThreeP, 'SingP1ThreePText');
+ ThemeLoadStatic(Sing.StaticP1ThreePScoreBG, 'SingP1ThreePStatic2');
+ ThemeLoadText(Sing.TextP1ThreePScore, 'SingP1ThreePTextScore');
+ end
+ else
+ begin
+ Sing.StaticP1ThreeP := Sing.StaticP1;
+ Sing.TextP1ThreeP := Sing.TextP1;
+ Sing.StaticP1ThreePScoreBG := Sing.StaticP1ScoreBG;
+ Sing.TextP1ThreePScore := Sing.TextP1Score;
+ end;
+ //eoa
+ ThemeLoadStatic(Sing.StaticP2R, 'SingP2RStatic');
+ ThemeLoadText(Sing.TextP2R, 'SingP2RText');
+ ThemeLoadStatic(Sing.StaticP2RScoreBG, 'SingP2RStatic2');
+ ThemeLoadText(Sing.TextP2RScore, 'SingP2RTextScore');
+
+ ThemeLoadStatic(Sing.StaticP2M, 'SingP2MStatic');
+ ThemeLoadText(Sing.TextP2M, 'SingP2MText');
+ ThemeLoadStatic(Sing.StaticP2MScoreBG, 'SingP2MStatic2');
+ ThemeLoadText(Sing.TextP2MScore, 'SingP2MTextScore');
+
+ ThemeLoadStatic(Sing.StaticP3R, 'SingP3RStatic');
+ ThemeLoadText(Sing.TextP3R, 'SingP3RText');
+ ThemeLoadStatic(Sing.StaticP3RScoreBG, 'SingP3RStatic2');
+ ThemeLoadText(Sing.TextP3RScore, 'SingP3RTextScore');
+
+ //Line Bonus Texts
+ Sing.LineBonusText[0] := Language.Translate('POPUP_AWFUL');
+ Sing.LineBonusText[1] := Sing.LineBonusText[0];
+ Sing.LineBonusText[2] := Language.Translate('POPUP_POOR');
+ Sing.LineBonusText[3] := Language.Translate('POPUP_BAD');
+ Sing.LineBonusText[4] := Language.Translate('POPUP_NOTBAD');
+ Sing.LineBonusText[5] := Language.Translate('POPUP_GOOD');
+ Sing.LineBonusText[6] := Language.Translate('POPUP_GREAT');
+ Sing.LineBonusText[7] := Language.Translate('POPUP_AWESOME');
+ Sing.LineBonusText[8] := Language.Translate('POPUP_PERFECT');
+
+ //VideoAspect
+ ThemeLoadStatic(Sing.VideoAspectStatic, 'VideoAspectStatic');
+ ThemeLoadText(Sing.VideoAspectText, 'VideoAspectText');
+
+
+ // Score
+ ThemeLoadBasic(Score, 'Score');
+
+ ThemeLoadText(Score.TextArtist, 'ScoreTextArtist');
+ ThemeLoadText(Score.TextTitle, 'ScoreTextTitle');
+ ThemeLoadText(Score.TextArtistTitle, 'ScoreTextArtistTitle');
+
+ ThemeLoadStatic(Score.StaticMedleyNav, 'ScoreMedleyNavStatic');
+ ThemeLoadText(Score.TextMedleyNav, 'ScoreMedleyNavText');
+
+ for I := 1 to 6 do begin
+ ThemeLoadStatics(Score.PlayerStatic[I], 'ScorePlayer' + IntToStr(I) + 'Static');
+ ThemeLoadTexts(Score.PlayerTexts[I], 'ScorePlayer' + IntToStr(I) + 'Text');
+
+ ThemeLoadText(Score.TextName[I], 'ScoreTextName' + IntToStr(I));
+ ThemeLoadText(Score.TextScore[I], 'ScoreTextScore' + IntToStr(I));
+ ThemeLoadText(Score.TextNotes[I], 'ScoreTextNotes' + IntToStr(I));
+ ThemeLoadText(Score.TextNotesScore[I], 'ScoreTextNotesScore' + IntToStr(I));
+ ThemeLoadText(Score.TextLineBonus[I], 'ScoreTextLineBonus' + IntToStr(I));
+ ThemeLoadText(Score.TextLineBonusScore[I], 'ScoreTextLineBonusScore' + IntToStr(I));
+ ThemeLoadText(Score.TextGoldenNotes[I], 'ScoreTextGoldenNotes' + IntToStr(I));
+ ThemeLoadText(Score.TextGoldenNotesScore[I], 'ScoreTextGoldenNotesScore' + IntToStr(I));
+ ThemeLoadText(Score.TextTotal[I], 'ScoreTextTotal' + IntToStr(I));
+ ThemeLoadText(Score.TextTotalScore[I], 'ScoreTextTotalScore' + IntToStr(I));
+
+ ThemeLoadStatic(Score.StaticBoxLightest[I], 'ScoreStaticBoxLightest' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticBoxLight[I], 'ScoreStaticBoxLight' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticBoxDark[I], 'ScoreStaticBoxDark' + IntToStr(I));
+
+ ThemeLoadStatic(Score.StaticBackLevel[I], 'ScoreStaticBackLevel' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticBackLevelRound[I], 'ScoreStaticBackLevelRound' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticLevel[I], 'ScoreStaticLevel' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticLevelRound[I], 'ScoreStaticLevelRound' + IntToStr(I));
+ end;
+
+ // Top
+ ThemeLoadBasic(Top, 'Top');
+
+ ThemeLoadText(Top.TextLevel, 'TopTextLevel');
+ ThemeLoadText(Top.TextArtistTitle, 'TopTextArtistTitle');
+ ThemeLoadStatics(Top.StaticNumber, 'TopStaticNumber');
+ ThemeLoadTexts(Top.TextNumber, 'TopTextNumber');
+ ThemeLoadTexts(Top.TextName, 'TopTextName');
+ ThemeLoadTexts(Top.TextScore, 'TopTextScore');
+ ThemeLoadTexts(Top.TextDate, 'TopTextDate');
+
+ // Options
+ ThemeLoadBasic(Options, 'Options');
+
+ ThemeLoadButton(Options.ButtonGame, 'OptionsButtonGame');
+ ThemeLoadButton(Options.ButtonGraphics, 'OptionsButtonGraphics');
+ ThemeLoadButton(Options.ButtonSound, 'OptionsButtonSound');
+ ThemeLoadButton(Options.ButtonLyrics, 'OptionsButtonLyrics');
+ ThemeLoadButton(Options.ButtonThemes, 'OptionsButtonThemes');
+ ThemeLoadButton(Options.ButtonRecord, 'OptionsButtonRecord');
+ ThemeLoadButton(Options.ButtonAdvanced, 'OptionsButtonAdvanced');
+ ThemeLoadButton(Options.ButtonExit, 'OptionsButtonExit');
+
+ {{$IFDEF TRANSLATE}
+ Options.Description[0] := Language.Translate('SING_OPTIONS_GAME');
+ Options.Description[1] := Language.Translate('SING_OPTIONS_GRAPHICS');
+ Options.Description[2] := Language.Translate('SING_OPTIONS_SOUND');
+ Options.Description[3] := Language.Translate('SING_OPTIONS_LYRICS');
+ Options.Description[4] := Language.Translate('SING_OPTIONS_THEMES');
+ Options.Description[5] := Language.Translate('SING_OPTIONS_RECORD');
+ Options.Description[6] := Language.Translate('SING_OPTIONS_ADVANCED');
+ Options.Description[7] := Language.Translate('SING_OPTIONS_EXIT');
+ {{$ENDIF}
+
+ ThemeLoadText(Options.TextDescription, 'OptionsTextDescription');
+ Options.TextDescription.Text := Options.Description[0];
+
+ // Options Game
+ ThemeLoadBasic(OptionsGame, 'OptionsGame');
+
+ ThemeLoadSelect(OptionsGame.SelectPlayers, 'OptionsGameSelectPlayers');
+ ThemeLoadSelect(OptionsGame.SelectDifficulty, 'OptionsGameSelectDifficulty');
+ ThemeLoadSelectSlide(OptionsGame.SelectLanguage, 'OptionsGameSelectSlideLanguage');
+ ThemeLoadSelect(OptionsGame.SelectTabs, 'OptionsGameSelectTabs');
+ ThemeLoadSelectSlide(OptionsGame.SelectSorting, 'OptionsGameSelectSlideSorting');
+ ThemeLoadSelect(OptionsGame.SelectDebug, 'OptionsGameSelectDebug');
+ ThemeLoadButton(OptionsGame.ButtonExit, 'OptionsGameButtonExit');
+
+ // Options Graphics
+ ThemeLoadBasic(OptionsGraphics, 'OptionsGraphics');
+
+ ThemeLoadSelect(OptionsGraphics.SelectFullscreen, 'OptionsGraphicsSelectFullscreen');
+ ThemeLoadSelectSlide(OptionsGraphics.SelectSlideResolution, 'OptionsGraphicsSelectSlideResolution');
+ ThemeLoadSelect(OptionsGraphics.SelectDepth, 'OptionsGraphicsSelectDepth');
+ ThemeLoadSelect(OptionsGraphics.SelectOscilloscope, 'OptionsGraphicsSelectOscilloscope');
+ ThemeLoadSelect(OptionsGraphics.SelectLineBonus, 'OptionsGraphicsSelectLineBonus');
+ ThemeLoadSelect(OptionsGraphics.SelectMovieSize, 'OptionsGraphicsSelectMovieSize');
+ ThemeLoadSelect(OptionsGraphics.SelectMoviePreview, 'OptionsGraphicsSelectMoviePreview');
+ ThemeLoadButton(OptionsGraphics.ButtonExit, 'OptionsGraphicsButtonExit');
+
+ // Options Sound
+ ThemeLoadBasic(OptionsSound, 'OptionsSound');
+
+ ThemeLoadSelect(OptionsSound.SelectMicBoost, 'OptionsSoundSelectMicBoost');
+ ThemeLoadSelect(OptionsSound.SelectClickAssist, 'OptionsSoundSelectClickAssist');
+ ThemeLoadSelect(OptionsSound.SelectBeatClick, 'OptionsSoundSelectBeatClick');
+ ThemeLoadSelect(OptionsSound.SelectThreshold, 'OptionsSoundSelectThreshold');
+ //Song Preview
+ ThemeLoadSelectSlide(OptionsSound.SelectSlidePreviewVolume, 'OptionsSoundSelectSlidePreviewVolume');
+ ThemeLoadSelectSlide(OptionsSound.SelectSlidePreviewFading, 'OptionsSoundSelectSlidePreviewFading');
+
+ ThemeLoadButton(OptionsSound.ButtonExit, 'OptionsSoundButtonExit');
+
+ // Options Lyrics
+ ThemeLoadBasic(OptionsLyrics, 'OptionsLyrics');
+
+ ThemeLoadSelect(OptionsLyrics.SelectLyricsFont, 'OptionsLyricsSelectLyricsFont');
+ ThemeLoadSelect(OptionsLyrics.SelectLyricsEffect, 'OptionsLyricsSelectLyricsEffect');
+ ThemeLoadSelect(OptionsLyrics.SelectSolmization, 'OptionsLyricsSelectSolmization');
+ ThemeLoadButton(OptionsLyrics.ButtonExit, 'OptionsLyricsButtonExit');
+
+ // Options Themes
+ ThemeLoadBasic(OptionsThemes, 'OptionsThemes');
+
+ ThemeLoadSelectSlide(OptionsThemes.SelectTheme, 'OptionsThemesSelectTheme');
+ ThemeLoadSelectSlide(OptionsThemes.SelectSkin, 'OptionsThemesSelectSkin');
+ ThemeLoadSelectSlide(OptionsThemes.SelectColor, 'OptionsThemesSelectColor');
+ ThemeLoadButton(OptionsThemes.ButtonExit, 'OptionsThemesButtonExit');
+
+ // Options Record
+ ThemeLoadBasic(OptionsRecord, 'OptionsRecord');
+
+ ThemeLoadSelectSlide(OptionsRecord.SelectSlideCard, 'OptionsRecordSelectSlideCard');
+ ThemeLoadSelectSlide(OptionsRecord.SelectSlideInput, 'OptionsRecordSelectSlideInput');
+ ThemeLoadSelectSlide(OptionsRecord.SelectSlideChannelL, 'OptionsRecordSelectSlideChannelL');
+ ThemeLoadSelectSlide(OptionsRecord.SelectSlideChannelR, 'OptionsRecordSelectSlideChannelR');
+ ThemeLoadButton(OptionsRecord.ButtonExit, 'OptionsRecordButtonExit');
+
+ //Options Advanced
+ ThemeLoadBasic(OptionsAdvanced, 'OptionsAdvanced');
+
+ ThemeLoadSelect (OptionsAdvanced.SelectLoadAnimation, 'OptionsAdvancedSelectLoadAnimation');
+ ThemeLoadSelect (OptionsAdvanced.SelectScreenFade, 'OptionsAdvancedSelectScreenFade');
+ ThemeLoadSelect (OptionsAdvanced.SelectEffectSing, 'OptionsAdvancedSelectEffectSing');
+ ThemeLoadSelect (OptionsAdvanced.SelectLineBonus, 'OptionsAdvancedSelectLineBonus');
+ ThemeLoadSelectSlide (OptionsAdvanced.SelectOnSongClick, 'OptionsAdvancedSelectSlideOnSongClick');
+ ThemeLoadSelect (OptionsAdvanced.SelectAskbeforeDel, 'OptionsAdvancedSelectAskbeforeDel');
+ ThemeLoadSelect (OptionsAdvanced.SelectPartyPopup, 'OptionsAdvancedSelectPartyPopup');
+ ThemeLoadButton (OptionsAdvanced.ButtonExit, 'OptionsAdvancedButtonExit');
+
+ //error and check popup
+ ThemeLoadBasic (ErrorPopup, 'ErrorPopup');
+ ThemeLoadButton(ErrorPopup.Button1, 'ErrorPopupButton1');
+ ThemeLoadText (ErrorPopup.TextError,'ErrorPopupText');
+ ThemeLoadBasic (CheckPopup, 'CheckPopup');
+ ThemeLoadButton(CheckPopup.Button1, 'CheckPopupButton1');
+ ThemeLoadButton(CheckPopup.Button2, 'CheckPopupButton2');
+ ThemeLoadText(CheckPopup.TextCheck , 'CheckPopupText');
+
+ //help popup
+ ThemeLoadBasic (HelpPopup, 'HelpPopup');
+ ThemeLoadButton(HelpPopup.Button1, 'HelpPopupButton1');
+
+ //Song Menu
+ ThemeLoadBasic (SongMenu, 'SongMenu');
+ ThemeLoadButton(SongMenu.Button1, 'SongMenuButton1');
+ ThemeLoadButton(SongMenu.Button2, 'SongMenuButton2');
+ ThemeLoadButton(SongMenu.Button3, 'SongMenuButton3');
+ ThemeLoadButton(SongMenu.Button4, 'SongMenuButton4');
+ ThemeLoadSelectSlide(SongMenu.SelectSlide3, 'SongMenuSelectSlide3');
+
+ ThemeLoadText(SongMenu.TextMenu, 'SongMenuTextMenu');
+
+ //Song Jumpto
+ ThemeLoadBasic (SongJumpto, 'SongJumpto');
+ ThemeLoadButton(SongJumpto.ButtonSearchText, 'SongJumptoButtonSearchText');
+ ThemeLoadSelectSlide(SongJumpto.SelectSlideType, 'SongJumptoSelectSlideType');
+ ThemeLoadText(SongJumpto.TextFound, 'SongJumptoTextFound');
+ //Translations
+ SongJumpto.IType[0] := Language.Translate('SONG_JUMPTO_TYPE1');
+ SongJumpto.IType[1] := Language.Translate('SONG_JUMPTO_TYPE2');
+ SongJumpto.IType[2] := Language.Translate('SONG_JUMPTO_TYPE3');
+ SongJumpto.SongsFound := Language.Translate('SONG_JUMPTO_SONGSFOUND');
+ SongJumpto.NoSongsFound := Language.Translate('SONG_JUMPTO_NOSONGSFOUND');
+ SongJumpto.CatText := Language.Translate('SONG_JUMPTO_CATTEXT');
+
+ //Party Screens:
+ //Party NewRound
+ ThemeLoadBasic(PartyNewRound, 'PartyNewRound');
+
+ ThemeLoadText (PartyNewRound.TextRound1, 'PartyNewRoundTextRound1');
+ ThemeLoadText (PartyNewRound.TextRound2, 'PartyNewRoundTextRound2');
+ ThemeLoadText (PartyNewRound.TextRound3, 'PartyNewRoundTextRound3');
+ ThemeLoadText (PartyNewRound.TextRound4, 'PartyNewRoundTextRound4');
+ ThemeLoadText (PartyNewRound.TextRound5, 'PartyNewRoundTextRound5');
+ ThemeLoadText (PartyNewRound.TextRound6, 'PartyNewRoundTextRound6');
+ ThemeLoadText (PartyNewRound.TextRound7, 'PartyNewRoundTextRound7');
+ ThemeLoadText (PartyNewRound.TextWinner1, 'PartyNewRoundTextWinner1');
+ ThemeLoadText (PartyNewRound.TextWinner2, 'PartyNewRoundTextWinner2');
+ ThemeLoadText (PartyNewRound.TextWinner3, 'PartyNewRoundTextWinner3');
+ ThemeLoadText (PartyNewRound.TextWinner4, 'PartyNewRoundTextWinner4');
+ ThemeLoadText (PartyNewRound.TextWinner5, 'PartyNewRoundTextWinner5');
+ ThemeLoadText (PartyNewRound.TextWinner6, 'PartyNewRoundTextWinner6');
+ ThemeLoadText (PartyNewRound.TextWinner7, 'PartyNewRoundTextWinner7');
+ ThemeLoadText (PartyNewRound.TextNextRound, 'PartyNewRoundTextNextRound');
+ ThemeLoadText (PartyNewRound.TextNextRoundNo, 'PartyNewRoundTextNextRoundNo');
+ ThemeLoadText (PartyNewRound.TextNextPlayer1, 'PartyNewRoundTextNextPlayer1');
+ ThemeLoadText (PartyNewRound.TextNextPlayer2, 'PartyNewRoundTextNextPlayer2');
+ ThemeLoadText (PartyNewRound.TextNextPlayer3, 'PartyNewRoundTextNextPlayer3');
+
+ ThemeLoadStatic (PartyNewRound.StaticRound1, 'PartyNewRoundStaticRound1');
+ ThemeLoadStatic (PartyNewRound.StaticRound2, 'PartyNewRoundStaticRound2');
+ ThemeLoadStatic (PartyNewRound.StaticRound3, 'PartyNewRoundStaticRound3');
+ ThemeLoadStatic (PartyNewRound.StaticRound4, 'PartyNewRoundStaticRound4');
+ ThemeLoadStatic (PartyNewRound.StaticRound5, 'PartyNewRoundStaticRound5');
+ ThemeLoadStatic (PartyNewRound.StaticRound6, 'PartyNewRoundStaticRound6');
+ ThemeLoadStatic (PartyNewRound.StaticRound7, 'PartyNewRoundStaticRound7');
+
+ ThemeLoadText (PartyNewRound.TextScoreTeam1, 'PartyNewRoundTextScoreTeam1');
+ ThemeLoadText (PartyNewRound.TextScoreTeam2, 'PartyNewRoundTextScoreTeam2');
+ ThemeLoadText (PartyNewRound.TextScoreTeam3, 'PartyNewRoundTextScoreTeam3');
+ ThemeLoadText (PartyNewRound.TextNameTeam1, 'PartyNewRoundTextNameTeam1');
+ ThemeLoadText (PartyNewRound.TextNameTeam2, 'PartyNewRoundTextNameTeam2');
+ ThemeLoadText (PartyNewRound.TextNameTeam3, 'PartyNewRoundTextNameTeam3');
+
+ ThemeLoadText (PartyNewRound.TextTeam1Players, 'PartyNewRoundTextTeam1Players');
+ ThemeLoadText (PartyNewRound.TextTeam2Players, 'PartyNewRoundTextTeam2Players');
+ ThemeLoadText (PartyNewRound.TextTeam3Players, 'PartyNewRoundTextTeam3Players');
+
+ ThemeLoadStatic (PartyNewRound.StaticTeam1, 'PartyNewRoundStaticTeam1');
+ ThemeLoadStatic (PartyNewRound.StaticTeam2, 'PartyNewRoundStaticTeam2');
+ ThemeLoadStatic (PartyNewRound.StaticTeam3, 'PartyNewRoundStaticTeam3');
+ ThemeLoadStatic (PartyNewRound.StaticNextPlayer1, 'PartyNewRoundStaticNextPlayer1');
+ ThemeLoadStatic (PartyNewRound.StaticNextPlayer2, 'PartyNewRoundStaticNextPlayer2');
+ ThemeLoadStatic (PartyNewRound.StaticNextPlayer3, 'PartyNewRoundStaticNextPlayer3');
+
+ //Party NewRound M2
+ ThemeLoadBasic(PartyNewRoundM2, 'PartyNewRoundM2');
+
+ for I := 1 to 9 do
+ begin
+ ThemeLoadText (PartyNewRoundM2.TextRound[I], 'PartyNewRoundM2TextRound'+IntToStr(I));
+ ThemeLoadText (PartyNewRoundM2.TextWinner[I], 'PartyNewRoundM2TextWinner'+IntToStr(I));
+ ThemeLoadStatic (PartyNewRoundM2.StaticRound[I], 'PartyNewRoundM2StaticRound'+IntToStr(I));
+ ThemeLoadStatic (PartyNewRoundM2.StaticTable[I], 'PartyNewRoundM2StaticTable'+IntToStr(I));
+ end;
+
+ ThemeLoadText (PartyNewRoundM2.TextNextRound, 'PartyNewRoundM2TextNextRound');
+ ThemeLoadText (PartyNewRoundM2.TextNextPlayer1, 'PartyNewRoundM2TextNextPlayer1');
+ ThemeLoadText (PartyNewRoundM2.TextNextPlayer2, 'PartyNewRoundM2TextNextPlayer2');
+ ThemeLoadText (PartyNewRoundM2.TextHandicap, 'PartyNewRoundM2TextHandicap');
+
+ {ThemeLoadText (PartyNewRoundM2.TextScoreTeam1, 'PartyNewRoundTextScoreTeam1');
+ ThemeLoadText (PartyNewRoundM2.TextScoreTeam2, 'PartyNewRoundTextScoreTeam2');
+ ThemeLoadText (PartyNewRoundM2.TextNameTeam1, 'PartyNewRoundTextNameTeam1');
+ ThemeLoadText (PartyNewRoundM2.TextNameTeam2, 'PartyNewRoundTextNameTeam2');}
+
+ //ThemeLoadStatic (PartyNewRoundM2.StaticTeam1, 'PartyNewRoundM2StaticTeam1');
+ //ThemeLoadStatic (PartyNewRoundM2.StaticTeam2, 'PartyNewRoundM2StaticTeam2');
+
+
+ ThemeLoadStatic (PartyNewRoundM2.StaticNextPlayer1, 'PartyNewRoundM2StaticNextPlayer1');
+ ThemeLoadStatic (PartyNewRoundM2.StaticNextPlayer2, 'PartyNewRoundM2StaticNextPlayer2');
+ ThemeLoadStatic (PartyNewRoundM2.StaticHandicap, 'PartyNewRoundM2StaticHandicap');
+
+ for I := 1 to 7 do
+ begin
+ for J := 1 to 9 do
+ begin
+ ThemeLoadText (PartyNewRoundM2.TextTableName[J,I], 'PartyNewRoundM2TextTableName' +
+ IntToStr(J) + IntToStr(I));
+ end;
+ end;
+
+
+ //Party Score
+ ThemeLoadBasic(PartyScore, 'PartyScore');
+
+ ThemeLoadText (PartyScore.TextScoreTeam1, 'PartyScoreTextScoreTeam1');
+ ThemeLoadText (PartyScore.TextScoreTeam2, 'PartyScoreTextScoreTeam2');
+ ThemeLoadText (PartyScore.TextScoreTeam3, 'PartyScoreTextScoreTeam3');
+ ThemeLoadText (PartyScore.TextNameTeam1, 'PartyScoreTextNameTeam1');
+ ThemeLoadText (PartyScore.TextNameTeam2, 'PartyScoreTextNameTeam2');
+ ThemeLoadText (PartyScore.TextNameTeam3, 'PartyScoreTextNameTeam3');
+
+ ThemeLoadStatic (PartyScore.StaticTeam1, 'PartyScoreStaticTeam1');
+ ThemeLoadStatic (PartyScore.StaticTeam1BG, 'PartyScoreStaticTeam1BG');
+ ThemeLoadStatic (PartyScore.StaticTeam1Deco, 'PartyScoreStaticTeam1Deco');
+ ThemeLoadStatic (PartyScore.StaticTeam2, 'PartyScoreStaticTeam2');
+ ThemeLoadStatic (PartyScore.StaticTeam2BG, 'PartyScoreStaticTeam2BG');
+ ThemeLoadStatic (PartyScore.StaticTeam2Deco, 'PartyScoreStaticTeam2Deco');
+ ThemeLoadStatic (PartyScore.StaticTeam3, 'PartyScoreStaticTeam3');
+ ThemeLoadStatic (PartyScore.StaticTeam3BG, 'PartyScoreStaticTeam3BG');
+ ThemeLoadStatic (PartyScore.StaticTeam3Deco, 'PartyScoreStaticTeam3Deco');
+
+ //Load Party Score DecoTextures Object
+ PartyScore.DecoTextures.ChangeTextures := (ThemeIni.ReadInteger('PartyScoreDecoTextures', 'ChangeTextures', 0) = 1);
+
+ PartyScore.DecoTextures.FirstTexture := ThemeIni.ReadString('PartyScoreDecoTextures', 'FirstTexture', '');
+ PartyScore.DecoTextures.FirstTyp := ThemeIni.ReadString('PartyScoreDecoTextures', 'FirstTyp', 'Note Black');
+ PartyScore.DecoTextures.FirstColor := ThemeIni.ReadString('PartyScoreDecoTextures', 'FirstColor', 'Black');
+
+ PartyScore.DecoTextures.SecondTexture := ThemeIni.ReadString('PartyScoreDecoTextures', 'SecondTexture', '');
+ PartyScore.DecoTextures.SecondTyp := ThemeIni.ReadString('PartyScoreDecoTextures', 'SecondTyp', 'Note Black');
+ PartyScore.DecoTextures.SecondColor := ThemeIni.ReadString('PartyScoreDecoTextures', 'SecondColor', 'Black');
+
+ PartyScore.DecoTextures.ThirdTexture := ThemeIni.ReadString('PartyScoreDecoTextures', 'ThirdTexture', '');
+ PartyScore.DecoTextures.ThirdTyp := ThemeIni.ReadString('PartyScoreDecoTextures', 'ThirdTyp', 'Note Black');
+ PartyScore.DecoTextures.ThirdColor := ThemeIni.ReadString('PartyScoreDecoTextures', 'ThirdColor', 'Black');
+
+ ThemeLoadText (PartyScore.TextWinner, 'PartyScoreTextWinner');
+
+ //Party Win
+ ThemeLoadBasic(PartyWin, 'PartyWin');
+
+ ThemeLoadText (PartyWin.TextScoreTeam1, 'PartyWinTextScoreTeam1');
+ ThemeLoadText (PartyWin.TextScoreTeam2, 'PartyWinTextScoreTeam2');
+ ThemeLoadText (PartyWin.TextScoreTeam3, 'PartyWinTextScoreTeam3');
+ ThemeLoadText (PartyWin.TextNameTeam1, 'PartyWinTextNameTeam1');
+ ThemeLoadText (PartyWin.TextNameTeam2, 'PartyWinTextNameTeam2');
+ ThemeLoadText (PartyWin.TextNameTeam3, 'PartyWinTextNameTeam3');
+
+ ThemeLoadStatic (PartyWin.StaticTeam1, 'PartyWinStaticTeam1');
+ ThemeLoadStatic (PartyWin.StaticTeam1BG, 'PartyWinStaticTeam1BG');
+ ThemeLoadStatic (PartyWin.StaticTeam1Deco, 'PartyWinStaticTeam1Deco');
+ ThemeLoadStatic (PartyWin.StaticTeam2, 'PartyWinStaticTeam2');
+ ThemeLoadStatic (PartyWin.StaticTeam2BG, 'PartyWinStaticTeam2BG');
+ ThemeLoadStatic (PartyWin.StaticTeam2Deco, 'PartyWinStaticTeam2Deco');
+ ThemeLoadStatic (PartyWin.StaticTeam3, 'PartyWinStaticTeam3');
+ ThemeLoadStatic (PartyWin.StaticTeam3BG, 'PartyWinStaticTeam3BG');
+ ThemeLoadStatic (PartyWin.StaticTeam3Deco, 'PartyWinStaticTeam3Deco');
+
+ ThemeLoadText (PartyWin.TextWinner, 'PartyWinTextWinner');
+
+ //Party Options
+ ThemeLoadBasic(PartyOptions, 'PartyOptions');
+ ThemeLoadSelectSlide(PartyOptions.SelectLevel, 'PartyOptionsSelectLevel');
+ ThemeLoadSelectSlide(PartyOptions.SelectPlayList, 'PartyOptionsSelectPlayList');
+ ThemeLoadSelectSlide(PartyOptions.SelectPlayList2, 'PartyOptionsSelectPlayList2');
+ ThemeLoadSelectSlide(PartyOptions.SelectRounds, 'PartyOptionsSelectRounds');
+ ThemeLoadSelectSlide(PartyOptions.SelectTeams, 'PartyOptionsSelectTeams');
+ ThemeLoadSelectSlide(PartyOptions.SelectPlayers1, 'PartyOptionsSelectPlayers1');
+ ThemeLoadSelectSlide(PartyOptions.SelectPlayers2, 'PartyOptionsSelectPlayers2');
+ ThemeLoadSelectSlide(PartyOptions.SelectPlayers3, 'PartyOptionsSelectPlayers3');
+
+ //Party Options M2
+ ThemeLoadBasic(PartyOptionsM2, 'PartyOptionsM2');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectLevel, 'PartyOptionsM2SelectLevel');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectPlayList, 'PartyOptionsM2SelectPlayList');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectPlayList2, 'PartyOptionsM2SelectPlayList2');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectPlayers1, 'PartyOptionsM2SelectPlayers');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectRounds, 'PartyOptionsM2SelectRounds');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectOptionPlugin, 'PartyOptionsM2SelectOptionPlugin');
+ ThemeLoadSelectSlide(PartyOptionsM2.SelectOptionHandicap, 'PartyOptionsM2SelectOptionHandicap');
+
+ //Party Player
+ ThemeLoadBasic(PartyPlayer, 'PartyPlayer');
+ ThemeLoadButton(PartyPlayer.Team1Name, 'PartyPlayerTeam1Name');
+ ThemeLoadButton(PartyPlayer.Player1Name, 'PartyPlayerPlayer1Name');
+ ThemeLoadButton(PartyPlayer.Player2Name, 'PartyPlayerPlayer2Name');
+ ThemeLoadButton(PartyPlayer.Player3Name, 'PartyPlayerPlayer3Name');
+ ThemeLoadButton(PartyPlayer.Player4Name, 'PartyPlayerPlayer4Name');
+
+ ThemeLoadButton(PartyPlayer.Team2Name, 'PartyPlayerTeam2Name');
+ ThemeLoadButton(PartyPlayer.Player5Name, 'PartyPlayerPlayer5Name');
+ ThemeLoadButton(PartyPlayer.Player6Name, 'PartyPlayerPlayer6Name');
+ ThemeLoadButton(PartyPlayer.Player7Name, 'PartyPlayerPlayer7Name');
+ ThemeLoadButton(PartyPlayer.Player8Name, 'PartyPlayerPlayer8Name');
+
+ ThemeLoadButton(PartyPlayer.Team3Name, 'PartyPlayerTeam3Name');
+ ThemeLoadButton(PartyPlayer.Player9Name, 'PartyPlayerPlayer9Name');
+ ThemeLoadButton(PartyPlayer.Player10Name, 'PartyPlayerPlayer10Name');
+ ThemeLoadButton(PartyPlayer.Player11Name, 'PartyPlayerPlayer11Name');
+ ThemeLoadButton(PartyPlayer.Player12Name, 'PartyPlayerPlayer12Name');
+
+ //Party Player M2
+ ThemeLoadBasic(PartyPlayerM2, 'PartyPlayerM2');
+
+ ThemeLoadButton(PartyPlayerM2.Player1Name, 'PartyPlayerM2Player1Name');
+ ThemeLoadButton(PartyPlayerM2.Player2Name, 'PartyPlayerM2Player2Name');
+ ThemeLoadButton(PartyPlayerM2.Player3Name, 'PartyPlayerM2Player3Name');
+ ThemeLoadButton(PartyPlayerM2.Player4Name, 'PartyPlayerM2Player4Name');
+ ThemeLoadButton(PartyPlayerM2.Player5Name, 'PartyPlayerM2Player5Name');
+ ThemeLoadButton(PartyPlayerM2.Player6Name, 'PartyPlayerM2Player6Name');
+ ThemeLoadButton(PartyPlayerM2.Player7Name, 'PartyPlayerM2Player7Name');
+ ThemeLoadButton(PartyPlayerM2.Player8Name, 'PartyPlayerM2Player8Name');
+ ThemeLoadButton(PartyPlayerM2.Player9Name, 'PartyPlayerM2Player9Name');
+
+ {ThemeLoadButton(ButtonNext, 'PartyPlayerButtonNext');
+ ThemeLoadButton(ButtonPrev, 'PartyPlayerButtonPrev');}
+
+ ThemeLoadBasic(StatMain, 'StatMain');
+
+ ThemeLoadButton(StatMain.ButtonScores, 'StatMainButtonScores');
+ ThemeLoadButton(StatMain.ButtonSingers, 'StatMainButtonSingers');
+ ThemeLoadButton(StatMain.ButtonSongs, 'StatMainButtonSongs');
+ ThemeLoadButton(StatMain.ButtonBands, 'StatMainButtonBands');
+ ThemeLoadButton(StatMain.ButtonExit, 'StatMainButtonExit');
+
+ ThemeLoadText (StatMain.TextOverview, 'StatMainTextOverview');
+
+
+ ThemeLoadBasic(StatDetail, 'StatDetail');
+
+ ThemeLoadButton(StatDetail.ButtonNext, 'StatDetailButtonNext');
+ ThemeLoadButton(StatDetail.ButtonPrev, 'StatDetailButtonPrev');
+ ThemeLoadButton(StatDetail.ButtonReverse, 'StatDetailButtonReverse');
+ ThemeLoadButton(StatDetail.ButtonExit, 'StatDetailButtonExit');
+
+ ThemeLoadText (StatDetail.TextDescription, 'StatDetailTextDescription');
+ ThemeLoadText (StatDetail.TextPage, 'StatDetailTextPage');
+ ThemeLoadTexts(StatDetail.TextList, 'StatDetailTextList');
+
+ //Translate Texts
+ StatDetail.Description[0] := Language.Translate('STAT_DESC_SCORES');
+ StatDetail.Description[1] := Language.Translate('STAT_DESC_SINGERS');
+ StatDetail.Description[2] := Language.Translate('STAT_DESC_SONGS');
+ StatDetail.Description[3] := Language.Translate('STAT_DESC_BANDS');
+
+ StatDetail.DescriptionR[0] := Language.Translate('STAT_DESC_SCORES_REVERSED');
+ StatDetail.DescriptionR[1] := Language.Translate('STAT_DESC_SINGERS_REVERSED');
+ StatDetail.DescriptionR[2] := Language.Translate('STAT_DESC_SONGS_REVERSED');
+ StatDetail.DescriptionR[3] := Language.Translate('STAT_DESC_BANDS_REVERSED');
+
+ StatDetail.FormatStr[0] := Language.Translate('STAT_FORMAT_SCORES');
+ StatDetail.FormatStr[1] := Language.Translate('STAT_FORMAT_SINGERS');
+ StatDetail.FormatStr[2] := Language.Translate('STAT_FORMAT_SONGS');
+ StatDetail.FormatStr[3] := Language.Translate('STAT_FORMAT_BANDS');
+
+ StatDetail.PageStr := Language.Translate('STAT_PAGE');
+
+ //Playlist Translations
+ Playlist.CatText := Language.Translate('PLAYLIST_CATTEXT');
+
+ //Level Translations
+ //Fill ILevel
+ ILevel[0] := Language.Translate('SING_EASY');
+ ILevel[1] := Language.Translate('SING_MEDIUM');
+ ILevel[2] := Language.Translate('SING_HARD');
+ end;
+
+ ThemeIni.Free;
+ end;
+end;
+
+procedure TTheme.ThemeLoadBasic(Theme: TThemeBasic; Name: string);
+begin
+ ThemeLoadBackground(Theme.Background, Name);
+ ThemeLoadTexts(Theme.Text, Name + 'Text');
+ ThemeLoadStatics(Theme.Static, Name + 'Static');
+ ThemeLoadButtonCollections(Theme.ButtonCollection, Name + 'ButtonCollection');
+
+ LastThemeBasic := Theme;
+end;
+
+procedure TTheme.ThemeLoadBackground(var ThemeBackground: TThemeBackground; Name: string);
+begin
+ ThemeBackground.Tex := ThemeIni.ReadString(Name + 'Background', 'Tex', '');
+end;
+
+procedure TTheme.ThemeLoadText(var ThemeText: TThemeText; Name: string);
+var
+ C: integer;
+begin
+ DecimalSeparator := '.';
+ ThemeText.X := ThemeIni.ReadInteger(Name, 'X', 0);
+ ThemeText.Y := ThemeIni.ReadInteger(Name, 'Y', 0);
+ ThemeText.W := ThemeIni.ReadInteger(Name, 'W', 0);
+
+ ThemeText.ColR := ThemeIni.ReadFloat(Name, 'ColR', 0);
+ ThemeText.ColG := ThemeIni.ReadFloat(Name, 'ColG', 0);
+ ThemeText.ColB := ThemeIni.ReadFloat(Name, 'ColB', 0);
+
+ ThemeText.Font := ThemeIni.ReadInteger(Name, 'Font', 0);
+ ThemeText.Size := ThemeIni.ReadInteger(Name, 'Size', 0);
+ ThemeText.Align := ThemeIni.ReadInteger(Name, 'Align', 0);
+
+ {{$IFDEF TRANSLATE}
+ ThemeText.Text := Language.Translate(ThemeIni.ReadString(Name, 'Text', ''));
+ {{$ELSE}{
+ ThemeText.Text := ThemeIni.ReadString(Name, 'Text', '');
+ {$ENDIF}
+
+ ThemeText.Color := ThemeIni.ReadString(Name, 'Color', '');
+
+ C := ColorExists(ThemeText.Color);
+ if C >= 0 then begin
+ ThemeText.ColR := Color[C].RGB.R;
+ ThemeText.ColG := Color[C].RGB.G;
+ ThemeText.ColB := Color[C].RGB.B;
+ end;
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeLoadTexts(var ThemeText: AThemeText; Name: string);
+var
+ T: integer;
+begin
+ T := 1;
+ while ThemeIni.SectionExists(Name + IntToStr(T)) do begin
+ SetLength(ThemeText, T);
+ ThemeLoadText(ThemeText[T-1], Name + IntToStr(T));
+ Inc(T);
+ end;
+end;
+
+procedure TTheme.ThemeLoadStatic(var ThemeStatic: TThemeStatic; Name: string);
+var
+ C: integer;
+begin
+ DecimalSeparator := '.';
+
+ ThemeStatic.Tex := ThemeIni.ReadString(Name, 'Tex', '');
+
+ ThemeStatic.X := ThemeIni.ReadInteger(Name, 'X', 0);
+ ThemeStatic.Y := ThemeIni.ReadInteger(Name, 'Y', 0);
+ ThemeStatic.Z := ThemeIni.ReadFloat(Name, 'Z', 0);
+ ThemeStatic.W := ThemeIni.ReadInteger(Name, 'W', 0);
+ ThemeStatic.H := ThemeIni.ReadInteger(Name, 'H', 0);
+
+ ThemeStatic.Typ := ThemeIni.ReadString(Name, 'Type', '');
+ ThemeStatic.Color := ThemeIni.ReadString(Name, 'Color', '');
+
+ C := ColorExists(ThemeStatic.Color);
+ if C >= 0 then begin
+ ThemeStatic.ColR := Color[C].RGB.R;
+ ThemeStatic.ColG := Color[C].RGB.G;
+ ThemeStatic.ColB := Color[C].RGB.B;
+ end;
+
+ ThemeStatic.TexX1 := ThemeIni.ReadFloat(Name, 'TexX1', 0);
+ ThemeStatic.TexY1 := ThemeIni.ReadFloat(Name, 'TexY1', 0);
+ ThemeStatic.TexX2 := ThemeIni.ReadFloat(Name, 'TexX2', 1);
+ ThemeStatic.TexY2 := ThemeIni.ReadFloat(Name, 'TexY2', 1);
+
+ //Reflection Mod
+ ThemeStatic.Reflection := (ThemeIni.ReadInteger(Name, 'Reflection', 0) = 1);
+ ThemeStatic.ReflectionSpacing := ThemeIni.ReadFloat(Name, 'ReflectionSpacing', 15);
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeLoadStatics(var ThemeStatic: AThemeStatic; Name: string);
+var
+ S: integer;
+begin
+ S := 1;
+ while ThemeIni.SectionExists(Name + IntToStr(S)) do begin
+ SetLength(ThemeStatic, S);
+ ThemeLoadStatic(ThemeStatic[S-1], Name + IntToStr(S));
+ Inc(S);
+ end;
+end;
+
+//Button Collection Mod
+procedure TTheme.ThemeLoadButtonCollection(var Collection: TThemeButtonCollection; Name: string);
+var T: Integer;
+begin
+ //Load Collection Style
+ ThemeLoadButton(Collection.Style, Name);
+
+ //Load Other Attributes
+ T := ThemeIni.ReadInteger (Name, 'FirstChild', 0);
+ if (T > 0) And (T < 256) then
+ Collection.FirstChild := T
+ else
+ Collection.FirstChild := 0;
+end;
+
+procedure TTheme.ThemeLoadButtonCollections(var Collections: AThemeButtonCollection; Name: string);
+var
+ I: integer;
+begin
+ I := 1;
+ while ThemeIni.SectionExists(Name + IntToStr(I)) do begin
+ SetLength(Collections, I);
+ ThemeLoadButtonCollection(Collections[I-1], Name + IntToStr(I));
+ Inc(I);
+ end;
+end;
+//End Button Collection Mod
+
+procedure TTheme.ThemeLoadButton(var ThemeButton: TThemeButton; Name: string; const Collections: PAThemeButtonCollection);
+var
+ C: integer;
+ TLen: integer;
+ T: integer;
+ Collections2: PAThemeButtonCollection;
+begin
+ if not ThemeIni.SectionExists(Name) then
+ begin
+ ThemeButton.Visible := False;
+ exit;
+ end;
+ DecimalSeparator := '.';
+ ThemeButton.Tex := ThemeIni.ReadString(Name, 'Tex', '');
+ ThemeButton.X := ThemeIni.ReadInteger (Name, 'X', 0);
+ ThemeButton.Y := ThemeIni.ReadInteger (Name, 'Y', 0);
+ ThemeButton.Z := ThemeIni.ReadFloat (Name, 'Z', 0);
+ ThemeButton.W := ThemeIni.ReadInteger (Name, 'W', 0);
+ ThemeButton.H := ThemeIni.ReadInteger (Name, 'H', 0);
+
+ ThemeButton.Typ := ThemeIni.ReadString(Name, 'Type', '');
+
+ //Reflection Mod
+ ThemeButton.Reflection := (ThemeIni.ReadInteger(Name, 'Reflection', 0) = 1);
+ ThemeButton.ReflectionSpacing := ThemeIni.ReadFloat(Name, 'ReflectionSpacing', 15);
+
+ ThemeButton.ColR := ThemeIni.ReadFloat(Name, 'ColR', 1);
+ ThemeButton.ColG := ThemeIni.ReadFloat(Name, 'ColG', 1);
+ ThemeButton.ColB := ThemeIni.ReadFloat(Name, 'ColB', 1);
+ ThemeButton.Int := ThemeIni.ReadFloat(Name, 'Int', 1);
+ ThemeButton.DColR := ThemeIni.ReadFloat(Name, 'DColR', 1);
+ ThemeButton.DColG := ThemeIni.ReadFloat(Name, 'DColG', 1);
+ ThemeButton.DColB := ThemeIni.ReadFloat(Name, 'DColB', 1);
+ ThemeButton.DInt := ThemeIni.ReadFloat(Name, 'DInt', 1);
+
+ ThemeButton.Color := ThemeIni.ReadString(Name, 'Color', '');
+ C := ColorExists(ThemeButton.Color);
+ if C >= 0 then begin
+ ThemeButton.ColR := Color[C].RGB.R;
+ ThemeButton.ColG := Color[C].RGB.G;
+ ThemeButton.ColB := Color[C].RGB.B;
+ end;
+
+ ThemeButton.DColor := ThemeIni.ReadString(Name, 'DColor', '');
+ C := ColorExists(ThemeButton.DColor);
+ if C >= 0 then begin
+ ThemeButton.DColR := Color[C].RGB.R;
+ ThemeButton.DColG := Color[C].RGB.G;
+ ThemeButton.DColB := Color[C].RGB.B;
+ end;
+
+ ThemeButton.Visible := (ThemeIni.ReadInteger(Name, 'Visible', 1) = 1);
+
+ //Fade Mod
+ ThemeButton.SelectH := ThemeIni.ReadInteger (Name, 'SelectH', ThemeButton.H);
+ ThemeButton.SelectW := ThemeIni.ReadInteger (Name, 'SelectW', ThemeButton.W);
+
+ ThemeButton.DeSelectReflectionspacing := ThemeIni.ReadFloat(Name, 'DeSelectReflectionSpacing', ThemeButton.Reflectionspacing);
+
+ ThemeButton.Fade := (ThemeIni.ReadInteger(Name, 'Fade', 0) = 1);
+ ThemeButton.FadeText := (ThemeIni.ReadInteger(Name, 'FadeText', 0) = 1);
+
+
+ ThemeButton.FadeTex := ThemeIni.ReadString(Name, 'FadeTex', '');
+ ThemeButton.FadeTexPos:= ThemeIni.ReadInteger(Name, 'FadeTexPos', 0);
+ if (ThemeButton.FadeTexPos > 4) Or (ThemeButton.FadeTexPos < 0) then
+ ThemeButton.FadeTexPos := 0;
+
+ //Button Collection Mod
+ T := ThemeIni.ReadInteger(Name, 'Parent', 0);
+
+ //Set Collections to Last Basic Collections if no valid Value
+ if (Collections = nil) then
+ Collections2 := @LastThemeBasic.ButtonCollection
+ else
+ Collections2 := Collections;
+ //Test for valid Value
+ if (Collections2 <> nil) AND (T > 0) AND (T <= Length(Collections2^)) then
+ begin
+ Inc(Collections2^[T-1].ChildCount);
+ ThemeButton.Parent := T;
+ end
+ else
+ ThemeButton.Parent := 0;
+
+ //Read ButtonTexts
+ TLen := ThemeIni.ReadInteger(Name, 'Texts', 0);
+ SetLength(ThemeButton.Text, TLen);
+ for T := 1 to TLen do
+ ThemeLoadText(ThemeButton.Text[T-1], Name + 'Text' + IntToStr(T));
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeLoadSelect(var ThemeSelect: TThemeSelect; Name: string);
+var
+ C: integer;
+begin
+ DecimalSeparator := '.';
+
+ {{$IFDEF TRANSLATE}
+ ThemeSelect.Text := Language.Translate(ThemeIni.ReadString(Name, 'Text', ''));
+ {{$ELSE}{
+ ThemeSelect.Text := ThemeIni.ReadString(Name, 'Text', '');
+ {$ENDIF}
+
+ ThemeSelect.Tex := {Skin.SkinPath + }ThemeIni.ReadString(Name, 'Tex', '');
+ ThemeSelect.TexSBG := {Skin.SkinPath + }ThemeIni.ReadString(Name, 'TexSBG', '');
+
+ ThemeSelect.X := ThemeIni.ReadInteger(Name, 'X', 0);
+ ThemeSelect.Y := ThemeIni.ReadInteger(Name, 'Y', 0);
+ ThemeSelect.W := ThemeIni.ReadInteger(Name, 'W', 0);
+ ThemeSelect.H := ThemeIni.ReadInteger(Name, 'H', 0);
+ ThemeSelect.SkipX := ThemeIni.ReadInteger(Name, 'SkipX', 0);
+
+
+ LoadColor(ThemeSelect.ColR, ThemeSelect.ColG, ThemeSelect.ColB, ThemeIni.ReadString(Name, 'Color', ''));
+ ThemeSelect.Int := ThemeIni.ReadFloat(Name, 'Int', 1);
+ LoadColor(ThemeSelect.DColR, ThemeSelect.DColG, ThemeSelect.DColB, ThemeIni.ReadString(Name, 'DColor', ''));
+ ThemeSelect.DInt := ThemeIni.ReadFloat(Name, 'DInt', 1);
+
+ LoadColor(ThemeSelect.TColR, ThemeSelect.TColG, ThemeSelect.TColB, ThemeIni.ReadString(Name, 'TColor', ''));
+ ThemeSelect.TInt := ThemeIni.ReadFloat(Name, 'TInt', 1);
+ LoadColor(ThemeSelect.TDColR, ThemeSelect.TDColG, ThemeSelect.TDColB, ThemeIni.ReadString(Name, 'TDColor', ''));
+ ThemeSelect.TDInt := ThemeIni.ReadFloat(Name, 'TDInt', 1);
+
+ LoadColor(ThemeSelect.SBGColR, ThemeSelect.SBGColG, ThemeSelect.SBGColB, ThemeIni.ReadString(Name, 'SBGColor', ''));
+ ThemeSelect.SBGInt := ThemeIni.ReadFloat(Name, 'SBGInt', 1);
+ LoadColor(ThemeSelect.SBGDColR, ThemeSelect.SBGDColG, ThemeSelect.SBGDColB, ThemeIni.ReadString(Name, 'SBGDColor', ''));
+ ThemeSelect.SBGDInt := ThemeIni.ReadFloat(Name, 'SBGDInt', 1);
+
+ LoadColor(ThemeSelect.STColR, ThemeSelect.STColG, ThemeSelect.STColB, ThemeIni.ReadString(Name, 'STColor', ''));
+ ThemeSelect.STInt := ThemeIni.ReadFloat(Name, 'STInt', 1);
+ LoadColor(ThemeSelect.STDColR, ThemeSelect.STDColG, ThemeSelect.STDColB, ThemeIni.ReadString(Name, 'STDColor', ''));
+ ThemeSelect.STDInt := ThemeIni.ReadFloat(Name, 'STDInt', 1);
+
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeLoadSelectSlide(var ThemeSelectS: TThemeSelectSlide; Name: string);
+var
+ C: integer;
+begin
+ DecimalSeparator := '.';
+
+ {{$IFDEF TRANSLATE}
+ ThemeSelectS.Text := Language.Translate(ThemeIni.ReadString(Name, 'Text', ''));
+ {{$ELSE}{
+ ThemeSelectS.Text := ThemeIni.ReadString(Name, 'Text', '');
+ {$ENDIF}
+
+ ThemeSelectS.Tex := {Skin.SkinPath + }ThemeIni.ReadString(Name, 'Tex', '');
+ ThemeSelectS.TexSBG := {Skin.SkinPath + }ThemeIni.ReadString(Name, 'TexSBG', '');
+
+ ThemeSelectS.X := ThemeIni.ReadInteger(Name, 'X', 0);
+ ThemeSelectS.Y := ThemeIni.ReadInteger(Name, 'Y', 0);
+ ThemeSelectS.W := ThemeIni.ReadInteger(Name, 'W', 0);
+ ThemeSelectS.H := ThemeIni.ReadInteger(Name, 'H', 0);
+
+ ThemeSelectS.Z := ThemeIni.ReadFloat(Name, 'Z', 0);
+
+ ThemeSelectS.TextSize := ThemeIni.ReadInteger(Name, 'TextSize', 10);
+
+ ThemeSelectS.SkipX := ThemeIni.ReadInteger(Name, 'SkipX', 0);
+
+ ThemeSelectS.SBGW := ThemeIni.ReadInteger(Name, 'SBGW', 450);
+
+ LoadColor(ThemeSelectS.ColR, ThemeSelectS.ColG, ThemeSelectS.ColB, ThemeIni.ReadString(Name, 'Color', ''));
+ ThemeSelectS.Int := ThemeIni.ReadFloat(Name, 'Int', 1);
+ LoadColor(ThemeSelectS.DColR, ThemeSelectS.DColG, ThemeSelectS.DColB, ThemeIni.ReadString(Name, 'DColor', ''));
+ ThemeSelectS.DInt := ThemeIni.ReadFloat(Name, 'DInt', 1);
+
+ LoadColor(ThemeSelectS.TColR, ThemeSelectS.TColG, ThemeSelectS.TColB, ThemeIni.ReadString(Name, 'TColor', ''));
+ ThemeSelectS.TInt := ThemeIni.ReadFloat(Name, 'TInt', 1);
+ LoadColor(ThemeSelectS.TDColR, ThemeSelectS.TDColG, ThemeSelectS.TDColB, ThemeIni.ReadString(Name, 'TDColor', ''));
+ ThemeSelectS.TDInt := ThemeIni.ReadFloat(Name, 'TDInt', 1);
+
+ LoadColor(ThemeSelectS.SBGColR, ThemeSelectS.SBGColG, ThemeSelectS.SBGColB, ThemeIni.ReadString(Name, 'SBGColor', ''));
+ ThemeSelectS.SBGInt := ThemeIni.ReadFloat(Name, 'SBGInt', 1);
+ LoadColor(ThemeSelectS.SBGDColR, ThemeSelectS.SBGDColG, ThemeSelectS.SBGDColB, ThemeIni.ReadString(Name, 'SBGDColor', ''));
+ ThemeSelectS.SBGDInt := ThemeIni.ReadFloat(Name, 'SBGDInt', 1);
+
+ LoadColor(ThemeSelectS.STColR, ThemeSelectS.STColG, ThemeSelectS.STColB, ThemeIni.ReadString(Name, 'STColor', ''));
+ ThemeSelectS.STInt := ThemeIni.ReadFloat(Name, 'STInt', 1);
+ LoadColor(ThemeSelectS.STDColR, ThemeSelectS.STDColG, ThemeSelectS.STDColB, ThemeIni.ReadString(Name, 'STDColor', ''));
+ ThemeSelectS.STDInt := ThemeIni.ReadFloat(Name, 'STDInt', 1);
+
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.LoadColors;
+var
+ SL: TStringList;
+ C: integer;
+ S: string;
+ Col: integer;
+ RGB: TRGB;
+begin
+ SL := TStringList.Create;
+ ThemeIni.ReadSection('Colors', SL);
+
+ // normal colors
+ SetLength(Color, SL.Count);
+ for C := 0 to SL.Count-1 do begin
+ Color[C].Name := SL.Strings[C];
+
+ S := ThemeIni.ReadString('Colors', SL.Strings[C], '');
+
+ Color[C].RGB.R := StrToInt(Copy(S, 1, Pos(' ' , S)-1))/255;
+ Delete(S, 1, Pos(' ', S));
+
+ Color[C].RGB.G := StrToInt(Copy(S, 1, Pos(' ' , S)-1))/255;
+ Delete(S, 1, Pos(' ', S));
+
+ Color[C].RGB.B := StrToInt(S)/255;
+ end;
+
+ // skin color
+ SetLength(Color, SL.Count + 3);
+ C := SL.Count;
+ Color[C].Name := 'ColorDark';
+ Color[C].RGB := GetSystemColor(Skin.Color); //Ini.Color);
+
+ C := C+1;
+ Color[C].Name := 'ColorLight';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'ColorLightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // players colors
+ SetLength(Color, Length(Color)+18);
+
+ // P1
+ C := C+1;
+ Color[C].Name := 'P1Dark';
+ Color[C].RGB := GetSystemColor(0); // 0 - blue
+
+ C := C+1;
+ Color[C].Name := 'P1Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P1Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // P2
+ C := C+1;
+ Color[C].Name := 'P2Dark';
+ Color[C].RGB := GetSystemColor(3); // 3 - red
+
+ C := C+1;
+ Color[C].Name := 'P2Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P2Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // P3
+ C := C+1;
+ Color[C].Name := 'P3Dark';
+ Color[C].RGB := GetSystemColor(1); // 1 - green
+
+ C := C+1;
+ Color[C].Name := 'P3Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P3Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // P4
+ C := C+1;
+ Color[C].Name := 'P4Dark';
+ Color[C].RGB := GetSystemColor(4); // 4 - brown
+
+ C := C+1;
+ Color[C].Name := 'P4Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P4Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // P5
+ C := C+1;
+ Color[C].Name := 'P5Dark';
+ Color[C].RGB := GetSystemColor(5); // 5 - yellow
+
+ C := C+1;
+ Color[C].Name := 'P5Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P5Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ // P6
+ C := C+1;
+ Color[C].Name := 'P6Dark';
+ Color[C].RGB := GetSystemColor(6); // 6 - violet
+
+ C := C+1;
+ Color[C].Name := 'P6Light';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+ C := C+1;
+ Color[C].Name := 'P6Lightest';
+ Color[C].RGB := ColorSqrt(Color[C-1].RGB);
+
+
+ SL.Free;
+end;
+
+function ColorExists(Name: string): integer;
+var
+ C: integer;
+begin
+ Result := -1;
+ for C := 0 to High(Color) do
+ if Color[C].Name = Name then Result := C;
+end;
+
+procedure LoadColor(var R, G, B: real; ColorName: string);
+var
+ C: integer;
+begin
+ C := ColorExists(ColorName);
+ if C >= 0 then begin
+ R := Color[C].RGB.R;
+ G := Color[C].RGB.G;
+ B := Color[C].RGB.B;
+ end;
+end;
+
+function GetSystemColor(Color: integer): TRGB;
+begin
+ case Color of
+ 0: begin
+ // blue
+ Result.R := 71/255;
+ Result.G := 175/255;
+ Result.B := 247/255;
+ end;
+ 1: begin
+ // green
+ Result.R := 63/255;
+ Result.G := 191/255;
+ Result.B := 63/255;
+ end;
+ 2: begin
+ // pink
+ Result.R := 255/255;
+{ Result.G := 63/255;
+ Result.B := 192/255;}
+ Result.G := 175/255;
+ Result.B := 247/255;
+ end;
+ 3: begin
+ // red
+ Result.R := 247/255;
+ Result.G := 71/255;
+ Result.B := 71/255;
+ end;
+ //'Violet', 'Orange', 'Yellow', 'Brown', 'Black'
+ //New Theme-Color Patch
+ 4: begin
+ // violet
+ Result.R := 230/255;
+ Result.G := 63/255;
+ Result.B := 230/255;
+ end;
+ 5: begin
+ // orange
+ Result.R := 255/255;
+ Result.G := 144/255;
+ Result.B := 0;
+ end;
+ 6: begin
+ // yellow
+ Result.R := 230/255;
+ Result.G := 230/255;
+ Result.B := 95/255;
+ end;
+ 7: begin
+ // brown
+ Result.R := 192/255;
+ Result.G := 127/255;
+ Result.B := 31/255;
+ end;
+ 8: begin
+ // black
+ Result.R := 0;
+ Result.G := 0;
+ Result.B := 0;
+ end;
+ //New Theme-Color Patch End
+
+ end;
+
+ // pink
+// Col := clRed;
+// Color[C].ColR := (32 + Col and $FF) / (255 + 32);
+// Color[C].ColG := (32 + Col div 256 and $FF) / (255 + 32);
+// Color[C].ColB := (32 + Col div (256*256) and $FF) / (255 + 32);
+
+ // purple
+// Color[C].ColR := 220/255;
+// Color[C].ColG := 95/255;
+// Color[C].ColB := 220/255;}
+
+end;
+
+function ColorSqrt(RGB: TRGB): TRGB;
+begin
+ Result.R := sqrt(RGB.R);
+ Result.G := sqrt(RGB.G);
+ Result.B := sqrt(RGB.B);
+end;
+
+procedure TTheme.ThemeSave(FileName: string);
+var
+ I: integer;
+begin
+ {$IFDEF THEMESAVE}
+ ThemeIni := TIniFile.Create(FileName);
+ {$ELSE}
+ ThemeIni := TMemIniFile.Create(FileName);
+ {$ENDIF}
+
+ ThemeSaveBasic(Loading, 'Loading');
+
+ ThemeSaveBasic(Main, 'Main');
+ ThemeSaveText(Main.TextDescription, 'MainTextDescription');
+ ThemeSaveText(Main.TextDescriptionLong, 'MainTextDescriptionLong');
+ ThemeSaveButton(Main.ButtonSolo, 'MainButtonSolo');
+ ThemeSaveButton(Main.ButtonEditor, 'MainButtonEditor');
+ ThemeSaveButton(Main.ButtonOptions, 'MainButtonOptions');
+ ThemeSaveButton(Main.ButtonExit, 'MainButtonExit');
+
+ ThemeSaveBasic(Name, 'Name');
+ for I := 1 to 6 do
+ ThemeSaveButton(Name.ButtonPlayer[I], 'NameButtonPlayer' + IntToStr(I));
+
+ ThemeSaveBasic(Level, 'Level');
+ ThemeSaveButton(Level.ButtonEasy, 'LevelButtonEasy');
+ ThemeSaveButton(Level.ButtonMedium, 'LevelButtonMedium');
+ ThemeSaveButton(Level.ButtonHard, 'LevelButtonHard');
+
+ ThemeSaveBasic(Song, 'Song');
+ ThemeSaveText(Song.TextArtist, 'SongTextArtist');
+ ThemeSaveText(Song.TextTitle, 'SongTextTitle');
+ ThemeSaveText(Song.TextNumber, 'SongTextNumber');
+
+ //Show CAt in Top Left Mod
+ ThemeSaveText(Song.TextCat, 'SongTextCat');
+ ThemeSaveStatic(Song.StaticCat, 'SongStaticCat');
+
+ ThemeSaveBasic(Sing, 'Sing');
+
+ //TimeBar mod
+ ThemeSaveStatic(Sing.StaticTimeProgress, 'SingTimeProgress');
+ ThemeSaveText(Sing.TextTimeText, 'SingTimeText');
+ //eoa TimeBar mod
+
+ ThemeSaveStatic(Sing.StaticP1, 'SingP1Static');
+ ThemeSaveText(Sing.TextP1, 'SingP1Text');
+ ThemeSaveStatic(Sing.StaticP1ScoreBG, 'SingP1Static2');
+ ThemeSaveText(Sing.TextP1Score, 'SingP1TextScore');
+
+ //moveable singbar mod
+ ThemeSaveStatic(Sing.StaticP1SingBar, 'SingP1SingBar');
+ ThemeSaveStatic(Sing.StaticP1TwoPSingBar, 'SingP1TwoPSingBar');
+ ThemeSaveStatic(Sing.StaticP1ThreePSingBar, 'SingP1ThreePSingBar');
+ ThemeSaveStatic(Sing.StaticP2RSingBar, 'SingP2RSingBar');
+ ThemeSaveStatic(Sing.StaticP2MSingBar, 'SingP2MSingBar');
+ ThemeSaveStatic(Sing.StaticP3SingBar, 'SingP3SingBar');
+ //eoa moveable singbar
+
+ //Added for ps3 skin
+ //This one is shown in 2/4P mode
+ ThemeSaveStatic(Sing.StaticP1TwoP, 'SingP1TwoPStatic');
+ ThemeSaveText(Sing.TextP1TwoP, 'SingP1TwoPText');
+ ThemeSaveStatic(Sing.StaticP1TwoPScoreBG, 'SingP1TwoPStatic2');
+ ThemeSaveText(Sing.TextP1TwoPScore, 'SingP1TwoPTextScore');
+
+ //This one is shown in 3/6P mode
+ ThemeSaveStatic(Sing.StaticP1ThreeP, 'SingP1ThreePStatic');
+ ThemeSaveText(Sing.TextP1ThreeP, 'SingP1ThreePText');
+ ThemeSaveStatic(Sing.StaticP1ThreePScoreBG, 'SingP1ThreePStatic2');
+ ThemeSaveText(Sing.TextP1ThreePScore, 'SingP1ThreePTextScore');
+ //eoa
+
+ ThemeSaveStatic(Sing.StaticP2R, 'SingP2RStatic');
+ ThemeSaveText(Sing.TextP2R, 'SingP2RText');
+ ThemeSaveStatic(Sing.StaticP2RScoreBG, 'SingP2RStatic2');
+ ThemeSaveText(Sing.TextP2RScore, 'SingP2RTextScore');
+
+ ThemeSaveStatic(Sing.StaticP2M, 'SingP2MStatic');
+ ThemeSaveText(Sing.TextP2M, 'SingP2MText');
+ ThemeSaveStatic(Sing.StaticP2MScoreBG, 'SingP2MStatic2');
+ ThemeSaveText(Sing.TextP2MScore, 'SingP2MTextScore');
+
+ ThemeSaveStatic(Sing.StaticP3R, 'SingP3RStatic');
+ ThemeSaveText(Sing.TextP3R, 'SingP3RText');
+ ThemeSaveStatic(Sing.StaticP3RScoreBG, 'SingP3RStatic2');
+ ThemeSaveText(Sing.TextP3RScore, 'SingP3RTextScore');
+
+ ThemeSaveBasic(Score, 'Score');
+ ThemeSaveText(Score.TextArtist, 'ScoreTextArtist');
+ ThemeSaveText(Score.TextTitle, 'ScoreTextTitle');
+
+ for I := 1 to 6 do begin
+ ThemeSaveStatics(Score.PlayerStatic[I], 'ScorePlayer' + IntToStr(I) + 'Static');
+
+ ThemeSaveText(Score.TextName[I], 'ScoreTextName' + IntToStr(I));
+ ThemeSaveText(Score.TextScore[I], 'ScoreTextScore' + IntToStr(I));
+ ThemeSaveText(Score.TextNotes[I], 'ScoreTextNotes' + IntToStr(I));
+ ThemeSaveText(Score.TextNotesScore[I], 'ScoreTextNotesScore' + IntToStr(I));
+ ThemeSaveText(Score.TextLineBonus[I], 'ScoreTextLineBonus' + IntToStr(I));
+ ThemeSaveText(Score.TextLineBonusScore[I], 'ScoreTextLineBonusScore' + IntToStr(I));
+ ThemeSaveText(Score.TextGoldenNotes[I], 'ScoreTextGoldenNotes' + IntToStr(I));
+ ThemeSaveText(Score.TextGoldenNotesScore[I], 'ScoreTextGoldenNotesScore' + IntToStr(I));
+ ThemeSaveText(Score.TextTotal[I], 'ScoreTextTotal' + IntToStr(I));
+ ThemeSaveText(Score.TextTotalScore[I], 'ScoreTextTotalScore' + IntToStr(I));
+
+ ThemeSaveStatic(Score.StaticBackLevel[I], 'ScoreStaticBackLevel' + IntToStr(I));
+ ThemeSaveStatic(Score.StaticBackLevelRound[I], 'ScoreStaticBackLevelRound' + IntToStr(I));
+ ThemeSaveStatic(Score.StaticLevel[I], 'ScoreStaticLevel' + IntToStr(I));
+ ThemeSaveStatic(Score.StaticLevelRound[I], 'ScoreStaticLevelRound' + IntToStr(I));
+ end;
+
+ ThemeSaveBasic(Top, 'Top');
+ ThemeSaveText(Top.TextLevel, 'TopTextLevel');
+ ThemeSaveText(Top.TextArtistTitle, 'TopTextArtistTitle');
+ ThemeSaveStatics(Top.StaticNumber, 'TopStaticNumber');
+ ThemeSaveTexts(Top.TextNumber, 'TopTextNumber');
+ ThemeSaveTexts(Top.TextName, 'TopTextName');
+ ThemeSaveTexts(Top.TextScore, 'TopTextScore');
+
+
+ ThemeIni.Free;
+end;
+
+procedure TTheme.ThemeSaveBasic(Theme: TThemeBasic; Name: string);
+begin
+ ThemeIni.WriteInteger(Name, 'Texts', Length(Theme.Text));
+
+ ThemeSaveBackground(Theme.Background, Name + 'Background');
+ ThemeSaveStatics(Theme.Static, Name + 'Static');
+ ThemeSaveTexts(Theme.Text, Name + 'Text');
+end;
+
+procedure TTheme.ThemeSaveBackground(ThemeBackground: TThemeBackground; Name: string);
+begin
+ if ThemeBackground.Tex <> '' then
+ ThemeIni.WriteString(Name, 'Tex', ThemeBackground.Tex)
+ else begin
+ ThemeIni.EraseSection(Name);
+ end;
+end;
+
+procedure TTheme.ThemeSaveStatic(ThemeStatic: TThemeStatic; Name: string);
+begin
+ DecimalSeparator := '.';
+ ThemeIni.WriteInteger(Name, 'X', ThemeStatic.X);
+ ThemeIni.WriteInteger(Name, 'Y', ThemeStatic.Y);
+ ThemeIni.WriteInteger(Name, 'W', ThemeStatic.W);
+ ThemeIni.WriteInteger(Name, 'H', ThemeStatic.H);
+
+ ThemeIni.WriteString(Name, 'Tex', ThemeStatic.Tex);
+ ThemeIni.WriteString(Name, 'Type', ThemeStatic.Typ);
+ ThemeIni.WriteString(Name, 'Color', ThemeStatic.Color);
+
+ ThemeIni.WriteFloat(Name, 'TexX1', ThemeStatic.TexX1);
+ ThemeIni.WriteFloat(Name, 'TexY1', ThemeStatic.TexY1);
+ ThemeIni.WriteFloat(Name, 'TexX2', ThemeStatic.TexX2);
+ ThemeIni.WriteFloat(Name, 'TexY2', ThemeStatic.TexY2);
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeSaveStatics(ThemeStatic: AThemeStatic; Name: string);
+var
+ S: integer;
+begin
+ for S := 0 to Length(ThemeStatic)-1 do
+ ThemeSaveStatic(ThemeStatic[S], Name + {'Static' +} IntToStr(S+1));
+
+ ThemeIni.EraseSection(Name + {'Static' + }IntToStr(S+1));
+end;
+
+procedure TTheme.ThemeSaveText(ThemeText: TThemeText; Name: string);
+begin
+ DecimalSeparator := '.';
+ ThemeIni.WriteInteger(Name, 'X', ThemeText.X);
+ ThemeIni.WriteInteger(Name, 'Y', ThemeText.Y);
+
+ ThemeIni.WriteInteger(Name, 'Font', ThemeText.Font);
+ ThemeIni.WriteInteger(Name, 'Size', ThemeText.Size);
+ ThemeIni.WriteInteger(Name, 'Align', ThemeText.Align);
+
+ ThemeIni.WriteString(Name, 'Text', ThemeText.Text);
+ ThemeIni.WriteString(Name, 'Color', ThemeText.Color);
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.ThemeSaveTexts(ThemeText: AThemeText; Name: string);
+var
+ T: integer;
+begin
+ for T := 0 to Length(ThemeText)-1 do
+ ThemeSaveText(ThemeText[T], Name + {'Text' + }IntToStr(T+1));
+
+ ThemeIni.EraseSection(Name + {'Text' + }IntToStr(T+1));
+end;
+
+procedure TTheme.ThemeSaveButton(ThemeButton: TThemeButton; Name: string);
+var
+ T: integer;
+begin
+ DecimalSeparator := '.';
+ ThemeIni.WriteString(Name, 'Tex', ThemeButton.Tex);
+ ThemeIni.WriteInteger(Name, 'X', ThemeButton.X);
+ ThemeIni.WriteInteger(Name, 'Y', ThemeButton.Y);
+ ThemeIni.WriteInteger(Name, 'W', ThemeButton.W);
+ ThemeIni.WriteInteger(Name, 'H', ThemeButton.H);
+
+ ThemeIni.WriteString(Name, 'Type', ThemeButton.Typ);
+ ThemeIni.WriteInteger(Name, 'Texts', Length(ThemeButton.Text));
+
+ ThemeIni.WriteString(Name, 'Color', ThemeButton.Color);
+
+{ ThemeButton.ColR := ThemeIni.ReadFloat(Name, 'ColR', 1);
+ ThemeButton.ColG := ThemeIni.ReadFloat(Name, 'ColG', 1);
+ ThemeButton.ColB := ThemeIni.ReadFloat(Name, 'ColB', 1);
+ ThemeButton.Int := ThemeIni.ReadFloat(Name, 'Int', 1);
+ ThemeButton.DColR := ThemeIni.ReadFloat(Name, 'DColR', 1);
+ ThemeButton.DColG := ThemeIni.ReadFloat(Name, 'DColG', 1);
+ ThemeButton.DColB := ThemeIni.ReadFloat(Name, 'DColB', 1);
+ ThemeButton.DInt := ThemeIni.ReadFloat(Name, 'DInt', 1);}
+
+{ C := ColorExists(ThemeIni.ReadString(Name, 'Color', ''));
+ if C >= 0 then begin
+ ThemeButton.ColR := Color[C].RGB.R;
+ ThemeButton.ColG := Color[C].RGB.G;
+ ThemeButton.ColB := Color[C].RGB.B;
+ end;
+
+ C := ColorExists(ThemeIni.ReadString(Name, 'DColor', ''));
+ if C >= 0 then begin
+ ThemeButton.DColR := Color[C].RGB.R;
+ ThemeButton.DColG := Color[C].RGB.G;
+ ThemeButton.DColB := Color[C].RGB.B;
+ end;}
+
+ for T := 0 to High(ThemeButton.Text) do
+ ThemeSaveText(ThemeButton.Text[T], Name + 'Text' + IntToStr(T+1));
+
+ DecimalSeparator := ',';
+end;
+
+procedure TTheme.create_theme_objects();
+begin
+ freeandnil( Loading );
+ Loading := TThemeLoading.Create;
+
+ freeandnil( Main );
+ Main := TThemeMain.Create;
+
+ freeandnil( Name );
+ Name := TThemeName.Create;
+
+ freeandnil( Level );
+ Level := TThemeLevel.Create;
+
+ freeandnil( Song );
+ Song := TThemeSong.Create;
+
+ freeandnil( Sing );
+ Sing := TThemeSing.Create;
+
+ freeandnil( Score );
+ Score := TThemeScore.Create;
+
+ freeandnil( Top );
+ Top := TThemeTop.Create;
+
+ freeandnil( Options );
+ Options := TThemeOptions.Create;
+
+ freeandnil( OptionsGame );
+ OptionsGame := TThemeOptionsGame.Create;
+
+ freeandnil( OptionsGraphics );
+ OptionsGraphics := TThemeOptionsGraphics.Create;
+
+ freeandnil( OptionsSound );
+ OptionsSound := TThemeOptionsSound.Create;
+
+ freeandnil( OptionsLyrics );
+ OptionsLyrics := TThemeOptionsLyrics.Create;
+
+ freeandnil( OptionsThemes );
+ OptionsThemes := TThemeOptionsThemes.Create;
+
+ freeandnil( OptionsRecord );
+ OptionsRecord := TThemeOptionsRecord.Create;
+
+ freeandnil( OptionsAdvanced );
+ OptionsAdvanced := TThemeOptionsAdvanced.Create;
+
+ freeandnil( ErrorPopup );
+ ErrorPopup := TThemeError.Create;
+
+ freeandnil( CheckPopup );
+ CheckPopup := TThemeCheck.Create;
+
+ freeandnil( HelpPopup );
+ HelpPopup := TThemeHelp.Create;
+
+ freeandnil( SongMenu );
+ SongMenu := TThemeSongMenu.Create;
+
+ freeandnil( SongJumpto );
+ SongJumpto := TThemeSongJumpto.Create;
+
+ //Party Screens
+ freeandnil( PartyNewRound );
+ PartyNewRound := TThemePartyNewRound.Create;
+
+ freeandnil( PartyWin );
+ PartyWin := TThemePartyWin.Create;
+
+ freeandnil( PartyScore );
+ PartyScore := TThemePartyScore.Create;
+
+ freeandnil( PartyOptions );
+ PartyOptions := TThemePartyOptions.Create;
+
+ freeandnil( PartyPlayer );
+ PartyPlayer := TThemePartyPlayer.Create;
+
+ //Party M2 Screens
+ freeandnil( PartyNewRoundM2 );
+ PartyNewRoundM2 := TThemePartyNewRoundM2.Create;
+
+ //freeandnil( PartyWin );
+ //PartyWin := TThemePartyWin.Create;
+
+ //freeandnil( PartyScore );
+ //PartyScore := TThemePartyScore.Create;
+
+ freeandnil( PartyOptionsM2 );
+ PartyOptionsM2 := TThemePartyOptionsM2.Create;
+
+ freeandnil( PartyPlayerM2 );
+ PartyPlayerM2 := TThemePartyPlayerM2.Create;
+
+ //Stats Screens:
+ freeandnil( StatMain );
+ StatMain := TThemeStatMain.Create;
+
+ freeandnil( StatDetail );
+ StatDetail := TThemeStatDetail.Create;
+
+ end;
+
+end.
diff --git a/Game/Code/Classes/UTime.pas b/Game/Code/Classes/UTime.pas
new file mode 100644
index 00000000..29e972ae
--- /dev/null
+++ b/Game/Code/Classes/UTime.pas
@@ -0,0 +1,81 @@
+unit UTime;
+
+interface
+
+type
+ TTime = class
+ constructor Create;
+ function GetTime: real;
+ end;
+
+procedure CountSkipTimeSet;
+procedure CountSkipTime;
+procedure CountMidTime;
+procedure TimeSleep(ms: real);
+
+var
+ USTime: TTime;
+
+ TimeFreq: int64;
+ TimeNew: int64;
+ TimeOld: int64;
+ TimeSkip: real;
+ TimeMid: real;
+ TimeMidTemp: int64;
+
+implementation
+
+uses Windows;
+
+constructor TTime.Create;
+begin
+ CountSkipTimeSet;
+end;
+
+procedure CountSkipTimeSet;
+begin
+ QueryPerformanceFrequency(TimeFreq);
+ QueryPerformanceCounter(TimeNew);
+end;
+
+procedure CountSkipTime;
+begin
+ TimeOld := TimeNew;
+ QueryPerformanceCounter(TimeNew);
+ TimeSkip := (TimeNew-TimeOld)/TimeFreq;
+end;
+
+procedure CountMidTime;
+begin
+ QueryPerformanceCounter(TimeMidTemp);
+ TimeMid := (TimeMidTemp-TimeNew)/TimeFreq;
+end;
+
+procedure TimeSleep(ms: real);
+var
+ TimeStart: int64;
+ TimeHalf: int64;
+ Time: real;
+ Stop: boolean;
+begin
+ QueryPerformanceCounter(TimeStart);
+
+ Stop := false;
+ while (not Stop) do begin
+ QueryPerformanceCounter(TimeHalf);
+ Time := 1000 * (TimeHalf-TimeStart)/TimeFreq;
+ if Time > ms then Stop := true;
+ end;
+
+end;
+
+function TTime.GetTime: real;
+var
+ TimeTemp: int64;
+begin
+ QueryPerformanceCounter(TimeTemp);
+ Result := TimeTemp/TimeFreq;
+end;
+
+
+end.
diff --git a/Game/Code/Classes/UVideo.pas b/Game/Code/Classes/UVideo.pas
new file mode 100644
index 00000000..94c58060
--- /dev/null
+++ b/Game/Code/Classes/UVideo.pas
@@ -0,0 +1,737 @@
+{############################################################################
+# FFmpeg support for UltraStar deluxe #
+# now uses acinerella #
+# #
+# Created by b1indy, modified by brunzel #
+# based on 'An ffmpeg and SDL Tutorial' (http://www.dranger.com/ffmpeg/) #
+# and acinerella demo (http://sourceforge.net/projects/acinerella/) #
+#############################################################################}
+
+//{$define Info}
+
+
+unit UVideo;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE DELPHI}
+{$ENDIF}
+
+
+uses SDL,
+ Classes, //for TFilestream
+ UGraphicClasses,
+ textgl,
+ acinerella,
+ math,
+ gl,
+ glu,
+ SysUtils,
+ {$ifdef DebugDisplay}
+ {$ifdef win32}
+ dialogs,
+ {$endif}
+ {$ENDIF}
+ UIni;
+
+type
+ TRectCoords = record //from 1.1
+ Left, Right: double;
+ Upper, Lower: double;
+ windowed: boolean;
+ end;
+
+ TAspectCorrection = (acoStretch, acoCrop, acoLetterBox); //from 1.1
+
+procedure Init;
+procedure acOpenFile(FileName: pAnsiChar);
+procedure acClose;
+procedure acGetFrame(Time: Extended);
+function acSearch(Time: Extended): integer;
+procedure acDrawGL(Screen: integer);
+procedure acDrawGLi(Screen: integer; Window: TRectCoords; Blend: real);
+procedure acTogglePause;
+procedure acSkip(Gap: Single; Start: Single);
+procedure acSkip2(Gap: Single; Start: Single);
+procedure ToggleAspectCorrection;
+procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords; Window: TRectCoords);
+procedure SetAspectCorrection(aspect: TAspectCorrection);
+procedure ResetAspectCorrection;
+
+var
+ VideoOpened, VideoPaused: Boolean;
+ VideoTex: glUint;
+ TexData: array of Byte;
+ VideoStreamIndex: Integer;
+ //myBuffer: pByte;
+ TexX, TexY, dataX, dataY: Cardinal;
+ VideoTimeBase, VideoTime, LastFrameTime, TimeDifference, NegativeSkipTime: Extended;
+ ScaledVideoWidth, ScaledVideoHeight: Real;
+ VideoAspect: Real;
+ VideoSkipTime: Single;
+ ActualH, ActualW: Integer;
+
+ inst: PAc_instance;
+ pack: PAc_package;
+ info: TAc_stream_info;
+ videodecoder: PAc_decoder;
+
+ fAspect: real; //**< width/height ratio (from 1.1)
+ fAspectCorrection: TAspectCorrection; //from 1.1
+
+ fs: TFileStream;
+ fName: string;
+
+
+ timediff: PChar; //for debug
+ timediff_str: string; //for debug
+ mtime: PChar; //for debug
+ mtime_str: string; //for debug
+
+implementation
+
+uses
+ UGraphic, ULog;
+
+function read_proc(sender: Pointer; buf: PByte; size: integer): integer; cdecl;
+begin
+ result := fs.Read(buf^, size);
+end;
+
+function seek_proc(sender: Pointer; pos: int64; whence: integer): int64; cdecl;
+begin
+ if whence in [0, 1, 2] then
+ result := fs.Seek(pos, TSeekOrigin(whence))
+ else
+ result := -1;
+end;
+
+procedure Init;
+begin
+ videodecoder := nil;
+
+ VideoOpened:=False;
+ VideoPaused:=False;
+ fName := '';
+
+ glGenTextures(1, PglUint(@VideoTex));
+ SetLength(TexData,0);
+
+ fAspectCorrection := TAspectCorrection(Ini.AspectCorrect);
+end;
+
+procedure acOpenFile(FileName: pAnsiChar);
+var
+ I: integer;
+ rTimeBase: Extended;
+begin
+
+ VideoPaused := False;
+ VideoTimeBase := 0;
+ rTimeBase:=0;
+ VideoTime := 0;
+ LastFrameTime := 0;
+ TimeDifference := 0;
+
+ acClose;
+
+ if not FileExists(FileName) then
+ Exit; //TODO: error.log
+
+ fs := TFileStream.Create(FileName, fmOpenRead);
+ fs.Position := 0;
+
+ inst := ac_init();
+ videodecoder := nil;
+ ac_open(inst, nil, nil, @read_proc, @seek_proc, nil);
+
+ if not inst^.opened then
+ begin
+ fs.Free;
+ Exit; //TODO: error.log
+ end;
+
+ //find VideoStreamIndex
+ VideoStreamIndex:=-1;
+ for I := 0 to inst^.stream_count - 1 do
+ begin
+ ac_get_stream_info(inst, I, @info);
+ case info.stream_type of
+ AC_STREAM_TYPE_VIDEO:
+ begin
+
+ if videodecoder = nil then
+ begin
+ VideoStreamIndex:=I;
+ inst^.output_format := AC_OUTPUT_RGB24;
+ videodecoder := ac_create_decoder(inst, I);
+ end;
+ end;
+ end;
+ end;
+
+ if(VideoStreamIndex < 0) then
+ begin
+ if videodecoder <> nil then
+ ac_free_decoder(videodecoder);
+ ac_close(inst);
+ ac_free(inst);
+ fs.Free;
+ Exit;
+ end;
+
+ VideoOpened:=True;
+ fName := FileName;
+
+ TexX := videodecoder^.stream_info.additional_info.video_info.frame_width;
+ TexY := videodecoder^.stream_info.additional_info.video_info.frame_height;
+ dataX := Round(Power(2, Ceil(Log2(TexX))));
+ dataY := Round(Power(2, Ceil(Log2(TexY))));
+ SetLength(TexData,TexX*TexY*3);
+
+ // calculate some information for video display
+ VideoAspect:=videodecoder^.stream_info.additional_info.video_info.pixel_aspect;
+ if (VideoAspect = 0) then
+ VideoAspect:=TexX/TexY
+ else
+ VideoAspect:=VideoAspect*TexX/TexY;
+
+ fAspect := VideoAspect;
+
+ VideoTimeBase:=info.additional_info.video_info.frames_per_second;
+
+ //from 1.1
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+ glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, dataX, dataY, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, nil);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+end;
+
+procedure acClose;
+begin
+ if VideoOpened then begin
+
+ if videodecoder <> nil then
+ ac_free_decoder(videodecoder);
+ videodecoder:=nil;
+ ac_close(inst);
+ ac_free(inst);
+ inst := nil;
+ fs.Free;
+ fs:=nil;
+ SetLength(TexData,0);
+ VideoOpened:=False;
+ fName := '';
+ end;
+end;
+
+procedure acTogglePause;
+begin
+ if VideoPaused then VideoPaused:=False
+ else VideoPaused:=True;
+end;
+
+procedure acSkip2(Gap: Single; Start: Single);
+var
+ seek_target: uint64;
+begin
+ VideoSkiptime:=Gap;
+ NegativeSkipTime:=Start+Gap;
+ if Start+Gap > 0 then
+ begin
+ VideoTime:=Start+Gap;
+ //ac_seek(videodecoder, 0, Floor((Start+Gap)*1000));
+ ac_seek(videodecoder, -1, Floor((Start+Gap)*1000));
+ //acSearch(Gap+Start);
+ {if (ac_seek(videodecoder, -1, Floor((Start+Gap)*1000))=0) then
+ if (ac_seek(videodecoder, 0, Floor((Start+Gap)*1000))=0) then
+ begin
+ ac_seek(videodecoder, 0, 0);
+ VideoTime:=0;
+ //acSearch(Gap+Start);
+
+ end; }
+ end else
+ begin
+ ac_seek(videodecoder, 0, 0);
+ VideoTime:=0;
+ end;
+end;
+
+procedure acSkip(Gap: Single; Start: Single);
+var
+ seek_target: uint64;
+begin
+ VideoSkiptime:=Gap;
+ NegativeSkipTime:=Start+Gap;
+ if Start+Gap > 0 then
+ begin
+ VideoTime:=0;
+ ac_seek(videodecoder, -1, Floor((Start+Gap)*1000));
+ if (acSearch(Gap+Start)=0) then
+ begin
+ ac_seek(videodecoder, 0, 0);
+ VideoTime:=0;
+ acSearch(Gap+Start);
+ end;
+ end else
+ begin
+ ac_seek(videodecoder, 0, 0);
+ VideoTime:=0;
+ end;
+end;
+
+function acSearch(Time: Extended): integer;
+var
+ FrameFinished: Integer;
+ errnum: Integer;
+ FrameDataPtr: PByteArray;
+ myTime: Extended;
+ DropFrame: Boolean;
+
+begin
+ Result := 0;
+ if not VideoOpened then Exit;
+ if (NegativeSkipTime < 0)and(Time+NegativeSkipTime>=0) then
+ NegativeSkipTime:=0;
+
+ myTime:=Time+VideoSkipTime;
+ TimeDifference:=myTime-VideoTime;
+ if Ini.Debug = 1 then
+ begin
+ timediff_str:= 't-diff: ' + FormatFloat('#0.00', TimeDifference);
+ timediff := Addr(timediff_str[1]);
+ mtime_str:= 'mytime: ' + FormatFloat('#0.00', myTime);
+ mtime := Addr(mtime_str[1]);
+ end;
+ DropFrame:=False;
+
+ if (VideoTime <> 0) and (TimeDifference <= VideoTimeBase) then begin
+ if Ini.Debug = 1 then
+ begin
+ // frame delay debug display
+ GoldenRec.Spawn(200,65,1,16,0,-1,ColoredStar,$00ff00);
+ end;
+ Exit;// we don't need a new frame now
+ end;
+
+ if TimeDifference >= 2*VideoTimeBase then
+ begin // skip frames
+ if Ini.Debug = 1 then
+ begin
+ //frame drop debug display
+ GoldenRec.Spawn(200,105,1,16,0,-1,ColoredStar,$ff0000);
+ end;
+
+ DropFrame:=True;
+ end;
+
+ pack := ac_read_package(inst);
+ FrameFinished:=0;
+ // read packets until we have a finished frame (or there are no more packets)
+ while ({(FrameFinished=0) or }(VideoTime < Time-VideoTimeBase)) and (pack <> nil) do
+ begin
+ // if we got a packet from the video stream, then decode it
+ if (videodecoder^.stream_index = pack^.stream_index) then
+ begin
+ FrameFinished := ac_decode_package(pack, videodecoder);
+ VideoTime := videodecoder^.timecode;
+ ac_free_package(pack);
+ if ((VideoTime < Time-VideoTimeBase) {or (FrameFinished=0)}) then
+ pack := ac_read_package(inst);
+ end else
+ begin
+ ac_free_package(pack);
+ pack := ac_read_package(inst);
+ //TimeDifference:=myTime-VideoTime;
+ end;
+ end;
+ if (pack<>nil) then
+ ac_free_package(pack);
+
+ // if we did not get an new frame, there's nothing more to do
+ if Framefinished=0 then
+ begin
+// GoldenRec.Spawn(220,15,1,16,0,-1,ColoredStar,$0000ff);
+ Exit;
+ end;
+
+ errnum:=1; //TODO!!
+ if errnum >=0 then begin
+ FrameDataPtr:=Pointer(videodecoder^.buffer);
+ Result := 1;
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY, GL_RGB, GL_UNSIGNED_BYTE, @FrameDataPtr[0]);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ if Ini.Debug = 1 then
+ begin
+ //frame decode debug display
+ GoldenRec.Spawn(200,85,1,16,0,-1,ColoredStar,$ffff00);
+ end;
+
+ end;
+end;
+
+procedure acGetFrame(Time: Extended);
+var
+ FrameFinished: Integer;
+ errnum, x, y: Integer;
+ FrameDataPtr: PByteArray;
+ linesize: integer;
+ myTime: Extended;
+ DropFrame: Boolean;
+ droppedFrames: Integer;
+ I, J: Integer;
+const
+ FRAMEDROPCOUNT=3;
+begin
+ if not VideoOpened then Exit;
+ if VideoPaused then Exit;
+ if (NegativeSkipTime < 0)and(Time+NegativeSkipTime>=0) then NegativeSkipTime:=0;
+
+ myTime:=Time+VideoSkipTime;
+ TimeDifference:=myTime-VideoTime;
+ if Ini.Debug = 1 then
+ begin
+ timediff_str:= 't-diff: ' + FormatFloat('#0.00', TimeDifference);
+ timediff := Addr(timediff_str[1]);
+ mtime_str:= 'mytime: ' + FormatFloat('#0.00', myTime);
+ mtime := Addr(mtime_str[1]);
+ end;
+ DropFrame:=False;
+
+ if (VideoTime <> 0) and (TimeDifference <= VideoTimeBase) then begin
+ if Ini.Debug = 1 then
+ begin
+ // frame delay debug display
+ GoldenRec.Spawn(200,65,1,16,0,-1,ColoredStar,$00ff00);
+ end;
+ Exit;// we don't need a new frame now
+ end;
+
+ if TimeDifference >= (FRAMEDROPCOUNT-1)*VideoTimeBase then begin // skip frames
+ if Ini.Debug = 1 then
+ begin
+ //frame drop debug display
+ GoldenRec.Spawn(200,105,1,16,0,-1,ColoredStar,$ff0000);
+ end;
+
+ DropFrame:=True;
+ end;
+
+ pack := ac_read_package(inst);
+ FrameFinished:=0;
+ // read packets until we have a finished frame (or there are no more packets)
+ while (FrameFinished=0) and (pack <> nil) do
+ begin
+ // if we got a packet from the video stream, then decode it
+ if (videodecoder^.stream_index = pack^.stream_index) then
+ begin
+ FrameFinished := ac_decode_package(pack, videodecoder);
+ ac_free_package(pack);
+ if (FrameFinished=0) then
+ pack := ac_read_package(inst);
+ end else
+ begin
+ ac_free_package(pack);
+ pack := ac_read_package(inst);
+ end;
+ end;
+
+
+ if DropFrame then
+ begin
+ //acSearch(Time);
+ for droppedFrames:=1 to FRAMEDROPCOUNT do
+ begin
+ pack := ac_read_package(inst);
+ FrameFinished:=0;
+ // read packets until we have a finished frame (or there are no more packets)
+ while (FrameFinished=0) and (pack <> nil) do
+ begin
+ // if we got a packet from the video stream, then decode it
+ if (videodecoder^.stream_index = pack^.stream_index) then
+ begin
+ FrameFinished := ac_decode_package(pack, videodecoder);
+ ac_free_package(pack);
+ if (FrameFinished=0) then
+ pack := ac_read_package(inst);
+ end else
+ begin
+ ac_free_package(pack);
+ pack := ac_read_package(inst);
+ end;
+ end;
+ end;
+ end;
+
+ // if we did not get an new frame, there's nothing more to do
+ if Framefinished=0 then
+ begin
+// GoldenRec.Spawn(220,15,1,16,0,-1,ColoredStar,$0000ff);
+ acClose;
+ Exit;
+ end;
+
+ errnum:=1; //TODO!!
+ if errnum >=0 then begin
+ FrameDataPtr:=Pointer(videodecoder^.buffer);
+
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexX, TexY, GL_RGB, GL_UNSIGNED_BYTE, @FrameDataPtr[0]);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ VideoTime := videodecoder^.timecode;
+
+ if Ini.Debug = 1 then
+ begin
+ //frame decode debug display
+ GoldenRec.Spawn(200,85,1,16,0,-1,ColoredStar,$ffff00);
+ end;
+
+ end;
+end;
+
+procedure ToggleAspectCorrection();
+begin
+ case fAspectCorrection of
+ acoCrop : fAspectCorrection := acoStretch;
+ acoStretch : fAspectCorrection := acoLetterBox;
+ acoLetterBox : fAspectCorrection := acoCrop;
+ end;
+ //Ini.AspectCorrect := integer(fAspectCorrection);
+ //Ini.Save;
+end;
+
+procedure SetAspectCorrection(aspect: TAspectCorrection);
+begin
+ fAspectCorrection := aspect;
+end;
+
+procedure ResetAspectCorrection;
+begin
+ case Ini.AspectCorrect of
+ integer(acoCrop) : fAspectCorrection := acoCrop;
+ integer(acoStretch) : fAspectCorrection := acoStretch;
+ integer(acoLetterBox) : fAspectCorrection := acoLetterBox;
+ end;
+end;
+
+procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords; Window: TRectCoords);
+var
+ ScreenAspect: double; // aspect of screen resolution
+ ScaledVideoWidth, ScaledVideoHeight: double;
+ rW, rH: double;
+begin
+ // Three aspects to take into account:
+ // 1. Screen/display resolution (e.g. 1920x1080 -> 16:9)
+ // 2. Render aspect (fixed to 800x600 -> 4:3)
+ // 3. Movie aspect (video frame aspect stored in fAspect)
+ if (Window.windowed) then
+ begin
+ rW := Window.Right-Window.Left;
+ rH := Window.Lower-Window.Upper;
+ ScreenAspect := rW/rH;
+ end else
+ begin
+ rW := RenderW;
+ rH := RenderH;
+ ScreenAspect := (ScreenW/Screens) / ScreenH;
+ end;
+
+ case fAspectCorrection of
+ acoStretch: begin
+ ScaledVideoWidth := rW;
+ ScaledVideoHeight := rH;
+ end;
+ acoCrop: begin
+ if (ScreenAspect >= fAspect) then
+ begin
+ ScaledVideoWidth := rW;
+ ScaledVideoHeight := rH * ScreenAspect/fAspect;
+ end
+ else
+ begin
+ ScaledVideoHeight := rH;
+ ScaledVideoWidth := rW * fAspect/ScreenAspect;
+ end;
+ end;
+ acoLetterBox: begin
+ if (ScreenAspect <= fAspect) then
+ begin
+ ScaledVideoWidth := rW;
+ ScaledVideoHeight := rH * ScreenAspect/fAspect;
+ end
+ else
+ begin
+ ScaledVideoHeight := rH;
+ ScaledVideoWidth := rW * fAspect/ScreenAspect;
+ end;
+ end
+ else
+ raise Exception.Create('Unhandled aspect correction!');
+ end;
+
+ ScreenRect.Left := (rW - ScaledVideoWidth) / 2 + Window.Left;
+ ScreenRect.Right := ScreenRect.Left + ScaledVideoWidth;
+ ScreenRect.Upper := (rH - ScaledVideoHeight) / 2 + Window.Upper;
+ ScreenRect.Lower := ScreenRect.Upper + ScaledVideoHeight;
+
+ // texture contains right/lower (power-of-2) padding.
+ // Determine the texture coords of the video frame.
+ TexRect.Left := 0;
+ TexRect.Right := TexX / dataX;
+ TexRect.Upper := 0;
+ TexRect.Lower := TexY / dataY;
+end;
+
+procedure acDrawGL(Screen: integer);
+var
+ Window: TRectCoords;
+begin
+ Window.Left := 0;
+ Window.Right := RenderW;
+ Window.Upper := 0;
+ Window.Lower := RenderH;
+ Window.windowed := false;
+ acDrawGLi(Screen, Window, 1);
+end;
+
+procedure acDrawGLi(Screen: integer; Window: TRectCoords; Blend: real);
+var
+ text: string;
+ test: PChar;
+ ScreenRect, TexRect: TRectCoords;
+begin
+ // have a nice black background to draw on (even if there were errors opening the vid)
+ if (Screen=1) and not Window.windowed then begin
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+ end;
+ // exit if there's nothing to draw
+ if not VideoOpened then Exit;
+ // if we're still inside negative skip, then exit
+ //if (NegativeSkipTime < 0) then Exit;
+
+ GetVideoRect(ScreenRect, TexRect, Window);
+
+ glEnable(GL_BLEND);
+
+ glScissor(round((Window.Left)*(ScreenW/Screens)/RenderW+(ScreenW/Screens)*(Screen-1)),
+ round((RenderH-Window.Lower)*ScreenH/RenderH),
+ round((Window.Right-Window.Left)*(ScreenW/Screens)/RenderW),
+ round((Window.Lower-Window.Upper)*ScreenH/RenderH));
+ glEnable(GL_SCISSOR_TEST);
+
+
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1, 1, 1, Blend);
+ glBindTexture(GL_TEXTURE_2D, VideoTex);
+ glbegin(gl_quads);
+ // upper-left coord
+ glTexCoord2f(TexRect.Left, TexRect.Upper);
+ glVertex2f(ScreenRect.Left, ScreenRect.Upper);
+ // lower-left coord
+ glTexCoord2f(TexRect.Left, TexRect.Lower);
+ glVertex2f(ScreenRect.Left, ScreenRect.Lower);
+ // lower-right coord
+ glTexCoord2f(TexRect.Right, TexRect.Lower);
+ glVertex2f(ScreenRect.Right, ScreenRect.Lower);
+ // upper-right coord
+ glTexCoord2f(TexRect.Right, TexRect.Upper);
+ glVertex2f(ScreenRect.Right, ScreenRect.Upper);
+
+ glEnd;
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ if (Ini.MovieSize < 1) then //HalfSize BG
+ begin
+ // draw fading bars over top and bottom of background/video
+ glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+ (* black top *)
+ glColor4f(0,0,0,1);
+ glVertex2f(0, 0);
+ glVertex2f(800,0);
+ glVertex2f(800,110);
+ glVertex2f(0,110);
+ (* top gradient *)
+ glVertex2f(0, 110);
+ glVertex2f(800,110);
+ glColor4f(0,0,0,0);
+ glVertex2f(800,130);
+ glVertex2f(0,130);
+
+ (* bottom gradient *)
+ glColor4f(0,0,0,0);
+ glVertex2f(0, 600-130);
+ glVertex2f(800,600-130);
+ glColor4f(0,0,0,1);
+ glVertex2f(800,600-110);
+ glVertex2f(0,600-110);
+ (* black bottom *)
+ glVertex2f(0, 600-110);
+ glVertex2f(800,600-110);
+ glVertex2f(800,600);
+ glVertex2f(0,600);
+
+ glEnd;
+ glDisable(GL_BLEND);
+ end;
+
+// info-stuff
+
+{$ifdef Info}
+ if VideoSkipTime+videodecoder^.timecode+VideoTimeBase < 0 then begin
+ glColor4f(0.7, 1, 0.3, 1);
+ SetFontStyle (1);
+ SetFontItalic(False);
+ SetFontSize(9);
+ SetFontPos (300, 0);
+ glPrint('Delay due to negative VideoGap');
+ glColor4f(1, 1, 1, 1);
+ end;
+{$endif}
+
+ if Ini.Debug = 1 then
+ begin
+ glColor4f(0, 0, 0, 0.2);
+ glbegin(gl_quads);
+ glVertex2f(0, 50);
+ glVertex2f(0, 140);
+ glVertex2f(250, 140);
+ glVertex2f(250, 50);
+ glEnd;
+
+ glColor4f(1,1,1,1);
+ SetFontStyle (1);
+ SetFontItalic(False);
+ SetFontSize(9);
+ SetFontPos (5, 50);
+ text:= 'vtime: ' + FormatFloat('#0.00', VideoTime);
+ test := Addr(text[1]);
+ glPrint(test);
+ SetFontPos (5, 70);
+ //text:= 'vtime: ' + FormatFloat('#0.00', videodecoder^.timecode);
+ //test := Addr(text[1]);
+ glPrint(timediff);
+ SetFontPos (5, 90);
+ glPrint(mtime);
+ SetFontPos (5, 110);
+ case fAspectCorrection of
+ acoCrop : glPrint('Crop');
+ acoStretch : glPrint('Stretch');
+ acoLetterBox : glPrint('LetterBox');
+ end;
+ end;
+end;
+
+end.