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;
}
}