2023-12-02 23:58:03 +01:00
|
|
|
local json = require("common.json")
|
|
|
|
local Sound = require("common.sound")
|
|
|
|
local Dim = require("common.dimensions")
|
|
|
|
local Wallpaper = require("components.wallpaper")
|
|
|
|
local Background = require('components.background');
|
|
|
|
local difbar = require('components.diff_rectangle');
|
|
|
|
|
|
|
|
local crew = game.GetSkinSetting("single_idol")
|
|
|
|
|
|
|
|
require('common.gameconfig')
|
|
|
|
|
|
|
|
-- inRoom components
|
|
|
|
local Jacket = require("multiplayer.Room.jacket")
|
|
|
|
local OwnInfo = require("multiplayer.Room.owninfo")
|
|
|
|
local BasePanel = require("multiplayer.Room.base")
|
|
|
|
local MainPanel = require("multiplayer.Room.main")
|
|
|
|
local SongInfo = require("multiplayer.Room.songinfo")
|
|
|
|
local BPM = require("multiplayer.Room.bpm")
|
|
|
|
local InfoPanel = require("multiplayer.Room.infopanel")
|
|
|
|
local PlayerPlate = require("multiplayer.Room.user")
|
|
|
|
|
|
|
|
-- roomList components
|
|
|
|
local SelectPanel = require("multiplayer.LobbySelect.panel")
|
|
|
|
|
|
|
|
local RoomListImages = {
|
|
|
|
panel = gfx.CreateSkinImage("nautica/room_panel.png", 1),
|
|
|
|
price = gfx.CreateSkinImage("nautica/pw_or_price_panel.png", 1),
|
|
|
|
jacket = gfx.CreateSkinImage("nautica/bg_jacket.png", 1),
|
|
|
|
dot = gfx.CreateSkinImage("nautica/dot.png", 1),
|
|
|
|
info = gfx.CreateSkinImage("nautica/panel_name.png", 1),
|
|
|
|
placeholder = gfx.CreateSkinImage("song_select/loading.png", 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
local MultiJacket = gfx.CreateSkinImage("multi/lobby/multi_jacket.png", 1);
|
|
|
|
|
|
|
|
local panelW,panelH = gfx.ImageSize(RoomListImages.panel);
|
|
|
|
local jacketW,jacketH = gfx.ImageSize(RoomListImages.jacket);
|
|
|
|
local infoW,infoH = gfx.ImageSize(RoomListImages.info);
|
|
|
|
local dotW,dotH = gfx.ImageSize(RoomListImages.dot);
|
|
|
|
|
|
|
|
local Gradient = gfx.CreateSkinImage("multi/roomselect/lobby_select_gradiant.png", 1);
|
|
|
|
local Plate = gfx.CreateSkinImage("multi/roomselect/lobby_select.png", 1);
|
|
|
|
local station = gfx.CreateSkinImage("multi/roomselect/multi_station.png", 1);
|
|
|
|
local no_dif = gfx.CreateSkinImage("nautica/no_dif.png", 1);
|
|
|
|
|
|
|
|
local gradientW, gradientH = gfx.ImageSize(Gradient);
|
|
|
|
local stationW, stationH = gfx.ImageSize(station);
|
|
|
|
|
|
|
|
local headerMatchingImage = gfx.CreateSkinImage("titlescreen/entry.png", 1);
|
|
|
|
|
|
|
|
local bg = gfx.CreateSkinImage("multi/lobby/bg.png", 1);
|
|
|
|
local bg_graid1 = gfx.CreateSkinImage("multi/lobby/gradient_bottom.png", 1);
|
|
|
|
local bg_graid2 = gfx.CreateSkinImage("multi/lobby/gradient_top.png", 1);
|
|
|
|
|
|
|
|
local idle = "/idle"
|
|
|
|
local idolAnimation = gfx.LoadSkinAnimation('crew/anim/' .. crew .. idle, 1 / 30, 0, true);
|
|
|
|
local idolAnimTransitionScale = 0;
|
|
|
|
|
|
|
|
local dancheck = require("components.danbadge");
|
|
|
|
local username = game.GetSkinSetting("username");
|
|
|
|
local msg = game.GetSkinSetting("MSG");
|
|
|
|
local vol = game.GetSkinSetting("_volforce");
|
|
|
|
|
|
|
|
local desw, desh = Dim.design.width, Dim.design.height
|
|
|
|
|
|
|
|
local mposx = 0;
|
|
|
|
local mposy = 0;
|
|
|
|
local hovered = nil;
|
|
|
|
local buttonWidth = desw * (3 / 4);
|
|
|
|
local buttonHeight = 100;
|
|
|
|
local buttonBorder = 2;
|
|
|
|
local portrait
|
|
|
|
local jacket_size;
|
|
|
|
|
|
|
|
-- RoomList Values --
|
|
|
|
local verticalOffset = panelH
|
|
|
|
local firstRoomY = (desh / 2)- (panelH/2)
|
|
|
|
local numOfRoomsAround = 2 -- numbers of Rooms Showing
|
|
|
|
local selectedIndex = 1
|
|
|
|
-- Users Value --
|
|
|
|
local userHeight = 100
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
local BAR_ALPHA = 191;
|
|
|
|
local HEADER_HEIGHT = 100
|
|
|
|
|
|
|
|
local scale;
|
|
|
|
|
|
|
|
game.LoadSkinSample("click-02")
|
|
|
|
game.LoadSkinSample("click-01")
|
|
|
|
game.LoadSkinSample("menu_click")
|
|
|
|
|
|
|
|
local loading = true;
|
|
|
|
local rooms = {};
|
|
|
|
local lobby_users = {};
|
|
|
|
selected_room = nil;
|
|
|
|
local user_id = nil;
|
|
|
|
local all_ready;
|
|
|
|
local user_ready;
|
|
|
|
local go;
|
|
|
|
local hard_mode = false;
|
|
|
|
local rotate_host = false;
|
|
|
|
local start_game_soon = false;
|
|
|
|
local host = nil;
|
|
|
|
local owner = nil;
|
|
|
|
local missing_song = false;
|
|
|
|
local did_exit = false;
|
|
|
|
|
|
|
|
local irHeartbeatRequested = false;
|
|
|
|
irText = ''
|
|
|
|
|
|
|
|
local grades = {
|
|
|
|
{ ["max"] = 6900000, ["image"] = gfx.CreateSkinImage("common/grades/D.png", 0) },
|
|
|
|
{ ["max"] = 7900000, ["image"] = gfx.CreateSkinImage("common/grades/C.png", 0) },
|
|
|
|
{ ["max"] = 8600000, ["image"] = gfx.CreateSkinImage("common/grades/B.png", 0) },
|
|
|
|
{ ["max"] = 8900000, ["image"] = gfx.CreateSkinImage("common/grades/A.png", 0) },
|
|
|
|
{ ["max"] = 9200000, ["image"] = gfx.CreateSkinImage("common/grades/A+.png", 0) },
|
|
|
|
{ ["max"] = 9400000, ["image"] = gfx.CreateSkinImage("common/grades/AA.png", 0) },
|
|
|
|
{ ["max"] = 9600000, ["image"] = gfx.CreateSkinImage("common/grades/AA+.png", 0) },
|
|
|
|
{ ["max"] = 9700000, ["image"] = gfx.CreateSkinImage("common/grades/AAA.png", 0) },
|
|
|
|
{ ["max"] = 9800000, ["image"] = gfx.CreateSkinImage("common/grades/AAA+.png", 0) },
|
|
|
|
{ ["max"] = 9900000, ["image"] = gfx.CreateSkinImage("common/grades/S.png", 0) }
|
|
|
|
}
|
|
|
|
|
|
|
|
local badges = {
|
|
|
|
gfx.CreateSkinImage("song_select/medal/saved.png", 0),
|
|
|
|
gfx.CreateSkinImage("song_select/medal/played.png", 0),
|
|
|
|
gfx.CreateSkinImage("song_select/medal/clear.png", 0),
|
|
|
|
gfx.CreateSkinImage("song_select/medal/hard-clear.png", 0),
|
|
|
|
gfx.CreateSkinImage("song_select/medal/full-combo.png", 0),
|
|
|
|
gfx.CreateSkinImage("song_select/medal/perfect.png", 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
local SERVER = game.GetSkinSetting("multi.server")
|
|
|
|
|
|
|
|
local drawIdol = function(deltaTime)
|
|
|
|
local idolAnimTickRes = gfx.TickAnimation(idolAnimation, deltaTime);
|
|
|
|
if idolAnimTickRes == 1 then
|
|
|
|
gfx.GlobalAlpha(idolAnimTransitionScale);
|
|
|
|
|
|
|
|
idolAnimTransitionScale = idolAnimTransitionScale + 1 / 60;
|
|
|
|
if (idolAnimTransitionScale > 1) then
|
|
|
|
idolAnimTransitionScale = 1;
|
|
|
|
end
|
|
|
|
|
|
|
|
gfx.ImageRect(0, 0, desw, desh, idolAnimation, 1, 0);
|
|
|
|
gfx.GlobalAlpha(1);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function getCorrectedIndex(from, offset)
|
|
|
|
total = #rooms
|
|
|
|
|
|
|
|
if (math.abs(offset) > total) then
|
|
|
|
if (offset < 0) then
|
|
|
|
offset = offset + total * math.floor(math.abs(offset) / total)
|
|
|
|
else
|
|
|
|
offset = offset - total * math.floor(math.abs(offset) / total)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
index = from + offset
|
|
|
|
|
|
|
|
if index < 1 then
|
|
|
|
index = total + (from + offset) -- this only happens if the offset is negative
|
|
|
|
end
|
|
|
|
|
|
|
|
if index > total then
|
|
|
|
indexesUntilEnd = total - from
|
|
|
|
index = offset - indexesUntilEnd -- this only happens if the offset is positive
|
|
|
|
end
|
|
|
|
|
|
|
|
return index
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
user_setup = function()
|
|
|
|
|
|
|
|
split = desw
|
|
|
|
user_y_off = 0
|
|
|
|
space = 0
|
|
|
|
|
|
|
|
local newlobby = {}
|
|
|
|
|
|
|
|
buttonY = user_y_off +125+ userHeight/2
|
|
|
|
for i, user in ipairs(lobby_users) do
|
|
|
|
if user.id ~= user_id then
|
|
|
|
table.insert(newlobby,user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for i, newUser in ipairs(newlobby) do
|
|
|
|
PlayerPlate.Draw(newUser,0,800,badges,grades,host)
|
|
|
|
local side_button_off = 0
|
|
|
|
if owner == user_id and newUser.id ~= user_id then
|
|
|
|
draw_button("K",split/2 + split*3/8+10+25, buttonY, 50, function()
|
|
|
|
kick_user(newUser);
|
|
|
|
end)
|
|
|
|
side_button_off = 60;
|
|
|
|
end
|
|
|
|
if (owner == user_id or host == user_id) and newUser.id ~= host then
|
|
|
|
draw_button("H",split/2 + split*3/8+10+25+side_button_off, buttonY, 50, function()
|
|
|
|
change_host(newUser);
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
buttonY = buttonY + userHeight
|
|
|
|
space = space +13
|
|
|
|
end
|
|
|
|
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
end
|
|
|
|
|
|
|
|
function drawHeader()
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.FillColor(0, 0, 0, BAR_ALPHA)
|
|
|
|
gfx.Rect(0, 0, desw, HEADER_HEIGHT)
|
|
|
|
gfx.Fill()
|
|
|
|
gfx.ClosePath()
|
|
|
|
|
|
|
|
gfx.ImageRect(desw / 2 - 200, HEADER_HEIGHT / 2 - 20, 400, 40, headerMatchingImage, 1, 0)
|
|
|
|
end
|
|
|
|
|
|
|
|
mouse_clipped = function(x, y, w, h)
|
|
|
|
return mposx > x and mposy > y and mposx < x + w and mposy < y + h;
|
|
|
|
end;
|
|
|
|
|
|
|
|
custom_button = function(name, x, y, image, font, font_size, hoverindex)
|
|
|
|
local jw, jh = gfx.ImageSize(image)
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x, y, jw, jh, image, 1, 0);
|
|
|
|
if mouse_clipped(x, y, jw, jh) then
|
|
|
|
hovered = hoverindex;
|
|
|
|
gfx.FillColor(255, 128, 0);
|
|
|
|
else
|
|
|
|
gfx.FillColor(255, 255, 255);
|
|
|
|
end
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE);
|
|
|
|
gfx.LoadSkinFont(font)
|
|
|
|
gfx.FontSize(font_size);
|
|
|
|
gfx.Text(name, x + (jw / 2) + 5, y + (jh / 2.25));
|
|
|
|
end
|
|
|
|
|
|
|
|
draw_button = function(name, x, y, buttonWidth, hoverindex)
|
|
|
|
draw_button_color(name, x, y, buttonWidth, hoverindex, 40, 40, 40, 0, 128, 255)
|
|
|
|
end
|
|
|
|
|
|
|
|
draw_button_color = function(name, x, y, buttonWidth, hoverindex, r, g, b, olr, olg, olb)
|
|
|
|
local rx = x - (buttonWidth / 2);
|
|
|
|
local ty = y - (buttonHeight / 2);
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.FillColor(olr, olg, olb);
|
|
|
|
if mouse_clipped(rx, ty, buttonWidth, buttonHeight) then
|
|
|
|
hovered = hoverindex;
|
|
|
|
gfx.FillColor(255, 128, 0);
|
|
|
|
end
|
|
|
|
gfx.Rect(rx - buttonBorder,
|
|
|
|
ty - buttonBorder,
|
|
|
|
buttonWidth + (buttonBorder * 2),
|
|
|
|
buttonHeight + (buttonBorder * 2));
|
|
|
|
gfx.Fill();
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.FillColor(r, g, b);
|
|
|
|
gfx.Rect(rx, ty, buttonWidth, buttonHeight);
|
|
|
|
gfx.Fill();
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.FillColor(255, 255, 255);
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE);
|
|
|
|
gfx.FontSize(40);
|
|
|
|
gfx.Text(name, x, y);
|
|
|
|
end;
|
|
|
|
|
|
|
|
draw_checkbox = function(text, x, y, hoverindex, current, can_click)
|
|
|
|
gfx.BeginPath();
|
|
|
|
|
|
|
|
if can_click then
|
|
|
|
gfx.FillColor(255, 255, 255, 100);
|
|
|
|
else
|
|
|
|
gfx.FillColor(100, 100, 100, 100);
|
|
|
|
end
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE);
|
|
|
|
gfx.Text(text, x, y)
|
|
|
|
|
|
|
|
local xmin, ymin, xmax, ymax = gfx.TextBounds(x, y, text);
|
|
|
|
|
|
|
|
local sx = xmin - 40;
|
|
|
|
local sy = y - 15;
|
|
|
|
|
|
|
|
if can_click and mouse_clipped(xmin - 10, ymin, xmax - xmin, ymax - ymin) then
|
|
|
|
hovered = hoverindex;
|
|
|
|
end
|
|
|
|
|
|
|
|
if current then
|
|
|
|
-- Draw checkmark
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.FillColor(0, 236, 0, 100);
|
|
|
|
gfx.Text(text, x, y)
|
|
|
|
end
|
|
|
|
end;
|
|
|
|
|
|
|
|
function render_loading()
|
|
|
|
if not loading then return end
|
|
|
|
gfx.Save()
|
|
|
|
gfx.ResetTransform()
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.MoveTo(desw, desh)
|
|
|
|
gfx.LineTo(desw - 350, desh)
|
|
|
|
gfx.LineTo(desw - 300, desh - 50)
|
|
|
|
gfx.LineTo(desw, desh - 50)
|
|
|
|
gfx.ClosePath()
|
|
|
|
gfx.FillColor(33, 33, 33)
|
|
|
|
gfx.Fill()
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_RIGHT, gfx.TEXT_ALIGN_BOTTOM)
|
|
|
|
gfx.FontSize(70)
|
|
|
|
gfx.Text("LOADING...", desw - 20, desh - 3)
|
|
|
|
gfx.Restore()
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_info()
|
|
|
|
|
|
|
|
if searchStatus then
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.FontSize(20);
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP)
|
|
|
|
gfx.Text(searchStatus, 3, 3)
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
draw_diff_icon = function(diff, x, y, w, h)
|
|
|
|
difbar.render(deltaTime, x, y, 1, diff.difficulty + 1, diff.level);
|
|
|
|
end
|
|
|
|
|
|
|
|
local doffset = 0;
|
|
|
|
local timer = 0;
|
|
|
|
|
|
|
|
local possy = 1095;
|
|
|
|
local possx = 150;
|
|
|
|
|
|
|
|
draw_diffs = function(diffs, x, y, w, h, selectedDiff)
|
|
|
|
local diffWidth = w / 2
|
|
|
|
local diffHeight = w / 2
|
|
|
|
local diffCount = #diffs
|
|
|
|
gfx.Scissor(x + 84 + possx, y + possy, w / 2.451, h)
|
|
|
|
for i = math.max(selectedDiff - 2, 1), math.max(selectedDiff - 1, 1) do
|
|
|
|
local diff = diffs[i]
|
|
|
|
local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth))
|
|
|
|
if i ~= selectedDiff then
|
|
|
|
draw_diff_icon(diff, xpos + possx, y + possy, diffWidth, diffHeight, false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--after selected
|
|
|
|
for i = math.min(selectedDiff + 2, diffCount), selectedDiff + 1, -1 do
|
|
|
|
local diff = diffs[i]
|
|
|
|
local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth))
|
|
|
|
if i ~= selectedDiff then
|
|
|
|
draw_diff_icon(diff, xpos + possx, y + possy, diffWidth, diffHeight, false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local diff = diffs[selectedDiff]
|
|
|
|
local xpos = x + ((w / 2 - diffWidth / 2) + (doffset) * (-0.8 * diffWidth))
|
|
|
|
draw_diff_icon(diff, xpos + possx, y + possy, diffWidth, diffHeight, true)
|
|
|
|
gfx.ResetScissor()
|
|
|
|
end
|
|
|
|
|
|
|
|
set_diff = function(oldDiff, newDiff)
|
|
|
|
game.PlaySample("click-02")
|
|
|
|
doffset = doffset + oldDiff - newDiff
|
|
|
|
end;
|
|
|
|
|
|
|
|
local selected_room_index = 1;
|
|
|
|
local ioffset = 0;
|
|
|
|
|
|
|
|
local draw_room = function(information, x, y, selected, hoverindex)
|
|
|
|
|
|
|
|
local PlayerAmount = information.current .. '/' .. information.max
|
|
|
|
local Name = information.name
|
|
|
|
local Status
|
|
|
|
local Password
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x/4.5,y, panelW/1.17, panelH/1.17, RoomListImages.panel,1,0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x/4.5+3,y+5, jacketW/1.25, jacketH/1.17, RoomListImages.jacket,1,0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x/4.5+10,y+22, jacketW/1.45,jacketH/1.45, RoomListImages.placeholder,1,0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x/2-5,y+5, infoW/1.17, infoH/1.17, RoomListImages.info,1,0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.SetImageTint(0,128,255);
|
|
|
|
if selected then
|
|
|
|
gfx.SetImageTint(0,255,0);
|
|
|
|
end
|
|
|
|
if mouse_clipped(x/4.5,y, panelW/1.17, panelH/1.17) then
|
|
|
|
hovered = hoverindex;
|
|
|
|
gfx.SetImageTint(255,128,0);
|
|
|
|
end
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x/4.5,y, dotW/1.17, dotH/1.17, RoomListImages.dot,1,0);
|
|
|
|
|
|
|
|
gfx.SetImageTint(255,255,255);
|
|
|
|
gfx.FillColor(255,255,255);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE);
|
|
|
|
gfx.FontSize(35);
|
|
|
|
gfx.Text(Name, x-230,y+40);
|
|
|
|
gfx.Text(PlayerAmount, x-230,y+40+40);
|
|
|
|
|
|
|
|
gfx.FontSize(24);
|
|
|
|
local jw,jh = gfx.ImageSize(RoomListImages.price);
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(x+230-5,y+40+29, jw/1.17, jh/1.17, RoomListImages.price,1,0);
|
|
|
|
if information.current == information.max then
|
|
|
|
Status = "<FULL>"
|
|
|
|
else
|
|
|
|
Status = "<NOT FULL>"
|
|
|
|
end
|
|
|
|
if information.ingame then
|
|
|
|
Status = '<IN MATCH>'
|
|
|
|
end
|
|
|
|
if information.password then
|
|
|
|
Password = '<LOCKED>'
|
|
|
|
else
|
|
|
|
Password = ' <OPEN>'
|
|
|
|
end
|
|
|
|
gfx.Text(Status.." / "..Password, x+230+9,y+40+52.5);
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function draw_rooms(y, h)
|
|
|
|
while #rooms == 0 do
|
|
|
|
gfx.FillColor(255, 255, 255);
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.Text("No Rooms are available",y,h/2)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if not rooms[selected_room_index] then
|
|
|
|
selected_room_index = getCorrectedIndex(selectedIndex, 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
local i = 1
|
|
|
|
if i <= numOfRoomsAround then
|
|
|
|
local roomIndex = getCorrectedIndex(selected_room_index, -i)
|
|
|
|
local room = rooms[roomIndex]
|
|
|
|
local y = firstRoomY + (i - 1) * verticalOffset + verticalOffset
|
|
|
|
draw_room(room, desw / 2, y, roomIndex == selected_room_index, function() join_room(room) end)
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local i = selected_room_index
|
|
|
|
if i ~= nil then
|
|
|
|
-- Draw the selected room
|
|
|
|
local room = rooms[i]
|
|
|
|
draw_room(room, desw / 2, firstRoomY, i == selected_room_index, function()join_room(room)end)
|
|
|
|
end
|
|
|
|
|
|
|
|
local i = 1
|
|
|
|
if i <= numOfRoomsAround then
|
|
|
|
local roomIndex = getCorrectedIndex(selected_room_index, i)
|
|
|
|
local room = rooms[roomIndex]
|
|
|
|
local y = firstRoomY - (i - 1) * verticalOffset - verticalOffset
|
|
|
|
draw_room(room, desw / 2, y, roomIndex == selected_room_index, function() join_room(room) end)
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
change_selected_room = function(off)
|
|
|
|
|
|
|
|
local new_index = selected_room_index + off;
|
|
|
|
--selected_room_index = 2;
|
|
|
|
if new_index < 1 or new_index > #rooms then
|
|
|
|
return;
|
|
|
|
end
|
|
|
|
|
|
|
|
local h = desh - 290;
|
|
|
|
|
|
|
|
local num_rooms_visible = math.floor(h / (buttonHeight + 10))
|
|
|
|
|
|
|
|
local first_half_rooms = math.floor(num_rooms_visible / 2)
|
|
|
|
local second_half_rooms = math.ceil(num_rooms_visible / 2) - 1
|
|
|
|
|
|
|
|
if off > 0 and (selected_room_index < first_half_rooms or selected_room_index >= #rooms - second_half_rooms - 1) then
|
|
|
|
elseif off < 0 and (selected_room_index <= first_half_rooms or selected_room_index >= #rooms - second_half_rooms) then
|
|
|
|
else
|
|
|
|
ioffset = ioffset - new_index + selected_room_index;
|
|
|
|
end
|
|
|
|
|
|
|
|
game.PlaySample("menu_click")
|
|
|
|
|
|
|
|
selected_room_index = new_index;
|
|
|
|
end
|
|
|
|
|
|
|
|
local IR_HeartbeatResponse = function(res)
|
|
|
|
if res.statusCode == IRData.States.Success then
|
|
|
|
irText = res.body.serverName .. ' ' .. res.body.irVersion;
|
|
|
|
else
|
|
|
|
game.Log("Can't connect to IR!", game.LOGGER_WARNING)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local IR_Handle = function()
|
|
|
|
if not irHeartbeatRequested then
|
|
|
|
IR.Heartbeat(IR_HeartbeatResponse)
|
|
|
|
irHeartbeatRequested = true;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_lobby(deltaTime)
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(0, 0, desw, desh, bg, 1, 0);
|
|
|
|
drawIdol(deltaTime)
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(0, 0, desw, desh, bg_graid1, 1, 0);
|
|
|
|
gfx.ImageRect(0, 0, desw, desh, bg_graid2, 1, 0);
|
|
|
|
gfx.BeginPath();
|
|
|
|
|
|
|
|
BasePanel.Draw()
|
|
|
|
|
|
|
|
user_setup()
|
|
|
|
|
|
|
|
InfoPanel.Draw(hard_mode,start_game_soon,owner,user_id,host)
|
|
|
|
MainPanel.Draw()
|
|
|
|
SongInfo.Draw()
|
|
|
|
|
|
|
|
OwnInfo.Draw(deltaTime,lobby_users,user_id,badges,grades)
|
|
|
|
|
|
|
|
BPM.Draw()
|
|
|
|
Jacket.Draw()
|
|
|
|
|
|
|
|
local jw , jh = gfx.ImageSize(MultiJacket);
|
|
|
|
if mouse_clipped(333+12, 1284+19, jw/1.269,jh/1.35) and host == user_id then
|
|
|
|
hovered = function()
|
|
|
|
mpScreen.SelectSong()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_room_list(deltaTime)
|
|
|
|
|
|
|
|
Background.draw(deltaTime)
|
|
|
|
SelectPanel.Draw()
|
|
|
|
|
|
|
|
|
|
|
|
-- the list
|
|
|
|
draw_rooms(desw/2, desh - 290);
|
|
|
|
--
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(desw / desw, lobbypanelY, gradientW, gradientH, Gradient, 1, 0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect(desw / desw, lobbypanelY, gradientW, gradientH, Plate, 1, 0);
|
|
|
|
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.ImageRect((desw / 2)-((stationW/0.8)/2), lobbypanelY+((stationH/0.8)/2)-5, stationW/0.8, stationH/0.8, station, 1, 0);
|
|
|
|
end
|
|
|
|
|
|
|
|
passwordErrorOffset = 0;
|
|
|
|
function render_password_screen(deltaTime)
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER, gfx.TEXT_ALIGN_BOTTOM)
|
|
|
|
gfx.FontSize(70)
|
|
|
|
gfx.Text("Joining " .. selected_room.name .. "...", desw / 2, desh / 4)
|
|
|
|
|
|
|
|
gfx.FillColor(50, 50, 50)
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.Rect(0, desh / 2 - 10, desw, 40)
|
|
|
|
gfx.Fill();
|
|
|
|
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.Text("Please enter room password:", desw / 2, desh / 2 - 40)
|
|
|
|
gfx.Text(string.rep("*", #textInput.text), desw / 2, desh / 2 + 40)
|
|
|
|
if passwordError then
|
|
|
|
|
|
|
|
gfx.FillColor(255, 50, 50)
|
|
|
|
gfx.FontSize(60 + math.floor(passwordErrorOffset * 20))
|
|
|
|
gfx.Text("Invalid password", desw / 2, desh / 2 + 80)
|
|
|
|
end
|
|
|
|
draw_button("Join", desw / 2, desh * 3 / 4, desw / 2, mpScreen.JoinWithPassword);
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_new_room_password(deltaTime)
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER, gfx.TEXT_ALIGN_BOTTOM)
|
|
|
|
gfx.FontSize(70)
|
|
|
|
gfx.Text("Create New Room", desw / 2, desh / 4)
|
|
|
|
|
|
|
|
-- make something here
|
|
|
|
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.Text("Enter room password:", desw / 2, desh / 2 - 40)
|
|
|
|
gfx.Text(string.rep("*", #textInput.text), desw / 2, desh / 2 + 40)
|
|
|
|
draw_button("Create Room", desw / 2, desh * 3 / 4, desw / 2, mpScreen.NewRoomStep);
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_new_room_name(deltaTime)
|
|
|
|
gfx.BeginPath();
|
|
|
|
gfx.LoadSkinFont("segoeui.ttf")
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER, gfx.TEXT_ALIGN_BOTTOM)
|
|
|
|
gfx.FontSize(70)
|
|
|
|
gfx.Text("Create New Room", desw / 2, desh / 4)
|
|
|
|
|
|
|
|
gfx.Rect(0, desh / 2 - 10, desw / 2, 60)
|
|
|
|
|
|
|
|
|
|
|
|
gfx.Text("Please enter room name:", desw / 2, desh / 2 - 40)
|
|
|
|
gfx.Text(textInput.text, desw / 2, desh / 2 + 40)
|
|
|
|
draw_button("Next", desw / 2, desh * 3 / 4, desw / 2, mpScreen.NewRoomStep);
|
|
|
|
end
|
|
|
|
|
|
|
|
function render_set_username(deltaTime)
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER, gfx.TEXT_ALIGN_BOTTOM)
|
|
|
|
gfx.FontSize(70)
|
|
|
|
gfx.Text("First things first...", desw / 2, desh / 4)
|
|
|
|
|
|
|
|
gfx.FillColor(50, 50, 50)
|
|
|
|
gfx.BeginPath()
|
|
|
|
gfx.Rect(0, desh / 2 - 10, desw, 60)
|
|
|
|
gfx.Fill();
|
|
|
|
|
|
|
|
gfx.FillColor(255, 255, 255)
|
|
|
|
gfx.Text("Enter a display name:", desw / 2, desh / 2 - 40)
|
|
|
|
gfx.Text(textInput.text, desw / 2, desh / 2 + 40)
|
|
|
|
draw_button("Join Multiplayer", desw / 2, desh * 3 / 4, desw / 2, function()
|
|
|
|
loading = true;
|
|
|
|
mpScreen.SaveUsername()
|
|
|
|
end);
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
render = function(deltaTime)
|
|
|
|
IR_Handle()
|
|
|
|
Dim.updateResolution()
|
|
|
|
Wallpaper.render()
|
|
|
|
|
|
|
|
Dim.transformToScreenSpace()
|
|
|
|
|
|
|
|
mposx, mposy = Dim.toViewSpace(game.GetMousePos())
|
|
|
|
|
|
|
|
Sound.stopMusic();
|
|
|
|
|
|
|
|
doffset = doffset * 0.9
|
|
|
|
ioffset = ioffset * 0.9
|
|
|
|
passwordErrorOffset = passwordErrorOffset * 0.9
|
|
|
|
timer = (timer + deltaTime)
|
|
|
|
timer = timer % 2
|
|
|
|
|
|
|
|
hovered = nil;
|
|
|
|
Background.draw(deltaTime)
|
|
|
|
do_sounds(deltaTime);
|
|
|
|
-- Room Listing View
|
|
|
|
if screenState == "inRoom" then
|
|
|
|
render_lobby(deltaTime);
|
|
|
|
drawHeader()
|
|
|
|
elseif screenState == "roomList" then
|
|
|
|
render_room_list(deltaTime);
|
|
|
|
drawHeader()
|
|
|
|
elseif screenState == "passwordScreen" then
|
|
|
|
|
|
|
|
render_password_screen(deltaTime);
|
|
|
|
drawHeader()
|
|
|
|
elseif screenState == "newRoomName" then
|
|
|
|
render_new_room_name()
|
|
|
|
drawHeader()
|
|
|
|
elseif screenState == "newRoomPassword" then
|
|
|
|
render_new_room_password()
|
|
|
|
drawHeader()
|
|
|
|
elseif screenState == "setUsername" then
|
|
|
|
loading = false;
|
|
|
|
render_set_username()
|
|
|
|
drawHeader()
|
|
|
|
end
|
|
|
|
render_loading();
|
|
|
|
render_info();
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Ready up to play
|
|
|
|
function ready_up()
|
|
|
|
Tcp.SendLine(json.encode({ topic = "user.ready.toggle" }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Toggle hard gauage
|
|
|
|
function toggle_hard()
|
|
|
|
Tcp.SendLine(json.encode({ topic = "user.hard.toggle" }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Toggle hard gauage
|
|
|
|
function toggle_mirror()
|
|
|
|
Tcp.SendLine(json.encode({ topic = "user.mirror.toggle" }))
|
|
|
|
end
|
|
|
|
|
|
|
|
function new_room()
|
|
|
|
host = user_id
|
|
|
|
owner = user_id
|
|
|
|
mpScreen.NewRoomStep()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Toggle host rotation
|
|
|
|
function toggle_rotate()
|
|
|
|
Tcp.SendLine(json.encode({ topic = "room.option.rotation.toggle" }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Change lobby host
|
|
|
|
function change_host(user)
|
|
|
|
Tcp.SendLine(json.encode({ topic = "room.host.set", host = user.id }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Kick user
|
|
|
|
function kick_user(user)
|
|
|
|
Tcp.SendLine(json.encode({ topic = "room.kick", id = user.id }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Tell the server to start the game
|
|
|
|
function start_game()
|
|
|
|
selected_song.self_picked = false
|
|
|
|
if (selected_song == nil) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if (start_game_soon) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
Tcp.SendLine(json.encode({ topic = "room.game.start" }))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Join a given room
|
|
|
|
function join_room(room)
|
|
|
|
host = user_id
|
|
|
|
selected_room = room;
|
|
|
|
if room.password then
|
|
|
|
mpScreen.JoinWithPassword(room.id)
|
|
|
|
else
|
|
|
|
mpScreen.JoinWithoutPassword(room.id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Handle button presses to advance the UI
|
|
|
|
button_pressed = function(button)
|
|
|
|
|
|
|
|
if button == game.BUTTON_STA then
|
|
|
|
if start_game_soon then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if screenState == "roomList" then
|
|
|
|
if #rooms == 0 then
|
|
|
|
new_room()
|
|
|
|
else
|
|
|
|
-- TODO navigate room selection
|
|
|
|
join_room(rooms[selected_room_index])
|
|
|
|
end
|
|
|
|
elseif screenState == "inRoom" then
|
|
|
|
if host == user_id then
|
|
|
|
if selected_song and selected_song.self_picked then
|
|
|
|
if all_ready then
|
|
|
|
start_game()
|
|
|
|
else
|
|
|
|
missing_song = false
|
|
|
|
mpScreen.SelectSong()
|
|
|
|
end
|
|
|
|
else
|
|
|
|
missing_song = false
|
|
|
|
mpScreen.SelectSong()
|
|
|
|
end
|
|
|
|
else
|
|
|
|
ready_up()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if button == game.BUTTON_BTA then
|
|
|
|
toggle_hard();
|
|
|
|
end
|
|
|
|
if button == game.BUTTON_BTB then
|
|
|
|
toggle_mirror();
|
|
|
|
end
|
|
|
|
if button == game.BUTTON_BTC then
|
|
|
|
toggle_rotate();
|
|
|
|
end
|
|
|
|
if button == game.BUTTON_BTD then
|
|
|
|
------------------------
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Handle the escape key around the UI
|
|
|
|
function key_pressed(key)
|
|
|
|
if key == 27 then --escape pressed
|
|
|
|
if screenState == "roomList" then
|
|
|
|
did_exit = true;
|
|
|
|
mpScreen.Exit();
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Reset room data
|
|
|
|
screenState = "roomList" -- have to update here
|
|
|
|
selected_room = nil;
|
|
|
|
rooms = {};
|
|
|
|
selected_song = nil
|
|
|
|
selected_song_index = 1;
|
|
|
|
jacket = 0;
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Handle mouse clicks in the UI
|
|
|
|
mouse_pressed = function(button)
|
|
|
|
if hovered then
|
|
|
|
hovered()
|
|
|
|
end
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
function init_tcp()
|
|
|
|
Tcp.SetTopicHandler("server.info", function(data)
|
|
|
|
loading = false
|
|
|
|
user_id = data.userid
|
|
|
|
end)
|
|
|
|
-- Update the list of rooms as well as get user_id for the client
|
|
|
|
Tcp.SetTopicHandler("server.rooms", function(data)
|
|
|
|
rooms = {}
|
|
|
|
for i, room in ipairs(data.rooms) do
|
|
|
|
table.insert(rooms, room)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
Tcp.SetTopicHandler("server.room.joined", function(data)
|
|
|
|
selected_room = data.room
|
|
|
|
--[[
|
|
|
|
local PlayerServerInfo = {
|
|
|
|
name = username,
|
|
|
|
msg = msg,
|
|
|
|
nav = crew,
|
|
|
|
volforce = vol,
|
|
|
|
dan = "nothing"
|
|
|
|
}
|
|
|
|
|
|
|
|
local ServerPushTable = {
|
|
|
|
topic = "user.extra.set",
|
|
|
|
data = PlayerServerInfo,
|
|
|
|
}
|
|
|
|
|
|
|
|
Tcp.SendLine(json.encode(ServerPushTable))
|
|
|
|
]]
|
|
|
|
end)
|
|
|
|
|
|
|
|
local sound_time = 0;
|
|
|
|
local sound_clip = nil;
|
|
|
|
local sounds_left = 0;
|
|
|
|
local sound_interval = 0;
|
|
|
|
|
|
|
|
function repeat_sound(clip, times, interval)
|
|
|
|
sound_clip = clip;
|
|
|
|
sound_time = 0;
|
|
|
|
sounds_left = times - 1;
|
|
|
|
sound_interval = interval;
|
|
|
|
game.PlaySample(clip)
|
|
|
|
end
|
|
|
|
|
|
|
|
function do_sounds(deltaTime)
|
|
|
|
if sound_clip == nil then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
sound_time = sound_time + deltaTime;
|
|
|
|
if sound_time > sound_interval then
|
|
|
|
sound_time = sound_time - sound_interval;
|
|
|
|
game.PlaySample(sound_clip);
|
|
|
|
sounds_left = sounds_left - 1
|
|
|
|
if sounds_left <= 0 then
|
|
|
|
sound_clip = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local last_song = nil
|
|
|
|
|
|
|
|
-- Update the current lobby
|
|
|
|
Tcp.SetTopicHandler("room.update", function(data)
|
|
|
|
-- Update the users in the lobby
|
|
|
|
lobby_users = {}
|
|
|
|
local prev_all_ready = all_ready;
|
|
|
|
all_ready = true
|
|
|
|
for i, user in ipairs(data.users) do
|
|
|
|
table.insert(lobby_users, user)
|
|
|
|
if user.id == user_id then
|
|
|
|
user_ready = user.ready
|
|
|
|
end
|
|
|
|
if not user.ready then
|
|
|
|
all_ready = false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if user_id == host and #data.users > 1 and all_ready and not prev_all_ready then
|
|
|
|
repeat_sound("click-02", 3, .1)
|
|
|
|
end
|
|
|
|
|
|
|
|
if data.host == user_id and host ~= user_id then
|
|
|
|
repeat_sound("click-02", 3, .1)
|
|
|
|
end
|
|
|
|
|
|
|
|
if data.song ~= nil and last_song ~= data.song then
|
|
|
|
game.PlaySample("menu_click")
|
|
|
|
last_song = data.song
|
|
|
|
end
|
|
|
|
host = data.host
|
|
|
|
if data.owner then
|
|
|
|
owner = data.owner
|
|
|
|
else
|
|
|
|
owner = host
|
|
|
|
end
|
|
|
|
hard_mode = data.hard_mode
|
|
|
|
mirror_mode = data.mirror_mode
|
|
|
|
do_rotate = data.do_rotate
|
|
|
|
if data.start_soon and not start_game_soon then
|
|
|
|
repeat_sound("click-01", 5, 1)
|
|
|
|
end
|
|
|
|
start_game_soon = data.start_soon
|
|
|
|
|
|
|
|
end)
|
|
|
|
end
|