Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
345f91c
init
IRacle1 Dec 1, 2024
d0482d2
xd
IRacle1 Dec 1, 2024
4fc2ebb
let him cook
IRacle1 Dec 1, 2024
35fe771
uuu
IRacle1 Dec 1, 2024
9dfa8ec
Merge branch 'scpsl14' into firearmhard
Misaka-ZeroTwo Dec 2, 2024
b79cb11
yep
IRacle1 Dec 3, 2024
c384ed9
oh
IRacle1 Dec 3, 2024
6bf5c81
ammo drain
IRacle1 Dec 6, 2024
e43047a
OnAdded fix
IRacle1 Dec 8, 2024
a651eda
Reload
IRacle1 Dec 8, 2024
6c77a89
IsDistributed
IRacle1 Dec 8, 2024
7a660a3
reviewuwu
IRacle1 Dec 9, 2024
e3cf0dc
Merge branch 'scpsl14' into firearmhard
IRacle1 Dec 9, 2024
cd3d4d5
-_-
IRacle1 Dec 9, 2024
76d36c7
build
IRacle1 Dec 9, 2024
ad20e18
reimplement props
IRacle1 Dec 9, 2024
db01c37
😥
IRacle1 Dec 9, 2024
13fe7f5
😊
IRacle1 Dec 9, 2024
8503fc5
ah
IRacle1 Dec 9, 2024
a5da95d
docs
IRacle1 Dec 9, 2024
16eceb7
docs
IRacle1 Dec 9, 2024
89151a8
Merge branch 'scpsl14' into firearmhard
IRacle1 Dec 14, 2024
c8beea0
fix: some server crash
IRacle1 Dec 16, 2024
5431c57
refactor: docs
IRacle1 Dec 16, 2024
95533f6
fix/feat: syncing `MaxAmmo`
IRacle1 Dec 16, 2024
c68eb7e
ammo drain sync
IRacle1 Dec 16, 2024
9c48040
refactor: strange modules interaction
IRacle1 Dec 16, 2024
d50b888
docs: its automatic, trust me
IRacle1 Dec 16, 2024
770d8b3
fix: revolver and maxammo
IRacle1 Dec 16, 2024
9c3bd16
fix: ammodrain for automatic firearms
IRacle1 Dec 16, 2024
2d1b9c5
Update EXILED/Exiled.API/Features/Items/Firearm.cs
IRacle1 Dec 22, 2024
bb1a0d8
Update EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/Automat…
IRacle1 Dec 22, 2024
64fc8e8
Update EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Normal…
IRacle1 Dec 22, 2024
619629f
Update EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Normal…
IRacle1 Dec 22, 2024
10596b6
Update EXILED/Exiled.API/Features/Items/FirearmModules/Primary/Normal…
IRacle1 Dec 22, 2024
7623aa2
all yamato requests
IRacle1 Dec 22, 2024
ad0aaa5
Merge branch 'scpsl14' into firearmhard
IRacle1 Dec 22, 2024
e82b890
fix
IRacle1 Dec 22, 2024
a3263ae
Merge branch 'dev' into firearmhard
BoltonDev Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions EXILED/Exiled.API/Enums/RevolverChamberState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// -----------------------------------------------------------------------
// <copyright file="RevolverChamberState.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Enums
{
using Exiled.API.Features.Items.FirearmModules.Primary;

/// <summary>
/// States for chamber in revolver cylindric magazine.
/// </summary>
/// <seealso cref="CylinderMagazine"/>
public enum RevolverChamberState
{
/// <summary>
/// State for empty chamber.
/// </summary>
Empty,

/// <summary>
/// State for chamber with a bullet.
/// </summary>
Live,

/// <summary>
/// State for discharged chamber.
/// </summary>
Discharged,
}
}
171 changes: 114 additions & 57 deletions EXILED/Exiled.API/Features/Items/Firearm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace Exiled.API.Features.Items

using CameraShaking;
using Enums;

using Exiled.API.Features.Items.FirearmModules;
using Exiled.API.Features.Items.FirearmModules.Barrel;
using Exiled.API.Features.Items.FirearmModules.Primary;
using Exiled.API.Features.Pickups;
using Exiled.API.Interfaces;
using Exiled.API.Structs;
Expand Down Expand Up @@ -55,6 +59,20 @@ public Firearm(BaseFirearm itemBase)
: base(itemBase)
{
Base = itemBase;

foreach (ModuleBase module in Base.Modules)
{
if (module is IPrimaryAmmoContainerModule primaryAmmoModule)
{
PrimaryMagazine ??= (PrimaryMagazine)Magazine.Get(primaryAmmoModule);
continue;
}

if (module is IAmmoContainerModule ammoModule)
{
BarrelMagazine ??= (BarrelMagazine)Magazine.Get(ammoModule);
}
}
}

