C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
TODO:
- Automatically update configuration
- Remove.prefab from block names in config
- Add option for disabling decay entirely?
- Add control over individual blocks?
- Fix prefab changes from Rust update
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Oxide.Plugins
{
[Info("DecayControl", "Wulf/lukespragg", "2.0.0", ResourceId = 857)]
[Description("")]
class DecayControl : RustPlugin
{
// Do NOT edit this file, instead edit DecayControl.json in server/<identity>/oxide/config
Dictionary<string, int> damage = new Dictionary<string, int>();
int timespan;
DateTime lastUpdate = DateTime.Now;
List<string> blocks = new List<string>();
bool initialized;
// A list of all translateable texts
List<string> texts = new List<string>() {
"Twigs",
"Wood",
"Stone",
"Metal",
"TopTier",
"Barricade",
"Ladder",
"%GRADE% buildings decay by %DAMAGE% HP per %TIMESPAN% minutes.",
"%GRADE% buildings do not decay."
};
Dictionary<string, string> messages = new Dictionary<string, string>();
protected override void LoadDefaultConfig() {
var damage = new Dictionary<string, object>() {
{"Twigs" , 1}, // health: 5
{"Wood" , 0}, // health: 250
{"Stone" , 0}, // health: 500
{"Metal" , 0}, // health: 200
{"TopTier" , 0}, // health: 1000
{"Barricade", 0}, // health: 350, 400, 500
{"Ladder" , 0} // health: 50
};
Config["damage"] = damage;
Config["timespan"] = 288;
var blocks = new List<object>() {
"block.halfheight.prefab",
"block.halfheight.slanted.prefab",
"block.stair.lshape.prefab",
"block.stair.ushape.prefab",
"floor.prefab",
"floor.triangle.prefab",
"foundation.prefab",
"foundation.steps.prefab",
"foundation.triangle.prefab",
"gates.external.high.prefab",
//"pillar.prefab",
"roof.prefab",
"wall.prefab",
"wall.doorway.prefab",
//"door.hinged.prefab",
"wall.external.high.prefab",
"wall.external.high.stone.prefab",
"wall.low.prefab",
"wall.window.prefab",
"wall.window.bars.prefab"
};
Config["blocks"] = blocks;
var messages = new Dictionary<string, object>();
foreach (var text in texts) {
if (messages.ContainsKey(text))
Puts("{0}", "Duplicate translation string: " + text);
else
messages.Add(text, text);
}
Config["messages"] = messages;
}
void Init() {
if (!(ConVar.Decay.scale > 0f)) return;
ConVar.Decay.scale = 0f;
Puts("{0}", "Default decay has been disabled");
}
void OnServerInitialized() {
LoadConfig();
try {
var damageConfig = (Dictionary<string, object>)Config["damage"];
int val;
foreach (var cfg in damageConfig)
damage.Add(cfg.Key, (val = Convert.ToInt32(cfg.Value)) >= 0 ? val : 0);
timespan = Convert.ToInt32(Config["timespan"]);
if (timespan < 0)
timespan = 15;
var blocksConfig = (List<object>)Config["blocks"];
foreach (var cfg in blocksConfig)
blocks.Add(Convert.ToString(cfg));
initialized = true;
var customMessages = (Dictionary<string, object>)Config["messages"];
if (customMessages == null) return;
foreach (var pair in customMessages)
messages[pair.Key] = Convert.ToString(pair.Value);
} catch (Exception ex) {
PrintError("{0}", "Failed to load configuration file: " + ex.Message);
}
}
void OnTick() {
if (!initialized)
return;
var now = DateTime.Now;
if (lastUpdate > now.AddMinutes(-timespan))
return;
lastUpdate = now;
var blocksDecayed = 0;
var blocksDestroyed = 0;
var allBlocks = UnityEngine.Object.FindObjectsOfType<BuildingBlock>();
int amount;
foreach (var block in allBlocks.Where(block => !block.isDestroyed)) {
string grade;
string name;
try {
grade = block.grade.ToString();
name = block.blockDefinition.fullName.Substring(29); // foundation.prefab
} catch (Exception) {
continue;
}
if (!blocks.Contains(name))
continue;
if (!damage.TryGetValue(grade, out amount) || amount <= 0) continue;
++blocksDecayed;
if (!Decay(block, amount))
++blocksDestroyed;
}
var barricadesDecayed = 0;
var barricadesDestroyed = 0;
if (damage.TryGetValue("Barricade", out amount) && amount > 0)
{
var allBarricades = UnityEngine.Object.FindObjectsOfType<Barricade>();
foreach (var barricade in allBarricades.Where(barricade => !barricade.isDestroyed)) {
++barricadesDecayed;
if (!Decay(barricade, amount))
++barricadesDestroyed;
}
}
var laddersDecayed = 0;
var laddersDestroyed = 0;
if (damage.TryGetValue("Ladder", out amount) && amount > 0)
{
var allLadders = UnityEngine.Object.FindObjectsOfType<BaseCombatEntity>();
foreach (var ladder in allLadders.Where(ladder => !ladder.isDestroyed && ladder.LookupShortPrefabName().StartsWith("ladder"))) {
++laddersDecayed;
if (!Decay(ladder, amount))
++laddersDestroyed;
}
}
Puts("{0}", "Decayed " +
blocksDecayed + " blocks (" + blocksDestroyed + " destroyed), " +
barricadesDecayed + " barricades (" + barricadesDestroyed + " destroyed) and " +
laddersDecayed + " ladders (" + laddersDestroyed + " destroyed)"
);
}
void SendHelpText(BasePlayer player)
{
var sb = new StringBuilder();
foreach (var dmg in damage)
{
if (dmg.Value > 0)
sb.Append(" ").Append(_("%GRADE% buildings decay by %DAMAGE% HP per %TIMESPAN% minutes.", new Dictionary<string, string> {
{ "GRADE", _(dmg.Key) },
{ "DAMAGE", dmg.Value.ToString() },
{ "TIMESPAN", timespan.ToString() }
})).Append("\n");
else
sb.Append(" ").Append(_("%GRADE% buildings do not decay.", new Dictionary<string, string>() {
{ "GRADE", _(dmg.Key) }
})).Append("\n");
}
player.ChatMessage(sb.ToString().TrimEnd());
}
string _(string text, Dictionary<string, string> replacements = null)
{
if (messages.ContainsKey(text) && messages[text] != null)
text = messages[text];
if (replacements != null)
text = replacements.Aggregate(text, (current, replacement) => current.Replace("%" + replacement.Key + "%", replacement.Value));
return text;
}
static bool Decay(BaseCombatEntity entity, float amount)
{
entity.health -= amount;
entity.SendNetworkUpdate();
if (!(entity.health <= 0f)) return true;
entity.GetComponent<BaseEntity>().KillMessage();
return false;
}
}
}