-- name: Squishy Votes! -- description: \\#55bb55\\Squishy Votes!\\#dcdcdc\\ - \\#ffff55\\(Hosting Tool)\\#dcdcdc\\\nA mod dedicated to allowing hosts to set up votes for users to cast in!\nStart a vote with \\#ffff00\\/vote\n\n\\#dcdcdc\\Created by:\\#008800\\ Squishy6094\n\\#dcdcdc\\Pulled and Enhanced from Squishy's Server local VERSION_MAJOR = 1 local VERSION_MINOR = 0 local VERSION_STRING = "v"..VERSION_MAJOR.."."..VERSION_MINOR local voteTimeMax = 3600 local voteTimer = -150 local voteSlide = -150 local voteName = "" local voteAnswers = {} local voteResponses = {} local MATH_DIVIDE_30 = 1/30 local table_insert,string_format,djui_hud_set_resolution,djui_hud_set_font,djui_hud_set_color,djui_hud_render_rect,network_player_get_palette_color,djui_hud_print_text,tostring,math_ceil,djui_hud_measure_text,network_player_connected_count,play_sound,tonumber,network_send,network_is_server,network_is_moderator,get_local_discord_id,string_lower = table.insert,string.format,djui_hud_set_resolution,djui_hud_set_font,djui_hud_set_color,djui_hud_render_rect,network_player_get_palette_color,djui_hud_print_text,tostring,math.ceil,djui_hud_measure_text,network_player_connected_count,play_sound,tonumber,network_send,network_is_server,network_is_moderator,get_local_discord_id,string.lower local function remove_start_end_spaces(string) local result = "" local waitToAdd = "" local firstLetter = false for i = 1, #string do local c = string:sub(i, i) if c == " " then if firstLetter then waitToAdd = waitToAdd .. c end else result = result .. waitToAdd .. c waitToAdd = "" firstLetter = true end end -- Subbed to not overflow packets return result:sub(1, 100) end local function split(s, splitAt) local result = {} if splitAt == nil then splitAt = "|" end for match in (s):gmatch(string_format("[^%s]+", splitAt)) do table_insert(result, remove_start_end_spaces(match)) end return result end local function get_votes_from_responses() local votes = {} for i = 1, #voteAnswers do votes[i] = 0 end if #voteResponses ~= 0 then for i = 1, #voteResponses do local currResponse = voteResponses[i].vote if currResponse > 0 then votes[currResponse] = votes[currResponse] + 1 end end end return votes end local function get_vote_max() local total = network_player_connected_count() local idList = {} -- Account for multiple of the same user for i = 0, MAX_PLAYERS - 1 do local id = tonumber(get_coopnet_id(i)) if id ~= 0 then if idList[id] then total = total - 1 else if id ~= nil then idList[id] = true end end end end -- Account for users who have left and voted for i = 1, #voteResponses do if not idList[voteResponses[i].id] then total = total + 1 end end return total end local function hud_render() if voteSlide <= -150 then return end djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_ALIASED) local x = 5 + voteSlide local y = 50 local heightAdd = #voteAnswers*8 djui_hud_set_color(0, 0, 0, 150) djui_hud_render_rect(x, y, 80, 43 + heightAdd) djui_hud_set_color(0, 0, 0, 200) djui_hud_render_rect(x + 2, y + 2, 76, 39 + heightAdd) local color = network_player_get_palette_color(gNetworkPlayers[0], SHIRT) color.r = color.r*0.5 + 127 color.g = color.g*0.5 + 127 color.b = color.b*0.5 + 127 djui_hud_set_color(color.r, color.g, color.b, 255) djui_hud_print_text("Vote:", x + 5, y + 5, 0.35) local text = "Ended" if voteTimer > 0 then text = tostring(math_ceil(voteTimer*MATH_DIVIDE_30)).."s left" end djui_hud_print_text(text, x + 74 - djui_hud_measure_text(text)*0.35, y + 5, 0.35) local voteScale = 1 if djui_hud_measure_text(voteName)*0.32 > 70 then voteScale = djui_hud_measure_text(voteName)*0.32 / 70 end djui_hud_print_text(voteName, x + 5, y + 15, 0.32 / voteScale) if #voteResponses == network_player_connected_count() and voteTimer > 0 then voteTimer = 0 end local votes = get_votes_from_responses() for i = 1, #voteAnswers do djui_hud_set_color(color.r, color.g, color.b, 255) djui_hud_render_rect(x + 5, y + 17.5 + i*8, 71*votes[i]/#voteResponses, 7) djui_hud_set_color(255, 255, 255, 255) local scale = 1 local string = i..". "..voteAnswers[i] .. " - " .. votes[i] if djui_hud_measure_text(string)*0.25 > 70 then scale = (djui_hud_measure_text(string))*0.25 / 69 end djui_hud_print_text(string, x + 6, y + 17 + i*8, 0.25 / scale) end djui_hud_set_font(FONT_NORMAL) djui_hud_set_color(150, 150, 150, 255) djui_hud_print_text('Use "/vote" to vote!', x + 5, y + 27 + heightAdd, 0.2) djui_hud_print_text(tostring(#voteResponses).."/"..tostring(network_player_connected_count()).." players have voted", x + 5, y + 33 + heightAdd, 0.2) djui_hud_print_text(VERSION_STRING, x + 75 - djui_hud_measure_text(VERSION_STRING)*0.2, y + 33 + heightAdd, 0.2) if voteTimer == 0 then play_sound(SOUND_GENERAL2_RIGHT_ANSWER, gMarioStates[0].marioObj.header.gfx.cameraToObject) local string = "The vote has ended: "..voteName.."\n" if #voteResponses > 0 then for i = 1, #voteAnswers do string = string..i..". "..voteAnswers[i] .. " - " .. votes[i] .. " ("..math.floor((votes[i]/#voteResponses)*100).."%)" if i < #voteAnswers then if #voteAnswers > 9 then string = string..(i%2 == 0 and "\n" or " | ") else string = string.."\n" end end end else string = string.."\nNo one voted..." end djui_chat_message_create(string) end end local PACKET_VOTE_START = 0 local PACKET_VOTE_CAST = 1 local PACKET_VOTE_CLOSE = 2 local PACKET_SYNC_USER = 3 local PACKET_REQUEST_SYNC = 4 local function on_packet_recieve(data) -- Recieved after a vote has been started if data.type == PACKET_VOTE_START then voteTimer = voteTimeMax voteName = data.voteName voteAnswers = {} voteResponses = {} for i = 1, #data do table_insert(voteAnswers, data[i]) end end -- Recieved after a vote has been casted if data.type == PACKET_VOTE_CAST then table_insert(voteResponses, {id = data.id, vote = data.vote}) end -- Recieved after a vote closes if data.type == PACKET_VOTE_CLOSE then voteTimer = 0 end -- Recieved after requesting a sync if data.type == PACKET_SYNC_USER then voteName = data.voteName voteTimer = data.voteTimer for i = 1, #data do table_insert(voteAnswers, data[i]) end if data.voteResponses ~= "0|0" then local responses = split(data.voteResponses, " ") for i = 1, #responses do local data = split(responses[i]) table_insert(voteResponses, {id = tonumber(data[1]), vote = tonumber(data[2])}) end else voteResponses = {} end voteSlide = -1 end -- Recieved when a new user joins if data.type == PACKET_REQUEST_SYNC then local responses = "" if #voteResponses > 0 then for i = 1, #voteResponses do responses = responses..voteResponses[i].id.."|"..voteResponses[i].vote.." " end else responses = "0|0" end local packet = { type = PACKET_SYNC_USER, voteName = voteName, voteTimer = voteTimer, voteResponses = responses, -- Sent for total vote checking index = network_global_index_from_local(0), id = get_coopnet_id(0) } for i = 1, #voteAnswers do table_insert(packet, voteAnswers[i]) end local localIndex = network_local_index_from_global(data.index) network_send_to(localIndex, true, packet) end end local function on_mods_load() local packet = { type = PACKET_REQUEST_SYNC, index = network_global_index_from_local(0), id = get_coopnet_id(0) } network_send(true, packet) end local function update() if voteTimer > -150 then voteTimer = voteTimer - 1 if voteSlide < -1 then voteSlide = voteSlide/1.1 end else if voteSlide > -150 then voteSlide = voteSlide*1.1 end end end local function network_has_permissions() return (network_is_server() or network_is_moderator()) end local function on_command(msg) if string_lower(msg) == "help" or string_lower(msg) == "?" then -- Help info djui_chat_message_create("\\#00AA00\\Squishy Votes "..VERSION_STRING.." Help:") if network_has_permissions() then djui_chat_message_create( "\\#00ffff\\Starting a Vote:\\#ffffff\\\n".. "When starting a vote you can use any word after the command to set it as a vote prompt.\n".. "ex: \\#ffff00\\/vote Prompt") djui_chat_message_create( "\\#00ffff\\Adding Custom Answers: \\#ffffff\\".. 'If "Yes" and "No"'.."doesn't fit your needs you can add "..'"|" in your command to split your promt and your custom answers.\n'.. "ex: \\#ffff00\\/vote Prompt|Answer 1|Answer 2") end djui_chat_message_create( "\\#00ffff\\Casting your Vote: \\#ffffff\\".. "To cast you vote, simply put the name or number relating to your answer.\n".. "ex: \\#ffff00\\/vote Yes \\#ffffff\\or \\#ffff00\\/vote 1") elseif voteTimer <= 0 then local args = split(msg) if network_has_permissions() then -- Start Vote if msg == "" then djui_chat_message_create("Invalid Prompt\nUse \\#ffff00\\/vote help \\#ffffff\\for info on how to vote!") return true end local packet = {} if #args < 2 then packet = { type = PACKET_VOTE_START, voteName = args[1], --Vote Responses [1] = "Yes", [2] = "No", } elseif #args < 3 then djui_chat_message_create("A vote with custom prompts requires at least 2 options") return true else packet = { type = PACKET_VOTE_START, voteName = args[1], } for i = 2, math.min(#args, 16) do table_insert(packet, args[i]) end if #args > 16 then djui_chat_message_create("Too many answers have been provided, your vote has been\ntrimmed to 15 answers!") end end network_send(true, packet) on_packet_recieve(packet) return true else djui_chat_message_create("A vote is not taking place at the moment") end elseif string_lower(msg) == "end" and network_has_permissions() then -- End Vote network_send(true, {type = PACKET_VOTE_CLOSE}) on_packet_recieve({type = PACKET_VOTE_CLOSE}) djui_chat_message_create("Ended Vote: "..voteName) else -- Cast Vote -- Discord ID check if #voteResponses ~= 0 and get_coopnet_id(0) ~= "-1" then for i = 1, #voteResponses do if voteResponses[i].id == tonumber(get_coopnet_id(0)) then djui_chat_message_create("You've already voted") return true end end end -- Answer Name Check msg = string_lower(remove_start_end_spaces(msg)) for i = 1, #voteAnswers do if msg == string_lower(voteAnswers[i]) then msg = i break end end msg = tonumber(msg) if msg == nil or msg > #voteAnswers or msg < 1 then djui_chat_message_create("Invalid Vote\nUse \\#ffff00\\/vote help \\#ffffff\\for info on how to vote!") return true end if msg ~= 0 then local packet = { type = PACKET_VOTE_CAST, id = tonumber(get_coopnet_id(0)), vote = tonumber(msg) } network_send(true, packet) on_packet_recieve(packet) end djui_chat_message_create("Voted for: ".. voteAnswers[tonumber(msg)]) end return true end hook_event(HOOK_ON_HUD_RENDER, hud_render) hook_event(HOOK_ON_PACKET_RECEIVE, on_packet_recieve) hook_event(HOOK_ON_MODS_LOADED, on_mods_load) hook_event(HOOK_UPDATE, update) hook_chat_command("vote", "Start a poll or Vote on an active one!", on_command)