C#:
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<string> 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<ConfigData>();
}
protected override void SaveConfig()
{
Config.WriteObject(config);
}
private void Init()
{
permission.RegisterPermission(permVoteDay, this);
permission.RegisterPermission(permVoteDayAdmin, this);
lang.RegisterMessages(new Dictionary<string, string>
{
["VoteStarted"] = "<color=#FFFF00>Vote to skip the night has started! You have {0} seconds to vote. Type /voteday to vote. {1} votes are needed to pass.</color>",
["VoteCount"] = "<color=#00FF00>{0} players voted yes out of {1}.</color>",
["VotePassed"] = "<color=#00FF00>The vote passed! {0} players voted yes out of {1}. Skipping to day.</color>",
["VoteFailed"] = "<color=#FF0000>The vote failed. {0} players voted yes out of {1}. The night will continue.</color>",
["NoPermission"] = "<color=#FF0000>You do not have permission to use this command.</color>",
["AlreadyVoting"] = "<color=#FF0000>A vote is already in progress.</color>",
["AlreadyVoted"] = "<color=#FF0000>You have already voted.</color>",
["ConfigReloaded"] = "<color=#00FF00>Configuration reloaded successfully.</color>",
["InvalidCommand"] = "<color=#FF0000>Invalid command usage. Use /voteday set timevote <seconds> or /voteday set requiredpercentage <percentage>.</color>",
["VoteDurationSet"] = "<color=#00FF00>Vote duration set to {0} seconds.</color>",
["RequiredPercentageSet"] = "<color=#00FF00>Required vote percentage set to {0}%.</color>",
["InvalidPercentage"] = "<color=#FF0000>Invalid percentage. Please enter a value between 1 and 100.</color>"
}, 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<string>();
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);
}
}
}
}