--[[ * UltraStar Deluxe - Karaoke Game * * UltraStar Deluxe is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * $URL$ * $Id$ *]] -- some values to adjust the creation of PlayerChanges local MinPercentage = 0.06; -- minimal amount of points between changes (in percent) local MaxPercentage = 0.12; -- maximal amount of points between changes (in percent) -- position of big progress bar in the center local BarPos = {}; BarPos.Top = 30 BarPos.Bottom = 50 BarPos.Left = 300 BarPos.Right = 500 function plugin_init() register('party mode: teamduel', '1.00', 'USDX Team', 'http://www.UltrastarDeluxe.org'); require('math', 'Usdx.Party', 'Usdx.ScreenSing', 'Usdx.Gl', 'Usdx.TextGl'); local Mode = {} Mode.Name = 'teamduel'; Mode.CanParty = true; Mode.PlayerCount = {2,3,4,5,6}; Mode.BeforeSing = 'BeforeSing' Mode.OnSing = 'Sing'; Usdx.Party.Register(Mode) ScreenSing.GetBeat(); return true; end -- called everytime a singing session w/ this party mode is startet -- we just hook ScreenSing.SongLoaded to prepare the mic changes here function BeforeSing() hSongLoaded = Usdx.Hook('ScreenSing.SongLoaded', 'PrepareChanges'); -- execute default action (e.g. set correct singing playercount) return true end; -- adds a new SentenceChange at Line to the PlayerChanges array function AddChange(Line) PlayerChanges[#PlayerChanges + 1] = {}; PlayerChanges[#PlayerChanges].OnBeat = Lines[Line].Start; PlayerChanges[#PlayerChanges].NextPlayer = {} for i = 1, #Teams do repeat PlayerChanges[#PlayerChanges].NextPlayer[i] = math.random(#Teams[i].Players); until (1 == #PlayerChanges) or (PlayerChanges[#PlayerChanges].NextPlayer[i] ~= PlayerChanges[#PlayerChanges-1].NextPlayer[i]) or (#Teams[i].Players == 1); end; end; function PrepareChanges() Lines = ScreenSing.GetSongLines(); Teams = Party.GetTeams(); -- get sum of hittable beats (per line and total) local TotalBeats = 0; local LineValue = {}; for i = 1, #Lines do for j = 1, #Lines[i].Notes do LineValue[i] = (LineValue[i] or 0) + Lines[i].Notes[j].Length * Lines[i].Notes[j].NoteType; end; TotalBeats = TotalBeats + LineValue[i]; end; -- calculate changes PlayerChanges = {}; -- fallback if there are only freestyle notes -- random count of lines between changes if (TotalBeats == 0) then local i = 1; repeat if i > 1 then AddChange(i); end local step = math.ceil((MinPercentage + (MaxPercentage - MinPercentage) * math.random()) * #Lines); if step < 1 then step = 1; end; i = i + step; until i >= #Lines; else -- calculate changes by amount of hittable beats local i = 1; local BeatsToChange = math.ceil((MinPercentage + (MaxPercentage - MinPercentage) * math.random()) * TotalBeats); local Beats = 0; repeat Beats = Beats + LineValue[i]; if Beats >= BeatsToChange then AddChange(i); BeatsToChange = BeatsToChange + math.ceil((MinPercentage + (MaxPercentage - MinPercentage) * math.random()) * TotalBeats); end i = i + 1; until i >= #Lines; end; -- free lines Lines = nil; -- init NextPlayerChange NextPlayerChange = 1; -- calculate OSD position for players do local RBRect = ScreenSing.GetRBRect(); OSD = {}; for i = 1, #RBRect do OSD[i] = {}; OSD[i].Left = RBRect[i].x; OSD[i].Right = RBRect[i].x + RBRect[i].w; OSD[i].Top = RBRect[i].y + RBRect[i].h; OSD[i].Bottom = RBRect[i].y + RBRect[i].h + math.max(RBRect[i].h, 13); end; end; -- remove hook hSongLoaded:Unhook(); hSongLoaded = nil; end function DrawPlayerText(i, Text) Gl.Disable('GL_TEXTURE_2D'); -- background Gl.Color (0, 0, 0, 1); Gl.Begin('GL_QUADS'); Gl.Vertex(OSD[i].Left, OSD[i].Top); Gl.Vertex(OSD[i].Left, OSD[i].Bottom); Gl.Vertex(OSD[i].Right, OSD[i].Bottom); Gl.Vertex(OSD[i].Right, OSD[i].Top); Gl.End(); -- text Gl.Color(1, 0, 0, 1); TextGl.Style(1); TextGl.Size(18); TextGl.Italic(false); local PosX = (OSD[i].Left + OSD[i].Right) / 2; PosX = PosX - TextGl.Width(Text) / 2; TextGl.Pos(PosX, OSD[i].Top - 3); TextGl.Print(Text); end; -- draws the progress bar for player i function DrawPlayerProgress(i, Progress) Gl.Disable('GL_TEXTURE_2D'); -- background Gl.Color (0, 0, 0, 1); Gl.Begin('GL_QUADS'); Gl.Vertex(OSD[i].Left, OSD[i].Top); Gl.Vertex(OSD[i].Left, OSD[i].Bottom); Gl.Vertex(OSD[i].Right, OSD[i].Bottom); Gl.Vertex(OSD[i].Right, OSD[i].Top); Gl.End(); -- bar Gl.Color(1, 0, 0, 1); Gl.Begin('GL_QUADS'); Gl.Vertex(OSD[i].Left + 2, OSD[i].Top + 2); Gl.Vertex(OSD[i].Left + 2, OSD[i].Bottom - 2); Gl.Vertex(OSD[i].Left + 2 + (OSD[i].Right - OSD[i].Left - 4) * Progress, OSD[i].Bottom - 2); Gl.Vertex(OSD[i].Left + 2 + (OSD[i].Right - OSD[i].Left - 4) * Progress, OSD[i].Top + 2); Gl.End(); end; -- draws the big progress bar in the screen center function DrawCenterProgress(Progress) Gl.Disable('GL_TEXTURE_2D'); -- background Gl.Color (0, 0, 0, 1); Gl.Begin('GL_QUADS'); Gl.Vertex(BarPos.Left, BarPos.Top); Gl.Vertex(BarPos.Left, BarPos.Bottom); Gl.Vertex(BarPos.Right, BarPos.Bottom); Gl.Vertex(BarPos.Right, BarPos.Top); Gl.End(); -- bar Gl.Color(1, 0, 0, 1); Gl.Begin('GL_QUADS'); Gl.Vertex(BarPos.Left + 2, BarPos.Top + 2); Gl.Vertex(BarPos.Left + 2, BarPos.Bottom - 2); Gl.Vertex(BarPos.Left + 2 + (BarPos.Right - BarPos.Left - 4) * Progress, BarPos.Bottom - 2); Gl.Vertex(BarPos.Left + 2 + (BarPos.Right - BarPos.Left - 4) * Progress, BarPos.Top + 2); Gl.End(); end; function Sing() if (NextPlayerChange <= #PlayerChanges) then local BeatsToNextChange = PlayerChanges[NextPlayerChange].OnBeat - ScreenSing.GetBeat(); local TimeToNextChange = ScreenSing.BeatsToSeconds(BeatsToNextChange); -- draw next player text or progress bar if (TimeToNextChange <= 0) then --there is a change NextPlayerChange = NextPlayerChange + 1; elseif (TimeToNextChange <= 5) then for i = 1, #Teams do DrawPlayerProgress(i, 1 - TimeToNextChange/5); end; elseif (TimeToNextChange <= 6.5) then for i = 1, #Teams do DrawPlayerText(i, Teams[i].Players[PlayerChanges[NextPlayerChange].NextPlayer[i]].Name); end; elseif (TimeToNextChange <= 8) then for i = 1, #Teams do DrawPlayerText(i, 'Next Player'); end; elseif (TimeToNextChange <= 9.5) then for i = 1, #Teams do DrawPlayerText(i, Teams[i].Players[PlayerChanges[NextPlayerChange].NextPlayer[i]].Name); end; elseif (TimeToNextChange <= 11) then for i = 1, #Teams do DrawPlayerText(i, 'Next Player'); end; end if (TimeToNextChange <= 11) then DrawCenterProgress(1 - TimeToNextChange/11); end; end; end