diff --git a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs index d55324798..4ea1909b7 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs @@ -10,19 +10,33 @@ namespace Exiled.API.Features.DamageHandlers using System; using Enums; + + using Exiled.API.Extensions; using Exiled.API.Features.Pickups.Projectiles; using Footprinting; + + using InventorySystem; + using InventorySystem.Items; + using InventorySystem.Items.Firearms; + using InventorySystem.Items.Firearms.Modules; + using InventorySystem.Items.Firearms.ShotEvents; using InventorySystem.Items.Scp1509; + using Items; + using PlayerRoles; using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.PlayableScps.Scp1507; using PlayerRoles.PlayableScps.Scp3114; using PlayerRoles.PlayableScps.Scp939; + using PlayerStatsSystem; + using UnityEngine; + using Object = UnityEngine.Object; + /// /// Allows generic damage to a player. /// @@ -59,7 +73,7 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage if (customCassieAnnouncement is not null) customCassieAnnouncement.Announcement ??= $"{player.Nickname} killed by {attacker.Nickname} utilizing {damageType}"; - Attacker = attacker.Footprint; + Attacker = attacker != null ? attacker.Footprint : Server.Host.Footprint; AllowSelfDamage = true; Damage = damage; ServerLogsText = $"GenericDamageHandler damage processing"; @@ -123,55 +137,57 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage Base = new GrayCandyDamageHandler(Attacker.Hub, damage); break; case DamageType.MicroHid: - InventorySystem.Items.MicroHID.MicroHIDItem microHidOwner = new(); - microHidOwner.Owner = attacker.ReferenceHub; + InventorySystem.Items.MicroHID.MicroHIDItem microHidOwner = new() + { + Owner = attacker.ReferenceHub, + }; Base = new MicroHidDamageHandler(damage, microHidOwner); break; case DamageType.Explosion: - Base = new ExplosionDamageHandler(attacker.Footprint, UnityEngine.Vector3.zero, damage, 0, ExplosionType.Grenade); + Base = new ExplosionDamageHandler(attacker.Footprint, Vector3.zero, damage, 0, ExplosionType.Grenade); break; case DamageType.Firearm: case DamageType.AK: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunAK); + GenericFirearm(damage, ItemType.GunAK); break; case DamageType.Crossvec: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunCrossvec); + GenericFirearm(damage, ItemType.GunCrossvec); break; case DamageType.Logicer: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunLogicer); + GenericFirearm(damage, ItemType.GunLogicer); break; case DamageType.Revolver: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunRevolver); + GenericFirearm(damage, ItemType.GunRevolver); break; case DamageType.Shotgun: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunShotgun); + GenericFirearm(damage, ItemType.GunShotgun); break; case DamageType.Com15: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunCOM15); + GenericFirearm(damage, ItemType.GunCOM15); break; case DamageType.Com18: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunCOM18); + GenericFirearm(damage, ItemType.GunCOM18); break; case DamageType.Fsp9: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunFSP9); + GenericFirearm(damage, ItemType.GunFSP9); break; case DamageType.E11Sr: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunE11SR); + GenericFirearm(damage, ItemType.GunE11SR); break; case DamageType.Com45: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunCom45); + GenericFirearm(damage, ItemType.GunCom45); break; case DamageType.Frmg0: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunFRMG0); + GenericFirearm(damage, ItemType.GunFRMG0); break; case DamageType.A7: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunA7); + GenericFirearm(damage, ItemType.GunA7); break; case DamageType.Scp127: - GenericFirearm(player, attacker, damage, damageType, ItemType.GunSCP127); + GenericFirearm(damage, ItemType.GunSCP127); break; case DamageType.ParticleDisruptor: - Base = new DisruptorDamageHandler(new (Item.Create(ItemType.ParticleDisruptor, attacker).Base as InventorySystem.Items.Firearms.Firearm, InventorySystem.Items.Firearms.Modules.DisruptorActionModule.FiringState.FiringSingle), Vector3.up, damage); + Base = new DisruptorDamageHandler(new DisruptorShotEvent(default, Attacker, InventorySystem.Items.Firearms.Modules.DisruptorActionModule.FiringState.FiringSingle), Vector3.up, damage); break; case DamageType.Scp096: Scp096Role curr096 = attacker.ReferenceHub.roleManager.CurrentRole as Scp096Role ?? new Scp096Role(); @@ -193,9 +209,12 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage Base = new PlayerStatsSystem.ScpDamageHandler(attacker.ReferenceHub, damage, DeathTranslations.Unknown); break; case DamageType.Scp018: - Scp018Projectile scp018Projectile = Projectile.Create(ProjectileType.Scp018); - scp018Projectile.PreviousOwner = attacker; - Base = new Scp018DamageHandler(scp018Projectile.Base, damage, true); + InventorySystem.Items.ThrowableProjectiles.Scp018Projectile dummy018 = new() + { + PreviousOwner = Attacker, + }; + + Base = new Scp018DamageHandler(dummy018, damage, true); break; case DamageType.Scp207: Base = new PlayerStatsSystem.ScpDamageHandler(attacker.ReferenceHub, damage, DeathTranslations.Scp207); @@ -303,21 +322,26 @@ public override HandlerOutput ApplyDamage(ReferenceHub ply) /// /// Generic firearm path for handle type. /// - /// Current player. - /// Current attacker. /// Damage amount. - /// Damage type. /// ItemType. - private void GenericFirearm(Player player, Player attacker, float amount, DamageType damageType, ItemType itemType) + private void GenericFirearm(float amount, ItemType itemType) { - Firearm firearm = new(itemType) + ItemType ammoType = ItemType.None; + + if (InventoryItemLoader.TryGetItem(itemType, out InventorySystem.Items.Firearms.Firearm firearmTemplate)) { - Base = - { - Owner = attacker.ReferenceHub, - }, + Items.Firearm firearm = new(firearmTemplate); + ammoType = firearm.AmmoType.GetItemType(); + } + + Base = new PlayerStatsSystem.FirearmDamageHandler + { + Damage = amount, + Attacker = Attacker, + AmmoType = ammoType, + WeaponType = itemType, + Firearm = firearmTemplate, }; - Base = new PlayerStatsSystem.FirearmDamageHandler() { Firearm = firearm.Base, Damage = amount }; } } } diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 89bb189c4..6e9a20d66 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -414,7 +414,19 @@ public static T Create(ItemType type, Player owner = null) /// /// Destroy this item. /// - public void Destroy() => Owner.RemoveItem(this); + public void Destroy() + { + if (Owner.RemoveItem(this)) + return; + + if (Base != null) + { + BaseToItem.Remove(Base); + + if (Base.gameObject != null) + Object.Destroy(Base.gameObject); + } + } /// /// Creates the that based on this . diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 522a0a211..90ea90f18 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -2324,7 +2324,23 @@ public void Heal(float amount, bool overrideMaxHealth = false) /// /// The ItemType to be used. /// if item was used successfully. Otherwise, . - public bool UseItem(ItemType usableItem) => UseItem(Item.Create(usableItem)); + public bool UseItem(ItemType usableItem) + { + if (usableItem.GetTemplate() is not UsableItem) + return false; + + Item item = Item.Create(usableItem); + + if (item is not Usable usable) + { + item.Destroy(); + return false; + } + + UseItem(usable); + item.Destroy(); + return true; + } /// /// Forces the player to use an item. @@ -2388,7 +2404,8 @@ public void Vaporize(Player attacker = null, string cassieAnnouncement = "") if ((Role.Side != Side.Scp) && !string.IsNullOrEmpty(cassieAnnouncement)) Cassie.Message(cassieAnnouncement); - Kill(new DisruptorDamageHandler(new DisruptorShotEvent(Item.Create(ItemType.ParticleDisruptor, attacker).Base as InventorySystem.Items.Firearms.Firearm, DisruptorActionModule.FiringState.FiringSingle), Vector3.up, -1)); + Footprint footprint = attacker != null ? attacker.Footprint : Server.Host.Footprint; + Kill(new DisruptorDamageHandler(new DisruptorShotEvent(default, footprint, DisruptorActionModule.FiringState.FiringSingle), Vector3.up, -1)); } /// diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs b/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs index e6f193290..c1a77f635 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs @@ -82,7 +82,7 @@ public override void Give(Player player, bool displayMessage = true) if (AmmoLimits.Count != 0) armor.AmmoLimits = AmmoLimits; - if (AmmoLimits.Count != 0) + if (CategoryLimits.Count != 0) armor.CategoryLimits = CategoryLimits; player.AddItem(armor); diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs b/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs index 48d725ce7..feafdae9c 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs @@ -19,10 +19,14 @@ namespace Exiled.CustomItems.API.Features using Exiled.Events.EventArgs.Player; using Footprinting; + + using InventorySystem; using InventorySystem.Items; using InventorySystem.Items.Pickups; using InventorySystem.Items.ThrowableProjectiles; + using Mirror; + using UnityEngine; using Object = UnityEngine.Object; @@ -70,31 +74,43 @@ public override ItemType Type /// The spawned. public virtual Pickup Throw(Vector3 position, float force, float weight, float fuseTime = 3f, ItemType grenadeType = ItemType.GrenadeHE, Player? player = null) { - if (player is null) - player = Server.Host; + player ??= Server.Host; - player.Role.Is(out FpcRole fpcRole); - Vector3 velocity = fpcRole.FirstPersonController.FpcModule.Motor.Velocity; + Vector3 velocity = Vector3.zero; + Quaternion rotation = Quaternion.identity; - Throwable throwable = (Throwable)Item.Create(grenadeType, player); + if (player != Server.Host) + { + if (player.Role.Is(out FpcRole fpcRole)) + velocity = fpcRole.FirstPersonController.FpcModule.Motor.Velocity; + + if (player.CameraTransform != null) + rotation = player.CameraTransform.rotation; + } - ThrownProjectile thrownProjectile = Object.Instantiate(throwable.Base.Projectile, position, throwable.Owner.CameraTransform.rotation); + InventoryItemLoader.TryGetItem(grenadeType, out ThrowableItem template); + + ThrownProjectile thrownProjectile = Object.Instantiate(template.Projectile, position, rotation); PickupSyncInfo newInfo = new() { - ItemId = throwable.Type, - Locked = !throwable.Base._repickupable, + ItemId = grenadeType, + Locked = !template._repickupable, Serial = ItemSerialGenerator.GenerateNext(), WeightKg = weight, }; + if (thrownProjectile is TimeGrenade time) time._fuseTime = fuseTime; + thrownProjectile.NetworkInfo = newInfo; - thrownProjectile.PreviousOwner = new Footprint(throwable.Owner.ReferenceHub); + thrownProjectile.PreviousOwner = player.Footprint; NetworkServer.Spawn(thrownProjectile.gameObject); thrownProjectile.InfoReceivedHook(default, newInfo); + if (thrownProjectile.TryGetComponent(out Rigidbody component)) - throwable.Base.PropelBody(component, throwable.Base.FullThrowSettings.StartTorque, ThrowableNetworkHandler.GetLimitedVelocity(velocity)); + template.PropelBody(component, template.FullThrowSettings.StartTorque, ThrowableNetworkHandler.GetLimitedVelocity(velocity)); + thrownProjectile.ServerActivate(); return Pickup.Get(thrownProjectile); diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs index 789fd25ce..e131db708 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -540,7 +540,7 @@ public static IEnumerable UnregisterItems(IEnumerable targetTy Pickup? pickup = Spawn(position, item, previousOwner); - UnityEngine.Object.Destroy(item.Base); + item.Destroy(); return pickup; } @@ -554,6 +554,7 @@ public static IEnumerable UnregisterItems(IEnumerable targetTy public virtual Pickup? Spawn(Vector3 position, Item item, Player? previousOwner = null) { Pickup? pickup = item.CreatePickup(position); + pickup.Scale = Scale; pickup.Weight = Weight; diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs index 9053cf2d6..e889ec3f9 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs @@ -18,9 +18,11 @@ namespace Exiled.CustomItems.API.Features using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Item; using Exiled.Events.EventArgs.Player; + using InventorySystem.Items.Firearms.Attachments; using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Firearms.Modules; + using UnityEngine; using Firearm = Exiled.API.Features.Items.Firearm; @@ -69,16 +71,22 @@ public override ItemType Type /// public override Pickup? Spawn(Vector3 position, Player? previousOwner = null) { - if (Item.Create(Type) is not Firearm firearm) + Item item = Item.Create(Type); + if (item is not Firearm firearm) { Log.Debug($"{nameof(Spawn)}: Item is not Firearm."); + item.Destroy(); return null; } if (!Attachments.IsEmpty()) firearm.AddAttachment(Attachments); - Pickup? pickup = firearm.CreatePickup(position); + if (ClipSize > 0) + firearm.MagazineAmmo = ClipSize; + + FirearmPickup? pickup = (FirearmPickup?)firearm.CreatePickup(position, spawn: false); + item.Destroy(); if (pickup is null) { @@ -86,15 +94,16 @@ public override ItemType Type return null; } - if (ClipSize > 0) - firearm.MagazineAmmo = ClipSize; - pickup.Weight = Weight; pickup.Scale = Scale; + if (previousOwner is not null) pickup.PreviousOwner = previousOwner; + pickup.Spawn(); + TrackedSerials.Add(pickup.Serial); + return pickup; } @@ -108,9 +117,11 @@ public override ItemType Type if (ClipSize > 0) firearm.MagazineAmmo = ClipSize; + int ammo = firearm.MagazineAmmo; Log.Debug($"{nameof(Name)}.{nameof(Spawn)}: Spawning weapon with {ammo} ammo."); Pickup? pickup = firearm.CreatePickup(position); + item.Destroy(); pickup.Scale = Scale; if (previousOwner is not null) diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index cebcffa74..49bfc21b8 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -145,9 +145,11 @@ private static void GenerateAttachments() if (firearmType == FirearmType.None) continue; - if (Item.Create(firearmType.GetItemType()) is not Firearm firearm) + if (!InventoryItemLoader.TryGetItem(firearmType.GetItemType(), out InventorySystem.Items.Firearms.Firearm firearmTemplate)) continue; + Firearm firearm = new(firearmTemplate); + Firearm.ItemTypeToFirearmInstance[firearmType] = firearm; List attachmentIdentifiers = ListPool.Pool.Get(); diff --git a/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs b/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs index 96441e17e..38ad7536e 100644 --- a/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs +++ b/EXILED/Exiled.Events/Patches/Generic/StaminaRegenArmor.cs @@ -16,14 +16,17 @@ namespace Exiled.Events.Patches.Generic /// /// Patches . - /// Implements . + /// Implements . /// [HarmonyPatch(typeof(BodyArmor), nameof(BodyArmor.StaminaRegenMultiplier), MethodType.Getter)] internal class StaminaRegenArmor { private static void Postfix(BodyArmor __instance, ref float __result) { - if(Item.Get(__instance) is Armor armor) + if (__instance.ItemSerial == 0) + return; + + if (Item.Get(__instance) is Armor armor) __result *= armor.StaminaRegenMultiplier; } }