C#:
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using Oxide.Core.Libraries;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using Facepunch;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("VehicleLoot", "https://topplugin.ru/", "1.0.0")]
internal class VehicleLoot : RustPlugin
{
#region Variables
private static bool Initialize = false;
private static System.Random Rnd = new System.Random();
private static LootContainer ToolContainer = null;
private static int SpawnCounter = 0;
private static List<bool> SpawnToolMap = new List<bool>();
private static Dictionary<string, List<string>> PartNames = new Dictionary<string, List<string>>()
{
{ "low", new List<string>()
{
"carburetor1",
"crankshaft1",
"piston1",
"sparkplug1",
"valve1"
}
},
{ "medium", new List<string>()
{
"carburetor2",
"crankshaft2",
"piston2",
"sparkplug2",
"valve2"
}
},
{ "high", new List<string>()
{
"carburetor3",
"crankshaft3",
"piston3",
"sparkplug3",
"valve3"
}
}
};
#endregion
#region Hooks
private void Init()
{
SpawnCounter = 0;
SpawnToolMap.Clear();
LoadVariables();
LoadData();
}
private void OnNewSave()
{
Data.Clear();
SaveData();
}
private void OnEntitySpawned(LootContainer loot)
{
if (!Initialize || loot == null) return;
ChangeLoot(loot);
}
private void OnServerInitialized()
{
Initialize = true;
var loots = BaseNetworkable.serverEntities.OfType<LootContainer>().ToList();
foreach(var loot in loots) ChangeLoot(loot);
}
private void OnServerSave() => SaveData();
private void Unload() => SaveData();
#endregion
#region Main
private void SuppressRefresh(LootContainer container)
{
container.minSecondsBetweenRefresh = -1;
container.maxSecondsBetweenRefresh = 0;
container.GetComponent<FacepunchBehaviour>().CancelInvoke(new Action(container.SpawnLoot));
}
private static void GenSpawnToolMap()
{
SpawnToolMap.Clear();
for (int ii = 0; ii < configData.CrateToolPercent; ii++)
SpawnToolMap.Add(true);
for (int ii = configData.CrateToolPercent; ii < 100; ii++)
SpawnToolMap.Add(false);
SpawnToolMap = SpawnToolMap.OrderBy(x=> Rnd.Next()).ToList();
}
private void ChangeLoot(LootContainer loot)
{
if (loot == null || !loot.ShortPrefabName.Contains("vehicle_parts") || Data.Contains(loot.net.ID)) return;
SuppressRefresh(loot);
if (SpawnCounter % 100 == 0)
GenSpawnToolMap();
SpawnCounter++;
// время спавнить содержимое ящика с инструментами
if (SpawnToolMap[SpawnCounter % 100])
{
for (int ii=loot.inventory.itemList.ToList().Count-1; ii>=0; ii--)
{
var item = loot.inventory.itemList[ii];
item.RemoveFromContainer();
item.Remove(0f);
}
// добавляем инструменты
var toolItems = GetToolItems();
foreach (var item in toolItems)
{
if (loot.inventory.capacity < loot.inventory.itemList.Count+1)
loot.inventory.capacity++;
item.MoveToContainer(loot.inventory, -1, true);
}
}
else // перезаполняем лут ящика с инструментами под улучшенный пак инструментов
{
// чистим все кроме скрапа
Item scrap = null;
for (int ii=loot.inventory.itemList.ToList().Count-1; ii>=0; ii--)
{
var item = loot.inventory.itemList[ii];
if (item.info.shortname == "scrap")
{
item.RemoveFromContainer();
scrap = item;
continue;
}
item.RemoveFromContainer();
item.Remove(0f);
}
// перемещаем скрап в первую позицию, иначе будет пустота в купе с финтом в конце loot.inventory.capacity = loot.inventory.itemList.Count();
if (scrap != null)
scrap.MoveToContainer(loot.inventory, -1, true);
// добавляем запчасти
int val = Rnd.Next(1, 101);
int comp = 0;
var type = "low";
foreach (var pair in configData.SpawnLimit.OrderBy(x=> x.Value))
{
if (val <= comp + pair.Value)
{
type = pair.Key;
break;
}
comp += pair.Value;
}
var part = configData.Parts.FirstOrDefault(x=> x.Type == type);
int amount = Rnd.Next(part.MinAmount, part.MaxAmount+1);
for (int ii = 0; ii < amount; ii++)
{
int condition = Rnd.Next(part.MinCondition, part.MaxCondition+1);
var itemName = (PartNames[type])[Rnd.Next(0, PartNames[type].Count)];
var item = ItemManager.CreateByName(itemName, 1);
item.condition = (item.maxCondition / 100f) * condition;
if (loot.inventory.capacity < loot.inventory.itemList.Count+1)
loot.inventory.capacity++;
item.MoveToContainer(loot.inventory, -1, true);
}
}
loot.inventory.capacity = loot.inventory.itemList.Count();
Data.Add(loot.net.ID);
}
private List<Item> GetToolItems()
{
if (ToolContainer == null)
{
var loot = GameManager.server.CreateEntity("assets/bundled/prefabs/radtown/crate_tools.prefab") as LootContainer;
loot.transform.position = new Vector3(0,-1f,0);
loot.enableSaving = false;
loot.Spawn();
loot.enableSaving = false;
ToolContainer = loot;
SuppressRefresh(loot);
PrintWarning("Заспавнен эталонный ящик с инструментами");
}
for (int ii=ToolContainer.inventory.itemList.ToList().Count-1; ii>=0; ii--)
{
var item = ToolContainer.inventory.itemList[ii];
item.RemoveFromContainer();
item.Remove(0f);
}
ToolContainer.PopulateLoot();
return ToolContainer.inventory.itemList.ToList();
}
#endregion
#region Command
[Oxide.Plugins.ChatCommand("vl.tp")]
private void TpCommand(BasePlayer player, string command, string[] args)
{
if (!player.IsAdmin) return;
var loots = BaseNetworkable.serverEntities.OfType<LootContainer>().Where(b => b.ShortPrefabName.Contains("vehicle_parts")).ToList();
if (loots == null || loots.Count == 0)
{
SendReply(player, "Ящики с запчастями не найдены!");
return;
}
player.Teleport(loots.GetRandom().transform.position);
}
#endregion
#region Config
private static ConfigData configData;
private class ConfigData
{
[JsonProperty(PropertyName = "Процент ящиков с запчастями, которые будут отданы под ящики с инструментами")]
public int CrateToolPercent;
[JsonProperty(PropertyName = "Шкала процентов, часть которой занимает группа запчастей (от 0 до 100)")]
public Dictionary<string, int> SpawnLimit;
[JsonProperty(PropertyName = "Запчасти для машин")]
public List<Part> Parts;
}
private class Part
{
[JsonProperty(PropertyName = "Группа запчастей (low, medium, high)")]
public string Type;
[JsonProperty(PropertyName = "Минимальная целостность запчасти, в процентах")]
public int MinCondition;
[JsonProperty(PropertyName = "Максимальная целостность запчасти, в процентах")]
public int MaxCondition;
[JsonProperty(PropertyName = "Минимальное количество запчастей")]
public int MinAmount;
[JsonProperty(PropertyName = "Максимальное количество запчастей")]
public int MaxAmount;
}
private void LoadVariables() => configData = Config.ReadObject<ConfigData>();
protected override void LoadDefaultConfig()
{
configData = new ConfigData
{
CrateToolPercent = 33,
SpawnLimit = new Dictionary<string, int>()
{
{ "low", 60 },
{ "medium", 30 },
{ "high", 10 }
},
Parts = new List<Part>()
{
new Part()
{
Type = "low",
MinCondition = 10,
MaxCondition = 90,
MinAmount = 2,
MaxAmount = 2
},
new Part()
{
Type = "medium",
MinCondition = 10,
MaxCondition = 70,
MinAmount = 1,
MaxAmount = 1
},
new Part()
{
Type = "high",
MinCondition = 10,
MaxCondition = 70,
MinAmount = 1,
MaxAmount = 1
}
}
};
SaveConfig(configData);
timer.Once(0.1f, ()=> SaveConfig(configData));
}
private void SaveConfig(ConfigData config) => Config.WriteObject(config, true);
#endregion
#region Data
private static HashSet<uint> Data = new HashSet<uint>();
private void LoadData() => Data = Interface.GetMod().DataFileSystem.ReadObject<HashSet<uint>>("VehicleLootData");
private static void SaveData() => Interface.GetMod().DataFileSystem.WriteObject("VehicleLootData", Data);
#endregion
}
}