C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Oxide.Plugins
{
[Info("Bet And Win", "Arinrr", "1.2.0")]
[Description("Simple gambling game")]
internal class BetAndWin : RustPlugin
{
[PluginReference] private readonly Plugin ServerRewards, Economics;
private const string PERMISSION_USE = "betandwin.use";
private Dictionary<ulong, int> playerBet = new Dictionary<ulong, int>();
private bool eventHasOpen;
private DateTime nextEventTime;
private DateTime currentTime;
private void Init()
{
LoadData();
LoadConfig();
permission.RegisterPermission(PERMISSION_USE, this);
cmd.AddChatCommand(configData.command, this, nameof(BetCMD));
}
private void OnServerInitialized()
{
currentTime = DateTime.Now;
float random = UnityEngine.Random.Range(configData.minimumEventTime, configData.maximumEventTime);
nextEventTime = currentTime.AddSeconds(random);
timer.Once(random, () => OpenEvent());
if (configData.useServerRewards)
{
if (ServerRewards == null)
PrintError("ServerRewards is not installed and cannot be used");
}
else if (Economics == null)
PrintError("Economics is not installed and cannot be used");
}
private void Unload()
{
if (eventHasOpen)
foreach (var entry in playerBet)
GiveBet(entry.Key, entry.Value);
foreach (var player in BasePlayer.activePlayerList)
player.SendConsoleCommand("gametip.hidegametip");
playerBet.Clear();
SaveData();
}
private void OnServerSave() => SaveData();
private void OpenEvent()
{
if (eventHasOpen) return;
eventHasOpen = true;
currentTime = DateTime.Now;
float random = UnityEngine.Random.Range(configData.minimumEventTime, configData.maximumEventTime);
nextEventTime = currentTime.AddSeconds(random);
timer.Once(random, () => OpenEvent());
NotifyAllPlayers(Lang("UI_EventOpen", null, configData.eventTime), configData.messageTime);
PrintServer(Lang("EventOpen", null, configData.eventTime));
timer.Once(configData.eventTime, () => OverEnvent());
}
private void OverEnvent()
{
if (!eventHasOpen) return;
ulong winnerID = GetWinner();
if (winnerID == 0)
{
NotifyAllPlayers(Lang("UI_NoWinner", null), configData.messageTime);
PrintServer(Lang("NoWinner", null));
eventHasOpen = false;
playerBet.Clear();
return;
}
int sum = playerBet.Values.Sum();
GiveBet(winnerID, sum);
playerBet.Clear();
string winner = winnerID.ToString();
if (storeData.playerRanking.ContainsKey(winnerID))
storeData.playerRanking[winnerID] += sum;
else
storeData.playerRanking.Add(winnerID, sum);
var player = RelationshipManager.FindByID(winnerID);
if (player != null)
{
winner = player.displayName;
NotifyPlayer(player, Lang("YourWin", player.UserIDString, sum), configData.messageTime);
}
NotifyAllPlayers(Lang("UI_BroadcastWinner", null, winner, sum, nextEventTime.Subtract(DateTime.Now).ToShortString()), configData.messageTime, player);
PrintServer(Lang("BroadcastWinner", null, winner, sum, nextEventTime.Subtract(DateTime.Now).ToShortString()));
eventHasOpen = false;
}
private ulong GetWinner()
{
if (playerBet.Count <= 0) return 0;
int sum = playerBet.Values.Sum();
int random = UnityEngine.Random.Range(0, sum);
playerBet = playerBet.OrderBy(x => x.Value).ToDictionary(x => x.Key, y => y.Value);
int i = 0;
foreach (var entry in playerBet)
{
if (i <= random && random < i + entry.Value)
return entry.Key;
i += entry.Value;
}
return 0;
}
private void NotifyPlayer(BasePlayer player, string text, float time)
{
if (player == null) return;
player.SendConsoleCommand("gametip.hidegametip");
player.SendConsoleCommand("gametip.showgametip", text);
timer.Once(time, () =>
{
if (player == null) return;
player.SendConsoleCommand("gametip.hidegametip");
});
}
private void NotifyAllPlayers(string text, float time, BasePlayer basePlayer = null)
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (basePlayer != null && player == basePlayer) continue;
NotifyPlayer(player, text, time);
}
}
private bool GiveBet(ulong playerID, int amount)
{
if (configData.useServerRewards)
{
object obj = ServerRewards?.Call("AddPoints", playerID, amount);
if (obj is bool && (bool)obj) return true;
}
else
{
object obj = Economics?.Call("Deposit", playerID, (double)amount);
if (obj is bool && (bool)obj) return true;
}
return false;
}
private bool TakeBet(ulong playerID, int amount)
{
if (configData.useServerRewards)
{
object obj1 = ServerRewards?.Call("CheckPoints", playerID);
if (obj1 is int && (int)obj1 < amount) return false;
object obj = ServerRewards?.Call("TakePoints", playerID, amount);
if (obj is bool && (bool)obj) return true;
}
else
{
object obj = Economics?.Call("Withdraw", playerID, (double)amount);
if (obj is bool && (bool)obj) return true;
}
return false;
}
private string GetTop()
{
if (storeData.playerRanking.Count <= 0) return string.Empty;
storeData.playerRanking = storeData.playerRanking.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, y => y.Value);
int count = 0;
string ranking = string.Empty;
foreach (var entry in storeData.playerRanking)
{
if (count > 10) break;
string playerName = entry.Key.ToString();
var player = RelationshipManager.FindByID(entry.Key);
if (player != null) playerName = player.displayName;
ranking += $"\n{playerName} : {entry.Value}";
count++;
}
return ranking;
}
private void BetCMD(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PERMISSION_USE))
{
Print(player, Lang("NoPermission", player.UserIDString));
return;
}
if (args?.Length == 0 && playerBet.ContainsKey(player.userID) && configData.canCancelBet)
{
GiveBet(player.userID, playerBet[player.userID]);
playerBet.Remove(player.userID);
Print(player, Lang("CancelBet", player.UserIDString));
return;
}
if (args?.Length != 1)
{
Print(player, Lang("InvalidSyntax", player.UserIDString, configData.command));
return;
}
if (args[0] == "next")
{
Print(player, Lang("NextTime", player.UserIDString, nextEventTime.Subtract(DateTime.Now).ToShortString()));
return;
}
else if (args[0] == "top")
{
Print(player, Lang("Top", player.UserIDString, GetTop()));
return;
}
if (!eventHasOpen)
{
Print(player, Lang("EventNotOpen", player.UserIDString));
return;
}
int bet = -1;
if (!int.TryParse(args[0], out bet) || bet <= 0)
{
Print(player, Lang("NoInteger", player.UserIDString));
return;
}
if (bet < configData.minimumBet || bet > configData.maximumBet)
{
Print(player, Lang("OutOfRange", player.UserIDString, configData.minimumBet, configData.maximumBet));
return;
}
if (playerBet.ContainsKey(player.userID))
{
if (configData.canModifyBet)
{
if (bet == playerBet[player.userID])
{
Print(player, Lang("ModifyBet", player.UserIDString, playerBet[player.userID]));
return;
}
if (bet > playerBet[player.userID])
{
if (!TakeBet(player.userID, bet - playerBet[player.userID]))
{
Print(player, Lang("CantModifyBet", player.UserIDString, playerBet[player.userID]));
return;
}
}
else GiveBet(player.userID, playerBet[player.userID] - bet);
playerBet[player.userID] = bet;
Print(player, Lang("ModifyBet", player.UserIDString, playerBet[player.userID]));
}
else
Print(player, Lang("AlreadyBet", player.UserIDString, playerBet[player.userID]));
return;
}
if (!TakeBet(player.userID, bet))
{
Print(player, Lang("UnableBet", player.UserIDString));
return;
}
playerBet.Add(player.userID, bet);
if (bet >= configData.notiftBet) NotifyAllPlayers(Lang("UI_Wealthy", player.UserIDString, player.displayName, bet), configData.messageTime);
PrintServer(Lang("Wealthy", player.UserIDString, player.displayName, bet));
Print(player, Lang("SuccessfulBet", player.UserIDString, bet));
}
#region ConfigurationFile
private ConfigData configData;
private class ConfigData
{
[JsonProperty(PropertyName = "If true, will use ServerRewards, otherwise use Economics")]
public bool useServerRewards;
[JsonProperty(PropertyName = "Allow players to cancel bets?")]
public bool canCancelBet;
[JsonProperty(PropertyName = "Allow players to modify their bets?")]
public bool canModifyBet;
[JsonProperty(PropertyName = "Minimum bet")]
public int minimumBet;
[JsonProperty(PropertyName = "Maximum bet")]
public int maximumBet;
[JsonProperty(PropertyName = "Minimum interval between events (seconds)")]
public float minimumEventTime;
[JsonProperty(PropertyName = "Maximum interval between events (seconds)")]
public float maximumEventTime;
[JsonProperty(PropertyName = "Event duration (seconds)")]
public float eventTime;
[JsonProperty(PropertyName = "Message duration (seconds)")]
public float messageTime;
[JsonProperty(PropertyName = "The bet is greater than it, will notify everyone")]
public int notiftBet;
[JsonProperty(PropertyName = "Chat command")]
public string command;
[JsonProperty(PropertyName = "Chat prefix")]
public string prefix;
[JsonProperty(PropertyName = "Chat prefix color")]
public string prefixColor;
[JsonProperty(PropertyName = "Chat steamID icon")]
public ulong steamIDIcon;
public static ConfigData DefaultConfig()
{
return new ConfigData
{
useServerRewards = true,
canCancelBet = false,
canModifyBet = false,
minimumBet = 5,
maximumBet = 50,
minimumEventTime = 1800f,
maximumEventTime = 3600f,
eventTime = 60f,
messageTime = 10f,
notiftBet = 45,
command = "bet",
prefix = "[BetAndWin]:",
prefixColor = "#00FFFF",
steamIDIcon = 76560000000000000,
};
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
configData = Config.ReadObject<ConfigData>();
if (configData == null)
LoadDefaultConfig();
}
catch
{
PrintError("The configuration file is corrupted");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig()
{
PrintWarning("Creating a new configuration file");
configData = ConfigData.DefaultConfig();
}
protected override void SaveConfig() => Config.WriteObject(configData);
#endregion ConfigurationFile
#region DataFile
private StoreData storeData;
private class StoreData
{
public Dictionary<ulong, int> playerRanking = new Dictionary<ulong, int>();
}
private void LoadData()
{
try
{
storeData = Interface.Oxide.DataFileSystem.ReadObject<StoreData>(Name);
}
catch
{
ClearData();
}
}
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, storeData);
private void ClearData()
{
storeData = new StoreData();
SaveData();
}
#endregion DataFile
#region LanguageFile
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPermission"] = "You do not have permission to use this command",
["InvalidSyntax"] = "Invalid Syntax.Please enter \"{0} <bet amount>\"",
["CancelBet"] = "You successfully cancelled the bet",
["EventNotOpen"] = "The event is not yet open",
["NoInteger"] = "The bet must be a positive integer",
["OutOfRange"] = "Unable to bet, minimum bet: {0}, maximum bet: {1}",
["CantModifyBet"] = "You can't modify the bet.The balance is insufficient.Current bet: {0}",
["ModifyBet"] = "You successfully modified the bet.Current bet: {0}",
["AlreadyBet"] = "You have placed a bet and cannot modify the bet.Current bet: {0}",
["UnableBet"] = "Unable to bet, insufficient balance",
["BroadcastWinner"] = "{0} won {1} bets.The next event time is after {2}",
["UI_BroadcastWinner"] = "{0} won {1} bets.The next event time is after {2}",
["NoWinner"] = "No one bet, the bet is over",
["UI_NoWinner"] = "No one bet, the bet is over",
["EventOpen"] = "The betting event has started.Please bet quickly, The event duration: {0}",
["UI_EventOpen"] = "The betting event has started.Please bet quickly, The event duration: {0}",
["YourWin"] = "You win.got all the bets: {0}",
["SuccessfulBet"] = "Successful bet, current bet: {0}",
["Wealthy"] = "{0} actually bet {1}, too rich",
["UI_Wealthy"] = "{0} actually bet {1}, too rich",
["NextTime"] = "The time of the next event is after {0}",
["Top"] = " Top 10 winners: {0}",
}, this);
}
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private void Print(BasePlayer player, string message) => Player.Message(player, message, $"<color={configData.prefixColor}>{configData.prefix}</color>", configData.steamIDIcon);
private void PrintServer(string message) => Server.Broadcast(message, $"<color={configData.prefixColor}>{configData.prefix}</color>", configData.steamIDIcon);
#endregion LanguageFile
}
}