C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Oxide.Core.Plugins;
/*
* This update 1.0.12
* Fixes economic issues
* Finished old feature integration for PopUpNotifications plugin
* Added new config option for setting custom health level
* Updated auto updater to include new config variables.*
* This update 1.0.20
* Added ServerRewards Support (Updated variables/logic)
* Updated Lang
* Updated To OnPlayerWounded to save on performance rather than using OnEntityTakeDamage.*/
namespace Oxide.Plugins {
[Info("Unwound", "mk_sky/Khan", "1.0.20")]
[Description("The sky presents the newest technology in calling the MEDIC!")]
class Unwound : RustPlugin {
#region vars
ListDictionary<string, string> localization;
List<ulong> called = new List<ulong>();
ListDictionary<uint, uint> ecoSettings;
List<ulong> inUnwoundZone = new List<ulong>();
float startHealth = 50;
uint waitTillMedic = 10;
bool popupsEnabled = false;
uint chanceTheMedicSavesYou = 100;
bool canCallMedicOncePerWounded = true;
bool enableServerRewards = false;
bool enableEconomics = true;
bool enableCurrency = false;
bool forceCurrency = false;
[PluginReference]
Plugin Economics, ZoneManager, PopupNotifications, ServerRewards;
#endregion
void OnServerInitialized() {
ConfigLoader();
permission.RegisterPermission("unwound.canuse", this);
}
protected override void LoadDefaultConfig() {
Config.Clear();
Config["Version"] = Version.ToString();
#region localization
Config["Localization", "PermissionMissing"] = "You have no permission to use this command, if you're wounded right now it means you're probably screwed!";
Config["Localization", "TheMedicIsComing"] = "The medic is coming for you...that means if you can survive another {0} seconds.";
Config["Localization", "NotWounded"] = "You're not wounded, get your extra shots somewhere else!";
Config["Localization", "Survived"] = "The claws of death failed to claim you this time!";
Config["Localization", "DontTrollTheMedic"] = "How dare you call the medic and then don't wait for him before staying up again!";
Config["Localization", "AboutToDie"] = "You are about to die, use /aid to call for a medic.\n{0}";
Config["Localization", "MedicToLate"] = "Seems like your medic found some free beer on the way and won't come in time now...I think we have to cut his salary!";
Config["Localization", "MedicIncompetent"] = "This incompetent troll of a medic is just to stupid to get you back up, we will get rid of him!";
Config["Localization", "MedicAlreadyCalled"] = "You already called for a medic, just wait for him.";
Config["Localization", "NotEnoughMoney"] = "You don't have enough money, how horrible...You have {0} and you would need {1} so just wait the full {2} seconds for the medic.";
Config["Localization", "NotEnoughMoney_ForcedEco"] = "You don't have enough money, how horrible...You have {0} and you would need {1}, maybe I'll come to your funeral then.";
#endregion
#region settings
Config["Settings", "StartHealth"] = 50f;
Config["Settings", "WaitTillMedic"] = 10;
Config["Settings", "ChanceTheMedicSavesYou"] = 100;
Config["Settings", "CanCallMedicOncePerWounded"] = true;
Config["Settings", "EnablePopups"] = false;
Config["Settings", "EnableServerRewards"] = false;
Config["Settings", "EnableEconomics"] = true;
Config["Settings", "EnableCurrency"] = false;
Config["Settings", "ForceCurrency"] = false;
Config["EcoSettings", "10"] = 10;
Config["EcoSettings", "100"] = 1;
#endregion
SaveConfig();
PrintWarning("Unwound created a new config.");
}
void ConfigLoader() {
base.LoadConfig();
if (Config.Exists() && Config["Version"].ToString() != Version.ToString()) ConfigUpdater();
#region localization
localization = new ListDictionary<string, string>();
localization.Add("PermissionMissing", Config["Localization", "PermissionMissing"].ToString());
localization.Add("TheMedicIsComing", Config["Localization", "TheMedicIsComing"].ToString());
localization.Add("NotWounded", Config["Localization", "NotWounded"].ToString());
localization.Add("Survived", Config["Localization", "Survived"].ToString());
localization.Add("DontTrollTheMedic", Config["Localization", "DontTrollTheMedic"].ToString());
localization.Add("AboutToDie", Config["Localization", "AboutToDie"].ToString());
localization.Add("MedicToLate", Config["Localization", "MedicToLate"].ToString());
localization.Add("MedicIncompetent", Config["Localization", "MedicIncompetent"].ToString());
localization.Add("MedicAlreadyCalled", Config["Localization", "MedicAlreadyCalled"].ToString());
localization.Add("NotEnoughMoney", Config["Localization", "NotEnoughMoney"].ToString());
localization.Add("NotEnoughMoney_ForcedEco", Config["Localization", "NotEnoughMoney_ForcedEco"].ToString());
#endregion
#region settings
startHealth = Convert.ToSingle(Config["Settings", "StartHealth"])> 100 ? 100 : Convert.ToUInt32(Config["Settings", "StartHealth"]);
if (startHealth == 0) {
PrintError("The startHealth can't be 0, Plugin will run it with 1.");
//still almost 0 but not 0
startHealth = 1;
}
waitTillMedic = Convert.ToUInt32(Config["Settings", "WaitTillMedic"]);
chanceTheMedicSavesYou = Convert.ToUInt32(Config["Settings", "ChanceTheMedicSavesYou"]) > 100 ? 100 : Convert.ToUInt32(Config["Settings", "ChanceTheMedicSavesYou"]);
if (chanceTheMedicSavesYou == 0) {
PrintError("The ChanceTheMedicSavesYou can't be 0, Plugin will run it with 1.");
//still almost 0 but not 0
chanceTheMedicSavesYou = 1;
}
canCallMedicOncePerWounded = Convert.ToBoolean(Config["Settings", "CanCallMedicOncePerWounded"]);
if (PopupNotifications == null && Convert.ToBoolean(Config["Settings", "EnablePopups"])) PrintError("PopupNotifications-Plugin missing, can't enable pop-ups.Get the plugin first: https://umod.org/plugins/popup-notifications/");
else if (PopupNotifications != null && Convert.ToBoolean(Config["Settings", "EnablePopups"])) popupsEnabled = true;
enableEconomics = Convert.ToBoolean(Config["Settings", "EnableEconomics"]);
enableServerRewards = Convert.ToBoolean(Config["Settings", "EnableServerRewards"]);
ecoSettings = new ListDictionary<uint, uint>();
if (Convert.ToBoolean(Config["Settings", "EnableCurrency"])) {
Puts("settings EnableCurrency is true");
enableCurrency = true;
forceCurrency = Convert.ToBoolean(Config["Settings", "ForceCurrency"]);
Dictionary<string, string> temp = Config.Get<Dictionary<string, string>>("EcoSettings");
foreach (KeyValuePair<string, string> s in temp) if (Convert.ToUInt32(s.Value) >= 0) ecoSettings.Add(Convert.ToUInt32(s.Key), Convert.ToUInt32(s.Value));
Puts($"{ecoSettings.Count}");
ecoSettings.Keys.Reverse();
}
if (Convert.ToBoolean(Config["Settings", "EnableEconomics"]) && Economics == null) {
PrintError("Economics-Plugin missing, can't enable economics.Get the plugin first: https://umod.org/plugins/economics");
}
if (Convert.ToBoolean(Config["Settings", "EnableServerRewards"]) && ServerRewards == null) {
PrintError("ServerRewards-Plugin missing, can't enable server rewards.Get the plugin first: https://umod.org/plugins/server-rewards");
}
#endregion
}
void ConfigUpdater() {
PrintWarning(String.Format("Config updated from v{0} to v{1}.", Config["Version"].ToString(), this.Version.ToString()));
while (Config["Version"].ToString() != this.Version.ToString()) switch (Config["Version"].ToString()) {
#region 1.0.0 => 1.0.1
case "1.0.0" : Config["Localization", "AboutToDie"] = "You are about to die, use /aid to call for a medic.";
Config["Localization", "MedicToLate"] = "Seems like your medic found some free beer on the way and won't come in time now...I think we have to cut his salary!";
Config["Localization", "MedicIncompetent"] = "This incompetent troll of a medic is just to stupid to get you back up, we will get rid of him!";
Config["Localization", "MedicAlreadyCalled"] = "You already called for a medic, just wait for him.";
Config["Localization", "NotEnoughMoney"] = "You don't have enough money, how horrible...You have {0} and you would need {1} so just wait the full {2} seconds for the medic.";
Config["Settings", "ChanceTheMedicSavesYou"] = 100;
Config["Settings", "CanCallMedicOncePerWounded"] = true;
Config["Settings", "EnablePopups"] = false;
Config["Settings", "EnableEconomics"] = false;
Config["EcoSettings", "500"] = 0;
Config["EcoSettings", "250"] = 5;
Config["Version"] = "1.0.1";
break;
#endregion
#region 1.0.1 || 1.0.2 || 1.0.3 || 1.0.4 || 1.0.5 || 1.0.6 || 1.0.7 => 1.0.8
case "1.0.1" : case "1.0.2" : case "1.0.3" : case "1.0.4" : case "1.0.5" : case "1.0.6" : case "1.0.7" : Config["Version"] = "1.0.8";
break;
#endregion
#region 1.0.8 => 1.0.9
case "1.0.8" : if (permission.PermissionExists("canuseunwound")) {
string[] playersWithPermission = permission.GetPermissionUsers("canuseunwound");
foreach (string s in playersWithPermission) if (permission.UserHasPermission(s.Substring(0, s.IndexOf('(')), "canuseunwound")) {
permission.RevokeUserPermission(s.Substring(0, s.IndexOf('(')), "canuseunwound");
permission.GrantUserPermission(s.Substring(0, s.IndexOf('(')), "unwound.canuse", this);
}
string[] groupsWithPermission = permission.GetPermissionGroups("canuseunwound");
foreach (string s in groupsWithPermission) if (permission.GroupHasPermission(s, "canuseunwound")) {
permission.RevokeGroupPermission(s, "canuseunwound");
permission.GrantGroupPermission(s, "unwound.canuse", this);
}
permission.RemoveGroup("canuseunwound");
}
Config["Localization", "NotEnoughMoney_ForcedEco"] = "You don't have enough money, how horrible...You have {0} and you would need {1}, maybe I'll come to your funeral then.";
Config["Settings", "EnablePopups"] = null;
Config["Settings", "ForceEconomics"] = false;
Config["Version"] = "1.0.9";
break;
#endregion
#region 1.0.11 => 1.0.12
case "1.0.11" : Config["Settings", "EnablePopups"] = false;
Config["Settings", "StartHealth"] = 50;
Config["Version"] = "1.0.12";
break;
#endregion
#region 1.0.12 => 1.0.20
case "1.0.12" : Config["Settings", "EnableServerRewards"] = false;
Config["Localization", "AboutToDie"] = "You are about to die, use /aid to call for a medic.\n{0}";
Config["Settings", "EnableCurrency"] = false;
Config["Settings", "ForceCurrency"] = false;
Config["Version"] = "1.0.20";
break;
#endregion
}
SaveConfig();
}
[ConsoleCommand("unwound.recreate")]
void ConsoleCommandConfigRecreate() {
LoadDefaultConfig();
ConfigLoader();
}
[ConsoleCommand("unwound.load")]
void ConsoleCommandConfigLoad() {
ConfigLoader();
}
[ConsoleCommand("unwound.set")]
void ConsoleCommandConfigSet(ConsoleSystem.Arg arg) {
if (IsUInt(arg.GetString(2))) Config[arg.GetString(0), arg.GetString(1)] = arg.GetUInt(2);
else if (arg.GetString(2) == "true" || arg.GetString(2) == "false") Config[arg.GetString(0), arg.GetString(1)] = arg.GetBool(2);
else Config[arg.GetString(0), arg.GetString(1)] = arg.GetString(2);
SaveConfig();
ConfigLoader();
}
[ChatCommand("aid")]
void ChatCommandAid(BasePlayer player, string command, string[] args) {
if (!permission.UserHasPermission(player.UserIDString, "unwound.canuse")) {
if (!popupsEnabled) SendReply(player, localization["PermissionMissing"]);
else PopupNotifications.Call("CreatePopupNotification", localization["PermissionMissing"], player);
return;
}
if (!player.IsWounded()) {
if (!popupsEnabled) SendReply(player, localization["NotWounded"]);
else PopupNotifications.Call("CreatePopupNotification", localization["NotWounded"], player);
return;
}
if (canCallMedicOncePerWounded && waitTillMedic > 0 && !CheckCanCall(player)) return;
if (args.Length > 0 && args[0] == "0" || args.Length > 0 && IsUInt(args[0]) && !ecoSettings.Contains(Convert.ToUInt32(args[0])) && !enableCurrency && args[0] != "?") {
args = new string[0];
}
double playerMoney = GetCurrency(player);
// Economics.Call<double>("Balance", player.userID);
if (args.Length == 0 && enableCurrency && forceCurrency || args.Length == 1 && args[0] == "?" && enableCurrency) {
playerMoney = GetCurrency(player);
// Economics.Call<double>("Balance", player.userID);
uint test = 0;
for (int i = 0; i < ecoSettings.Count; i++) if (playerMoney >= ecoSettings.GetByIndex(i).Key && test < ecoSettings.GetByIndex(i).Key) {
test = ecoSettings.GetByIndex(i).Key;
}
else if (i + 1 == ecoSettings.Count && test == 0 && forceCurrency) {
test = ecoSettings.GetByIndex(0).Key;
}
if (forceCurrency || test != 0) {
args = new string[1] {
test.ToString()
}
;
}
else if (args.Length == 1 && args[0] == "?") {
args = new string[0];
}
}
if (waitTillMedic > 0 || enableCurrency && forceCurrency) {
if (args.Length >= 1 && IsUInt(args[0])) {
if (playerMoney >= Convert.ToDouble(args[0])) {
uint waittime = waitTillMedic;
if (ecoSettings.Contains(Convert.ToUInt32(args[0]))) {
Withdraw(player, Convert.ToDouble(args[0]));
waittime = ecoSettings[Convert.ToUInt32(args[0])];
}
else if (!ecoSettings.Contains(Convert.ToUInt32(args[0]))) {
SendReply(player, $"Invalid aid amount, valid options are\n{string.Join("\n", ecoSettings.Select(x => $"Cost {
x.Key
}
, Seconds until revived {
x.Value
}
").ToArray())}");
}
//Economics.Call("Withdraw", player.userID, Convert.ToDouble(args[0]));
if (waittime > 0) {
if (!popupsEnabled) SendReply(player, String.Format(localization["TheMedicIsComing"], waittime.ToString()));
else PopupNotifications.Call("CreatePopupNotification", String.Format(localization["TheMedicIsComing"], waittime.ToString()), player);
Action timed = new Action(() => TimedMedic(player.userID));
timer.In(waittime, timed);
}
else {
called.Remove(player.userID);
if (!MedicGetsYouUp(player)) {
switch (Oxide.Core.Random.Range(0, 1)) {
case 0 : if (!popupsEnabled) SendReply(player, localization["MedicToLate"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicToLate"], player);
break;
case 1 : if (!popupsEnabled) SendReply(player, localization["MedicIncompetent"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicIncompetent"], player);
break;
}
return;
}
player.StopWounded();
player.health = startHealth;
player.metabolism.bleeding.value = 0f;
if (!popupsEnabled) SendReply(player, localization["Survived"]);
else PopupNotifications.Call("CreatePopupNotification", localization["Survived"], player);
}
}
else {
if (!popupsEnabled) SendReply(player, String.Format((forceCurrency ? localization["NotEnoughMoney_ForcedEco"] : localization["NotEnoughMoney"]), playerMoney.ToString(""), args[0], waitTillMedic.ToString()));
else PopupNotifications.Call("CreatePopupNotification", String.Format((forceCurrency ? localization["NotEnoughMoney_ForcedEco"] : localization["NotEnoughMoney"]), playerMoney.ToString(""), args[0], waitTillMedic.ToString()), player);
if (!forceCurrency) {
Action timed = new Action(() => TimedMedic(player.userID));
timer.In(waitTillMedic, timed);
}
else called.Remove(player.userID);
}
}
else if (!forceCurrency) {
Puts("is called inside the !forceCurrency");
if (!popupsEnabled) SendReply(player, String.Format(localization["TheMedicIsComing"], waitTillMedic.ToString()));
else PopupNotifications.Call("CreatePopupNotification", String.Format(localization["TheMedicIsComing"], waitTillMedic.ToString()), player);
Action timed = new Action(() => TimedMedic(player.userID));
timer.In(waitTillMedic, timed);
}
}
else {
if (!MedicGetsYouUp(player)) {
switch (Oxide.Core.Random.Range(0, 1)) {
case 0 : if (!popupsEnabled) SendReply(player, localization["MedicToLate"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicToLate"], player);
break;
case 1 : if (!popupsEnabled) SendReply(player, localization["MedicIncompetent"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicIncompetent"], player);
break;
}
return;
}
player.StopWounded();
player.health = startHealth;
player.metabolism.bleeding.value = 0f;
if (!popupsEnabled) SendReply(player, localization["Survived"]);
else PopupNotifications.Call("CreatePopupNotification", localization["Survived"], player);
}
}
void TimedMedic(ulong playerID) {
BasePlayer player = BasePlayer.FindByID(playerID);
if (player == null) {
PrintWarning(String.Format("Unwound reports that the medic has arrived, but player \"{0}\" does not exist...", playerID.ToString()));
SendReply(player, String.Format("Unwound reports that the medic has arrived, but player \"{0}\" does not exist...", playerID.ToString()));
return;
}
else if (!player.IsConnected) return;
else if (player.IsDead()) {
//TODO: code to enqueue a message for the player
return;
}
else if (!player.IsWounded()) {
if (!popupsEnabled) SendReply(player, localization["DontTrollTheMedic"]);
else PopupNotifications.Call("CreatePopupNotification", localization["DontTrollTheMedic"], player);
return;
}
else if (!MedicGetsYouUp(player)) {
called.Remove(player.userID);
switch (Oxide.Core.Random.Range(0, 1)) {
case 0 : if (!popupsEnabled) SendReply(player, localization["MedicToLate"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicToLate"], player);
break;
case 1 : if (!popupsEnabled) SendReply(player, localization["MedicIncompetent"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicIncompetent"], player);
break;
}
return;
}
called.Remove(player.userID);
player.StopWounded();
player.health = startHealth;
player.metabolism.bleeding.value = 0f;
if (!popupsEnabled) SendReply(player, localization["Survived"]);
else PopupNotifications.Call("CreatePopupNotification", localization["Survived"], player);
}
void OnPlayerWound(BasePlayer player, HitInfo hitInfo) {
if (ZoneManager != null) {
object canBeWounded = ZoneManager.Call("CanBeWounded", player, hitInfo);
if (canBeWounded == null) return;
}
if (!popupsEnabled) SendReply(player, string.Format(localization["AboutToDie"], string.Join("\n", ecoSettings.Select(x => $"Cost {x.Key}, Seconds until revived {x.Value}").ToArray())));
else PopupNotifications.Call("CreatePopupNotification", string.Format(localization["AboutToDie"], string.Join("\n", ecoSettings.Select(x => $"Cost {x.Key}, Seconds until revived {x.Value}").ToArray())), player);
}
bool CheckCanCall(BasePlayer player) {
if (called.Contains(player.userID)) {
if (!popupsEnabled) SendReply(player, localization["MedicAlreadyCalled"]);
else PopupNotifications.Call("CreatePopupNotification", localization["MedicAlreadyCalled"], player);
return false;
}
else {
called.Add(player.userID);
return true;
}
}
bool MedicGetsYouUp(BasePlayer player) {
if (chanceTheMedicSavesYou == 100) return true;
uint success = 0;
//with 100k-test-rounds this seemed pretty accurate...well 99% chance is as failsafe as 100%, so not perfect but good enough
for (int i = 0; i <= 100; i++) success += (uint)Oxide.Core.Random.Range(1, 100);
success = success % 100;
return success <= chanceTheMedicSavesYou;
}
static double ConvertToUnixTimestamp(DateTime date) {
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalSeconds);
}
static bool IsUInt(string s) {
Regex _uint = new Regex("^\\d*$");
return _uint.Match(s).Success;
}
#region Currency System
double GetCurrency(BasePlayer player) {
if (enableEconomics && !enableServerRewards && Economics != null) {
return Economics.Call<double>("Balance", player.UserIDString);
}
if (enableServerRewards && !enableEconomics && ServerRewards != null) {
return ServerRewards.Call<int>("CheckPoints", player.UserIDString);
}
PrintWarning("Default currency not selected");
return 0;
}
bool Withdraw(BasePlayer player, double amount) {
if (enableEconomics && !enableServerRewards && Economics != null) {
Puts("Economics called all good.");
return Economics.Call<bool>("Withdraw", player.userID, amount);
}
if (enableServerRewards && !enableEconomics && ServerRewards != null) {
Puts("Yo called fucking Server Rewards bitch");
return ServerRewards.Call<object>("TakePoints", player.userID, (int)amount) != null;
}
Puts("Both failed.");
return false;
}
#endregion
}
}