using System; using System.Collections.Generic; using System.Linq; using Oxide.Core; using Oxide.Core.Libraries.Covalence; using UnityEngine; using Newtonsoft.Json; namespace Oxide.Plugins { [Info("VoteDay", "Kalvi", "1.2.0")] [Description("Allows players to vote to skip the night.")] public class VoteDay : CovalencePlugin { private const string permVoteDay = "voteday.use"; private const string permVoteDayAdmin = "voteday.admin"; private bool isVotingActive = false; private int yesVotes = 0; private int totalPlayers = 0; private Timer voteTimer; private HashSet votedPlayers; private ConfigData config; private class ConfigData { public float VoteDuration { get; set; } public int RequiredPercentage { get; set; } } protected override void LoadDefaultConfig() { config = new ConfigData { VoteDuration = 180f, RequiredPercentage = 50 }; SaveConfig(); } protected override void LoadConfig() { base.LoadConfig(); config = Config.ReadObject(); } protected override void SaveConfig() { Config.WriteObject(config); } private void Init() { permission.RegisterPermission(permVoteDay, this); permission.RegisterPermission(permVoteDayAdmin, this); lang.RegisterMessages(new Dictionary { ["VoteStarted"] = "Vote to skip the night has started! You have {0} seconds to vote. Type /voteday to vote. {1} votes are needed to pass.", ["VoteCount"] = "{0} players voted yes out of {1}.", ["VotePassed"] = "The vote passed! {0} players voted yes out of {1}. Skipping to day.", ["VoteFailed"] = "The vote failed. {0} players voted yes out of {1}. The night will continue.", ["NoPermission"] = "You do not have permission to use this command.", ["AlreadyVoting"] = "A vote is already in progress.", ["AlreadyVoted"] = "You have already voted.", ["ConfigReloaded"] = "Configuration reloaded successfully.", ["InvalidCommand"] = "Invalid command usage. Use /voteday set timevote or /voteday set requiredpercentage .", ["VoteDurationSet"] = "Vote duration set to {0} seconds.", ["RequiredPercentageSet"] = "Required vote percentage set to {0}%.", ["InvalidPercentage"] = "Invalid percentage. Please enter a value between 1 and 100." }, this); } private void OnTick() { var time = TOD_Sky.Instance.Cycle.Hour; if (Mathf.Floor(time) == 19f && !isVotingActive) { isVotingActive = true; yesVotes = 0; totalPlayers = covalence.Players.Connected.Count(); votedPlayers = new HashSet(); StartVote(); } } [Command("voteday")] private void VoteDayCommand(IPlayer player, string command, string[] args) { if (args.Length == 0) { HandleVoteCommand(player); return; } if (args.Length >= 1 && !player.HasPermission(permVoteDayAdmin)) { player.Message(lang.GetMessage("NoPermission", this, player.Id)); return; } switch (args[0].ToLower()) { case "reload": ReloadConfigCommand(player); break; case "set": if (args.Length == 3) { switch (args[1].ToLower()) { case "timevote": if (float.TryParse(args[2], out float newDuration)) { SetVoteDurationCommand(player, newDuration); } else { player.Message(lang.GetMessage("InvalidCommand", this, player.Id)); } break; case "requiredpercentage": if (int.TryParse(args[2], out int newPercentage) && newPercentage >= 1 && newPercentage <= 100) { SetRequiredPercentageCommand(player, newPercentage); } else { player.Message(lang.GetMessage("InvalidPercentage", this, player.Id)); } break; default: player.Message(lang.GetMessage("InvalidCommand", this, player.Id)); break; } } else { player.Message(lang.GetMessage("InvalidCommand", this, player.Id)); } break; default: player.Message(lang.GetMessage("InvalidCommand", this, player.Id)); break; } } private void HandleVoteCommand(IPlayer player) { if (!player.HasPermission(permVoteDay)) { player.Message(lang.GetMessage("NoPermission", this, player.Id)); return; } if (!isVotingActive) { player.Message(lang.GetMessage("AlreadyVoting", this, player.Id)); return; } if (votedPlayers.Contains(player.Id)) { player.Message(lang.GetMessage("AlreadyVoted", this, player.Id)); return; } votedPlayers.Add(player.Id); yesVotes++; player.Message(string.Format(lang.GetMessage("VoteCount", this, player.Id), yesVotes, totalPlayers)); } private void ReloadConfigCommand(IPlayer player) { LoadConfig(); player.Message(lang.GetMessage("ConfigReloaded", this, player.Id)); } private void SetVoteDurationCommand(IPlayer player, float newDuration) { config.VoteDuration = newDuration; SaveConfig(); player.Message(string.Format(lang.GetMessage("VoteDurationSet", this, player.Id), newDuration)); } private void SetRequiredPercentageCommand(IPlayer player, int newPercentage) { config.RequiredPercentage = newPercentage; SaveConfig(); player.Message(string.Format(lang.GetMessage("RequiredPercentageSet", this, player.Id), newPercentage)); } private void StartVote() { int requiredVotes = Mathf.CeilToInt(totalPlayers * (config.RequiredPercentage / 100f)); BroadcastToServer("VoteStarted", config.VoteDuration, requiredVotes); voteTimer = timer.Once(config.VoteDuration, EndVote); } private void EndVote() { isVotingActive = false; float requiredVotes = totalPlayers * (config.RequiredPercentage / 100f); if (yesVotes >= requiredVotes) { BroadcastToServer("VotePassed", yesVotes, totalPlayers); TOD_Sky.Instance.Cycle.Hour = 8f; } else { BroadcastToServer("VoteFailed", yesVotes, totalPlayers); } } private void BroadcastToServer(string messageKey, params object[] args) { string message = string.Format(lang.GetMessage(messageKey, this), args); foreach (var player in covalence.Players.Connected) { player.Message(message); } } } }