using Network; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using UnityEngine; namespace Oxide.Plugins { [Info("ExplosiveChest", "0xF", "1")] public class ExplosiveChest : RustPlugin { const string givePerm = "explosivechest.give"; #region Commands [ConsoleCommand("give.echest")] void GiveExplosiveChest(ConsoleSystem.Arg arg) { BasePlayer player = arg.Player(); if (player == null) return; if (player.IsAdmin || player.IPlayer.HasPermission("explosivechest.give")) player.inventory.GiveItem(ItemManager.Create(ItemManager.FindItemDefinition("box.wooden"), 100, config.SkinId)); } [ConsoleCommand("give.echest.large")] void GiveExplosiveChestLarge(ConsoleSystem.Arg arg) { BasePlayer player = arg.Player(); if (player == null) return; if (player.IsAdmin || player.IPlayer.HasPermission("explosivechest.give")) player.inventory.GiveItem(ItemManager.Create(ItemManager.FindItemDefinition("box.wooden.large"), 100, config.SkinId)); } #endregion #region Hooks private void Init() { LoadConfig(); permission.RegisterPermission(givePerm, this); if (config.Explosion.Mode) Unsubscribe(nameof(OnLootEntityEnd)); else Unsubscribe(nameof(OnLootEntity)); } void OnLootEntity(BasePlayer player, BaseEntity entity) => Boom(player, entity); void OnLootEntityEnd(BasePlayer player, BaseEntity entity) => Boom(player, entity); void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) { if (entity.skinID != config.SkinId) return; if (config.Attacking.OnlyPlayerDamage && !(info.Initiator is BasePlayer)) return; info.damageTypes.ScaleAll(0); switch (config.Attacking.Mode) { case ConfigData.AttackingSettings.Modes.Explosion: Boom(info.InitiatorPlayer, info.HitEntity); break; case ConfigData.AttackingSettings.Modes.Rocket: entity.transform.LookAt(info.Initiator.transform); entity.SendNetworkUpdate(); string prefabName; switch (config.Attacking.Rocket.RocketType) { case ConfigData.AttackingSettings.RocketTypes.Basic: prefabName = "assets/prefabs/ammo/rocket/rocket_basic.prefab"; break; case ConfigData.AttackingSettings.RocketTypes.HV: prefabName = "assets/prefabs/ammo/rocket/rocket_hv.prefab"; break; case ConfigData.AttackingSettings.RocketTypes.Fire: prefabName = "assets/prefabs/ammo/rocket/rocket_fire.prefab"; break; case ConfigData.AttackingSettings.RocketTypes.Smoke: prefabName = "assets/prefabs/ammo/rocket/rocket_smoke.prefab"; break; case ConfigData.AttackingSettings.RocketTypes.MLRS: prefabName = "assets/content/vehicles/mlrs/rocket_mlrs.prefab"; break; default: PrintError("An unknown type of rocket is chosen!"); return; } var rocket = GameManager.server.CreateEntity(prefabName, entity.GetNetworkPosition() + new Vector3(0, 1), entity.GetNetworkRotation()); if (rocket == null) return; var proj = rocket.GetComponent(); if (proj == null) return; proj.InitializeVelocity(entity.transform.forward * config.Attacking.Rocket.RocketSpeed); timer.Once(config.Attacking.Timer, () => { if (config.Attacking.ClearChest) entity.GetComponentInChildren().inventory?.Kill(); entity.Kill(); rocket.Spawn(); }); break; default: break; } } #endregion #region Methods private void Boom(BasePlayer player, BaseEntity entity) { if (entity.skinID == config.SkinId) { global::Effect.server.Run("assets/bundled/prefabs/fx/weapons/landmine/landmine_trigger.prefab", entity.transform.position, entity.transform.up, null, true); timer.Once(config.Explosion.Timer, () => { if (entity == null) return; global::Effect.server.Run("assets/bundled/prefabs/fx/weapons/landmine/landmine_explosion.prefab", entity.transform.position, entity.transform.up, null, true); global::DamageUtil.RadiusDamage(entity, GameManager.server.FindPrefab("assets/prefabs/deployable/landmine/landmine.prefab").ToBaseEntity(), entity.WorldSpaceBounds().position, config.Explosion.MinRadius, config.Explosion.Radius, new List() { new Rust.DamageTypeEntry() { type = Rust.DamageType.Explosion, amount = config.Explosion.Damage } }, 2263296, true); if (config.Explosion.ClearChest) entity.GetComponentInChildren().inventory?.Kill(); entity.Kill(); }); } } #endregion #region Config private static ConfigData config; private class ConfigData { public class AttackingSettings { public enum Modes { Disabled, Explosion, Rocket } public enum RocketTypes { Basic, HV, Fire, Smoke, MLRS, } public class RocketSettings { [JsonProperty(PropertyName = "Rocket Type (0 - Basic | 1 - HV | 2 - Fire | 3 - Smoke | 4 - MLRS)")] public RocketTypes RocketType { get; set; } = RocketTypes.HV; [JsonProperty(PropertyName = "Rocket Speed")] public float RocketSpeed { get; set; } = 20f; } [JsonProperty(PropertyName = "React only to damage from the player?")] public bool OnlyPlayerDamage { get; set; } = true; [JsonProperty(PropertyName = "Time to launch after the trigger (in seconds)")] public float Timer { get; set; } = 0.5f; [JsonProperty(PropertyName = "Clear the chest inventory?")] public bool ClearChest { get; set; } = true; [JsonProperty(PropertyName = "Mode (0 - disabled | 1 - explosion | 2 - rocket launch at the player)")] public Modes Mode { get; set; } = Modes.Rocket; [JsonProperty(PropertyName = "Rocket Settings")] public RocketSettings Rocket { get; set; } = new RocketSettings(); } public class ExplosionSettings { [JsonProperty(PropertyName = "When to blow up? (true - after opening, false - after closing)")] public bool Mode { get; set; } = true; [JsonProperty(PropertyName = "Time to explode after the trigger (in seconds)")] public float Timer { get; set; } = 0.3f; [JsonProperty(PropertyName = "Clear the chest inventory?")] public bool ClearChest { get; set; } = false; [JsonProperty(PropertyName = "Damage")] public float Damage { get; set; } = 50f; [JsonProperty(PropertyName = "Min Radius")] public float MinRadius { get; set; } = 1f; [JsonProperty(PropertyName = "Radius")] public float Radius { get; set; } = 5f; } [JsonProperty(PropertyName = "SkinId for the Explosive Chest")] public ulong SkinId { get; set; } = 377663254519; [JsonProperty(PropertyName = "Explosion Settings")] public ExplosionSettings Explosion { get; set; } = new ExplosionSettings(); [JsonProperty(PropertyName = "Settings when attacking the chest")] public AttackingSettings Attacking { get; set; } = new AttackingSettings(); } private ConfigData GetDefaultConfig() { return new ConfigData(); } protected override void LoadConfig() { base.LoadConfig(); try { config = Config.ReadObject(); if (config == null) LoadDefaultConfig(); else SaveConfig(); } catch (Exception ex) { if (ex is JsonSerializationException || ex is NullReferenceException || ex is JsonReaderException) { Puts($"Exception: {ex}"); LoadDefaultConfig(); return; } throw; } } protected override void LoadDefaultConfig() { Puts("Configuration file missing or corrupt, creating default config file."); config = GetDefaultConfig(); SaveConfig(); } protected override void SaveConfig() { Config.WriteObject(config); } #endregion } }