diff --git a/NwPluginAPI/Core/Doors/FacilityBreakableDoor.cs b/NwPluginAPI/Core/Doors/FacilityBreakableDoor.cs index 47f9293..5954017 100644 --- a/NwPluginAPI/Core/Doors/FacilityBreakableDoor.cs +++ b/NwPluginAPI/Core/Doors/FacilityBreakableDoor.cs @@ -71,6 +71,24 @@ public void Destroy() DoorEvents.TriggerAction(OriginalObject, DoorAction.Destroyed, null); } + /// + /// Try-get a from a + /// + /// The + /// The if its found otherwise will be + /// A boolean indicating if the was found. + public static bool TryGet(DoorVariant baseDoor, out FacilityBreakableDoor facilityDoor) + { + if (List == null) + { + facilityDoor = null; + return false; + } + + facilityDoor = List.FirstOrDefault(door => door.GameObject == baseDoor.gameObject); + return facilityDoor != null; + } + /// /// Initializes a new instance of the class. /// diff --git a/NwPluginAPI/Core/Doors/FacilityDoor.cs b/NwPluginAPI/Core/Doors/FacilityDoor.cs index dec084f..c1ed554 100644 --- a/NwPluginAPI/Core/Doors/FacilityDoor.cs +++ b/NwPluginAPI/Core/Doors/FacilityDoor.cs @@ -124,6 +124,25 @@ public static IEnumerable Get(Zones.FacilityZone facilityZone) => /// Whether or not the door lock reason is new. public void Lock(DoorLockReason reason, bool enabled) => OriginalObject.ServerChangeLock(reason, enabled); + + /// + /// Try-get a from a + /// + /// The + /// The if its found otherwise will be + /// A boolean indicating if the was found. + public static bool TryGet(DoorVariant baseDoor, out FacilityDoor facilityDoor) + { + if (Facility.Doors == null) + { + facilityDoor = null; + return false; + } + + facilityDoor = Facility.Doors.FirstOrDefault(door => door.GameObject == baseDoor.gameObject); + return facilityDoor != null; + } + /// /// Initializes a new instance of the class. /// diff --git a/NwPluginAPI/Core/Doors/FacilityGate.cs b/NwPluginAPI/Core/Doors/FacilityGate.cs index 2e5919b..3fa379d 100644 --- a/NwPluginAPI/Core/Doors/FacilityGate.cs +++ b/NwPluginAPI/Core/Doors/FacilityGate.cs @@ -6,6 +6,7 @@ namespace PluginAPI.Core.Doors using System.Collections.Generic; using System.Linq; using UnityEngine; + using Interactables.Interobjects.DoorUtils; /// /// Represents a gate. @@ -32,6 +33,24 @@ public class FacilityGate : FacilityDoor /// public Transform[] PryPositions => OriginalObject.PryPositions; + /// + /// Try-get a from a + /// + /// The + /// The if its found otherwise will be + /// A boolean indicating if the was found. + public static bool TryGet(DoorVariant baseDoor, out FacilityGate facilityDoor) + { + if (List == null) + { + facilityDoor = null; + return false; + } + + facilityDoor = List.FirstOrDefault(door => door.GameObject == baseDoor.gameObject); + return facilityDoor != null; + } + /// /// Initializes a new instance of the class. /// diff --git a/NwPluginAPI/Core/Extensions/ItemExtensions.cs b/NwPluginAPI/Core/Extensions/ItemExtensions.cs new file mode 100644 index 0000000..92456b8 --- /dev/null +++ b/NwPluginAPI/Core/Extensions/ItemExtensions.cs @@ -0,0 +1,296 @@ +using InventorySystem; +using InventorySystem.Items; +using InventorySystem.Items.Firearms; +using InventorySystem.Items.Firearms.Attachments; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace PluginAPI.Core.Extensions +{ + public static class ItemExtensions + { + /// + /// Checks if the current is ammunition. + /// + /// The ItemType value to check. + /// + /// true if the specified is an ammunition; otherwise, false. + /// + public static bool IsAmmo(this ItemType type) + { + switch (type) + { + // List of ammunition + case ItemType.Ammo12gauge: + case ItemType.Ammo44cal: + case ItemType.Ammo556x45: + case ItemType.Ammo762x39: + case ItemType.Ammo9x19: + return true; + // Default case: not an ammunition + default: + return false; + } + } + + /// + /// Checks if the current represents a firearm. + /// + /// The ItemType value to check. + /// + /// A boolean parameter indicating whether to count special weapons (default is false). + /// If set to true, special weapons like Jailbird and MicroHID are considered firearms; otherwise, they are not. + /// + /// + /// true if the specified is a firearm; otherwise, false. + /// + public static bool IsFirearm(this ItemType type, bool countSpecialWeapons = false) + { + switch (type) + { + // List of firearm + case ItemType.GunAK: + case ItemType.GunCOM15: + case ItemType.GunCOM18: + case ItemType.GunCom45: + case ItemType.GunCrossvec: + case ItemType.GunLogicer: + case ItemType.GunRevolver: + case ItemType.GunShotgun: + case ItemType.GunE11SR: + case ItemType.GunFRMG0: + case ItemType.GunA7: + case ItemType.GunFSP9: + return true; + // Special cases (Jailbird and MicroHID) depend on the value of countSpecialWeapons + case ItemType.Jailbird: + case ItemType.MicroHID: + return countSpecialWeapons; + // Default case: not a firearm + default: + return false; + } + } + + /// + /// Checks if the current is an medical item. + /// + /// The ItemType value to check. + /// + /// true if the specified is a medical item; otherwise, false. + /// + public static bool IsMedical(this ItemType type) => type is ItemType.Medkit or ItemType.Adrenaline or ItemType.Painkillers or ItemType.SCP500; + + /// + /// Checks if the current is an utility item. + /// + /// The ItemType value to check. + /// + /// true if the specified is a utility item; otherwise, false. + /// + public static bool IsUtility(this ItemType type) => type is ItemType.Radio or ItemType.Flashlight; + + /// + /// Checks if the current is an armor item. + /// + /// The value to check. + /// + /// true if the specified is an armor item; otherwise, false. + /// + public static bool IsArmor(this ItemType type) => type is ItemType.ArmorCombat or ItemType.ArmorHeavy or ItemType.ArmorLight; + + /// + /// Checks if the current represents is an throwable item. + /// + /// The ItemType value to check. + /// + /// true if the specified is a throwable item; otherwise, false. + /// + public static bool IsThrowable(this ItemType type) => type is ItemType.SCP018 or ItemType.GrenadeFlash or ItemType.GrenadeHE or ItemType.SCP2176; + + /// + /// Checks if the current is an keycard. + /// + /// The ItemType value to check. + /// + /// true if the specified is a keycard; otherwise, false. + /// + public static bool IsKeycard(this ItemType type) + { + switch (type) + { + // List of keycard + case ItemType.KeycardChaosInsurgency: + case ItemType.KeycardContainmentEngineer: + case ItemType.KeycardFacilityManager: + case ItemType.KeycardGuard: + case ItemType.KeycardJanitor: + case ItemType.KeycardMTFCaptain: + case ItemType.KeycardMTFOperative: + case ItemType.KeycardMTFPrivate: + case ItemType.KeycardO5: + case ItemType.KeycardResearchCoordinator: + case ItemType.KeycardScientist: + case ItemType.KeycardZoneManager: + return true; + // Default case: not a keycard + default: + return false; + } + } + + /// + /// Retrieves the associated with the specified . + /// + /// The value for which to retrieve the . + /// + /// The associated with the specified if found; otherwise, null. + /// + public static ItemBase GetItemBase(this ItemType type) + { + return InventoryItemLoader.TryGetItem(type, out ItemBase itemBase) ? itemBase : null; + } + + /// + /// Gets a random attachments code for the specified representing a firearm. + /// + /// The value representing the firearm. + /// + /// A random attachments code for the specified firearm, or an exception if the provided + /// argument is not a valid firearm. + /// + /// + /// Thrown when the provided argument is not a valid firearm. + /// + public static uint GetRandomAttachments(this ItemType firearm) + { + if (!firearm.IsFirearm()) + throw new ArgumentException("The provided argument is not a valid firearm.", nameof(firearm)); + + return AttachmentsUtils.GetRandomAttachmentsCode(firearm); + } + + /// + /// Applies attachments to the specified using the provided attachments code. + /// + /// The to which to apply the attachments. + /// The attachments code to apply to the firearm. + /// If the weapon when applying attachments has a flashlight, do you want to turn it on; default is true + /// + /// Thrown when the provided is null. + /// + public static void ApplyAttachments(this Firearm firearm, uint attachmentCode, bool enableFlashLight = true) + { + if (firearm == null) + throw new ArgumentNullException(nameof(firearm), "Firearm is null"); + + firearm.ApplyAttachmentsCode(attachmentCode, true); + + var firearmStatusFlags = firearm.Status.Flags; + + if(!firearmStatusFlags.HasFlag(FirearmStatusFlags.MagazineInserted)) + firearmStatusFlags |= FirearmStatusFlags.MagazineInserted; + + if (firearm.HasAdvantageFlag(AttachmentDescriptiveAdvantages.Flashlight) && enableFlashLight) + { + firearmStatusFlags |= FirearmStatusFlags.FlashlightEnabled; + } + + firearm.Status = new FirearmStatus(firearm.Status.Ammo, firearmStatusFlags, firearm.GetCurrentAttachmentsCode()); + } + + /// + /// Applies a set of random attachments to the specified . + /// + /// The to which random attachments will be applied. + /// Thrown if the is null. + public static void ApplyRandomAttachments(this Firearm firearm) + { + if (firearm == null) + throw new ArgumentNullException(nameof(firearm), "Firearm is null"); + // Get a random attachments code + var randomAttachments = GetRandomAttachments(firearm.ItemTypeId); + + // Apply the random attachments, preserving the flashlight status if it's enabled + ApplyAttachments(firearm, randomAttachments, firearm.Status.Flags.HasFlag(FirearmStatusFlags.FlashlightEnabled)); + } + + /// + /// Try to apply attachment to the specified based on a player's preferences. + /// + /// The to which attachments preferences will be applied. + /// The whose preferences are used for attachments. + /// Optional. Indicates whether to preserve the current ammo when applying preferences (default is true). + /// + /// true if attachment preferences were successfully applied; otherwise, false. + /// + public static bool TryApplyAttachmentsPreferences(this Firearm firearm, Player player, bool preserveAmmo = true) + { + if (firearm == null) + return false; + + if(AttachmentsServerHandler.PlayerPreferences.TryGetValue(player.ReferenceHub, out var prefs) && prefs.TryGetValue(firearm.ItemTypeId, out uint attachmentsCode)) + { + firearm.Status = preserveAmmo ? new FirearmStatus(firearm.Status.Ammo, firearm.Status.Flags, firearm.GetCurrentAttachmentsCode()) : new FirearmStatus(0, firearm.Status.Flags, firearm.GetCurrentAttachmentsCode()); + + ApplyAttachments(firearm, attachmentsCode, firearm.Status.Flags.HasFlag(FirearmStatusFlags.FlashlightEnabled)); + return true; + } + return false; + } + + /// + /// Gets the maximum ammo capacity for the specified . + /// + /// The for which to retrieve the maximum ammo capacity. + /// The maximum ammo capacity for the specified . + public static byte GetMaxAmmo(this Firearm firearm) + { + return firearm == null ? (byte)0 : firearm.AmmoManagerModule.MaxAmmo; + } + + /// + /// Gets the maximum ammo capacity for the specified . + /// + /// The for which to retrieve the maximum ammo capacity. + /// The maximum ammo capacity for the specified . Returns 0 if the item is not a firearm. + public static byte GetMaxAmmo(this ItemType type) + { + var baseItem = GetItemBase(type); + + return baseItem is not Firearm firearm ? (byte)0 : firearm.AmmoManagerModule.MaxAmmo; + } + + /// + /// Reloads the specified to its maximum ammo capacity while preserving attachments and status flags. + /// + /// The to be reloaded. + /// Thrown if the is null. + public static void ReloadFirearm(this Firearm firearm) + { + if (firearm == null) + throw new ArgumentNullException(nameof(firearm), "Firearm is null"); + + // Create a new FirearmStatus with maximum ammo capacity while preserving attachments and status flags + firearm.Status = new FirearmStatus(firearm.AmmoManagerModule.MaxAmmo, firearm.Status.Flags, firearm.Status.Attachments); + } + + /// + /// Removes all ammunition from the specified . + /// + /// The from which to remove all ammunition. + /// Thrown if the is null. + public static void RemoveAmmo(this Firearm firearm) + { + if (firearm == null) + throw new ArgumentNullException(nameof(firearm), "Firearm is null"); + + // Set the ammo count to zero + firearm.Status = new FirearmStatus(0, firearm.Status.Flags, firearm.Status.Attachments); + } + } +} diff --git a/NwPluginAPI/Core/Player.cs b/NwPluginAPI/Core/Player.cs index 47475e0..b3dfcc9 100644 --- a/NwPluginAPI/Core/Player.cs +++ b/NwPluginAPI/Core/Player.cs @@ -118,6 +118,54 @@ public static bool TryGet(IGameComponent component, out T player) where T : P return true; } + /// + /// Gets a filtred by . + /// Can be empty. + /// + /// The player's team + /// The filtered . + public static IEnumerable GetPlayers(Team team) => GetPlayers().Where(p => p.Team == team); + + /// + /// Gets a filtred by . + /// Can be empty. + /// + /// The player's team + /// The filtered . + public static IEnumerable GetPlayers(RoleTypeId roleType) => GetPlayers().Where(p => p.Role == roleType); + + #region Get player from collider + + /// + /// Gets the associated with the , if any. + /// + public static Player Get(Collider collider) => Get(collider.gameObject); + + /// + /// Try-get a associated with the . + /// + /// The + /// The found by the , if there is none it will return . + /// A boolean indicating whether or not a player was found. + public static bool TryGet(Collider collider, out Player player) => TryGet(collider.gameObject, out player); + #endregion + + #region Get player from footprint + + /// + /// Gets the associated with the , if any. + /// + public static Player Get(Footprint footprint) => Get(footprint.Hub); + + /// + /// Try-get a associated with the . + /// + /// The + /// The found by the , if there is none it will return . + /// A boolean indicating whether or not a player was found. + public static bool TryGet(Footprint footprint, out Player player) => TryGet(footprint.Hub, out player); + #endregion + #region Get player from gameobject. /// @@ -581,6 +629,11 @@ public RoleTypeId Role set => ReferenceHub.roleManager.ServerSetRole(value, RoleChangeReason.RemoteAdmin); } + /// + /// Gets the player's . + /// + public Footprint Footprint => new(ReferenceHub); + /// /// Gets player . /// @@ -1200,7 +1253,7 @@ public void RemoveItems(ItemType itemType, int number = 1) /// The amount of ammo which will be dropped. /// Will prevent dropping small amounts of ammo. /// Whether or not the player dropped the ammo successfully. - public List DropAmmo(ItemType item, ushort amount, bool checkMinimals = false) => null;// ReferenceHub.inventory.ServerDropAmmo(item, amount, checkMinimals); + public List DropAmmo(ItemType item, ushort amount, bool checkMinimals = false) => ReferenceHub.inventory.ServerDropAmmo(item, amount, checkMinimals); /// /// Drops all items including ammo. @@ -1248,7 +1301,8 @@ public void SetGroup(UserGroup group) /// /// The which will be set. /// The of role change. - public void SetRole(RoleTypeId newRole, RoleChangeReason reason = RoleChangeReason.RemoteAdmin) => ReferenceHub.roleManager.ServerSetRole(newRole, reason); + /// The of role change. + public void SetRole(RoleTypeId newRole, RoleChangeReason reason = RoleChangeReason.RemoteAdmin, RoleSpawnFlags spawnFlags = RoleSpawnFlags.All) => ReferenceHub.roleManager.ServerSetRole(newRole, reason, spawnFlags); /// /// Disconnects the player from the server. @@ -1387,6 +1441,5 @@ public bool TryGetComponent(out T component, bool globalSearch = false) where #endregion #endregion - } } \ No newline at end of file