Can the author add the temperature in items that cause infection on consumption, such as - 20 ° C, which is likely to cause viruses
Mention meaning
I'm a bit confused at your request, you want temperature to be listed in items? You can already create a disease that is contracted by being exposed to cold temperatures, it can be done using the Random Outbreak settings in the disease configuration.
mr01sam
I'm a bit confused at your request, you want temperature to be listed in items? You can already create a disease that is contracted by being exposed to cold temperatures, it can be done using the Random Outbreak settings in the disease configuration.
thank you
mr01sam
I'm a bit confused at your request, you want temperature to be listed in items? You can already create a disease that is contracted by being exposed to cold temperatures, it can be done using the Random Outbreak settings in the disease configuration.
I configured it, but it didn't work,0 ° ~ - 30 °, 100% of people at this temperature will be detected every 30 seconds
"Entities that cause infection on hit": [],
"Random outbreak settings": {
"Outbreaks enabled": true,
"Outbreak chance (0-100)": 100.0,
"Time interval (seconds)": 30,
"Only outbreak on players with the following stats": [
{
"Stat name": "temperature",
"Min value": 0.0,
"Max value": -30.0
}
] You want min value to be -30 and max value to be 0. What you have currently won't work because -30 is less than 0.
Edit: Or, if u want it to affect people who are in conditions less than -30. Then make it maxvalue=-30 minvalue=-100 (or something really cold)
mr01sam
You want min value to be -30 and max value to be 0. What you have currently won't work because -30 is less than 0.
Edit: Or, if u want it to affect people who are in conditions less than -30. Then make it maxvalue=-30 minvalue=-100 (or something really cold)
"Random outbreak settings": {
"Outbreaks enabled": true,
"Outbreak chance (0-100)": 100.0,
"Time interval (seconds)": 30,
"Only outbreak on players with the following stats": [
{
"Stat name": "temperature",
"Min value": -30.0,
"Max value": 0.0
}It's still useless if I set it like this
mr01sam
You want min value to be -30 and max value to be 0. What you have currently won't work because -30 is less than 0.
Edit: Or, if u want it to affect people who are in conditions less than -30. Then make it maxvalue=-30 minvalue=-100 (or something really cold)
My entire breakconditions have not been reflected. Can you help me see that there is no red ink in my CMD
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Diseases", "mr01sam", "2.1.0")]
[Description("Players can be inflicted with disease that can be spread to others")]
public class Diseases : CovalencePlugin
{
public static Diseases PLUGIN;
/* Permissions */
private const string PermissionUse = "diseases.use";
private const string PermissionAdmin = "diseases.admin";
/* Dependencies */
[PluginReference]
private Plugin ImageLibrary;
/* Constants */
private const float PLAYER_TICK_RATE = 1f;
private static bool debug = false;
/* Global data */
private DiseaseManager diseaseManager;
private EffectManager effectManager;
private Dictionary<string, DiseaseStats> diseaseStats;
#region Oxide Hooks
void Init()
{
PLUGIN = this;
/* Unsubscribe */
Unsubscribe(nameof(OnEntityDeath));
Unsubscribe(nameof(OnPlayerSleep));
Unsubscribe(nameof(OnPlayerSleepEnded));
Unsubscribe(nameof(OnItemUse));
Unsubscribe(nameof(OnEntityTakeDamage));
/* Init */
InitCommands();
}
void Unload()
{
/* Clear effects and UI */
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
effectManager.ClearAllEffects(player);
HideAllIndicators(player);
}
}
void OnServerInitialized(bool initial)
{
/* Load images (if ImageLibrary is installed) */
LoadImages();
/* Register perms */
permission.RegisterPermission(PermissionUse, this);
/* Init */
diseaseStats = new Dictionary<string, DiseaseStats>();
diseaseManager = new DiseaseManager();
effectManager = new EffectManager();
/* Load disease files */
diseaseManager.LoadAllDiseases(() =>
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
RefreshIndicator(player);
});
/* Unsubscribe */
Subscribe(nameof(OnEntityDeath));
Subscribe(nameof(OnPlayerSleep));
Subscribe(nameof(OnPlayerSleepEnded));
Subscribe(nameof(OnItemUse));
Subscribe(nameof(OnEntityTakeDamage));
}
void OnEntityDeath(BasePlayer player, HitInfo info)
{
if (player.IsValid())
{
foreach (string diseasename in diseaseManager.GetPlayerInfections(player))
{
Disease disease = diseaseManager.GetDisease(diseasename);
if (disease != null)
{
bool killedByDisease = WasCauseOfDeath(player, info, disease);
if (killedByDisease)
{
diseaseStats[disease.name].playersKilled.count += 1;
if (config.BroadcastDeathMessages)
BasePlayer.activePlayerList.ToList().ForEach(x => x.ChatMessage(Lang("Death", player.UserIDString, player.displayName, Color(disease.name, config.DiseaseNameColor))));
}
if (debug)
PLUGIN.Puts("Died: " + player.displayName + " removing of " + disease.name);
diseaseStats[disease.name].activeInfected.count -= 1;
diseaseManager.RemoveInfected(player, disease);
Interface.CallHook("OnInfectedDeath", player, disease, killedByDisease);
}
}
RefreshIndicator(player);
}
}
object OnPlayerSleep(BasePlayer player)
{
if (player.IsValid())
{
foreach (string diseasename in diseaseManager.GetPlayerInfections(player))
{
diseaseStats[diseasename].sleepersInfected.count += 1;
diseaseStats[diseasename].activeInfected.count -= 1;
}
}
return null;
}
void OnPlayerSleepEnded(BasePlayer player)
{
if (debug)
PLUGIN.Puts("Sleep ended for " + player.displayName);
if (player.IsValid())
{
if (debug)
PLUGIN.Puts("Is valid: " + player.displayName);
foreach (string diseasename in diseaseManager.GetPlayerInfections(player))
{
Disease disease = diseaseManager.GetDisease(diseasename);
if (debug)
PLUGIN.Puts("Has active tick: " + diseaseManager.HasActiveTick(player, disease));
if (disease != null && diseaseManager.HasActiveTick(player, disease))
{
if (diseaseManager.HasImmunity(player, disease))
{
if (debug)
PLUGIN.Puts("Resuming recovery for " + player.displayName + " with " + disease.name);
DoRecoverTick(player, disease);
}
else
{
if (debug)
PLUGIN.Puts("Resuming infection for " + player.displayName + " with " + disease.name);
DoInfectedTick(player, disease);
}
diseaseStats[disease.name].sleepersInfected.count -= 1;
diseaseStats[disease.name].activeInfected.count += 1;
}
}
RefreshIndicator(player);
}
}
void OnItemUse(Item item, int amountToUse)
{
if (item == null) return;
BasePlayer player = item.GetOwnerPlayer();
if (!player.IsValid()) return;
foreach (Disease disease in diseaseManager.LoadedDiseases.Values)
{
CureItem ci = diseaseManager.ItemsThatCure.Get(item.info.shortname, disease.name);
if (ci != null && ci.cureChanceOnConsumption >= UnityEngine.Random.Range(0, 100))
{
RecoverPlayer(player, disease, () => {
diseaseStats[disease.name].timesCuredFromItem.count += 1;
});
}
InfectionItem ii = diseaseManager.ItemsThatInfect.Get(item.info.shortname, disease.name);
if (ii != null && ii.infectionChanceOnConsumption >= UnityEngine.Random.Range(0, 100))
{
InfectPlayer(player, disease, () =>
{
diseaseStats[disease.name].infectedFromItem.count += 1;
});
}
TreatmentItem ti = diseaseManager.ItemsThatTreat.Get(item.info.shortname, disease.name);
if (ti != null)
{
TreatPlayer(player, disease, ti.Value(), ti.treatmentDelay, () =>
{
diseaseStats[disease.name].timesTreatedFromItem.count += 1;
});
}
}
}
object OnEntityTakeDamage(BasePlayer player, HitInfo info)
{
if (!player.IsValid() || info == null || info.Initiator == null) return null;
foreach (Disease disease in diseaseManager.LoadedDiseases.Values)
{
if (debug)
Puts(disease.name);
SpreaderEntity se = diseaseManager.EntitiesThatInfect.Get(info.Initiator.ShortPrefabName, disease.name);
if (se != null && (se.shortPrefabName != "player" || !info.IsProjectile()) && se.infectionChanceOnHit >= UnityEngine.Random.Range(0, 100))
{
if (debug)
Puts("Should infect: " + player.displayName + " with " + disease.name);
InfectPlayer(player, disease, () =>
{
diseaseStats[disease.name].infectedFromEntity.count += 1;
});
}
}
return null;
}
#endregion
#region Helper Functions
private void LoadImages()
{
if (ImageLibrary != null && ImageLibrary.IsLoaded)
{
ImageLibrary.Call<bool>("AddImage", "http://qungz.photo.store.qq.com/qun-qungz/V51EtM0n1gKtTQ02BUws28QZuZ04JNg0/V5bCQA5NDk1MzMwMDLwQB5hXYkjJw!!/800?w5=1600&h5=1600&rf=viewer_421", "DiseaseIndicatorIcon", 0UL);
}
}
private void DoDiseaseTick(Disease disease)
{
if (disease.outbreakConditions.enabled)
{
timer.In(disease.outbreakConditions.timeInterval, () =>
{
/* Attempt outbreak */
Outbreak(disease);
/* Continue */
DoDiseaseTick(disease);
});
}
}
private void DoInfectedTick(BasePlayer player, Disease disease)
{
if (player.IsConnected && player.IsAlive() && player.IsValid() && !player.IsSleeping() && disease != null && diseaseManager.HasDisease(player, disease) && !diseaseManager.HasImmunity(player, disease))
{
/* Show symptoms */
if (debug)
Puts("Showing symptom for: " + player.displayName);
DoSymptomDamage(player, disease);
DoSymptomEffects(player, disease);
DoSymptomScreenEffects(player, disease);
/* Spread to other players */
foreach (BasePlayer entity in NearbyValidPlayers(player.transform.position, disease))
{
if (GetSpreadChance(entity, disease) >= UnityEngine.Random.Range(1, 100))
{
if (debug)
Puts("Spread " + disease.name + " from " + player.name + " to " + entity.displayName);
InfectPlayer(entity, disease, () =>
{
diseaseStats[disease.name].infectedFromSpreading.count += 1;
});
}
}
/* Continue timer */
int spreadTime = disease.SpreadTime();
timer.In(spreadTime, () =>
{
if (diseaseManager.UpdateInfectedTime(player, disease, spreadTime))
{
RecoverPlayer(player, disease);
}
else
{
DoInfectedTick(player, disease);
}
});
}
else
{
if (debug)
Puts("Stopped infection tick for: " + player.displayName);
}
}
private void DoRecoverTick(BasePlayer player, Disease disease)
{
if (player.IsConnected && player.IsAlive() && player.IsValid() && !player.IsSleeping())
{
diseaseManager.SetActiveTick(player, disease, true);
RefreshIndicator(player);
timer.In(disease.ImmunityTime(), () =>
{
if (player.IsConnected && player.IsAlive() && player.IsValid() && !player.IsSleeping())
{
CurePlayer(player, disease);
}
});
}
else
{
if (debug)
Puts("Stopped recovery tick for: " + player.displayName);
}
}
private List<BaseCombatEntity> NearbyValidPlayers(Vector3 position, Disease disease)
{
List<BaseCombatEntity> valid = new List<BaseCombatEntity>();
List<BasePlayer> nearby = new List<BasePlayer>();
Vis.Entities(position, disease.spreadDistance, nearby); foreach (BasePlayer entity in nearby)
{
if (diseaseManager.CanInfect(entity, disease))
{
valid.Add(entity);
}
}
return valid;
}
private void InfectPlayer(BasePlayer player, Disease disease, Action callback = null)
{
if (Interface.CallHook("OnPlayerInfected", player, disease) != null) return;
if (diseaseManager.AddInfected(player, disease))
{
if (debug)
Puts("Started tick for: " + player.displayName);
diseaseManager.SetActiveTick(player, disease, true);
DoInfectedTick(player, disease);
RefreshIndicator(player);
StatusMessage(player, disease, Lang("StatusInfected", player.UserIDString, Color(disease.name, config.DiseaseNameColor)));
diseaseStats[disease.name].activeInfected.count += 1;
diseaseStats[disease.name].totalInfected.count += 1; ;
callback?.Invoke();
}
}
private void RecoverPlayer(BasePlayer player, Disease disease, Action callback = null)
{
if (diseaseManager.HasDisease(player, disease) && diseaseManager.SetRecovery(player, disease))
{
if (debug)
Puts("Started recovery for: " + player.displayName);
diseaseManager.SetActiveTick(player, disease, true);
DoRecoverTick(player, disease);
RefreshIndicator(player);
StatusMessage(player, disease, Lang("StatusRecovered", player.UserIDString, Color(disease.name, config.DiseaseNameColor)));
callback?.Invoke();
}
}
private int Outbreak(Disease disease, int tries = 1)
{
if (Interface.CallHook("OnOutbreak", disease) != null) return 0;
int infected = 0;
if (debug)
Puts("Attempting outbreak for " + disease.name);
List<BasePlayer> activePlayerList = BasePlayer.activePlayerList.ToList().Where(p => diseaseManager.CanInfect(p, disease)).ToList();
if (debug)
Puts("Valid players: " + activePlayerList.Count);
if (activePlayerList.Count > 0)
{
List<BasePlayer> filteredList = activePlayerList.ToArray().ToList(); // Make a copy
foreach (StatFilter filter in disease.outbreakConditions.statFilters)
{
filteredList = filteredList.Where(p => CompareStat(p, filter.stat, filter.minValue, (x, y) => { return x >= y; }) && CompareStat(p, filter.stat, filter.maxValue, (x, y) => { return x <= y; })).ToList();
}
if (debug)
Puts("Filters players: " + filteredList.Count);
for (int i = 0; i < tries; i++)
{
if (filteredList.Count > 0)
{
BasePlayer randomPlayer = filteredList[UnityEngine.Random.Range(0, filteredList.Count - 1)];
if (disease.outbreakConditions.outbreakChance >= UnityEngine.Random.Range(0, 100))
{
InfectPlayer(randomPlayer, disease);
infected++;
filteredList.Remove(randomPlayer);
}
}
}
diseaseStats[disease.name].infectedFromOutbreak.count += infected;
}
diseaseStats[disease.name].numOutbreaks.count += 1; ;
if (infected > 0)
{
if (config.BroadcastOutbreaks)
BasePlayer.activePlayerList.ToList().ForEach(x => x.ChatMessage(Lang("StatusOutbreak", x.UserIDString, Color(disease.name, config.DiseaseNameColor))));
}
return infected;
}
private void CurePlayer(BasePlayer player, Disease disease, Action callback = null)
{
if (Interface.CallHook("OnPlayerCured", player, disease) != null) return;
if (diseaseManager.RemoveInfected(player, disease))
{
if (debug)
Puts("Cured: " + player.displayName + " of " + disease.name);
RefreshIndicator(player);
diseaseManager.SetActiveTick(player, disease, false);
StatusMessage(player, disease, Lang("StatusCured", player.UserIDString, Color(disease.name, config.DiseaseNameColor)));
diseaseStats[disease.name].activeInfected.count -= 1;
callback?.Invoke();
}
}
private void TreatPlayer(BasePlayer player, Disease disease, int amount, int delay, Action callback = null)
{
if (Interface.CallHook("OnPlayerTreated", player, disease) != null) return;
if (diseaseManager.HasDisease(player, disease) && !diseaseManager.HasTreatment(player, disease) && !diseaseManager.HasImmunity(player, disease))
{
if (debug)
Puts("Treated: " + player.displayName + " of " + disease.name + " for " + amount);
diseaseManager.SetTreatment(player, disease, true);
RefreshIndicator(player);
timer.In(delay, () =>
{
diseaseManager.SetTreatment(player, disease, false);
RefreshIndicator(player);
});
if (diseaseManager.UpdateInfectedTime(player, disease, amount))
{
diseaseManager.SetActiveTick(player, disease, true);
RecoverPlayer(player, disease);
}
StatusMessage(player, disease, Lang("StatusTreated", player.UserIDString, Color(disease.name, config.DiseaseNameColor)));
callback?.Invoke();
}
}
private void StatusMessage(BasePlayer player, Disease disease, string message)
{
if (config.ShowStatusMessages)
player.ChatMessage(message);
}
private void DoSymptomEffects(BasePlayer player, Disease disease)
{
foreach (SymptomEffect effect in disease.symptomEffects)
{
effectManager.PlayEffect(player, effect.shortPrefabName, effect.LocalOnly);
}
}
private void DoSymptomScreenEffects(BasePlayer player, Disease disease)
{
foreach (SymptomScreenEffect effect in disease.symptomScreenEffects)
{
effectManager.ShowScreenEffect(player, effect.shortPrefabName, effect.materialName, effect.opacity, effect.duration, effect.fadeOut);
}
}
private void DoSymptomDamage(BasePlayer player, Disease disease)
{
foreach (SymptomDamage damage in disease.damageValues)
{
float value = damage.Value();
switch (damage.stat)
{
case RustStat.health:
player.Hurt(value, Rust.DamageType.Poison);
break;
case RustStat.bleeding:
player.metabolism.ApplyChange(MetabolismAttribute.Type.Bleeding, value, 1);
break;
case RustStat.calories:
player.metabolism.ApplyChange(MetabolismAttribute.Type.Calories, -value, 1);
break;
case RustStat.hydration:
player.metabolism.ApplyChange(MetabolismAttribute.Type.Hydration, -value, 1);
break;
case RustStat.oxygen:
player.metabolism.oxygen.value -= value;
break;
case RustStat.radiation:
player.metabolism.ApplyChange(MetabolismAttribute.Type.Radiation, value, 1);
break;
case RustStat.temperature:
player.metabolism.temperature.value += value;
break;
case RustStat.poison:
player.metabolism.ApplyChange(MetabolismAttribute.Type.Poison, value, 1);
break;
}
}
}
private bool WasCauseOfDeath(BasePlayer player, HitInfo info, Disease disease)
{
if (!diseaseManager.HasDisease(player, disease))
return false;
Rust.DamageType cause = info.damageTypes.GetMajorityDamageType();
foreach (SymptomDamage damage in disease.damageValues)
if (cause == damage.GetDamageType())
return true;
return false;
}
private float GetSpreadChance(BasePlayer player, Disease disease)
{
foreach (Item item in player.inventory.containerWear.itemList)
{
if (config.FaceCoveringItems.Contains(item.info.shortname))
return disease.spreadChanceCovered;
}
return disease.spreadChanceUncovered;
}
private bool CompareStat(BasePlayer player, string statname, float value, Func<float, float, bool> comparison)
{
switch (statname)
{
case RustStat.health:
return comparison(player.health, value);
case RustStat.bleeding:
return comparison(player.metabolism.bleeding.value, value);
case RustStat.calories:
return comparison(player.metabolism.calories.value, value);
case RustStat.hydration:
return comparison(player.metabolism.hydration.value, value);
case RustStat.oxygen:
return comparison(player.metabolism.oxygen.value, value);
case RustStat.radiation:
return comparison(player.metabolism.radiation_level.value, value);
case RustStat.temperature:
return comparison(player.metabolism.temperature.value, value);
case RustStat.poison:
return comparison(player.metabolism.poison.value, value);
}
return false;
}
private string AsTitle(string str) => str.ToLower().TitleCase();
#endregion
#region Data Structures
class DoubleDictionary<TkeyA, TkeyB, Tvalue>
{
private Dictionary<TkeyA, Dictionary<TkeyB, Tvalue>> a2b;
private Dictionary<TkeyB, Dictionary<TkeyA, Tvalue>> b2a;
public DoubleDictionary()
{
a2b = new Dictionary<TkeyA, Dictionary<TkeyB, Tvalue>>();
b2a = new Dictionary<TkeyB, Dictionary<TkeyA, Tvalue>>();
}
public void Set(TkeyA keyA, TkeyB keyB, Tvalue value)
{
if (!a2b.ContainsKey(keyA))
a2b.Add(keyA, new Dictionary<TkeyB, Tvalue>());
if (!b2a.ContainsKey(keyB))
b2a.Add(keyB, new Dictionary<TkeyA, Tvalue>());
if (!a2b[keyA].ContainsKey(keyB))
a2b[keyA].Add(keyB, value);
else
a2b[keyA][keyB] = value;
if (!b2a[keyB].ContainsKey(keyA))
b2a[keyB].Add(keyA, value);
else
b2a[keyB][keyA] = value;
}
public Tvalue Get(TkeyA keyA, TkeyB keyB)
{
if (a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB))
return a2b[keyA][keyB];
return default(Tvalue);
}
public Dictionary<TkeyB, Tvalue> Get(TkeyA keyA)
{
if (a2b.ContainsKey(keyA))
return a2b[keyA];
return new Dictionary<TkeyB, Tvalue>();
}
public Dictionary<TkeyA, Tvalue> Get(TkeyB keyB)
{
if (b2a.ContainsKey(keyB))
return b2a[keyB];
return new Dictionary<TkeyA, Tvalue>();
}
public bool ContainsKey(TkeyA keyA, TkeyB keyB)
{
return a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB);
}
public void Delete(TkeyA keyA, TkeyB keyB)
{
if (a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB))
a2b[keyA].Remove(keyB);
if (b2a.ContainsKey(keyB) && b2a[keyB].ContainsKey(keyA))
b2a[keyB].Remove(keyA);
}
public void Delete(TkeyA keyA)
{
foreach (TkeyB keyB in b2a.Keys)
if (b2a[keyB].ContainsKey(keyA))
b2a[keyB].Remove(keyA);
if (a2b.ContainsKey(keyA))
a2b.Remove(keyA);
}
public void Delete(TkeyB keyB)
{
foreach (TkeyA keyA in a2b.Keys)
if (a2b[keyA].ContainsKey(keyB))
a2b[keyA].Remove(keyB);
if (b2a.ContainsKey(keyB))
b2a.Remove(keyB);
}
}
class LookupList<TOne, TTwo>
{
private Dictionary<TOne, List<TTwo>> a2b;
private Dictionary<TTwo, List<TOne>> b2a;
public LookupList()
{
a2b = new Dictionary<TOne, List<TTwo>>();
b2a = new Dictionary<TTwo, List<TOne>>();
}
public int Count()
{
return a2b.Count();
}
public void Add(TOne a, TTwo b)
{
if (!a2b.ContainsKey(a))
a2b.Add(a, new List<TTwo>());
if (!b2a.ContainsKey(b))
b2a.Add(b, new List<TOne>());
if (!a2b[a].Contains(b))
a2b[a].Add(b);
if (!b2a[b].Contains(a))
b2a[b].Add(a);
}
public void AddAll(TOne[] listA, TTwo b)
{
foreach (TOne a in listA)
Add(a, b);
}
public void AddAll(TTwo[] listB, TOne a)
{
foreach (TTwo b in listB)
Add(a, b);
}
public void Remove(TOne a)
{
TTwo[] depends = Get(a).ToArray();
foreach (TTwo b in depends)
Remove(a, b);
}
public void Remove(TTwo b)
{
TOne[] depends = Get(b).ToArray();
foreach (TOne a in depends)
Remove(a, b);
}
public void Remove(TOne a, TTwo b)
{
if (a2b.ContainsKey(a) && a2b[a].Contains(b))
{
a2b[a].Remove(b);
if (a2b[a].Count() <= 0)
a2b.Remove(a);
}
if (b2a.ContainsKey(b) && b2a[b].Contains(a))
{
b2a[b].Remove(a);
if (b2a[b].Count() <= 0)
b2a.Remove(b);
}
}
public List<TTwo> Get(TOne a)
{
if (a2b.ContainsKey(a))
return a2b[a];
return new List<TTwo>();
}
public List<TOne> Get(TTwo b)
{
if (b2a.ContainsKey(b))
return b2a[b];
return new List<TOne>();
}
public bool ContainsKey(TOne a)
{
return a2b.ContainsKey(a);
}
public bool ContainsKey(TTwo b)
{
return b2a.ContainsKey(b);
}
public bool Contains(TOne a, TTwo b)
{
return a2b.ContainsKey(a) && a2b[a].Contains(b);
}
public bool Contains(TTwo b, TOne a)
{
return b2a.ContainsKey(b) && b2a[b].Contains(a);
}
}
#endregion
#region Models
class RustStat
{
public const string health = "health";
public const string bleeding = "bleeding";
public const string calories = "calories";
public const string hydration = "hydration";
public const string oxygen = "oxygen";
public const string radiation = "radiation";
public const string temperature = "temperature";
public const string poison = "poison";
}
class SymptomEffect
{
[JsonProperty(PropertyName = "Asset path")]
public string shortPrefabName;
[JsonProperty(PropertyName = "Local only")]
public bool LocalOnly = false;
}
class SymptomScreenEffect
{
[JsonProperty(PropertyName = "Sprite asset path")]
public string shortPrefabName = "assets/content/textures/generic/fulltransparent.tga";
[JsonProperty(PropertyName = "Opacity (0-1.0)")]
public float opacity;
[JsonProperty(PropertyName = "Duration (seconds)")]
public float duration;
[JsonProperty(PropertyName = "Fade out (seconds)")]
public float fadeOut;
[JsonProperty(PropertyName = "Material asset path (optional)")]
public string materialName = "";
}
class SpreaderEntity
{
[JsonProperty(PropertyName = "Short prefab name")]
public string shortPrefabName;
[JsonProperty(PropertyName = "Infection chance on hit (0-100)")]
public float infectionChanceOnHit;
}
class InfectionItem : ItemPrefab
{
[JsonProperty(PropertyName = "Infection chance on consumption (0-100)")]
public float infectionChanceOnConsumption;
}
class TreatmentItem : ItemPrefab
{
[JsonProperty(PropertyName = "Min infection time decreased (seconds)")]
public int minTimeDecrease;
[JsonProperty(PropertyName = "Max infection time decreased (seconds)")]
public int maxTimeDecrease;
[JsonProperty(PropertyName = "Delay between reusing treament (seconds)")]
public int treatmentDelay;
public int Value() => UnityEngine.Random.Range(minTimeDecrease, maxTimeDecrease);
}
class CureItem : ItemPrefab
{
[JsonProperty(PropertyName = "Cure chance on consumption (0-100)")]
public float cureChanceOnConsumption;
}
abstract class ItemPrefab
{
[JsonProperty(PropertyName = "Short prefab name")]
public string shortPrefabName;
}
class SymptomDamage
{
[JsonProperty(PropertyName = "Stat name")]
public string stat;
[JsonProperty(PropertyName = "Min damage")]
public float minValue;
[JsonProperty(PropertyName = "Max damage")]
public float maxValue;
public float Value() => UnityEngine.Random.Range(minValue, maxValue);
public Rust.DamageType GetDamageType()
{
switch (stat)
{
case "health":
return Rust.DamageType.Poison;
case "bleeding":
return Rust.DamageType.Bleeding;
case "calories":
return Rust.DamageType.Hunger;
case "hydration":
return Rust.DamageType.Thirst;
case "oxygen":
return Rust.DamageType.Drowned;
case "radiation":
return Rust.DamageType.Radiation;
case "temperature":
return Rust.DamageType.Cold;
case "poison":
return Rust.DamageType.Poison;
default:
return Rust.DamageType.LAST;
}
}
}
class StatFilter
{
[JsonProperty(PropertyName = "Stat name")]
public string stat;
[JsonProperty(PropertyName = "Min value")]
public float minValue;
[JsonProperty(PropertyName = "Max value")]
public float maxValue;
}
class OutbreakCondition
{
[JsonProperty(PropertyName = "Outbreaks enabled")]
public bool enabled;
[JsonProperty(PropertyName = "Outbreak chance (0-100)")]
public float outbreakChance;
[JsonProperty(PropertyName = "Time interval (seconds)")]
public int timeInterval;
[JsonProperty(PropertyName = "Only outbreak on players with the following stats")]
public StatFilter[] statFilters;
}
class DiseaseStats
{
public class DiseaseStat
{
public string name;
public int count;
}
public DiseaseStat activeInfected = new DiseaseStat { name = "Active players infected", count = 0 };
public DiseaseStat sleepersInfected = new DiseaseStat { name = "Sleeping players infected", count = 0 };
public DiseaseStat totalInfected = new DiseaseStat { name = "Total players infected", count = 0 };
public DiseaseStat playersKilled = new DiseaseStat { name = "Total players killed", count = 0 };
public DiseaseStat numOutbreaks = new DiseaseStat { name = "Number of outbreaks", count = 0 };
public DiseaseStat infectedFromSpreading = new DiseaseStat { name = "Players infected from spreading", count = 0 };
public DiseaseStat infectedFromEntity = new DiseaseStat { name = "Players infected from entities", count = 0 };
public DiseaseStat infectedFromItem = new DiseaseStat { name = "Players infected from items", count = 0 };
public DiseaseStat infectedFromOutbreak = new DiseaseStat { name = "Players infected from outbreaks", count = 0 };
public DiseaseStat infectedFromCommand = new DiseaseStat { name = "Players infected from commands", count = 0 };
public DiseaseStat timesTreatedFromItem = new DiseaseStat { name = "Times treated by items", count = 0 };
public DiseaseStat timesCuredFromItem = new DiseaseStat { name = "Times cured by items", count = 0 };
}
#endregion
#region Classes
class Disease
{
[JsonProperty(PropertyName = "Disease name")]
public string name { get; set; } = "";
[JsonProperty(PropertyName = "Description")]
public string info { get; set; } = "No information on this disease.";
[JsonProperty(PropertyName = "Min time immune after recovery (seconds)")]
public int minImmunityTime { get; set; } = 0;
[JsonProperty(PropertyName = "Max time immune after recovery (seconds)")]
public int maxImmunityTime { get; set; } = 0;
[JsonProperty(PropertyName = "Min time infected (seconds)")]
public int minInfectionTime { get; set; } = 0;
[JsonProperty(PropertyName = "Max time infected (seconds)")]
public int maxInfectionTime { get; set; } = 0;
[JsonProperty(PropertyName = "Min time between symptoms (seconds)")]
public int minSpreadTime { get; set; } = 0;
[JsonProperty(PropertyName = "Max time between symptoms (seconds)")]
public int maxSpreadTime { get; set; } = 0;
[JsonProperty(PropertyName = "Spread distance (4.0 = 1 foundation)")]
public float spreadDistance { get; set; } = 0;
[JsonProperty(PropertyName = "Spread chance with mask (0-100)")]
public float spreadChanceCovered { get; set; } = 0;
[JsonProperty(PropertyName = "Spread chance without mask (0-100)")]
public float spreadChanceUncovered { get; set; } = 0;
[JsonProperty(PropertyName = "Symptom damage effects")]
public SymptomDamage[] damageValues { get; set; } = new SymptomDamage[] { };
[JsonProperty(PropertyName = "Items that cause infection on consumption")]
public InfectionItem[] infectionItems { get; set; } = new InfectionItem[] { };
[JsonProperty(PropertyName = "Items that cure on consumption")]
public CureItem[] cureItems { get; set; } = new CureItem[] { };
[JsonProperty(PropertyName = "Items that reduce infection time on consumption")]
public TreatmentItem[] treatmentItems { get; set; } = new TreatmentItem[] { };
[JsonProperty(PropertyName = "Entities that cause infection on hit")]
public SpreaderEntity[] spreaderEntities { get; set; } = new SpreaderEntity[] { };
[JsonProperty(PropertyName = "Random outbreak settings")]
public OutbreakCondition outbreakConditions { get; set; } = new OutbreakCondition
{
enabled = false,
outbreakChance = 0,
timeInterval = 300,
statFilters = new StatFilter[] { }
};
[JsonProperty(PropertyName = "Symptom effects")]
public SymptomEffect[] symptomEffects { get; set; } = new SymptomEffect[] { };
[JsonProperty(PropertyName = "Symptom screen effects")]
public SymptomScreenEffect[] symptomScreenEffects { get; set; } = new SymptomScreenEffect[] { };
[JsonProperty(PropertyName = "Version")]
public VersionNumber version { get; set; } = new VersionNumber(0, 0, 0);
public int SpreadTime() => UnityEngine.Random.Range(minSpreadTime, maxSpreadTime);
public int InfectedTime() => UnityEngine.Random.Range(minInfectionTime, maxInfectionTime);
public int ImmunityTime() => UnityEngine.Random.Range(minImmunityTime, maxImmunityTime);
#region File IO
public static Disease GenerateDefault()
{
Disease disease = new Disease
{
name = "感冒",
info = "去雪地一定要穿的厚一点哦!",
minImmunityTime = 0,
maxImmunityTime = 0,
minInfectionTime = 180,
maxInfectionTime = 300,
minSpreadTime = 10,
maxSpreadTime = 20,
spreadDistance = 8f,
spreadChanceCovered = 1,
spreadChanceUncovered = 30,
damageValues = new SymptomDamage[]
{
new SymptomDamage { stat=RustStat.health , minValue=1f, maxValue=5f},
new SymptomDamage { stat=RustStat.calories , minValue=3f, maxValue=5f},
new SymptomDamage { stat=RustStat.hydration , minValue=3f, maxValue=5f},
new SymptomDamage { stat=RustStat.oxygen , minValue=0.2f, maxValue=0.5f},
new SymptomDamage { stat=RustStat.radiation , minValue=-8f, maxValue=-12f}
},
infectionItems = new InfectionItem[]
{
},
cureItems = new CureItem[]
{
new CureItem { shortPrefabName="healingtea", cureChanceOnConsumption=10f },
new CureItem { shortPrefabName="healingtea.advanced", cureChanceOnConsumption=25f },
new CureItem { shortPrefabName="healingtea.pure", cureChanceOnConsumption=100f }
},
treatmentItems = new TreatmentItem[]
{
new TreatmentItem { shortPrefabName="bandage", minTimeDecrease=1, maxTimeDecrease=10, treatmentDelay=20 },
new TreatmentItem { shortPrefabName="syringe.medical", minTimeDecrease=10, maxTimeDecrease=20, treatmentDelay=1 },
new TreatmentItem { shortPrefabName="largemedkit", minTimeDecrease=15, maxTimeDecrease=30, treatmentDelay=20 },
new TreatmentItem { shortPrefabName="antiradpills", minTimeDecrease=10, maxTimeDecrease=30, treatmentDelay=1 }
},
spreaderEntities = new SpreaderEntity[]
{
},
outbreakConditions = new OutbreakCondition
{
enabled = true,
outbreakChance = 100f,
timeInterval = 60,
statFilters = new StatFilter[] {
new StatFilter { stat=RustStat.health, minValue=1, maxValue=100 }
}
},
symptomEffects = new SymptomEffect[]
{
new SymptomEffect { shortPrefabName="assets/bundled/prefabs/fx/player/drown.prefab" },
new SymptomEffect { shortPrefabName="assets/prefabs/weapons/cake/effects/strike_screenshake.prefab" },
},
symptomScreenEffects = new SymptomScreenEffect[]
{
new SymptomScreenEffect { shortPrefabName="assets/scenes/test/bradleylaunchtest/normaltexture.png", duration=0f, opacity=0f, fadeOut=0f }
},
version = PLUGIN.Version
};
return disease;
}
public static void SaveToFile(Disease disease)
{
Interface.Oxide.DataFileSystem.WriteObject("Diseases/" + disease.name, disease);
}
public static Disease ReadFromFile(string diseaseName)
{
try
{
Disease disease = Interface.Oxide.DataFileSystem.ReadObject<Disease>("Diseases/" + diseaseName);
if (disease.name == null)
disease.name = "null";
if (PLUGIN.AsTitle(diseaseName) != PLUGIN.AsTitle(disease.name))
PLUGIN.PrintWarning($"Disease file '{diseaseName}.json' does not match with disease name of '{disease.name}', the name '{diseaseName}' will be used instead.");
disease.name = PLUGIN.AsTitle(diseaseName);
if (disease.version.Major != PLUGIN.Version.Major || disease.version.Minor != PLUGIN.Version.Minor)
{
PLUGIN.PrintError($"The disease file '{disease.name}.json' is version {disease.version} but the plugin version is {PLUGIN.Version}. This disease cannot be loaded until it is updated.");
return null;
}
else if (disease.version.Patch != PLUGIN.Version.Patch)
{
PLUGIN.PrintWarning($"Consider updating the 'Version' property in '{diseaseName}.json' from {disease.version} to {PLUGIN.Version}.");
}
return disease;
}
catch (Newtonsoft.Json.JsonSerializationException)
{
PLUGIN.PrintError($"The disease file '{diseaseName}.json' contains a syntax error. Please check to make sure it matches the syntax in 'Norovirus.json'.");
}
catch (Exception)
{
PLUGIN.PrintError($"The disease file '{diseaseName}.json' failed to load properly.");
}
return null;
}
#endregion
}
#endregion
#region Manager
class EffectManager
{
public readonly Dictionary<ulong, List<string>> ActiveEffects;
private ulong idCount;
public EffectManager()
{
ActiveEffects = new Dictionary<ulong, List<string>>();
idCount = 0;
}
private void InitPlayer(ulong userid)
{
if (!ActiveEffects.ContainsKey(userid))
ActiveEffects.Add(userid, new List<string>());
}
private void AddEffect(ulong userid, string effectString)
{
InitPlayer(userid);
ActiveEffects[userid].Add(effectString + idCount);
idCount++;
}
private void RemoveEffect(ulong userid, string effectString)
{
InitPlayer(userid);
if (ActiveEffects[userid].Contains(effectString))
ActiveEffects[userid].Remove(effectString);
}
public void PlayEffect(BasePlayer player, string effectString, bool local)
{
var effect = new Effect(effectString, player, 0, Vector3.zero, Vector3.forward);
if (local)
EffectNetwork.Send(effect, player.net.connection);
else
EffectNetwork.Send(effect);
}
public void ClearAllEffects(BasePlayer player)
{
InitPlayer(player.userID);
foreach (string activeEffect in ActiveEffects[player.userID])
{
CuiHelper.DestroyUi(player, activeEffect);
RemoveEffect(player.userID, activeEffect);
}
}
public void ShowScreenEffect(BasePlayer player, string assetStringPath, string materialStringPath, float opacity = 1, float duration = 1, float fadeOut = 1)
{
CuiElementContainer container = new CuiElementContainer();
ulong thisId = idCount;
container.Add(new CuiElement
{
Name = assetStringPath + thisId,
Parent = "Hud",
FadeOut = fadeOut,
Components =
{
new CuiRawImageComponent {
Sprite = assetStringPath,
Material = materialStringPath,
Color = "1 1 1 " + opacity
},
new CuiRectTransformComponent
{
AnchorMin = "0 0",
AnchorMax = "1 1"
}
},
});
if (debug)
PLUGIN.Puts("Started screen effect for " + assetStringPath + thisId);
CuiHelper.AddUi(player, container);
AddEffect(player.userID, assetStringPath);
PLUGIN.timer.In(duration, () =>
{
CuiHelper.DestroyUi(player, assetStringPath + thisId);
if (debug)
PLUGIN.Puts("Cleared screen effect for " + assetStringPath + thisId);
RemoveEffect(player.userID, assetStringPath + thisId);
});
}
}
class DiseaseManager
{
public readonly LookupList<BasePlayer, string> InfectedPlayers; /* playerid, diseasename */
public readonly Dictionary<string, Disease> LoadedDiseases; /*diseasename, disease*/
private DoubleDictionary<ulong, string, int> InfectedTimes;
private DoubleDictionary<ulong, string, int> NextGoalTimes;
private DoubleDictionary<ulong, string, bool> IsImmune;
private DoubleDictionary<ulong, string, bool> IsTreated;
private DoubleDictionary<ulong, string, bool> ActiveTick;
private Dictionary<ulong, bool> SafeZone;
public readonly DoubleDictionary<string, string, CureItem> ItemsThatCure;
public readonly DoubleDictionary<string, string, InfectionItem> ItemsThatInfect;
public readonly DoubleDictionary<string, string, TreatmentItem> ItemsThatTreat;
public readonly DoubleDictionary<string, string, SpreaderEntity> EntitiesThatInfect;
public DiseaseManager()
{
InfectedPlayers = new LookupList<BasePlayer, string>();
LoadedDiseases = new Dictionary<string, Disease>();
InfectedTimes = new DoubleDictionary<ulong, string, int>();
NextGoalTimes = new DoubleDictionary<ulong, string, int>();
IsImmune = new DoubleDictionary<ulong, string, bool>();
IsTreated = new DoubleDictionary<ulong, string, bool>();
ActiveTick = new DoubleDictionary<ulong, string, bool>();
ItemsThatCure = new DoubleDictionary<string, string, CureItem>();
ItemsThatInfect = new DoubleDictionary<string, string, InfectionItem>();
ItemsThatTreat = new DoubleDictionary<string, string, TreatmentItem>();
EntitiesThatInfect = new DoubleDictionary<string, string, SpreaderEntity>();
}
public void LoadAllDiseases(Action callback = null)
{
List<string> files = new List<string>();
try
{
files = Interface.Oxide.DataFileSystem.GetFiles("Diseases/").ToList();
}
catch (Exception) {
PLUGIN.PrintError("Failed to read files from /Diseases directory");
};
/* Generate Default Disease */
if (PLUGIN.config.GenerateDefaultDisease)
{
Disease disease = Disease.GenerateDefault();
LoadDisease(disease);
Disease.SaveToFile(disease);
}
foreach (string filename in files)
{
string[] split = filename.Split('/');
string diseaseName = split[split.Length - 1].Replace(".json", "");
foreach (string nameInConfig in PLUGIN.config.DefaultLoadedDiseases)
{
if (PLUGIN.AsTitle(nameInConfig) == PLUGIN.AsTitle(diseaseName))
{
Disease disease = Disease.ReadFromFile(diseaseName);
if (disease != null)
{
LoadDisease(disease);
PLUGIN.Puts($"Loaded disease {disease.name}");
}
}
}
}
callback?.Invoke();
}
public void LoadDisease(Disease disease, Action callback = null)
{
if (!LoadedDiseases.ContainsKey(disease.name))
{
LoadedDiseases.Add(disease.name, disease);
LoadItems(disease);
LoadEntities(disease);
PLUGIN.diseaseStats.Add(disease.name, new DiseaseStats());
if (debug)
PLUGIN.Puts("Loaded " + disease.name);
callback?.Invoke();
}
}
public void UnloadDisease(string diseasename)
{
InfectedPlayers.Remove(diseasename);
InfectedTimes.Delete(diseasename);
NextGoalTimes.Delete(diseasename);
IsImmune.Delete(diseasename);
PLUGIN.diseaseStats.Remove(diseasename);
LoadedDiseases.Remove(diseasename);
if (debug)
PLUGIN.Puts("Unloaded " + diseasename);
}
public Disease GetDisease(string diseasename)
{
if (LoadedDiseases.ContainsKey(diseasename))
return LoadedDiseases[diseasename];
return null;
}
// Called when a player is to be infected with the given disease
public bool AddInfected(BasePlayer player, Disease disease)
{
if (CanInfect(player, disease))
{
InfectedPlayers.Add(player, disease.name);
InfectedTimes.Set(player.userID, disease.name, 0);
NextGoalTimes.Set(player.userID, disease.name, disease.InfectedTime());
IsImmune.Set(player.userID, disease.name, false);
if (debug)
PLUGIN.Puts("Infected: " + player.displayName + " with " + disease.name + " for " + NextGoalTimes.Get(player.userID, disease.name) + " seconds");
return true;
}
return false;
}
// Called when a player is to be no longer infected with the given disease
public bool RemoveInfected(BasePlayer player, Disease disease)
{
if (InfectedPlayers.ContainsKey(player))
{
InfectedPlayers.Remove(player, disease.name);
InfectedTimes.Delete(player.userID);
NextGoalTimes.Delete(player.userID);
IsImmune.Delete(player.userID);
if (debug)
PLUGIN.Puts("Uninfected: " + player.displayName + " from " + disease.name);
return true;
}
return false;
}
public bool RemoveAllInfected(string diseasename)
{
if (InfectedPlayers.ContainsKey(diseasename))
{
InfectedPlayers.Remove(diseasename);
if (debug)
PLUGIN.Puts("Uninfected all of: " + diseasename);
return true;
}
return false;
}
// Returns an iterable copy of all players infected by the disease
public BasePlayer[] GetInfectedList(string diseasename)
{
return InfectedPlayers.Get(diseasename).ToArray();
}
// Returns an iterable copy of all diseases a player has
public string[] GetPlayerInfections(BasePlayer player)
{
return InfectedPlayers.Get(player).ToArray();
}
public void SetActiveTick(BasePlayer player, Disease disease, bool value)
{
ActiveTick.Set(player.userID, disease.name, value);
}
public bool HasActiveTick(BasePlayer player, Disease disease)
{
if (ActiveTick.ContainsKey(player.userID, disease.name))
return ActiveTick.Get(player.userID, disease.name);
return false;
}
public bool CanInfect(BasePlayer player, Disease disease)
{
return player.IsValid() && player.IsConnected && PLUGIN.permission.UserHasPermission(player.UserIDString, PermissionUse) && !HasDisease(player, disease) && !HasImmunity(player, disease) && InfectedPlayers.Count() < PLUGIN.config.MaxInfectedEntities && !(player.InSafeZone() && PLUGIN.config.SafezoneInfectionSpread);
}
public bool HasDisease(BasePlayer player, Disease disease)
{
return InfectedPlayers.Contains(player, disease.name);
}
public bool HasImmunity(BasePlayer player, Disease disease)
{
return IsImmune.ContainsKey(player.userID, disease.name) && IsImmune.Get(player.userID, disease.name);
}
public void SetTreatment(BasePlayer player, Disease disease, bool value)
{
IsTreated.Set(player.userID, disease.name, value);
}
public bool HasTreatment(BasePlayer player, Disease disease)
{
return IsTreated.ContainsKey(player.userID, disease.name) && IsTreated.Get(player.userID, disease.name);
}
// Modifies the infected time for a user/disease combo with the modifier, returns true if goal is reached
public bool UpdateInfectedTime(BasePlayer player, Disease disease, int modifier)
{
if (HasImmunity(player, disease)) return true;
if (InfectedTimes.ContainsKey(player.userID, disease.name) && NextGoalTimes.ContainsKey(player.userID, disease.name) && LoadedDiseases.ContainsKey(disease.name))
{
InfectedTimes.Set(player.userID, disease.name, InfectedTimes.Get(player.userID, disease.name) + modifier);
return InfectedTimes.Get(player.userID, disease.name) >= NextGoalTimes.Get(player.userID, disease.name);
}
return false;
}
public bool SetRecovery(BasePlayer player, Disease disease)
{
if (!HasImmunity(player, disease))
{
InfectedTimes.Set(player.userID, disease.name, 0);
IsImmune.Set(player.userID, disease.name, true);
return true;
}
return false;
}
private void LoadItems(Disease disease)
{
foreach (CureItem item in disease.cureItems)
ItemsThatCure.Set(item.shortPrefabName, disease.name, item);
foreach (InfectionItem item in disease.infectionItems)
ItemsThatInfect.Set(item.shortPrefabName, disease.name, item);
foreach (TreatmentItem item in disease.treatmentItems)
ItemsThatTreat.Set(item.shortPrefabName, disease.name, item);
}
private void LoadEntities(Disease disease)
{
foreach (SpreaderEntity entity in disease.spreaderEntities)
{
if (debug)
PLUGIN.Puts("Set " + entity.shortPrefabName + " " + disease.name);
EntitiesThatInfect.Set(entity.shortPrefabName, disease.name, entity);
}
}
}
#endregion
#region Commands
private Dictionary<string, ChatCmd> commands = new Dictionary<string, ChatCmd>();
void InitCommands()
{
commands.Add("help", new ChatCmd
{
perms = new List<string>() { PermissionUse },
function = (IPlayer player, string command, string[] args) => { cmd_help(player, command, args); }
});
commands.Add("infect", new ChatCmd
{
usages = new List<string>() { "<player_name> <disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_infect(player, command, args); }
});
commands.Add("cure", new ChatCmd
{
usages = new List<string>() { "<player_name> <disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_cure(player, command, args); }
});
commands.Add("outbreak", new ChatCmd
{
usages = new List<string>() { "<player_name> <disease_name>", "<player_name> <disease_name> <number>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_outbreak(player, command, args); }
});
commands.Add("eradicate", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_eradicate(player, command, args); }
});
commands.Add("list", new ChatCmd
{
perms = new List<string>() { PermissionUse, PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_list(player, command, args); }
});
commands.Add("info", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionUse, PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_info(player, command, args); }
});
commands.Add("stats", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionUse, PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_stats(player, command, args); }
});
commands.Add("config", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_config(player, command, args); }
});
commands.Add("load", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_load(player, command, args); }
});
commands.Add("unload", new ChatCmd
{
usages = new List<string>() { "<disease_name>" },
perms = new List<string>() { PermissionAdmin },
function = (IPlayer player, string command, string[] args) => { cmd_unload(player, command, args); }
});
}
class ChatCmd
{
public string prefix = "";
public List<string> usages = new List<string>();
public List<string> perms = new List<string>();
public Action<IPlayer, string, string[]> function;
public bool HasPerms(string id)
{
foreach (string perm in perms)
if (PLUGIN.permission.UserHasPermission(id, perm))
return true;
return false;
}
public string Usage(string prefix, string usg)
{
prefix = PLUGIN.Color(prefix, "orange");
usg = PLUGIN.Color(usg, "#00ffff");
return $"{prefix} {usg}";
}
}
[Command("disease")]
private void cmd_disease(IPlayer player, string command, string[] args)
{
if (args.Length == 0)
{
/* Help command */
}
if (args.Length >= 1)
{
string prefix = args[0];
if (commands.ContainsKey(prefix))
{
args = args.Skip(1).ToArray();
ChatCmd cmd = commands[prefix];
if (cmd.HasPerms(player.Id))
{
try
{
commands[prefix].function(player, command, args);
return;
}
catch { }
}
}
}
player.Reply(Lang("Invalid", player.Id));
}
[Command("disease.help"), Permission(PermissionAdmin)]
private void cmd_help(IPlayer player, string command, string[] args)
{
string size = "16";
string cmdList = Size(Color("Diseases", "green"), size) + "\n";
foreach (string prefix in commands.Keys)
{
ChatCmd cmd = commands[prefix];
if (cmd.HasPerms(player.Id))
{
foreach (string usg in cmd.usages)
{
cmdList += Color($"/disease {cmd.Usage(prefix, usg)}\n", "yellow");
}
}
}
player.Reply(cmdList);
}
[Command("infect"), Permission(PermissionAdmin)]
private void cmd_infect(IPlayer player, string command, string[] args)
{
string playerName = args[0];
string diseaseName = AsTitle(args[1]);
BasePlayer target = BasePlayer.Find(playerName);
Disease disease = diseaseManager.GetDisease(diseaseName);
if (!target.IsValid())
{
player.Reply(Lang("NoPlayer", player.Id, playerName));
}
else if (disease == null)
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
else
{
if (diseaseManager.CanInfect(target, disease))
{
InfectPlayer(target, disease, () =>
{
diseaseStats[disease.name].infectedFromCommand.count += 1; ;
});
player.Reply(Lang("Infect", player.Id, target.displayName, disease.name));
}
else
{
player.Reply(Lang("NoInfect", player.Id, target.displayName, disease.name));
}
}
}
[Command("cure"), Permission(PermissionAdmin)]
private void cmd_cure(IPlayer player, string command, string[] args)
{
string playerName = args[0];
string diseaseName = AsTitle(args[1]);
BasePlayer target = BasePlayer.Find(playerName);
Disease disease = diseaseManager.GetDisease(diseaseName);
if (!target.IsValid())
{
player.Reply(Lang("NoPlayer", player.Id, playerName));
}
else if (disease == null)
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
else
{
if (diseaseManager.HasDisease(target, disease))
{
CurePlayer(target, disease);
player.Reply(Lang("Cure", player.Id, target.displayName, disease.name));
}
else
{
player.Reply(Lang("NoCure", player.Id, target.displayName, disease.name));
}
}
}
[Command("outbreak"), Permission(PermissionAdmin)]
private void cmd_outbreak(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
int tries = args.Length >= 2 ? int.Parse(args[1]) : 1;
Disease disease = diseaseManager.GetDisease(diseaseName);
if (disease == null)
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
else
{
int infected = Outbreak(disease, tries);
player.Reply(Lang("Outbreak", player.Id, disease.name, infected));
}
}
[Command("eradicate"), Permission(PermissionAdmin)]
private void cmd_eradicate(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
Disease disease = diseaseManager.GetDisease(diseaseName);
if (disease == null)
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
else if (diseaseManager.RemoveAllInfected(diseaseName))
{
player.Reply(Lang("Eradicate", player.Id, disease.name));
}
else
{
player.Reply(Lang("NoEradicate", player.Id, disease.name));
}
}
[Command("disease.load"), Permission(PermissionAdmin)]
private void cmd_load(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
if (!diseaseManager.LoadedDiseases.ContainsKey(diseaseName))
{
Disease disease = Disease.ReadFromFile(diseaseName);
if (disease != null)
{
diseaseManager.LoadDisease(disease, () =>
{
player.Reply(Lang("Load", player.Id, disease.name));
});
}
return;
}
player.Reply(Lang("NoLoad", player.Id, diseaseName));
}
[Command("disease.unload"), Permission(PermissionAdmin)]
private void cmd_unload(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
if (diseaseManager.LoadedDiseases.ContainsKey(diseaseName))
{
diseaseManager.UnloadDisease(diseaseName);
player.Reply(Lang("Unload", player.Id, diseaseName));
return;
}
player.Reply(Lang("NoUnload", player.Id, diseaseName));
}
[Command("disease.list"), Permission(PermissionAdmin)]
private void cmd_list(IPlayer player, string command, string[] args)
{
player.Reply(Lang("List", player.Id, diseaseManager.LoadedDiseases.Keys.ToSentence()));
}
[Command("disease.info"), Permission(PermissionAdmin)]
private void cmd_info(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
if (diseaseManager.LoadedDiseases.ContainsKey(diseaseName))
{
Disease disease = diseaseManager.GetDisease(diseaseName);
player.Reply($"{Color(disease.name, config.DiseaseNameColor)}: {disease.info}");
return;
}
else
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
}
[Command("disease.config"), Permission(PermissionAdmin)]
private void cmd_config(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
if (diseaseManager.LoadedDiseases.ContainsKey(diseaseName))
{
Disease disease = diseaseManager.GetDisease(diseaseName);
var jsonString = JsonConvert.SerializeObject(
disease, Formatting.Indented,
new JsonConverter[] { new StringEnumConverter() });
player.Reply(jsonString);
}
else
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
}
[Command("disease.stats"), Permission(PermissionAdmin)]
private void cmd_stats(IPlayer player, string command, string[] args)
{
string diseaseName = AsTitle(args[0]);
if (diseaseManager.LoadedDiseases.ContainsKey(diseaseName))
{
DiseaseStats stats = diseaseStats[diseaseName];
string entry = "{0}: " + Color("{1}", "yellow") + "\n";
string message = $"{Color(diseaseName, config.DiseaseNameColor)}:\n";
message += string.Format(entry, stats.activeInfected.name, stats.activeInfected.count);
message += string.Format(entry, stats.sleepersInfected.name, stats.sleepersInfected.count);
message += string.Format(entry, stats.totalInfected.name, stats.totalInfected.count);
message += string.Format(entry, stats.playersKilled.name, stats.playersKilled.count);
message += string.Format(entry, stats.numOutbreaks.name, stats.numOutbreaks.count);
message += string.Format(entry, stats.infectedFromSpreading.name, stats.infectedFromSpreading.count);
message += string.Format(entry, stats.infectedFromEntity.name, stats.infectedFromEntity.count);
message += string.Format(entry, stats.infectedFromItem.name, stats.infectedFromItem.count);
message += string.Format(entry, stats.infectedFromOutbreak.name, stats.infectedFromOutbreak.count);
message += string.Format(entry, stats.infectedFromCommand.name, stats.infectedFromCommand.count);
message += string.Format(entry, stats.timesTreatedFromItem.name, stats.timesTreatedFromItem.count);
message += string.Format(entry, stats.timesCuredFromItem.name, stats.timesCuredFromItem.count);
player.Reply(message);
return;
}
else
{
player.Reply(Lang("NoExist", player.Id, diseaseName));
}
}
#endregion
#region Configuration
private Configuration config;
private class Configuration
{
[JsonProperty(PropertyName = "Generate default disease (true/false)")]
public bool GenerateDefaultDisease = true;
[JsonProperty(PropertyName = "Loaded diseases on startup")]
public string[] DefaultLoadedDiseases { get; set; } = {
"Norovirus",
};
[JsonProperty(PropertyName = "Max number of infected entities")]
public int MaxInfectedEntities { get; set; } = 100;
[JsonProperty(PropertyName = "Disease name color in messages")]
public string DiseaseNameColor { get; set; } = "green";
[JsonProperty(PropertyName = "Face covering items")]
public string[] FaceCoveringItems { get; set; } = {
"mask.bandana",
"burlap.headwrap",
"clatter.helmet",
"coffeecan.helmet",
"heavy.plate.helmet",
"hazmatsuit",
"hazmatsuit.spacesuit",
"metal.facemask",
"halloween.surgeonsuit"
};
[JsonProperty(PropertyName = "Show status chat messages")]
public bool ShowStatusMessages { get; set; } = true;
[JsonProperty(PropertyName = "Infections can spread in safe zones")]
public bool SafezoneInfectionSpread { get; set; } = true;
[JsonProperty(PropertyName = "Broadcast disease death messages")]
public bool BroadcastDeathMessages { get; set; } = false;
[JsonProperty(PropertyName = "Broadcast outbreaks")]
public bool BroadcastOutbreaks { get; set; } = false;
[JsonProperty(PropertyName = "HUD indicator list")]
public PositionUI IndicatorHUD { get; set; } = new PositionUI { AnchorMin = "0.9 0.6", AnchorMax = "0.985 0.9", EntryHeight = 0.1f, ImgAnchorMin = "0.04 0.1", ImgAnchorMax = "0.22 0.85", ImgShow = true };
}
private class PositionUI
{
[JsonProperty(PropertyName = "Anchor min")]
public string AnchorMin;
[JsonProperty(PropertyName = "Anchor max")]
public string AnchorMax;
[JsonProperty(PropertyName = "Entry height")]
public float EntryHeight;
[JsonProperty(PropertyName = "Anchor min (image)")]
public string ImgAnchorMin;
[JsonProperty(PropertyName = "Anchor max (image)")]
public string ImgAnchorMax;
[JsonProperty(PropertyName = "Show image (requires ImageLibrary)")]
public bool ImgShow;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) throw new Exception();
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultConfig() => config = new Configuration();
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["StatusInfected"] = "You are infected with {0}",
["StatusRecovered"] = "You have recovered from {0}",
["StatusTreated"] = "You treated the {0} and will recover faster",
["StatusCured"] = "You are not longer suffering from {0}",
["StatusOutbreak"] = "An outbreak of {0} has started",
["Infect"] = "Infected {0} with {1}",
["NoInfect"] = "{0} is already infected with {1} or is immune",
["Cure"] = "Cured {0} of {1}",
["NoCure"] = "{0} is not infected with {0} or cannot be cured",
["Outbreak"] = "Outbreak of {0} infected {1} players",
["Eradicate"] = "Cured all players of {0}",
["NoEradicate"] = "No players are infected with {0}",
["Load"] = "Loaded disease {0}",
["NoLoad"] = "Failed to load disease {0}, it is either already loaded or file is invalid",
["Unload"] = "Unloaded disease {0}",
["NoUnload"] = "Failed to unload disease {0}, it is not currently loaded",
["List"] = "Loaded diseases: {0}",
["NoExist"] = "The disease {0} is not currently loaded or doesn't exist on this server",
["NoExist"] = "The disease {0} is not currently loaded or doesn't exist on this server",
["NoPlayer"] = "There is no active player with the name {0}",
["StatInfected"] = "Players infected: {0}",
["StatInfectedTotal"] = "Total players infected: {0}",
["StatKilled"] = "Total players killed: {0}",
["Death"] = "{0} died from {1}",
["Invalid"] = "Invalid command, try /disease help for a list of commands",
["Treated"] = "Treated"
}, this);
}
private string Lang(string key, string id = null, params object[] args) => string.Format(la mr01sam
I'm a bit confused at your request, you want temperature to be listed in items? You can already create a disease that is contracted by being exposed to cold temperatures, it can be done using the Random Outbreak settings in the disease configuration.
I tested random breakout settings, but I can't use them anyway. Does it need to update the code