Skip to content
86 changes: 55 additions & 31 deletions EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Allows generic damage to a player.
/// </summary>
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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();
Expand All @@ -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<Scp018Projectile>(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);
Expand Down Expand Up @@ -303,21 +322,26 @@ public override HandlerOutput ApplyDamage(ReferenceHub ply)
/// <summary>
/// Generic firearm path for handle type.
/// </summary>
/// <param name="player"> Current player. </param>
/// <param name="attacker"> Current attacker. </param>
/// <param name="amount"> Damage amount. </param>
/// <param name="damageType"> Damage type. </param>
/// <param name="itemType"> ItemType. </param>
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 };
}
}
}
14 changes: 13 additions & 1 deletion EXILED/Exiled.API/Features/Items/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,19 @@ public static T Create<T>(ItemType type, Player owner = null)
/// <summary>
/// Destroy this item.
/// </summary>
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);
}
}

/// <summary>
/// Creates the <see cref="Pickup"/> that based on this <see cref="Item"/>.
Expand Down
15 changes: 13 additions & 2 deletions EXILED/Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2324,7 +2324,17 @@ public void Heal(float amount, bool overrideMaxHealth = false)
/// </summary>
/// <param name="usableItem">The ItemType to be used.</param>
/// <returns><see langword="true"/> if item was used successfully. Otherwise, <see langword="false"/>.</returns>
public bool UseItem(ItemType usableItem) => UseItem(Item.Create(usableItem));
public bool UseItem(ItemType usableItem)
{
if (usableItem.GetTemplate() is not UsableItem)
return false;

Item usable = Item.Create<Usable>(usableItem);

UseItem(usable);
usable.Destroy();
return true;
}

/// <summary>
/// Forces the player to use an item.
Expand Down Expand Up @@ -2388,7 +2398,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));
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.CustomItems/API/Features/CustomArmor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
36 changes: 26 additions & 10 deletions EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,31 +74,43 @@ public override ItemType Type
/// <returns>The <see cref="Pickup"/> spawned.</returns>
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);
Expand Down
3 changes: 2 additions & 1 deletion EXILED/Exiled.CustomItems/API/Features/CustomItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ public static IEnumerable<CustomItem> UnregisterItems(IEnumerable<Type> targetTy

Pickup? pickup = Spawn(position, item, previousOwner);

UnityEngine.Object.Destroy(item.Base);
item.Destroy();
return pickup;
}

Expand All @@ -554,6 +554,7 @@ public static IEnumerable<CustomItem> UnregisterItems(IEnumerable<Type> targetTy
public virtual Pickup? Spawn(Vector3 position, Item item, Player? previousOwner = null)
{
Pickup? pickup = item.CreatePickup(position);

pickup.Scale = Scale;
pickup.Weight = Weight;

Expand Down
23 changes: 17 additions & 6 deletions EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -69,32 +71,39 @@ public override ItemType Type
/// <inheritdoc />
public override Pickup? Spawn(Vector3 position, Player? previousOwner = null)
{
if (Item.Create(Type) is not Firearm firearm)
if (Type.IsWeapon(false))
{
Log.Debug($"{nameof(Spawn)}: Item is not Firearm.");
Log.Warn($"{nameof(Spawn)}: Item is not Firearm.");
return null;
}

Firearm firearm = Item.Create<Firearm>(Type);

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);
firearm.Destroy();

if (pickup is null)
{
Log.Debug($"{nameof(Spawn)}: Pickup is null.");
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;
}

Expand All @@ -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);

pickup.Scale = Scale;

if (previousOwner is not null)
Expand Down
Loading
Loading