C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using Oxide.Core.Plugins;
using UnityEngine;
using Rust;
namespace Oxide.Plugins {
[Info("RainOfFire", "emu / k1lly0u", "0.2.51", ResourceId = 1249)]
class RainOfFire : RustPlugin {
#region Fields
[PluginReference]
Plugin PopupNotifications;
private Timer EventTimer = null;
private List<Timer> RocketTimers = new List<Timer>();
private float launchHeight = 200f;
private float fireRocketChance = 0.05f;
private float launchStraightness = 2.0f;
private float projectileSpeed = 20f;
private float gravityModifier = 0f;
private float detonationTime = 20f;
#endregion
#region Oxide Hooks
void OnServerInitialized() {
lang.RegisterMessages(Messages, this);
LoadVariables();
StartEventTimer();
}
void Unload() {
StopTimer();
foreach (var t in RocketTimers) t.Destroy();
var objects = UnityEngine.Object.FindObjectsOfType<ItemCarrier>();
if (objects != null) foreach (var gameObj in objects) UnityEngine.Object.Destroy(gameObj);
}
#endregion
#region Functions
private void StartEventTimer() {
if (configData.Options.EnableAutomaticEvents) {
if (configData.Options.EventTimers.UseRandomTimer) {
var random = GetRandom(configData.Options.EventTimers.RandomTimerMin, configData.Options.EventTimers.RandomTimerMax);
EventTimer = timer.Once(random * 60, () => {
StartRandomOnMap();
StartEventTimer();
}
);
}
else EventTimer = timer.Repeat(configData.Options.EventTimers.EventInterval * 60, 0, () => StartRandomOnMap());
}
}
private void StopTimer() {
if (EventTimer != null) EventTimer.Destroy();
}
private void StartRandomOnMap() {
float mapsize = MapSize() - 600f;
float randomX = UnityEngine.Random.Range(-mapsize, mapsize);
float randomY = UnityEngine.Random.Range(-mapsize, mapsize);
Vector3 callAt = new Vector3(randomX, 0f, randomY);
StartRainOfFire(callAt, configData.z_IntensitySettings.Settings_Optimal);
}
private bool StartOnPlayer(string playerName, Settings setting) {
BasePlayer player = GetPlayerByName(playerName);
if (player == null) return false;
StartRainOfFire(player.transform.position, setting);
return true;
}
private void StartBarrage(Vector3 origin, Vector3 direction) => timer.Repeat(configData.BarrageSettings.RocketDelay, configData.BarrageSettings.NumberOfRockets, () => SpreadRocket(origin, direction));
private void StartRainOfFire(Vector3 origin, Settings setting) {
float radius = setting.Radius;
int numberOfRockets = setting.RocketAmount;
float duration = setting.Duration;
bool dropsItems = setting.ItemDropControl.EnableItemDrop;
ItemDrop[] itemDrops = setting.ItemDropControl.ItemsToDrop;
float intervals = duration / numberOfRockets;
if (configData.Options.NotifyEvent) {
if (PopupNotifications) PopupNotifications.Call("CreatePopupNotification", msg("incoming"));
else PrintToChat(msg("incoming"));
}
timer.Repeat(intervals, numberOfRockets, () => RandomRocket(origin, radius, setting));
}
private void RandomRocket(Vector3 origin, float radius, Settings setting) {
bool isFireRocket = false;
Vector2 rand = UnityEngine.Random.insideUnitCircle;
Vector3 offset = new Vector3(rand.x * radius, 0, rand.y * radius);
Vector3 direction = (Vector3.up * -launchStraightness + Vector3.right).normalized;
Vector3 launchPos = origin + offset - direction * launchHeight;
if (GetRandom(1, setting.FireRocketChance) == 1) isFireRocket = true;
BaseEntity rocket = CreateRocket(launchPos, direction, isFireRocket);
if (setting.ItemDropControl.EnableItemDrop) {
var comp = rocket.gameObject.AddComponent<ItemCarrier>();
comp.SetCarriedItems(setting.ItemDropControl.ItemsToDrop);
comp.SetDropMultiplier(configData.Options.GlobalDropMultiplier);
}
}
private void SpreadRocket(Vector3 origin, Vector3 direction) {
var barrageSpread = configData.BarrageSettings.RocketSpread;
direction = Quaternion.Euler(UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f), UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f), UnityEngine.Random.Range((float)(-(double)barrageSpread * 0.5), barrageSpread * 0.5f)) * direction;
CreateRocket(origin, direction, false);
}
private BaseEntity CreateRocket(Vector3 startPoint, Vector3 direction, bool isFireRocket) {
ItemDefinition projectileItem;
if (isFireRocket) projectileItem = GetFireRocket();
else projectileItem = GetRocket();
ItemModProjectile component = projectileItem.GetComponent<ItemModProjectile>();
BaseEntity entity = GameManager.server.CreateEntity(component.projectileObject.resourcePath, startPoint, new Quaternion(), true);
TimedExplosive timedExplosive = entity.GetComponent<TimedExplosive>();
ServerProjectile serverProjectile = entity.GetComponent<ServerProjectile>();
serverProjectile.gravityModifier = gravityModifier;
serverProjectile.speed = projectileSpeed;
timedExplosive.timerAmountMin = detonationTime;
timedExplosive.timerAmountMax = detonationTime;
ScaleAllDamage(timedExplosive.damageTypes, configData.DamageControl.DamageMultiplier);
entity.SendMessage("InitializeVelocity", (object)(direction * 1f));
entity.Spawn();
return entity;
}
private void ScaleAllDamage(List<DamageTypeEntry> damageTypes, float scale) {
for (int i = 0; i < damageTypes.Count; i++) {
damageTypes[i].amount *= scale;
}
}
#endregion
#region Config editing
private void SetIntervals(int intervals) {
StopTimer();
configData.Options.EventTimers.EventInterval = intervals;
SaveConfig(configData);
StartEventTimer();
}
private void SetDamageMult(float scale) {
configData.DamageControl.DamageMultiplier = scale;
SaveConfig(configData);
}
private void SetNotifyEvent(bool notify) {
configData.Options.NotifyEvent = notify;
SaveConfig(configData);
}
private void SetDropRate(float rate) {
configData.Options.GlobalDropMultiplier = rate;
SaveConfig(configData);
}
#endregion
#region Commands
[ChatCommand("rof")]
private void cmdROF(BasePlayer player, string command, string[] args) {
if (!player.IsAdmin || args.Length == 0) {
SendReply(player, msg("help1", player.UserIDString));
SendReply(player, msg("help2", player.UserIDString));
SendReply(player, msg("help3", player.UserIDString));
SendReply(player, msg("help4", player.UserIDString));
SendReply(player, msg("help5", player.UserIDString));
SendReply(player, msg("help6", player.UserIDString));
SendReply(player, msg("help7", player.UserIDString));
SendReply(player, msg("help8", player.UserIDString));
return;
}
switch (args[0].ToLower()) {
case "onplayer" : if (args.Length == 2) {
if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Optimal)) SendReply(player, string.Format(msg("calledOn", player.UserIDString), args[1]));
else SendReply(player, msg("noPlayer", player.UserIDString));
}
else {
StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Optimal);
SendReply(player, msg("onPos", player.UserIDString));
}
break;
case "onplayer_extreme" : if (args.Length == 2) {
if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Extreme)) SendReply(player, msg("Extreme", player.UserIDString) + string.Format(msg("calledOn", player.UserIDString), args[1]));
else SendReply(player, msg("noPlayer", player.UserIDString));
}
else {
StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Extreme);
SendReply(player, msg("Extreme", player.UserIDString) + msg("onPos", player.UserIDString));
}
break;
case "onplayer_mild" : if (args.Length == 2) {
if (StartOnPlayer(args[1], configData.z_IntensitySettings.Settings_Mild)) SendReply(player, msg("Mild", player.UserIDString) + string.Format(msg("calledOn", player.UserIDString), args[1]));
else SendReply(player, msg("noPlayer", player.UserIDString));
}
else {
StartRainOfFire(player.transform.position, configData.z_IntensitySettings.Settings_Mild);
SendReply(player, msg("Mild", player.UserIDString) + msg("onPos", player.UserIDString));
}
break;
case "barrage" : StartBarrage(player.eyes.position + player.eyes.HeadForward() * 1f, player.eyes.HeadForward());
break;
case "random" : StartRandomOnMap();
SendReply(player, msg("randomCall", player.UserIDString));
break;
case "intervals" : if (args.Length > 1) {
int newIntervals;
bool isValid;
isValid = int.TryParse(args[1], out newIntervals);
if (isValid) {
if (newIntervals >= 4 || newIntervals == 0) {
SetIntervals(newIntervals);
SendReply(player, string.Format(msg("interSet", player.UserIDString), newIntervals));
StopTimer();
StartEventTimer();
}
else {
SendReply(player, msg("smallInter", player.UserIDString));
}
}
else {
SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
}
}
break;
case "droprate" : if (args.Length > 1) {
float newDropMultiplier;
bool isValid;
isValid = float.TryParse(args[1], out newDropMultiplier);
if (isValid) {
SetDropRate(newDropMultiplier);
SendReply(player, msg("dropMulti", player.UserIDString) + newDropMultiplier);
}
else {
SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
}
}
break;
case "damagescale" : if (args.Length > 1) {
float newDamageMultiplier;
bool isValid;
isValid = float.TryParse(args[1], out newDamageMultiplier);
if (isValid) {
SetDamageMult(newDamageMultiplier);
SendReply(player, msg("damageMulti", player.UserIDString) + newDamageMultiplier);
}
else {
SendReply(player, string.Format(msg("invalidParam", player.UserIDString), args[1]));
}
}
break;
case "togglemsg" : if (configData.Options.NotifyEvent) {
SetNotifyEvent(false);
SendReply(player, msg("notifDeAct", player.UserIDString));
}
else {
SetNotifyEvent(true);
SendReply(player, msg("notifAct", player.UserIDString));
}
break;
default : SendReply(player, string.Format(msg("unknown", player.UserIDString), args[0]));
break;
}
}
[ConsoleCommand("rof.random")]
private void ccmdEventRandom(ConsoleSystem.Arg arg) {
if (!arg.IsAdmin) return;
StartRandomOnMap();
Puts("Random event started");
}
[ConsoleCommand("rof.onposition")]
private void ccmdEventOnPosition(ConsoleSystem.Arg arg) {
if (!arg.IsAdmin) return;
float x, z;
if (arg.Args.Length == 2 && float.TryParse(arg.Args[0], out x) && float.TryParse(arg.Args[1], out z)) {
var position = new Vector3(x, 0, z);
StartRainOfFire(GetGroundPosition(position), configData.z_IntensitySettings.Settings_Optimal);
Puts($"Random event started on position {x}, {position.y}, {z}");
}
else Puts("Usage: rof.onposition x z");
}
#endregion
#region Helpers
private BasePlayer GetPlayerByName(string name) {
string currentName;
string lastName;
BasePlayer foundPlayer = null;
name = name.ToLower();
foreach (BasePlayer player in BasePlayer.activePlayerList) {
currentName = player.displayName.ToLower();
if (currentName.Contains(name)) {
if (foundPlayer != null) {
lastName = foundPlayer.displayName;
if (currentName.Replace(name, "").Length < lastName.Replace(name, "").Length) {
foundPlayer = player;
}
}
foundPlayer = player;
}
}
return foundPlayer;
}
static int GetRandom(int min, int max) => UnityEngine.Random.Range(min, max);
private float MapSize() => TerrainMeta.Size.x / 2;
private ItemDefinition GetRocket() => ItemManager.FindItemDefinition("ammo.rocket.basic");
private ItemDefinition GetFireRocket() => ItemManager.FindItemDefinition("ammo.rocket.fire");
static Vector3 GetGroundPosition(Vector3 sourcePos) // credit Wulf & Nogrod
{
RaycastHit hitInfo;
if (Physics.Raycast(sourcePos, Vector3.down, out hitInfo, LayerMask.GetMask("Terrain", "World", "Construction"))) {
sourcePos.y = hitInfo.point.y;
}
sourcePos.y = Mathf.Max(sourcePos.y, TerrainMeta.HeightMap.GetHeight(sourcePos));
return sourcePos;
}
#endregion
#region Classes
class ItemCarrier : MonoBehaviour {
private ItemDrop[] carriedItems = null;
private float multiplier;
public void SetCarriedItems(ItemDrop[] carriedItems) => this.carriedItems = carriedItems;
public void SetDropMultiplier(float multiplier) => this.multiplier = multiplier;
private void OnDestroy() {
if (carriedItems == null) return;
int amount;
for (int i = 0; i < carriedItems.Length; i++) {
if ((amount = (int)(GetRandom(carriedItems[i].Minimum, carriedItems[i].Maximum) * multiplier)) > 0) ItemManager.CreateByName(carriedItems[i].Shortname, amount).Drop(gameObject.transform.position, Vector3.up);
}
}
}
class ItemDrop {
public string Shortname;
public int Minimum;
public int Maximum;
}
#endregion
#region Config
private ConfigData configData;
class Damage {
public float DamageMultiplier {
get;
set;
}
}
class Barrage {
public int NumberOfRockets {
get;
set;
}
public float RocketDelay {
get;
set;
}
public float RocketSpread {
get;
set;
}
}
class Drops {
public bool EnableItemDrop {
get;
set;
}
public ItemDrop[] ItemsToDrop {
get;
set;
}
}
class Options {
public bool EnableAutomaticEvents {
get;
set;
}
public Timers EventTimers {
get;
set;
}
public float GlobalDropMultiplier {
get;
set;
}
public bool NotifyEvent {
get;
set;
}
}
class Timers {
public int EventInterval {
get;
set;
}
public bool UseRandomTimer {
get;
set;
}
public int RandomTimerMin {
get;
set;
}
public int RandomTimerMax {
get;
set;
}
}
class Settings {
public int FireRocketChance {
get;
set;
}
public float Radius {
get;
set;
}
public int RocketAmount {
get;
set;
}
public int Duration {
get;
set;
}
public Drops ItemDropControl {
get;
set;
}
}
class Intensity {
public Settings Settings_Mild {
get;
set;
}
public Settings Settings_Optimal {
get;
set;
}
public Settings Settings_Extreme {
get;
set;
}
}
class ConfigData {
public Barrage BarrageSettings {
get;
set;
}
public Damage DamageControl {
get;
set;
}
public Options Options {
get;
set;
}
public Intensity z_IntensitySettings {
get;
set;
}
}
private void LoadVariables() {
LoadConfigVariables();
SaveConfig();
}
protected override void LoadDefaultConfig() {
var config = new ConfigData {
BarrageSettings = new Barrage {
NumberOfRockets = 20, RocketDelay = 0.33f, RocketSpread = 16f
}
, DamageControl = new Damage {
DamageMultiplier = 0.2f,
}
, Options = new Options {
EnableAutomaticEvents = true, EventTimers = new Timers {
EventInterval = 30, RandomTimerMax = 45, RandomTimerMin = 15, UseRandomTimer = false
}
, GlobalDropMultiplier = 1.0f, NotifyEvent = true
}
, z_IntensitySettings = new Intensity {
Settings_Mild = new Settings {
FireRocketChance = 30, Radius = 500f, Duration = 240, ItemDropControl = new Drops {
EnableItemDrop = true, ItemsToDrop = new ItemDrop[] {
new ItemDrop {
Maximum = 120, Minimum = 80, Shortname = "stones"
}
, new ItemDrop {
Maximum = 50, Minimum = 25, Shortname = "metal.ore"
}
}
}
, RocketAmount = 20
}
, Settings_Optimal = new Settings {
FireRocketChance = 20, Radius = 300f, Duration = 120, ItemDropControl = new Drops {
EnableItemDrop = true, ItemsToDrop = new ItemDrop[] {
new ItemDrop {
Maximum = 250, Minimum = 160, Shortname = "stones"
}
, new ItemDrop {
Maximum = 120, Minimum = 60, Shortname = "metal.fragments"
}
, new ItemDrop {
Maximum = 50, Minimum = 20, Shortname = "hq.metal.ore"
}
}
}
, RocketAmount = 45
}
, Settings_Extreme = new Settings {
FireRocketChance = 10, Radius = 100f, Duration = 30, ItemDropControl = new Drops {
EnableItemDrop = true, ItemsToDrop = new ItemDrop[] {
new ItemDrop {
Maximum = 400, Minimum = 250, Shortname = "stones"
}
, new ItemDrop {
Maximum = 300, Minimum = 125, Shortname = "metal.fragments"
}
, new ItemDrop {
Maximum = 50, Minimum = 20, Shortname = "metal.refined"
}
, new ItemDrop {
Maximum = 120, Minimum = 45, Shortname = "sulfur.ore"
}
}
}
, RocketAmount = 70
}
}
}
;
SaveConfig(config);
}
private void LoadConfigVariables() => configData = Config.ReadObject<ConfigData>();
void SaveConfig(ConfigData config) => Config.WriteObject(config, true);
#endregion
#region Localization
string msg(string key, string playerId = "") => lang.GetMessage(key, this, playerId);
Dictionary<string, string> Messages = new Dictionary<string, string> {
{
"incoming", "Meteor shower incoming"
}
, {
"help1", "/rof onplayer <opt:playername> - Calls a event on your position, or the player specified"
}
, {
"help2", "/rof onplayer_extreme <opt:playername> - Starts a extreme event on your position, or the player specified"
}
, {
"help3", "/rof onplayer_mild <opt:playername> - Starts a optimal event on your position, or the player specified"
}
, {
"help4", "/rof barrage - Fire a barrage of rockets from your position"
}
, {
"help5", "/rof random - Calls a event at a random postion"
}
, {
"help6", "/rof intervals <amount> - Change the time between events"
}
, {
"help7", "/rof damagescale <amount> - Change the damage scale"
}
, {
"help8", "/rof togglemsg - Toggle public event broadcast"
}
, {
"calledOn", "Event called on {0}'s position"
}
, {
"noPlayer", "No player found with that name"
}
, {
"onPos", "Event called on your position"
}
, {
"Extreme", "Extreme"
}
, {
"Mild", "Mild"
}
, {
"randomCall", "Event called on random position"
}
, {
"invalidParam", "Invalid parameter '{0}'"
}
, {
"smallInter", "Event intervals under 4 minutes are not allowed"
}
, {
"interSet", "Event intervals set to {0} minutes"
}
, {
"dropMulti", "Global item drop multiplier set to "
}
, {
"damageMulti", "Damage scale set to "
}
, {
"notifDeAct", "Event notification de-activated"
}
, {
"notifAct", "Event notification activated"
}
, {
"unknown", "Unknown parameter '{0}'"
}
}
;
#endregion
}
}