diff options
author | k-m_schindler <k-m_schindler@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2008-08-27 14:58:32 +0000 |
---|---|---|
committer | k-m_schindler <k-m_schindler@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2008-08-27 14:58:32 +0000 |
commit | 873f177f08dc7c4fe2d7e50bbe7709df98e238d3 (patch) | |
tree | 78158db79e85a1ac406e81cd6923af4b5a0fd0bc /src/screens | |
parent | 6809e61aef42c36bfebe16414693c82e45bceaff (diff) | |
download | usdx-873f177f08dc7c4fe2d7e50bbe7709df98e238d3.tar.gz usdx-873f177f08dc7c4fe2d7e50bbe7709df98e238d3.tar.xz usdx-873f177f08dc7c4fe2d7e50bbe7709df98e238d3.zip |
rename Screen part2
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1306 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'src/screens')
34 files changed, 14522 insertions, 0 deletions
diff --git a/src/screens/UScreenCredits.pas b/src/screens/UScreenCredits.pas new file mode 100644 index 00000000..f7f1fca7 --- /dev/null +++ b/src/screens/UScreenCredits.pas @@ -0,0 +1,1398 @@ +unit UScreenCredits; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses + UMenu, + SDL, + SDL_Image, + UDisplay, + UTexture, + gl, + UMusic, + UFiles, + SysUtils, + UThemes, + //ULCD, + //ULight, + UGraphicClasses; + +type + TCreditsStages=(InitialDelay,Intro,MainPart,Outro); + + TScreenCredits = class(TMenu) + public + + Credits_X: Real; + Credits_Time: Cardinal; + Credits_Alpha: Cardinal; + CTime: Cardinal; + CTime_hold: Cardinal; + ESC_Alpha: Integer; + + credits_entry_tex: TTexture; + credits_entry_dx_tex: TTexture; + credits_bg_tex: TTexture; + credits_bg_ovl: TTexture; +// credits_bg_logo: TTexture; + credits_bg_scrollbox_left: TTexture; + credits_blindguard: TTexture; + credits_blindy: TTexture; + credits_canni: TTexture; + credits_commandio: TTexture; + credits_lazyjoker: TTexture; + credits_mog: TTexture; + credits_mota: TTexture; + credits_skillmaster: TTexture; + credits_whiteshark: TTexture; + intro_layer01: TTexture; + intro_layer02: TTexture; + intro_layer03: TTexture; + intro_layer04: TTexture; + intro_layer05: TTexture; + intro_layer06: TTexture; + intro_layer07: TTexture; + intro_layer08: TTexture; + intro_layer09: TTexture; + outro_bg: TTexture; + outro_esc: TTexture; + outro_exd: TTexture; + + deluxe_slidein: cardinal; + + CurrentScrollText: String; + NextScrollUpdate: Real; + EndofLastScrollingPart: Cardinal; + CurrentScrollStart, CurrentScrollEnd: Integer; + + CRDTS_Stage: TCreditsStages; + + myTex: glUint; + mysdlimage,myconvertedsdlimage: PSDL_Surface; + + Fadeout: boolean; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function Draw: boolean; override; + procedure onShow; override; + procedure onHide; override; + procedure DrawCredits; + procedure Draw_FunkyText; + end; + +const + Funky_Text: AnsiString = + 'Grandma Deluxe has arrived! Thanks to Corvus5 for the massive work on UltraStar, Wome for the nice tune you´re hearing, '+ + 'all the people who put massive effort and work in new songs (don´t forget UltraStar w/o songs would be nothing), ppl from '+ + 'irc helping us - eBandit and Gabari, scene ppl who really helped instead of compiling and running away. Greetings to DennisTheMenace for betatesting, '+ + 'Demoscene.tv, pouet.net, KakiArts, Sourceforge,..'; + + + Timings: array[0..21] of Cardinal=( + 20, // 0 Delay vor Start + + 149, // 1 Ende erster Intro Zoom + 155, // 2 Start 2. Action im Intro + 170, // 3 Ende Separation im Intro + 271, // 4 Anfang Zoomout im Intro + 0, // 5 unused + 261, // 6 Start fade-to-white im Intro + + 271, // 7 Start Main Part + 280, // 8 Start On-Beat-Sternchen Main Part + + 396, // 9 Start BlindGuard + 666, // 10 Start blindy + 936, // 11 Start Canni + 1206, // 12 Start Commandio + 1476, // 13 Start LazyJoker + 1746, // 14 Start Mog + 2016, // 15 Start Mota + 2286, // 16 Start SkillMaster + 2556, // 17 Start WhiteShark + 2826, // 18 Ende Whiteshark + 3096, // 19 Start FadeOut Mainscreen + 3366, // 20 Ende Credits Tune + 60); // 21 start flare im intro + + + sdl32bpprgba: TSDL_Pixelformat=(palette: nil; + BitsPerPixel: 32; + BytesPerPixel: 4; + Rloss: 0; + Gloss: 0; + Bloss: 0; + Aloss: 0; + Rshift: 0; + Gshift: 8; + Bshift: 16; + Ashift: 24; + Rmask: $000000ff; + Gmask: $0000ff00; + Bmask: $00ff0000; + Amask: $ff000000; + colorkey: 0; + alpha: 255 ); + + +implementation + +uses + ULog, + UGraphic, + UMain, + UIni, + USongs, + Textgl, + ULanguage, + UCommon, + Math; + + +function TScreenCredits.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + case PressedKey of + + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + FadeTo(@ScreenMain); + AudioPlayback.PlaySound(SoundLib.Back); + end; +{ SDLK_SPACE: + begin + setlength(CTime_hold,length(CTime_hold)+1); + CTime_hold[high(CTime_hold)]:=CTime; + end; +} + end;//esac + end; //fi +end; + +constructor TScreenCredits.Create; +begin + inherited Create; + + credits_bg_tex := Texture.LoadTexture(true, 'CRDTS_BG', TEXTURE_TYPE_PLAIN, 0); + credits_bg_ovl := Texture.LoadTexture(true, 'CRDTS_OVL', TEXTURE_TYPE_TRANSPARENT, 0); + + credits_blindguard := Texture.LoadTexture(true, 'CRDTS_blindguard', TEXTURE_TYPE_TRANSPARENT, 0); + credits_blindy := Texture.LoadTexture(true, 'CRDTS_blindy', TEXTURE_TYPE_TRANSPARENT, 0); + credits_canni := Texture.LoadTexture(true, 'CRDTS_canni', TEXTURE_TYPE_TRANSPARENT, 0); + credits_commandio := Texture.LoadTexture(true, 'CRDTS_commandio', TEXTURE_TYPE_TRANSPARENT, 0); + credits_lazyjoker := Texture.LoadTexture(true, 'CRDTS_lazyjoker', TEXTURE_TYPE_TRANSPARENT, 0); + credits_mog := Texture.LoadTexture(true, 'CRDTS_mog', TEXTURE_TYPE_TRANSPARENT, 0); + credits_mota := Texture.LoadTexture(true, 'CRDTS_mota', TEXTURE_TYPE_TRANSPARENT, 0); + credits_skillmaster := Texture.LoadTexture(true, 'CRDTS_skillmaster', TEXTURE_TYPE_TRANSPARENT, 0); + credits_whiteshark := Texture.LoadTexture(true, 'CRDTS_whiteshark', TEXTURE_TYPE_TRANSPARENT, 0); + + intro_layer01 := Texture.LoadTexture(true, 'INTRO_L01', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer02 := Texture.LoadTexture(true, 'INTRO_L02', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer03 := Texture.LoadTexture(true, 'INTRO_L03', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer04 := Texture.LoadTexture(true, 'INTRO_L04', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer05 := Texture.LoadTexture(true, 'INTRO_L05', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer06 := Texture.LoadTexture(true, 'INTRO_L06', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer07 := Texture.LoadTexture(true, 'INTRO_L07', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer08 := Texture.LoadTexture(true, 'INTRO_L08', TEXTURE_TYPE_TRANSPARENT, 0); + intro_layer09 := Texture.LoadTexture(true, 'INTRO_L09', TEXTURE_TYPE_TRANSPARENT, 0); + + outro_bg := Texture.LoadTexture(true, 'OUTRO_BG', TEXTURE_TYPE_PLAIN, 0); + outro_esc := Texture.LoadTexture(true, 'OUTRO_ESC', TEXTURE_TYPE_TRANSPARENT, 0); + outro_exd := Texture.LoadTexture(true, 'OUTRO_EXD', TEXTURE_TYPE_TRANSPARENT, 0); + + CRDTS_Stage:=InitialDelay; +end; + +function TScreenCredits.Draw: boolean; +begin + DrawCredits; + Draw:=true; +end; + +function pixfmt_eq(fmt1,fmt2: TSDL_Pixelformat): boolean; +begin + if (fmt1.BitsPerPixel = fmt2.BitsPerPixel) and + (fmt1.BytesPerPixel = fmt2.BytesPerPixel) and + (fmt1.Rloss = fmt2.Rloss) and + (fmt1.Gloss = fmt2.Gloss) and + (fmt1.Bloss = fmt2.Bloss) and + (fmt1.Rmask = fmt2.Rmask) and + (fmt1.Gmask = fmt2.Gmask) and + (fmt1.Bmask = fmt2.Bmask) and + (fmt1.Rshift = fmt2.Rshift) and + (fmt1.Gshift = fmt2.Gshift) and + (fmt1.Bshift = fmt2.Bshift) + then + pixfmt_eq:=True + else + pixfmt_eq:=False; +end; + +function inttohexstr(i: cardinal):pchar; +var helper, i2, c:cardinal; + tmpstr: string; +begin + helper:=0; + i2:=i; + tmpstr:=''; + for c:=1 to 8 do + begin + helper:=(helper shl 4) or (i2 and $f); + i2:=i2 shr 4; + end; + for c:=1 to 8 do + begin + i2:=helper and $f; + helper := helper shr 4; + case i2 of + 0: tmpstr:=tmpstr+'0'; + 1: tmpstr:=tmpstr+'1'; + 2: tmpstr:=tmpstr+'2'; + 3: tmpstr:=tmpstr+'3'; + 4: tmpstr:=tmpstr+'4'; + 5: tmpstr:=tmpstr+'5'; + 6: tmpstr:=tmpstr+'6'; + 7: tmpstr:=tmpstr+'7'; + 8: tmpstr:=tmpstr+'8'; + 9: tmpstr:=tmpstr+'9'; + 10: tmpstr:=tmpstr+'a'; + 11: tmpstr:=tmpstr+'b'; + 12: tmpstr:=tmpstr+'c'; + 13: tmpstr:=tmpstr+'d'; + 14: tmpstr:=tmpstr+'e'; + 15: tmpstr:=tmpstr+'f'; + end; + end; + inttohexstr:=pchar(tmpstr); +end; + +procedure TScreenCredits.onShow; +begin + inherited; + + CRDTS_Stage:=InitialDelay; + Credits_X := 580; + deluxe_slidein := 0; + Credits_Alpha := 0; + //Music.SetLoop(true); Loop looped ned, so ne scheisse - loop loops not, shit + AudioPlayback.Open(soundpath + 'wome-credits-tune.mp3'); //danke kleinster liebster weeeetüüüüü!! - thank you wetü +// Music.Play; + CTime:=0; +// setlength(CTime_hold,0); + + mysdlimage:=IMG_Load('test.png'); + if assigned(mysdlimage) then + begin + showmessage('opened image via SDL_Image'+#13#10+ + 'Width: '+inttostr(mysdlimage^.w)+#13#10+ + 'Height: '+inttostr(mysdlimage^.h)+#13#10+ + 'BitsPP: '+inttostr(mysdlimage^.format.BitsPerPixel)+#13#10+ + 'BytesPP: '+inttostr(mysdlimage^.format.BytesPerPixel)+#13#10+ + 'Rloss: '+inttostr(mysdlimage^.format.Rloss)+#13#10+ + 'Gloss: '+inttostr(mysdlimage^.format.Gloss)+#13#10+ + 'Bloss: '+inttostr(mysdlimage^.format.Bloss)+#13#10+ + 'Aloss: '+inttostr(mysdlimage^.format.Aloss)+#13#10+ + 'Rshift: '+inttostr(mysdlimage^.format.Rshift)+#13#10+ + 'Gshift: '+inttostr(mysdlimage^.format.Gshift)+#13#10+ + 'Bshift: '+inttostr(mysdlimage^.format.Bshift)+#13#10+ + 'Ashift: '+inttostr(mysdlimage^.format.Ashift)+#13#10+ + 'Rmask: '+inttohexstr(mysdlimage^.format.Rmask)+#13#10+ + 'Gmask: '+inttohexstr(mysdlimage^.format.Gmask)+#13#10+ + 'Bmask: '+inttohexstr(mysdlimage^.format.Bmask)+#13#10+ + 'Amask: '+inttohexstr(mysdlimage^.format.Amask)+#13#10+ + 'ColKey: '+inttostr(mysdlimage^.format.Colorkey)+#13#10+ + 'Alpha: '+inttostr(mysdlimage^.format.Alpha)); + + if pixfmt_eq(mysdlimage^.format^,sdl32bpprgba) then + showmessage('equal pixelformats') + else + showmessage('different pixelformats'); + + myconvertedsdlimage:=SDL_ConvertSurface(mysdlimage,@sdl32bpprgba,SDL_SWSURFACE); + glGenTextures(1,@myTex); + glBindTexture(GL_TEXTURE_2D, myTex); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, 4, myconvertedsdlimage^.w, myconvertedsdlimage^.h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, myconvertedsdlimage^.pixels ); + SDL_FreeSurface(mysdlimage); + SDL_FreeSurface(myconvertedsdlimage); + end + else + showmessage('could not open file - test.png'); + +end; + +procedure TScreenCredits.onHide; +begin + AudioPlayback.Stop; +end; + +Procedure TScreenCredits.Draw_FunkyText; +var + S: Integer; + X,Y,A: Real; + visibleText: PChar; +begin + SetFontSize(10); + //Init ScrollingText + if (CTime = Timings[7]) then + begin + //Set Position of Text + Credits_X := 600; + CurrentScrollStart:=1; + CurrentScrollEnd:=1; + end; + + if (CTime > Timings[7]) and (CurrentScrollStart < length(Funky_Text)) then + begin + X:=0; + visibleText:=pchar(Copy(Funky_Text, CurrentScrollStart, CurrentScrollEnd)); + for S := 0 to length(visibleText)-1 do begin + Y:=abs(sin((Credits_X+X)*0.93{*(((Credits_X+X))/1200)}/100*pi)); + SetFontPos(Credits_X+X,538-Y*(Credits_X+X)*(Credits_X+X)*(Credits_X+X)/1000000); + A:=0; + if (Credits_X+X < 15) then A:=0; + if (Credits_X+X >=15) then A:=Credits_X+X-15; + if Credits_X+X > 32 then A:=17; + glColor4f( 230/255-40/255+Y*(Credits_X+X)/900, 200/255-30/255+Y*(Credits_X+X)/1000, 155/255-20/255+Y*(Credits_X+X)/1100, A/17); + glPrintLetter(visibleText[S]); + X := X + Fonts[ActFont].Width[Ord(visibleText[S])] * Fonts[ActFont].Tex.H / 30 * Fonts[ActFont].AspectW; + end; + if (Credits_X<0) and (CurrentScrollStart < length(Funky_Text)) then begin + Credits_X:=Credits_X + Fonts[ActFont].Width[Ord(Funky_Text[CurrentScrollStart])] * Fonts[ActFont].Tex.H / 30 * Fonts[ActFont].AspectW; + inc(CurrentScrollStart); + end; + visibleText:=pchar(Copy(Funky_Text, CurrentScrollStart, CurrentScrollEnd)); + if (Credits_X+glTextWidth(visibleText) < 600) and (CurrentScrollEnd < length(Funky_Text)) then begin + inc(CurrentScrollEnd); + end; + end; +{ // timing hack + X:=5; + SetFontStyle (2); + SetFontItalic(False); + SetFontSize(9); + glColor4f(1, 1, 1, 1); + for S:=0 to high(CTime_hold) do begin + visibleText:=pchar(inttostr(CTime_hold[S])); + SetFontPos (500, X); + glPrint (Addr(visibleText[0])); + X:=X+20; + end;} +end; + +procedure Start3D; +begin + glMatrixMode(GL_PROJECTION); + glPushMatrix; + glLoadIdentity; + glFrustum(-0.3*4/3,0.3*4/3,-0.3,0.3,1,1000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity; +end; +procedure End3D; +begin + glMatrixMode(GL_PROJECTION); + glPopMatrix; + glMatrixMode(GL_MODELVIEW); +end; + +procedure TScreenCredits.DrawCredits; +var +T{*, I*}: Cardinal; // Auto Removed, Unused Variable (I) // Auto Removed, Unused Variable (I) +// X: Real; // Auto Removed, Unused Variable +// Ver: PChar; // Auto Removed, Unused Variable +// RuntimeStr: AnsiString; // Auto Removed, Unused Variable + Data: TFFTData; + j,k,l:cardinal; +f,g{*, h*}: Real; // Auto Removed, Unused Variable (h) // Auto Removed, Unused Variable (h) + STime:cardinal; + Delay:cardinal; + +// myPixel: longword; // Auto Removed, Unused Variable +// myColor: Cardinal; // Auto Removed, Unused Variable + myScale: Real; + myAngle: Real; + + +const myLogoCoords: Array[0..27,0..1] of Cardinal = ((39,32),(84,32),(100,16),(125,24), + (154,31),(156,58),(168,32),(203,36), + (258,34),(251,50),(274,93),(294,84), + (232,54),(278,62),(319,34),(336,92), + (347,23),(374,32),(377,58),(361,83), + (385,91),(405,91),(429,35),(423,51), + (450,32),(485,34),(444,91),(486,93)); + +begin + //dis does teh muiwk y0r + AudioPlayback.GetFFTData(Data); + + Log.LogStatus('',' JB-1'); + + T := SDL_GetTicks() div 33; + if T <> Credits_Time then + begin + Credits_Time := T; + inc(CTime); + inc(CTime_hold); + Credits_X := Credits_X-2; + + Log.LogStatus('',' JB-2'); + if (CRDTS_Stage=InitialDelay) and (CTime=Timings[0]) then + begin +// CTime:=Timings[20]; +// CRDTS_Stage:=Outro; + + CRDTS_Stage:=Intro; + CTime:=0; + AudioPlayback.Play; + + end; + if (CRDTS_Stage=Intro) and (CTime=Timings[7]) then + begin + CRDTS_Stage:=MainPart; + end; + if (CRDTS_Stage=MainPart) and (CTime=Timings[20]) then + begin + CRDTS_Stage:=Outro; + end; + end; + + Log.LogStatus('',' JB-3'); + + //draw background + if CRDTS_Stage=InitialDelay then + begin + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + end + else + if CRDTS_Stage=Intro then + begin + Start3D; + glPushMatrix; + + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + if CTime < Timings[1] then begin + myScale:= 0.5+0.5*(Timings[1]-CTime)/(Timings[1]); // slowly move layers together + myAngle:=cos((CTime)*pi/((Timings[1])*2)); // and make logo face towards camera + end else begin // this is the part when the logo stands still + myScale:=0.5; + myAngle:=0; + end; + if CTime > Timings[2] then begin + myScale:= 0.5+0.5*(CTime-Timings[2])/(Timings[3]-Timings[2]); // get some space between layers + myAngle:=0; + end; +// if CTime > Timings[3] then myScale:=1; // keep the space between layers + glTranslatef(0,0,-5+0.5*myScale); + if CTime > Timings[3] then myScale:=1; // keep the space between layers + if CTime > Timings[3] then begin // make logo rotate left and grow +// myScale:=(CTime-Timings[4])/(Timings[7]-Timings[4]); + glRotatef(20*sqr(CTime-Timings[3])/sqr((Timings[7]-Timings[3])/2),0,0,1); + glScalef(1+sqr(CTime-Timings[3])/(32*(Timings[7]-Timings[3])),1+sqr(CTime-Timings[3])/(32*(Timings[7]-Timings[3])),1); + end; + if CTime < Timings[2] then + glRotatef(30*myAngle,0.5*myScale+myScale,1+myScale,0); +// glScalef(0.5,0.5,0.5); + glScalef(4/3,-1,1); + glColor4f(1, 1, 1, 1); + + glBindTexture(GL_TEXTURE_2D, intro_layer01.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, -0.4 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, -0.4 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, -0.4 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, -0.4 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer02.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, -0.3 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, -0.3 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, -0.3 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, -0.3 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer03.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, -0.2 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, -0.2 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, -0.2 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, -0.2 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer04.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, -0.1 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, -0.1 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, -0.1 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, -0.1 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer05.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, 0 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, 0 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, 0 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, 0 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer06.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, 0.1 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, 0.1 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, 0.1 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, 0.1 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer07.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, 0.2 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, 0.2 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, 0.2 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, 0.2 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer08.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, 0.3 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, 0.3 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, 0.3 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, 0.3 * myScale); + glEnd; + glBindTexture(GL_TEXTURE_2D, intro_layer09.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex3f(-1, -1, 0.22 * myScale); + glTexCoord2f(0,1);glVertex3f(-1, 1, 0.22 * myScale); + glTexCoord2f(1,1); glVertex3f(1, 1, 0.22 * myScale); + glTexCoord2f(1,0);glVertex3f(1, -1, 0.22 * myScale); + glEnd; + gldisable(gl_texture_2d); + glDisable(GL_BLEND); + + glPopMatrix; + End3D; + + // do some sparkling effects + if (CTime < Timings[1]) and (CTime > Timings[21]) then + begin + for k:=1 to 3 do begin + l:=410+floor((CTime-Timings[21])/(Timings[1]-Timings[21])*(536-410))+RandomRange(-5,5); + j:=floor((Timings[1]-CTime)/22)+RandomRange(285,301); + GoldenRec.Spawn(l, j, 1, 16, 0, -1, Flare, 0); + end; + end; + + // fade to white at end + if Ctime > Timings[6] then + begin + glColor4f(1,1,1,sqr(Ctime-Timings[6])*(Ctime-Timings[6])/sqr(Timings[7]-Timings[6])); + glEnable(GL_BLEND); + glBegin(GL_QUADS); + glVertex2f(0,0); + glVertex2f(0,600); + glVertex2f(800,600); + glVertex2f(800,0); + glEnd; + glDisable(GL_BLEND); + end; + + end; + if (CRDTS_Stage=MainPart) then + // main credits screen background, scroller, logo and girl + begin + + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, credits_bg_tex.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(0, 0); + glTexCoord2f(0,600/1024);glVertex2f(0, 600); + glTexCoord2f(800/1024,600/1024); glVertex2f(800, 600); + glTexCoord2f(800/1024,0);glVertex2f(800, 0); + glEnd; + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // draw scroller + Draw_FunkyText; + +//######################################################################### +// draw credits names + + +Log.LogStatus('',' JB-4'); + +// BlindGuard (von links oben reindrehen, nach rechts unten rausdrehen) - (rotate in from upper left, rotate out to lower right) + STime:=Timings[9]-10; + Delay:=Timings[10]-Timings[9]; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(0,329,0); + if CTime <= STime+10 then begin glrotatef((CTime-STime)*9+270,0,0,1);end; + gltranslatef(223,0,0); + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + gltranslatef(223,0,0); + glrotatef((integer(CTime)-(integer(STime+Delay)-10))*-9,0,0,1); + gltranslatef(-223,0,0); + end; + glBindTexture(GL_TEXTURE_2D, credits_blindguard.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Blindy (zoom von 0 auf volle grösse und drehung, zoom auf doppelte grösse und nach rechts oben schieben) - (zoom from 0 to full size and rotation, zoom zo doubble size and shift to upper right) + STime:=Timings[10]-10; + Delay:=Timings[11]-Timings[10]+5; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+20) and (CTime<=STime+22) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+20 then begin + j:=CTime-Stime; + glscalef(j*j/400,j*j/400,j*j/400); + glrotatef(j*18.0,0,0,1); + end; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=CTime-(STime+Delay-10); + f:=j*10.0; + gltranslatef(f*3,-f,0); + glscalef(1+j/10,1+j/10,1+j/10); + glrotatef(j*9.0,0,0,1); + end; + glBindTexture(GL_TEXTURE_2D, credits_blindy.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Canni (von links reinschieben, nach rechts oben rausschieben) - (shift in from left, shift out to upper right) + STime:=Timings[11]-10; + Delay:=Timings[12]-Timings[11]+5; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then begin + gltranslatef(((CTime-STime)*21.0)-210,0,0); + end; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=(CTime-(STime+Delay-10))*21; + gltranslatef(j,-j/2,0); + end; + glBindTexture(GL_TEXTURE_2D, credits_canni.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Commandio (von unten reinklappen, nach rechts oben rausklappen) - (flip in from down, flip out to upper right) + STime:=Timings[12]-10; + Delay:=Timings[13]-Timings[12]; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then + f:=258.0-25.8*(CTime-STime) + else + f:=0; + g:=0; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=CTime-(STime+Delay-10); + g:=32.6*j; + end; + glBindTexture(GL_TEXTURE_2D, credits_commandio.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163+g-f*1.5, -129+f*1.5-g/2); + glTexCoord2f(0,1);glVertex2f(-163+g*1.5, 129-(g*1.5*258/326)); + glTexCoord2f(1,1); glVertex2f(163+g, 129+g/4); + glTexCoord2f(1,0);glVertex2f(163+f*1.5+g/4, -129+f*1.5-g/4); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// lazy joker (just scrolls from left to right, no twinkling stars, no on-beat flashing) + STime:=Timings[13]-35; + Delay:=Timings[14]-Timings[13]+5; + if CTime > STime then + begin + k:=0; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)>10) and ((CTime-STime)<20) then ESC_Alpha:=20; + ESC_Alpha:=10; + f:=CTime-STime; + if CTime <=STime+40 then j:=CTime-STime else j:=40; + if (CTime >=STime+Delay-40) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j*j/1600); + + glPushMatrix; + gltranslatef(180+(f-70),329,0); + glBindTexture(GL_TEXTURE_2D, credits_lazyjoker.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Mog (von links reinklappen, nach rechts unten rausklappen) - (flip in from right, flip out to lower right) + STime:=Timings[14]-10; + Delay:=Timings[15]-Timings[14]+5; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then + f:=326.0-32.6*(CTime-STime) + else + f:=0; + + g:=0; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=CTime-(STime+Delay-10); + g:=32.6*j; + end; + glBindTexture(GL_TEXTURE_2D, credits_mog.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163+g*1.5, -129+g*1.5); + glTexCoord2f(0,1);glVertex2f(-163+g*1.2, 129+g); + glTexCoord2f(1,1); glVertex2f(163-f+g/2, 129+f*1.5+g/4); + glTexCoord2f(1,0);glVertex2f(163-f+g*1.5, -129-f*1.5); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Mota (von rechts oben reindrehen, nach links unten rausschieben und verkleinern und dabei drehen) - (rotate in from upper right, shift out to lower left while shrinking and rotateing) + STime:=Timings[15]-10; + Delay:=Timings[16]-Timings[15]+5; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then begin + gltranslatef(223,0,0); + glrotatef((10-(CTime-STime))*9,0,0,1); + gltranslatef(-223,0,0); + end; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=CTime-(STime+Delay-10); + f:=j*10.0; + gltranslatef(-f*2,-f,0); + glscalef(1-j/10,1-j/10,1-j/10); + glrotatef(-j*9.0,0,0,1); + end; + glBindTexture(GL_TEXTURE_2D, credits_mota.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// Skillmaster (von rechts unten reinschieben, nach rechts oben rausdrehen) - (shift in from lower right, rotate out to upper right) + STime:=Timings[16]-10; + Delay:=Timings[17]-Timings[16]+5; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then begin + j:=STime+10-CTime; + f:=j*10.0; + gltranslatef(+f*2,+f/2,0); + end; + if CTime >=STime+Delay-10 then if CTime <=STime+Delay then begin + j:=CTime-(STime+Delay-10); + gltranslatef(0,-223,0); + glrotatef(integer(j)*-9,0,0,1); + gltranslatef(0,223,0); + glrotatef(j*9,0,0,1); + end; + glBindTexture(GL_TEXTURE_2D, credits_skillmaster.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163, -129); + glTexCoord2f(0,1);glVertex2f(-163, 129); + glTexCoord2f(1,1); glVertex2f(163, 129); + glTexCoord2f(1,0);glVertex2f(163, -129); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + +// WhiteShark (von links unten reinklappen, nach rechts oben rausklappen) - (flip in from lower left, flip out to upper right) + STime:=Timings[17]-10; + Delay:=Timings[18]-Timings[17]; + if CTime > STime then + begin + k:=0; + ESC_Alpha:=20; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + + if Data[k]>0.25 then ESC_Alpha:=5 else inc(ESC_Alpha); + if ESC_Alpha >20 then ESC_Alpha:=20; + if ((CTime-STime)<20) then ESC_Alpha:=20; + if CTime <=STime+10 then j:=CTime-STime else j:=10; + if (CTime >=STime+Delay-10) then if (CTime <=STime+Delay) then j:=(STime+Delay)-CTime else j:=0; + glColor4f(1, 1, 1, ESC_Alpha/20*j/10); + + if (CTime >= STime+10) and (CTime<=STime+12) then begin + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 0); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 1); + GoldenRec.Spawn(RandomRange(65,390), RandomRange(200,460), 1, 16, 0, -1, PerfectLineTwinkle, 5); + end; + + glPushMatrix; + gltranslatef(223,329,0); + if CTime <= STime+10 then + f:=326.0-32.6*(CTime-STime) + else + f:=0; + + if (CTime >= STime+Delay-10) and (CTime <= STime+Delay) then + begin + j:=CTime-(STime+Delay-10); + g:=32.6*j; + end + else + begin + g:=0; + end; + + glBindTexture(GL_TEXTURE_2D, credits_whiteshark.TexNum); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(-163-f+g, -129+f/4-g/2); + glTexCoord2f(0,1);glVertex2f(-163-f/4+g, 129+g/2+f/4); + glTexCoord2f(1,1); glVertex2f(163-f*1.2+g/4, 129+f/2-g/4); + glTexCoord2f(1,0);glVertex2f(163-f*1.5+g/4, -129+f*1.5+g/4); + glEnd; + gldisable(gl_texture_2d); + gldisable(GL_BLEND); + glPopMatrix; + end; + + + Log.LogStatus('',' JB-103'); + +// #################################################################### +// do some twinkle stuff (kinda on beat) + if (CTime > Timings[8] ) and + (CTime < Timings[19] ) then + begin + k := 0; + + try + for j:=0 to 40 do + begin + if ( j < length( Data ) ) AND + ( k < length( Data ) ) then + begin + if Data[j] >= Data[k] then + k:=j; + end; + end; + except + end; + + if Data[k]>0.2 then + begin + l := RandomRange(6,16); + j := RandomRange(0,27); + + GoldenRec.Spawn(myLogoCoords[j,0], myLogoCoords[j,1], 16-l, l, 0, -1, PerfectNote, 0); + end; + end; + +//################################################# +// draw the rest of the main screen (girl and logo + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, credits_bg_ovl.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(800-393, 0); + glTexCoord2f(0,600/1024);glVertex2f(800-393, 600); + glTexCoord2f(393/512,600/1024); glVertex2f(800, 600); + glTexCoord2f(393/512,0);glVertex2f(800, 0); + glEnd; +{ glBindTexture(GL_TEXTURE_2D, credits_bg_logo.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(0, 0); + glTexCoord2f(0,112/128);glVertex2f(0, 112); + glTexCoord2f(497/512,112/128); glVertex2f(497, 112); + glTexCoord2f(497/512,0);glVertex2f(497, 0); + glEnd; +} + gldisable(gl_texture_2d); + glDisable(GL_BLEND); + + // fade out at end of main part + if Ctime > Timings[19] then + begin + glColor4f(0,0,0,(Ctime-Timings[19])/(Timings[20]-Timings[19])); + glEnable(GL_BLEND); + glBegin(GL_QUADS); + glVertex2f(0,0); + glVertex2f(0,600); + glVertex2f(800,600); + glVertex2f(800,0); + glEnd; + glDisable(GL_BLEND); + end; + end + else + if (CRDTS_Stage=Outro) then + begin + if CTime=Timings[20] then begin + CTime_hold:=0; + AudioPlayback.Stop; + AudioPlayback.Open(soundpath + 'credits-outro-tune.mp3'); + AudioPlayback.SetVolume(0.2); + AudioPlayback.SetLoop(True); + AudioPlayback.Play; + end; + if CTime_hold > 231 then begin + AudioPlayback.Play; + Ctime_hold:=0; + end; + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + + // do something useful + // outro background + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, outro_bg.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(0, 0); + glTexCoord2f(0,600/1024);glVertex2f(0, 600); + glTexCoord2f(800/1024,600/1024); glVertex2f(800, 600); + glTexCoord2f(800/1024,0);glVertex2f(800, 0); + glEnd; + + //outro overlays + glColor4f(1, 1, 1, (1+sin(CTime/15))/3+1/3); + glBindTexture(GL_TEXTURE_2D, outro_esc.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(0, 0); + glTexCoord2f(0,223/256);glVertex2f(0, 223); + glTexCoord2f(487/512,223/256); glVertex2f(487, 223); + glTexCoord2f(487/512,0);glVertex2f(487, 0); + glEnd; + + ESC_Alpha:=20; + if (RandomRange(0,20) > 18) and (ESC_Alpha=20) then + ESC_Alpha:=0 + else inc(ESC_Alpha); + if ESC_Alpha > 20 then ESC_Alpha:=20; + glColor4f(1, 1, 1, ESC_Alpha/20); + glBindTexture(GL_TEXTURE_2D, outro_exd.TexNum); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(800-310, 600-247); + glTexCoord2f(0,247/256);glVertex2f(800-310, 600); + glTexCoord2f(310/512,247/256); glVertex2f(800, 600); + glTexCoord2f(310/512,0);glVertex2f(800, 600-247); + glEnd; + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // outro scrollers? + // ... + end; + +{ // draw credits runtime counter + SetFontStyle (2); + SetFontItalic(False); + SetFontSize(9); + SetFontPos (5, 5); + glColor4f(1, 1, 1, 1); +// RuntimeStr:='CTime: '+inttostr(floor(CTime/30.320663991914489602156136106092))+'.'+inttostr(floor(CTime/3.0320663991914489602156136106092)-floor(CTime/30.320663991914489602156136106092)*10); + RuntimeStr:='CTime: '+inttostr(CTime); + glPrint (Addr(RuntimeStr[1])); +} + + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, myTex); + glbegin(gl_quads); + glTexCoord2f(0,0);glVertex2f(100, 100); + glTexCoord2f(0,1);glVertex2f(100, 200); + glTexCoord2f(1,1); glVertex2f(200, 200); + glTexCoord2f(1,0);glVertex2f(200, 100); + glEnd; + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + + // make the stars shine + GoldenRec.Draw; +end; + +end. diff --git a/src/screens/UScreenEdit.pas b/src/screens/UScreenEdit.pas new file mode 100644 index 00000000..bf664eb1 --- /dev/null +++ b/src/screens/UScreenEdit.pas @@ -0,0 +1,121 @@ +unit UScreenEdit; + +interface + +{$I switches.inc} + +uses UMenu, SDL, UThemes; + +type + TScreenEdit = class(TMenu) + public +{ Tex_Background: TTexture; + FadeOut: boolean; + Path: string; + FileName: string;} + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; +{ function Draw: boolean; override; + procedure Finish;} + end; + +implementation + +uses UGraphic, UMusic, USkins, SysUtils; + +function TScreenEdit.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); +// Result := false; + end; + SDLK_RETURN: + begin + if Interaction = 0 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenEditConvert); + end; +// if Interaction = 1 then begin +// Music.PlayStart; +// FadeTo(@ScreenEditHeader); +// end; + + if Interaction = 1 then + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end; + end; + + SDLK_DOWN: + begin + InteractNext; + end; + SDLK_UP: + begin + InteractPrev; + end; + end; + end; +end; + +constructor TScreenEdit.Create; +begin + inherited Create; + AddButton(400-200, 100 + 0*70, 400, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(10, 5, 0, 0, 0, 'Convert Midi to Txt'); +// Button[High(Button)].Text[0].Size := 11; + +// AddButton(400-200, 100 + 1*60, 400, 40, 'ButtonF'); +// AddButtonText(10, 5, 0, 0, 0, 'Edit Headers'); + +// AddButton(400-200, 100 + 2*60, 400, 40, 'ButtonF'); +// AddButtonText(10, 5, 0, 0, 0, 'Set GAP'); + + AddButton(400-200, 100 + 3*60, 400, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(10, 5, 0, 0, 0, 'Exit'); + +end; + +procedure TScreenEdit.onShow; +begin + inherited; + +// Interaction := 0; +end; + +(*function TScreenEdit.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + Pet: integer; + AktBeat: integer; +begin +end; + +procedure TScreenEdit.Finish; +begin +// +end;*) + +end. diff --git a/src/screens/UScreenEditConvert.pas b/src/screens/UScreenEditConvert.pas new file mode 100644 index 00000000..dfde696e --- /dev/null +++ b/src/screens/UScreenEditConvert.pas @@ -0,0 +1,584 @@ +unit UScreenEditConvert; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses UMenu, + SDL, + {$IFDEF UseMIDIPort} + MidiFile, + MidiOut, + {$ENDIF} + ULog, + USongs, + USong, + UMusic, + UThemes; + +type + TNote = record + Event: integer; + EventType: integer; + Channel: integer; + Start: real; + Len: real; + Data1: integer; + Data2: integer; + Str: string; + end; + + TTrack = record + Note: array of TNote; + Name: string; + Hear: boolean; + Status: byte; // 0 - none, 1 - notes, 2 - lyrics, 3 - notes + lyrics + end; + + TNuta = record + Start: integer; + Len: integer; + Tone: integer; + Lyric: string; + NewSentence: boolean; + end; + + TArrayTrack = array of TTrack; + + TScreenEditConvert = class(TMenu) + public + ATrack: TArrayTrack; // actual track +// Track: TArrayTrack; + Channel: TArrayTrack; + ColR: array[0..100] of real; + ColG: array[0..100] of real; + ColB: array[0..100] of real; + Len: real; + Sel: integer; + Selected: boolean; +// FileName: string; + + {$IFDEF UseMIDIPort} + MidiFile: TMidiFile; + MidiTrack: TMidiTrack; + MidiEvent: pMidiEvent; + MidiOut: TMidiOutput; + {$ENDIF} + + Song: TSong; + Lines: TLines; + BPM: real; + Ticks: real; + Note: array of TNuta; + + procedure AddLyric(Start: integer; Text: string); + procedure Extract; + + {$IFDEF UseMIDIPort} + procedure MidiFile1MidiEvent(event: PMidiEvent); + {$ENDIF} + + function SelectedNumber: integer; + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function Draw: boolean; override; + procedure onHide; override; + end; + +implementation +uses UGraphic, + SysUtils, + UDrawTexture, + TextGL, + UFiles, + UMain, + UIni, + gl, + USkins; + +function TScreenEditConvert.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + T: integer; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + {$IFDEF UseMIDIPort} + MidiFile.StopPlaying; + {$ENDIF} + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenEdit); + end; + + SDLK_RETURN: + begin + if Interaction = 0 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + ScreenOpen.BackScreen := @ScreenEditConvert; + FadeTo(@ScreenOpen); + end; + + if Interaction = 1 then + begin + Selected := false; + {$IFDEF UseMIDIPort} + MidiFile.OnMidiEvent := MidiFile1MidiEvent; +// MidiFile.GoToTime(MidiFile.GetTrackLength div 2); + MidiFile.StartPlaying; + {$ENDIF} + end; + + if Interaction = 2 then begin + Selected := true; + {$IFDEF UseMIDIPort} + MidiFile.OnMidiEvent := nil; + {$ENDIF} + {for T := 0 to High(ATrack) do begin + if ATrack[T].Hear then begin + MidiTrack := MidiFile.GetTrack(T); + MidiTrack.OnMidiEvent := MidiFile1MidiEvent; + end; + end; + MidiFile.StartPlaying;//} + end; + + if Interaction = 3 then begin + if SelectedNumber > 0 then begin + Extract; + SaveSong(Song, Lines, ChangeFileExt(ConversionFileName, '.txt'), false); + end; + end; + + end; + + SDLK_SPACE: + begin +// ATrack[Sel].Hear := not ATrack[Sel].Hear; + ATrack[Sel].Status := (ATrack[Sel].Status + 1) mod 4; + +{ if Selected then begin + MidiTrack := MidiFile.GetTrack(Sel); + if Track[Sel].Hear then + MidiTrack.OnMidiEvent := MidiFile1MidiEvent + else + MidiTrack.OnMidiEvent := nil; + end;} + end; + + SDLK_RIGHT: + begin + InteractNext; + end; + + SDLK_LEFT: + begin + InteractPrev; + end; + + SDLK_DOWN: + begin + Inc(Sel); + if Sel > High(ATrack) then Sel := 0; + end; + SDLK_UP: + begin + Dec(Sel); + if Sel < 0 then Sel := High(ATrack); + end; + end; + end; +end; + +procedure TScreenEditConvert.AddLyric(Start: integer; Text: string); +var + N: integer; +begin + for N := 0 to High(Note) do begin + if Note[N].Start = Start then begin + // check for new sentece + if Copy(Text, 1, 1) = '\' then Delete(Text, 1, 1); + if Copy(Text, 1, 1) = '/' then begin + Delete(Text, 1, 1); + Note[N].NewSentence := true; + end; + + // overwrite lyric od append + if Note[N].Lyric = '-' then + Note[N].Lyric := Text + else + Note[N].Lyric := Note[N].Lyric + Text; + end; + end; +end; + +procedure TScreenEditConvert.Extract; +var + T: integer; + C: integer; + N: integer; + Nu: integer; + NoteTemp: TNuta; + Move: integer; + Max, Min: integer; +begin + // song info + Song.Title := ''; + Song.Artist := ''; + Song.Mp3 := ''; + Song.Resolution := 4; + SetLength(Song.BPM, 1); + Song.BPM[0].BPM := BPM*4; + + SetLength(Note, 0); + + // extract notes + for T := 0 to High(ATrack) do begin +// if ATrack[T].Hear then begin + if ((ATrack[T].Status div 1) and 1) = 1 then begin + for N := 0 to High(ATrack[T].Note) do begin + if (ATrack[T].Note[N].EventType = 9) and (ATrack[T].Note[N].Data2 > 0) then begin + Nu := Length(Note); + SetLength(Note, Nu + 1); + Note[Nu].Start := Round(ATrack[T].Note[N].Start / Ticks); + Note[Nu].Len := Round(ATrack[T].Note[N].Len / Ticks); + Note[Nu].Tone := ATrack[T].Note[N].Data1 - 12*5; + Note[Nu].Lyric := '-'; + end; + end; + end; + end; + + // extract lyrics + for T := 0 to High(ATrack) do begin +// if ATrack[T].Hear then begin + if ((ATrack[T].Status div 2) and 1) = 1 then begin + for N := 0 to High(ATrack[T].Note) do begin + if (ATrack[T].Note[N].EventType = 15) then begin +// Log.LogStatus('<' + Track[T].Note[N].Str + '>', 'MIDI'); + AddLyric(Round(ATrack[T].Note[N].Start / Ticks), ATrack[T].Note[N].Str); + end; + end; + end; + end; + + // sort notes + for N := 0 to High(Note) do + for Nu := 0 to High(Note)-1 do + if Note[Nu].Start > Note[Nu+1].Start then begin + NoteTemp := Note[Nu]; + Note[Nu] := Note[Nu+1]; + Note[Nu+1] := NoteTemp; + end; + + // move to 0 at beginning + Move := Note[0].Start; + for N := 0 to High(Note) do + Note[N].Start := Note[N].Start - Move; + + // copy notes + SetLength(Lines.Line, 1); + Lines.Number := 1; + Lines.High := 0; + + C := 0; + N := 0; + Lines.Line[C].HighNote := -1; + + for Nu := 0 to High(Note) do begin + if Note[Nu].NewSentence then begin // nowa linijka + SetLength(Lines.Line, Length(Lines.Line)+1); + Lines.Number := Lines.Number + 1; + Lines.High := Lines.High + 1; + C := C + 1; + N := 0; + SetLength(Lines.Line[C].Note, 0); + Lines.Line[C].HighNote := -1; + + //Calculate Start of the Last Sentence + if (C > 0) and (Nu > 0) then + begin + Max := Note[Nu].Start; + Min := Note[Nu-1].Start + Note[Nu-1].Len; + + case (Max - Min) of + 0: Lines.Line[C].Start := Max; + 1: Lines.Line[C].Start := Max; + 2: Lines.Line[C].Start := Max - 1; + 3: Lines.Line[C].Start := Max - 2; + else + if ((Max - Min) > 4) then + Lines.Line[C].Start := Min + 2 + else + Lines.Line[C].Start := Max; + + end; // case + + end; + end; + + // tworzy miejsce na nowa nute + SetLength(Lines.Line[C].Note, Length(Lines.Line[C].Note)+1); + + // dopisuje + Lines.Line[C].Note[N].Start := Note[Nu].Start; + Lines.Line[C].Note[N].Length := Note[Nu].Len; + Lines.Line[C].Note[N].Tone := Note[Nu].Tone; + Lines.Line[C].Note[N].Text := Note[Nu].Lyric; + //All Notes are Freestyle when Converted Fix: + Lines.Line[C].Note[N].NoteType := ntNormal; + Inc(N); + end; +end; + +function TScreenEditConvert.SelectedNumber: integer; +var + T: integer; // track +begin + Result := 0; + for T := 0 to High(ATrack) do +// if ATrack[T].Hear then Inc(Result); + if ((ATrack[T].Status div 1) and 1) = 1 then Inc(Result); +end; + +{$IFDEF UseMIDIPort} +procedure TScreenEditConvert.MidiFile1MidiEvent(event: PMidiEvent); +begin +// Log.LogStatus(IntToStr(event.event), 'MIDI'); + MidiOut.PutShort(event.event, event.data1, event.data2); +end; +{$ENDIF} + +constructor TScreenEditConvert.Create; +var + P: integer; +begin + inherited Create; + AddButton(40, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(15, 5, 0, 0, 0, 'Open'); +// Button[High(Button)].Text[0].Size := 11; + + AddButton(160, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(25, 5, 0, 0, 0, 'Play'); + + AddButton(280, 20, 200, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(25, 5, 0, 0, 0, 'Play Selected'); + + AddButton(500, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(20, 5, 0, 0, 0, 'Save'); + + +{ MidiOut := TMidiOutput.Create(nil); +// MidiOut.Close; +// MidiOut.DeviceID := 0; + if Ini.Debug = 1 then + MidiOut.ProductName := 'Microsoft GS Wavetable SW Synth'; // for my kxproject without midi table + Log.LogStatus(MidiOut.ProductName, 'MIDI'); + MidiOut.Open; +// MidiOut.SetVolume(100, 100); // temporary} + + ConversionFileName := GamePath + 'file.mid'; + {$IFDEF UseMIDIPort} + MidiFile := TMidiFile.Create(nil); + {$ENDIF} + + for P := 0 to 100 do begin + ColR[P] := Random(10)/10; + ColG[P] := Random(10)/10; + ColB[P] := Random(10)/10; + end; + +end; + +procedure TScreenEditConvert.onShow; +var + T: integer; // track + N: integer; // note + C: integer; // channel + CN: integer; // channel note +begin + inherited; + +{$IFDEF UseMIDIPort} + MidiOut := TMidiOutput.Create(nil); + if Ini.Debug = 1 then + MidiOut.ProductName := 'Microsoft GS Wavetable SW Synth'; // for my kxproject without midi table + Log.LogStatus(MidiOut.ProductName, 'MIDI'); + MidiOut.Open; + + + if FileExists(ConversionFileName) then + begin + MidiFile.Filename := ConversionFileName; + MidiFile.ReadFile; + + + Len := 0; + Sel := 0; + BPM := MidiFile.Bpm; + Ticks := MidiFile.TicksPerQuarter / 4; + +{ for T := 0 to MidiFile.NumberOfTracks-1 do begin + SetLength(Track, Length(Track)+1); + MidiTrack := MidiFile.GetTrack(T); + MidiTrack.OnMidiEvent := MidiFile1MidiEvent; + Track[T].Name := MidiTrack.getName; + + for N := 0 to MidiTrack.getEventCount-1 do begin + SetLength(Track[T].Note, Length(Track[T].Note)+1); + MidiEvent := MidiTrack.GetEvent(N); + Track[T].Note[N].Start := MidiEvent.time; + Track[T].Note[N].Len := MidiEvent.len; + Track[T].Note[N].Event := MidiEvent.event; + Track[T].Note[N].EventType := MidiEvent.event div 16; + Track[T].Note[N].Channel := MidiEvent.event and 15; + Track[T].Note[N].Data1 := MidiEvent.data1; + Track[T].Note[N].Data2 := MidiEvent.data2; + Track[T].Note[N].Str := MidiEvent.str; + + if Track[T].Note[N].Start + Track[T].Note[N].Len > Len then + Len := Track[T].Note[N].Start + Track[T].Note[N].Len; + end; + end;} + + + SetLength(Channel, 16); + for T := 0 to 15 do + begin + Channel[T].Name := IntToStr(T+1); + SetLength(Channel[T].Note, 0); + Channel[T].Status := 0; + end; + + for T := 0 to MidiFile.NumberOfTracks-1 do begin + MidiTrack := MidiFile.GetTrack(T); + MidiTrack.OnMidiEvent := MidiFile1MidiEvent; + + for N := 0 to MidiTrack.getEventCount-1 do begin + MidiEvent := MidiTrack.GetEvent(N); + C := MidiEvent.event and 15; + + CN := Length(Channel[C].Note); + SetLength(Channel[C].Note, CN+1); + + Channel[C].Note[CN].Start := MidiEvent.time; + Channel[C].Note[CN].Len := MidiEvent.len; + Channel[C].Note[CN].Event := MidiEvent.event; + Channel[C].Note[CN].EventType := MidiEvent.event div 16; + Channel[C].Note[CN].Channel := MidiEvent.event and 15; + Channel[C].Note[CN].Data1 := MidiEvent.data1; + Channel[C].Note[CN].Data2 := MidiEvent.data2; + Channel[C].Note[CN].Str := MidiEvent.str; + + if Channel[C].Note[CN].Start + Channel[C].Note[CN].Len > Len then + Len := Channel[C].Note[CN].Start + Channel[C].Note[CN].Len; + end; + end; + ATrack := Channel; + + end; + + Interaction := 0; +{$ENDIF} +end; + +function TScreenEditConvert.Draw: boolean; +var + Pet: integer; + Pet2: integer; + Bottom: real; + X: real; + Y: real; + H: real; + YSkip: real; +begin + // draw static menu + inherited Draw; + + Y := 100; + + H := Length(ATrack)*40; + if H > 480 then H := 480; + Bottom := Y + H; + + YSkip := H / Length(ATrack); + + // select + DrawQuad(10, Y+Sel*YSkip, 780, YSkip, 0.8, 0.8, 0.8); + + // selected - now me use Status System + for Pet := 0 to High(ATrack) do + if ATrack[Pet].Hear then + DrawQuad(10, Y+Pet*YSkip, 50, YSkip, 0.8, 0.3, 0.3); + glColor3f(0, 0, 0); + for Pet := 0 to High(ATrack) do begin + if ((ATrack[Pet].Status div 1) and 1) = 1 then begin + SetFontPos(25, Y + Pet*YSkip + 10); + SetFontSize(5); + glPrint('N'); + end; + if ((ATrack[Pet].Status div 2) and 1) = 1 then begin + SetFontPos(40, Y + Pet*YSkip + 10); + SetFontSize(5); + glPrint('L'); + end; + end; + + DrawLine(10, Y, 10, Bottom, 0, 0, 0); + DrawLine(60, Y, 60, Bottom, 0, 0, 0); + DrawLine(790, Y, 790, Bottom, 0, 0, 0); + + for Pet := 0 to Length(ATrack) do + DrawLine(10, Y+Pet*YSkip, 790, Y+Pet*YSkip, 0, 0, 0); + + for Pet := 0 to High(ATrack) do begin + SetFontPos(11, Y + 10 + Pet*YSkip); + SetFontSize(5); + glPrint(pchar(ATrack[Pet].Name)); + end; + + for Pet := 0 to High(ATrack) do + for Pet2 := 0 to High(ATrack[Pet].Note) do begin + if ATrack[Pet].Note[Pet2].EventType = 9 then + DrawQuad(60 + ATrack[Pet].Note[Pet2].Start/Len * 725, Y + (Pet+1)*YSkip - ATrack[Pet].Note[Pet2].Data1*35/127, 3, 3, ColR[Pet], ColG[Pet], ColB[Pet]); + if ATrack[Pet].Note[Pet2].EventType = 15 then + DrawLine(60 + ATrack[Pet].Note[Pet2].Start/Len * 725, Y + 0.75 * YSkip + Pet*YSkip, 60 + ATrack[Pet].Note[Pet2].Start/Len * 725, Y + YSkip + Pet*YSkip, ColR[Pet], ColG[Pet], ColB[Pet]); + end; + + // playing line + {$IFDEF UseMIDIPort} + X := 60 + MidiFile.GetCurrentTime/MidiFile.GetTrackLength*730; + {$ENDIF} + DrawLine(X, Y, X, Bottom, 0.3, 0.3, 0.3); + + Result := true; +end; + +procedure TScreenEditConvert.onHide; +begin +{$IFDEF UseMIDIPort} + MidiOut.Close; + MidiOut.Free; +{$ENDIF} +end; + +end. diff --git a/src/screens/UScreenEditHeader.pas b/src/screens/UScreenEditHeader.pas new file mode 100644 index 00000000..28bf7682 --- /dev/null +++ b/src/screens/UScreenEditHeader.pas @@ -0,0 +1,380 @@ +unit UScreenEditHeader; + +interface + +{$I switches.inc} + +uses UMenu, + SDL, + USongs, + USong, + UThemes; + +type + TScreenEditHeader = class(TMenu) + public + CurrentSong: TSong; + TextTitle: integer; + TextArtist: integer; + TextMp3: integer; + TextBackground: integer; + TextVideo: integer; + TextVideoGAP: integer; + TextRelative: integer; + TextResolution: integer; + TextNotesGAP: integer; + TextStart: integer; + TextGAP: integer; + TextBPM: integer; + StaticTitle: integer; + StaticArtist: integer; + StaticMp3: integer; + StaticBackground: integer; + StaticVideo: integer; + StaticVideoGAP: integer; + StaticRelative: integer; + StaticResolution: integer; + StaticNotesGAP: integer; + StaticStart: integer; + StaticGAP: integer; + StaticBPM: integer; + Sel: array[0..11] of boolean; + procedure SetRoundButtons; + + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; +{ function Draw: boolean; override; + procedure Finish;} + end; + +implementation + +uses UGraphic, UMusic, SysUtils, UFiles, USkins, UTexture; + +function TScreenEditHeader.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + T: integer; +begin + Result := true; + If (PressedDown) Then begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE : + begin +// Music.PlayBack; +// FadeTo(@MainScreen); + Result := false; + end; + + SDLK_RETURN: + begin + if Interaction = 1 then begin +// Save; + end; + end; + + SDLK_RIGHT: + begin + case Interaction of + 0..0: InteractNext; + 1: Interaction := 0; + end; + end; + + SDLK_LEFT: + begin + case Interaction of + 0: Interaction := 1; + 1..1: InteractPrev; + end; + end; + + SDLK_DOWN: + begin + case Interaction of + 0..1: Interaction := 2; + 2..12: InteractNext; + 13: Interaction := 0; + end; + end; + + SDLK_UP: + begin + case Interaction of + 0..1: Interaction := 13; + 2: Interaction := 0; + 3..13: InteractPrev; + end; + end; + + SDLK_BACKSPACE: + begin + T := Interaction - 2 + TextTitle; + if (Interaction >= 2) and (Interaction <= 13) and (Length(Text[T].Text) >= 1) then begin + Text[T].DeleteLastL; + SetRoundButtons; + end; + end; + + end; + case CharCode of + #32..#255: + begin + if (Interaction >= 2) and (Interaction <= 13) then begin + Text[Interaction - 2 + TextTitle].Text := + Text[Interaction - 2 + TextTitle].Text + CharCode; + SetRoundButtons; + end; + end; + end; + end; +end; + +constructor TScreenEditHeader.Create; +begin + inherited Create; + + AddButton(40, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(15, 5, 'Open'); + + AddButton(160, 20, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(20, 5, 'Save'); + + AddBox(80, 60, 640, 550); + + AddText(160, 110 + 0*30, 0, 10, 0, 0, 0, 'Title:'); + AddText(160, 110 + 1*30, 0, 10, 0, 0, 0, 'Artist:'); + AddText(160, 110 + 2*30, 0, 10, 0, 0, 0, 'MP3:'); + + AddText(160, 110 + 4*30, 0, 10, 0, 0, 0, 'Background:'); + AddText(160, 110 + 5*30, 0, 10, 0, 0, 0, 'Video:'); + AddText(160, 110 + 6*30, 0, 10, 0, 0, 0, 'VideoGAP:'); + + AddText(160, 110 + 8*30, 0, 10, 0, 0, 0, 'Relative:'); + AddText(160, 110 + 9*30, 0, 10, 0, 0, 0, 'Resolution:'); + AddText(160, 110 + 10*30, 0, 10, 0, 0, 0, 'NotesGAP:'); + + AddText(160, 110 + 12*30, 0, 10, 0, 0, 0, 'Start:'); + AddText(160, 110 + 13*30, 0, 10, 0, 0, 0, 'GAP:'); + AddText(160, 110 + 14*30, 0, 10, 0, 0, 0, 'BPM:'); + + TextTitle := AddText(340, 110 + 0*30, 0, 10, 0, 0, 0, ''); + TextArtist := AddText(340, 110 + 1*30, 0, 10, 0, 0, 0, ''); + TextMp3 := AddText(340, 110 + 2*30, 0, 10, 0, 0, 0, ''); + + TextBackground := AddText(340, 110 + 4*30, 0, 10, 0, 0, 0, ''); + TextVideo := AddText(340, 110 + 5*30, 0, 10, 0, 0, 0, ''); + TextVideoGAP := AddText(340, 110 + 6*30, 0, 10, 0, 0, 0, ''); + + TextRelative := AddText(340, 110 + 8*30, 0, 10, 0, 0, 0, ''); + TextResolution := AddText(340, 110 + 9*30, 0, 10, 0, 0, 0, ''); + TextNotesGAP := AddText(340, 110 + 10*30, 0, 10, 0, 0, 0, ''); + + TextStart := AddText(340, 110 + 12*30, 0, 10, 0, 0, 0, ''); + TextGAP := AddText(340, 110 + 13*30, 0, 10, 0, 0, 0, ''); + TextBPM := AddText(340, 110 + 14*30, 0, 10, 0, 0, 0, ''); + + StaticTitle := AddStatic(130, 115 + 0*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticArtist := AddStatic(130, 115 + 1*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticMp3 := AddStatic(130, 115 + 2*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticBackground := AddStatic(130, 115 + 4*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticVideo := AddStatic(130, 115 + 5*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticVideoGAP := AddStatic(130, 115 + 6*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticRelative := AddStatic(130, 115 + 8*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticResolution := AddStatic(130, 115 + 9*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticNotesGAP := AddStatic(130, 115 + 10*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticStart := AddStatic(130, 115 + 12*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticGAP := AddStatic(130, 115 + 13*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + StaticBPM := AddStatic(130, 115 + 14*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF); + + AddInteraction(iText, TextTitle); + AddInteraction(iText, TextArtist); + AddInteraction(iText, TextMp3); + AddInteraction(iText, TextBackground); + AddInteraction(iText, TextVideo); + AddInteraction(iText, TextVideoGAP); + AddInteraction(iText, TextRelative); + AddInteraction(iText, TextResolution); + AddInteraction(iText, TextNotesGAP); + AddInteraction(iText, TextStart); + AddInteraction(iText, TextGAP); + AddInteraction(iText, TextBPM); +end; + +procedure TScreenEditHeader.onShow; +begin + inherited; + +{ if FileExists(FileName) then begin // load file + CurrentSong.FileName := FileName; + SkanujPlik(CurrentSong); + + SetLength(TrueBoolStrs, 1); + TrueBoolStrs[0] := 'yes'; + SetLength(FalseBoolStrs, 1); + FalseBoolStrs[0] := 'no'; + + Text[TextTitle].Text := CurrentSong.Title; + Text[TextArtist].Text := CurrentSong.Artist; + Text[TextMP3].Text := CurrentSong.Mp3; + Text[TextBackground].Text := CurrentSong.Background; + Text[TextVideo].Text := CurrentSong.Video; + Text[TextVideoGAP].Text := FloatToStr(CurrentSong.VideoGAP); + Text[TextRelative].Text := BoolToStr(CurrentSong.Relative, true); + Text[TextResolution].Text := IntToStr(CurrentSong.Resolution); + Text[TextNotesGAP].Text := IntToStr(CurrentSong.NotesGAP); + Text[TextStart].Text := FloatToStr(CurrentSong.Start); + Text[TextGAP].Text := FloatToStr(CurrentSong.GAP); + Text[TextBPM].Text := FloatToStr(CurrentSong.BPM[0].BPM); + SetRoundButtons; + end;} + + Interaction := 0; +end; + +(*function TScreenEdit.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + Pet: integer; + AktBeat: integer; +begin +{ glClearColor(1,1,1,1); + + // control music + if PlaySentence then begin + // stop the music + if (Music.Position > PlayStopTime) then begin + Music.Stop; + PlaySentence := false; + end; + + // click + if (Click) and (PlaySentence) then begin + AktBeat := Floor(CurrentSong.BPM[0].BPM * (Music.Position - CurrentSong.GAP / 1000) / 60); + Text[TextDebug].Text := IntToStr(AktBeat); + if AktBeat <> LastClick then begin + for Pet := 0 to Czesci[0].Czesc[Czesci[0].Akt].HighNut do + if (Czesci[0].Czesc[Czesci[0].Akt].Nuta[Pet].Start = AktBeat) then begin + Music.PlayClick; + LastClick := AktBeat; + end; + end; + end; // click + end; // if PlaySentence + + Text[TextSentence].Text := IntToStr(Czesci[0].Akt + 1) + ' / ' + IntToStr(Czesci[0].Ilosc); + Text[TextNote].Text := IntToStr(AktNuta + 1) + ' / ' + IntToStr(Czesci[0].Czesc[Czesci[0].Akt].LengthNote); + + // Song info + Text[TextBPM].Text := FloatToStr(CurrentSong.BPM[0].BPM / 4); + Text[TextGAP].Text := FloatToStr(CurrentSong.GAP); + + // Note info + Text[TextNStart].Text := IntToStr(Czesci[0].Czesc[Czesci[0].Akt].Nuta[AktNuta].Start); + Text[TextNDlugosc].Text := IntToStr(Czesci[0].Czesc[Czesci[0].Akt].Nuta[AktNuta].Dlugosc); + Text[TextNTon].Text := IntToStr(Czesci[0].Czesc[Czesci[0].Akt].Nuta[AktNuta].Ton); + Text[TextNText].Text := Czesci[0].Czesc[Czesci[0].Akt].Nuta[AktNuta].Tekst; + + // draw static menu + inherited Draw; + + // draw notes + SingDrawNoteLines(20, 300, 780, 15); + SingDrawBeatDelimeters(40, 300, 760, 0); + SingDrawCzesc(40, 405, 760, 0); + + // draw text + Lyric.Draw;} + +end;*) + +procedure TScreenEditHeader.SetRoundButtons; +begin + if Length(Text[TextTitle].Text) > 0 then Static[StaticTitle].Visible := true + else Static[StaticTitle].Visible := false; + + if Length(Text[TextArtist].Text) > 0 then Static[StaticArtist].Visible := true + else Static[StaticArtist].Visible := false; + + if Length(Text[TextMp3].Text) > 0 then Static[StaticMp3].Visible := true + else Static[StaticMp3].Visible := false; + + if Length(Text[TextBackground].Text) > 0 then Static[StaticBackground].Visible := true + else Static[StaticBackground].Visible := false; + + if Length(Text[TextVideo].Text) > 0 then Static[StaticVideo].Visible := true + else Static[StaticVideo].Visible := false; + + try + StrToFloat(Text[TextVideoGAP].Text); + if StrToFloat(Text[TextVideoGAP].Text)<> 0 then Static[StaticVideoGAP].Visible := true + else Static[StaticVideoGAP].Visible := false; + except + Static[StaticVideoGAP].Visible := false; + end; + + if LowerCase(Text[TextRelative].Text) = 'yes' then Static[StaticRelative].Visible := true + else Static[StaticRelative].Visible := false; + + try + StrToInt(Text[TextResolution].Text); + if (StrToInt(Text[TextResolution].Text) <> 0) and (StrToInt(Text[TextResolution].Text) >= 1) + then Static[StaticResolution].Visible := true + else Static[StaticResolution].Visible := false; + except + Static[StaticResolution].Visible := false; + end; + + try + StrToInt(Text[TextNotesGAP].Text); + Static[StaticNotesGAP].Visible := true; + except + Static[StaticNotesGAP].Visible := false; + end; + + // start + try + StrToFloat(Text[TextStart].Text); + if (StrToFloat(Text[TextStart].Text) > 0) then Static[StaticStart].Visible := true + else Static[StaticStart].Visible := false; + except + Static[StaticStart].Visible := false; + end; + + // GAP + try + StrToFloat(Text[TextGAP].Text); + Static[StaticGAP].Visible := true; + except + Static[StaticGAP].Visible := false; + end; + + // BPM + try + StrToFloat(Text[TextBPM].Text); + if (StrToFloat(Text[TextBPM].Text) > 0) then Static[StaticBPM].Visible := true + else Static[StaticBPM].Visible := false; + except + Static[StaticBPM].Visible := false; + end; + +end; + +(*procedure TScreenEdit.Finish; +begin +// +end;*) + +end. diff --git a/src/screens/UScreenEditSub.pas b/src/screens/UScreenEditSub.pas new file mode 100644 index 00000000..2d98f6bc --- /dev/null +++ b/src/screens/UScreenEditSub.pas @@ -0,0 +1,1368 @@ +unit UScreenEditSub; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} +{$I switches.inc} + +uses + UMenu, + UMusic, + SDL, + SysUtils, + UFiles, + UTime, + USongs, + USong, + UIni, + ULog, + UTexture, + UMenuText, + UEditorLyrics, + Math, + gl, + {$IFDEF UseMIDIPort} + MidiOut, + {$ENDIF} + UThemes; + +type + TScreenEditSub = class(TMenu) + private + //Variable is True if no Song is loaded + Error: Boolean; + + TextNote: integer; + TextSentence: integer; + TextTitle: integer; + TextArtist: integer; + TextMp3: integer; + TextBPM: integer; + TextGAP: integer; + TextDebug: integer; + TextNStart: integer; + TextNLength: integer; + TextNTon: integer; + TextNText: integer; + CurrentNote: integer; + PlaySentence: boolean; + PlaySentenceMidi: boolean; + PlayStopTime: real; + LastClick: integer; + Click: boolean; + CopySrc: integer; + + {$IFDEF UseMIDIPort} + MidiOut: TMidiOutput; + {$endif} + + MidiStart: real; + MidiStop: real; + MidiTime: real; + MidiPos: real; + MidiLastNote: integer; + + TextEditMode: boolean; + + Lyric: TEditorLyrics; + + procedure NewBeat; + procedure DivideBPM; + procedure MultiplyBPM; + procedure LyricsCapitalize; + procedure LyricsCorrectSpaces; + procedure FixTimings; + procedure DivideSentence; + procedure JoinSentence; + procedure DivideNote; + procedure DeleteNote; + procedure TransposeNote(Transpose: integer); + procedure ChangeWholeTone(Tone: integer); + procedure MoveAllToEnd(Move: integer); + procedure MoveTextToRight; + procedure MarkSrc; + procedure PasteText; + procedure CopySentence(Src, Dst: integer); + procedure CopySentences(Src, Dst, Num: integer); + //Note Name Mod + function GetNoteName(Note: Integer): String; + public + Tex_Background: TTexture; + FadeOut: boolean; + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function ParseInputEditText(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; + function Draw: boolean; override; + procedure onHide; override; + end; + +implementation + +uses + UGraphic, + UDraw, + UMain, + USkins, + ULanguage; + +// Method for input parsing. If False is returned, GetNextWindow +// should be checked to know the next window to load; +function TScreenEditSub.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + SDL_ModState: Word; + R: real; +begin + Result := true; + + if TextEditMode then begin + Result := ParseInputEditText(PressedKey, CharCode, PressedDown); + end else begin + + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS}); + + If (PressedDown) then begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + 'S': + begin + // Save Song + if SDL_ModState = KMOD_LSHIFT then + SaveSong(CurrentSong, Lines[0], CurrentSong.Path + CurrentSong.FileName, true) + else + SaveSong(CurrentSong, Lines[0], CurrentSong.Path + CurrentSong.FileName, false); + + {if SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL + KMOD_LALT then + // Save Song + SaveSongDebug(CurrentSong, Lines[0], 'C:\song.asm', false);} + + Exit; + end; + 'D': + begin + // Divide lengths by 2 + DivideBPM; + Exit; + end; + 'M': + begin + // Multiply lengths by 2 + MultiplyBPM; + Exit; + end; + 'C': + begin + // Capitalize letter at the beginning of line + if SDL_ModState = 0 then + LyricsCapitalize; + + // Correct spaces + if SDL_ModState = KMOD_LSHIFT then + LyricsCorrectSpaces; + + // Copy sentence + if SDL_ModState = KMOD_LCTRL then + MarkSrc; + + Exit; + end; + 'V': + begin + // Paste text + if SDL_ModState = KMOD_LCTRL then begin + if Lines[0].Line[Lines[0].Current].HighNote >= Lines[0].Line[CopySrc].HighNote then + PasteText + else + Log.LogStatus('PasteText: invalid range', 'TScreenEditSub.ParseInput'); + end; + + if SDL_ModState = KMOD_LCTRL + KMOD_LSHIFT then begin + CopySentence(CopySrc, Lines[0].Current); + end; + end; + 'T': + begin + // Fixes timings between sentences + FixTimings; + Exit; + end; + 'P': + begin + if SDL_ModState = 0 then + begin + // Play Sentence + Click := true; + AudioPlayback.Stop; + R := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[0].Start); + if R <= AudioPlayback.Length then + begin + AudioPlayback.Position := R; + PlayStopTime := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].End_); + PlaySentence := true; + AudioPlayback.Play; + LastClick := -100; + end; + end + else if SDL_ModState = KMOD_LSHIFT then + begin + PlaySentenceMidi := true; + + MidiTime := USTime.GetTime; + MidiStart := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[0].Start); + MidiStop := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].End_); + + LastClick := -100; + end + else if SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL then + begin + PlaySentenceMidi := true; + MidiTime := USTime.GetTime; + MidiStart := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[0].Start); + MidiStop := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].End_); + LastClick := -100; + + PlaySentence := true; + Click := true; + AudioPlayback.Stop; + AudioPlayback.Position := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[0].Start)+0{-0.10}; + PlayStopTime := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].End_)+0; + AudioPlayback.Play; + LastClick := -100; + end; + Exit; + end; + + // Golden Note Patch + 'G': + begin + if (Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType = ntGolden) then + Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntNormal + else + Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntGolden; + + Exit; + end; + + // Freestyle Note Patch + 'F': + begin + if (Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType = ntFreestyle) then + Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntNormal + else + Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntFreestyle; + + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + FadeTo(@ScreenSong); + end; + + SDLK_BACKQUOTE: + begin + // Increase Note Length (same as Alt + Right) + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + if CurrentNote = Lines[0].Line[Lines[0].Current].HighNote then + Inc(Lines[0].Line[Lines[0].Current].End_); + end; + + SDLK_EQUALS: + begin + // Increase BPM + if SDL_ModState = 0 then + CurrentSong.BPM[0].BPM := Round((CurrentSong.BPM[0].BPM * 5) + 1) / 5; // (1/20) + if SDL_ModState = KMOD_LSHIFT then + CurrentSong.BPM[0].BPM := CurrentSong.BPM[0].BPM + 4; // (1/1) + if SDL_ModState = KMOD_LCTRL then + CurrentSong.BPM[0].BPM := Round((CurrentSong.BPM[0].BPM * 25) + 1) / 25; // (1/100) + end; + + SDLK_MINUS: + begin + // Decrease BPM + if SDL_ModState = 0 then + CurrentSong.BPM[0].BPM := Round((CurrentSong.BPM[0].BPM * 5) - 1) / 5; + if SDL_ModState = KMOD_LSHIFT then + CurrentSong.BPM[0].BPM := CurrentSong.BPM[0].BPM - 4; + if SDL_ModState = KMOD_LCTRL then + CurrentSong.BPM[0].BPM := Round((CurrentSong.BPM[0].BPM * 25) - 1) / 25; + end; + + SDLK_4: + begin + if SDL_ModState = KMOD_LCTRL + KMOD_LSHIFT then begin + CopySentence(CopySrc, Lines[0].Current); + CopySentence(CopySrc+1, Lines[0].Current+1); + CopySentence(CopySrc+2, Lines[0].Current+2); + CopySentence(CopySrc+3, Lines[0].Current+3); + end; + + if SDL_ModState = KMOD_LCTRL + KMOD_LSHIFT + KMOD_LALT then begin + CopySentences(CopySrc, Lines[0].Current, 4); + end; + end; + SDLK_5: + begin + if SDL_ModState = KMOD_LCTRL + KMOD_LSHIFT then begin + CopySentence(CopySrc, Lines[0].Current); + CopySentence(CopySrc+1, Lines[0].Current+1); + CopySentence(CopySrc+2, Lines[0].Current+2); + CopySentence(CopySrc+3, Lines[0].Current+3); + CopySentence(CopySrc+4, Lines[0].Current+4); + end; + + if SDL_ModState = KMOD_LCTRL + KMOD_LSHIFT + KMOD_LALT then begin + CopySentences(CopySrc, Lines[0].Current, 5); + end; + end; + + SDLK_9: + begin + // Decrease GAP + if SDL_ModState = 0 then + CurrentSong.GAP := CurrentSong.GAP - 10; + if SDL_ModState = KMOD_LSHIFT then + CurrentSong.GAP := CurrentSong.GAP - 1000; + end; + SDLK_0: + begin + // Increase GAP + if SDL_ModState = 0 then + CurrentSong.GAP := CurrentSong.GAP + 10; + if SDL_ModState = KMOD_LSHIFT then + CurrentSong.GAP := CurrentSong.GAP + 1000; + end; + + SDLK_KP_PLUS: + begin + // Increase tone of all notes + if SDL_ModState = 0 then + ChangeWholeTone(1); + if SDL_ModState = KMOD_LSHIFT then + ChangeWholeTone(12); + end; + + SDLK_KP_MINUS: + begin + // Decrease tone of all notes + if SDL_ModState = 0 then + ChangeWholeTone(-1); + if SDL_ModState = KMOD_LSHIFT then + ChangeWholeTone(-12); + end; + + SDLK_SLASH: + begin + if SDL_ModState = 0 then begin + // Insert start of sentece + if CurrentNote > 0 then + DivideSentence; + end; + + if SDL_ModState = KMOD_LSHIFT then begin + // Join next sentence with current + if Lines[0].Current < Lines[0].High then + JoinSentence; + end; + + if SDL_ModState = KMOD_LCTRL then begin + // divide note + DivideNote; + end; + + end; + + SDLK_F4: + begin + // Enter Text Edit Mode + TextEditMode := true; + end; + + SDLK_SPACE: + begin + // Play Sentence + PlaySentenceMidi := false; // stop midi + PlaySentence := true; + Click := false; + AudioPlayback.Stop; + AudioPlayback.Position := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + PlayStopTime := (GetTimeFromBeat( + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start + + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length)); + AudioPlayback.Play; + LastClick := -100; + end; + + SDLK_RETURN: + begin + end; + + SDLK_LCTRL: + begin + end; + + SDLK_DELETE: + begin + if SDL_ModState = KMOD_LCTRL then begin + // moves text to right in current sentence + DeleteNote; + end; + end; + + SDLK_PERIOD: + begin + // moves text to right in current sentence + MoveTextToRight; + end; + + SDLK_RIGHT: + begin + // right + if SDL_ModState = 0 then begin + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Inc(CurrentNote); + if CurrentNote > Lines[0].Line[Lines[0].Current].HighNote then CurrentNote := 0; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + Lyric.Selected := CurrentNote; + end; + + // ctrl + right + if SDL_ModState = KMOD_LCTRL then begin + if Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length > 1 then begin + Dec(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + if CurrentNote = 0 then begin + Inc(Lines[0].Line[Lines[0].Current].Start); + end; + end; + end; + + // shift + right + if SDL_ModState = KMOD_LSHIFT then begin + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + if CurrentNote = 0 then begin + Inc(Lines[0].Line[Lines[0].Current].Start); + end; + if CurrentNote = Lines[0].Line[Lines[0].Current].HighNote then + Inc(Lines[0].Line[Lines[0].Current].End_); + end; + + // alt + right + if SDL_ModState = KMOD_LALT then begin + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + if CurrentNote = Lines[0].Line[Lines[0].Current].HighNote then + Inc(Lines[0].Line[Lines[0].Current].End_); + end; + + // alt + ctrl + shift + right = move all from cursor to right + if SDL_ModState = KMOD_LALT + KMOD_LCTRL + KMOD_LSHIFT then begin + MoveAllToEnd(1); + end; + + end; + + SDLK_LEFT: + begin + // left + if SDL_ModState = 0 then begin + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Dec(CurrentNote); + if CurrentNote = -1 then CurrentNote := Lines[0].Line[Lines[0].Current].HighNote; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + Lyric.Selected := CurrentNote; + end; + + // ctrl + left + if SDL_ModState = KMOD_LCTRL then begin + Dec(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + if CurrentNote = 0 then begin + Dec(Lines[0].Line[Lines[0].Current].Start); + end; + end; + + // shift + left + if SDL_ModState = KMOD_LSHIFT then begin + Dec(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + + // resizing sentences + if CurrentNote = 0 then begin + Dec(Lines[0].Line[Lines[0].Current].Start); + end; + + if CurrentNote = Lines[0].Line[Lines[0].Current].HighNote then + Dec(Lines[0].Line[Lines[0].Current].End_); + + end; + + // alt + left + if SDL_ModState = KMOD_LALT then begin + if Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length > 1 then begin + Dec(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + if CurrentNote = Lines[0].Line[Lines[0].Current].HighNote then + Dec(Lines[0].Line[Lines[0].Current].End_); + end; + end; + + // alt + ctrl + shift + right = move all from cursor to left + if SDL_ModState = KMOD_LALT + KMOD_LCTRL + KMOD_LSHIFT then begin + MoveAllToEnd(-1); + end; + + end; + + SDLK_DOWN: + begin + + // skip to next sentence + if SDL_ModState = 0 then begin {$IFDEF UseMIDIPort} + MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127); + PlaySentenceMidi := false; + {$endif} + + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Inc(Lines[0].Current); + CurrentNote := 0; + if Lines[0].Current > Lines[0].High then Lines[0].Current := 0; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + + Lyric.AddLine(Lines[0].Current); + Lyric.Selected := 0; + AudioPlayback.Stop; + PlaySentence := false; + end; + + // decrease tone + if SDL_ModState = KMOD_LCTRL then begin + TransposeNote(-1); + end; + + end; + + SDLK_UP: + begin + + // skip to previous sentence + if SDL_ModState = 0 then begin + {$IFDEF UseMIDIPort} + MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127); + PlaySentenceMidi := false; + {$endif} + + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Dec(Lines[0].Current); + CurrentNote := 0; + if Lines[0].Current = -1 then Lines[0].Current := Lines[0].High; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + + Lyric.AddLine(Lines[0].Current); + Lyric.Selected := 0; + AudioPlayback.Stop; + PlaySentence := false; + end; + + // increase tone + if SDL_ModState = KMOD_LCTRL then begin + TransposeNote(1); + end; + end; + + end; // case + end; + end; // if +end; + +function TScreenEditSub.ParseInputEditText(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + SDL_ModState: Word; +begin + // used when in Text Edit Mode + Result := true; + + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS}); + + If (PressedDown) Then + begin // Key Down + case PressedKey of + + SDLK_ESCAPE: + begin + FadeTo(@ScreenSong); + end; + SDLK_F4, SDLK_RETURN: + begin + // Exit Text Edit Mode + TextEditMode := false; + end; + SDLK_0..SDLK_9, SDLK_A..SDLK_Z, SDLK_SPACE, SDLK_MINUS, SDLK_EXCLAIM, SDLK_COMMA, SDLK_SLASH, SDLK_ASTERISK, SDLK_QUESTION, SDLK_QUOTE, SDLK_QUOTEDBL: + begin + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text := + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text + CharCode; + end; + SDLK_BACKSPACE: + begin + Delete(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text, + Length(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text), 1); + end; + SDLK_RIGHT: + begin + // right + if SDL_ModState = 0 then begin + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Inc(CurrentNote); + if CurrentNote > Lines[0].Line[Lines[0].Current].HighNote then CurrentNote := 0; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + Lyric.Selected := CurrentNote; + end; + end; + SDLK_LEFT: + begin + // left + if SDL_ModState = 0 then begin + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0; + Dec(CurrentNote); + if CurrentNote = -1 then CurrentNote := Lines[0].Line[Lines[0].Current].HighNote; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + Lyric.Selected := CurrentNote; + end; + end; + end; + end; +end; + +procedure TScreenEditSub.NewBeat; +begin + // click +{ for Pet := 0 to Lines[0].Line[Lines[0].Current].HighNut do + if (Lines[0].Line[Lines[0].Current].Note[Pet].Start = Czas.AktBeat) then begin + // old} +// Music.PlayClick; +end; + +procedure TScreenEditSub.DivideBPM; +var + C: integer; + N: integer; +begin + CurrentSong.BPM[0].BPM := CurrentSong.BPM[0].BPM / 2; + for C := 0 to Lines[0].High do begin + Lines[0].Line[C].Start := Lines[0].Line[C].Start div 2; + Lines[0].Line[C].End_ := Lines[0].Line[C].End_ div 2; + for N := 0 to Lines[0].Line[C].HighNote do begin + Lines[0].Line[C].Note[N].Start := Lines[0].Line[C].Note[N].Start div 2; + Lines[0].Line[C].Note[N].Length := Round(Lines[0].Line[C].Note[N].Length / 2); + end; // N + end; // C +end; + +procedure TScreenEditSub.MultiplyBPM; +var + C: integer; + N: integer; +begin + CurrentSong.BPM[0].BPM := CurrentSong.BPM[0].BPM * 2; + for C := 0 to Lines[0].High do begin + Lines[0].Line[C].Start := Lines[0].Line[C].Start * 2; + Lines[0].Line[C].End_ := Lines[0].Line[C].End_ * 2; + for N := 0 to Lines[0].Line[C].HighNote do begin + Lines[0].Line[C].Note[N].Start := Lines[0].Line[C].Note[N].Start * 2; + Lines[0].Line[C].Note[N].Length := Lines[0].Line[C].Note[N].Length * 2; + end; // N + end; // C +end; + +procedure TScreenEditSub.LyricsCapitalize; +var + C: integer; + N: integer; // temporary + S: string; +begin + // temporary +{ for C := 0 to Lines[0].High do + for N := 0 to Lines[0].Line[C].HighNut do + Lines[0].Line[C].Note[N].Text := AnsiLowerCase(Lines[0].Line[C].Note[N].Text);} + + for C := 0 to Lines[0].High do begin + S := AnsiUpperCase(Copy(Lines[0].Line[C].Note[0].Text, 1, 1)); + S := S + Copy(Lines[0].Line[C].Note[0].Text, 2, Length(Lines[0].Line[C].Note[0].Text)-1); + Lines[0].Line[C].Note[0].Text := S; + end; // C +end; + +procedure TScreenEditSub.LyricsCorrectSpaces; +var + C: integer; + N: integer; +begin + for C := 0 to Lines[0].High do begin + // correct starting spaces in the first word + while Copy(Lines[0].Line[C].Note[0].Text, 1, 1) = ' ' do + Lines[0].Line[C].Note[0].Text := Copy(Lines[0].Line[C].Note[0].Text, 2, 100); + + // move spaces on the start to the end of the previous note + for N := 1 to Lines[0].Line[C].HighNote do begin + while (Copy(Lines[0].Line[C].Note[N].Text, 1, 1) = ' ') do begin + Lines[0].Line[C].Note[N].Text := Copy(Lines[0].Line[C].Note[N].Text, 2, 100); + Lines[0].Line[C].Note[N-1].Text := Lines[0].Line[C].Note[N-1].Text + ' '; + end; + end; // N + + // correct '-' to '- ' + for N := 0 to Lines[0].Line[C].HighNote do begin + if Lines[0].Line[C].Note[N].Text = '-' then + Lines[0].Line[C].Note[N].Text := '- '; + end; // N + + // add space to the previous note when the current word is '- ' + for N := 1 to Lines[0].Line[C].HighNote do begin + if Lines[0].Line[C].Note[N].Text = '- ' then + Lines[0].Line[C].Note[N-1].Text := Lines[0].Line[C].Note[N-1].Text + ' '; + end; // N + + // correct too many spaces at the end of note + for N := 0 to Lines[0].Line[C].HighNote do begin + while Copy(Lines[0].Line[C].Note[N].Text, Length(Lines[0].Line[C].Note[N].Text)-1, 2) = ' ' do + Lines[0].Line[C].Note[N].Text := Copy(Lines[0].Line[C].Note[N].Text, 1, Length(Lines[0].Line[C].Note[N].Text)-1); + end; // N + + // and correct if there is no space at the end of sentence + N := Lines[0].Line[C].HighNote; + if Copy(Lines[0].Line[C].Note[N].Text, Length(Lines[0].Line[C].Note[N].Text), 1) <> ' ' then + Lines[0].Line[C].Note[N].Text := Lines[0].Line[C].Note[N].Text + ' '; + + end; // C +end; + +procedure TScreenEditSub.FixTimings; +var + C: integer; + S: integer; + Min: integer; + Max: integer; +begin + for C := 1 to Lines[0].High do begin + with Lines[0].Line[C-1] do begin + Min := Note[HighNote].Start + Note[HighNote].Length; + Max := Lines[0].Line[C].Note[0].Start; + case (Max - Min) of + 0: S := Max; + 1: S := Max; + 2: S := Max - 1; + 3: S := Max - 2; + else + if ((Max - Min) > 4) then + S := Min + 2 + else + S := Max; + end; // case + + Lines[0].Line[C].Start := S; + end; // with + end; // for +end; + +procedure TScreenEditSub.DivideSentence; +var + C: integer; + CStart: integer; + CNew: integer; + CLen: integer; + N: integer; + NStart: integer; + NHigh: integer; +begin + // increase sentence length by 1 + CLen := Length(Lines[0].Line); + SetLength(Lines[0].Line, CLen + 1); + Inc(Lines[0].Number); + Inc(Lines[0].High); + + // move needed sentences to one forward. newly has the copy of divided sentence + CStart := Lines[0].Current; + for C := CLen-1 downto CStart do + Lines[0].Line[C+1] := Lines[0].Line[C]; + + // clear and set new sentence + CNew := CStart + 1; + NStart := CurrentNote; + Lines[0].Line[CNew].Start := Lines[0].Line[CStart].Note[NStart].Start; + Lines[0].Line[CNew].Lyric := ''; + Lines[0].Line[CNew].LyricWidth := 0; + Lines[0].Line[CNew].End_ := 0; + Lines[0].Line[CNew].BaseNote := 0; // 0.5.0: we modify it later in this procedure + Lines[0].Line[CNew].HighNote := -1; + SetLength(Lines[0].Line[CNew].Note, 0); + + // move right notes to new sentences + NHigh := Lines[0].Line[CStart].HighNote; + for N := NStart to NHigh do begin + // increase sentence counters + with Lines[0].Line[CNew] do + begin + Inc(HighNote); + SetLength(Note, HighNote + 1); + Note[HighNote] := Note[N]; + End_ := Note[HighNote].Start + Note[HighNote].Length; + + if Note[HighNote].Tone < BaseNote then + BaseNote := Note[HighNote].Tone; + end; + end; + + // clear old notes and set sentence counters + Lines[0].Line[CStart].HighNote := NStart - 1; + Lines[0].Line[CStart].End_ := Lines[0].Line[CStart].Note[NStart-1].Start + + Lines[0].Line[CStart].Note[NStart-1].Length; + SetLength(Lines[0].Line[CStart].Note, Lines[0].Line[CStart].HighNote + 1); + + Lines[0].Current := Lines[0].Current + 1; + CurrentNote := 0; + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + Lyric.AddLine(Lines[0].Current); +end; + +procedure TScreenEditSub.JoinSentence; +var + C: integer; + N: integer; + NStart: integer; + NDst: integer; +begin + C := Lines[0].Current; + + // set new sentence + NStart := Lines[0].Line[C].HighNote + 1; + Lines[0].Line[C].HighNote := Lines[0].Line[C].HighNote + Lines[0].Line[C+1].HighNote + 1; + SetLength(Lines[0].Line[C].Note, Lines[0].Line[C].HighNote + 1); + + // move right notes to new sentences + for N := 0 to Lines[0].Line[C+1].HighNote do begin + NDst := NStart + N; + Lines[0].Line[C].Note[NDst] := Lines[0].Line[C+1].Note[N]; + end; + + // increase sentence counters + NDst := Lines[0].Line[C].HighNote; + Lines[0].Line[C].End_ := Lines[0].Line[C].Note[NDst].Start + + Lines[0].Line[C].Note[NDst].Length; + + // move needed sentences to one backward. + for C := Lines[0].Current + 1 to Lines[0].High - 1 do + Lines[0].Line[C] := Lines[0].Line[C+1]; + + // increase sentence length by 1 + SetLength(Lines[0].Line, Length(Lines[0].Line) - 1); + Dec(Lines[0].Number); + Dec(Lines[0].High); +end; + +procedure TScreenEditSub.DivideNote; +var + C: integer; + N: integer; +begin + C := Lines[0].Current; + + with Lines[0].Line[C] do + begin + Inc(HighNote); + SetLength(Note, HighNote + 1); + + // we copy all notes including selected one + for N := HighNote downto CurrentNote+1 do begin + Note[N] := Note[N-1]; + end; + + // me slightly modify new note + Note[CurrentNote].Length := 1; + Inc(Note[CurrentNote+1].Start); + Dec(Note[CurrentNote+1].Length); + Note[CurrentNote+1].Text := '- '; + Note[CurrentNote+1].Color := 0; + end; +end; + +procedure TScreenEditSub.DeleteNote; +var + C: integer; + N: integer; + NLen: integer; +begin + C := Lines[0].Current; + + //Do Not delete Last Note + if (Lines[0].High > 0) OR (Lines[0].Line[C].HighNote > 0) then + begin + + // we copy all notes from the next to the selected one + for N := CurrentNote+1 to Lines[0].Line[C].HighNote do begin + Lines[0].Line[C].Note[N-1] := Lines[0].Line[C].Note[N]; + end; + + Dec(Lines[0].Line[C].HighNote); + if (Lines[0].Line[C].HighNote >= 0) then + begin + SetLength(Lines[0].Line[C].Note, Lines[0].Line[C].HighNote + 1); + + // me slightly modify new note + if CurrentNote > Lines[0].Line[C].HighNote then + Dec(CurrentNote); + + Lines[0].Line[C].Note[CurrentNote].Color := 1; + end + //Last Note of current Sentence Deleted - > Delete Sentence + else + begin + //Move all Sentences after the current to the Left + for N := C+1 to Lines[0].High do + Lines[0].Line[N-1] := Lines[0].Line[N]; + + //Delete Last Sentence + SetLength(Lines[0].Line, Lines[0].High); + Lines[0].High := High(Lines[0].Line); + Lines[0].Number := Length(Lines[0].Line); + + CurrentNote := 0; + if (C > 0) then + Lines[0].Current := C - 1 + else + Lines[0].Current := 0; + + Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 1; + end; + end; +end; + +procedure TScreenEditSub.TransposeNote(Transpose: integer); +begin + Inc(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Tone, Transpose); +end; + +procedure TScreenEditSub.ChangeWholeTone(Tone: integer); +var + C: integer; + N: integer; +begin + for C := 0 to Lines[0].High do begin + Lines[0].Line[C].BaseNote := Lines[0].Line[C].BaseNote + Tone; + for N := 0 to Lines[0].Line[C].HighNote do + Lines[0].Line[C].Note[N].Tone := Lines[0].Line[C].Note[N].Tone + Tone; + end; +end; + +procedure TScreenEditSub.MoveAllToEnd(Move: integer); +var + C: integer; + N: integer; + NStart: integer; +begin + for C := Lines[0].Current to Lines[0].High do begin + NStart := 0; + if C = Lines[0].Current then NStart := CurrentNote; + for N := NStart to Lines[0].Line[C].HighNote do begin + Inc(Lines[0].Line[C].Note[N].Start, Move); // move note start + + if N = 0 then begin // fix beginning + Inc(Lines[0].Line[C].Start, Move); + end; + + if N = Lines[0].Line[C].HighNote then // fix ending + Inc(Lines[0].Line[C].End_, Move); + + end; // for + end; // for +end; + +procedure TScreenEditSub.MoveTextToRight; +var + C: integer; + N: integer; + NHigh: integer; +begin +{ C := Lines[0].Current; + + for N := Lines[0].Line[C].HighNut downto 1 do begin + Lines[0].Line[C].Note[N].Text := Lines[0].Line[C].Note[N-1].Text; + end; // for + + Lines[0].Line[C].Note[0].Text := '- ';} + + C := Lines[0].Current; + NHigh := Lines[0].Line[C].HighNote; + + // last word + Lines[0].Line[C].Note[NHigh].Text := Lines[0].Line[C].Note[NHigh-1].Text + Lines[0].Line[C].Note[NHigh].Text; + + // other words + for N := NHigh - 1 downto CurrentNote + 1 do begin + Lines[0].Line[C].Note[N].Text := Lines[0].Line[C].Note[N-1].Text; + end; // for + Lines[0].Line[C].Note[CurrentNote].Text := '- '; +end; + +procedure TScreenEditSub.MarkSrc; +begin + CopySrc := Lines[0].Current; +end; + +procedure TScreenEditSub.PasteText; +var + C: integer; + N: integer; +begin + C := Lines[0].Current; + + for N := 0 to Lines[0].Line[CopySrc].HighNote do + Lines[0].Line[C].Note[N].Text := Lines[0].Line[CopySrc].Note[N].Text; +end; + +procedure TScreenEditSub.CopySentence(Src, Dst: integer); +var + N: integer; + Time1: integer; + Time2: integer; + TD: integer; +begin + Time1 := Lines[0].Line[Src].Note[0].Start; + Time2 := Lines[0].Line[Dst].Note[0].Start; + TD := Time2-Time1; + + SetLength(Lines[0].Line[Dst].Note, Lines[0].Line[Src].HighNote + 1); + Lines[0].Line[Dst].HighNote := Lines[0].Line[Src].HighNote; + for N := 0 to Lines[0].Line[Src].HighNote do begin + Lines[0].Line[Dst].Note[N].Text := Lines[0].Line[Src].Note[N].Text; + Lines[0].Line[Dst].Note[N].Length := Lines[0].Line[Src].Note[N].Length; + Lines[0].Line[Dst].Note[N].Tone := Lines[0].Line[Src].Note[N].Tone; + Lines[0].Line[Dst].Note[N].Start := Lines[0].Line[Src].Note[N].Start + TD; + end; + N := Lines[0].Line[Src].HighNote; + Lines[0].Line[Dst].End_ := Lines[0].Line[Dst].Note[N].Start + Lines[0].Line[Dst].Note[N].Length; +end; + +procedure TScreenEditSub.CopySentences(Src, Dst, Num: integer); +var + C: integer; +begin + // create place for new sentences + SetLength(Lines[0].Line, Lines[0].Number + Num - 1); + + // moves sentences next to the destination + for C := Lines[0].High downto Dst + 1 do begin + Lines[0].Line[C + Num - 1] := Lines[0].Line[C]; + end; + + // prepares new sentences: sets sentence start and create first note + for C := 1 to Num-1 do begin + Lines[0].Line[Dst + C].Start := Lines[0].Line[Dst + C - 1].Note[0].Start + + (Lines[0].Line[Src + C].Note[0].Start - Lines[0].Line[Src + C - 1].Note[0].Start); + SetLength(Lines[0].Line[Dst + C].Note, 1); + Lines[0].Line[Dst + C].HighNote := 0; + Lines[0].Line[Dst + C].Note[0].Start := Lines[0].Line[Dst + C].Start; + Lines[0].Line[Dst + C].Note[0].Length := 1; + Lines[0].Line[Dst + C].End_ := Lines[0].Line[Dst + C].Start + 1; + end; + + // increase counters + Lines[0].Number := Lines[0].Number + Num - 1; + Lines[0].High := Lines[0].High + Num - 1; + + for C := 0 to Num-1 do + CopySentence(Src + C, Dst + C); +end; + + +constructor TScreenEditSub.Create; +begin + inherited Create; + SetLength(Player, 1); + + // linijka + AddStatic(20, 10, 80, 30, 0, 0, 0, Skin.GetTextureFileName('ButtonF'), TEXTURE_TYPE_COLORIZED); + AddText(40, 17, 1, 6, 1, 1, 1, 'Line'); + TextSentence := AddText(120, 14, 1, 8, 0, 0, 0, '0 / 0'); + + // Note + AddStatic(220, 10, 80, 30, 0, 0, 0, Skin.GetTextureFileName('ButtonF'), TEXTURE_TYPE_COLORIZED); + AddText(242, 17, 1, 6, 1, 1, 1, 'Note'); + TextNote := AddText(320, 14, 1, 8, 0, 0, 0, '0 / 0'); + + // file info + AddStatic(150, 50, 500, 150, 0, 0, 0, Skin.GetTextureFileName('MainBar'), TEXTURE_TYPE_COLORIZED); + AddStatic(151, 52, 498, 146, 1, 1, 1, Skin.GetTextureFileName('MainBar'), TEXTURE_TYPE_COLORIZED); + AddText(180, 65, 0, 8, 0, 0, 0, 'Title:'); + AddText(180, 90, 0, 8, 0, 0, 0, 'Artist:'); + AddText(180, 115, 0, 8, 0, 0, 0, 'Mp3:'); + AddText(180, 140, 0, 8, 0, 0, 0, 'BPM:'); + AddText(180, 165, 0, 8, 0, 0, 0, 'GAP:'); + + TextTitle := AddText(250, 65, 0, 8, 0, 0, 0, 'a'); + TextArtist := AddText(250, 90, 0, 8, 0, 0, 0, 'b'); + TextMp3 := AddText(250, 115, 0, 8, 0, 0, 0, 'c'); + TextBPM := AddText(250, 140, 0, 8, 0, 0, 0, 'd'); + TextGAP := AddText(250, 165, 0, 8, 0, 0, 0, 'e'); + +{ AddInteraction(2, TextTitle); + AddInteraction(2, TextArtist); + AddInteraction(2, TextMp3); + AddInteraction(2, TextBPM); + AddInteraction(2, TextGAP);} + + // note info + AddText(20, 190, 0, 8, 0, 0, 0, 'Start:'); + AddText(20, 215, 0, 8, 0, 0, 0, 'Duration:'); + AddText(20, 240, 0, 8, 0, 0, 0, 'Tone:'); + AddText(20, 265, 0, 8, 0, 0, 0, 'Text:'); + + TextNStart := AddText(120, 190, 0, 8, 0, 0, 0, 'a'); + TextNLength := AddText(120, 215, 0, 8, 0, 0, 0, 'b'); + TextNTon := AddText(120, 240, 0, 8, 0, 0, 0, 'c'); + TextNText := AddText(120, 265, 0, 8, 0, 0, 0, 'd'); + + // debug + TextDebug := AddText(30, 550, 0, 8, 0, 0, 0, ''); + +end; + +procedure TScreenEditSub.onShow; +begin + inherited; + + Log.LogStatus('Initializing', 'TEditScreen.onShow'); + Lyric := TEditorLyrics.Create; + + ResetSingTemp; + + try + //Check if File is XML + if copy(CurrentSong.FileName,length(CurrentSong.FileName)-3,4) = '.xml' + then Error := not CurrentSong.LoadXMLSong() + else Error := not CurrentSong.LoadSong(); + except + Error := True; + end; + + if Error then + begin + //Error Loading Song -> Go back to Song Screen and Show some Error Message + FadeTo(@ScreenSong); + ScreenPopupError.ShowPopup (Language.Translate('ERROR_CORRUPT_SONG')); + Exit; + end + else begin + {$IFDEF UseMIDIPort} + MidiOut := TMidiOutput.Create(nil); + if Ini.Debug = 1 then + MidiOut.ProductName := 'Microsoft GS Wavetable SW Synth'; // for my kxproject without midi table + MidiOut.Open; + {$ENDIF} + Text[TextTitle].Text := CurrentSong.Title; + Text[TextArtist].Text := CurrentSong.Artist; + Text[TextMp3].Text := CurrentSong.Mp3; + + Lines[0].Current := 0; + CurrentNote := 0; + Lines[0].Line[0].Note[0].Color := 1; + AudioPlayback.Open(CurrentSong.Path + CurrentSong.Mp3); + //Set Down Music Volume for Better hearability of Midi Sounds + //Music.SetVolume(0.4); + + Lyric.Clear; + Lyric.X := 400; + Lyric.Y := 500; + Lyric.Align := 1; + Lyric.Size := 14; + Lyric.ColR := 0; + Lyric.ColG := 0; + Lyric.ColB := 0; + Lyric.ColSR := Skin_FontHighlightR; + Lyric.ColSG := Skin_FontHighlightG; + Lyric.ColSB := Skin_FontHighlightB; + Lyric.AddLine(0); + Lyric.Selected := 0; + + NotesH := 7; + NotesW := 4; + + end; + +// Interaction := 0; + TextEditMode := false; +end; + +function TScreenEditSub.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + Pet: integer; + AktBeat: integer; +begin + glClearColor(1,1,1,1); + + // midi music + if PlaySentenceMidi then begin + {$IFDEF UseMIDIPort} + MidiPos := USTime.GetTime - MidiTime + MidiStart; + + + // stop the music + if (MidiPos > MidiStop) then begin + MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127); + PlaySentenceMidi := false; + end; + {$ENDIF} + + // click + AktBeat := Floor(GetMidBeat(MidiPos - CurrentSong.GAP / 1000)); + Text[TextDebug].Text := IntToStr(AktBeat); + + if AktBeat <> LastClick then begin + for Pet := 0 to Lines[0].Line[Lines[0].Current].HighNote do + if (Lines[0].Line[Lines[0].Current].Note[Pet].Start = AktBeat) then + begin + + + LastClick := AktBeat; + {$IFDEF UseMIDIPort} + if Pet > 0 then + MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[Pet-1].Tone + 60, 127); + MidiOut.PutShort($91, Lines[0].Line[Lines[0].Current].Note[Pet].Tone + 60, 127); + MidiLastNote := Pet; + {$ENDIF} + + end; + end; + end; // if PlaySentenceMidi + + // mp3 music + if PlaySentence then begin + // stop the music + if (AudioPlayback.Position > PlayStopTime) then + begin + AudioPlayback.Stop; + PlaySentence := false; + end; + + // click + if (Click) and (PlaySentence) then begin +// AktBeat := Floor(CurrentSong.BPM[0].BPM * (Music.Position - CurrentSong.GAP / 1000) / 60); + AktBeat := Floor(GetMidBeat(AudioPlayback.Position - CurrentSong.GAP / 1000)); + Text[TextDebug].Text := IntToStr(AktBeat); + if AktBeat <> LastClick then begin + for Pet := 0 to Lines[0].Line[Lines[0].Current].HighNote do + if (Lines[0].Line[Lines[0].Current].Note[Pet].Start = AktBeat) then + begin + AudioPlayback.PlaySound( SoundLib.Click ); + LastClick := AktBeat; + end; + end; + end; // click + end; // if PlaySentence + + + Text[TextSentence].Text := IntToStr(Lines[0].Current + 1) + ' / ' + IntToStr(Lines[0].Number); + Text[TextNote].Text := IntToStr(CurrentNote + 1) + ' / ' + IntToStr(Lines[0].Line[Lines[0].Current].HighNote + 1); + + // Song info + Text[TextBPM].Text := FloatToStr(CurrentSong.BPM[0].BPM / 4); + Text[TextGAP].Text := FloatToStr(CurrentSong.GAP); + + //Error reading Variables when no Song is loaded + if not Error then + begin + // Note info + Text[TextNStart].Text := IntToStr(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start); + Text[TextNLength].Text := IntToStr(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length); + Text[TextNTon].Text := IntToStr(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Tone) + ' ( ' + GetNoteName(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Tone) + ' )'; + Text[TextNText].Text := Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text; + end; + + // Text Edit Mode + if TextEditMode then + Text[TextNText].Text := Text[TextNText].Text + '|'; + + // draw static menu + inherited Draw; + + // draw notes + SingDrawNoteLines(20, 300, 780, 15); + //Error Drawing when no Song is loaded + if not Error then + begin + SingDrawBeatDelimeters(40, 300, 760, 0); + EditDrawLine(40, 405, 760, 0, 15); + end; + + // draw text + Lyric.Draw; + + Result := true; +end; + +procedure TScreenEditSub.onHide; +begin + {$IFDEF UseMIDIPort} + MidiOut.Close; + MidiOut.Free; + {$ENDIF} + Lyric.Free; + //Music.SetVolume(1.0); +end; + +function TScreenEditSub.GetNoteName(Note: Integer): String; +var N1, N2: Integer; +begin + if (Note > 0) then + begin + N1 := Note mod 12; + N2 := Note div 12; + end + else + begin + N1 := (Note + (-Trunc(Note/12)+1)*12) mod 12; + N2 := -1; + end; + + + + case N1 of + 0: Result := 'c'; + 1: Result := 'c#'; + 2: Result := 'd'; + 3: Result := 'd#'; + 4: Result := 'e'; + 5: Result := 'f'; + 6: Result := 'f#'; + 7: Result := 'g'; + 8: Result := 'g#'; + 9: Result := 'a'; + 10: Result := 'b'; + 11: Result := 'h'; + end; + + case N2 of + 0: Result := UpperCase(Result); //Normal Uppercase Note, 1: Normal lowercase Note + 2: Result := Result + ''''; //One Striped + 3: Result := Result + ''''''; //Two Striped + 4: Result := Result + ''''''''; //etc. + 5: Result := Result + ''''''''''; + 6: Result := Result + ''''''''''''; + 7: Result := Result + ''''''''''''''; + end; +end; + +end. diff --git a/src/screens/UScreenLevel.pas b/src/screens/UScreenLevel.pas new file mode 100644 index 00000000..1ea79e7f --- /dev/null +++ b/src/screens/UScreenLevel.pas @@ -0,0 +1,103 @@ +unit UScreenLevel; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenLevel = class(TMenu) + public + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, + UMain, + UIni, + USong, + UTexture; + +function TScreenLevel.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenName); + end; + + SDLK_RETURN: + begin + Ini.Difficulty := Interaction; + Ini.SaveLevel; + AudioPlayback.PlaySound(SoundLib.Start); + //Set Standard Mode + ScreenSong.Mode := smNormal; + FadeTo(@ScreenSong); + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end; +end; + +constructor TScreenLevel.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + LoadFromTheme(Theme.Level); + + AddButton(Theme.Level.ButtonEasy); + AddButton(Theme.Level.ButtonMedium); + AddButton(Theme.Level.ButtonHard); + + Interaction := 0; +end; + +procedure TScreenLevel.onShow; +begin + inherited; + + Interaction := Ini.Difficulty; + +// LCD.WriteText(1, ' Choose mode: '); +// UpdateLCD; +end; + +procedure TScreenLevel.SetAnimationProgress(Progress: real); +begin + Button[0].Texture.ScaleW := Progress; + Button[1].Texture.ScaleW := Progress; + Button[2].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenLoading.pas b/src/screens/UScreenLoading.pas new file mode 100644 index 00000000..ee3c6f7f --- /dev/null +++ b/src/screens/UScreenLoading.pas @@ -0,0 +1,57 @@ +unit UScreenLoading; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, + SDL, + SysUtils, + UThemes, + gl; + +type + TScreenLoading = class(TMenu) + public + Fadeout: boolean; + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function GetBGTexNum: GLUInt; + end; + +implementation + +uses UGraphic, + UTime; + +function TScreenLoading.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; +end; + +constructor TScreenLoading.Create; +begin + inherited Create; + + LoadFromTheme(Theme.Loading); + + Fadeout := false; +end; + +procedure TScreenLoading.onShow; +begin + inherited; +end; + +function TScreenLoading.GetBGTexNum: GLUInt; +begin + Result := Self.BackImg.TexNum; +end; + +end. diff --git a/src/screens/UScreenMain.pas b/src/screens/UScreenMain.pas new file mode 100644 index 00000000..4dbdaaa1 --- /dev/null +++ b/src/screens/UScreenMain.pas @@ -0,0 +1,256 @@ +unit UScreenMain; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, + SDL, + UDisplay, + UMusic, + UFiles, + SysUtils, + UThemes; + +type + TScreenMain = class(TMenu) + public + TextDescription: integer; + TextDescriptionLong: integer; + + constructor Create; override; + function ParseInput(PressedKey: cardinal; CharCode: widechar; + PressedDown: boolean): boolean; override; + procedure onShow; override; + procedure InteractNext; override; + procedure InteractPrev; override; + procedure InteractInc; override; + procedure InteractDec; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses + UGraphic, + UMain, + UIni, + UTexture, + USongs, + Textgl, + ULanguage, + UParty, + UDLLManager, + UScreenCredits, + USkins; + +function TScreenMain.ParseInput(PressedKey: cardinal; CharCode: widechar; + PressedDown: boolean): boolean; +var + SDL_ModState: word; +begin + Result := True; + + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT); + + if (PressedDown) then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := False; + Exit; + end; + 'C': + begin + if (SDL_ModState = KMOD_LALT) then + begin + FadeTo(@ScreenCredits, SoundLib.Start); + Exit; + end; + end; + 'M': + begin + if (Ini.Players >= 1) and (Length(DLLMan.Plugins) >= 1) then + begin + FadeTo(@ScreenPartyOptions, SoundLib.Start); + Exit; + end; + end; + + 'S': + begin + FadeTo(@ScreenStatMain, SoundLib.Start); + Exit; + end; + + 'E': + begin + FadeTo(@ScreenEdit, SoundLib.Start); + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE: + begin + Result := False; + end; + + SDLK_RETURN: + begin + //Solo + if (Interaction = 0) then + begin + if (Songs.SongList.Count >= 1) then + begin + if (Ini.Players >= 0) and (Ini.Players <= 3) then + PlayersPlay := Ini.Players + 1; + if (Ini.Players = 4) then + PlayersPlay := 6; + + ScreenName.Goto_SingScreen := False; + FadeTo(@ScreenName, SoundLib.Start); + end + else //show error message + ScreenPopupError.ShowPopup(Language.Translate('ERROR_NO_SONGS')); + end; + + //Multi + if Interaction = 1 then + begin + if (Songs.SongList.Count >= 1) then + begin + if (Length(DLLMan.Plugins) >= 1) then + begin + FadeTo(@ScreenPartyOptions, SoundLib.Start); + end + else //show error message, No Plugins Loaded + ScreenPopupError.ShowPopup(Language.Translate('ERROR_NO_PLUGINS')); + end + else //show error message, No Songs Loaded + ScreenPopupError.ShowPopup(Language.Translate('ERROR_NO_SONGS')); + end; + + //Stats + if Interaction = 2 then + begin + FadeTo(@ScreenStatMain, SoundLib.Start); + end; + + //Editor + if Interaction = 3 then + begin + FadeTo(@ScreenEdit, SoundLib.Start); + end; + + //Options + if Interaction = 4 then + begin + FadeTo(@ScreenOptions, SoundLib.Start); + end; + + //Exit + if Interaction = 5 then + begin + Result := False; + end; + end; + {** + * Up and Down could be done at the same time, + * but I don't want to declare variables inside + * functions like this one, called so many times + *} + SDLK_DOWN: InteractInc; + SDLK_UP: InteractDec; + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end + else // Key Up + case PressedKey of + SDLK_RETURN: + begin + end; + end; +end; + +constructor TScreenMain.Create; +begin + inherited Create; +{** + * Attention ^^: + * New Creation Order needed because of LoadFromTheme + * and Button Collections. + * At First Custom Texts and Statics + * Then LoadFromTheme + * after LoadFromTheme the Buttons and Selects + *} + TextDescription := AddText(Theme.Main.TextDescription); + TextDescriptionLong := AddText(Theme.Main.TextDescriptionLong); + + LoadFromTheme(Theme.Main); + + AddButton(Theme.Main.ButtonSolo); + AddButton(Theme.Main.ButtonMulti); + AddButton(Theme.Main.ButtonStat); + AddButton(Theme.Main.ButtonEditor); + AddButton(Theme.Main.ButtonOptions); + AddButton(Theme.Main.ButtonExit); + + Interaction := 0; +end; + +procedure TScreenMain.onShow; +begin + inherited; +{** + * Start background music + *} + SoundLib.StartBgMusic; +end; + +procedure TScreenMain.InteractNext; +begin + inherited InteractNext; + Text[TextDescription].Text := Theme.Main.Description[Interaction]; + Text[TextDescriptionLong].Text := Theme.Main.DescriptionLong[Interaction]; +end; + +procedure TScreenMain.InteractPrev; +begin + inherited InteractPrev; + Text[TextDescription].Text := Theme.Main.Description[Interaction]; + Text[TextDescriptionLong].Text := Theme.Main.DescriptionLong[Interaction]; +end; + +procedure TScreenMain.InteractDec; +begin + inherited InteractDec; + Text[TextDescription].Text := Theme.Main.Description[Interaction]; + Text[TextDescriptionLong].Text := Theme.Main.DescriptionLong[Interaction]; +end; + +procedure TScreenMain.InteractInc; +begin + inherited InteractInc; + Text[TextDescription].Text := Theme.Main.Description[Interaction]; + Text[TextDescriptionLong].Text := Theme.Main.DescriptionLong[Interaction]; +end; + +procedure TScreenMain.SetAnimationProgress(Progress: real); +begin + Static[0].Texture.ScaleW := Progress; + Static[0].Texture.ScaleH := Progress; +end; + +end. diff --git a/src/screens/UScreenName.pas b/src/screens/UScreenName.pas new file mode 100644 index 00000000..f2d59f05 --- /dev/null +++ b/src/screens/UScreenName.pas @@ -0,0 +1,243 @@ +unit UScreenName; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenName = class(TMenu) + public + Goto_SingScreen: Boolean; //If True then next Screen in SingScreen + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, UMain, UIni, UTexture, UCommon; + + +function TScreenName.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + I: integer; +SDL_ModState: Word; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT); + + // check normal keys + if (IsAlphaNumericChar(CharCode) or + {(CharCode in [' ','-','_','!',',','<','/','*','?','''','"']))} IsPunctuationChar(CharCode)) then + begin + Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode; + Exit; + end; + + // check special keys + case PressedKey of + // Templates for Names Mod + SDLK_F1: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[0] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[0]; + end; + SDLK_F2: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[1] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[1]; + end; + SDLK_F3: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[2] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[2]; + end; + SDLK_F4: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[3] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[3]; + end; + SDLK_F5: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[4] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[4]; + end; + SDLK_F6: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[5] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[5]; + end; + SDLK_F7: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[6] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[6]; + end; + SDLK_F8: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[7] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[7]; + end; + SDLK_F9: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[8] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[8]; + end; + SDLK_F10: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[9] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[9]; + end; + SDLK_F11: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[10] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[10]; + end; + SDLK_F12: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[11] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[11]; + end; + + + SDLK_BACKSPACE: + begin + Button[Interaction].Text[0].DeleteLastL; + end; + + SDLK_ESCAPE : + begin + Ini.SaveNames; + AudioPlayback.PlaySound(SoundLib.Back); + if GoTo_SingScreen then + FadeTo(@ScreenSong) + else + FadeTo(@ScreenMain); + end; + + SDLK_RETURN: + begin + for I := 1 to 6 do + Ini.Name[I-1] := Button[I-1].Text[0].Text; + Ini.SaveNames; + AudioPlayback.PlaySound(SoundLib.Start); + + if GoTo_SingScreen then + FadeTo(@ScreenSing) + else + FadeTo(@ScreenLevel); + + GoTo_SingScreen := False; + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end; +end; + +constructor TScreenName.Create; +var + I: integer; +begin + inherited Create; + + LoadFromTheme(Theme.Name); + + + for I := 1 to 6 do + AddButton(Theme.Name.ButtonPlayer[I]); + + Interaction := 0; +end; + +procedure TScreenName.onShow; +var + I: integer; +begin + inherited; + + for I := 1 to 6 do + Button[I-1].Text[0].Text := Ini.Name[I-1]; + + for I := 1 to PlayersPlay do begin + Button[I-1].Visible := true; + Button[I-1].Selectable := true; + end; + + for I := PlayersPlay+1 to 6 do begin + Button[I-1].Visible := false; + Button[I-1].Selectable := false; + end; + +end; + +procedure TScreenName.SetAnimationProgress(Progress: real); +var + I: integer; +begin + for I := 1 to 6 do + Button[I-1].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenOpen.pas b/src/screens/UScreenOpen.pas new file mode 100644 index 00000000..186b9b47 --- /dev/null +++ b/src/screens/UScreenOpen.pas @@ -0,0 +1,173 @@ +unit UScreenOpen; + +interface + +{$I switches.inc} + +uses UMenu, UMusic, SDL, SysUtils, UFiles, UTime, USongs, UIni, ULog, UTexture, UMenuText, + ULyrics, Math, gl, UThemes; + +type + TScreenOpen = class(TMenu) + private + TextF: array[0..1] of integer; + TextN: integer; + public + Tex_Background: TTexture; + FadeOut: boolean; + Path: string; + BackScreen: pointer; + procedure AddBox(X, Y, W, H: real); + constructor Create; override; + procedure onShow; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; +// function Draw: boolean; override; +// procedure Finish; + end; + +implementation +uses UGraphic, UDraw, UMain, USkins; + +function TScreenOpen.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + + if (PressedDown) then begin // Key Down + // check normal keys + case CharCode of + '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '.', ':', '\': + begin + if Interaction = 0 then begin + Text[TextN].Text := Text[TextN].Text + CharCode; + end; + end; + end; + + // check special keys + case PressedKey of + SDLK_Q: + begin + Result := false; + end; + 8: // del + begin + if Interaction = 0 then + begin + Text[TextN].DeleteLastL; + end; + end; + + + SDLK_ESCAPE : + begin + //Empty Filename and go to last Screen + ConversionFileName := ''; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(BackScreen); + end; + + SDLK_RETURN: + begin + if (Interaction = 2) then begin + //Update Filename and go to last Screen + ConversionFileName := Text[TextN].Text; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(BackScreen); + end + else if (Interaction = 1) then + begin + //Empty Filename and go to last Screen + ConversionFileName := ''; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(BackScreen); + end; + end; + + SDLK_LEFT: + begin + InteractPrev; + end; + + SDLK_RIGHT: + begin + InteractNext; + end; + + SDLK_DOWN: + begin + end; + + SDLK_UP: + begin + end; + end; + end; +end; + +procedure TScreenOpen.AddBox(X, Y, W, H: real); +begin + AddStatic(X, Y, W, H, 0, 0, 0, Skin.GetTextureFileName('MainBar'), TEXTURE_TYPE_COLORIZED); + AddStatic(X+2, Y+2, W-4, H-4, 1, 1, 1, Skin.GetTextureFileName('MainBar'), TEXTURE_TYPE_COLORIZED); +end; + +constructor TScreenOpen.Create; +begin + inherited Create; + + // linijka +{ AddStatic(20, 10, 80, 30, 0, 0, 0, 'MainBar', 'JPG', TEXTURE_TYPE_COLORIZED); + AddText(35, 17, 1, 6, 1, 1, 1, 'Linijka'); + TextSentence := AddText(120, 14, 1, 8, 0, 0, 0, '0 / 0');} + + // file list +// AddBox(400, 100, 350, 450); + +// TextF[0] := AddText(430, 155, 0, 8, 0, 0, 0, 'a'); +// TextF[1] := AddText(430, 180, 0, 8, 0, 0, 0, 'a'); + + // file name + AddBox(20, 540, 500, 40); + TextN := AddText(50, 548, 0, 8, 0, 0, 0, ConversionFileName); + AddInteraction(iText, TextN); + + // buttons + {AddButton(540, 540, 100, 40, Skin.SkinPath + Skin.ButtonF); + AddButtonText(10, 5, 0, 0, 0, 'Cancel'); + + AddButton(670, 540, 100, 40, Skin.SkinPath + Skin.ButtonF); + AddButtonText(30, 5, 0, 0, 0, 'OK');} + // buttons + AddButton(540, 540, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(10, 5, 0, 0, 0, 'Cancel'); + + AddButton(670, 540, 100, 40, Skin.GetTextureFileName('ButtonF')); + AddButtonText(30, 5, 0, 0, 0, 'OK'); + + +end; + +procedure TScreenOpen.onShow; +begin + inherited; + + Interaction := 0; +end; + +(*function TScreenEditSub.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + Pet: integer; + AktBeat: integer; +begin + +end; + +procedure TScreenEditSub.Finish; +begin +// +end;*) + +end. + diff --git a/src/screens/UScreenOptions.pas b/src/screens/UScreenOptions.pas new file mode 100644 index 00000000..24633115 --- /dev/null +++ b/src/screens/UScreenOptions.pas @@ -0,0 +1,196 @@ +unit UScreenOptions; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, SysUtils, UDisplay, UMusic, UFiles, UIni, UThemes; + +type + TScreenOptions = class(TMenu) + public + TextDescription: integer; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure InteractNext; override; + procedure InteractPrev; override; + procedure InteractNextRow; override; + procedure InteractPrevRow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic; + +function TScreenOptions.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin +// Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end; + SDLK_RETURN: + begin + if SelInteraction = 0 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsGame); + end; + + if SelInteraction = 1 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsGraphics); + end; + + if SelInteraction = 2 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsSound); + end; + + if SelInteraction = 3 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsLyrics); + end; + + if SelInteraction = 4 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsThemes); + end; + + if SelInteraction = 5 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsRecord); + end; + + if SelInteraction = 6 then + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenOptionsAdvanced); + end; + + if SelInteraction = 7 then + begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end; + end; + SDLK_DOWN: InteractNextRow; + SDLK_UP: InteractPrevRow; + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end; +end; + +constructor TScreenOptions.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + TextDescription := AddText(Theme.Options.TextDescription); + + LoadFromTheme(Theme.Options); + + AddButton(Theme.Options.ButtonGame); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[0]); + + AddButton(Theme.Options.ButtonGraphics); + if (Length(Button[1].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[1]); + + AddButton(Theme.Options.ButtonSound); + if (Length(Button[2].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[2]); + + AddButton(Theme.Options.ButtonLyrics); + if (Length(Button[3].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[3]); + + AddButton(Theme.Options.ButtonThemes); + if (Length(Button[4].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[4]); + + AddButton(Theme.Options.ButtonRecord); + if (Length(Button[5].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[5]); + + AddButton(Theme.Options.ButtonAdvanced); + if (Length(Button[6].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[6]); + + AddButton(Theme.Options.ButtonExit); + if (Length(Button[7].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + + Interaction := 0; +end; + +procedure TScreenOptions.onShow; +begin + inherited; +end; + +procedure TScreenOptions.InteractNext; +begin + inherited InteractNext; + Text[TextDescription].Text := Theme.Options.Description[Interaction]; +end; + +procedure TScreenOptions.InteractPrev; +begin + inherited InteractPrev; + Text[TextDescription].Text := Theme.Options.Description[Interaction]; +end; + +procedure TScreenOptions.InteractNextRow; +begin + inherited InteractNextRow; + Text[TextDescription].Text := Theme.Options.Description[Interaction]; +end; + +procedure TScreenOptions.InteractPrevRow; +begin + inherited InteractPrevRow; + Text[TextDescription].Text := Theme.Options.Description[Interaction]; +end; + +procedure TScreenOptions.SetAnimationProgress(Progress: real); +begin + Button[0].Texture.ScaleW := Progress; + Button[1].Texture.ScaleW := Progress; + Button[2].Texture.ScaleW := Progress; + Button[3].Texture.ScaleW := Progress; + Button[4].Texture.ScaleW := Progress; + Button[5].Texture.ScaleW := Progress; + Button[6].Texture.ScaleW := Progress; + Button[7].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenOptionsAdvanced.pas b/src/screens/UScreenOptionsAdvanced.pas new file mode 100644 index 00000000..be8895e1 --- /dev/null +++ b/src/screens/UScreenOptionsAdvanced.pas @@ -0,0 +1,113 @@ +unit UScreenOptionsAdvanced; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, UIni, UThemes; + +type + TScreenOptionsAdvanced = class(TMenu) + public + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + end; + +implementation + +uses UGraphic, SysUtils; + +function TScreenOptionsAdvanced.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + // Escape -> save nothing - just leave this screen + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + //SelectLoadAnimation Hidden because it is useless atm + //if SelInteraction = 7 then begin + if SelInteraction = 6 then begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + //SelectLoadAnimation Hidden because it is useless atm + //if (SelInteraction >= 0) and (SelInteraction <= 6) then begin + if (SelInteraction >= 0) and (SelInteraction <= 5) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + //SelectLoadAnimation Hidden because it is useless atm + //if (SelInteraction >= 0) and (SelInteraction <= 6) then begin + if (SelInteraction >= 0) and (SelInteraction <= 5) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; +end; + +constructor TScreenOptionsAdvanced.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + LoadFromTheme(Theme.OptionsAdvanced); + + //SelectLoadAnimation Hidden because it is useless atm + //AddSelect(Theme.OptionsAdvanced.SelectLoadAnimation, Ini.LoadAnimation, ILoadAnimation); + AddSelectSlide(Theme.OptionsAdvanced.SelectScreenFade, Ini.ScreenFade, IScreenFade); + AddSelectSlide(Theme.OptionsAdvanced.SelectEffectSing, Ini.EffectSing, IEffectSing); + AddSelectSlide(Theme.OptionsAdvanced.SelectLineBonus, Ini.LineBonus, ILineBonus); + AddSelectSlide(Theme.OptionsAdvanced.SelectOnSongClick, Ini.OnSongClick, IOnSongClick); + AddSelectSlide(Theme.OptionsAdvanced.SelectAskbeforeDel, Ini.AskBeforeDel, IAskbeforeDel); + AddSelectSlide(Theme.OptionsAdvanced.SelectPartyPopup, Ini.PartyPopup, IPartyPopup); + + AddButton(Theme.OptionsAdvanced.ButtonExit); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + + Interaction := 0; +end; + +procedure TScreenOptionsAdvanced.onShow; +begin + inherited; + + Interaction := 0; +end; + +end. diff --git a/src/screens/UScreenOptionsGame.pas b/src/screens/UScreenOptionsGame.pas new file mode 100644 index 00000000..2dc8dd7f --- /dev/null +++ b/src/screens/UScreenOptionsGame.pas @@ -0,0 +1,117 @@ +unit UScreenOptionsGame; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, UIni, UThemes, USongs; + +type + TScreenOptionsGame = class(TMenu) + public + old_Tabs, old_Sorting: integer; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure RefreshSongs; + end; + +implementation + +uses UGraphic, SysUtils; + +function TScreenOptionsGame.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + RefreshSongs; + + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + if SelInteraction = 6 then begin + AudioPlayback.PlaySound(SoundLib.Back); + RefreshSongs; + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 5) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 5) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; +end; + +constructor TScreenOptionsGame.Create; +begin + inherited Create; + + LoadFromTheme(Theme.OptionsGame); + + //Refresh Songs Patch + old_Sorting := Ini.Sorting; + old_Tabs := Ini.Tabs; + + AddSelectSlide(Theme.OptionsGame.SelectPlayers, Ini.Players, IPlayers); + AddSelectSlide(Theme.OptionsGame.SelectDifficulty, Ini.Difficulty, IDifficulty); + AddSelectSlide(Theme.OptionsGame.SelectLanguage, Ini.Language, ILanguage); + AddSelectSlide(Theme.OptionsGame.SelectTabs, Ini.Tabs, ITabs); + AddSelectSlide(Theme.OptionsGame.SelectSorting, Ini.Sorting, ISorting); + AddSelectSlide(Theme.OptionsGame.SelectDebug, Ini.Debug, IDebug); + + AddButton(Theme.OptionsGame.ButtonExit); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + +end; + +//Refresh Songs Patch +procedure TScreenOptionsGame.RefreshSongs; +begin +if (ini.Sorting <> old_Sorting) or (ini.Tabs <> old_Tabs) then + ScreenSong.Refresh; +end; + +procedure TScreenOptionsGame.onShow; +begin + inherited; + +// Interaction := 0; +end; + +end. diff --git a/src/screens/UScreenOptionsGraphics.pas b/src/screens/UScreenOptionsGraphics.pas new file mode 100644 index 00000000..f2b6faa2 --- /dev/null +++ b/src/screens/UScreenOptionsGraphics.pas @@ -0,0 +1,113 @@ +unit UScreenOptionsGraphics; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, UIni, UThemes; + +type + TScreenOptionsGraphics = class(TMenu) + public + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + end; + +implementation + +uses UGraphic, UMain, SysUtils, TypInfo; + +function TScreenOptionsGraphics.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + // Escape -> save nothing - just leave this screen + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin +{ if SelInteraction <= 1 then begin + Restart := true; + end;} + if SelInteraction = 6 then begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + // FIXME: changing the video mode does not work this way in windows + // and MacOSX as all textures will be invalidated through this. + // See the ALT+TAB code too. + {$IFDEF Linux} + Reinitialize3D(); + {$ENDIF} + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction < 6) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction < 6) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; +end; + +constructor TScreenOptionsGraphics.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + LoadFromTheme(Theme.OptionsGraphics); + + AddSelectSlide(Theme.OptionsGraphics.SelectResolution, Ini.Resolution, IResolution); + AddSelectSlide(Theme.OptionsGraphics.SelectFullscreen, Ini.Fullscreen, IFullscreen); + AddSelectSlide(Theme.OptionsGraphics.SelectDepth, Ini.Depth, IDepth); + AddSelectSlide(Theme.OptionsGraphics.SelectVisualizer, Ini.VisualizerOption, IVisualizer); + AddSelectSlide(Theme.OptionsGraphics.SelectOscilloscope, Ini.Oscilloscope, IOscilloscope); + AddSelectSlide(Theme.OptionsGraphics.SelectMovieSize, Ini.MovieSize, IMovieSize); + + + AddButton(Theme.OptionsGraphics.ButtonExit); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + +end; + +procedure TScreenOptionsGraphics.onShow; +begin + inherited; + + Interaction := 0; +end; + +end. diff --git a/src/screens/UScreenOptionsLyrics.pas b/src/screens/UScreenOptionsLyrics.pas new file mode 100644 index 00000000..42f1fadb --- /dev/null +++ b/src/screens/UScreenOptionsLyrics.pas @@ -0,0 +1,103 @@ +unit UScreenOptionsLyrics; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, UIni, UThemes; + +type + TScreenOptionsLyrics = class(TMenu) + public + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + end; + +implementation + +uses UGraphic, SysUtils; + +function TScreenOptionsLyrics.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + // Escape -> save nothing - just leave this screen + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + if SelInteraction = 3 then begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 3) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 3) then begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; +end; + +constructor TScreenOptionsLyrics.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + LoadFromTheme(Theme.OptionsLyrics); + + AddSelectSlide(Theme.OptionsLyrics.SelectLyricsFont, Ini.LyricsFont, ILyricsFont); + AddSelectSlide(Theme.OptionsLyrics.SelectLyricsEffect, Ini.LyricsEffect, ILyricsEffect); + //AddSelect(Theme.OptionsLyrics.SelectSolmization, Ini.Solmization, ISolmization); GAH!!!!11 DIE!!! + AddSelectSlide(Theme.OptionsLyrics.SelectNoteLines, Ini.NoteLines, INoteLines); + + + AddButton(Theme.OptionsLyrics.ButtonExit); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + +end; + +procedure TScreenOptionsLyrics.onShow; +begin + inherited; + + Interaction := 0; +end; + +end. diff --git a/src/screens/UScreenOptionsRecord.pas b/src/screens/UScreenOptionsRecord.pas new file mode 100644 index 00000000..885f7db5 --- /dev/null +++ b/src/screens/UScreenOptionsRecord.pas @@ -0,0 +1,785 @@ +unit UScreenOptionsRecord; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UThemes, + UMusic, + URecord, + UMenu; + +type + TDrawState = record + ChannelIndex: integer; + R, G, B: real; // mapped player color (normal) + RD, GD, BD: real; // mapped player color (dark) + end; + + TPeakInfo = record + Volume: single; + Time: cardinal; + end; + + TScreenOptionsRecord = class(TMenu) + private + // max. count of input-channels determined for all devices + MaxChannelCount: integer; + + // current input device + CurrentDeviceIndex: integer; + PreviewDeviceIndex: integer; + + // string arrays for select-slide options + InputSourceNames: array of string; + InputDeviceNames: array of string; + + // dynamic generated themes for channel select-sliders + SelectSlideChannelTheme: array of TThemeSelectSlide; + + // indices for widget-updates + SelectInputSourceID: integer; + SelectSlideChannelID: array of integer; + + // interaction IDs + ExitButtonIID: integer; + + // dummy data for non-available channels + ChannelToPlayerMapDummy: integer; + + // preview channel-buffers + PreviewChannel: array of TCaptureBuffer; + ChannelPeak: array of TPeakInfo; + + // Device source volume + SourceVolume: single; + NextVolumePollTime: cardinal; + + procedure StartPreview; + procedure StopPreview; + procedure UpdateInputDevice; + procedure ChangeVolume(VolumeChange: single); + procedure DrawVolume(x, y, Width, Height: single); + procedure DrawVUMeter(const State: TDrawState; x, y, Width, Height: single); + procedure DrawPitch(const State: TDrawState; x, y, Width, Height: single); + public + constructor Create; override; + function Draw: boolean; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure onHide; override; + end; + +const + PeakDecay = 0.2; // strength of peak-decay (reduction after one sec) + +const + BarHeight = 11; // height of each bar (volume/vu-meter/pitch) + BarUpperSpacing = 1; // spacing between a bar-area and the previous widget + BarLowerSpacing = 3; // spacing between a bar-area and the next widget + SourceBarsTotalHeight = BarHeight + BarUpperSpacing + BarLowerSpacing; + ChannelBarsTotalHeight = 2*BarHeight + BarUpperSpacing + BarLowerSpacing; + +implementation + +uses + SysUtils, + Math, + SDL, + gl, + TextGL, + UGraphic, + UDraw, + UMain, + UMenuSelectSlide, + UMenuText, + UFiles, + UDisplay, + UIni, + ULog; + +function TScreenOptionsRecord.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + '+': + begin + // FIXME: add a nice volume-slider instead + // or at least provide visualization and acceleration if the user holds the key pressed. + ChangeVolume(0.02); + end; + '-': + begin + // FIXME: add a nice volume-slider instead + // or at least provide visualization and acceleration if the user holds the key pressed. + ChangeVolume(-0.02); + end; + 'T': + begin + if ((SDL_GetModState() and KMOD_SHIFT) <> 0) then + Ini.ThresholdIndex := (Ini.ThresholdIndex + Length(IThresholdVals) - 1) mod Length(IThresholdVals) + else + Ini.ThresholdIndex := (Ini.ThresholdIndex + 1) mod Length(IThresholdVals); + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE: + begin + // Escape -> save nothing - just leave this screen + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + if (SelInteraction = ExitButtonIID) then + begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction < ExitButtonIID) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + UpdateInputDevice; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction < ExitButtonIID) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + UpdateInputDevice; + end; + end; + end; +end; + +constructor TScreenOptionsRecord.Create; +var + DeviceIndex: integer; + SourceIndex: integer; + ChannelIndex: integer; + InputDevice: TAudioInputDevice; + InputDeviceCfg: PInputDeviceConfig; + ChannelTheme: ^TThemeSelectSlide; + //ButtonTheme: TThemeButton; + WidgetYPos: integer; +begin + inherited Create; + + LoadFromTheme(Theme.OptionsRecord); + + // set CurrentDeviceIndex to a valid device + if (Length(AudioInputProcessor.DeviceList) > 0) then + CurrentDeviceIndex := 0 + else + CurrentDeviceIndex := -1; + + PreviewDeviceIndex := -1; + + WidgetYPos := 0; + + // init sliders if at least one device was detected + if (Length(AudioInputProcessor.DeviceList) > 0) then + begin + InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex]; + InputDeviceCfg := @Ini.InputDeviceConfig[InputDevice.CfgIndex]; + + // init device-selection slider + SetLength(InputDeviceNames, Length(AudioInputProcessor.DeviceList)); + for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do + begin + InputDeviceNames[DeviceIndex] := AudioInputProcessor.DeviceList[DeviceIndex].Name; + end; + // add device-selection slider (InteractionID: 0) + AddSelectSlide(Theme.OptionsRecord.SelectSlideCard, CurrentDeviceIndex, InputDeviceNames); + + // init source-selection slider + SetLength(InputSourceNames, Length(InputDevice.Source)); + for SourceIndex := 0 to High(InputDevice.Source) do + begin + InputSourceNames[SourceIndex] := InputDevice.Source[SourceIndex].Name; + end; + // add source-selection slider (InteractionID: 1) + SelectInputSourceID := AddSelectSlide(Theme.OptionsRecord.SelectSlideInput, + InputDeviceCfg.Input, InputSourceNames); + + // add space for source volume bar + WidgetYPos := Theme.OptionsRecord.SelectSlideInput.Y + + Theme.OptionsRecord.SelectSlideInput.H + + SourceBarsTotalHeight; + + // find max. channel count of all devices + MaxChannelCount := 0; + for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do + begin + if (AudioInputProcessor.DeviceList[DeviceIndex].AudioFormat.Channels > MaxChannelCount) then + MaxChannelCount := AudioInputProcessor.DeviceList[DeviceIndex].AudioFormat.Channels; + end; + + // init channel-to-player mapping sliders + SetLength(SelectSlideChannelID, MaxChannelCount); + SetLength(SelectSlideChannelTheme, MaxChannelCount); + + for ChannelIndex := 0 to MaxChannelCount-1 do + begin + // copy reference slide + SelectSlideChannelTheme[ChannelIndex] := + Theme.OptionsRecord.SelectSlideChannel; + // set current channel-theme + ChannelTheme := @SelectSlideChannelTheme[ChannelIndex]; + // adjust vertical position + ChannelTheme.Y := WidgetYPos; + // calc size of next slide (add space for bars) + WidgetYPos := WidgetYPos + ChannelTheme.H + ChannelBarsTotalHeight; + // append channel index to name + ChannelTheme.Text := ChannelTheme.Text + IntToStr(ChannelIndex+1); + + // show/hide widgets depending on whether the channel exists + if (ChannelIndex < Length(InputDeviceCfg.ChannelToPlayerMap)) then + begin + // current device has this channel + + // add slider + SelectSlideChannelID[ChannelIndex] := AddSelectSlide(ChannelTheme^, + InputDeviceCfg.ChannelToPlayerMap[ChannelIndex], IChannelPlayer); + end + else + begin + // current device does not have that many channels + + // add slider but hide it and assign a dummy variable to it + SelectSlideChannelID[ChannelIndex] := AddSelectSlide(ChannelTheme^, + ChannelToPlayerMapDummy, IChannelPlayer); + SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := false; + end; + end; + end; + + // add Exit-button + //ButtonTheme := Theme.OptionsRecord.ButtonExit; + // adjust button position + //if (WidgetYPos <> 0) then + // ButtonTheme.Y := WidgetYPos; + //AddButton(ButtonTheme); + // <mog> I uncommented the stuff above, because it's not skinable :X + AddButton(Theme.OptionsRecord.ButtonExit); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + // store InteractionID + if (Length(AudioInputProcessor.DeviceList) > 0) then + ExitButtonIID := MaxChannelCount + 2 + else + ExitButtonIID := 0; + + // set focus + Interaction := 0; +end; + +procedure TScreenOptionsRecord.UpdateInputDevice; +var + SourceIndex: integer; + InputDevice: TAudioInputDevice; + InputDeviceCfg: PInputDeviceConfig; + ChannelIndex: integer; +begin + //Log.LogStatus('Update input-device', 'TScreenOptionsRecord.UpdateCard') ; + + StopPreview(); + + // set CurrentDeviceIndex to a valid device + if (CurrentDeviceIndex > High(AudioInputProcessor.DeviceList)) then + CurrentDeviceIndex := 0; + + // update sliders if at least one device was detected + if (Length(AudioInputProcessor.DeviceList) > 0) then + begin + InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex]; + InputDeviceCfg := @Ini.InputDeviceConfig[InputDevice.CfgIndex]; + + // update source-selection slider + SetLength(InputSourceNames, Length(InputDevice.Source)); + for SourceIndex := 0 to High(InputDevice.Source) do + begin + InputSourceNames[SourceIndex] := InputDevice.Source[SourceIndex].Name; + end; + UpdateSelectSlideOptions(Theme.OptionsRecord.SelectSlideInput, SelectInputSourceID, + InputSourceNames, InputDeviceCfg.Input); + + // update channel-to-player mapping sliders + for ChannelIndex := 0 to MaxChannelCount-1 do + begin + // show/hide widgets depending on whether the channel exists + if (ChannelIndex < Length(InputDeviceCfg.ChannelToPlayerMap)) then + begin + // current device has this channel + + // show slider + UpdateSelectSlideOptions(SelectSlideChannelTheme[ChannelIndex], + SelectSlideChannelID[ChannelIndex], IChannelPlayer, + InputDeviceCfg.ChannelToPlayerMap[ChannelIndex]); + SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := true; + end + else + begin + // current device does not have that many channels + + // hide slider and assign a dummy variable to it + UpdateSelectSlideOptions(SelectSlideChannelTheme[ChannelIndex], + SelectSlideChannelID[ChannelIndex], IChannelPlayer, + ChannelToPlayerMapDummy); + SelectsS[SelectSlideChannelID[ChannelIndex]].Visible := false; + end; + end; + end; + + StartPreview(); +end; + +procedure TScreenOptionsRecord.ChangeVolume(VolumeChange: single); +var + InputDevice: TAudioInputDevice; + Volume: single; +begin + // validate CurrentDeviceIndex + if ((CurrentDeviceIndex < 0) or + (CurrentDeviceIndex > High(AudioInputProcessor.DeviceList))) then + begin + Exit; + end; + + InputDevice := AudioInputProcessor.DeviceList[CurrentDeviceIndex]; + if not assigned(InputDevice) then + Exit; + + // set new volume + Volume := InputDevice.GetVolume() + VolumeChange; + InputDevice.SetVolume(Volume); + //DebugWriteln('Volume: ' + floattostr(InputDevice.GetVolume)); + + // volume must be polled again + NextVolumePollTime := 0; +end; + +procedure TScreenOptionsRecord.onShow; +var + ChannelIndex: integer; +begin + inherited; + + Interaction := 0; + + // create preview sound-buffers + SetLength(PreviewChannel, MaxChannelCount); + for ChannelIndex := 0 to High(PreviewChannel) do + PreviewChannel[ChannelIndex] := TCaptureBuffer.Create(); + + SetLength(ChannelPeak, MaxChannelCount); + + StartPreview(); +end; + +procedure TScreenOptionsRecord.onHide; +var + ChannelIndex: integer; +begin + StopPreview(); + + // free preview buffers + for ChannelIndex := 0 to High(PreviewChannel) do + PreviewChannel[ChannelIndex].Free; + SetLength(PreviewChannel, 0); + SetLength(ChannelPeak, 0); +end; + +procedure TScreenOptionsRecord.StartPreview; +var + ChannelIndex: integer; + Device: TAudioInputDevice; +begin + if ((CurrentDeviceIndex >= 0) and + (CurrentDeviceIndex <= High(AudioInputProcessor.DeviceList))) then + begin + Device := AudioInputProcessor.DeviceList[CurrentDeviceIndex]; + // set preview channel as active capture channel + for ChannelIndex := 0 to High(Device.CaptureChannel) do + begin + PreviewChannel[ChannelIndex].Clear(); + Device.LinkCaptureBuffer(ChannelIndex, PreviewChannel[ChannelIndex]); + FillChar(ChannelPeak[ChannelIndex], SizeOf(TPeakInfo), 0); + end; + Device.Start(); + PreviewDeviceIndex := CurrentDeviceIndex; + + // volume must be polled again + NextVolumePollTime := 0; + end; +end; + +procedure TScreenOptionsRecord.StopPreview; +var + ChannelIndex: integer; + Device: TAudioInputDevice; +begin + if ((PreviewDeviceIndex >= 0) and + (PreviewDeviceIndex <= High(AudioInputProcessor.DeviceList))) then + begin + Device := AudioInputProcessor.DeviceList[PreviewDeviceIndex]; + Device.Stop; + for ChannelIndex := 0 to High(Device.CaptureChannel) do + Device.LinkCaptureBuffer(ChannelIndex, nil); + end; + PreviewDeviceIndex := -1; +end; + + +procedure TScreenOptionsRecord.DrawVolume(x, y, Width, Height: single); +var + x1, y1, x2, y2: single; + VolBarInnerWidth: integer; + Volume: single; +const + VolBarInnerHSpacing = 2; + VolBarInnerVSpacing = 1; +begin + // coordinates for black rect + x1 := x; + y1 := y; + x2 := x1 + Width; + y2 := y1 + Height; + + // init blend mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + // draw black background-rect + glColor4f(0, 0, 0, 0.8); + glBegin(GL_QUADS); + glVertex2f(x1, y1); + glVertex2f(x2, y1); + glVertex2f(x2, y2); + glVertex2f(x1, y2); + glEnd(); + + VolBarInnerWidth := Trunc(Width - 2*VolBarInnerHSpacing); + + // TODO: if no volume is available, show some info (a blue bar maybe) + if (SourceVolume >= 0) then + Volume := SourceVolume + else + Volume := 0; + + // coordinates for first half of the volume bar + x1 := x + VolBarInnerHSpacing; + x2 := x1 + VolBarInnerWidth * Volume; + y1 := y1 + VolBarInnerVSpacing; + y2 := y2 - VolBarInnerVSpacing; + + // draw volume-bar + glBegin(GL_QUADS); + // draw volume bar + glColor3f(0.4, 0.3, 0.3); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glColor3f(1, 0.1, 0.1); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + glEnd(); + + { not needed anymore + // coordinates for separator + x1 := x + VolBarInnerHSpacing; + x2 := x1 + VolBarInnerWidth; + + // draw separator + glBegin(GL_LINE_STRIP); + glColor4f(0.1, 0.1, 0.1, 0.2); + glVertex2f(x1, y2); + glColor4f(0.4, 0.4, 0.4, 0.2); + glVertex2f((x1+x2)/2, y2); + glColor4f(0.1, 0.1, 0.1, 0.2); + glVertex2f(x2, y2); + glEnd(); + } + + glDisable(GL_BLEND); +end; + +procedure TScreenOptionsRecord.DrawVUMeter(const State: TDrawState; x, y, Width, Height: single); +var + x1, y1, x2, y2: single; + Volume, PeakVolume: single; + Delta: single; + VolBarInnerWidth: integer; +const + VolBarInnerHSpacing = 2; + VolBarInnerVSpacing = 1; +begin + // coordinates for black rect + x1 := x; + y1 := y; + x2 := x1 + Width; + y2 := y1 + Height; + + // init blend mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + // draw black background-rect + glColor4f(0, 0, 0, 0.8); + glBegin(GL_QUADS); + glVertex2f(x1, y1); + glVertex2f(x2, y1); + glVertex2f(x2, y2); + glVertex2f(x1, y2); + glEnd(); + + VolBarInnerWidth := Trunc(Width - 2*VolBarInnerHSpacing); + + // vertical positions + y1 := y1 + VolBarInnerVSpacing; + y2 := y2 - VolBarInnerVSpacing; + + // coordinates for bevel + x1 := x + VolBarInnerHSpacing; + x2 := x1 + VolBarInnerWidth; + + glBegin(GL_QUADS); + Volume := PreviewChannel[State.ChannelIndex].MaxSampleVolume(); + + // coordinates for volume bar + x1 := x + VolBarInnerHSpacing; + x2 := x1 + VolBarInnerWidth * Volume; + + // draw volume bar + glColor3f(State.RD, State.GD, State.BD); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glColor3f(State.R, State.G, State.B); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + + Delta := (SDL_GetTicks() - ChannelPeak[State.ChannelIndex].Time)/1000; + PeakVolume := ChannelPeak[State.ChannelIndex].Volume - Delta*Delta*PeakDecay; + + // determine new peak-volume + if (Volume > PeakVolume) then + begin + PeakVolume := Volume; + ChannelPeak[State.ChannelIndex].Volume := Volume; + ChannelPeak[State.ChannelIndex].Time := SDL_GetTicks(); + end; + + x1 := x + VolBarInnerHSpacing + VolBarInnerWidth * PeakVolume; + x2 := x1 + 2; + + // draw peak + glColor3f(0.8, 0.8, 0.8); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + + // draw threshold + x1 := x + VolBarInnerHSpacing; + x2 := x1 + VolBarInnerWidth * IThresholdVals[Ini.ThresholdIndex]; + + glColor4f(0.3, 0.3, 0.3, 0.6); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + glEnd(); + + glDisable(GL_BLEND); +end; + +procedure TScreenOptionsRecord.DrawPitch(const State: TDrawState; x, y, Width, Height: single); +var + x1, y1, x2, y2: single; + i: integer; + ToneBoxWidth: real; + ToneString: PChar; + ToneStringWidth, ToneStringHeight: real; + ToneStringMaxWidth: real; + ToneStringCenterXOffset: real; +const + PitchBarInnerHSpacing = 2; + PitchBarInnerVSpacing = 1; +begin + // calc tone pitch + PreviewChannel[State.ChannelIndex].AnalyzeBuffer(); + + // coordinates for black rect + x1 := x; + y1 := y; + x2 := x + Width; + y2 := y + Height; + + // init blend mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + // draw black background-rect + glColor4f(0, 0, 0, 0.8); + glBegin(GL_QUADS); + glVertex2f(x1, y1); + glVertex2f(x2, y1); + glVertex2f(x2, y2); + glVertex2f(x1, y2); + glEnd(); + + // coordinates for tone boxes + ToneBoxWidth := Width / NumHalftones; + y1 := y1 + PitchBarInnerVSpacing; + y2 := y2 - PitchBarInnerVSpacing; + + glBegin(GL_QUADS); + // draw tone boxes + for i := 0 to NumHalftones-1 do + begin + x1 := x + i * ToneBoxWidth + PitchBarInnerHSpacing; + x2 := x1 + ToneBoxWidth - 2*PitchBarInnerHSpacing; + + if ((PreviewChannel[State.ChannelIndex].ToneValid) and + (PreviewChannel[State.ChannelIndex].ToneAbs = i)) then + begin + // highlight current tone-pitch + glColor3f(1, i / (NumHalftones-1), 0) + end + else + begin + // grey other tone-pitches + glColor3f(0.3, i / (NumHalftones-1) * 0.3, 0); + end; + + glVertex2f(x1, y1); + glVertex2f(x2, y1); + glVertex2f(x2, y2); + glVertex2f(x1, y2); + end; + glEnd(); + + glDisable(GL_BLEND); + + /// + // draw the name of the tone + /////// + + ToneString := PChar(PreviewChannel[State.ChannelIndex].ToneString); + ToneStringHeight := ChannelBarsTotalHeight; + + // initialize font + // TODO: what about reflection, italic etc.? + SetFontSize(ToneStringHeight/3); + + // center + // Note: for centering let us assume that G#4 has the max. horizontal extent + ToneStringWidth := glTextWidth(ToneString); + ToneStringMaxWidth := glTextWidth('G#4'); + ToneStringCenterXOffset := (ToneStringMaxWidth-ToneStringWidth) / 2; + + // draw + SetFontPos(x-ToneStringWidth-ToneStringCenterXOffset, y-ToneStringHeight/2); + glColor3f(0, 0, 0); + glPrint(ToneString); +end; + +function TScreenOptionsRecord.Draw: boolean; +var + i: integer; + Device: TAudioInputDevice; + DeviceCfg: PInputDeviceConfig; + SelectSlide: TSelectSlide; + BarXOffset, BarYOffset, BarWidth: real; + ChannelIndex: integer; + State: TDrawState; +begin + DrawBG; + DrawFG; + + if ((PreviewDeviceIndex >= 0) and + (PreviewDeviceIndex <= High(AudioInputProcessor.DeviceList))) then + begin + Device := AudioInputProcessor.DeviceList[PreviewDeviceIndex]; + DeviceCfg := @Ini.InputDeviceConfig[Device.CfgIndex]; + + // update source volume + if (SDL_GetTicks() >= NextVolumePollTime) then + begin + NextVolumePollTime := SDL_GetTicks() + 500; // next poll in 500ms + SourceVolume := Device.GetVolume(); + end; + + // get source select slide + SelectSlide := SelectsS[SelectInputSourceID]; + BarXOffset := SelectSlide.TextureSBG.X; + BarYOffset := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H + BarUpperSpacing; + BarWidth := SelectSlide.TextureSBG.W; + DrawVolume(SelectSlide.TextureSBG.X, BarYOffset, BarWidth, BarHeight); + + for ChannelIndex := 0 to High(Device.CaptureChannel) do + begin + // load player color mapped to current input channel + if (DeviceCfg.ChannelToPlayerMap[ChannelIndex] > 0) then + begin + // set mapped channel to corresponding player-color + LoadColor(State.R, State.G, State.B, 'P'+ IntToStr(DeviceCfg.ChannelToPlayerMap[ChannelIndex]) + 'Dark'); + end + else + begin + // set non-mapped channel to white + State.R := 1; State.G := 1; State.B := 1; + end; + + // dark player colors + State.RD := 0.2 * State.R; + State.GD := 0.2 * State.G; + State.BD := 0.2 * State.B; + + // channel select slide + SelectSlide := SelectsS[SelectSlideChannelID[ChannelIndex]]; + + BarXOffset := SelectSlide.TextureSBG.X; + BarYOffset := SelectSlide.TextureSBG.Y + SelectSlide.TextureSBG.H + BarUpperSpacing; + BarWidth := SelectSlide.TextureSBG.W; + + State.ChannelIndex := ChannelIndex; + + DrawVUMeter(State, BarXOffset, BarYOffset, BarWidth, BarHeight); + DrawPitch(State, BarXOffset, BarYOffset+BarHeight, BarWidth, BarHeight); + end; + end; + + Result := True; +end; + + +end. diff --git a/src/screens/UScreenOptionsSound.pas b/src/screens/UScreenOptionsSound.pas new file mode 100644 index 00000000..9c602788 --- /dev/null +++ b/src/screens/UScreenOptionsSound.pas @@ -0,0 +1,133 @@ +unit UScreenOptionsSound; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, UIni, UThemes; + +type + TScreenOptionsSound = class(TMenu) + public + constructor Create; override; + function ParseInput(PressedKey: cardinal; CharCode: widechar; + PressedDown: boolean): boolean; override; + procedure onShow; override; + end; + +implementation + +uses UGraphic, SysUtils; + +function TScreenOptionsSound.ParseInput(PressedKey: cardinal; + CharCode: widechar; PressedDown: boolean): boolean; +begin + Result := True; + if (PressedDown) then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := False; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE: + begin + // Escape -> save nothing - just leave this screen + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + if SelInteraction = 8 then + begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP: + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction < 8) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction < 8) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; + +{** + * Actually this one isn't pretty - but it does the trick of + * turning the background music on/off in "real time" + * bgm = background music + * TODO: - Fetching the SelectInteraction via something more descriptive + * - Obtaining the current value of a select is imho ugly + *} + if (SelInteraction = 1) then + begin + if TBackgroundMusicOption(SelectsS[1].SelectedOption) = bmoOn then + SoundLib.StartBgMusic + else + SoundLib.PauseBgMusic; + end; + +end; + +constructor TScreenOptionsSound.Create; +begin + inherited Create; + + LoadFromTheme(Theme.OptionsSound); + + AddSelectSlide(Theme.OptionsSound.SelectSlideVoicePassthrough, + Ini.VoicePassthrough, IVoicePassthrough); + AddSelectSlide(Theme.OptionsSound.SelectBackgroundMusic, + Ini.BackgroundMusicOption, IBackgroundMusic); + AddSelectSlide(Theme.OptionsSound.SelectMicBoost, Ini.MicBoost, IMicBoost); + // TODO: - MicBoost needs to be moved to ScreenOptionsRecord + AddSelectSlide(Theme.OptionsSound.SelectClickAssist, Ini.ClickAssist, IClickAssist); + AddSelectSlide(Theme.OptionsSound.SelectBeatClick, Ini.BeatClick, IBeatClick); + AddSelectSlide(Theme.OptionsSound.SelectThreshold, Ini.ThresholdIndex, IThreshold); + AddSelectSlide(Theme.OptionsSound.SelectSlidePreviewVolume, + Ini.PreviewVolume, IPreviewVolume); + AddSelectSlide(Theme.OptionsSound.SelectSlidePreviewFading, + Ini.PreviewFading, IPreviewFading); + + AddButton(Theme.OptionsSound.ButtonExit); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + + Interaction := 0; +end; + +procedure TScreenOptionsSound.onShow; +begin + inherited; + Interaction := 0; +end; + +end. diff --git a/src/screens/UScreenOptionsThemes.pas b/src/screens/UScreenOptionsThemes.pas new file mode 100644 index 00000000..a4f00b64 --- /dev/null +++ b/src/screens/UScreenOptionsThemes.pas @@ -0,0 +1,171 @@ +unit UScreenOptionsThemes; + +interface + +{$I switches.inc} + +uses + SDL, + UMenu, + UDisplay, + UMusic, + UFiles, + UIni, + UThemes; + +type + TScreenOptionsThemes = class(TMenu) + private + procedure ReloadTheme; + public + SkinSelect: Integer; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure InteractInc; override; + procedure InteractDec; override; + end; + +implementation + +uses UMain, + UGraphic, + USkins, + SysUtils; + +function TScreenOptionsThemes.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + // Escape -> save nothing - just leave this screen + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + SDLK_RETURN: + begin + if SelInteraction = 3 then + begin + Ini.Save; + + // Reload all screens, after Theme changed + // Todo : JB - Check if theme was actually changed + UGraphic.UnLoadScreens(); + UGraphic.LoadScreens(); + + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenOptions); + end; + end; + SDLK_DOWN: + InteractNext; + SDLK_UP : + InteractPrev; + SDLK_RIGHT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 2) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + end; + end; + SDLK_LEFT: + begin + if (SelInteraction >= 0) and (SelInteraction <= 2) then + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + end; + end; + end; + end; +end; + +procedure TScreenOptionsThemes.InteractInc; +begin + inherited InteractInc; + + //Update Skins + if (SelInteraction = 0) then + begin + Skin.OnThemeChange; + UpdateSelectSlideOptions (Theme.OptionsThemes.SelectSkin, SkinSelect, ISkin, Ini.SkinNo); + end; + + ReloadTheme(); +end; + +procedure TScreenOptionsThemes.InteractDec; +begin + inherited InteractDec; + + //Update Skins + if (SelInteraction = 0 ) then + begin + Skin.OnThemeChange; + UpdateSelectSlideOptions (Theme.OptionsThemes.SelectSkin, SkinSelect, ISkin, Ini.SkinNo); + end; + + ReloadTheme(); +end; + +constructor TScreenOptionsThemes.Create; +var + I: integer; +begin + inherited Create; + + LoadFromTheme(Theme.OptionsThemes); + + AddSelectSlide(Theme.OptionsThemes.SelectTheme, Ini.Theme, ITheme); + + SkinSelect := AddSelectSlide(Theme.OptionsThemes.SelectSkin, Ini.SkinNo, ISkin); + + AddSelectSlide(Theme.OptionsThemes.SelectColor, Ini.Color, IColor); + + AddButton(Theme.OptionsThemes.ButtonExit); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); +end; + +procedure TScreenOptionsThemes.onShow; +begin + inherited; + + Interaction := 0; +end; + +procedure TScreenOptionsThemes.ReloadTheme; +begin + Theme.LoadTheme(ThemePath + ITheme[Ini.Theme] + '.ini', Ini.Color); + + ScreenOptionsThemes := TScreenOptionsThemes.create(); + ScreenOptionsThemes.onshow; + Display.CurrentScreen := @ScreenOptionsThemes; + + ScreenOptionsThemes.Interaction := self.Interaction; + ScreenOptionsThemes.Draw; + + + Display.Draw; + SwapBuffers; + + freeandnil( self ); +end; + +end. diff --git a/src/screens/UScreenPartyNewRound.pas b/src/screens/UScreenPartyNewRound.pas new file mode 100644 index 00000000..057344dc --- /dev/null +++ b/src/screens/UScreenPartyNewRound.pas @@ -0,0 +1,439 @@ +unit UScreenPartyNewRound; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenPartyNewRound = class(TMenu) + public + //Texts: + TextRound1: Cardinal; + TextRound2: Cardinal; + TextRound3: Cardinal; + TextRound4: Cardinal; + TextRound5: Cardinal; + TextRound6: Cardinal; + TextRound7: Cardinal; + + TextWinner1: Cardinal; + TextWinner2: Cardinal; + TextWinner3: Cardinal; + TextWinner4: Cardinal; + TextWinner5: Cardinal; + TextWinner6: Cardinal; + TextWinner7: Cardinal; + + TextNextRound: Cardinal; + TextNextRoundNo: Cardinal; + TextNextPlayer1: Cardinal; + TextNextPlayer2: Cardinal; + TextNextPlayer3: Cardinal; + + //Statics + StaticRound1: Cardinal; + StaticRound2: Cardinal; + StaticRound3: Cardinal; + StaticRound4: Cardinal; + StaticRound5: Cardinal; + StaticRound6: Cardinal; + StaticRound7: Cardinal; + + //Scores + TextScoreTeam1: Cardinal; + TextScoreTeam2: Cardinal; + TextScoreTeam3: Cardinal; + TextNameTeam1: Cardinal; + TextNameTeam2: Cardinal; + TextNameTeam3: Cardinal; + + TextTeam1Players: Cardinal; + TextTeam2Players: Cardinal; + TextTeam3Players: Cardinal; + + StaticTeam1: Cardinal; + StaticTeam2: Cardinal; + StaticTeam3: Cardinal; + StaticNextPlayer1: Cardinal; + StaticNextPlayer2: Cardinal; + StaticNextPlayer3: Cardinal; + + + + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, + UMain, + UIni, + UTexture, + UParty, + UDLLManager, + ULanguage, + USong, + ULog; + +function TScreenPartyNewRound.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + CheckFadeTo(@ScreenMain,'MSG_END_PARTY'); + end; + + SDLK_RETURN: + begin + AudioPlayback.PlaySound(SoundLib.Start); + if DLLMan.Selected.LoadSong then + begin + //Select PartyMode ScreenSong + ScreenSong.Mode := smPartyMode; + FadeTo(@ScreenSong); + end + else + begin + FadeTo(@ScreenSingModi); + end; + end; + end; + end; +end; + +constructor TScreenPartyNewRound.Create; +var + I: integer; +begin + inherited Create; + + TextRound1 := AddText (Theme.PartyNewRound.TextRound1); + TextRound2 := AddText (Theme.PartyNewRound.TextRound2); + TextRound3 := AddText (Theme.PartyNewRound.TextRound3); + TextRound4 := AddText (Theme.PartyNewRound.TextRound4); + TextRound5 := AddText (Theme.PartyNewRound.TextRound5); + TextRound6 := AddText (Theme.PartyNewRound.TextRound6); + TextRound7 := AddText (Theme.PartyNewRound.TextRound7); + + TextWinner1 := AddText (Theme.PartyNewRound.TextWinner1); + TextWinner2 := AddText (Theme.PartyNewRound.TextWinner2); + TextWinner3 := AddText (Theme.PartyNewRound.TextWinner3); + TextWinner4 := AddText (Theme.PartyNewRound.TextWinner4); + TextWinner5 := AddText (Theme.PartyNewRound.TextWinner5); + TextWinner6 := AddText (Theme.PartyNewRound.TextWinner6); + TextWinner7 := AddText (Theme.PartyNewRound.TextWinner7); + + TextNextRound := AddText (Theme.PartyNewRound.TextNextRound); + TextNextRoundNo := AddText (Theme.PartyNewRound.TextNextRoundNo); + TextNextPlayer1 := AddText (Theme.PartyNewRound.TextNextPlayer1); + TextNextPlayer2 := AddText (Theme.PartyNewRound.TextNextPlayer2); + TextNextPlayer3 := AddText (Theme.PartyNewRound.TextNextPlayer3); + + StaticRound1 := AddStatic (Theme.PartyNewRound.StaticRound1); + StaticRound2 := AddStatic (Theme.PartyNewRound.StaticRound2); + StaticRound3 := AddStatic (Theme.PartyNewRound.StaticRound3); + StaticRound4 := AddStatic (Theme.PartyNewRound.StaticRound4); + StaticRound5 := AddStatic (Theme.PartyNewRound.StaticRound5); + StaticRound6 := AddStatic (Theme.PartyNewRound.StaticRound6); + StaticRound7 := AddStatic (Theme.PartyNewRound.StaticRound7); + + //Scores + TextScoreTeam1 := AddText (Theme.PartyNewRound.TextScoreTeam1); + TextScoreTeam2 := AddText (Theme.PartyNewRound.TextScoreTeam2); + TextScoreTeam3 := AddText (Theme.PartyNewRound.TextScoreTeam3); + TextNameTeam1 := AddText (Theme.PartyNewRound.TextNameTeam1); + TextNameTeam2 := AddText (Theme.PartyNewRound.TextNameTeam2); + TextNameTeam3 := AddText (Theme.PartyNewRound.TextNameTeam3); + + //Players + TextTeam1Players := AddText (Theme.PartyNewRound.TextTeam1Players); + TextTeam2Players := AddText (Theme.PartyNewRound.TextTeam2Players); + TextTeam3Players := AddText (Theme.PartyNewRound.TextTeam3Players); + + StaticTeam1 := AddStatic (Theme.PartyNewRound.StaticTeam1); + StaticTeam2 := AddStatic (Theme.PartyNewRound.StaticTeam2); + StaticTeam3 := AddStatic (Theme.PartyNewRound.StaticTeam3); + StaticNextPlayer1 := AddStatic (Theme.PartyNewRound.StaticNextPlayer1); + StaticNextPlayer2 := AddStatic (Theme.PartyNewRound.StaticNextPlayer2); + StaticNextPlayer3 := AddStatic (Theme.PartyNewRound.StaticNextPlayer3); + + LoadFromTheme(Theme.PartyNewRound); +end; + +procedure TScreenPartyNewRound.onShow; +var + I: Integer; + function GetTeamPlayers(const Num: Byte): String; + var + Players: Array of String; + J: Byte; + begin // to-do : Party + if (Num-1 >= {PartySession.Teams.NumTeams}0) then + exit; + + {//Create Players Array + SetLength(Players, PartySession.Teams.TeamInfo[Num-1].NumPlayers); + For J := 0 to PartySession.Teams.TeamInfo[Num-1].NumPlayers-1 do + Players[J] := String(PartySession.Teams.TeamInfo[Num-1].PlayerInfo[J].Name);} + + //Implode and Return + Result := Language.Implode(Players); + end; +begin + inherited; + + // to-do : Party + //PartySession.StartRound; + + //Set Visibility of Round Infos + // to-do : Party + I := {Length(PartySession.Rounds)}0; + if (I >= 1) then + begin + Static[StaticRound1].Visible := True; + Text[TextRound1].Visible := True; + Text[TextWinner1].Visible := True; + + //Texts: + //Text[TextRound1].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[0].Plugin].Name); + //Text[TextWinner1].Text := PartySession.GetWinnerString(0); + end + else + begin + Static[StaticRound1].Visible := False; + Text[TextRound1].Visible := False; + Text[TextWinner1].Visible := False; + end; + + if (I >= 2) then + begin + Static[StaticRound2].Visible := True; + Text[TextRound2].Visible := True; + Text[TextWinner2].Visible := True; + + //Texts: + //Text[TextRound2].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[1].Plugin].Name); + //Text[TextWinner2].Text := PartySession.GetWinnerString(1); + end + else + begin + Static[StaticRound2].Visible := False; + Text[TextRound2].Visible := False; + Text[TextWinner2].Visible := False; + end; + + if (I >= 3) then + begin + Static[StaticRound3].Visible := True; + Text[TextRound3].Visible := True; + Text[TextWinner3].Visible := True; + + //Texts: + //Text[TextRound3].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[2].Plugin].Name); + //Text[TextWinner3].Text := PartySession.GetWinnerString(2); + end + else + begin + Static[StaticRound3].Visible := False; + Text[TextRound3].Visible := False; + Text[TextWinner3].Visible := False; + end; + + if (I >= 4) then + begin + Static[StaticRound4].Visible := True; + Text[TextRound4].Visible := True; + Text[TextWinner4].Visible := True; + + //Texts: + //Text[TextRound4].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[3].Plugin].Name); + //Text[TextWinner4].Text := PartySession.GetWinnerString(3); + end + else + begin + Static[StaticRound4].Visible := False; + Text[TextRound4].Visible := False; + Text[TextWinner4].Visible := False; + end; + + if (I >= 5) then + begin + Static[StaticRound5].Visible := True; + Text[TextRound5].Visible := True; + Text[TextWinner5].Visible := True; + + //Texts: + //Text[TextRound5].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[4].Plugin].Name); + //Text[TextWinner5].Text := PartySession.GetWinnerString(4); + end + else + begin + Static[StaticRound5].Visible := False; + Text[TextRound5].Visible := False; + Text[TextWinner5].Visible := False; + end; + + if (I >= 6) then + begin + Static[StaticRound6].Visible := True; + Text[TextRound6].Visible := True; + Text[TextWinner6].Visible := True; + + //Texts: + //Text[TextRound6].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[5].Plugin].Name); + //Text[TextWinner6].Text := PartySession.GetWinnerString(5); + end + else + begin + Static[StaticRound6].Visible := False; + Text[TextRound6].Visible := False; + Text[TextWinner6].Visible := False; + end; + + if (I >= 7) then + begin + Static[StaticRound7].Visible := True; + Text[TextRound7].Visible := True; + Text[TextWinner7].Visible := True; + + //Texts: + //Text[TextRound7].Text := Language.Translate(DllMan.Plugins[PartySession.Rounds[6].Plugin].Name); + //Text[TextWinner7].Text := PartySession.GetWinnerString(6); + end + else + begin + Static[StaticRound7].Visible := False; + Text[TextRound7].Visible := False; + Text[TextWinner7].Visible := False; + end; + + //Display Scores + {if (PartySession.Teams.NumTeams >= 1) then + begin + Text[TextScoreTeam1].Text := InttoStr(PartySession.Teams.TeamInfo[0].Score); + Text[TextNameTeam1].Text := String(PartySession.Teams.TeamInfo[0].Name); + Text[TextTeam1Players].Text := GetTeamPlayers(1); + + Text[TextScoreTeam1].Visible := True; + Text[TextNameTeam1].Visible := True; + Text[TextTeam1Players].Visible := True; + Static[StaticTeam1].Visible := True; + Static[StaticNextPlayer1].Visible := True; + end + else + begin + Text[TextScoreTeam1].Visible := False; + Text[TextNameTeam1].Visible := False; + Text[TextTeam1Players].Visible := False; + Static[StaticTeam1].Visible := False; + Static[StaticNextPlayer1].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 2) then + begin + Text[TextScoreTeam2].Text := InttoStr(PartySession.Teams.TeamInfo[1].Score); + Text[TextNameTeam2].Text := String(PartySession.Teams.TeamInfo[1].Name); + Text[TextTeam2Players].Text := GetTeamPlayers(2); + + Text[TextScoreTeam2].Visible := True; + Text[TextNameTeam2].Visible := True; + Text[TextTeam2Players].Visible := True; + Static[StaticTeam2].Visible := True; + Static[StaticNextPlayer2].Visible := True; + end + else + begin + Text[TextScoreTeam2].Visible := False; + Text[TextNameTeam2].Visible := False; + Text[TextTeam2Players].Visible := False; + Static[StaticTeam2].Visible := False; + Static[StaticNextPlayer2].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 3) then + begin + Text[TextScoreTeam3].Text := InttoStr(PartySession.Teams.TeamInfo[2].Score); + Text[TextNameTeam3].Text := String(PartySession.Teams.TeamInfo[2].Name); + Text[TextTeam3Players].Text := GetTeamPlayers(3); + + Text[TextScoreTeam3].Visible := True; + Text[TextNameTeam3].Visible := True; + Text[TextTeam3Players].Visible := True; + Static[StaticTeam3].Visible := True; + Static[StaticNextPlayer3].Visible := True; + end + else + begin + Text[TextScoreTeam3].Visible := False; + Text[TextNameTeam3].Visible := False; + Text[TextTeam3Players].Visible := False; + Static[StaticTeam3].Visible := False; + Static[StaticNextPlayer3].Visible := False; + end; + + //nextRound Texts + Text[TextNextRound].Text := Language.Translate(DllMan.Selected.PluginDesc); + Text[TextNextRoundNo].Text := InttoStr(PartySession.CurRound + 1); + if (PartySession.Teams.NumTeams >= 1) then + begin + Text[TextNextPlayer1].Text := PartySession.Teams.Teaminfo[0].Playerinfo[PartySession.Teams.Teaminfo[0].CurPlayer].Name; + Text[TextNextPlayer1].Visible := True; + end + else + Text[TextNextPlayer1].Visible := False; + + if (PartySession.Teams.NumTeams >= 2) then + begin + Text[TextNextPlayer2].Text := PartySession.Teams.Teaminfo[1].Playerinfo[PartySession.Teams.Teaminfo[1].CurPlayer].Name; + Text[TextNextPlayer2].Visible := True; + end + else + Text[TextNextPlayer2].Visible := False; + + if (PartySession.Teams.NumTeams >= 3) then + begin + Text[TextNextPlayer3].Text := PartySession.Teams.Teaminfo[2].Playerinfo[PartySession.Teams.Teaminfo[2].CurPlayer].Name; + Text[TextNextPlayer3].Visible := True; + end + else + Text[TextNextPlayer3].Visible := False; } + + +// LCD.WriteText(1, ' Choose mode: '); +// UpdateLCD; +end; + +procedure TScreenPartyNewRound.SetAnimationProgress(Progress: real); +begin + {Button[0].Texture.ScaleW := Progress; + Button[1].Texture.ScaleW := Progress; + Button[2].Texture.ScaleW := Progress; } +end; + +end. diff --git a/src/screens/UScreenPartyOptions.pas b/src/screens/UScreenPartyOptions.pas new file mode 100644 index 00000000..bd05e653 --- /dev/null +++ b/src/screens/UScreenPartyOptions.pas @@ -0,0 +1,279 @@ +unit UScreenPartyOptions; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenPartyOptions = class(TMenu) + public + SelectLevel: Cardinal; + SelectPlayList: Cardinal; + SelectPlayList2: Cardinal; + SelectRounds: Cardinal; + SelectTeams: Cardinal; + SelectPlayers1: Cardinal; + SelectPlayers2: Cardinal; + SelectPlayers3: Cardinal; + + PlayList: Integer; + PlayList2: Integer; + Rounds: Integer; + NumTeams: Integer; + NumPlayer1, NumPlayer2, NumPlayer3: Integer; + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + procedure SetPlaylist2; + end; + +var + IPlaylist: array[0..2] of String; + IPlaylist2: array of String; +const + ITeams: array[0..1] of String =('2', '3'); + IPlayers: array[0..3] of String =('1', '2', '3', '4'); + IRounds: array[0..5] of String = ('2', '3', '4', '5', '6', '7'); + +implementation + +uses UGraphic, UMain, UIni, UTexture, ULanguage, UParty, USong, UDLLManager, UPlaylist, USongs; + +function TScreenPartyOptions.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; + var + I, J: Integer; + OnlyMultiPlayer: boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end; + + SDLK_RETURN: + begin + //Don'T start when Playlist is Selected and there are no Playlists + If (Playlist = 2) and (Length(PlaylistMan.Playlists) = 0) then + Exit; + // Don't start when SinglePlayer Teams but only Multiplayer Plugins available + OnlyMultiPlayer:=true; + for I := 0 to High(DLLMan.Plugins) do begin + OnlyMultiPlayer := (OnlyMultiPlayer AND DLLMan.Plugins[I].TeamModeOnly); + end; + if (OnlyMultiPlayer) AND ((NumPlayer1 = 0) OR (NumPlayer2 = 0) OR ((NumPlayer3 = 0) AND (NumTeams = 1))) then begin + ScreenPopupError.ShowPopup(Language.Translate('ERROR_NO_PLUGINS')); + Exit; + end; + //Save Difficulty + Ini.Difficulty := SelectsS[SelectLevel].SelectedOption; + Ini.SaveLevel; + + + //Save Num Teams: + {PartySession.Teams.NumTeams := NumTeams + 2; + PartySession.Teams.Teaminfo[0].NumPlayers := NumPlayer1+1; + PartySession.Teams.Teaminfo[1].NumPlayers := NumPlayer2+1; + PartySession.Teams.Teaminfo[2].NumPlayers := NumPlayer3+1;} + + //Save Playlist + PlaylistMan.Mode := TSingMode( Playlist ); + PlaylistMan.CurPlayList := High(Cardinal); + //If Category Selected Search Category ID + if Playlist = 1 then + begin + J := -1; + For I := 0 to high(CatSongs.Song) do + begin + if CatSongs.Song[I].Main then + Inc(J); + + if J = Playlist2 then + begin + PlaylistMan.CurPlayList := I; + Break; + end; + end; + + //No Categorys or Invalid Entry + If PlaylistMan.CurPlayList = High(Cardinal) then + Exit; + end + else + PlaylistMan.CurPlayList := Playlist2; + + //Start Party + // to-do : Party + //PartySession.StartNewParty(Rounds + 2); + + AudioPlayback.PlaySound(SoundLib.Start); + //Go to Player Screen + FadeTo(@ScreenPartyPlayer); + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + SDLK_RIGHT: + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractInc; + + //Change Playlist2 if Playlist is Changed + If (Interaction = 1) then + begin + SetPlaylist2; + end //Change Team3 Players visibility + Else If (Interaction = 4) then + begin + SelectsS[7].Visible := (NumTeams = 1); + end; + end; + SDLK_LEFT: + begin + AudioPlayback.PlaySound(SoundLib.Option); + InteractDec; + + //Change Playlist2 if Playlist is Changed + If (Interaction = 1) then + begin + SetPlaylist2; + end //Change Team3 Players visibility + Else If (Interaction = 4) then + begin + SelectsS[7].Visible := (NumTeams = 1); + end; + end; + end; + end; +end; + +constructor TScreenPartyOptions.Create; +var + I: integer; +begin + inherited Create; + //Fill IPlaylist + IPlaylist[0] := Language.Translate('PARTY_PLAYLIST_ALL'); + IPlaylist[1] := Language.Translate('PARTY_PLAYLIST_CATEGORY'); + IPlaylist[2] := Language.Translate('PARTY_PLAYLIST_PLAYLIST'); + + //Fill IPlaylist2 + SetLength(IPlaylist2, 1); + IPlaylist2[0] := '---'; + + //Clear all Selects + NumTeams := 0; + NumPlayer1 := 0; + NumPlayer2 := 0; + NumPlayer3 := 0; + Rounds := 5; + PlayList := 0; + PlayList2 := 0; + + //Load Screen From Theme + LoadFromTheme(Theme.PartyOptions); + + SelectLevel := AddSelectSlide (Theme.PartyOptions.SelectLevel, Ini.Difficulty, Theme.ILevel); + SelectPlayList := AddSelectSlide (Theme.PartyOptions.SelectPlayList, PlayList, IPlaylist); + SelectPlayList2 := AddSelectSlide (Theme.PartyOptions.SelectPlayList2, PlayList2, IPlaylist2); + SelectRounds := AddSelectSlide (Theme.PartyOptions.SelectRounds, Rounds, IRounds); + SelectTeams := AddSelectSlide (Theme.PartyOptions.SelectTeams, NumTeams, ITeams); + SelectPlayers1 := AddSelectSlide (Theme.PartyOptions.SelectPlayers1, NumPlayer1, IPlayers); + SelectPlayers2 := AddSelectSlide (Theme.PartyOptions.SelectPlayers2, NumPlayer2, IPlayers); + SelectPlayers3 := AddSelectSlide (Theme.PartyOptions.SelectPlayers3, NumPlayer3, IPlayers); + + Interaction := 0; + + //Hide Team3 Players + SelectsS[7].Visible := False; +end; + +procedure TScreenPartyOptions.SetPlaylist2; +var I: Integer; +begin + Case Playlist of + 0: + begin + SetLength(IPlaylist2, 1); + IPlaylist2[0] := '---'; + end; + 1: + begin + SetLength(IPlaylist2, 0); + For I := 0 to high(CatSongs.Song) do + begin + If (CatSongs.Song[I].Main) then + begin + SetLength(IPlaylist2, Length(IPlaylist2) + 1); + IPlaylist2[high(IPlaylist2)] := CatSongs.Song[I].Artist; + end; + end; + + If (Length(IPlaylist2) = 0) then + begin + SetLength(IPlaylist2, 1); + IPlaylist2[0] := 'No Categories found'; + end; + end; + 2: + begin + if (Length(PlaylistMan.Playlists) > 0) then + begin + SetLength(IPlaylist2, Length(PlaylistMan.Playlists)); + PlaylistMan.GetNames(IPlaylist2); + end + else + begin + SetLength(IPlaylist2, 1); + IPlaylist2[0] := 'No Playlists found'; + end; + end; + end; + + Playlist2 := 0; + UpdateSelectSlideOptions(Theme.PartyOptions.SelectPlayList2, 2, IPlaylist2, Playlist2); +end; + +procedure TScreenPartyOptions.onShow; +begin + inherited; + + Randomize; + +// LCD.WriteText(1, ' Choose mode: '); +// UpdateLCD; +end; + +procedure TScreenPartyOptions.SetAnimationProgress(Progress: real); +begin + {for I := 0 to 6 do + SelectS[I].Texture.ScaleW := Progress;} +end; + +end. diff --git a/src/screens/UScreenPartyPlayer.pas b/src/screens/UScreenPartyPlayer.pas new file mode 100644 index 00000000..fa717677 --- /dev/null +++ b/src/screens/UScreenPartyPlayer.pas @@ -0,0 +1,340 @@ +unit UScreenPartyPlayer; + +Interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenPartyPlayer = class(TMenu) + public + Team1Name: Cardinal; + Player1Name: Cardinal; + Player2Name: Cardinal; + Player3Name: Cardinal; + Player4Name: Cardinal; + + Team2Name: Cardinal; + Player5Name: Cardinal; + Player6Name: Cardinal; + Player7Name: Cardinal; + Player8Name: Cardinal; + + Team3Name: Cardinal; + Player9Name: Cardinal; + Player10Name: Cardinal; + Player11Name: Cardinal; + Player12Name: Cardinal; + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, UMain, UIni, UTexture, UParty; + +function TScreenPartyPlayer.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var +{*I, *}J: integer; // Auto Removed, Unused Variable (I) + SDL_ModState: Word; + procedure IntNext; + begin + repeat + InteractNext; + until Button[Interaction].Visible; + end; + procedure IntPrev; + begin + repeat + InteractPrev; + until Button[Interaction].Visible; + end; +begin + Result := true; + + if (PressedDown) then + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT) + else + SDL_ModState := 0; + + begin // Key Down + // check normal keys + case CharCode of + '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"': + begin + Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode; + Exit; + end; + end; + + // check special keys + case PressedKey of + // Templates for Names Mod + SDLK_F1: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[0] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[0]; + end; + SDLK_F2: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[1] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[1]; + end; + SDLK_F3: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[2] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[2]; + end; + SDLK_F4: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[3] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[3]; + end; + SDLK_F5: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[4] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[4]; + end; + SDLK_F6: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[5] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[5]; + end; + SDLK_F7: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[6] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[6]; + end; + SDLK_F8: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[7] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[7]; + end; + SDLK_F9: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[8] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[8]; + end; + SDLK_F10: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[9] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[9]; + end; + SDLK_F11: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[10] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[10]; + end; + SDLK_F12: + if (SDL_ModState = KMOD_LALT) then + begin + Ini.NameTemplate[11] := Button[Interaction].Text[0].Text; + end + else + begin + Button[Interaction].Text[0].Text := Ini.NameTemplate[11]; + end; + + SDLK_BACKSPACE: + begin + Button[Interaction].Text[0].DeleteLastL; + end; + + SDLK_ESCAPE: + begin + Ini.SaveNames; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenPartyOptions); + end; + + SDLK_RETURN: + begin + + {//Save PlayerNames + for I := 0 to PartySession.Teams.NumTeams-1 do + begin + PartySession.Teams.Teaminfo[I].Name := PChar(Button[I*5].Text[0].Text); + for J := 0 to PartySession.Teams.Teaminfo[I].NumPlayers-1 do + begin + PartySession.Teams.Teaminfo[I].Playerinfo[J].Name := PChar(Button[I*5 + J+1].Text[0].Text); + PartySession.Teams.Teaminfo[I].Playerinfo[J].TimesPlayed := 0; + end; + end; + + AudioPlayback.PlayStart; + FadeTo(@ScreenPartyNewRound);} + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: IntNext; + SDLK_UP: IntPrev; + SDLK_RIGHT: IntNext; + SDLK_LEFT: IntPrev; + end; + end; +end; + +constructor TScreenPartyPlayer.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + LoadFromTheme(Theme.PartyPlayer); + + Team1Name := AddButton(Theme.PartyPlayer.Team1Name); + AddButton(Theme.PartyPlayer.Player1Name); + AddButton(Theme.PartyPlayer.Player2Name); + AddButton(Theme.PartyPlayer.Player3Name); + AddButton(Theme.PartyPlayer.Player4Name); + + Team2Name := AddButton(Theme.PartyPlayer.Team2Name); + AddButton(Theme.PartyPlayer.Player5Name); + AddButton(Theme.PartyPlayer.Player6Name); + AddButton(Theme.PartyPlayer.Player7Name); + AddButton(Theme.PartyPlayer.Player8Name); + + Team3Name := AddButton(Theme.PartyPlayer.Team3Name); + AddButton(Theme.PartyPlayer.Player9Name); + AddButton(Theme.PartyPlayer.Player10Name); + AddButton(Theme.PartyPlayer.Player11Name); + AddButton(Theme.PartyPlayer.Player12Name); + + Interaction := 0; +end; + +procedure TScreenPartyPlayer.onShow; +var + I: integer; +begin + inherited; + + // Templates for Names Mod + for I := 1 to 4 do + Button[I].Text[0].Text := Ini.Name[I-1]; + + for I := 6 to 9 do + Button[I].Text[0].Text := Ini.Name[I-2]; + + for I := 11 to 14 do + Button[I].Text[0].Text := Ini.Name[I-3]; + + Button[0].Text[0].Text := Ini.NameTeam[0]; + Button[5].Text[0].Text := Ini.NameTeam[1]; + Button[10].Text[0].Text := Ini.NameTeam[2]; + // Templates for Names Mod end + + {If (PartySession.Teams.NumTeams>=1) then + begin + Button[0].Visible := True; + Button[1].Visible := (PartySession.Teams.Teaminfo[0].NumPlayers >=1); + Button[2].Visible := (PartySession.Teams.Teaminfo[0].NumPlayers >=2); + Button[3].Visible := (PartySession.Teams.Teaminfo[0].NumPlayers >=3); + Button[4].Visible := (PartySession.Teams.Teaminfo[0].NumPlayers >=4); + end + else + begin + Button[0].Visible := False; + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := False; + Button[4].Visible := False; + end; + + If (PartySession.Teams.NumTeams>=2) then + begin + Button[5].Visible := True; + Button[6].Visible := (PartySession.Teams.Teaminfo[1].NumPlayers >=1); + Button[7].Visible := (PartySession.Teams.Teaminfo[1].NumPlayers >=2); + Button[8].Visible := (PartySession.Teams.Teaminfo[1].NumPlayers >=3); + Button[9].Visible := (PartySession.Teams.Teaminfo[1].NumPlayers >=4); + end + else + begin + Button[5].Visible := False; + Button[6].Visible := False; + Button[7].Visible := False; + Button[8].Visible := False; + Button[9].Visible := False; + end; + + If (PartySession.Teams.NumTeams>=3) then + begin + Button[10].Visible := True; + Button[11].Visible := (PartySession.Teams.Teaminfo[2].NumPlayers >=1); + Button[12].Visible := (PartySession.Teams.Teaminfo[2].NumPlayers >=2); + Button[13].Visible := (PartySession.Teams.Teaminfo[2].NumPlayers >=3); + Button[14].Visible := (PartySession.Teams.Teaminfo[2].NumPlayers >=4); + end + else + begin + Button[10].Visible := False; + Button[11].Visible := False; + Button[12].Visible := False; + Button[13].Visible := False; + Button[14].Visible := False; + end; } + +end; + +procedure TScreenPartyPlayer.SetAnimationProgress(Progress: real); +var + I: integer; +begin + for I := 0 to high(Button) do + Button[I].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenPartyScore.pas b/src/screens/UScreenPartyScore.pas new file mode 100644 index 00000000..176a94b2 --- /dev/null +++ b/src/screens/UScreenPartyScore.pas @@ -0,0 +1,302 @@ +unit UScreenPartyScore; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, SysUtils, UThemes; + +type + TScreenPartyScore = class(TMenu) + public + TextScoreTeam1: Cardinal; + TextScoreTeam2: Cardinal; + TextScoreTeam3: Cardinal; + TextNameTeam1: Cardinal; + TextNameTeam2: Cardinal; + TextNameTeam3: Cardinal; + StaticTeam1: Cardinal; + StaticTeam1BG: Cardinal; + StaticTeam1Deco: Cardinal; + StaticTeam2: Cardinal; + StaticTeam2BG: Cardinal; + StaticTeam2Deco: Cardinal; + StaticTeam3: Cardinal; + StaticTeam3BG: Cardinal; + StaticTeam3Deco: Cardinal; + TextWinner: Cardinal; + + DecoTex: Array[0..5] of Integer; + DecoColor: Array[0..5] of Record + R, G, B: Real; + end; + + MaxScore: Word; + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, UMain, UParty, UScreenSingModi, ULanguage, UTexture, USkins; + +function TScreenPartyScore.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Start); + {if (PartySession.CurRound < High(PartySession.Rounds)) then + FadeTo(@ScreenPartyNewRound) + else // to-do : Party + begin + PartySession.EndRound; } + FadeTo(@ScreenPartyWin); + //end; + end; + + SDLK_RETURN: + begin + AudioPlayback.PlaySound(SoundLib.Start); + // to-do : Party + {if (PartySession.CurRound < High(PartySession.Rounds)) then + FadeTo(@ScreenPartyNewRound) + else } + FadeTo(@ScreenPartyWin); + end; + end; + end; +end; + +constructor TScreenPartyScore.Create; +var +// I: integer; // Auto Removed, Unused Variable + Tex: TTexture; + R, G, B: Real; + Color: Integer; +begin + inherited Create; + + TextScoreTeam1 := AddText (Theme.PartyScore.TextScoreTeam1); + TextScoreTeam2 := AddText (Theme.PartyScore.TextScoreTeam2); + TextScoreTeam3 := AddText (Theme.PartyScore.TextScoreTeam3); + TextNameTeam1 := AddText (Theme.PartyScore.TextNameTeam1); + TextNameTeam2 := AddText (Theme.PartyScore.TextNameTeam2); + TextNameTeam3 := AddText (Theme.PartyScore.TextNameTeam3); + + StaticTeam1 := AddStatic (Theme.PartyScore.StaticTeam1); + StaticTeam1BG := AddStatic (Theme.PartyScore.StaticTeam1BG); + StaticTeam1Deco := AddStatic (Theme.PartyScore.StaticTeam1Deco); + StaticTeam2 := AddStatic (Theme.PartyScore.StaticTeam2); + StaticTeam2BG := AddStatic (Theme.PartyScore.StaticTeam2BG); + StaticTeam2Deco := AddStatic (Theme.PartyScore.StaticTeam2Deco); + StaticTeam3 := AddStatic (Theme.PartyScore.StaticTeam3); + StaticTeam3BG := AddStatic (Theme.PartyScore.StaticTeam3BG); + StaticTeam3Deco := AddStatic (Theme.PartyScore.StaticTeam3Deco); + + TextWinner := AddText (Theme.PartyScore.TextWinner); + + //Load Deco Textures + if Theme.PartyScore.DecoTextures.ChangeTextures then + begin + //Get Color + LoadColor(R, G, B, Theme.PartyScore.DecoTextures.FirstColor); + Color := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255); + DecoColor[0].R := R; + DecoColor[0].G := G; + DecoColor[0].B := B; + + //Load Texture + Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.FirstTexture)), Theme.PartyScore.DecoTextures.FirstTyp, Color); + DecoTex[0] := Tex.TexNum; + + //Get Second Color + LoadColor(R, G, B, Theme.PartyScore.DecoTextures.SecondColor); + Color := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255); + DecoColor[1].R := R; + DecoColor[1].G := G; + DecoColor[1].B := B; + + //Load Second Texture + Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.SecondTexture)), Theme.PartyScore.DecoTextures.SecondTyp, Color); + DecoTex[1] := Tex.TexNum; + + //Get Third Color + LoadColor(R, G, B, Theme.PartyScore.DecoTextures.ThirdColor); + Color := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255); + DecoColor[2].R := R; + DecoColor[2].G := G; + DecoColor[2].B := B; + + //Load Third Texture + Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.ThirdTexture)), Theme.PartyScore.DecoTextures.ThirdTyp, Color); + DecoTex[2] := Tex.TexNum; + end; + + LoadFromTheme(Theme.PartyScore); +end; + +procedure TScreenPartyScore.onShow; +var + I, J: Integer; + Placings: Array [0..5] of Byte; +begin + inherited; + + + //Get Maxscore + + MaxScore := 0; + for I := 0 to ScreenSingModi.PlayerInfo.NumPlayers - 1 do + begin + if (ScreenSingModi.PlayerInfo.Playerinfo[I].Score > MaxScore) then + MaxScore := ScreenSingModi.PlayerInfo.Playerinfo[I].Score; + end; + + //Get Placings + for I := 0 to ScreenSingModi.PlayerInfo.NumPlayers - 1 do + begin + Placings[I] := 0; + for J := 0 to ScreenSingModi.PlayerInfo.NumPlayers - 1 do + If (ScreenSingModi.PlayerInfo.Playerinfo[J].Score > ScreenSingModi.PlayerInfo.Playerinfo[I].Score) then + Inc(Placings[I]); + end; + + + //Set Static Length + Static[StaticTeam1].Texture.ScaleW := ScreenSingModi.PlayerInfo.Playerinfo[0].Percentage / 100; + Static[StaticTeam2].Texture.ScaleW := ScreenSingModi.PlayerInfo.Playerinfo[1].Percentage / 100; + Static[StaticTeam3].Texture.ScaleW := ScreenSingModi.PlayerInfo.Playerinfo[2].Percentage / 100; + + //fix: prevents static from drawn out of bounds. + if Static[StaticTeam1].Texture.ScaleW > 99 then Static[StaticTeam1].Texture.ScaleW := 99; + if Static[StaticTeam2].Texture.ScaleW > 99 then Static[StaticTeam2].Texture.ScaleW := 99; + if Static[StaticTeam3].Texture.ScaleW > 99 then Static[StaticTeam3].Texture.ScaleW := 99; + + //End Last Round // to-do : Party + //PartySession.EndRound; + + //Set Winnertext + //Text[TextWinner].Text := Format(Language.Translate('PARTY_SCORE_WINS'), [PartySession.GetWinnerString(PartySession.CurRound)]); + + if (ScreenSingModi.PlayerInfo.NumPlayers >= 1) then + begin + Text[TextScoreTeam1].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[0].Score); + Text[TextNameTeam1].Text := String(ScreenSingModi.TeamInfo.Teaminfo[0].Name); + + //Set Deco Texture + if Theme.PartyScore.DecoTextures.ChangeTextures then + begin + Static[StaticTeam1Deco].Texture.TexNum := DecoTex[Placings[0]]; + Static[StaticTeam1Deco].Texture.ColR := DecoColor[Placings[0]].R; + Static[StaticTeam1Deco].Texture.ColG := DecoColor[Placings[0]].G; + Static[StaticTeam1Deco].Texture.ColB := DecoColor[Placings[0]].B; + end; + + Text[TextScoreTeam1].Visible := True; + Text[TextNameTeam1].Visible := True; + Static[StaticTeam1].Visible := True; + Static[StaticTeam1BG].Visible := True; + Static[StaticTeam1Deco].Visible := True; + end + else + begin + Text[TextScoreTeam1].Visible := False; + Text[TextNameTeam1].Visible := False; + Static[StaticTeam1].Visible := False; + Static[StaticTeam1BG].Visible := False; + Static[StaticTeam1Deco].Visible := False; + end; + + if (ScreenSingModi.PlayerInfo.NumPlayers >= 2) then + begin + Text[TextScoreTeam2].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[1].Score); + Text[TextNameTeam2].Text := String(ScreenSingModi.TeamInfo.Teaminfo[1].Name); + + //Set Deco Texture + if Theme.PartyScore.DecoTextures.ChangeTextures then + begin + Static[StaticTeam2Deco].Texture.TexNum := DecoTex[Placings[1]]; + Static[StaticTeam2Deco].Texture.ColR := DecoColor[Placings[1]].R; + Static[StaticTeam2Deco].Texture.ColG := DecoColor[Placings[1]].G; + Static[StaticTeam2Deco].Texture.ColB := DecoColor[Placings[1]].B; + end; + + Text[TextScoreTeam2].Visible := True; + Text[TextNameTeam2].Visible := True; + Static[StaticTeam2].Visible := True; + Static[StaticTeam2BG].Visible := True; + Static[StaticTeam2Deco].Visible := True; + end + else + begin + Text[TextScoreTeam2].Visible := False; + Text[TextNameTeam2].Visible := False; + Static[StaticTeam2].Visible := False; + Static[StaticTeam2BG].Visible := False; + Static[StaticTeam2Deco].Visible := False; + end; + + if (ScreenSingModi.PlayerInfo.NumPlayers >= 3) then + begin + Text[TextScoreTeam3].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[2].Score); + Text[TextNameTeam3].Text := String(ScreenSingModi.TeamInfo.Teaminfo[2].Name); + + //Set Deco Texture + if Theme.PartyScore.DecoTextures.ChangeTextures then + begin + Static[StaticTeam3Deco].Texture.TexNum := DecoTex[Placings[2]]; + Static[StaticTeam3Deco].Texture.ColR := DecoColor[Placings[2]].R; + Static[StaticTeam3Deco].Texture.ColG := DecoColor[Placings[2]].G; + Static[StaticTeam3Deco].Texture.ColB := DecoColor[Placings[2]].B; + end; + + Text[TextScoreTeam3].Visible := True; + Text[TextNameTeam3].Visible := True; + Static[StaticTeam3].Visible := True; + Static[StaticTeam3BG].Visible := True; + Static[StaticTeam3Deco].Visible := True; + end + else + begin + Text[TextScoreTeam3].Visible := False; + Text[TextNameTeam3].Visible := False; + Static[StaticTeam3].Visible := False; + Static[StaticTeam3BG].Visible := False; + Static[StaticTeam3Deco].Visible := False; + end; + + +// LCD.WriteText(1, ' Choose mode: '); +// UpdateLCD; +end; + +procedure TScreenPartyScore.SetAnimationProgress(Progress: real); +begin + if (ScreenSingModi.PlayerInfo.NumPlayers >= 1) then + Static[StaticTeam1].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[0].Percentage / 100; + if (ScreenSingModi.PlayerInfo.NumPlayers >= 2) then + Static[StaticTeam2].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[1].Percentage / 100; + if (ScreenSingModi.PlayerInfo.NumPlayers >= 3) then + Static[StaticTeam3].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[2].Percentage / 100; +end; + +end. diff --git a/src/screens/UScreenPartyWin.pas b/src/screens/UScreenPartyWin.pas new file mode 100644 index 00000000..002c6f75 --- /dev/null +++ b/src/screens/UScreenPartyWin.pas @@ -0,0 +1,267 @@ +unit UScreenPartyWin; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, SysUtils, UThemes; + +type + TScreenPartyWin = class(TMenu) + public + TextScoreTeam1: Cardinal; + TextScoreTeam2: Cardinal; + TextScoreTeam3: Cardinal; + TextNameTeam1: Cardinal; + TextNameTeam2: Cardinal; + TextNameTeam3: Cardinal; + StaticTeam1: Cardinal; + StaticTeam1BG: Cardinal; + StaticTeam1Deco: Cardinal; + StaticTeam2: Cardinal; + StaticTeam2BG: Cardinal; + StaticTeam2Deco: Cardinal; + StaticTeam3: Cardinal; + StaticTeam3BG: Cardinal; + StaticTeam3Deco: Cardinal; + TextWinner: Cardinal; + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + end; + +implementation + +uses UGraphic, UMain, UParty, UScreenSingModi, ULanguage; + +function TScreenPartyWin.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenMain); + end; + + SDLK_RETURN: + begin + AudioPlayback.PlaySound(SoundLib.Start); + FadeTo(@ScreenMain); + end; + end; + end; +end; + +constructor TScreenPartyWin.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + TextScoreTeam1 := AddText (Theme.PartyWin.TextScoreTeam1); + TextScoreTeam2 := AddText (Theme.PartyWin.TextScoreTeam2); + TextScoreTeam3 := AddText (Theme.PartyWin.TextScoreTeam3); + TextNameTeam1 := AddText (Theme.PartyWin.TextNameTeam1); + TextNameTeam2 := AddText (Theme.PartyWin.TextNameTeam2); + TextNameTeam3 := AddText (Theme.PartyWin.TextNameTeam3); + + StaticTeam1 := AddStatic (Theme.PartyWin.StaticTeam1); + StaticTeam1BG := AddStatic (Theme.PartyWin.StaticTeam1BG); + StaticTeam1Deco := AddStatic (Theme.PartyWin.StaticTeam1Deco); + StaticTeam2 := AddStatic (Theme.PartyWin.StaticTeam2); + StaticTeam2BG := AddStatic (Theme.PartyWin.StaticTeam2BG); + StaticTeam2Deco := AddStatic (Theme.PartyWin.StaticTeam2Deco); + StaticTeam3 := AddStatic (Theme.PartyWin.StaticTeam3); + StaticTeam3BG := AddStatic (Theme.PartyWin.StaticTeam3BG); + StaticTeam3Deco := AddStatic (Theme.PartyWin.StaticTeam3Deco); + + TextWinner := AddText (Theme.PartyWin.TextWinner); + + LoadFromTheme(Theme.PartyWin); +end; + +procedure TScreenPartyWin.onShow; +//var +// I: Integer; // Auto Removed, Unused Variable +// Placing: Integer; // Auto Removed, Unused Variable + + Function GetTeamColor(Team: Byte): Cardinal; + var + NameString: String; + begin + NameString := 'P' + InttoStr(Team+1) + 'Dark'; + + Result := ColorExists(NameString); + end; + +begin + inherited; + + // to-do : Party + //Get Team Placing + //Placing := PartySession.GetTeamOrder; + + //Set Winnertext + //Text[TextWinner].Text := Format(Language.Translate('PARTY_SCORE_WINS'), [PartySession.Teams.Teaminfo[Placing[0]].Name]); + {if (PartySession.Teams.NumTeams >= 1) then + begin + Text[TextScoreTeam1].Text := InttoStr(PartySession.Teams.TeamInfo[Placing[0]].Score); + Text[TextNameTeam1].Text := String(PartySession.Teams.TeamInfo[Placing[0]].Name); + + Text[TextScoreTeam1].Visible := True; + Text[TextNameTeam1].Visible := True; + Static[StaticTeam1].Visible := True; + Static[StaticTeam1BG].Visible := True; + Static[StaticTeam1Deco].Visible := True; + + //Set Static Color to Team Color + If (Theme.PartyWin.StaticTeam1BG.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[0]); + if (I <> -1) then + begin + Static[StaticTeam1BG].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam1BG].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam1BG].Texture.ColB := Color[I].RGB.B; + end; + end; + + If (Theme.PartyWin.StaticTeam1.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[0]); + if (I <> -1) then + begin + Static[StaticTeam1].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam1].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam1].Texture.ColB := Color[I].RGB.B; + end; + end; + end + else + begin + Text[TextScoreTeam1].Visible := False; + Text[TextNameTeam1].Visible := False; + Static[StaticTeam1].Visible := False; + Static[StaticTeam1BG].Visible := False; + Static[StaticTeam1Deco].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 2) then + begin + Text[TextScoreTeam2].Text := InttoStr(PartySession.Teams.TeamInfo[Placing[1]].Score); + Text[TextNameTeam2].Text := String(PartySession.Teams.TeamInfo[Placing[1]].Name); + + Text[TextScoreTeam2].Visible := True; + Text[TextNameTeam2].Visible := True; + Static[StaticTeam2].Visible := True; + Static[StaticTeam2BG].Visible := True; + Static[StaticTeam2Deco].Visible := True; + + //Set Static Color to Team Color + If (Theme.PartyWin.StaticTeam2BG.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[1]); + if (I <> -1) then + begin + Static[StaticTeam2BG].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam2BG].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam2BG].Texture.ColB := Color[I].RGB.B; + end; + end; + + If (Theme.PartyWin.StaticTeam2.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[1]); + if (I <> -1) then + begin + Static[StaticTeam2].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam2].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam2].Texture.ColB := Color[I].RGB.B; + end; + end; + end + else + begin + Text[TextScoreTeam2].Visible := False; + Text[TextNameTeam2].Visible := False; + Static[StaticTeam2].Visible := False; + Static[StaticTeam2BG].Visible := False; + Static[StaticTeam2Deco].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 3) then + begin + Text[TextScoreTeam3].Text := InttoStr(PartySession.Teams.TeamInfo[Placing[2]].Score); + Text[TextNameTeam3].Text := String(PartySession.Teams.TeamInfo[Placing[2]].Name); + + Text[TextScoreTeam3].Visible := True; + Text[TextNameTeam3].Visible := True; + Static[StaticTeam3].Visible := True; + Static[StaticTeam3BG].Visible := True; + Static[StaticTeam3Deco].Visible := True; + + //Set Static Color to Team Color + If (Theme.PartyWin.StaticTeam3BG.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[2]); + if (I <> -1) then + begin + Static[StaticTeam3BG].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam3BG].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam3BG].Texture.ColB := Color[I].RGB.B; + end; + end; + + If (Theme.PartyWin.StaticTeam3.Color = 'TeamColor') then + begin + I := GetTeamColor(Placing[2]); + if (I <> -1) then + begin + Static[StaticTeam3].Texture.ColR := Color[I].RGB.R; + Static[StaticTeam3].Texture.ColG := Color[I].RGB.G; + Static[StaticTeam3].Texture.ColB := Color[I].RGB.B; + end; + end; + end + else + begin + Text[TextScoreTeam3].Visible := False; + Text[TextNameTeam3].Visible := False; + Static[StaticTeam3].Visible := False; + Static[StaticTeam3BG].Visible := False; + Static[StaticTeam3Deco].Visible := False; + end; } + + +// LCD.WriteText(1, ' Choose mode: '); +// UpdateLCD; +end; + +procedure TScreenPartyWin.SetAnimationProgress(Progress: real); +begin + {if (ScreenSingModi.PlayerInfo.NumPlayers >= 1) then + Static[StaticTeam1].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[0].Score / maxScore; + if (ScreenSingModi.PlayerInfo.NumPlayers >= 2) then + Static[StaticTeam2].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[1].Score / maxScore; + if (ScreenSingModi.PlayerInfo.NumPlayers >= 3) then + Static[StaticTeam3].Texture.ScaleW := Progress * ScreenSingModi.PlayerInfo.Playerinfo[2].Score / maxScore;} +end; + +end. diff --git a/src/screens/UScreenPopup.pas b/src/screens/UScreenPopup.pas new file mode 100644 index 00000000..b51fac98 --- /dev/null +++ b/src/screens/UScreenPopup.pas @@ -0,0 +1,252 @@ +unit UScreenPopup; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenPopupCheck = class(TMenu) + public + Visible: Boolean; //Whether the Menu should be Drawn + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure ShowPopup(msg: String); + function Draw: boolean; override; + end; + +type + TScreenPopupError = class(TMenu) +{ private + CurMenu: Byte; //Num of the cur. Shown Menu} + public + Visible: Boolean; //Whether the Menu should be Drawn + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure onHide; override; + procedure ShowPopup(msg: String); + function Draw: boolean; override; + end; + +var +// ISelections: Array of String; + SelectValue: Integer; + + +implementation + +uses UGraphic, UMain, UIni, UTexture, ULanguage, UParty, UPlaylist, UDisplay; + +function TScreenPopupCheck.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + Display.CheckOK:=False; + Display.NextScreenWithCheck:=NIL; + Visible:=False; + Result := false; + end; + + SDLK_RETURN: + begin + case Interaction of + 0: begin + //Hack to Finish Singscreen correct on Exit with Q Shortcut + if (Display.NextScreenWithCheck = NIL) then + begin + if (Display.CurrentScreen = @ScreenSing) then + ScreenSing.Finish + else if (Display.CurrentScreen = @ScreenSingModi) then + ScreenSingModi.Finish; + end; + + Display.CheckOK:=True; + end; + 1: begin + Display.CheckOK:=False; + Display.NextScreenWithCheck:=NIL; + end; + end; + Visible:=False; + Result := false; + end; + + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end; +end; + +constructor TScreenPopupCheck.Create; +var + I: integer; +begin + inherited Create; + + AddBackground(Theme.CheckPopup.Background.Tex); + + AddButton(Theme.CheckPopup.Button1); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, 'Button 1'); + + AddButton(Theme.CheckPopup.Button2); + if (Length(Button[1].Text) = 0) then + AddButtonText(14, 20, 'Button 2'); + + AddText(Theme.CheckPopup.TextCheck); + + for I := 0 to High(Theme.CheckPopup.Static) do + AddStatic(Theme.CheckPopup.Static[I]); + + for I := 0 to High(Theme.CheckPopup.Text) do + AddText(Theme.CheckPopup.Text[I]); + + Interaction := 0; +end; + +function TScreenPopupCheck.Draw: boolean; +begin + Draw:=inherited Draw; +end; + +procedure TScreenPopupCheck.onShow; +begin + inherited; +end; + +procedure TScreenPopupCheck.ShowPopup(msg: String); +begin + Interaction := 0; //Reset Interaction + Visible := True; //Set Visible + + Text[0].Text := Language.Translate(msg); + + Button[0].Visible := True; + Button[1].Visible := True; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_YES'); + Button[1].Text[0].Text := Language.Translate('SONG_MENU_NO'); +end; + +// error popup + +function TScreenPopupError.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + + case PressedKey of + SDLK_Q: + begin + Result := false; + end; + + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + Visible:=False; + Result := false; + end; + + SDLK_RETURN: + begin + Visible:=False; + Result := false; + end; + + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + + SDLK_RIGHT: InteractNext; + SDLK_LEFT: InteractPrev; + end; + end; +end; + +constructor TScreenPopupError.Create; +var + I: integer; +begin + inherited Create; + + AddBackground(Theme.CheckPopup.Background.Tex); + + AddButton(Theme.ErrorPopup.Button1); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, 'Button 1'); + + AddText(Theme.ErrorPopup.TextError); + + for I := 0 to High(Theme.ErrorPopup.Static) do + AddStatic(Theme.ErrorPopup.Static[I]); + + for I := 0 to High(Theme.ErrorPopup.Text) do + AddText(Theme.ErrorPopup.Text[I]); + + Interaction := 0; +end; + +function TScreenPopupError.Draw: boolean; +begin + Draw:=inherited Draw; +end; + +procedure TScreenPopupError.onShow; +begin + inherited; + +end; + +procedure TScreenPopupError.onHide; +begin +end; + +procedure TScreenPopupError.ShowPopup(msg: String); +begin + Interaction := 0; //Reset Interaction + Visible := True; //Set Visible + +{ //dirty hack... Text[0] is invisible for some strange reason + for i:=1 to high(Text) do + if i-1 <= high(msg) then + begin + Text[i].Visible:=True; + Text[i].Text := msg[i-1]; + end + else + begin + Text[i].Visible:=False; + end;} + Text[0].Text:=msg; + + Button[0].Visible := True; + + Button[0].Text[0].Text := 'OK'; +end; + +end. diff --git a/src/screens/UScreenScore.pas b/src/screens/UScreenScore.pas new file mode 100644 index 00000000..ab6c020d --- /dev/null +++ b/src/screens/UScreenScore.pas @@ -0,0 +1,848 @@ +unit UScreenScore; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, + SDL, + SysUtils, + UDisplay, + UMusic, + USongs, + UThemes, + gl, + math, + UTexture; + +const + ZBars : real = 0.8; // Z value for the bars + ZRatingPic : real = 0.8; // Z value for the rating pictures + + EaseOut_MaxSteps : real = 10; // that's the speed of the bars (10 is fast | 100 is slower) + + BarRaiseSpeed : cardinal = 0; // Time for raising the bar one step higher (in ms) + +type + TPlayerScoreScreenTexture = record // holds all colorized textures for up to 6 players + //Bar textures + Score_NoteBarLevel_Dark : TTexture; // Note + Score_NoteBarRound_Dark : TTexture; // that's the round thing on top + + Score_NoteBarLevel_Light : TTexture; // LineBonus | Phrasebonus + Score_NoteBarRound_Light : TTexture; + + Score_NoteBarLevel_Lightest : TTexture; // GoldenNotes + Score_NoteBarRound_Lightest : TTexture; + end; + + TPlayerScoreScreenData = record // holds the positions and other data + Bar_Y :Real; + Bar_Actual_Height : Real; // this one holds the actual height of the bar, while we animate it + BarScore_ActualHeight : Real; + BarLine_ActualHeight : Real; + BarGolden_ActualHeight : Real; + end; + + TPlayerScoreRatingPics = record // a fine array of the rating pictures + RateEaseStep : Integer; + RateEaseValue: Real; + end; + + TScreenScore = class(TMenu) + private + BarTime : Cardinal; + ArrayStartModifier : integer; + public + aPlayerScoreScreenTextures : array[1..6] of TPlayerScoreScreenTexture; + aPlayerScoreScreenDatas : array[1..6] of TPlayerScoreScreenData; + aPlayerScoreScreenRatings : array[1..6] of TPlayerScoreRatingPics; + + BarScore_EaseOut_Step : real; + BarPhrase_EaseOut_Step : real; + BarGolden_EaseOut_Step : real; + + TextArtist: integer; + TextTitle: integer; + + TextArtistTitle : integer; + + TextName: array[1..6] of integer; + TextScore: array[1..6] of integer; + + TextNotes: array[1..6] of integer; + TextNotesScore: array[1..6] of integer; + TextLineBonus: array[1..6] of integer; + TextLineBonusScore: array[1..6] of integer; + TextGoldenNotes: array[1..6] of integer; + TextGoldenNotesScore: array[1..6] of integer; + TextTotal: array[1..6] of integer; + TextTotalScore: array[1..6] of integer; + + PlayerStatic: array[1..6] of array of integer; + PlayerTexts : array[1..6] of array of integer; + + + StaticBoxLightest: array[1..6] of integer; + StaticBoxLight: array[1..6] of integer; + StaticBoxDark: array[1..6] of integer; + + StaticBackLevel: array[1..6] of integer; + StaticBackLevelRound: array[1..6] of integer; + StaticLevel: array[1..6] of integer; + StaticLevelRound: array[1..6] of integer; + + Animation: real; + + TextScore_ActualValue : array[1..6] of integer; + TextPhrase_ActualValue : array[1..6] of integer; + TextGolden_ActualValue : array[1..6] of integer; + + + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure onShowFinish; override; + function Draw: boolean; override; + procedure FillPlayer(Item, P: integer); + + procedure EaseBarIn(PlayerNumber : Integer; BarType: String); + procedure EaseScoreIn(PlayerNumber : Integer; ScoreType: String); + + procedure FillPlayerItems(PlayerNumber : Integer; ScoreType: String); + + + procedure DrawBar(BarType:string; PlayerNumber: integer; BarStartPosY: single; NewHeight: real); + + //Rating Picture + procedure ShowRating(PlayerNumber: integer); + function CalculateBouncing(PlayerNumber : Integer): real; + procedure DrawRating(PlayerNumber:integer;Rating:integer); + end; + +implementation + + +uses UGraphic, + UScreenSong, + UMenuStatic, + UTime, + UMain, + UIni, + ULog, + ULanguage; + +function TScreenScore.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then begin + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE, + SDLK_RETURN: + begin + FadeTo(@ScreenTop5); + Exit; + end; + + SDLK_SYSREQ: + begin + Display.SaveScreenShot; + end; + end; + end; +end; + +constructor TScreenScore.Create; +var + Player: integer; + Counter: integer; +begin + inherited Create; + + LoadFromTheme(Theme.Score); + + // These two texts arn't used in the deluxe skin + TextArtist := AddText(Theme.Score.TextArtist); + TextTitle := AddText(Theme.Score.TextTitle); + + TextArtistTitle := AddText(Theme.Score.TextArtistTitle); + + for Player := 1 to 6 do + begin + SetLength(PlayerStatic[Player], Length(Theme.Score.PlayerStatic[Player])); + SetLength(PlayerTexts[Player], Length(Theme.Score.PlayerTexts[Player])); + + for Counter := 0 to High(Theme.Score.PlayerStatic[Player]) do + PlayerStatic[Player, Counter] := AddStatic(Theme.Score.PlayerStatic[Player, Counter]); + + for Counter := 0 to High(Theme.Score.PlayerTexts[Player]) do + PlayerTexts[Player, Counter] := AddText(Theme.Score.PlayerTexts[Player, Counter]); + + TextName[Player] := AddText(Theme.Score.TextName[Player]); + TextScore[Player] := AddText(Theme.Score.TextScore[Player]); + + TextNotes[Player] := AddText(Theme.Score.TextNotes[Player]); + TextNotesScore[Player] := AddText(Theme.Score.TextNotesScore[Player]); + TextLineBonus[Player] := AddText(Theme.Score.TextLineBonus[Player]); + TextLineBonusScore[Player] := AddText(Theme.Score.TextLineBonusScore[Player]); + TextGoldenNotes[Player] := AddText(Theme.Score.TextGoldenNotes[Player]); + TextGoldenNotesScore[Player] := AddText(Theme.Score.TextGoldenNotesScore[Player]); + TextTotal[Player] := AddText(Theme.Score.TextTotal[Player]); + TextTotalScore[Player] := AddText(Theme.Score.TextTotalScore[Player]); + + StaticBoxLightest[Player] := AddStatic(Theme.Score.StaticBoxLightest[Player]); + StaticBoxLight[Player] := AddStatic(Theme.Score.StaticBoxLight[Player]); + StaticBoxDark[Player] := AddStatic(Theme.Score.StaticBoxDark[Player]); + + StaticBackLevel[Player] := AddStatic(Theme.Score.StaticBackLevel[Player]); + StaticBackLevelRound[Player] := AddStatic(Theme.Score.StaticBackLevelRound[Player]); + StaticLevel[Player] := AddStatic(Theme.Score.StaticLevel[Player]); + StaticLevelRound[Player] := AddStatic(Theme.Score.StaticLevelRound[Player]); + + //textures + aPlayerScoreScreenTextures[Player].Score_NoteBarLevel_Dark := Tex_Score_NoteBarLevel_Dark[Player]; + aPlayerScoreScreenTextures[Player].Score_NoteBarRound_Dark := Tex_Score_NoteBarRound_Dark[Player]; + + aPlayerScoreScreenTextures[Player].Score_NoteBarLevel_Light := Tex_Score_NoteBarLevel_Light[Player]; + aPlayerScoreScreenTextures[Player].Score_NoteBarRound_Light := Tex_Score_NoteBarRound_Light[Player]; + + aPlayerScoreScreenTextures[Player].Score_NoteBarLevel_Lightest := Tex_Score_NoteBarLevel_Lightest[Player]; + aPlayerScoreScreenTextures[Player].Score_NoteBarRound_Lightest := Tex_Score_NoteBarRound_Lightest[Player]; + end; + +end; + +procedure TScreenScore.onShow; +var + P: integer; // player + I: integer; + V: array[1..6] of boolean; // visibility array + +begin + +{** + * Turn backgroundmusic on + *} + SoundLib.StartBgMusic; + + inherited; + + // all statics / texts are loaded at start - so that we have them all even if we change the amount of players + // To show the corrects statics / text from the them, we simply modify the start of the according arrays + // 1 Player -> Player[0].Score (The score for one player starts at 0) + // -> Statics[1] (The statics for the one player screen start at 1) + // 2 Player -> Player[0..1].Score + // -> Statics[2..3] + // 3 Player -> Player[0..5].Score + // -> Statics[4..6] + case PlayersPlay of + 1: ArrayStartModifier := 0; + 2, 4: ArrayStartModifier := 1; + 3, 6: ArrayStartModifier := 3; + else + ArrayStartModifier := 0; //this should never happen + end; + + for P := 1 to PlayersPlay do + begin + // data + aPlayerScoreScreenDatas[P].Bar_Y := Theme.Score.StaticBackLevel[P + ArrayStartModifier].Y; + + // ratings + aPlayerScoreScreenRatings[P].RateEaseStep := 1; + aPlayerScoreScreenRatings[P].RateEaseValue := 20; + end; + + + Text[TextArtist].Text := CurrentSong.Artist; + Text[TextTitle].Text := CurrentSong.Title; + Text[TextArtistTitle].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title; + + // set visibility + case PlayersPlay of + 1: begin + V[1] := true; + V[2] := false; + V[3] := false; + V[4] := false; + V[5] := false; + V[6] := false; + end; + 2, 4: begin + V[1] := false; + V[2] := true; + V[3] := true; + V[4] := false; + V[5] := false; + V[6] := false; + end; + 3, 6: begin + V[1] := false; + V[2] := false; + V[3] := false; + V[4] := true; + V[5] := true; + V[6] := true; + end; + end; + + for P := 1 to 6 do + begin + Text[TextName[P]].Visible := V[P]; + Text[TextScore[P]].Visible := V[P]; + + // We set alpha to 0 , so we can nicely blend them in when we need them + Text[TextScore[P]].Alpha := 0; + Text[TextNotesScore[P]].Alpha := 0; + Text[TextNotes[P]].Alpha := 0; + Text[TextLineBonus[P]].Alpha := 0; + Text[TextLineBonusScore[P]].Alpha := 0; + Text[TextGoldenNotes[P]].Alpha := 0; + Text[TextGoldenNotesScore[P]].Alpha := 0; + Text[TextTotal[P]].Alpha := 0; + Text[TextTotalScore[P]].Alpha := 0; + Static[StaticBoxLightest[P]].Texture.Alpha := 0; + Static[StaticBoxLight[P]].Texture.Alpha := 0; + Static[StaticBoxDark[P]].Texture.Alpha := 0; + + + Text[TextNotes[P]].Visible := V[P]; + Text[TextNotesScore[P]].Visible := V[P]; + Text[TextLineBonus[P]].Visible := V[P]; + Text[TextLineBonusScore[P]].Visible := V[P]; + Text[TextGoldenNotes[P]].Visible := V[P]; + Text[TextGoldenNotesScore[P]].Visible := V[P]; + Text[TextTotal[P]].Visible := V[P]; + Text[TextTotalScore[P]].Visible := V[P]; + + for I := 0 to high(PlayerStatic[P]) do + Static[PlayerStatic[P, I]].Visible := V[P]; + + for I := 0 to high(PlayerTexts[P]) do + Text[PlayerTexts[P, I]].Visible := V[P]; + + Static[StaticBoxLightest[P]].Visible := V[P]; + Static[StaticBoxLight[P]].Visible := V[P]; + Static[StaticBoxDark[P]].Visible := V[P]; + + // we draw that on our own + Static[StaticBackLevel[P]].Visible := false; + Static[StaticBackLevelRound[P]].Visible := false; + Static[StaticLevel[P]].Visible := false; + Static[StaticLevelRound[P]].Visible := false; + end; +end; + +procedure TScreenScore.onShowFinish; +var + index : integer; +begin + for index := 1 to (PlayersPlay) do + begin + TextScore_ActualValue[index] := 0; + TextPhrase_ActualValue[index] := 0; + TextGolden_ActualValue[index] := 0; + end; + + BarScore_EaseOut_Step := 1; + BarPhrase_EaseOut_Step := 1; + BarGolden_EaseOut_Step := 1; +end; + +function TScreenScore.Draw: boolean; +var + CurrentTime : Cardinal; + PlayerCounter : integer; +begin + + inherited Draw; +{* + player[0].ScoreInt := 7000; + player[0].ScoreLineInt := 2000; + player[0].ScoreGoldenInt := 1000; + player[0].ScoreTotalInt := 10000; + + player[1].ScoreInt := 2500; + player[1].ScoreLineInt := 1100; + player[1].ScoreGoldenInt := 900; + player[1].ScoreTotalInt := 4500; +*} + // Let's start to arise the bars + CurrentTime := SDL_GetTicks(); + if((CurrentTime >= BarTime) AND ShowFinish) then + begin + BarTime := CurrentTime + BarRaiseSpeed; + + for PlayerCounter := 1 to PlayersPlay do + begin + // We actually arise them in the right order, but we have to draw them in reverse order (golden -> phrase -> mainscore) + if (BarScore_EaseOut_Step < EaseOut_MaxSteps * 10) then + BarScore_EaseOut_Step:= BarScore_EaseOut_Step + 1; + + // PhrasenBonus + if (BarScore_EaseOut_Step >= (EaseOut_MaxSteps * 10)) then + begin + if (BarPhrase_EaseOut_Step < EaseOut_MaxSteps * 10) then + BarPhrase_EaseOut_Step := BarPhrase_EaseOut_Step + 1; + + + // GoldenNotebonus + if (BarPhrase_EaseOut_Step >= (EaseOut_MaxSteps * 10)) then + begin + if (BarGolden_EaseOut_Step < EaseOut_MaxSteps * 10) then + BarGolden_EaseOut_Step := BarGolden_EaseOut_Step + 1; + + // Draw golden score bar # + EaseBarIn(PlayerCounter, 'Golden'); + EaseScoreIn(PlayerCounter,'Golden'); + end; + + // Draw phrase score bar # + EaseBarIn(PlayerCounter, 'Line'); + EaseScoreIn(PlayerCounter,'Line'); + end; + + // Draw plain score bar # + EaseBarIn(PlayerCounter, 'Note'); + EaseScoreIn(PlayerCounter,'Note'); + + + FillPlayerItems(PlayerCounter,'Funky'); + + end; + end; + + +(* + //todo: i need a clever method to draw statics with their z value + for I := 0 to Length(Static) - 1 do + Static[I].Draw; + for I := 0 to Length(Text) - 1 do + Text[I].Draw; +*) + + Result := true; +end; + +procedure TscreenScore.FillPlayerItems(PlayerNumber : Integer; ScoreType: String); +var + ThemeIndex: integer; +begin + // todo: take the name from player[PlayerNumber].Name instead of the ini when this is done (mog) + Text[TextName[PlayerNumber + ArrayStartModifier]].Text := Ini.Name[PlayerNumber - 1]; + // end todo + + ThemeIndex := PlayerNumber + ArrayStartModifier; + + //golden + Text[TextGoldenNotesScore[ThemeIndex]].Text := IntToStr(TextGolden_ActualValue[PlayerNumber]); + Text[TextGoldenNotesScore[ThemeIndex]].Alpha := (BarGolden_EaseOut_Step / 100); + + Static[StaticBoxLightest[ThemeIndex]].Texture.Alpha := (BarGolden_EaseOut_Step / 100); + Text[TextGoldenNotes[ThemeIndex]].Alpha := (BarGolden_EaseOut_Step / 100); + + // line bonus + Text[TextLineBonusScore[ThemeIndex]].Text := IntToStr(TextPhrase_ActualValue[PlayerNumber]); + Text[TextLineBonusScore[ThemeIndex]].Alpha := (BarPhrase_EaseOut_Step / 100); + + Static[StaticBoxLight[ThemeIndex]].Texture.Alpha := (BarPhrase_EaseOut_Step / 100); + Text[TextLineBonus[ThemeIndex]].Alpha := (BarPhrase_EaseOut_Step / 100); + + // plain score + Text[TextNotesScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber]); + Text[TextNotes[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); + + Static[StaticBoxDark[ThemeIndex]].Texture.Alpha := (BarScore_EaseOut_Step / 100); + Text[TextNotesScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); + + // total score + Text[TextTotalScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber] + TextPhrase_ActualValue[PlayerNumber] + TextGolden_ActualValue[PlayerNumber]); + Text[TextTotalScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); + + Text[TextTotal[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); + + Text[TextTotal[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100); + + if(BarGolden_EaseOut_Step = 100) then + begin + ShowRating(PlayerNumber); + end; +end; + + +procedure TScreenScore.ShowRating(PlayerNumber: integer); +var + Rating : integer; + ThemeIndex : integer; +begin + + ThemeIndex := PlayerNumber + ArrayStartModifier; + + case (Player[PlayerNumber-1].ScoreTotalInt) of + 0..2009: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_TONE_DEAF'); + Rating := 0; + end; + 2010..4009: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_AMATEUR'); + Rating := 1; + end; + 4010..5009: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_WANNABE'); + Rating := 2; + end; + 5010..6009: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_HOPEFUL'); + Rating := 3; + end; + 6010..7509: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_RISING_STAR'); + Rating := 4; + end; + 7510..8509: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_LEAD_SINGER'); + Rating := 5; + end; + 8510..9009: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_SUPERSTAR'); + Rating := 6; + end; + 9010..10000: + begin + Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_ULTRASTAR'); + Rating := 7; + end; + else + Rating := 0; // Cheata :P + end; + + //todo: this could break if the width is not given, for instance when there's a skin with no picture for ratings + if ( Theme.Score.StaticRatings[ThemeIndex].W > 0 ) AND ( aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue > 0 ) then + begin + Text[TextScore[ThemeIndex]].Alpha := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue / Theme.Score.StaticRatings[ThemeIndex].W; + end; + // end todo + + DrawRating(PlayerNumber, Rating); +end; + +procedure TscreenScore.DrawRating(PlayerNumber:integer;Rating:integer); +var + Posx : real; + Posy : real; + Width :real; +begin + + CalculateBouncing(PlayerNumber); + + PosX := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].X + (Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].W * 0.5); + PosY := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].Y + (Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].H * 0.5); ; + + Width := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue/2; + + glBindTexture(GL_TEXTURE_2D, Tex_Score_Ratings[Rating].TexNum); + + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(PosX - Width, PosY - Width); + glTexCoord2f(Tex_Score_Ratings[Rating].TexW, 0); glVertex2f(PosX + Width, PosY - Width); + glTexCoord2f(Tex_Score_Ratings[Rating].TexW, Tex_Score_Ratings[Rating].TexH); glVertex2f(PosX + Width, PosY + Width); + glTexCoord2f(0, Tex_Score_Ratings[Rating].TexH); glVertex2f(PosX - Width, PosY + Width); + glEnd; + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2d); +end; + + + +function TscreenScore.CalculateBouncing(PlayerNumber : Integer): real; +var + ReturnValue : real; + p, s : real; + + RaiseStep, MaxVal : real; + EaseOut_Step : integer; +begin + EaseOut_Step := aPlayerScoreScreenRatings[PlayerNumber].RateEaseStep; + MaxVal := Theme.Score.StaticRatings[PlayerNumber + ArrayStartModifier].W; + + RaiseStep := EaseOut_Step; + + if (MaxVal > 0) AND (RaiseStep > 0) then + RaiseStep := RaiseStep / MaxVal; + + if (RaiseStep = 1) then + begin + ReturnValue := MaxVal; + end + else + begin + p := MaxVal * 0.4; + + s := p/(2*PI) * arcsin (1); + ReturnValue := MaxVal * power(2,-5 * RaiseStep) * sin( (RaiseStep * MaxVal - s) * (2 * PI) / p) + MaxVal; + + inc(aPlayerScoreScreenRatings[PlayerNumber].RateEaseStep); + aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue := ReturnValue; + end; + + Result := ReturnValue; +end; + + +procedure TscreenScore.EaseBarIn(PlayerNumber : Integer; BarType: String); +const + RaiseSmoothness : integer = 100; +var + MaxHeight : real; + NewHeight : real; + + Height2Reach : real; + RaiseStep : real; + BarStartPosY : single; + + lTmp : real; + Score : integer; +begin + MaxHeight := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].H; + + // let's get the points according to the bar we draw + // score array starts at 0, which means the score for player 1 is in score[0] + // EaseOut_Step is the actual step in the raising process, like the 20iest step of EaseOut_MaxSteps + if (BarType = 'Note') then + begin + Score := Player[PlayerNumber - 1].ScoreInt; + RaiseStep := BarScore_EaseOut_Step; + BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y + MaxHeight; + end + else if (BarType = 'Line') then + begin + Score := Player[PlayerNumber - 1].ScoreLineInt; + RaiseStep := BarPhrase_EaseOut_Step; + BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight + MaxHeight; + end + else if (BarType = 'Golden') then + begin + Score := Player[PlayerNumber - 1].ScoreGoldenInt; + RaiseStep := BarGolden_EaseOut_Step; + BarStartPosY := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight - aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight + MaxHeight; + end + else + begin + Log.LogCritical('Unknown bar-type: ' + BarType, 'TScreenScore.EaseBarIn'); + Exit; // suppress warnings + end; + + // the height dependend of the score + Height2Reach := (Score / MAX_SONG_SCORE) * MaxHeight; + + if (aPlayerScoreScreenDatas[PlayerNumber].Bar_Actual_Height < Height2Reach) then + begin + // Check http://proto.layer51.com/d.aspx?f=400 for more info on easing functions + // Calculate the actual step according to the maxsteps + RaiseStep := RaiseStep / EaseOut_MaxSteps; + + // quadratic easing out - decelerating to zero velocity + // -end_position * current_time * ( current_time - 2 ) + start_postion + lTmp := (-Height2Reach * RaiseStep * (RaiseStep - 20) + BarStartPosY); + + if ( RaiseSmoothness > 0 ) and ( lTmp > 0 ) then + NewHeight := lTmp / RaiseSmoothness; + + end + else + NewHeight := Height2Reach; + + DrawBar(BarType, PlayerNumber, BarStartPosY, NewHeight); + + if (BarType = 'Note') then + aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight := NewHeight + else if (BarType = 'Line') then + aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight := NewHeight + else if (BarType = 'Golden') then + aPlayerScoreScreenDatas[PlayerNumber].BarGolden_ActualHeight := NewHeight; +end; + +procedure TscreenScore.DrawBar(BarType:string; PlayerNumber: integer; BarStartPosY: single; NewHeight: real); +var + Width:real; + BarStartPosX:real; +begin + // this is solely for better readability of the drawing + Width := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].W; + BarStartPosX := Theme.Score.StaticBackLevel[PlayerNumber + ArrayStartModifier].X; + + glColor4f(1, 1, 1, 1); + + // set the texture for the bar + if (BarType = 'Note') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarLevel_Dark.TexNum); + if (BarType = 'Line') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarLevel_Light.TexNum); + if (BarType = 'Golden') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarLevel_Lightest.TexNum); + + //draw it + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex3f(BarStartPosX, BarStartPosY - NewHeight, ZBars); + glTexCoord2f(1, 0); glVertex3f(BarStartPosX + Width, BarStartPosY - NewHeight, ZBars); + glTexCoord2f(1, 1); glVertex3f(BarStartPosX + Width, BarStartPosY, ZBars); + glTexCoord2f(0, 1); glVertex3f(BarStartPosX, BarStartPosY, ZBars); + glEnd; + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2d); + + //the round thing on top + if (BarType = 'Note') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarRound_Dark.TexNum); + if (BarType = 'Line') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarRound_Light.TexNum); + if (BarType = 'Golden') then + glBindTexture(GL_TEXTURE_2D, aPlayerScoreScreenTextures[PlayerNumber].Score_NoteBarRound_Lightest.TexNum); + + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex3f(BarStartPosX, (BarStartPosY - Static[StaticLevelRound[PlayerNumber + ArrayStartModifier]].Texture.h) - NewHeight, ZBars); + glTexCoord2f(1, 0); glVertex3f(BarStartPosX + Width, (BarStartPosY - Static[StaticLevelRound[PlayerNumber + ArrayStartModifier]].Texture.h) - NewHeight, ZBars); + glTexCoord2f(1, 1); glVertex3f(BarStartPosX + Width, BarStartPosY - NewHeight, ZBars); + glTexCoord2f(0, 1); glVertex3f(BarStartPosX, BarStartPosY - NewHeight, ZBars); + glEnd; + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2d); +end; + +procedure TScreenScore.EaseScoreIn(PlayerNumber: integer; ScoreType : String); +const + RaiseSmoothness : integer = 100; +var + RaiseStep : Real; + lTmpA : Real; + ScoreReached :Integer; + EaseOut_Step :Real; + ActualScoreValue:integer; +begin + if (ScoreType = 'Note') then + begin + EaseOut_Step := BarScore_EaseOut_Step; + ActualScoreValue := TextScore_ActualValue[PlayerNumber]; + ScoreReached := Player[PlayerNumber-1].ScoreInt; + end; + if (ScoreType = 'Line') then + begin + EaseOut_Step := BarPhrase_EaseOut_Step; + ActualScoreValue := TextPhrase_ActualValue[PlayerNumber]; + ScoreReached := Player[PlayerNumber-1].ScoreLineInt; + end; + if (ScoreType = 'Golden') then + begin + EaseOut_Step := BarGolden_EaseOut_Step; + ActualScoreValue := TextGolden_ActualValue[PlayerNumber]; + ScoreReached := Player[PlayerNumber-1].ScoreGoldenInt; + end; + + // EaseOut_Step is the actual step in the raising process, like the 20iest step of EaseOut_MaxSteps + RaiseStep := EaseOut_Step; + + if (ActualScoreValue < ScoreReached) then + begin + // Calculate the actual step according to the maxsteps + RaiseStep := RaiseStep / EaseOut_MaxSteps; + + // quadratic easing out - decelerating to zero velocity + // -end_position * current_time * ( current_time - 2 ) + start_postion + lTmpA := (-ScoreReached * RaiseStep * (RaiseStep - 20)); + if ( lTmpA > 0 ) AND + ( RaiseSmoothness > 0 ) then + begin + if (ScoreType = 'Note') then + TextScore_ActualValue[PlayerNumber] := floor( lTmpA / RaiseSmoothness); + if (ScoreType = 'Line') then + TextPhrase_ActualValue[PlayerNumber] := floor( lTmpA / RaiseSmoothness); + if (ScoreType = 'Golden') then + TextGolden_ActualValue[PlayerNumber] := floor( lTmpA / RaiseSmoothness); + end; + end + else + begin + if (ScoreType = 'Note') then + TextScore_ActualValue[PlayerNumber] := ScoreReached; + if (ScoreType = 'Line') then + TextPhrase_ActualValue[PlayerNumber] := ScoreReached; + if (ScoreType = 'Golden') then + TextGolden_ActualValue[PlayerNumber] := ScoreReached; + end; +end; + +procedure TScreenScore.FillPlayer(Item, P: integer); +var + S: string; +begin + Text[TextName[Item]].Text := Ini.Name[P]; + + S := IntToStr((Round(Player[P].Score) div 10) * 10); + while (Length(S)<4) do + S := '0' + S; + Text[TextNotesScore[Item]].Text := S; + + // while (Length(S)<5) do S := '0' + S; + // Text[TextTotalScore[Item]].Text := S; + + //fixed: line bonus and golden notes don't show up, + // another bug: total score was shown without added golden-, linebonus + S := IntToStr(Player[P].ScoreTotalInt); + while (Length(S)<5) do + S := '0' + S; + Text[TextTotalScore[Item]].Text := S; + + S := IntToStr(Player[P].ScoreLineInt); + while (Length(S)<4) do + S := '0' + S; + Text[TextLineBonusScore[Item]].Text := S; + + S := IntToStr(Player[P].ScoreGoldenInt); + while (Length(S)<4) do + S := '0' + S; + Text[TextGoldenNotesScore[Item]].Text := S; + //end of fix + + +end; + +end. diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas new file mode 100644 index 00000000..911d122e --- /dev/null +++ b/src/screens/UScreenSing.pas @@ -0,0 +1,934 @@ +unit UScreenSing; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses UMenu, + UMusic, + SDL, + SysUtils, + UFiles, + UTime, + USongs, + UIni, + ULog, + UTexture, + ULyrics, + TextGL, + gl, + UThemes, + UGraphicClasses, + USingScores; + +type + TLyricsSyncSource = class(TSyncSource) + function GetClock(): real; override; + end; + +type + TScreenSing = class(TMenu) + protected + Paused: boolean; //Pause Mod + LyricsSync: TLyricsSyncSource; + NumEmptySentences: integer; + public + //TextTime: integer; + + // TimeBar fields + StaticTimeProgress: integer; + TextTimeText: integer; + + StaticP1: integer; + TextP1: integer; + + //shown when game is in 2/4 player modus + StaticP1TwoP: integer; + TextP1TwoP: integer; + + //shown when game is in 3/6 player modus + StaticP1ThreeP: integer; + TextP1ThreeP: integer; + + StaticP2R: integer; + TextP2R: integer; + + StaticP2M: integer; + TextP2M: integer; + + StaticP3R: integer; + TextP3R: integer; + + StaticPausePopup: integer; + + Tex_Background: TTexture; + FadeOut: boolean; + Lyrics: TLyricEngine; + + //Score Manager: + Scores: TSingScores; + + fShowVisualization: boolean; + fCurrentVideoPlaybackEngine: IVideoPlayback; + + constructor Create; override; + procedure onShow; override; + procedure onShowFinish; override; + + function ParseInput(PressedKey: cardinal; CharCode: widechar; + PressedDown: boolean): boolean; override; + function Draw: boolean; override; + + procedure Finish; virtual; + procedure Pause; // Toggle Pause + + procedure OnSentenceEnd(SentenceIndex: cardinal); // for LineBonus + Singbar + procedure OnSentenceChange(SentenceIndex: cardinal); // for Golden Notes + end; + +implementation + +uses UGraphic, + UDraw, + UMain, + USong, + Classes, + URecord, + ULanguage, + Math; + + // Method for input parsing. If False is returned, GetNextWindow + // should be checked to know the next window to load; +function TScreenSing.ParseInput(PressedKey: cardinal; CharCode: widechar; + PressedDown: boolean): boolean; +begin + Result := True; + if (PressedDown) then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + //When not ask before Exit then Finish now + if (Ini.AskbeforeDel <> 1) then + Finish + //else just Pause and let the Popup make the Work + else if not Paused then + Pause; + + Result := False; + Exit; + end; + 'V': //Show Visualization + begin + fShowVisualization := not fShowVisualization; + + if fShowVisualization then + fCurrentVideoPlaybackEngine := Visualization + else + fCurrentVideoPlaybackEngine := VideoPlayback; + + if fShowVisualization then + fCurrentVideoPlaybackEngine.play; + + Exit; + end; + 'P': + begin + Pause; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE: + begin + //Record Sound Hack: + //Sound[0].BufferLong + + Finish; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenScore); + end; + + SDLK_SPACE: + begin + Pause; + end; + + SDLK_TAB: //Change Visualization Preset + begin + if fShowVisualization then + fCurrentVideoPlaybackEngine.Position := now; // move to a random position + end; + + SDLK_RETURN: + begin + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: + begin + end; + SDLK_UP: + begin + end; + end; + end; +end; + +//Pause Mod +procedure TScreenSing.Pause; +begin + if (not Paused) then //enable Pause + begin + // pause Time + Paused := True; + + LyricsState.Pause(); + + // pause Music + AudioPlayback.Pause; + + // pause Video + if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path + + CurrentSong.Video) then + fCurrentVideoPlaybackEngine.Pause; + + end + else //disable Pause + begin + LyricsState.Resume(); + + // Play Music + AudioPlayback.Play; + + // Video + if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path + + CurrentSong.Video) then + fCurrentVideoPlaybackEngine.Pause; + + Paused := False; + end; +end; +//Pause Mod End + +constructor TScreenSing.Create; +var + I: integer; + P: integer; +begin + inherited Create; + + fShowVisualization := False; + + fCurrentVideoPlaybackEngine := VideoPlayback; + + //Create Score Class + Scores := TSingScores.Create; + Scores.LoadfromTheme; + + LoadFromTheme(Theme.Sing); + + //TimeBar + StaticTimeProgress := AddStatic(Theme.Sing.StaticTimeProgress); + TextTimeText := AddText(Theme.Sing.TextTimeText); + + // 1 player | P1 + StaticP1 := AddStatic(Theme.Sing.StaticP1); + TextP1 := AddText(Theme.Sing.TextP1); + + // 2 or 4 players | P1 + StaticP1TwoP := AddStatic(Theme.Sing.StaticP1TwoP); + TextP1TwoP := AddText(Theme.Sing.TextP1TwoP); + + // | P2 + StaticP2R := AddStatic(Theme.Sing.StaticP2R); + TextP2R := AddText(Theme.Sing.TextP2R); + + // 3 or 6 players | P1 + StaticP1ThreeP := AddStatic(Theme.Sing.StaticP1ThreeP); + TextP1ThreeP := AddText(Theme.Sing.TextP1ThreeP); + + // | P2 + StaticP2M := AddStatic(Theme.Sing.StaticP2M); + TextP2M := AddText(Theme.Sing.TextP2M); + + // | P3 + StaticP3R := AddStatic(Theme.Sing.StaticP3R); + TextP3R := AddText(Theme.Sing.TextP3R); + + StaticPausePopup := AddStatic(Theme.Sing.PausePopUp); + + //<note>Pausepopup is not visibile at the beginning</note> + Static[StaticPausePopup].Visible := False; + + Lyrics := TLyricEngine.Create(80, Skin_LyricsT, 640, 12, 80, Skin_LyricsT + 36, 640, 12); + + LyricsSync := TLyricsSyncSource.Create(); +end; + +procedure TScreenSing.onShow; +var + P: integer; + V1: boolean; + V1TwoP: boolean; //Position of ScoreBox in two-player mode + V1ThreeP: boolean; //Position of ScoreBox in three-player mode + V2R: boolean; + V2M: boolean; + V3R: boolean; + NR: TRecR; //Some enlightment of who, how and what this is here please + Color: TRGB; + + success: boolean; +begin + inherited; + + Log.LogStatus('Begin', 'onShow'); + FadeOut := False; + + // reset video playback engine, to play Video Clip... + fCurrentVideoPlaybackEngine := VideoPlayback; + + // setup score manager + Scores.ClearPlayers; // clear old player values + Color.R := 0; + Color.G := 0; + Color.B := 0; // dummy atm <- \(O.o)/? B like bummy? + + // add new players + for P := 0 to PlayersPlay - 1 do + begin + Scores.AddPlayer(Tex_ScoreBG[P], Color); + end; + + Scores.Init; //Get Positions for Players + + // prepare players + SetLength(Player, PlayersPlay); + + case PlayersPlay of + 1: + begin + V1 := True; + V1TwoP := False; + V1ThreeP := False; + V2R := False; + V2M := False; + V3R := False; + end; + 2: + begin + V1 := False; + V1TwoP := True; + V1ThreeP := False; + V2R := True; + V2M := False; + V3R := False; + end; + 3: + begin + V1 := False; + V1TwoP := False; + V1ThreeP := True; + V2R := False; + V2M := True; + V3R := True; + end; + 4: + begin // double screen + V1 := False; + V1TwoP := True; + V1ThreeP := False; + V2R := True; + V2M := False; + V3R := False; + end; + 6: + begin // double screen + V1 := False; + V1TwoP := False; + V1ThreeP := True; + V2R := False; + V2M := True; + V3R := True; + end; + + end; + + //This one is shown in 1P mode + Static[StaticP1].Visible := V1; + Text[TextP1].Visible := V1; + + + //This one is shown in 2/4P mode + Static[StaticP1TwoP].Visible := V1TwoP; + Text[TextP1TwoP].Visible := V1TwoP; + + Static[StaticP2R].Visible := V2R; + Text[TextP2R].Visible := V2R; + + + //This one is shown in 3/6P mode + Static[StaticP1ThreeP].Visible := V1ThreeP; + Text[TextP1ThreeP].Visible := V1ThreeP; + + + Static[StaticP2M].Visible := V2M; + Text[TextP2M].Visible := V2M; + + + Static[StaticP3R].Visible := V3R; + Text[TextP3R].Visible := V3R; + + + // FIXME: sets Path and Filename to '' + ResetSingTemp; + + CurrentSong := CatSongs.Song[CatSongs.Selected]; + + // FIXME: bad style, put the try-except into LoadSong() and not here + try + // Check if file is XML + if copy(CurrentSong.FileName, length(CurrentSong.FileName) - 3, 4) = '.xml' then + success := CurrentSong.LoadXMLSong() + else + success := CurrentSong.LoadSong(); + except + success := False; + end; + + if (not success) then + begin + // error loading song -> go back to song screen and show some error message + FadeTo(@ScreenSong); + // select new song in party mode + if ScreenSong.Mode = smPartyMode then + ScreenSong.SelectRandomSong(); + ScreenPopupError.ShowPopup(Language.Translate('ERROR_CORRUPT_SONG')); + // FIXME: do we need this? + CurrentSong.Path := CatSongs.Song[CatSongs.Selected].Path; + Exit; + end; + + // reset video playback engine, to play video clip... + fCurrentVideoPlaybackEngine.Close; + fCurrentVideoPlaybackEngine := VideoPlayback; +{** + * == Background == + * We have four types of backgrounds: + * + Blank : Nothing has been set, this is our fallback + * + Picture : Picture has been set, and exists - otherwise we fallback + * + Video : Video has been set, and exists - otherwise we fallback + * + Visualization: + Off : No Visialization + * + WhenNoVideo: Overwrites Blank and Picture + * + On : Overwrites Blank, Picture and Video + *} +{** + * set background to: video + *} + CurrentSong.VideoLoaded := False; + fShowVisualization := False; + if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path + CurrentSong.Video) then + begin + if (fCurrentVideoPlaybackEngine.Open(CurrentSong.Path + CurrentSong.Video)) then + begin + fShowVisualization := False; + fCurrentVideoPlaybackEngine := VideoPlayback; + fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + CurrentSong.Start; + CurrentSong.VideoLoaded := True; + fCurrentVideoPlaybackEngine.play; + end; + end; + +{** + * set background to: picture + *} + if (CurrentSong.Background <> '') and (CurrentSong.VideoLoaded = False) + and (TVisualizerOption(Ini.VisualizerOption) = voOff) then + try + Tex_Background := Texture.LoadTexture(CurrentSong.Path + CurrentSong.Background); + except + Log.LogError('Background could not be loaded: ' + CurrentSong.Path + + CurrentSong.Background); + Tex_Background.TexNum := 0; + end + else + Tex_Background.TexNum := 0; +{** + * set background to: visualization (Overwrites all) + *} + if (TVisualizerOption(Ini.VisualizerOption) in [voOn]) then + begin + fShowVisualization := True; + fCurrentVideoPlaybackEngine := Visualization; + fCurrentVideoPlaybackEngine.play; + end; + +{** + * set background to: visualization (Videos are still shown) + *} + if ((TVisualizerOption(Ini.VisualizerOption) in [voWhenNoVideo]) and + (CurrentSong.VideoLoaded = False)) then + begin + fShowVisualization := True; + fCurrentVideoPlaybackEngine := Visualization; + fCurrentVideoPlaybackEngine.play; + end; + + // prepare lyrics timer + LyricsState.Reset(); + LyricsState.SetCurrentTime(CurrentSong.Start); + LyricsState.StartTime := CurrentSong.Gap; + if (CurrentSong.Finish > 0) then + LyricsState.TotalTime := CurrentSong.Finish / 1000 + else + LyricsState.TotalTime := AudioPlayback.Length; + LyricsState.UpdateBeats(); + + // prepare music + AudioPlayback.Stop(); + AudioPlayback.Position := CurrentSong.Start; + // synchronize music to the lyrics + AudioPlayback.SetSyncSource(LyricsSync); + + // prepare and start voice-capture + AudioInput.CaptureStart; + + for P := 0 to High(Player) do + ClearScores(P); + + // main text + Lyrics.Clear(CurrentSong.BPM[0].BPM, CurrentSong.Resolution); + + // set custom options + case Ini.LyricsFont of + 0: + begin + Lyrics.UpperLineSize := 14; + Lyrics.LowerLineSize := 14; + Lyrics.FontStyle := 0; + + Lyrics.LineColor_en.R := Skin_FontR; + Lyrics.LineColor_en.G := Skin_FontG; + Lyrics.LineColor_en.B := Skin_FontB; + Lyrics.LineColor_en.A := 1; + + Lyrics.LineColor_dis.R := 0.4; + Lyrics.LineColor_dis.G := 0.4; + Lyrics.LineColor_dis.B := 0.4; + Lyrics.LineColor_dis.A := 1; + + Lyrics.LineColor_act.R := 5 / 256; + Lyrics.LineColor_act.G := 163 / 256; + Lyrics.LineColor_act.B := 210 / 256; + Lyrics.LineColor_act.A := 1; + end; + 1: + begin + Lyrics.UpperLineSize := 14; + Lyrics.LowerLineSize := 14; + Lyrics.FontStyle := 2; + + Lyrics.LineColor_en.R := 0.75; + Lyrics.LineColor_en.G := 0.75; + Lyrics.LineColor_en.B := 1; + Lyrics.LineColor_en.A := 1; + + Lyrics.LineColor_dis.R := 0.8; + Lyrics.LineColor_dis.G := 0.8; + Lyrics.LineColor_dis.B := 0.8; + Lyrics.LineColor_dis.A := 1; + + Lyrics.LineColor_act.R := 0.5; + Lyrics.LineColor_act.G := 0.5; + Lyrics.LineColor_act.B := 1; + Lyrics.LineColor_act.A := 1; + end; + 2: + begin + Lyrics.UpperLineSize := 12; + Lyrics.LowerLineSize := 12; + Lyrics.FontStyle := 3; + + Lyrics.LineColor_en.R := 0.75; + Lyrics.LineColor_en.G := 0.75; + Lyrics.LineColor_en.B := 1; + Lyrics.LineColor_en.A := 1; + + Lyrics.LineColor_dis.R := 0.8; + Lyrics.LineColor_dis.G := 0.8; + Lyrics.LineColor_dis.B := 0.8; + Lyrics.LineColor_dis.A := 1; + + Lyrics.LineColor_act.R := 0.5; + Lyrics.LineColor_act.G := 0.5; + Lyrics.LineColor_act.B := 1; + Lyrics.LineColor_act.A := 1; + end; + end; // case + + // Initialize lyrics by filling its queue + while (not Lyrics.IsQueueFull) and (Lyrics.LineCounter <= + High(Lines[0].Line)) do + begin + Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]); + end; + + // Deactivate pause + Paused := False; + + // Kill all stars not killed yet (GoldenStarsTwinkle Mod) + GoldenRec.SentenceChange; + + // set Position of Line Bonus - Line Bonus end + // set number of empty sentences for Line Bonus + NumEmptySentences := 0; + for P := Low(Lines[0].Line) to High(Lines[0].Line) do + if Lines[0].Line[P].TotalNotes = 0 then + Inc(NumEmptySentences); + + Log.LogStatus('End', 'onShow'); +end; + +procedure TScreenSing.onShowFinish; +begin + // start lyrics + LyricsState.Resume(); + + // start music + AudioPlayback.Play(); + + // start timer + CountSkipTimeSet; +end; + +function TScreenSing.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + Flash: real; + S: integer; + T: integer; + CurLyricsTime: real; +begin + + // set player names (for 2 screens and only Singstar skin) + if ScreenAct = 1 then + begin + Text[TextP1].Text := 'P1'; + Text[TextP1TwoP].Text := 'P1'; + Text[TextP1ThreeP].Text := 'P1'; + Text[TextP2R].Text := 'P2'; + Text[TextP2M].Text := 'P2'; + Text[TextP3R].Text := 'P3'; + end; + + if ScreenAct = 2 then + begin + case PlayersPlay of + 4: + begin + Text[TextP1TwoP].Text := 'P3'; + Text[TextP2R].Text := 'P4'; + end; + 6: + begin + Text[TextP1ThreeP].Text := 'P4'; + Text[TextP2M].Text := 'P5'; + Text[TextP3R].Text := 'P6'; + end; + end; // case + end; // if + + + //// + // dual screen, part 1 + //////////////////////// + + // Note: ScreenX is the offset of the current screen in dual-screen mode so we + // will move the statics and texts to the correct screen here. + // FIXME: clean up this weird stuff. Commenting this stuff out, nothing + // was missing on screen w/ 6 players - so do we even need this stuff? + Static[StaticP1].Texture.X := Static[StaticP1].Texture.X + 10 * ScreenX; + + Text[TextP1].X := Text[TextP1].X + 10 * ScreenX; + + {Static[StaticP1ScoreBG].Texture.X := Static[StaticP1ScoreBG].Texture.X + 10*ScreenX; + Text[TextP1Score].X := Text[TextP1Score].X + 10*ScreenX;} + + + Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X + 10 * ScreenX; + + Text[TextP2R].X := Text[TextP2R].X + 10 * ScreenX; + + {Static[StaticP2RScoreBG].Texture.X := Static[StaticP2RScoreBG].Texture.X + 10*ScreenX; + Text[TextP2RScore].X := Text[TextP2RScore].X + 10*ScreenX;} + + // end of weird stuff + + Static[1].Texture.X := Static[1].Texture.X + 10 * ScreenX; + + for T := 0 to 1 do + Text[T].X := Text[T].X + 10 * ScreenX; + + + + // retrieve current lyrics time, we have to store the value to avoid + // that min- and sec-values do not match + CurLyricsTime := LyricsState.GetCurrentTime(); + Min := Round(CurLyricsTime) div 60; + Sec := Round(CurLyricsTime) mod 60; + + // update static menu with time ... + Text[TextTimeText].Text := ''; + if Min < 10 then + Text[TextTimeText].Text := '0'; + Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Min) + ':'; + if Sec < 10 then + Text[TextTimeText].Text := Text[TextTimeText].Text + '0'; + Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Sec); + + // draw static menu (BG) + // Note: there is no menu and the animated background brakes the video playback + //DrawBG; + + // Draw Background + SingDrawBackground; + + // update and draw movie + if (ShowFinish and (CurrentSong.VideoLoaded or fShowVisualization)) then + begin + if assigned(fCurrentVideoPlaybackEngine) then + begin + fCurrentVideoPlaybackEngine.GetFrame(LyricsState.GetCurrentTime()); + fCurrentVideoPlaybackEngine.DrawGL(ScreenAct); + end; + end; + + // draw static menu (FG) + DrawFG; + + // check for music finish + //Log.LogError('Check for music finish: ' + BoolToStr(Music.Finished) + ' ' + FloatToStr(LyricsState.CurrentTime*1000) + ' ' + IntToStr(CurrentSong.Finish)); + if ShowFinish then + begin + if (not AudioPlayback.Finished) and ((CurrentSong.Finish = 0) or + (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) then + begin + // analyze song if not paused + if (not Paused) then + Sing(Self); + end + else + begin + if (not FadeOut) then + begin + Finish; + FadeOut := True; + FadeTo(@ScreenScore); + end; + end; + end; + + // always draw custom items + SingDraw; + + //GoldenNoteStarsTwinkle + GoldenRec.SpawnRec; + + //Draw Scores + Scores.Draw; + + //// + // dual screen, part 2 + //////////////////////// + + // Note: ScreenX is the offset of the current screen in dual-screen mode so we + // will move the statics and texts to the correct screen here. + // FIXME: clean up this weird stuff + + Static[StaticP1].Texture.X := Static[StaticP1].Texture.X - 10 * ScreenX; + Text[TextP1].X := Text[TextP1].X - 10 * ScreenX; + + Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X - 10 * ScreenX; + Text[TextP2R].X := Text[TextP2R].X - 10 * ScreenX; + + //end of weird + + Static[1].Texture.X := Static[1].Texture.X - 10 * ScreenX; + + for T := 0 to 1 do + Text[T].X := Text[T].X - 10 * ScreenX; + + // Draw Pausepopup + // FIXME: this is a workaround that the Static is drawn over the Lyrics, Lines, Scores and Effects + // maybe someone could find a better solution + if Paused then + begin + Static[StaticPausePopup].Visible := True; + Static[StaticPausePopup].Draw; + Static[StaticPausePopup].Visible := False; + end; + + Result := True; +end; + +procedure TScreenSing.Finish; +begin + AudioInput.CaptureStop; + AudioPlayback.Stop; + AudioPlayback.SetSyncSource(nil); + + if (Ini.SavePlayback = 1) then + begin + Log.BenchmarkStart(0); + Log.LogVoice(0); + Log.LogVoice(1); + Log.LogVoice(2); + Log.BenchmarkEnd(0); + Log.LogBenchmark('Creating files', 0); + end; + + if CurrentSong.VideoLoaded then + begin + fCurrentVideoPlaybackEngine.Close; + CurrentSong.VideoLoaded := False; // to prevent drawing closed video + end; + + SetFontItalic(False); +end; + +procedure TScreenSing.OnSentenceEnd(SentenceIndex: cardinal); +var + PlayerIndex: integer; + CurrentPlayer: PPLayer; + CurrentScore: real; + Line: PLine; + LinePerfection: real; // perfection of singing performance on the current line + Rating: integer; + LineScore: real; + LineBonus: real; + MaxSongScore: integer; // max. points for the song (without line bonus) + MaxLineScore: real; // max. points for the current line +const + // TODO: move this to a better place + MAX_LINE_RATING = 8; // max. rating for singing performance +begin + Line := @Lines[0].Line[SentenceIndex]; + + // check for empty sentence + if (Line.TotalNotes <= 0) then + Exit; + + // set max song score + if (Ini.LineBonus = 0) then + MaxSongScore := MAX_SONG_SCORE + else + MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS; + + // Note: ScoreValue is the sum of all note values of the song + MaxLineScore := MaxSongScore * (Line.TotalNotes / Lines[0].ScoreValue); + + for PlayerIndex := 0 to High(Player) do + begin + CurrentPlayer := @Player[PlayerIndex]; + CurrentScore := CurrentPlayer.Score + CurrentPlayer.ScoreGolden; + + // Line Bonus + + // points for this line + LineScore := CurrentScore - CurrentPlayer.ScoreLast; + + // determine LinePerfection + // Note: the "+2" extra points are a little bonus so the player does not + // have to be that perfect to reach the bonus steps. + LinePerfection := (LineScore + 2) / MaxLineScore; + + // clamp LinePerfection to range [0..1] + if (LinePerfection < 0) then + LinePerfection := 0 + else if (LinePerfection > 1) then + LinePerfection := 1; + + // add line-bonus if enabled + if (Ini.LineBonus > 0) then + begin + // line-bonus points (same for each line, no matter how long the line is) + LineBonus := MAX_SONG_LINE_BONUS / (Length(Lines[0].Line) - + NumEmptySentences); + // apply line-bonus + CurrentPlayer.ScoreLine := + CurrentPlayer.ScoreLine + LineBonus * LinePerfection; + CurrentPlayer.ScoreLineInt := Round(CurrentPlayer.ScoreLine / 10) * 10; + // update total score + CurrentPlayer.ScoreTotalInt := + CurrentPlayer.ScoreInt + + CurrentPlayer.ScoreGoldenInt + + CurrentPlayer.ScoreLineInt; + + // spawn rating pop-up + Rating := Round(LinePerfection * MAX_LINE_RATING); + Scores.SpawnPopUp(PlayerIndex, Rating, CurrentPlayer.ScoreTotalInt); + end; + + // PerfectLineTwinkle (effect), Part 1 + if (Ini.EffectSing = 1) then + CurrentPlayer.LastSentencePerfect := (LinePerfection >= 1); + + // refresh last score + CurrentPlayer.ScoreLast := CurrentScore; + end; + + // PerfectLineTwinkle (effect), Part 2 + if (Ini.EffectSing = 1) then + GoldenRec.SpawnPerfectLineTwinkle; +end; + + // Called on sentence change + // SentenceIndex: index of the new active sentence +procedure TScreenSing.OnSentenceChange(SentenceIndex: cardinal); +var + LyricEngine: TLyricEngine; +begin + //GoldenStarsTwinkle + GoldenRec.SentenceChange; + + // Fill lyrics queue and set upper line to the current sentence + while (Lyrics.GetUpperLineIndex() < SentenceIndex) or + (not Lyrics.IsQueueFull) do + begin + // Add the next line to the queue or a dummy if no more lines are available + if (Lyrics.LineCounter <= High(Lines[0].Line)) then + Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]) + else + Lyrics.AddLine(nil); + end; + + // AddLine draws the passed line to the back-buffer of the render context + // and copies it into a texture afterwards (offscreen rendering). + // This leaves an in invalidated screen. Calling Draw() makes sure, + // that the back-buffer stores the sing-screen, when the next + // swap between the back- and front-buffer is done (eliminates flickering) + // <note> calling AddLine() right before the regular screen update (Display.Draw) + // would be a better solution.</note> + Draw; +end; + +function TLyricsSyncSource.GetClock(): real; +begin + Result := LyricsState.GetCurrentTime(); +end; + +end. + diff --git a/src/screens/UScreenSingModi.pas b/src/screens/UScreenSingModi.pas new file mode 100644 index 00000000..616ba1c1 --- /dev/null +++ b/src/screens/UScreenSingModi.pas @@ -0,0 +1,707 @@ +unit UScreenSingModi; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses UMenu, + UMusic, + SDL, + SysUtils, + UFiles, + UTime, + USongs, + UIni, + ULog, + UTexture, + ULyrics, + TextGL, + gl, + + UThemes, + //ULCD, //TODO: maybe LCD Support as Plugin? + UScreenSing, + ModiSDK; + +type + TScreenSingModi = class(TScreenSing) + protected + //paused: boolean; //Pause Mod + //PauseTime: Real; + //NumEmptySentences: integer; + public + //TextTime: integer; + + //StaticP1: integer; + //StaticP1ScoreBG: integer; + //TextP1: integer; + //TextP1Score: integer; + + //StaticP2R: integer; + //StaticP2RScoreBG: integer; + //TextP2R: integer; + //TextP2RScore: integer; + + //StaticP2M: integer; + //StaticP2MScoreBG: integer; + //TextP2M: integer; + //TextP2MScore: integer; + + //StaticP3R: integer; + //StaticP3RScoreBG: integer; + //TextP3R: integer; + //TextP3RScore: integer; + + //Tex_Background: TTexture; + //FadeOut: boolean; + //LyricMain: TLyric; + //LyricSub: TLyric; + Winner: Byte; //Who Wins + PlayerInfo: TPlayerInfo; + TeamInfo: TTeamInfo; + + constructor Create; override; + procedure onShow; override; + //procedure onShowFinish; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function Draw: boolean; override; + procedure Finish; override; + //procedure UpdateLCD; //TODO: maybe LCD Support as Plugin? + //procedure Pause; //Pause Mod(Toggles Pause) + end; + +type + TCustomSoundEntry = record + Filename : String; + Stream : TAudioPlaybackStream; + end; + +var + //Custom Sounds + CustomSounds: array of TCustomSoundEntry; + +//Procedured for Plugin +function LoadTex (const Name: PChar; Typ: TTextureType): TsmallTexture; stdcall; +//function Translate (const Name: PChar): PChar; stdcall; +procedure Print (const Style, Size: Byte; const X, Y: Real; const Text: PChar); stdcall; //Procedure to Print Text +function LoadSound (const Name: PChar): Cardinal; stdcall; //Procedure that loads a Custom Sound +procedure PlaySound (const Index: Cardinal); stdcall; //Plays a Custom Sound + +//Utilys +function ToSentences(Const Lines: TLines): TSentences; + +implementation +uses UGraphic, UDraw, UMain, Classes, URecord, ULanguage, math, UDLLManager, USkins, UGraphicClasses; + +// Method for input parsing. If False is returned, GetNextWindow +// should be checked to know the next window to load; +function TScreenSingModi.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + case PressedKey of + + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + Finish; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenPartyScore); + end; + + else + Result := inherited ParseInput(PressedKey, CharCode, PressedDown); + end; + end; +end; + +constructor TScreenSingModi.Create; +begin + inherited Create; + +end; + +function ToSentences(Const Lines: TLines): TSentences; +var + I, J: Integer; +begin + Result.Current := Lines.Current; + Result.High := Lines.High; + Result.Number := Lines.Number; + Result.Resolution := Lines.Resolution; + Result.NotesGAP := Lines.NotesGAP; + Result.TotalLength := Lines.ScoreValue; + + SetLength(Result.Sentence, Length(Lines.Line)); + for I := low(Result.Sentence) to high(Result.Sentence) do + begin + Result.Sentence[I].Start := Lines.Line[I].Start; + Result.Sentence[I].StartNote := Lines.Line[I].Note[0].Start; + Result.Sentence[I].Lyric := Lines.Line[I].Lyric; + Result.Sentence[I].LyricWidth := Lines.Line[I].LyricWidth; + Result.Sentence[I].End_ := Lines.Line[I].End_; + Result.Sentence[I].BaseNote := Lines.Line[I].BaseNote; + Result.Sentence[I].HighNote := Lines.Line[I].HighNote; + Result.Sentence[I].TotalNotes := Lines.Line[I].TotalNotes; + + SetLength(Result.Sentence[I].Note, Length(Lines.Line[I].Note)); + for J := low(Result.Sentence[I].Note) to high(Result.Sentence[I].Note) do + begin + Result.Sentence[I].Note[J].Color := Lines.Line[I].Note[J].Color; + Result.Sentence[I].Note[J].Start := Lines.Line[I].Note[J].Start; + Result.Sentence[I].Note[J].Length := Lines.Line[I].Note[J].Length; + Result.Sentence[I].Note[J].Tone := Lines.Line[I].Note[J].Tone; + //Result.Sentence[I].Note[J].Text := Lines.Line[I].Note[J].Tekst; + Result.Sentence[I].Note[J].FreeStyle := (Lines.Line[I].Note[J].NoteType = ntFreestyle); + end; + end; +end; + +procedure TScreenSingModi.onShow; +var + I: Integer; +begin + inherited; + + PlayersPlay := TeamInfo.NumTeams; + + if DLLMan.Selected.LoadSong then //Start with Song + begin + inherited; + end + else //Start Without Song + begin + AudioInput.CaptureStart; + end; + +//Set Playerinfo + PlayerInfo.NumPlayers := PlayersPlay; + for I := 0 to PlayerInfo.NumPlayers-1 do + begin + PlayerInfo.Playerinfo[I].Name := PChar(Ini.Name[I]); + PlayerInfo.Playerinfo[I].Score := 0; + PlayerInfo.Playerinfo[I].Bar := 50; + PlayerInfo.Playerinfo[I].Enabled := True; + end; + + for I := PlayerInfo.NumPlayers to high(PlayerInfo.Playerinfo) do + begin + PlayerInfo.Playerinfo[I].Score:= 0; + PlayerInfo.Playerinfo[I].Bar := 0; + PlayerInfo.Playerinfo[I].Enabled := False; + end; + + {Case PlayersPlay of + 1: begin + PlayerInfo.Playerinfo[0].PosX := Static[StaticP1ScoreBG].Texture.X; + PlayerInfo.Playerinfo[0].PosY := Static[StaticP1ScoreBG].Texture.Y + Static[StaticP1ScoreBG].Texture.H; + end; + 2,4: begin + PlayerInfo.Playerinfo[0].PosX := Static[StaticP1TwoPScoreBG].Texture.X; + PlayerInfo.Playerinfo[0].PosY := Static[StaticP1TwoPScoreBG].Texture.Y + Static[StaticP1TwoPScoreBG].Texture.H; + PlayerInfo.Playerinfo[2].PosX := Static[StaticP1TwoPScoreBG].Texture.X; + PlayerInfo.Playerinfo[2].PosY := Static[StaticP1TwoPScoreBG].Texture.Y + Static[StaticP1TwoPScoreBG].Texture.H; + PlayerInfo.Playerinfo[1].PosX := Static[StaticP2RScoreBG].Texture.X; + PlayerInfo.Playerinfo[1].PosY := Static[StaticP2RScoreBG].Texture.Y + Static[StaticP2RScoreBG].Texture.H; + PlayerInfo.Playerinfo[3].PosX := Static[StaticP2RScoreBG].Texture.X; + PlayerInfo.Playerinfo[3].PosY := Static[StaticP2RScoreBG].Texture.Y + Static[StaticP2RScoreBG].Texture.H; + end; + 3,6: begin + PlayerInfo.Playerinfo[0].PosX := Static[StaticP1ThreePScoreBG].Texture.X; + PlayerInfo.Playerinfo[0].PosY := Static[StaticP1ThreePScoreBG].Texture.Y + Static[StaticP1ThreePScoreBG].Texture.H; + PlayerInfo.Playerinfo[3].PosX := Static[StaticP1ThreePScoreBG].Texture.X; + PlayerInfo.Playerinfo[3].PosY := Static[StaticP1ThreePScoreBG].Texture.Y + Static[StaticP1ThreePScoreBG].Texture.H; + PlayerInfo.Playerinfo[1].PosX := Static[StaticP2MScoreBG].Texture.X; + PlayerInfo.Playerinfo[1].PosY := Static[StaticP2MScoreBG].Texture.Y + Static[StaticP2MScoreBG].Texture.H; + PlayerInfo.Playerinfo[4].PosX := Static[StaticP2MScoreBG].Texture.X; + PlayerInfo.Playerinfo[4].PosY := Static[StaticP2MScoreBG].Texture.Y + Static[StaticP2MScoreBG].Texture.H; + PlayerInfo.Playerinfo[2].PosX := Static[StaticP3RScoreBG].Texture.X; + PlayerInfo.Playerinfo[2].PosY := Static[StaticP3RScoreBG].Texture.Y + Static[StaticP3RScoreBG].Texture.H; + PlayerInfo.Playerinfo[5].PosX := Static[StaticP3RScoreBG].Texture.X; + PlayerInfo.Playerinfo[5].PosY := Static[StaticP3RScoreBG].Texture.Y + Static[StaticP3RScoreBG].Texture.H; + end; + end; } + + // play music (I) + //Music.CaptureStart; + //Music.MoveTo(AktSong.Start); + + //Init Plugin + if not DLLMan.PluginInit(TeamInfo, PlayerInfo, ToSentences(Lines[0]), LoadTex, Print, LoadSound, PlaySound) then + begin + //Fehler + Log.LogError('Could not Init Plugin'); + Halt; + end; + + // Set Background (Little Workaround, maybe change sometime) + if (DLLMan.Selected.LoadBack) AND (DLLMan.Selected.LoadSong) then + ScreenSing.Tex_Background := Tex_Background; + + Winner := 0; + + //Set Score Visibility + {if PlayersPlay = 1 then begin + Text[TextP1Score].Visible := DLLMan.Selected.ShowScore; + Static[StaticP1ScoreBG].Visible := DLLMan.Selected.ShowScore; + end; + + if (PlayersPlay = 2) OR (PlayersPlay = 4) then begin + Text[TextP1TwoPScore].Visible := DLLMan.Selected.ShowScore; + Static[StaticP1TwoPScoreBG].Visible := DLLMan.Selected.ShowScore; + + Text[TextP2RScore].Visible := DLLMan.Selected.ShowScore; + Static[StaticP2RScoreBG].Visible := DLLMan.Selected.ShowScore; + end; + + if (PlayersPlay = 3) OR (PlayersPlay = 6) then begin + Text[TextP1ThreePScore].Visible := DLLMan.Selected.ShowScore; + Static[StaticP1ThreePScoreBG].Visible := DLLMan.Selected.ShowScore; + + Text[TextP2MScore].Visible := DLLMan.Selected.ShowScore; + Static[StaticP2MScoreBG].Visible := DLLMan.Selected.ShowScore; + + Text[TextP3RScore].Visible := DLLMan.Selected.ShowScore; + Static[StaticP3RScoreBG].Visible := DLLMan.Selected.ShowScore; + end; } +end; + +function TScreenSingModi.Draw: boolean; +var + Min: integer; + Sec: integer; + Tekst: string; + S, I: integer; + T: integer; + CurLyricsTime: real; +begin + Result := false; + + //Set Playerinfo + PlayerInfo.NumPlayers := PlayersPlay; + for I := 0 to PlayerInfo.NumPlayers-1 do + begin + PlayerInfo.Playerinfo[I].Name := PChar(Player[I].Name); + if PlayerInfo.Playerinfo[I].Enabled then + begin + if (Player[I].ScoreTotalInt <= MAX_SONG_SCORE) then + PlayerInfo.Playerinfo[I].Score:= Player[I].ScoreTotalInt; + PlayerInfo.Playerinfo[I].Bar := Round(Scores.Players[I].RBPos * 100); + end; + end; + + //Show Score + if DLLMan.Selected.ShowScore then + begin + {//ScoreBG Mod + // set player colors + if PlayersPlay = 4 then begin + if ScreenAct = 1 then begin + LoadColor(Static[StaticP1TwoP].Texture.ColR, Static[StaticP1TwoP].Texture.ColG, + Static[StaticP1TwoP].Texture.ColB, 'P1Dark'); + LoadColor(Static[StaticP2R].Texture.ColR, Static[StaticP2R].Texture.ColG, + Static[StaticP2R].Texture.ColB, 'P2Dark'); + + + + LoadColor(Static[StaticP1TwoPScoreBG].Texture.ColR, Static[StaticP1TwoPScoreBG].Texture.ColG, + Static[StaticP1TwoPScoreBG].Texture.ColB, 'P1Dark'); + LoadColor(Static[StaticP2RScoreBG].Texture.ColR, Static[StaticP2RScoreBG].Texture.ColG, + Static[StaticP2RScoreBG].Texture.ColB, 'P2Dark'); + + + + end; + if ScreenAct = 2 then begin + LoadColor(Static[StaticP1TwoP].Texture.ColR, Static[StaticP1TwoP].Texture.ColG, + Static[StaticP1TwoP].Texture.ColB, 'P3Dark'); + LoadColor(Static[StaticP2R].Texture.ColR, Static[StaticP2R].Texture.ColG, + Static[StaticP2R].Texture.ColB, 'P4Dark'); + + + + LoadColor(Static[StaticP1TwoPScoreBG].Texture.ColR, Static[StaticP1TwoPScoreBG].Texture.ColG, + Static[StaticP1TwoPScoreBG].Texture.ColB, 'P3Dark'); + LoadColor(Static[StaticP2RScoreBG].Texture.ColR, Static[StaticP2RScoreBG].Texture.ColG, + Static[StaticP2RScoreBG].Texture.ColB, 'P4Dark'); + + + + end; + end; + + if PlayersPlay = 6 then begin + if ScreenAct = 1 then begin + LoadColor(Static[StaticP1ThreeP].Texture.ColR, Static[StaticP1ThreeP].Texture.ColG, + Static[StaticP1ThreeP].Texture.ColB, 'P1Dark'); + LoadColor(Static[StaticP2M].Texture.ColR, Static[StaticP2M].Texture.ColG, + Static[StaticP2R].Texture.ColB, 'P2Dark'); + LoadColor(Static[StaticP3R].Texture.ColR, Static[StaticP3R].Texture.ColG, + Static[StaticP3R].Texture.ColB, 'P3Dark'); + + + + LoadColor(Static[StaticP1ThreePScoreBG].Texture.ColR, Static[StaticP1ThreePScoreBG].Texture.ColG, + Static[StaticP1ThreePScoreBG].Texture.ColB, 'P1Dark'); + LoadColor(Static[StaticP2MScoreBG].Texture.ColR, Static[StaticP2MScoreBG].Texture.ColG, + Static[StaticP2RScoreBG].Texture.ColB, 'P2Dark'); + LoadColor(Static[StaticP3RScoreBG].Texture.ColR, Static[StaticP3RScoreBG].Texture.ColG, + Static[StaticP3RScoreBG].Texture.ColB, 'P3Dark'); + + + + end; + if ScreenAct = 2 then begin + LoadColor(Static[StaticP1ThreeP].Texture.ColR, Static[StaticP1ThreeP].Texture.ColG, + Static[StaticP1ThreeP].Texture.ColB, 'P4Dark'); + LoadColor(Static[StaticP2M].Texture.ColR, Static[StaticP2M].Texture.ColG, + Static[StaticP2R].Texture.ColB, 'P5Dark'); + LoadColor(Static[StaticP3R].Texture.ColR, Static[StaticP3R].Texture.ColG, + Static[StaticP3R].Texture.ColB, 'P6Dark'); + + + + + LoadColor(Static[StaticP1ThreePScoreBG].Texture.ColR, Static[StaticP1ThreePScoreBG].Texture.ColG, + Static[StaticP1ThreePScoreBG].Texture.ColB, 'P4Dark'); + LoadColor(Static[StaticP2MScoreBG].Texture.ColR, Static[StaticP2MScoreBG].Texture.ColG, + Static[StaticP2RScoreBG].Texture.ColB, 'P5Dark'); + LoadColor(Static[StaticP3RScoreBG].Texture.ColR, Static[StaticP3RScoreBG].Texture.ColG, + Static[StaticP3RScoreBG].Texture.ColB, 'P6Dark'); + + + + + end; + end; + //end ScoreBG Mod } + + // set player names (for 2 screens and only Singstar skin) + if ScreenAct = 1 then begin + Text[TextP1].Text := 'P1'; + Text[TextP1TwoP].Text := 'P1'; // added for ps3 skin + Text[TextP1ThreeP].Text := 'P1'; // added for ps3 skin + Text[TextP2R].Text := 'P2'; + Text[TextP2M].Text := 'P2'; + Text[TextP3R].Text := 'P3'; + end; + + if ScreenAct = 2 then begin + case PlayersPlay of + 4: begin + Text[TextP1TwoP].Text := 'P3'; + Text[TextP2R].Text := 'P4'; + end; + 6: begin + Text[TextP1ThreeP].Text := 'P4'; + Text[TextP2M].Text := 'P5'; + Text[TextP3R].Text := 'P6'; + end; + end; // case + end; // if + + + // stereo <- and where iss P2M? or P3? + Static[StaticP1].Texture.X := Static[StaticP1].Texture.X + 10*ScreenX; + Text[TextP1].X := Text[TextP1].X + 10*ScreenX; + + {Static[StaticP1ScoreBG].Texture.X := Static[StaticP1ScoreBG].Texture.X + 10*ScreenX; + Text[TextP1Score].X := Text[TextP1Score].X + 10*ScreenX;} + + Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X + 10*ScreenX; + Text[TextP2R].X := Text[TextP2R].X + 10*ScreenX; + + {Static[StaticP2RScoreBG].Texture.X := Static[StaticP2RScoreBG].Texture.X + 10*ScreenX; + Text[TextP2RScore].X := Text[TextP2RScore].X + 10*ScreenX;} + + // .. and scores + {if PlayersPlay = 1 then begin + Tekst := IntToStr(Player[0].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1Score].Text := Tekst; + end; + + if PlayersPlay = 2 then begin + Tekst := IntToStr(Player[0].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1TwoPScore].Text := Tekst; + + Tekst := IntToStr(Player[1].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2RScore].Text := Tekst; + end; + + if PlayersPlay = 3 then begin + Tekst := IntToStr(Player[0].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1ThreePScore].Text := Tekst; + + Tekst := IntToStr(Player[1].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2MScore].Text := Tekst; + + Tekst := IntToStr(Player[2].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP3RScore].Text := Tekst; + end; + + if PlayersPlay = 4 then begin + if ScreenAct = 1 then begin + Tekst := IntToStr(Player[0].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1TwoPScore].Text := Tekst; + + Tekst := IntToStr(Player[1].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2RScore].Text := Tekst; + end; + if ScreenAct = 2 then begin + Tekst := IntToStr(Player[2].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1TwoPScore].Text := Tekst; + + Tekst := IntToStr(Player[3].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2RScore].Text := Tekst; + end; + end; + + if PlayersPlay = 6 then begin + if ScreenAct = 1 then begin + Tekst := IntToStr(Player[0].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1ThreePScore].Text := Tekst; + + Tekst := IntToStr(Player[1].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2MScore].Text := Tekst; + + Tekst := IntToStr(Player[2].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP3RScore].Text := Tekst; + end; + if ScreenAct = 2 then begin + Tekst := IntToStr(Player[3].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP1ThreePScore].Text := Tekst; + + Tekst := IntToStr(Player[4].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP2MScore].Text := Tekst; + + Tekst := IntToStr(Player[5].ScoreTotalI); + while Length(Tekst) < 5 do Tekst := '0' + Tekst; + Text[TextP3RScore].Text := Tekst; + end; + end; } + + end; //ShowScore + + for S := 1 to 1 do + Static[S].Texture.X := Static[S].Texture.X + 10*ScreenX; + + for T := 0 to 1 do + Text[T].X := Text[T].X + 10*ScreenX; + + if DLLMan.Selected.LoadSong then + begin + // update static menu with time ... + CurLyricsTime := LyricsState.GetCurrentTime(); + Min := Round(CurLyricsTime) div 60; + Sec := Round(CurLyricsTime) mod 60; + + Text[TextTimeText].Text := ''; + if Min < 10 then Text[TextTimeText].Text := '0'; + Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Min) + ':'; + if Sec < 10 then Text[TextTimeText].Text := Text[TextTimeText].Text + '0'; + Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Sec); + end; + + // draw static menu (BG) + DrawBG; + + //Draw Background + if (DllMan.Selected.LoadSong) AND (DllMan.Selected.LoadBack) then + SingDrawBackground; + + // comment by blindy: wo zum henker wird denn in diesem screen ein video abgespielt? + // update and draw movie + // <mog> wie wo wadd? also in der selben funktion in der uscreensing kommt des video in der zeile 995, oder was wollteste wissen? :X +{ if ShowFinish and CurrentSong.VideoLoaded AND DllMan.Selected.LoadVideo then begin + UpdateSmpeg; // this only draws + end;} + + // draw static menu (FG) + DrawFG; + + if ShowFinish then begin + if DllMan.Selected.LoadSong then + begin + if (not AudioPlayback.Finished) and ((CurrentSong.Finish = 0) or (LyricsState.GetCurrentTime*1000 <= CurrentSong.Finish)) then begin + //Pause Mod: + if not Paused then + Sing(Self); // analyze song + end else begin + if not FadeOut then begin + Finish; + FadeOut := true; + FadeTo(@ScreenPartyScore); + end; + end; + end; + end; + + // draw custom items + SingModiDraw(PlayerInfo); // always draw + + //GoldenNoteStarsTwinkle Mod + GoldenRec.SpawnRec; + //GoldenNoteStarsTwinkle Mod + + //Update PlayerInfo + for I := 0 to PlayerInfo.NumPlayers-1 do + begin + if PlayerInfo.Playerinfo[I].Enabled then + begin + //PlayerInfo.Playerinfo[I].Bar := Player[I].ScorePercent; + PlayerInfo.Playerinfo[I].Score := Player[I].ScoreTotalInt; + end; + end; + + if ((ShowFinish) AND (NOT Paused)) then + begin + if not DLLMan.PluginDraw(Playerinfo, Lines[0].Current) then + begin + if not FadeOut then begin + Finish; + FadeOut := true; + FadeTo(@ScreenPartyScore); + end; + end; + end; + + //Change PlayerInfo/Changeables + for I := 0 to PlayerInfo.NumPlayers-1 do + begin + if (Player[I].ScoreTotalInt <> PlayerInfo.Playerinfo[I].Score) then + begin + //Player[I].ScoreTotal := Player[I].ScoreTotal + (PlayerInfo.Playerinfo[I].Score - Player[I].ScoreTotalI); + Player[I].ScoreTotalInt := PlayerInfo.Playerinfo[I].Score; + end; + {if (PlayerInfo.Playerinfo[I].Bar <> Player[I].ScorePercent) then + Player[I].ScorePercentTarget := PlayerInfo.Playerinfo[I].Bar; } + end; + + // back stereo + Static[StaticP1].Texture.X := Static[StaticP1].Texture.X - 10*ScreenX; + Text[TextP1].X := Text[TextP1].X - 10*ScreenX; + + {Static[StaticP1ScoreBG].Texture.X := Static[StaticP1ScoreBG].Texture.X - 10*ScreenX; + Text[TextP1Score].X := Text[TextP1Score].X - 10*ScreenX;} + + + Static[StaticP2R].Texture.X := Static[StaticP2R].Texture.X - 10*ScreenX; + Text[TextP2R].X := Text[TextP2R].X - 10*ScreenX; + + {Static[StaticP2RScoreBG].Texture.X := Static[StaticP2RScoreBG].Texture.X - 10*ScreenX; + Text[TextP2RScore].X := Text[TextP2RScore].X - 10*ScreenX;} + + + for S := 1 to 1 do + Static[S].Texture.X := Static[S].Texture.X - 10*ScreenX; + + for T := 0 to 1 do + Text[T].X := Text[T].X - 10*ScreenX; + + Result := true; +end; + +procedure TScreenSingModi.Finish; +begin +inherited Finish; + +Winner := DllMan.PluginFinish(PlayerInfo); + +//Log.LogError('Winner: ' + InttoStr(Winner)); + +//DLLMan.UnLoadPlugin; +end; + +function LoadTex (const Name: PChar; Typ: TTextureType): TsmallTexture; stdcall; +var + Texname, EXT: String; + Tex: TTexture; +begin + //Get texture Name + TexName := Skin.GetTextureFileName(String(Name)); + //Get File Typ + Ext := ExtractFileExt(TexName); + if (uppercase(Ext) = '.JPG') then + Ext := 'JPG' + else + Ext := 'BMP'; + + Tex := Texture.LoadTexture(false, PChar(TexName), UTEXTURE.TTextureType(Typ), 0); + + Result.TexNum := Tex.TexNum; + Result.W := Tex.W; + Result.H := Tex.H; +end; +{ +function Translate (const Name: PChar): PChar; stdcall; +begin + Result := PChar(Language.Translate(String(Name))); +end; } + +procedure Print(const Style, Size: Byte; const X, Y: Real; const Text: PChar); stdcall; //Procedure to Print Text +begin + SetFontItalic ((Style and 128) = 128); + SetFontStyle(Style and 7); + SetFontSize(Size); + SetFontPos (X, Y); + glPrint (PChar(Language.Translate(String(Text)))); +end; + +function LoadSound(const Name: PChar): Cardinal; stdcall; //Procedure that loads a Custom Sound +var + Stream: TAudioPlaybackStream; + i: Integer; + Filename: String; +begin + //Search for Sound in already loaded Sounds + Filename := UpperCase(SoundPath + Name); + for i := 0 to High(CustomSounds) do + begin + if (UpperCase(CustomSounds[i].Filename) = Filename) then + begin + Result := i; + Exit; + end; + end; + + Stream := AudioPlayback.OpenSound(SoundPath + String(Name)); + if (Stream = nil) then + begin + Result := 0; + Exit; + end; + + SetLength(CustomSounds, Length(CustomSounds)+1); + CustomSounds[High(CustomSounds)].Stream := Stream; + Result := High(CustomSounds); +end; + +procedure PlaySound(const Index: Cardinal); stdcall; //Plays a Custom Sound +begin + if (Index <= High(CustomSounds)) then + AudioPlayback.PlaySound(CustomSounds[Index].Stream); +end; + +end. + diff --git a/src/screens/UScreenSong.pas b/src/screens/UScreenSong.pas new file mode 100644 index 00000000..be1320f2 --- /dev/null +++ b/src/screens/UScreenSong.pas @@ -0,0 +1,2019 @@ +unit UScreenSong; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + + +uses + UMenu, + SDL, + UMusic, + UFiles, + UTime, + UDisplay, + USongs, + SysUtils, + UCommon, + ULog, + UThemes, + UTexture, + ULanguage, + USong, + UIni; + +type + TScreenSong = class(TMenu) + private + EqualizerData: TFFTData; // moved here to avoid stack overflows + EqualizerBands: array of Byte; + EqualizerTime: Cardinal; + + procedure StartMusicPreview(); + procedure StopMusicPreview(); + public + TextArtist: integer; + TextTitle: integer; + TextNumber: integer; + + //Video Icon Mod + VideoIcon: Cardinal; + + TextCat: integer; + StaticCat: integer; + + SongCurrent: real; + SongTarget: real; + + HighSpeed: boolean; + CoverFull: boolean; + CoverTime: real; + MusicPreviewTimer: PSDL_TimerID; + + CoverX: integer; + CoverY: integer; + CoverW: integer; + is_jump: boolean; // Jump to Song Mod + is_jump_title:boolean; //Jump to SOng MOd-YTrue if search for Title + + //Party Mod + Mode: TSingMode; + + //party Statics (Joker) + StaticTeam1Joker1: Cardinal; + StaticTeam1Joker2: Cardinal; + StaticTeam1Joker3: Cardinal; + StaticTeam1Joker4: Cardinal; + StaticTeam1Joker5: Cardinal; + + StaticTeam2Joker1: Cardinal; + StaticTeam2Joker2: Cardinal; + StaticTeam2Joker3: Cardinal; + StaticTeam2Joker4: Cardinal; + StaticTeam2Joker5: Cardinal; + + StaticTeam3Joker1: Cardinal; + StaticTeam3Joker2: Cardinal; + StaticTeam3Joker3: Cardinal; + StaticTeam3Joker4: Cardinal; + StaticTeam3Joker5: Cardinal; + + StaticParty: array of Cardinal; + TextParty: array of Cardinal; + StaticNonParty: array of Cardinal; + TextNonParty: array of Cardinal; + + + constructor Create; override; + procedure SetScroll; + //procedure SetScroll1; + //procedure SetScroll2; + procedure SetScroll3; + procedure SetScroll4; + procedure SetScroll5; + procedure SetScroll6; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function Draw: boolean; override; + procedure GenerateThumbnails(); + procedure onShow; override; + procedure onHide; override; + procedure SelectNext; + procedure SelectPrev; + //procedure UpdateLCD; //TODO: maybe LCD Support as Plugin? + procedure SkipTo(Target: Cardinal); + procedure FixSelected; //Show Wrong Song when Tabs on Fix + procedure FixSelected2; //Show Wrong Song when Tabs on Fix + procedure ShowCatTL(Cat: Integer);// Show Cat in Top left + procedure ShowCatTLCustom(Caption: String);// Show Custom Text in Top left + procedure HideCatTL;// Show Cat in Tob left + procedure Refresh; //Refresh Song Sorting + procedure DrawEqualizer; + procedure ChangeMusic; + //Party Mode + procedure SelectRandomSong; + procedure SetJoker; + procedure SetStatics; + //procedures for Menu + procedure StartSong; + procedure OpenEditor; + procedure DoJoker(Team: Byte); + procedure SelectPlayers; + + procedure UnloadDetailedCover; + + //Extensions + procedure DrawExtensions; + end; + +implementation + +uses + UGraphic, + UMain, + UCovers, + math, + gl, + USkins, + UDLLManager, + UParty, + UPlaylist, + UMenuButton, + UScreenSongMenu; + +// ***** Public methods ****** // + +//Show Wrong Song when Tabs on Fix +procedure TScreenSong.FixSelected; +var I, I2: Integer; +begin + if CatSongs.VisibleSongs > 0 then + begin + I2:= 0; + for I := low(CatSongs.Song) to High(Catsongs.Song) do + begin + if CatSongs.Song[I].Visible then + inc(I2); + + if I = Interaction - 1 then + break; + end; + + SongCurrent := I2; + SongTarget := I2; + end; +end; + +procedure TScreenSong.FixSelected2; +var I, I2: Integer; +begin + if CatSongs.VisibleSongs > 0 then + begin + I2:= 0; + for I := low(CatSongs.Song) to High(Catsongs.Song) do + begin + if CatSongs.Song[I].Visible then + inc(I2); + + if I = Interaction - 1 then + break; + end; + + SongTarget := I2; + end; +end; +//Show Wrong Song when Tabs on Fix End + +procedure TScreenSong.ShowCatTLCustom(Caption: String);// Show Custom Text in Top left +begin + Text[TextCat].Text := Caption; + Text[TextCat].Visible := true; + Static[StaticCat].Visible := False; +end; + +//Show Cat in Top Left Mod +procedure TScreenSong.ShowCatTL(Cat: Integer); +begin + //Change + Text[TextCat].Text := CatSongs.Song[Cat].Artist; + Static[StaticCat].Texture := Texture.GetTexture(Button[Cat].Texture.Name, TEXTURE_TYPE_PLAIN, true); + + //Show + Text[TextCat].Visible := true; + Static[StaticCat].Visible := True; +end; + +procedure TScreenSong.HideCatTL; +begin + //Hide + //Text[TextCat].Visible := false; + Static[StaticCat].Visible := false; + //New -> Show Text specified in Theme + Text[TextCat].Visible := True; + Text[TextCat].Text := Theme.Song.TextCat.Text; +end; +//Show Cat in Top Left Mod End + + +// Method for input parsing. If False is returned, GetNextWindow +// should be checked to know the next window to load; +function TScreenSong.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +var + I: integer; + I2: integer; + SDL_ModState: Word; + Letter: WideChar; +begin + Result := true; + + //Song Screen Extensions (Jumpto + Menu) + if (ScreenSongMenu.Visible) then + begin + Result := ScreenSongMenu.ParseInput(PressedKey, CharCode, PressedDown); + Exit; + end + else if (ScreenSongJumpto.Visible) then + begin + Result := ScreenSongJumpto.ParseInput(PressedKey, CharCode, PressedDown); + Exit; + end; + + if (PressedDown) then + begin // Key Down + + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT); + + //Jump to Artist/Titel + if ((SDL_ModState and KMOD_LALT <> 0) and (Mode = smNormal)) then + begin + if (WideCharUpperCase(CharCode)[1] in ([WideChar('A')..WideChar('Z')]) ) then + begin + Letter := WideCharUpperCase(CharCode)[1]; + I2 := Length(CatSongs.Song); + + //Jump To Titel + if (SDL_ModState = (KMOD_LALT or KMOD_LSHIFT)) then + begin + for I := 1 to high(CatSongs.Song) do + begin + if (CatSongs.Song[(I + Interaction) mod I2].Visible) and + (Length(CatSongs.Song[(I + Interaction) mod I2].Title)>0) and + (WideStringUpperCase(CatSongs.Song[(I + Interaction) mod I2].Title)[1] = Letter) then + begin + SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2)); + + AudioPlayback.PlaySound(SoundLib.Change); + + ChangeMusic; + SetScroll4; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + //Break and Exit + Exit; + end; + end; + end + //Jump to Artist + else if (SDL_ModState = KMOD_LALT) then + begin + for I := 1 to high(CatSongs.Song) do + begin + if (CatSongs.Song[(I + Interaction) mod I2].Visible) and + (Length(CatSongs.Song[(I + Interaction) mod I2].Artist)>0) and + (WideStringUpperCase(CatSongs.Song[(I + Interaction) mod I2].Artist)[1] = Letter) then + begin + SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2)); + + AudioPlayback.PlaySound(SoundLib.Change); + + ChangeMusic; + SetScroll4; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + + //Break and Exit + Exit; + end; + end; + end; + end; + + Exit; + end; + + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + + 'M': //Show SongMenu + begin + if (Songs.SongList.Count > 0) then + begin + if (Mode = smNormal) then + begin + if (not CatSongs.Song[Interaction].Main) then // clicked on Song + begin + if CatSongs.CatNumShow = -3 then + ScreenSongMenu.MenuShow(SM_Playlist) + else + ScreenSongMenu.MenuShow(SM_Main); + end + else + begin + ScreenSongMenu.MenuShow(SM_Playlist_Load); + end; + end //Party Mode -> Show Party Menu + else + begin + ScreenSongMenu.MenuShow(SM_Party_Main); + end; + end; + Exit; + end; + + 'P': //Show Playlist Menu + begin + if (Songs.SongList.Count > 0) and (Mode = smNormal) then + begin + ScreenSongMenu.MenuShow(SM_Playlist_Load); + end; + Exit; + end; + + 'J': //Show Jumpto Menu + begin + if (Songs.SongList.Count > 0) and (Mode = smNormal) then + begin + ScreenSongJumpto.Visible := True; + end; + Exit; + end; + + 'E': + begin + OpenEditor; + Exit; + end; + + 'R': + begin + if (Songs.SongList.Count > 0) and (Mode = smNormal) then + begin + if (SDL_ModState = KMOD_LSHIFT) and (Ini.Tabs_at_startup = 1) then //Random Category + begin + I2 := 0; //Count Cats + for I:= low(CatSongs.Song) to high (CatSongs.Song) do + begin + if CatSongs.Song[I].Main then + Inc(I2); + end; + + I2 := Random (I2)+1; //Zufall + + //Find Cat: + for I:= low(CatSongs.Song) to high (CatSongs.Song) do + begin + if CatSongs.Song[I].Main then + Dec(I2); + if (I2<=0) then + begin + //Show Cat in Top Left Mod + ShowCatTL (I); + + Interaction := I; + + CatSongs.ShowCategoryList; + CatSongs.ClickCategoryButton(I); + SelectNext; + FixSelected; + break; + end; + end; + end + else if (SDL_ModState = KMOD_LCTRL) and (Ini.Tabs_at_startup = 1) then //random in All Categorys + begin + repeat + I2 := Random(high(CatSongs.Song)+1) - low(CatSongs.Song)+1; + until CatSongs.Song[I2].Main = false; + + //Search Cat + for I := I2 downto low(CatSongs.Song) do + begin + if CatSongs.Song[I].Main then + break; + end; + + //In I is now the categorie in I2 the song + + //Choose Cat + CatSongs.ShowCategoryList; + + //Show Cat in Top Left Mod + ShowCatTL (I); + + CatSongs.ClickCategoryButton(I); + SelectNext; + + //Fix: Not Existing Song selected: + //if (I+1=I2) then Inc(I2); + + //Choose Song + SkipTo(I2-I); + end + else //Random in one Category + begin + SkipTo(Random(CatSongs.VisibleSongs)); + end; + AudioPlayback.PlaySound(SoundLib.Change); + + ChangeMusic; + SetScroll4; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + end; + Exit; + end; + end; // normal keys + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + if (Mode = smNormal) then + begin + //On Escape goto Cat-List Hack + if (Ini.Tabs_at_startup = 1) and (CatSongs.CatNumShow <> -1) then + begin + //Find Category + I := Interaction; + while not catsongs.Song[I].Main do + begin + Dec (I); + if (I < low(catsongs.Song)) then + break; + end; + if (I<= 1) then + Interaction := high(catsongs.Song) + else + Interaction := I - 1; + + //Stop Music + StopMusicPreview(); + + CatSongs.ShowCategoryList; + + //Show Cat in Top Left Mod + HideCatTL; + + + //Show Wrong Song when Tabs on Fix + SelectNext; + FixSelected; + //SelectPrev; + //CatSongs.Song[0].Visible := False; + end + else + begin + //On Escape goto Cat-List Hack End + //Tabs off and in Search or Playlist -> Go back to Song view + if (CatSongs.CatNumShow < -1) then + begin + //Atm: Set Empty Filter + CatSongs.SetFilter('', 0); + + //Show Cat in Top Left Mod + HideCatTL; + Interaction := 0; + + //Show Wrong Song when Tabs on Fix + SelectNext; + FixSelected; + + ChangeMusic; + end + else + begin + StopMusicPreview(); + AudioPlayback.PlaySound(SoundLib.Back); + + FadeTo(@ScreenMain); + end; + + end; + end + //When in party Mode then Ask before Close + else if (Mode = smPartyMode) then + begin + AudioPlayback.PlaySound(SoundLib.Back); + CheckFadeTo(@ScreenMain,'MSG_END_PARTY'); + end; + end; + SDLK_RETURN: + begin + if Songs.SongList.Count > 0 then + begin + {$IFDEF UseSerialPort} + // PortWriteB($378, 0); + {$ENDIF} + if CatSongs.Song[Interaction].Main then + begin // clicked on Category Button + //Show Cat in Top Left Mod + ShowCatTL (Interaction); + + //I := CatSongs.VisibleIndex(Interaction); + CatSongs.ClickCategoryButton(Interaction); + {I2 := CatSongs.VisibleIndex(Interaction); + SongCurrent := SongCurrent - I + I2; + SongTarget := SongTarget - I + I2; } + + // SetScroll4; + + //Show Wrong Song when Tabs on Fix + SelectNext; + FixSelected; + + //Play Music: + ChangeMusic; + end + else + begin // clicked on song + if (Mode = smNormal) then //Normal Mode -> Start Song + begin + //Do the Action that is specified in Ini + case Ini.OnSongClick of + 0: StartSong; + 1: SelectPlayers; + 2:begin + if (CatSongs.CatNumShow = -3) then + ScreenSongMenu.MenuShow(SM_Playlist) + else + ScreenSongMenu.MenuShow(SM_Main); + end; + end; + end + else if (Mode = smPartyMode) then //PartyMode -> Show Menu + begin + if (Ini.PartyPopup = 1) then + ScreenSongMenu.MenuShow(SM_Party_Main) + else + ScreenSong.StartSong; + end; + end; + end; + end; + + SDLK_DOWN: + begin + if (Mode = smNormal) then + begin + //Only Change Cat when not in Playlist or Search Mode + if (CatSongs.CatNumShow > -2) then + begin + //Cat Change Hack + if Ini.Tabs_at_startup = 1 then + begin + I := Interaction; + if I <= 0 then I := 1; + + while not catsongs.Song[I].Main do + begin + Inc (I); + if (I > high(catsongs.Song)) then + I := low(catsongs.Song); + end; + + Interaction := I; + + //Show Cat in Top Left Mod + ShowCatTL (Interaction); + + CatSongs.ClickCategoryButton(Interaction); + SelectNext; + FixSelected; + + //Play Music: + AudioPlayback.PlaySound(SoundLib.Change); + ChangeMusic; + + end; + + // + //Cat Change Hack End} + end; + end; + end; + SDLK_UP: + begin + if (Mode = smNormal) then + begin + //Only Change Cat when not in Playlist or Search Mode + if (CatSongs.CatNumShow > -2) then + begin + //Cat Change Hack + if Ini.Tabs_at_startup = 1 then + begin + I := Interaction; + I2 := 0; + if I <= 0 then I := 1; + + while not catsongs.Song[I].Main or (I2 = 0) do + begin + if catsongs.Song[I].Main then + Inc(I2); + Dec (I); + if (I < low(catsongs.Song)) then + I := high(catsongs.Song); + end; + + Interaction := I; + + //Show Cat in Top Left Mod + ShowCatTL (I); + + CatSongs.ClickCategoryButton(I); + SelectNext; + FixSelected; + + //Play Music: + AudioPlayback.PlaySound(SoundLib.Change); + ChangeMusic; + end; + end; + //Cat Change Hack End} + end; + end; + + SDLK_RIGHT: + begin + if (Songs.SongList.Count > 0) and (Mode = smNormal) then + begin + AudioPlayback.PlaySound(SoundLib.Change); + SelectNext; + //InteractNext; + //SongTarget := Interaction; + ChangeMusic; + SetScroll4; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + //Light.LightOne(1, 200); //TODO: maybe Light Support as Plugin? + end; + end; + + SDLK_LEFT: + begin + if (Songs.SongList.Count > 0)and (Mode = smNormal) then + begin + AudioPlayback.PlaySound(SoundLib.Change); + SelectPrev; + ChangeMusic; + SetScroll4; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + //Light.LightOne(0, 200); //TODO: maybe Light Support as Plugin? + end; + end; + + SDLK_1: + begin //Joker // to-do : Party + {if (Mode = smPartyMode) and (PartySession.Teams.NumTeams >= 1) and (PartySession.Teams.Teaminfo[0].Joker > 0) then + begin + //Use Joker + Dec(PartySession.Teams.Teaminfo[0].Joker); + SelectRandomSong; + SetJoker; + end; } + end; + + SDLK_2: + begin //Joker + {if (Mode = smPartyMode) and (PartySession.Teams.NumTeams >= 2) and (PartySession.Teams.Teaminfo[1].Joker > 0) then + begin + //Use Joker + Dec(PartySession.Teams.Teaminfo[1].Joker); + SelectRandomSong; + SetJoker; + end; } + end; + + SDLK_3: + begin //Joker + {if (Mode = smPartyMode) and (PartySession.Teams.NumTeams >= 3) and (PartySession.Teams.Teaminfo[2].Joker > 0) then + begin + //Use Joker + Dec(PartySession.Teams.Teaminfo[2].Joker); + SelectRandomSong; + SetJoker; + end; } + end; + end; + end; +end; + +constructor TScreenSong.Create; +var + i: integer; +begin + inherited Create; + + LoadFromTheme(Theme.Song); + + TextArtist := AddText(Theme.Song.TextArtist); + TextTitle := AddText(Theme.Song.TextTitle); + TextNumber := AddText(Theme.Song.TextNumber); + + //Show Cat in Top Left mod + TextCat := AddText(Theme.Song.TextCat); + StaticCat := AddStatic(Theme.Song.StaticCat); + + //Show Video Icon Mod + VideoIcon := AddStatic(Theme.Song.VideoIcon); + + //Party Mode + StaticTeam1Joker1 := AddStatic(Theme.Song.StaticTeam1Joker1); + StaticTeam1Joker2 := AddStatic(Theme.Song.StaticTeam1Joker2); + StaticTeam1Joker3 := AddStatic(Theme.Song.StaticTeam1Joker3); + StaticTeam1Joker4 := AddStatic(Theme.Song.StaticTeam1Joker4); + StaticTeam1Joker5 := AddStatic(Theme.Song.StaticTeam1Joker5); + + StaticTeam2Joker1 := AddStatic(Theme.Song.StaticTeam2Joker1); + StaticTeam2Joker2 := AddStatic(Theme.Song.StaticTeam2Joker2); + StaticTeam2Joker3 := AddStatic(Theme.Song.StaticTeam2Joker3); + StaticTeam2Joker4 := AddStatic(Theme.Song.StaticTeam2Joker4); + StaticTeam2Joker5 := AddStatic(Theme.Song.StaticTeam2Joker5); + + StaticTeam3Joker1 := AddStatic(Theme.Song.StaticTeam3Joker1); + StaticTeam3Joker2 := AddStatic(Theme.Song.StaticTeam3Joker2); + StaticTeam3Joker3 := AddStatic(Theme.Song.StaticTeam3Joker3); + StaticTeam3Joker4 := AddStatic(Theme.Song.StaticTeam3Joker4); + StaticTeam3Joker5 := AddStatic(Theme.Song.StaticTeam3Joker5); + + //Load Party or NonParty specific Statics and Texts + SetLength(StaticParty, Length(Theme.Song.StaticParty)); + for i := 0 to High(Theme.Song.StaticParty) do + StaticParty[i] := AddStatic(Theme.Song.StaticParty[i]); + + SetLength(TextParty, Length(Theme.Song.TextParty)); + for i := 0 to High(Theme.Song.TextParty) do + TextParty[i] := AddText(Theme.Song.TextParty[i]); + + SetLength(StaticNonParty, Length(Theme.Song.StaticNonParty)); + for i := 0 to High(Theme.Song.StaticNonParty) do + StaticNonParty[i] := AddStatic(Theme.Song.StaticNonParty[i]); + + SetLength(TextNonParty, Length(Theme.Song.TextNonParty)); + for i := 0 to High(Theme.Song.TextNonParty) do + TextNonParty[i] := AddText(Theme.Song.TextNonParty[i]); + + // Song List + //Songs.LoadSongList; // moved to the UltraStar unit + CatSongs.Refresh; + + GenerateThumbnails(); + + + // Randomize Patch + Randomize; + //Equalizer + SetLength(EqualizerBands, Theme.Song.Equalizer.Bands); + //ClearArray + For I := low(EqualizerBands) to high(EqualizerBands) do + EqualizerBands[I] := 3; + + if (Length(CatSongs.Song) > 0) then + Interaction := 0; +end; + +procedure TScreenSong.GenerateThumbnails(); +var + I: Integer; + CoverButtonIndex: integer; + CoverButton: TButton; + CoverName: string; + CoverTexture: TTexture; + Cover: TCover; + Song: TSong; +begin + if (Length(CatSongs.Song) <= 0) then + Exit; + + // set length of button array once instead for every song + SetButtonLength(Length(CatSongs.Song)); + + // create all buttons + for I := 0 to High(CatSongs.Song) do + begin + CoverButton := nil; + + // create a clickable cover + CoverButtonIndex := AddButton(300 + I*250, 140, 200, 200, '', TEXTURE_TYPE_PLAIN, Theme.Song.Cover.Reflections); + if (CoverButtonIndex > -1) then + CoverButton := Button[CoverButtonIndex]; + if (CoverButton = nil) then + Continue; + + Song := CatSongs.Song[I]; + + // if cover-image is not found then show 'no cover' + if (not FileExists(Song.Path + Song.Cover)) then + Song.Cover := ''; + + if (Song.Cover = '') then + CoverName := Skin.GetTextureFileName('SongCover') + else + CoverName := Song.Path + Song.Cover; + + // load cover and cache its texture + Cover := Covers.FindCover(CoverName); + if (Cover = nil) then + Cover := Covers.AddCover(CoverName); + + // use the cached texture + // TODO: this is a workaround until the new song-loading works. + // The TCover object should be added to the song-object. The thumbnails + // should be loaded each time the song-screen is shown (it is real fast). + // This way, we will not waste that much memory and have a link between + // song and cover. + if (Cover <> nil) then + begin + CoverTexture := Cover.GetPreviewTexture(); + Texture.AddTexture(CoverTexture, TEXTURE_TYPE_PLAIN, true); + CoverButton.Texture := CoverTexture; + end; + + Cover.Free; + end; +end; + +procedure TScreenSong.SetScroll; +var + VS, B: Integer; +begin + VS := CatSongs.VisibleSongs; + if VS > 0 then + begin + // Set Positions + case Theme.Song.Cover.Style of + 3: SetScroll3; + 5:begin + if VS > 5 then + SetScroll5 + else + SetScroll4; + end; + 6: SetScroll6; + else SetScroll4; + end; + + // Set visibility of video icon + Static[VideoIcon].Visible := (CatSongs.Song[Interaction].Video <> ''); + + // Set texts + Text[TextArtist].Text := CatSongs.Song[Interaction].Artist; + Text[TextTitle].Text := CatSongs.Song[Interaction].Title; + if (Ini.Tabs_at_startup = 1) and (CatSongs.CatNumShow = -1) then + begin + Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].OrderNum) + '/' + IntToStr(CatSongs.CatCount); + Text[TextTitle].Text := '(' + IntToStr(CatSongs.Song[Interaction].CatNumber) + ' ' + Language.Translate('SING_SONGS_IN_CAT') + ')'; + end + else if (CatSongs.CatNumShow = -2) then + Text[TextNumber].Text := IntToStr(CatSongs.VisibleIndex(Interaction)+1) + '/' + IntToStr(VS) + else if (CatSongs.CatNumShow = -3) then + Text[TextNumber].Text := IntToStr(CatSongs.VisibleIndex(Interaction)+1) + '/' + IntToStr(VS) + else if (Ini.Tabs_at_startup = 1) then + Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].CatNumber) + '/' + IntToStr(CatSongs.Song[Interaction - CatSongs.Song[Interaction].CatNumber].CatNumber) + else + Text[TextNumber].Text := IntToStr(Interaction+1) + '/' + IntToStr(Length(CatSongs.Song)); + end + else + begin + Text[TextNumber].Text := '0/0'; + Text[TextArtist].Text := ''; + Text[TextTitle].Text := ''; + for B := 0 to High(Button) do + Button[B].Visible := False; + + end; +end; + +(* +procedure TScreenSong.SetScroll1; +var + B: integer; // button + //BMin: integer; // button min // Auto Removed, Unused Variable + //BMax: integer; // button max // Auto Removed, Unused Variable + Src: integer; + //Dst: integer; + Count: integer; // Dst is not used. Count is used. + Ready: boolean; + + VisCount: integer; // count of visible (or selectable) buttons + VisInt: integer; // visible position of interacted button + Typ: integer; // 0 when all songs fits the screen + Placed: integer; // number of placed visible buttons +begin + //Src := 0; + //Dst := -1; + Count := 1; + Typ := 0; + Ready := false; + Placed := 0; + + VisCount := 0; + for B := 0 to High(Button) do + if CatSongs.Song[B].Visible then Inc(VisCount); + + VisInt := 0; + for B := 0 to Interaction-1 do + if CatSongs.Song[B].Visible then Inc(VisInt); + + + if VisCount <= 6 then begin + Typ := 0; + end else begin + if VisInt <= 3 then begin + Typ := 1; + Count := 7; + Ready := true; + end; + + if (VisCount - VisInt) <= 3 then begin + Typ := 2; + Count := 7; + Ready := true; + end; + + if not Ready then begin + Typ := 3; + Src := Interaction; + end; + end; + + + + // hide all buttons + for B := 0 to High(Button) do begin + Button[B].Visible := false; + Button[B].Selectable := CatSongs.Song[B].Visible; + end; + + { + for B := Src to Dst do begin + //Button[B].Visible := true; + Button[B].Visible := CatSongs.Song[B].Visible; + Button[B].Selectable := Button[B].Visible; + Button[B].Y := 140 + (B-Src) * 60; + end; + } + + + if Typ = 0 then begin + for B := 0 to High(Button) do begin + if CatSongs.Song[B].Visible then begin + Button[B].Visible := true; + Button[B].Y := 140 + (Placed) * 60; + Inc(Placed); + end; + end; + end; + + if Typ = 1 then begin + B := 0; + while (Count > 0) do begin + if CatSongs.Song[B].Visible then begin + Button[B].Visible := true; + Button[B].Y := 140 + (Placed) * 60; + Inc(Placed); + Dec(Count); + end; + Inc(B); + end; + end; + + if Typ = 2 then begin + B := High(Button); + while (Count > 0) do begin + if CatSongs.Song[B].Visible then begin + Button[B].Visible := true; + Button[B].Y := 140 + (6-Placed) * 60; + Inc(Placed); + Dec(Count); + end; + Dec(B); + end; + end; + + if Typ = 3 then begin + B := Src; + Count := 4; + while (Count > 0) do begin + if CatSongs.Song[B].Visible then begin + Button[B].Visible := true; + Button[B].Y := 140 + (3+Placed) * 60; + Inc(Placed); + Dec(Count); + end; + Inc(B); + end; + + B := Src-1; + Placed := 0; + Count := 3; + while (Count > 0) do begin + if CatSongs.Song[B].Visible then begin + Button[B].Visible := true; + Button[B].Y := 140 + (2-Placed) * 60; + Inc(Placed); + Dec(Count); + end; + Dec(B); + end; + + end; + + if Length(Button) > 0 then + Static[1].Texture.Y := Button[Interaction].Y - 5; // selection texture +end; + +procedure TScreenSong.SetScroll2; +var + B: integer; + //Wsp: integer; // wspolczynnik przesuniecia wzgledem srodka ekranu + //Wsp2: real; +begin + // liniowe + for B := 0 to High(Button) do + Button[B].X := 300 + (B - Interaction) * 260; + + if Length(Button) >= 3 then begin + if Interaction = 0 then + Button[High(Button)].X := 300 - 260; + + if Interaction = High(Button) then + Button[0].X := 300 + 260; + end; + + // kolowe + { + for B := 0 to High(Button) do begin + Wsp := (B - Interaction); // 0 dla srodka, -1 dla lewego, +1 dla prawego itd. + Wsp2 := Wsp / Length(Button); + Button[B].X := 300 + 10000 * sin(2*pi*Wsp2); + //Button[B].Y := 140 + 50 * ; + end; + } +end; +*) + +procedure TScreenSong.SetScroll3; // with slide +var + B: integer; + //Wsp: integer; // wspolczynnik przesuniecia wzgledem srodka ekranu + //Wsp2: real; +begin + SongTarget := Interaction; + + // liniowe + for B := 0 to High(Button) do + begin + Button[B].X := 300 + (B - SongCurrent) * 260; + if (Button[B].X < -Button[B].W) or (Button[B].X > 800) then + Button[B].Visible := False + else + Button[B].Visible := True; + end; + + { + if Length(Button) >= 3 then begin + if Interaction = 0 then + Button[High(Button)].X := 300 - 260; + + if Interaction = High(Button) then + Button[0].X := 300 + 260; + end; + } + + // kolowe + { + for B := 0 to High(Button) do begin + Wsp := (B - Interaction); // 0 dla srodka, -1 dla lewego, +1 dla prawego itd. + Wsp2 := Wsp / Length(Button); + Button[B].X := 300 + 10000 * sin(2*pi*Wsp2); + //Button[B].Y := 140 + 50 * ; + end; + } +end; + +(** + * Rotation + *) +procedure TScreenSong.SetScroll4; +var + B: integer; + Angle: real; + Z, Z2: real; + VS: integer; +begin + VS := CatSongs.VisibleSongs(); + + for B := 0 to High(Button) do + begin + Button[B].Visible := CatSongs.Song[B].Visible; + if Button[B].Visible then + begin + // angle between the cover and selected song-cover in radians + Angle := 2*Pi * (CatSongs.VisibleIndex(B) - SongCurrent) / VS; + + // calc z-position from angle + Z := (1 + cos(Angle)) / 2; // scaled to range [0..1] + Z2 := (1 + 2*Z) / 3; // scaled to range [1/3..1] + + // adjust cover's width and height according its z-position + // Note: Theme.Song.Cover.W is not used as width and height are equal + // and Theme.Song.Cover.W is used as circle radius in Scroll5. + Button[B].W := Theme.Song.Cover.H * Z2; + Button[B].H := Button[B].W; + + // set cover position + Button[B].X := Theme.Song.Cover.X + + (0.185 * Theme.Song.Cover.H * VS * sin(Angle)) * Z2 - + ((Button[B].H - Theme.Song.Cover.H)/2); + Button[B].Y := Theme.Song.Cover.Y + + (Theme.Song.Cover.H - Abs(Button[B].H)) * 0.7; + Button[B].Z := Z / 2 + 0.3; + end; + end; +end; + +(** + * rotate + *) +procedure TScreenSong.SetScroll5; +var + B: integer; + Angle: real; + Pos: Real; + VS: integer; + Padding: real; + X: Real; + { + Theme.Song.CoverW: circle radius + Theme.Song.CoverX: x-pos. of the left edge of the selected cover + Theme.Song.CoverY: y-pos. of the upper edge of the selected cover + Theme.Song.CoverH: cover height + } +begin + VS := CatSongs.VisibleSongs(); + + // Update positions of all buttons + for B := 0 to High(Button) do + begin + Button[B].Visible := CatSongs.Song[B].Visible; // adjust visibility + if Button[B].Visible then // Only change pos for visible buttons + begin + // Pos is the distance to the centered cover in the range [-VS/2..+VS/2] + Pos := (CatSongs.VisibleIndex(B) - SongCurrent); + if (Pos < -VS/2) then + Pos := Pos + VS + else if (Pos > VS/2) then + Pos := Pos - VS; + + // Avoid overlapping of the front covers. + // Use an alternate position for the five front covers. + if (Abs(Pos) < 2.5) then + begin + Angle := Pi * (Pos / 5); // Range: (-1/4*Pi .. +1/4*Pi) + + Button[B].H := Abs(Theme.Song.Cover.H * cos(Angle*0.8)); + Button[B].W := Button[B].H; + + //Button[B].Reflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + + Padding := (Button[B].H - Theme.Song.Cover.H)/2; + X := Sin(Angle*1.3) * 0.9; + + Button[B].X := Theme.Song.Cover.X + Theme.Song.Cover.W * X - Padding; + Button[B].Y := (Theme.Song.Cover.Y + (Theme.Song.Cover.H - Abs(Theme.Song.Cover.H * cos(Angle))) * 0.5); + Button[B].Z := 0.95 - Abs(Pos) * 0.01; + end + else + begin + // Transform Pos to range [-1..-1/2, +1/2..+1] + if Pos < 0 then + Pos := Pos/VS - 0.5 + else + Pos := Pos/VS + 0.5; + + // angle in radians [-2Pi..-Pi, +Pi..+2Pi] + Angle := 2*Pi * Pos; + + Button[B].H := 0.6*(Theme.Song.Cover.H-Abs(Theme.Song.Cover.H * cos(Angle/2)*0.8)); + Button[B].W := Button[B].H; + + Padding := (Button[B].H - Theme.Song.Cover.H)/2; + + Button[B].X := Theme.Song.Cover.X+Theme.Song.Cover.H/2-Button[b].H/2+Theme.Song.Cover.W/320*((Theme.Song.Cover.H)*sin(Angle/2)*1.52); + Button[B].Y := Theme.Song.Cover.Y - (Button[B].H - Theme.Song.Cover.H)*0.75; + Button[B].Z := (0.4 - Abs(Pos/4)) -0.00001; //z < 0.49999 is behind the cover 1 is in front of the covers + + //Button[B].Reflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + end; + end; + end; +end; + +procedure TScreenSong.SetScroll6; // rotate (slotmachine style) +var + B: integer; + Angle: real; + Pos: Real; + VS: integer; + diff: real; + X: Real; + Wsp: real; + Z, Z2: real; +begin + VS := CatSongs.VisibleSongs; + if VS <= 5 then + begin + // kolowe + for B := 0 to High(Button) do + begin + Button[B].Visible := CatSongs.Song[B].Visible; // nowe + if Button[B].Visible then begin // optimization for 1000 songs - updates only visible songs, hiding in tabs becomes useful for maintaing good speed + + Wsp := 2 * pi * (CatSongs.VisibleIndex(B) - SongCurrent) / VS {CatSongs.VisibleSongs};// 0.5.0 (II): takes another 16ms + + Z := (1 + cos(Wsp)) / 2; + Z2 := (1 + 2*Z) / 3; + + + Button[B].Y := Theme.Song.Cover.Y + (0.185 * Theme.Song.Cover.H * VS * sin(Wsp)) * Z2 - ((Button[B].H - Theme.Song.Cover.H)/2); // 0.5.0 (I): 2 times faster by not calling CatSongs.VisibleSongs + Button[B].Z := Z / 2 + 0.3; + + Button[B].W := Theme.Song.Cover.H * Z2; + + //Button[B].Y := {50 +} 140 + 50 - 50 * Z2; + Button[B].X := Theme.Song.Cover.X + (Theme.Song.Cover.H - Abs(Button[B].H)) * 0.7 ; + Button[B].H := Button[B].W; + end; + end; + end + else + begin + //Change Pos of all Buttons + for B := low(Button) to high(Button) do + begin + Button[B].Visible := CatSongs.Song[B].Visible; //Adjust Visibility + if Button[B].Visible then //Only Change Pos for Visible Buttons + begin + Pos := (CatSongs.VisibleIndex(B) - SongCurrent); + if (Pos < -VS/2) then + Pos := Pos + VS + else if (Pos > VS/2) then + Pos := Pos - VS; + + if (Abs(Pos) < 2.5) then {fixed Positions} + begin + Angle := Pi * (Pos / 5); + //Button[B].Visible := False; + + Button[B].H := Abs(Theme.Song.Cover.H * cos(Angle*0.8));//Power(Z2, 3); + + Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + + Button[B].Z := 0.95 - Abs(Pos) * 0.01; + + Button[B].X := (Theme.Song.Cover.X + (Theme.Song.Cover.H - Abs(Theme.Song.Cover.H * cos(Angle))) * 0.5); + + Button[B].W := Button[B].H; + + Diff := (Button[B].H - Theme.Song.Cover.H)/2; + + + X := Sin(Angle*1.3)*0.9; + + Button[B].Y := Theme.Song.Cover.Y + Theme.Song.Cover.W * X - Diff; + end + else + begin {Behind the Front Covers} + + // limit-bg-covers hack + if (abs(VS/2-abs(Pos))>10) then Button[B].Visible:=False; + if VS > 25 then VS:=25; + // end of limit-bg-covers hack + + if Pos < 0 then + Pos := (Pos - VS/2)/VS + else + Pos := (Pos + VS/2)/VS; + + Angle := Pi * Pos*2; + + Button[B].Z := (0.4 - Abs(Pos/4)) -0.00001; //z < 0.49999 is behind the cover 1 is in front of the covers + + Button[B].H :=0.6*(Theme.Song.Cover.H-Abs(Theme.Song.Cover.H * cos(Angle/2)*0.8));//Power(Z2, 3); + + Button[B].W := Button[B].H; + + Button[B].X := Theme.Song.Cover.X - (Button[B].H - Theme.Song.Cover.H)*0.5; + + + Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H; + + Button[B].Y := Theme.Song.Cover.Y+Theme.Song.Cover.H/2-Button[b].H/2+Theme.Song.Cover.W/320*(Theme.Song.Cover.H*sin(Angle/2)*1.52); + end; + end; + end; + end; +end; + + +procedure TScreenSong.onShow; +begin + inherited; +{** + * Pause background music, so we can play it again on scorescreen + *} + SoundLib.PauseBgMusic; + + AudioPlayback.Stop; + + if Ini.Players <= 3 then PlayersPlay := Ini.Players + 1; + if Ini.Players = 4 then PlayersPlay := 6; + + //Cat Mod etc + if (Ini.Tabs_at_startup = 1) and (CatSongs.CatNumShow = -1) then + begin + CatSongs.ShowCategoryList; + FixSelected; + //Show Cat in Top Left Mod + HideCatTL; + end; + + if Length(CatSongs.Song) > 0 then + begin + //Load Music only when Song Preview is activated + if ( Ini.PreviewVolume <> 0 ) then + StartMusicPreview(); + + SetScroll; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? + end; + + //Playlist Mode + if (Mode = smNormal) then + begin + //If Playlist Shown -> Select Next automatically + if (CatSongs.CatNumShow = -3) then + begin + SelectNext; + ChangeMusic; + end; + end + //Party Mode + else if (Mode = smPartyMode) then + begin + SelectRandomSong; + //Show Menu directly in PartyMode + //But only if selected in Options + if (Ini.PartyPopup = 1) then + begin + ScreenSongMenu.MenuShow(SM_Party_Main); + end; + end; + + SetJoker; + SetStatics; +end; + +procedure TScreenSong.onHide; +begin + // turn music volume to 100% + AudioPlayback.SetVolume(1.0); + + // if preview is deactivated: load musicfile now + If (IPreviewVolumeVals[Ini.PreviewVolume] = 0) then + AudioPlayback.Open(CatSongs.Song[Interaction].Path + CatSongs.Song[Interaction].Mp3); + + // if hide then stop music (for party mode popup on exit) + if (Display.NextScreen <> @ScreenSing) and + (Display.NextScreen <> @ScreenSingModi) then + begin + StopMusicPreview(); + end; +end; + +procedure TScreenSong.DrawExtensions; +begin + //Draw Song Menu + if (ScreenSongMenu.Visible) then + begin + ScreenSongMenu.Draw; + end + else if (ScreenSongJumpto.Visible) then + begin + ScreenSongJumpto.Draw; + end +end; + +function TScreenSong.Draw: boolean; +var + dx: real; + dt: real; + I: Integer; +begin + dx := SongTarget-SongCurrent; + dt := TimeSkip * 7; + + if dt > 1 then + dt := 1; + + SongCurrent := SongCurrent + dx*dt; + + { + if SongCurrent > Catsongs.VisibleSongs then begin + SongCurrent := SongCurrent - Catsongs.VisibleSongs; + SongTarget := SongTarget - Catsongs.VisibleSongs; + end; + } + + //Log.BenchmarkStart(5); + + SetScroll; + + //Log.BenchmarkEnd(5); + //Log.LogBenchmark('SetScroll4', 5); + + //Fading Functions, Only if Covertime is under 5 Seconds + if (CoverTime < 5) then + begin + // cover fade + if (CoverTime < 1) and (CoverTime + TimeSkip >= 1) then + begin + // load new texture + Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false); + Button[Interaction].Texture.Alpha := 1; + Button[Interaction].Texture2 := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false); + Button[Interaction].Texture2.Alpha := 1; + end; + + //Update Fading Time + CoverTime := CoverTime + TimeSkip; + + //Update Fading Texture + Button[Interaction].Texture2.Alpha := (CoverTime - 1) * 1.5; + if Button[Interaction].Texture2.Alpha > 1 then + Button[Interaction].Texture2.Alpha := 1; + + end; + + //inherited Draw; + //heres a little Hack, that causes the Statics + //are Drawn after the Buttons because of some Blending Problems. + //This should cause no Problems because all Buttons on this screen + //Has Z Position. + //Draw BG + DrawBG; + + //Instead of Draw FG Procedure: + //We draw Buttons for our own + for I := 0 to Length(Button) - 1 do + Button[I].Draw; + + // Statics + for I := 0 to Length(Static) - 1 do + Static[I].Draw; + + // and texts + for I := 0 to Length(Text) - 1 do + Text[I].Draw; + + + //Draw Equalizer + if Theme.Song.Equalizer.Visible then + DrawEqualizer; + + DrawExtensions; + + Result := true; +end; + +procedure TScreenSong.SelectNext; +var + Skip: integer; + VS: Integer; +begin + VS := CatSongs.VisibleSongs; + + if VS > 0 then + begin + UnLoadDetailedCover; + + Skip := 1; + + // this 1 could be changed by CatSongs.FindNextVisible + while (not CatSongs.Song[(Interaction + Skip) mod Length(Interactions)].Visible) do + Inc(Skip); + + SongTarget := SongTarget + 1;//Skip; + + Interaction := (Interaction + Skip) mod Length(Interactions); + + // try to keep all at the beginning + if SongTarget > VS-1 then begin + SongTarget := SongTarget - VS; + SongCurrent := SongCurrent - VS; + end; + + end; + + // Interaction -> Button, ktorego okladke przeczytamy + // show uncached texture + //Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false); +end; + +procedure TScreenSong.SelectPrev; +var + Skip: integer; + VS: Integer; +begin + VS := CatSongs.VisibleSongs; + + if VS > 0 then + begin + UnLoadDetailedCover; + + Skip := 1; + + while (not CatSongs.Song[(Interaction - Skip + Length(Interactions)) mod Length(Interactions)].Visible) do Inc(Skip); + SongTarget := SongTarget - 1;//Skip; + + Interaction := (Interaction - Skip + Length(Interactions)) mod Length(Interactions); + + // try to keep all at the beginning + if SongTarget < 0 then begin + SongTarget := SongTarget + CatSongs.VisibleSongs; + SongCurrent := SongCurrent + CatSongs.VisibleSongs; + end; + + // show uncached texture + //Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false); + end; +end; + +(* +procedure TScreenSong.UpdateLCD; //TODO: maybe LCD Support as Plugin? +begin + LCD.HideCursor; + LCD.Clear; + LCD.WriteText(1, Text[TextArtist].Text); + LCD.WriteText(2, Text[TextTitle].Text); + +end; +*) + +procedure TScreenSong.StartMusicPreview(); +var + Song: TSong; +begin + AudioPlayback.Close(); + + Song := CatSongs.Song[Interaction]; + if not assigned(Song) then + Exit; + + if AudioPlayback.Open(Song.Path + Song.Mp3) then + begin + AudioPlayback.Position := AudioPlayback.Length / 4; + // set preview volume + if (Ini.PreviewFading = 0) then + begin + // music fade disabled: start with full volume + AudioPlayback.SetVolume(IPreviewVolumeVals[Ini.PreviewVolume]); + AudioPlayback.Play() + end + else + begin + // music fade enabled: start muted and fade-in + AudioPlayback.SetVolume(0); + AudioPlayback.FadeIn(Ini.PreviewFading, IPreviewVolumeVals[Ini.PreviewVolume]); + end; + end; +end; + +procedure TScreenSong.StopMusicPreview(); +begin + // Cancel pending preview requests + SDL_RemoveTimer(MusicPreviewTimer); + + // Stop preview of previous song + AudioPlayback.Stop; +end; + +function MusicPreviewTimerCallback(interval: UInt32; param: Pointer): UInt32; cdecl; +var + ScreenSong: TScreenSong; +begin + ScreenSong := TScreenSong(param); + if (ScreenSong <> nil) then + ScreenSong.StartMusicPreview(); + Result := 0; +end; + +// Changes previewed song +procedure TScreenSong.ChangeMusic; +begin + StopMusicPreview(); + + // Preview song if activated and current selection is not a category cover + if (CatSongs.VisibleSongs > 0) and + (not CatSongs.Song[Interaction].Main) and + (Ini.PreviewVolume <> 0) then + begin + // Delay song fading to prevent the song from being played while scrolling + MusicPreviewTimer := SDL_AddTimer(200, MusicPreviewTimerCallback, Self); + end; +end; + +procedure TScreenSong.SkipTo(Target: Cardinal); +var + i: integer; +begin + UnLoadDetailedCover; + + Interaction := High(CatSongs.Song); + SongTarget := 0; + + for i := 1 to Target+1 do + SelectNext; + + FixSelected2; +end; + +procedure TScreenSong.DrawEqualizer; +var + I, J: Integer; + ChansPerBand: byte; // channels per band + MaxChannel: Integer; + CurBand: Integer; // current band + CurTime: Cardinal; + PosX, PosY: Integer; + Pos: Real; +begin + // Nothing to do if no music is played or an equalizer bar consists of no block + if (AudioPlayback.Finished or (Theme.Song.Equalizer.Length <= 0)) then + Exit; + + CurTime := SDL_GetTicks(); + + // Evaluate FFT-data every 44 ms + if (CurTime >= EqualizerTime) then + begin + EqualizerTime := CurTime + 44; + AudioPlayback.GetFFTData(EqualizerData); + + Pos := 0; + // use only the first approx. 92 of 256 FFT-channels (approx. up to 8kHz + ChansPerBand := ceil(92 / Theme.Song.Equalizer.Bands); // How much channels are used for one Band + MaxChannel := ChansPerBand * Theme.Song.Equalizer.Bands - 1; + + // Change Lengths + for i := 0 to MaxChannel do + begin + // Gain higher freq. data so that the bars are visible + if i > 35 then + EqualizerData[i] := EqualizerData[i] * 8 + else if i > 11 then + EqualizerData[i] := EqualizerData[i] * 4.5 + else + EqualizerData[i] := EqualizerData[i] * 1.1; + + // clamp data + if (EqualizerData[i] > 1) then + EqualizerData[i] := 1; + + // Get max. pos + if (EqualizerData[i] * Theme.Song.Equalizer.Length > Pos) then + Pos := EqualizerData[i] * Theme.Song.Equalizer.Length; + + // Check if this is the last channel in the band + if ((i+1) mod ChansPerBand = 0) then + begin + CurBand := i div ChansPerBand; + + // Smooth delay if new equalizer is lower than the old one + if ((EqualizerBands[CurBand] > Pos) and (EqualizerBands[CurBand] > 1)) then + EqualizerBands[CurBand] := EqualizerBands[CurBand] - 1 + else + EqualizerBands[CurBand] := Round(Pos); + + Pos := 0; + end; + end; + + end; + + // Draw equalizer bands + + // Setup OpenGL + glColor4f(Theme.Song.Equalizer.ColR, Theme.Song.Equalizer.ColG, Theme.Song.Equalizer.ColB, Theme.Song.Equalizer.Alpha); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + // Set position of the first equalizer bar + PosY := Theme.Song.Equalizer.Y; + PosX := Theme.Song.Equalizer.X; + + // Draw bars for each band + for I := 0 to High(EqualizerBands) do + begin + // Reset to lower or left position depending on the drawing-direction + if Theme.Song.Equalizer.Direction then // Vertical bars + // FIXME: Is Theme.Song.Equalizer.Y the upper or lower coordinate? + PosY := Theme.Song.Equalizer.Y //+ (Theme.Song.Equalizer.H + Theme.Song.Equalizer.Space) * Theme.Song.Equalizer.Length + else // Horizontal bars + PosX := Theme.Song.Equalizer.X; + + // Draw the bar as a stack of blocks + for J := 1 to EqualizerBands[I] do + begin + // Draw block + glBegin(GL_QUADS); + glVertex3f(PosX, PosY, Theme.Song.Equalizer.Z); + glVertex3f(PosX, PosY+Theme.Song.Equalizer.H, Theme.Song.Equalizer.Z); + glVertex3f(PosX+Theme.Song.Equalizer.W, PosY+Theme.Song.Equalizer.H, Theme.Song.Equalizer.Z); + glVertex3f(PosX+Theme.Song.Equalizer.W, PosY, Theme.Song.Equalizer.Z); + glEnd; + + // Calc position of the bar's next block + if Theme.Song.Equalizer.Direction then // Vertical bars + PosY := PosY - Theme.Song.Equalizer.H - Theme.Song.Equalizer.Space + else // Horizontal bars + PosX := PosX + Theme.Song.Equalizer.W + Theme.Song.Equalizer.Space; + end; + + // Calc position of the next bar + if Theme.Song.Equalizer.Direction then // Vertical bars + PosX := PosX + Theme.Song.Equalizer.W + Theme.Song.Equalizer.Space + else // Horizontal bars + PosY := PosY + Theme.Song.Equalizer.H + Theme.Song.Equalizer.Space; + end; +end; + +procedure TScreenSong.SelectRandomSong; +var + I, I2: Integer; +begin + case PlaylistMan.Mode of + smNormal: //All Songs Just Select Random Song + begin + //When Tabs are activated then use Tab Method + if (Ini.Tabs_at_startup = 1) then + begin + repeat + I2 := Random(high(CatSongs.Song)+1) - low(CatSongs.Song)+1; + until CatSongs.Song[I2].Main = false; + + //Search Cat + for I := I2 downto low(CatSongs.Song) do + begin + if CatSongs.Song[I].Main then + break; + end; + //In I ist jetzt die Kategorie in I2 der Song + //I is the CatNum, I2 is the No of the Song within this Cat + + //Choose Cat + CatSongs.ShowCategoryList; + + //Show Cat in Top Left Mod + ShowCatTL (I); + + CatSongs.ClickCategoryButton(I); + SelectNext; + + //Choose Song + SkipTo(I2-I); + end + //When Tabs are deactivated use easy Method + else + SkipTo(Random(CatSongs.VisibleSongs)); + end; + smPartyMode: //One Category Select Category and Select Random Song + begin + CatSongs.ShowCategoryList; + CatSongs.ClickCategoryButton(PlaylistMan.CurPlayList); + ShowCatTL(PlaylistMan.CurPlayList); + + SelectNext; + FixSelected2; + + SkipTo(Random(CatSongs.VisibleSongs)); + end; + smPlaylistRandom: //Playlist: Select Playlist and Select Random Song + begin + PlaylistMan.SetPlayList(PlaylistMan.CurPlayList); + + SkipTo(Random(CatSongs.VisibleSongs)); + FixSelected2; + end; + end; + + AudioPlayback.PlaySound(SoundLib.Change); + ChangeMusic; + SetScroll; + //UpdateLCD; //TODO: maybe LCD Support as Plugin? +end; + +procedure TScreenSong.SetJoker; +begin + // If Party Mode + // to-do : Party + if Mode = smPartyMode then //Show Joker that are available + begin + (* + if (PartySession.Teams.NumTeams >= 1) then + begin + Static[StaticTeam1Joker1].Visible := (PartySession.Teams.Teaminfo[0].Joker >= 1); + Static[StaticTeam1Joker2].Visible := (PartySession.Teams.Teaminfo[0].Joker >= 2); + Static[StaticTeam1Joker3].Visible := (PartySession.Teams.Teaminfo[0].Joker >= 3); + Static[StaticTeam1Joker4].Visible := (PartySession.Teams.Teaminfo[0].Joker >= 4); + Static[StaticTeam1Joker5].Visible := (PartySession.Teams.Teaminfo[0].Joker >= 5); + end + else + begin + Static[StaticTeam1Joker1].Visible := False; + Static[StaticTeam1Joker2].Visible := False; + Static[StaticTeam1Joker3].Visible := False; + Static[StaticTeam1Joker4].Visible := False; + Static[StaticTeam1Joker5].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 2) then + begin + Static[StaticTeam2Joker1].Visible := (PartySession.Teams.Teaminfo[1].Joker >= 1); + Static[StaticTeam2Joker2].Visible := (PartySession.Teams.Teaminfo[1].Joker >= 2); + Static[StaticTeam2Joker3].Visible := (PartySession.Teams.Teaminfo[1].Joker >= 3); + Static[StaticTeam2Joker4].Visible := (PartySession.Teams.Teaminfo[1].Joker >= 4); + Static[StaticTeam2Joker5].Visible := (PartySession.Teams.Teaminfo[1].Joker >= 5); + end + else + begin + Static[StaticTeam2Joker1].Visible := False; + Static[StaticTeam2Joker2].Visible := False; + Static[StaticTeam2Joker3].Visible := False; + Static[StaticTeam2Joker4].Visible := False; + Static[StaticTeam2Joker5].Visible := False; + end; + + if (PartySession.Teams.NumTeams >= 3) then + begin + Static[StaticTeam3Joker1].Visible := (PartySession.Teams.Teaminfo[2].Joker >= 1); + Static[StaticTeam3Joker2].Visible := (PartySession.Teams.Teaminfo[2].Joker >= 2); + Static[StaticTeam3Joker3].Visible := (PartySession.Teams.Teaminfo[2].Joker >= 3); + Static[StaticTeam3Joker4].Visible := (PartySession.Teams.Teaminfo[2].Joker >= 4); + Static[StaticTeam3Joker5].Visible := (PartySession.Teams.Teaminfo[2].Joker >= 5); + end + else + begin + Static[StaticTeam3Joker1].Visible := False; + Static[StaticTeam3Joker2].Visible := False; + Static[StaticTeam3Joker3].Visible := False; + Static[StaticTeam3Joker4].Visible := False; + Static[StaticTeam3Joker5].Visible := False; + end; + *) + end + else + begin //Hide all + Static[StaticTeam1Joker1].Visible := False; + Static[StaticTeam1Joker2].Visible := False; + Static[StaticTeam1Joker3].Visible := False; + Static[StaticTeam1Joker4].Visible := False; + Static[StaticTeam1Joker5].Visible := False; + + Static[StaticTeam2Joker1].Visible := False; + Static[StaticTeam2Joker2].Visible := False; + Static[StaticTeam2Joker3].Visible := False; + Static[StaticTeam2Joker4].Visible := False; + Static[StaticTeam2Joker5].Visible := False; + + Static[StaticTeam3Joker1].Visible := False; + Static[StaticTeam3Joker2].Visible := False; + Static[StaticTeam3Joker3].Visible := False; + Static[StaticTeam3Joker4].Visible := False; + Static[StaticTeam3Joker5].Visible := False; + end; +end; + +procedure TScreenSong.SetStatics; +var + I: Integer; + Visible: Boolean; +begin + //Set Visibility of Party Statics and Text + Visible := (Mode = smPartyMode); + + for I := 0 to high(StaticParty) do + Static[StaticParty[I]].Visible := Visible; + + for I := 0 to high(TextParty) do + Text[TextParty[I]].Visible := Visible; + + //Set Visibility of Non Party Statics and Text + Visible := not Visible; + + for I := 0 to high(StaticNonParty) do + Static[StaticNonParty[I]].Visible := Visible; + + for I := 0 to high(TextNonParty) do + Text[TextNonParty[I]].Visible := Visible; +end; + +//Procedures for Menu + +procedure TScreenSong.StartSong; +begin + CatSongs.Selected := Interaction; + StopMusicPreview(); + + //Party Mode + if (Mode = smPartyMode) then + begin + FadeTo(@ScreenSingModi); + end + else + begin + FadeTo(@ScreenSing); + end; +end; + +procedure TScreenSong.SelectPlayers; +begin + CatSongs.Selected := Interaction; + StopMusicPreview(); + + ScreenName.Goto_SingScreen := True; + FadeTo(@ScreenName); +end; + +procedure TScreenSong.OpenEditor; +begin + if (Songs.SongList.Count > 0) and + (not CatSongs.Song[Interaction].Main) and + (Mode = smNormal) then + begin + StopMusicPreview(); + AudioPlayback.PlaySound(SoundLib.Start); + CurrentSong := CatSongs.Song[Interaction]; + FadeTo(@ScreenEditSub); + end; +end; + +//Team No of Team (0-5) +procedure TScreenSong.DoJoker (Team: Byte); +begin + { + if (Mode = smPartyMode) and + (PartySession.Teams.NumTeams >= Team + 1) and + (PartySession.Teams.Teaminfo[Team].Joker > 0) then + begin + //Use Joker + Dec(PartySession.Teams.Teaminfo[Team].Joker); + SelectRandomSong; + SetJoker; + end; + } +end; + +//Detailed Cover Unloading. Unloads the Detailed, uncached Cover of the cur. Song +procedure TScreenSong.UnloadDetailedCover; +begin + CoverTime := 0; + + // show cached texture + Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, true); + Button[Interaction].Texture2.Alpha := 0; + + if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then + Texture.UnloadTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false); +end; + +procedure TScreenSong.Refresh; +begin + { + CatSongs.Refresh; + CatSongs.ShowCategoryList; + Interaction := 0; + SelectNext; + FixSelected; + } +end; + +end. diff --git a/src/screens/UScreenSongJumpto.pas b/src/screens/UScreenSongJumpto.pas new file mode 100644 index 00000000..89d198cc --- /dev/null +++ b/src/screens/UScreenSongJumpto.pas @@ -0,0 +1,212 @@ +unit UScreenSongJumpto; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, UDisplay, UMusic, UFiles, SysUtils, UThemes; + +type + TScreenSongJumpto = class(TMenu) + private + //For ChangeMusic + LastPlayed: Integer; + VisibleBool: Boolean; + public + VisSongs: Integer; + + constructor Create; override; + + //Visible //Whether the Menu should be Drawn + //Whether the Menu should be Drawn + procedure SetVisible(Value: Boolean); + property Visible: Boolean read VisibleBool write SetVisible; + + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + function Draw: boolean; override; + + procedure SetTextFound(const Count: Cardinal); + end; + +var + IType: Array [0..2] of String; + SelectType: Integer; + + +implementation + +uses UGraphic, UMain, UIni, UTexture, ULanguage, UParty, USongs, UScreenSong, ULog; + +function TScreenSongJumpto.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case CharCode of + '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"', + '[', '{', ';', ':': + begin + if Interaction = 0 then + begin + Button[0].Text[0].Text := Button[0].Text[0].Text + CharCode; + SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType)); + end; + end; + end; + + // check special keys + case PressedKey of + SDLK_BACKSPACE: + begin + if (Interaction = 0) AND (Length(Button[0].Text[0].Text) > 0) then + begin + Button[0].Text[0].DeleteLastL; + SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType)); + end; + end; + + SDLK_RETURN, + SDLK_ESCAPE: + begin + Visible := False; + AudioPlayback.PlaySound(SoundLib.Back); + if (VisSongs = 0) AND (Length(Button[0].Text[0].Text) > 0) then + begin + ScreenSong.UnLoadDetailedCover; + Button[0].Text[0].Text := ''; + CatSongs.SetFilter('', 0); + SetTextFound(0); + end; + end; + + // Up and Down could be done at the same time, + // but I don't want to declare variables inside + // functions like this one, called so many times + SDLK_DOWN: + begin + {SelectNext; + Button[0].Text[0].Selected := (Interaction = 0);} + end; + + SDLK_UP: + begin + {SelectPrev; + Button[0].Text[0].Selected := (Interaction = 0); } + end; + + SDLK_RIGHT: + begin + Interaction := 1; + InteractInc; + if (Length(Button[0].Text[0].Text) > 0) then + SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType)); + Interaction := 0; + end; + SDLK_LEFT: + begin + Interaction := 1; + InteractDec; + if (Length(Button[0].Text[0].Text) > 0) then + SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType)); + Interaction := 0; + end; + end; + end; +end; + +constructor TScreenSongJumpto.Create; +//var +// I: integer; // Auto Removed, Unused Variable +begin + inherited Create; + + AddText(Theme.SongJumpto.TextFound); + + LoadFromTheme(Theme.SongJumpto); + + AddButton(Theme.SongJumpto.ButtonSearchText); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, ''); + + SelectType := 0; + AddSelectSlide(Theme.SongJumpto.SelectSlideType, SelectType, Theme.SongJumpto.IType); + + + Interaction := 0; + LastPlayed := 0; +end; + +procedure TScreenSongJumpto.SetVisible(Value: Boolean); +begin +//If change from unvisible to Visible then OnShow + if (VisibleBool = False) AND (Value = True) then + OnShow; + + VisibleBool := Value; +end; + +procedure TScreenSongJumpto.onShow; +begin + inherited; + + //Reset Screen if no Old Search is Displayed + if (CatSongs.CatNumShow <> -2) then + begin + SelectsS[0].SetSelectOpt(0); + + Button[0].Text[0].Text := ''; + Text[0].Text := Theme.SongJumpto.NoSongsFound; + end; + + //Select Input + Interaction := 0; + Button[0].Text[0].Selected := True; + + LastPlayed := ScreenSong.Interaction; +end; + +function TScreenSongJumpto.Draw: boolean; +begin + Result := inherited Draw; +end; + +procedure TScreenSongJumpto.SetTextFound(const Count: Cardinal); +begin + if (Count = 0) then + begin + Text[0].Text := Theme.SongJumpto.NoSongsFound; + if (Length(Button[0].Text[0].Text) = 0) then + ScreenSong.HideCatTL + else + ScreenSong.ShowCatTLCustom(Format(Theme.SongJumpto.CatText, [Button[0].Text[0].Text])); + end + else + begin + Text[0].Text := Format(Theme.SongJumpto.SongsFound, [Count]); + + //Set CatTopLeftText + ScreenSong.ShowCatTLCustom(Format(Theme.SongJumpto.CatText, [Button[0].Text[0].Text])); + end; + + + //Set visSongs + VisSongs := Count; + + //Fix SongSelection + ScreenSong.Interaction := high(CatSongs.Song); + ScreenSong.SelectNext; + ScreenSong.FixSelected; + + //Play Correct Music + if (ScreenSong.Interaction <> LastPlayed) then + begin + LastPlayed := ScreenSong.Interaction; + + ScreenSong.ChangeMusic; + end; +end; + +end. diff --git a/src/screens/UScreenSongMenu.pas b/src/screens/UScreenSongMenu.pas new file mode 100644 index 00000000..74e2c3fc --- /dev/null +++ b/src/screens/UScreenSongMenu.pas @@ -0,0 +1,641 @@ +unit UScreenSongMenu; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, + SDL, + UDisplay, + UMusic, + UFiles, + SysUtils, + UThemes; + +type + TScreenSongMenu = class(TMenu) + private + CurMenu: Byte; //Num of the cur. Shown Menu + public + Visible: Boolean; //Whether the Menu should be Drawn + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + function Draw: boolean; override; + procedure MenuShow(sMenu: Byte); + procedure HandleReturn; + end; + +const + SM_Main = 1; + + SM_PlayList = 64 or 1; + SM_Playlist_Add = 64 or 2; + SM_Playlist_New = 64 or 3; + + SM_Playlist_DelItem = 64 or 5; + + SM_Playlist_Load = 64 or 8 or 1; + SM_Playlist_Del = 64 or 8 or 5; + + + SM_Party_Main = 128 or 1; + SM_Party_Joker = 128 or 2; + +var + ISelections: Array of String; + SelectValue: Integer; + + +implementation + +uses UGraphic, + UMain, + UIni, + UTexture, + ULanguage, + UParty, + UPlaylist, + USongs; + +function TScreenSongMenu.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + if (PressedDown) then + begin // Key Down + if (CurMenu = SM_Playlist_New) AND (Interaction=0) then + begin + // check normal keys + case WideCharUpperCase(CharCode)[1] of + '0'..'9', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"': + begin + Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode; + exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_BACKSPACE: + begin + Button[Interaction].Text[0].DeleteLastL; + exit; + end; + end; + end; + + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + Visible := False; + end; + + SDLK_RETURN: + begin + HandleReturn; + end; + + SDLK_DOWN: InteractNext; + SDLK_UP: InteractPrev; + + SDLK_RIGHT: + begin + if (Interaction=3) then + InteractInc; + end; + SDLK_LEFT: + begin + if (Interaction=3) then + InteractDec; + end; + + SDLK_1: + begin //Jocker + //Use Joker + case CurMenu of + SM_Party_Main: + begin + ScreenSong.DoJoker(0) + end; + end; + end; + SDLK_2: + begin //Jocker + //Use Joker + case CurMenu of + SM_Party_Main: + begin + ScreenSong.DoJoker(1) + end; + end; + end; + SDLK_3: + begin //Jocker + //Use Joker + case CurMenu of + SM_Party_Main: + begin + ScreenSong.DoJoker(2) + end; + end; + end; + end; // case + end; // if +end; + +constructor TScreenSongMenu.Create; +var + I: integer; +begin + inherited Create; + + //Create Dummy SelectSlide Entrys + SetLength(ISelections, 1); + ISelections[0] := 'Dummy'; + + + AddText(Theme.SongMenu.TextMenu); + + LoadFromTheme(Theme.SongMenu); + + AddButton(Theme.SongMenu.Button1); + if (Length(Button[0].Text) = 0) then + AddButtonText(14, 20, 'Button 1'); + + AddButton(Theme.SongMenu.Button2); + if (Length(Button[1].Text) = 0) then + AddButtonText(14, 20, 'Button 2'); + + AddButton(Theme.SongMenu.Button3); + if (Length(Button[2].Text) = 0) then + AddButtonText(14, 20, 'Button 3'); + + AddSelectSlide(Theme.SongMenu.SelectSlide3, SelectValue, ISelections); + + AddButton(Theme.SongMenu.Button4); + if (Length(Button[3].Text) = 0) then + AddButtonText(14, 20, 'Button 4'); + + + Interaction := 0; +end; + +function TScreenSongMenu.Draw: boolean; +begin + Result := inherited Draw; +end; + +procedure TScreenSongMenu.onShow; +begin + inherited; + +end; + +procedure TScreenSongMenu.MenuShow(sMenu: Byte); +begin + Interaction := 0; //Reset Interaction + Visible := True; //Set Visible + Case sMenu of + SM_Main: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_MAIN'); + + Button[0].Visible := True; + Button[1].Visible := True; + Button[2].Visible := True; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAY'); + Button[1].Text[0].Text := Language.Translate('SONG_MENU_CHANGEPLAYERS'); + Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_ADD'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_EDIT'); + end; + + SM_PlayList: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST'); + + Button[0].Visible := True; + Button[1].Visible := True; + Button[2].Visible := True; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAY'); + Button[1].Text[0].Text := Language.Translate('SONG_MENU_CHANGEPLAYERS'); + Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_DEL'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_EDIT'); + end; + + SM_Playlist_Add: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST_ADD'); + + Button[0].Visible := True; + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := True; + SelectsS[0].Visible := True; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_ADD_NEW'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_ADD_EXISTING'); + + SetLength(ISelections, Length(PlaylistMan.Playlists)); + PlaylistMan.GetNames(ISelections); + + if (Length(ISelections)>=1) then + begin + UpdateSelectSlideOptions(Theme.SongMenu.SelectSlide3, 0, ISelections, SelectValue); + end + else + begin + Button[3].Visible := False; + SelectsS[0].Visible := False; + Button[2].Visible := True; + Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_NOEXISTING'); + end; + end; + + SM_Playlist_New: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST_NEW'); + + Button[0].Visible := True; + Button[1].Visible := False; + Button[2].Visible := True; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_NEW_UNNAMED'); + Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_NEW_CREATE'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_CANCEL'); + end; + + SM_Playlist_DelItem: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST_DELITEM'); + + Button[0].Visible := True; + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_YES'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_CANCEL'); + end; + + SM_Playlist_Load: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST_LOAD'); + + //Show Delete Curent Playlist Button when Playlist is opened + Button[0].Visible := (CatSongs.CatNumShow = -3); + + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := True; + SelectsS[0].Visible := True; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_DELCURRENT'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_LOAD'); + + SetLength(ISelections, Length(PlaylistMan.Playlists)); + PlaylistMan.GetNames(ISelections); + + if (Length(ISelections)>=1) then + begin + UpdateSelectSlideOptions(Theme.SongMenu.SelectSlide3, 0, ISelections, SelectValue); + Interaction := 3; + end + else + begin + Button[3].Visible := False; + SelectsS[0].Visible := False; + Button[2].Visible := True; + Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYLIST_NOEXISTING'); + Interaction := 2; + end; + end; + + SM_Playlist_Del: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PLAYLIST_DEL'); + + Button[0].Visible := True; + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_YES'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_CANCEL'); + end; + + + SM_Party_Main: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PARTY_MAIN'); + + Button[0].Visible := True; + Button[1].Visible := False; + Button[2].Visible := False; + Button[3].Visible := True; + SelectsS[0].Visible := False; + + Button[0].Text[0].Text := Language.Translate('SONG_MENU_PLAY'); + //Button[1].Text[0].Text := Language.Translate('SONG_MENU_JOKER'); + //Button[2].Text[0].Text := Language.Translate('SONG_MENU_PLAYMODI'); + Button[3].Text[0].Text := Language.Translate('SONG_MENU_JOKER'); + end; + + SM_Party_Joker: + begin + CurMenu := sMenu; + Text[0].Text := Language.Translate('SONG_MENU_NAME_PARTY_JOKER'); + // to-do : Party + {Button[0].Visible := (PartySession.Teams.NumTeams >= 1) AND (PartySession.Teams.Teaminfo[0].Joker > 0); + Button[1].Visible := (PartySession.Teams.NumTeams >= 2) AND (PartySession.Teams.Teaminfo[1].Joker > 0); + Button[2].Visible := (PartySession.Teams.NumTeams >= 3) AND (PartySession.Teams.Teaminfo[2].Joker > 0);} + Button[3].Visible := True; + SelectsS[0].Visible := False; + + {Button[0].Text[0].Text := String(PartySession.Teams.Teaminfo[0].Name); + Button[1].Text[0].Text := String(PartySession.Teams.Teaminfo[1].Name); + Button[2].Text[0].Text := String(PartySession.Teams.Teaminfo[2].Name);} + Button[3].Text[0].Text := Language.Translate('SONG_MENU_CANCEL'); + + //Set right Interaction + if (not Button[0].Visible) then + begin + if (not Button[1].Visible) then + begin + if (not Button[2].Visible) then + begin + Interaction := 4; + end + else Interaction := 2; + end + else Interaction := 1; + end; + + end; + end; +end; + +procedure TScreenSongMenu.HandleReturn; +begin + Case CurMenu of + SM_Main: + begin + Case Interaction of + 0: //Button 1 + begin + ScreenSong.StartSong; + Visible := False; + end; + + 1: //Button 2 + begin + //Select New Players then Sing: + ScreenSong.SelectPlayers; + Visible := False; + end; + + 2: //Button 3 + begin + //Show add to Playlist Menu + MenuShow(SM_Playlist_Add); + end; + + 3: //SelectSlide 3 + begin + //Dummy + end; + + 4: //Button 4 + begin + ScreenSong.OpenEditor; + Visible := False; + end; + end; + end; + + SM_PlayList: + begin + Visible := False; + Case Interaction of + 0: //Button 1 + begin + ScreenSong.StartSong; + Visible := False; + end; + + 1: //Button 2 + begin + //Select New Players then Sing: + ScreenSong.SelectPlayers; + Visible := False; + end; + + 2: //Button 3 + begin + //Show add to Playlist Menu + MenuShow(SM_Playlist_DelItem); + end; + + 3: //SelectSlide 3 + begin + //Dummy + end; + + 4: //Button 4 + begin + ScreenSong.OpenEditor; + Visible := False; + end; + end; + end; + + SM_Playlist_Add: + begin + Case Interaction of + 0: //Button 1 + begin + MenuShow(SM_Playlist_New); + end; + + 3: //SelectSlide 3 + begin + //Dummy + end; + + 4: //Button 4 + begin + PlaylistMan.AddItem(ScreenSong.Interaction, SelectValue); + Visible := False; + end; + end; + end; + + SM_Playlist_New: + begin + Case Interaction of + 0: //Button 1 + begin + //Nothing, Button for Entering Name + end; + + 2: //Button 3 + begin + //Create Playlist and Add Song + PlaylistMan.AddItem( + ScreenSong.Interaction, + PlaylistMan.AddPlaylist(Button[0].Text[0].Text)); + Visible := False; + end; + + 3: //SelectSlide 3 + begin + //Cancel -> Go back to Add screen + MenuShow(SM_Playlist_Add); + end; + + 4: //Button 4 + begin + Visible := False; + end; + end; + end; + + SM_Playlist_DelItem: + begin + Visible := False; + Case Interaction of + 0: //Button 1 + begin + //Delete + PlayListMan.DelItem(PlayListMan.GetIndexbySongID(ScreenSong.Interaction)); + Visible := False; + end; + + 4: //Button 4 + begin + MenuShow(SM_Playlist); + end; + end; + end; + + SM_Playlist_Load: + begin + Case Interaction of + 0: //Button 1 (Delete Playlist) + begin + MenuShow(SM_Playlist_Del); + end; + 4: //Button 4 + begin + //Load Playlist + PlaylistMan.SetPlayList(SelectValue); + Visible := False; + end; + end; + end; + + SM_Playlist_Del: + begin + Visible := False; + Case Interaction of + 0: //Button 1 + begin + //Delete + PlayListMan.DelPlaylist(PlaylistMan.CurPlayList); + Visible := False; + end; + + 4: //Button 4 + begin + MenuShow(SM_Playlist_Load); + end; + end; + end; + + SM_Party_Main: + begin + Case Interaction of + 0: //Button 1 + begin + //Start Singing + ScreenSong.StartSong; + Visible := False; + end; + + 4: //Button 4 + begin + //Joker + MenuShow(SM_Party_Joker); + end; + end; + end; + + SM_Party_Joker: + begin + Visible := False; + Case Interaction of + 0: //Button 1 + begin + //Joker Team 1 + ScreenSong.DoJoker(0); + end; + + 1: //Button 2 + begin + //Joker Team 2 + ScreenSong.DoJoker(1); + end; + + 2: //Button 3 + begin + //Joker Team 3 + ScreenSong.DoJoker(2); + end; + + 4: //Button 4 + begin + //Cancel... (Fo back to old Menu) + MenuShow(SM_Party_Main); + end; + end; + end; + end; +end; + +end. + diff --git a/src/screens/UScreenStatDetail.pas b/src/screens/UScreenStatDetail.pas new file mode 100644 index 00000000..891b108d --- /dev/null +++ b/src/screens/UScreenStatDetail.pas @@ -0,0 +1,270 @@ +unit UScreenStatDetail; + +interface + +{$I switches.inc} + +uses + UMenu, + SDL, + SysUtils, + UDisplay, + UMusic, + UIni, + UDataBase, + UThemes; + +type + TScreenStatDetail = class(TMenu) + public + Typ: TStatType; + Page: Cardinal; + Count: Byte; + Reversed: Boolean; + + TotEntrys: Cardinal; + TotPages: Cardinal; + + + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + + procedure SetTitle; + Procedure SetPage(NewPage: Cardinal); + end; + +implementation + +uses + UGraphic, + ULanguage, + Math, + Classes, + ULog; + +function TScreenStatDetail.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenStatMain); + end; + SDLK_RETURN: + begin + if Interaction = 0 then begin + //Next Page + SetPage(Page+1); + end; + + if Interaction = 1 then begin + //Previous Page + if (Page > 0) then + SetPage(Page-1); + end; + + if Interaction = 2 then begin + //Reverse Order + Reversed := not Reversed; + SetPage(Page); + end; + + if Interaction = 3 then begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenStatMain); + end; + end; + SDLK_LEFT: + begin + InteractPrev; + end; + SDLK_RIGHT: + begin + InteractNext; + end; + SDLK_UP: + begin + InteractPrev; + end; + SDLK_DOWN: + begin + InteractNext; + end; + end; + end; +end; + +constructor TScreenStatDetail.Create; +var + I: integer; +begin + inherited Create; + + for I := 0 to High(Theme.StatDetail.TextList) do + AddText(Theme.StatDetail.TextList[I]); + + Count := Length(Theme.StatDetail.TextList); + + AddText(Theme.StatDetail.TextDescription); + AddText(Theme.StatDetail.TextPage); + + LoadFromTheme(Theme.StatDetail); + + AddButton(Theme.StatDetail.ButtonNext); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Language.Translate('STAT_NEXT')); + + AddButton(Theme.StatDetail.ButtonPrev); + if (Length(Button[1].Text)=0) then + AddButtonText(14, 20, Language.Translate('STAT_PREV')); + + AddButton(Theme.StatDetail.ButtonReverse); + if (Length(Button[2].Text)=0) then + AddButtonText(14, 20, Language.Translate('STAT_REVERSE')); + + AddButton(Theme.StatDetail.ButtonExit); + if (Length(Button[3].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[7]); + + Interaction := 0; + Typ := TStatType(0); +end; + +procedure TScreenStatDetail.onShow; +begin + inherited; + + //Set Tot Entrys and PAges + TotEntrys := DataBase.GetTotalEntrys(Typ); + TotPages := Ceil(TotEntrys / Count); + + //Show correct Title + SetTitle; + + //Show First Page + Reversed := False; + SetPage(0); +end; + +procedure TScreenStatDetail.SetTitle; +begin + if Reversed then + Text[Count].Text := Theme.StatDetail.DescriptionR[Ord(Typ)] + else + Text[Count].Text := Theme.StatDetail.Description[Ord(Typ)]; +end; + +procedure TScreenStatDetail.SetPage(NewPage: Cardinal); +var + StatList: TList; + I: Integer; + FormatStr: String; + PerPage: Byte; +begin + // fetch statistics + StatList := Database.GetStats(Typ, Count, NewPage, Reversed); + if ((StatList <> nil) and (StatList.Count > 0)) then + begin + Page := NewPage; + + // reset texts + for I := 0 to Count-1 do + Text[I].Text := ''; + + FormatStr := Theme.StatDetail.FormatStr[Ord(Typ)]; + + //refresh Texts + for I := 0 to StatList.Count-1 do + begin + try + case Typ of + stBestScores: begin //Best Scores + with TStatResultBestScores(StatList[I]) do + begin + //Set Texts + if (Score > 0) then + begin + Text[I].Text := Format(FormatStr, + [Singer, Score, Theme.ILevel[Difficulty], SongArtist, SongTitle]); + end; + end; + end; + + stBestSingers: begin //Best Singers + with TStatResultBestSingers(StatList[I]) do + begin + //Set Texts + if (AverageScore > 0) then + Text[I].Text := Format(FormatStr, [Player, AverageScore]); + end; + end; + + stMostSungSong: begin //Popular Songs + with TStatResultMostSungSong(StatList[I]) do + begin + //Set Texts + if (Artist <> '') then + Text[I].Text := Format(FormatStr, [Artist, Title, TimesSung]); + end; + end; + + stMostPopBand: begin //Popular Bands + with TStatResultMostPopBand(StatList[I]) do + begin + //Set Texts + if (ArtistName <> '') then + Text[I].Text := Format(FormatStr, [ArtistName, TimesSungtot]); + end; + end; + end; + except + on E: EConvertError do + Log.LogError('Error Parsing FormatString in UScreenStatDetail: ' + E.Message); + end; + end; + + if (Page + 1 = TotPages) and (TotEntrys mod Count <> 0) then + PerPage := (TotEntrys mod Count) + else + PerPage := Count; + + try + Text[Count+1].Text := Format(Theme.StatDetail.PageStr, + [Page + 1, TotPages, PerPage, TotEntrys]); + except + on E: EConvertError do + Log.LogError('Error Parsing FormatString in UScreenStatDetail: ' + E.Message); + end; + + //Show correct Title + SetTitle; + end; + + Database.FreeStats(StatList); +end; + + +procedure TScreenStatDetail.SetAnimationProgress(Progress: real); +var I: Integer; +begin + for I := 0 to High(Button) do + Button[I].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenStatMain.pas b/src/screens/UScreenStatMain.pas new file mode 100644 index 00000000..bec9d312 --- /dev/null +++ b/src/screens/UScreenStatMain.pas @@ -0,0 +1,301 @@ +unit UScreenStatMain; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, + SDL, + SysUtils, + UDisplay, + UMusic, + UIni, + UThemes; + +type + TScreenStatMain = class(TMenu) + private + //Some Stat Value that don't need to be calculated 2 times + SongsWithVid: Cardinal; + function FormatOverviewIntro(FormatStr: string): string; + function FormatSongOverview(FormatStr: string): string; + function FormatPlayerOverview(FormatStr: string): string; + public + TextOverview: integer; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + procedure SetAnimationProgress(Progress: real); override; + + procedure SetOverview; + end; + +implementation + +uses UGraphic, + UDataBase, + USongs, + USong, + ULanguage, + UCommon, + Classes, + {$IFDEF win32} + windows, + {$ELSE} + sysconst, + {$ENDIF} + ULog; + +function TScreenStatMain.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then + begin // Key Down + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + Ini.Save; + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end; + SDLK_RETURN: + begin + //Exit Button Pressed + if Interaction = 4 then + begin + AudioPlayback.PlaySound(SoundLib.Back); + FadeTo(@ScreenMain); + end + else //One of the Stats Buttons Pressed + begin + AudioPlayback.PlaySound(SoundLib.Back); + ScreenStatDetail.Typ := TStatType(Interaction); + FadeTo(@ScreenStatDetail); + end; + end; + SDLK_LEFT: + begin + InteractPrev; + end; + SDLK_RIGHT: + begin + InteractNext; + end; + SDLK_UP: + begin + InteractPrev; + end; + SDLK_DOWN: + begin + InteractNext; + end; + end; + end; +end; + +constructor TScreenStatMain.Create; +var + I: integer; +begin + inherited Create; + + TextOverview := AddText(Theme.StatMain.TextOverview); + + LoadFromTheme(Theme.StatMain); + + AddButton(Theme.StatMain.ButtonScores); + if (Length(Button[0].Text)=0) then + AddButtonText(14, 20, Theme.StatDetail.Description[0]); + + AddButton(Theme.StatMain.ButtonSingers); + if (Length(Button[1].Text)=0) then + AddButtonText(14, 20, Theme.StatDetail.Description[1]); + + AddButton(Theme.StatMain.ButtonSongs); + if (Length(Button[2].Text)=0) then + AddButtonText(14, 20, Theme.StatDetail.Description[2]); + + AddButton(Theme.StatMain.ButtonBands); + if (Length(Button[3].Text)=0) then + AddButtonText(14, 20, Theme.StatDetail.Description[3]); + + AddButton(Theme.StatMain.ButtonExit); + if (Length(Button[4].Text)=0) then + AddButtonText(14, 20, Theme.Options.Description[4]); + + Interaction := 0; + + //Set Songs with Vid + SongsWithVid := 0; + For I := 0 to Songs.SongList.Count -1 do + if (TSong(Songs.SongList[I]).Video <> '') then + Inc(SongsWithVid); +end; + +procedure TScreenStatMain.onShow; +begin + inherited; + + //Set Overview Text: + SetOverview; +end; + +function TScreenStatMain.FormatOverviewIntro(FormatStr: string): string; +var + Year, Month, Day: Word; +begin + {Format: + %0:d Ultrastar Version + %1:d Day of Reset + %2:d Month of Reset + %3:d Year of Reset} + + Result := ''; + + try + DecodeDate(Database.GetStatReset(), Year, Month, Day); + Result := Format(FormatStr, [Language.Translate('US_VERSION'), Day, Month, Year]); + except + on E: EConvertError do + Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_INTRO": ' + E.Message); + end; +end; + +function TScreenStatMain.FormatSongOverview(FormatStr: string): string; +var + CntSongs, CntSungSongs, CntVidSongs: Integer; + MostPopSongArtist, MostPopSongTitle: String; + StatList: TList; + MostSungSong: TStatResultMostSungSong; +begin + {Format: + %0:d Count Songs + %1:d Count of Sung Songs + %2:d Count of UnSung Songs + %3:d Count of Songs with Video + %4:s Name of the most popular Song} + + CntSongs := Songs.SongList.Count; + CntSungSongs := Database.GetTotalEntrys(stMostSungSong); + CntVidSongs := SongsWithVid; + + StatList := Database.GetStats(stMostSungSong, 1, 0, False); + if ((StatList <> nil) and (StatList.Count > 0)) then + begin + MostSungSong := StatList[0]; + MostPopSongArtist := MostSungSong.Artist; + MostPopSongTitle := MostSungSong.Title; + end + else + begin + MostPopSongArtist := '-'; + MostPopSongTitle := '-'; + end; + Database.FreeStats(StatList); + + Result := ''; + + try + Result := Format(FormatStr, [ + CntSongs, CntSungSongs, CntSongs-CntSungSongs, CntVidSongs, + MostPopSongArtist, MostPopSongTitle]); + except + on E: EConvertError do + Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_SONG": ' + E.Message); + end; +end; + +function TScreenStatMain.FormatPlayerOverview(FormatStr: string): string; +var + CntPlayers: Integer; + BestScoreStat: TStatResultBestScores; + BestSingerStat: TStatResultBestSingers; + BestPlayer, BestScorePlayer: String; + BestPlayerScore, BestScore: Integer; + SingerStats, ScoreStats: TList; +begin + {Format: + %0:d Count Players + %1:s Best Player + %2:d Best Players Score + %3:s Best Score Player + %4:d Best Score} + + CntPlayers := Database.GetTotalEntrys(stBestSingers); + + SingerStats := Database.GetStats(stBestSingers, 1, 0, False); + if ((SingerStats <> nil) and (SingerStats.Count > 0)) then + begin + BestSingerStat := SingerStats[0]; + BestPlayer := BestSingerStat.Player; + BestPlayerScore := BestSingerStat.AverageScore; + end + else + begin + BestPlayer := '-'; + BestPlayerScore := 0; + end; + Database.FreeStats(SingerStats); + + ScoreStats := Database.GetStats(stBestScores, 1, 0, False); + if ((ScoreStats <> nil) and (ScoreStats.Count > 0)) then + begin + BestScoreStat := ScoreStats[0]; + BestScorePlayer := BestScoreStat.Singer; + BestScore := BestScoreStat.Score; + end + else + begin + BestScorePlayer := '-'; + BestScore := 0; + end; + Database.FreeStats(ScoreStats); + + Result := ''; + + try + Result := Format(Formatstr, [ + CntPlayers, BestPlayer, BestPlayerScore, + BestScorePlayer, BestScore]); + except + on E: EConvertError do + Log.LogError('Error Parsing FormatString "STAT_OVERVIEW_PLAYER": ' + E.Message); + end; +end; + +procedure TScreenStatMain.SetOverview; +var + Overview: String; +begin + // Format overview + Overview := FormatOverviewIntro(Language.Translate('STAT_OVERVIEW_INTRO')) + '\n \n' + + FormatSongOverview(Language.Translate('STAT_OVERVIEW_SONG')) + '\n \n' + + FormatPlayerOverview(Language.Translate('STAT_OVERVIEW_PLAYER')); + Text[0].Text := Overview; +end; + + +procedure TScreenStatMain.SetAnimationProgress(Progress: real); +var I: Integer; +begin + For I := 0 to high(Button) do + Button[I].Texture.ScaleW := Progress; +end; + +end. diff --git a/src/screens/UScreenTop5.pas b/src/screens/UScreenTop5.pas new file mode 100644 index 00000000..f4be431f --- /dev/null +++ b/src/screens/UScreenTop5.pas @@ -0,0 +1,175 @@ +unit UScreenTop5; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + UMenu, SDL, SysUtils, UDisplay, UMusic, USongs, UThemes; + +type + TScreenTop5 = class(TMenu) + public + TextLevel: integer; + TextArtistTitle: integer; + + StaticNumber: array[1..5] of integer; + TextNumber: array[1..5] of integer; + TextName: array[1..5] of integer; + TextScore: array[1..5] of integer; + + Fadeout: boolean; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + procedure onShow; override; + function Draw: boolean; override; + end; + +implementation + +uses UGraphic, UDataBase, UMain, UIni; + +function TScreenTop5.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then begin + // check normal keys + case WideCharUpperCase(CharCode)[1] of + 'Q': + begin + Result := false; + Exit; + end; + end; + + // check special keys + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE, + SDLK_RETURN: + begin + if (not Fadeout) then begin + FadeTo(@ScreenSong); + Fadeout := true; + end; + end; + SDLK_SYSREQ: + begin + Display.SaveScreenShot; + end; + end; + end; +end; + +constructor TScreenTop5.Create; +var + I: integer; +begin + inherited Create; + + LoadFromTheme(Theme.Top5); + + + TextLevel := AddText(Theme.Top5.TextLevel); + TextArtistTitle := AddText(Theme.Top5.TextArtistTitle); + + for I := 0 to 4 do + StaticNumber[I+1] := AddStatic( Theme.Top5.StaticNumber[I] ); + + for I := 0 to 4 do + TextNumber[I+1] := AddText(Theme.Top5.TextNumber[I]); + for I := 0 to 4 do + TextName[I+1] := AddText(Theme.Top5.TextName[I]); + for I := 0 to 4 do + TextScore[I+1] := AddText(Theme.Top5.TextScore[I]); + +end; + +procedure TScreenTop5.onShow; +var + I: integer; + PMax: integer; +begin + inherited; + + Fadeout := false; + + //ReadScore(CurrentSong); + + PMax := Ini.Players; + if PMax = 4 then PMax := 5; + for I := 0 to PMax do + DataBase.AddScore(CurrentSong, Ini.Difficulty, Ini.Name[I], Round(Player[I].ScoreTotalInt)); + + DataBase.WriteScore(CurrentSong); + DataBase.ReadScore(CurrentSong); + + Text[TextArtistTitle].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title; + + for I := 1 to Length(CurrentSong.Score[Ini.Difficulty]) do begin + Static[StaticNumber[I]].Visible := true; + Text[TextNumber[I]].Visible := true; + Text[TextName[I]].Visible := true; + Text[TextScore[I]].Visible := true; + + Text[TextName[I]].Text := CurrentSong.Score[Ini.Difficulty, I-1].Name; + Text[TextScore[I]].Text := IntToStr(CurrentSong.Score[Ini.Difficulty, I-1].Score); + end; + + for I := Length(CurrentSong.Score[Ini.Difficulty])+1 to 5 do begin + Static[StaticNumber[I]].Visible := false; + Text[TextNumber[I]].Visible := false; + Text[TextName[I]].Visible := false; + Text[TextScore[I]].Visible := false; + end; + + Text[TextLevel].Text := IDifficulty[Ini.Difficulty]; +end; + +function TScreenTop5.Draw: boolean; +//var +{ Min: real; + Max: real; + Wsp: real; + Wsp2: real; + Pet: integer;} + +{ Item: integer; + P: integer; + C: integer;} +begin + // Singstar - let it be...... with 6 statics +(* if PlayersPlay = 6 then begin + for Item := 4 to 6 do begin + if ScreenAct = 1 then P := Item-4; + if ScreenAct = 2 then P := Item-1; + + FillPlayer(Item, P); + +{ if ScreenAct = 1 then begin + LoadColor( + Static[StaticBoxLightest[Item]].Texture.ColR, + Static[StaticBoxLightest[Item]].Texture.ColG, + Static[StaticBoxLightest[Item]].Texture.ColB, + 'P1Dark'); + end; + + if ScreenAct = 2 then begin + LoadColor( + Static[StaticBoxLightest[Item]].Texture.ColR, + Static[StaticBoxLightest[Item]].Texture.ColG, + Static[StaticBoxLightest[Item]].Texture.ColB, + 'P4Dark'); + end; } + + end; + end; *) + + Result := inherited Draw; +end; + +end. diff --git a/src/screens/UScreenWelcome.pas b/src/screens/UScreenWelcome.pas new file mode 100644 index 00000000..613f3a80 --- /dev/null +++ b/src/screens/UScreenWelcome.pas @@ -0,0 +1,122 @@ +unit UScreenWelcome; + +interface + +{$I switches.inc} + +uses + UMenu, SDL, SysUtils, UThemes; + +type + TScreenWelcome = class(TMenu) + public + Animation: real; + Fadeout: boolean; + constructor Create; override; + function ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; override; + function Draw: boolean; override; + procedure onShow; override; + end; + +implementation + +uses UGraphic, UTime, USkins, UTexture; + +function TScreenWelcome.ParseInput(PressedKey: Cardinal; CharCode: WideChar; PressedDown: Boolean): Boolean; +begin + Result := true; + If (PressedDown) Then begin + case PressedKey of + SDLK_ESCAPE, + SDLK_BACKSPACE : + begin + Result := False; + end; + SDLK_RETURN: + begin + FadeTo(@ScreenMain); + Fadeout := true; + end; + end; + end; +end; + +constructor TScreenWelcome.Create; +begin + inherited Create; + AddStatic(-10, -10, 0, 0, 1, 1, 1, Skin.GetTextureFileName('ButtonAlt'), TEXTURE_TYPE_TRANSPARENT); + AddStatic(-500, 440, 200, 5, 0, 0, 0, Skin.GetTextureFileName('Rectangle'), TEXTURE_TYPE_COLORIZED); + AddStatic(-500, 472, 200, 5, 0, 0, 0, Skin.GetTextureFileName('Rectangle'), TEXTURE_TYPE_COLORIZED); + AddStatic(-500, 504, 200, 5, 0, 0, 0, Skin.GetTextureFileName('Rectangle'), TEXTURE_TYPE_COLORIZED); + AddStatic(-500, 536, 200, 5, 0, 0, 0, Skin.GetTextureFileName('Rectangle'), TEXTURE_TYPE_COLORIZED); + AddStatic(-500, 568, 200, 5, 0, 0, 0, Skin.GetTextureFileName('Rectangle'), TEXTURE_TYPE_COLORIZED); + Animation := 0; + Fadeout := false; +end; + +procedure TScreenWelcome.onShow; +begin + inherited; + + CountSkipTimeSet; +end; + +function TScreenWelcome.Draw: boolean; +var + Min: real; + Max: real; + Wsp: real; + Pet: integer; +begin + // star animation + Animation := Animation + TimeSkip*1000; + + // draw nothing + Min := 0; Max := 1000; + if (Animation >= Min) and (Animation < Max) then begin + end; + + // popup + Min := 1000; Max := 1120; + if (Animation >= Min) and (Animation < Max) then begin + Wsp := (Animation - Min) / (Max - Min); + Static[0].Texture.X := 600; + Static[0].Texture.Y := 600 - Wsp * 230; + Static[0].Texture.W := 200; + Static[0].Texture.H := Wsp * 230; + end; + + // bounce + Min := 1120; Max := 1200; + if (Animation >= Min) and (Animation < Max) then begin + Wsp := (Animation - Min) / (Max - Min); + Static[0].Texture.Y := 370 + Wsp * 50; + Static[0].Texture.H := 230 - Wsp * 50; + end; + + // run + Min := 1500; Max := 3500; + if (Animation >= Min) and (Animation < Max) then begin + Wsp := (Animation - Min) / (Max - Min); + + Static[0].Texture.X := 600 - Wsp * 1400; + Static[0].Texture.H := 180; + + + for Pet := 1 to 5 do begin + Static[Pet].Texture.X := 770 - Wsp * 1400; + Static[Pet].Texture.W := 150 + Wsp * 200; + Static[Pet].Texture.Alpha := Wsp * 0.5; + end; + end; + + Min := 3500; + if (Animation >= Min) and (not Fadeout) then begin + FadeTo(@ScreenMain); + Fadeout := true; + end; + + Result := inherited Draw; +end; + +end. |