/// <summary>
Expand Down Expand Up @@ -105,24 +123,94 @@ public static IReadOnlyDictionary<Player, Dictionary<FirearmType, AttachmentIden
public new BaseFirearm Base { get; }

/// <summary>
/// Gets or sets the amount of ammo in the firearm.
/// Gets a primaty magazine for current firearm.
/// </summary>
public PrimaryMagazine PrimaryMagazine { get; }

/// <summary>
/// Gets a barrel magazine for current firearm.
/// </summary>
/// <remarks>
/// <see langword="null"/> for Revolver and ParticleDisruptor.
/// </remarks>
public BarrelMagazine BarrelMagazine { get; }

/// <summary>
/// Gets or sets the amount of ammo in the firearm magazine.
/// </summary>
public int MagazineAmmo
{
get => PrimaryMagazine.Ammo;
set => PrimaryMagazine.Ammo = value;
}

/// <summary>
/// Gets or sets the amount of ammo in the firearm barrel.
/// </summary>
public int Ammo
/// <remarks>
/// not working for Revolver and ParticleDisruptor.
/// </remarks>
public int BarrelAmmo
{
get => (Base.Modules[Array.IndexOf(Base.Modules, typeof(MagazineModule))] as MagazineModule).AmmoStored;
set => (Base.Modules[Array.IndexOf(Base.Modules, typeof(MagazineModule))] as MagazineModule).AmmoStored = value;
get => BarrelMagazine?.Ammo ?? 0;

set
{
if (BarrelMagazine != null)
BarrelMagazine.Ammo = value;
}
}

/// <summary>
/// Gets the total amount of ammo in the firearm.
/// </summary>
public int TotalAmmo => Base.GetTotalStoredAmmo();

/// <summary>
/// Gets or sets the max ammo for this firearm.
/// </summary>
/// <remarks>Disruptor can't be used for MaxAmmo.</remarks>
public int MaxAmmo
public int MaxMagazineAmmo
{
get => PrimaryMagazine.MaxAmmo;
set => PrimaryMagazine.MaxAmmo = value;
}

/// <summary>
/// Gets or sets the amount of max ammo in the firearm barrel.
/// </summary>
/// <remarks>
/// not working for Revolver and ParticleDisruptor.
/// </remarks>
public int MaxBarrelAmmo
{
get => (Base.Modules[Array.IndexOf(Base.Modules, typeof(MagazineModule))] as MagazineModule).AmmoMax;
set => (Base.Modules[Array.IndexOf(Base.Modules, typeof(MagazineModule))] as MagazineModule)._defaultCapacity = value; // Synced?
get => BarrelMagazine?.MaxAmmo ?? 0;

set
{
if (BarrelMagazine != null)
BarrelMagazine.MaxAmmo = value;
}
}

/// <summary>
/// Gets the total amount of ammo in the firearm.
/// </summary>
public int TotalMaxAmmo => Base.GetTotalMaxAmmo();

/// <summary>
/// Gets or sets a ammo drain per shoot.
/// </summary>
/// <remarks>
/// Always <see langword="1"/> by default.
/// Applied on a high layer nether basegame ammo controllers.
/// </remarks>
public int AmmoDrain { get; set; } = 1;

/// <summary>
/// Gets a value indicating whether the weapon is reloading.
/// </summary>
public bool IsReloading => Base.TryGetModule(out IReloaderModule module) && module.IsReloading;

/// <summary>
/// Gets the <see cref="Enums.FirearmType"/> of the firearm.
/// </summary>
Expand All @@ -131,12 +219,12 @@ public int MaxAmmo
/// <summary>
/// Gets the <see cref="Enums.AmmoType"/> of the firearm.
/// </summary>
public AmmoType AmmoType => (Base.Modules.OfType<MagazineModule>().FirstOrDefault()?.AmmoType ?? ItemType.None).GetAmmoType();
public AmmoType AmmoType => PrimaryMagazine.AmmoType;

/// <summary>
/// Gets a value indicating whether the firearm is being aimed.
/// </summary>
public bool Aiming => Base.Modules.OfType<LinearAdsModule>().FirstOrDefault()?.AdsTarget ?? false;
public bool Aiming => Base.TryGetModule(out LinearAdsModule module) && module.AdsTarget;

/// <summary>
/// Gets a value indicating whether the firearm's flashlight module is enabled.
Expand All @@ -156,7 +244,7 @@ public int MaxAmmo
/// <summary>
/// Gets a value indicating whether the firearm is automatic.
/// </summary>
public bool IsAutomatic => Array.Exists(Base.Modules, x => x is AutomaticActionModule);
public bool IsAutomatic => BarrelMagazine is AutomaticBarrelMagazine;

/// <summary>
/// Gets the <see cref="Attachment"/>s of the firearm.
Expand All @@ -180,47 +268,21 @@ public IEnumerable<AttachmentIdentifier> AttachmentIdentifiers
/// </summary>
public uint BaseCode => BaseCodesValue[FirearmType];

/// <summary>
/// Gets or sets the fire rate of the firearm, if it is an automatic weapon.
/// </summary>
/// <remarks>This property will not do anything if the firearm is not an automatic weapon.</remarks>
/// <seealso cref="IsAutomatic"/>
public float FireRate
{
get => Base.Modules.OfType<AutomaticActionModule>().FirstOrDefault()?.BaseFireRate ?? 0f;
set
{
AutomaticActionModule module = Base.Modules.OfType<AutomaticActionModule>().FirstOrDefault();

if (module != null)
module.BaseFireRate = value;
}
}

/// <summary>
/// Gets or sets the recoil settings of the firearm, if it's an automatic weapon.
/// </summary>
/// <remarks>This property will not do anything if the firearm is not an automatic weapon.</remarks>
/// <seealso cref="IsAutomatic"/>
public RecoilSettings Recoil
{
get => Base.Modules.OfType<RecoilPatternModule>().FirstOrDefault()?.BaseRecoil ?? default;
get => Base.TryGetModule(out RecoilPatternModule module) ? module.BaseRecoil : default;
set
{
RecoilPatternModule module = Base.Modules.OfType<RecoilPatternModule>().FirstOrDefault();

if (module != null)
if (Base.TryGetModule(out RecoilPatternModule module))
module.BaseRecoil = value;
}
}

/*
/// <summary>
/// Gets the firearm's <see cref="FirearmRecoilPattern"/>. Will be <see langword="null"/> for non-automatic weapons.
/// </summary>
public FirearmRecoilPattern RecoilPattern => Base is AutomaticFirearm auto ? auto._recoilPattern : null;
*/

/// <summary>
/// Gets a <see cref="Dictionary{TKey, TValue}"/> of <see cref="ItemType"/> and <see cref="AttachmentIdentifier"/>[] which contains all available attachments for all firearms.
/// </summary>
Expand Down Expand Up @@ -587,23 +649,15 @@ public void ClearPreferences()
/// <summary>
/// Reloads current <see cref="Firearm"/>.
/// </summary>
/// <param name="emptyMagazine">Whether empty magazine should be loaded.</param>
public void Reload(bool emptyMagazine = false)
/// <remarks>
/// For specific reloading logic you also can use <see cref="NormalMagazine"/> for avaible weapons.
/// </remarks>
public void Reload()
{
MagazineModule magazineModule = Base.Modules.OfType<MagazineModule>().FirstOrDefault();

if (magazineModule == null)
return;

magazineModule.ServerRemoveMagazine();

Timing.CallDelayed(0.1f, () =>
if (Base.TryGetModule(out AnimatorReloaderModuleBase module))
{
if (emptyMagazine)
magazineModule.ServerInsertEmptyMagazine();
else
magazineModule.ServerInsertMagazine();
});
module.StartReloading();
}
}

/// <summary>
Expand All @@ -614,7 +668,6 @@ public override Item Clone()
{
Firearm cloneableItem = new(Type)
{
Ammo = Ammo,
};

// TODO Not finish
Expand All @@ -639,6 +692,10 @@ internal override void ChangeOwner(Player oldOwner, Player newOwner)
{
Base.Owner = newOwner.ReferenceHub;
Base._footprintCacheSet = false;
foreach (ModuleBase module in Base.Modules)
{
module.OnAdded();
}
}

/// <inheritdoc/>
Expand All @@ -648,8 +705,8 @@ internal override void ReadPickupInfo(Pickup pickup)

if (pickup is FirearmPickup firearmPickup)
{
// TODO If synced
// MaxAmmo = firearmPickup.MaxAmmo;
PrimaryMagazine.MaxAmmo = firearmPickup.MaxAmmo;
AmmoDrain = firearmPickup.AmmoDrain;
}
}
}
Expand Down
Loading