diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 4d67329a6..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file - -version: 2 -updates: - - package-ecosystem: "nuget" # See documentation for possible values - directory: "./EXILED" # Location of package manifests - schedule: - interval: "weekly" diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 16ff4dafa..7ee77d48a 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -4,9 +4,11 @@ on: push: branches: - dev + - scpsl14 pull_request: branches: - dev + - scpsl14 workflow_dispatch: defaults: diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml index a54bed971..6e2248852 100644 --- a/.github/workflows/pull_request_opened.yml +++ b/.github/workflows/pull_request_opened.yml @@ -1,7 +1,9 @@ -name: Labeler +name: Pull Request CI on: - - pull_request_target + pull_request_target: + branches: + - '**' defaults: run: @@ -9,21 +11,28 @@ defaults: jobs: set-labels: + name: Set Labels permissions: contents: read pull-requests: write runs-on: ubuntu-latest steps: - - name: Labeler - uses: actions/labeler@v5.0.0 + - uses: actions/labeler@v5.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} configuration-path: .github/labeler.yml sync-labels: true assign-author: + name: Assign Author runs-on: ubuntu-latest permissions: pull-requests: write - steps: - uses: toshimaru/auto-author-assign@v2.1.1 + validate-pr-title: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/push_nuget.yml b/.github/workflows/push_nuget.yml index 87acc59b8..5150b0c7e 100644 --- a/.github/workflows/push_nuget.yml +++ b/.github/workflows/push_nuget.yml @@ -10,7 +10,7 @@ defaults: working-directory: ./EXILED env: - EXILED_REFERENCES_URL: https://ExMod-Team.github.io/SL-References/Master.zip + EXILED_REFERENCES_URL: https://ExMod-Team.github.io/SL-References/Dev.zip EXILED_REFERENCES_PATH: ${{ github.workspace }}/EXILED/References jobs: diff --git a/.gitignore b/.gitignore index ecdece2bb..958e3428c 100644 --- a/.gitignore +++ b/.gitignore @@ -373,4 +373,7 @@ NuGet.config _site/ # JSON Schemas -JSON/ \ No newline at end of file +JSON/ + +# Mac DS_Store +.DS_Store \ No newline at end of file diff --git a/EXILED/EXILED.props b/EXILED/EXILED.props index 62d6e57cd..c9b421e84 100644 --- a/EXILED/EXILED.props +++ b/EXILED/EXILED.props @@ -2,7 +2,7 @@ - Exiled Official + ExMod Team @@ -15,7 +15,7 @@ - 8.14.1 + 9.0.0 false diff --git a/EXILED/Exiled.API/Enums/AdminToyType.cs b/EXILED/Exiled.API/Enums/AdminToyType.cs index 181c62552..c7f937721 100644 --- a/EXILED/Exiled.API/Enums/AdminToyType.cs +++ b/EXILED/Exiled.API/Enums/AdminToyType.cs @@ -27,5 +27,10 @@ public enum AdminToyType /// ShootingTarget toy. /// ShootingTarget, + + /// + /// Speaker toy. + /// + Speaker, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/CameraType.cs b/EXILED/Exiled.API/Enums/CameraType.cs index 26685fa8e..6248d2a24 100644 --- a/EXILED/Exiled.API/Enums/CameraType.cs +++ b/EXILED/Exiled.API/Enums/CameraType.cs @@ -68,9 +68,6 @@ public enum CameraType HczElevSysB, HczHallway, HczThreeWay, - HczServersBottom, - HczServersStairs, - HczServersTop, HczTeslaGate, HczTestroomBridge, HczTestroomMain, @@ -124,6 +121,19 @@ public enum CameraType Hcz173ContChamber, Hcz173Hallway, HczCurve, + HczJunkMain, + HczJunkHallway, + HczCornerDeep, + HczDSS08, + HczMicroHIDStairs, + HczPipesHallway, + HczWarheadStarboardElevator, + HczMicroHIDMain, + HczWarheadTopElevators, + HczWarheadConnector, + HczWarheadPortElevator, + HczMicroHIDLab, + HczPipesMain, #endregion } } diff --git a/EXILED/Exiled.API/Enums/DamageType.cs b/EXILED/Exiled.API/Enums/DamageType.cs index f9d1617f6..add8d86ca 100644 --- a/EXILED/Exiled.API/Enums/DamageType.cs +++ b/EXILED/Exiled.API/Enums/DamageType.cs @@ -120,6 +120,11 @@ public enum DamageType /// SeveredHands, + /// + /// Damage caused by severed eyes. + /// + SeveredEyes, + /// /// Damage caused by a custom source. /// @@ -250,4 +255,4 @@ public enum DamageType /// Marshmallow, } -} +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/DisruptorMode.cs b/EXILED/Exiled.API/Enums/DisruptorMode.cs new file mode 100644 index 000000000..643ed0c30 --- /dev/null +++ b/EXILED/Exiled.API/Enums/DisruptorMode.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Enums +{ + /// + /// Represents disruptor's fire modes. + /// + public enum DisruptorMode + { + /// + /// Unknown mode. + /// + None, + + /// + /// Single shot mode. + /// + Disintegrator, + + /// + /// Triple shot mode. + /// + BurstFire, + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/DoorType.cs b/EXILED/Exiled.API/Enums/DoorType.cs index 04f38c19d..36bb9b853 100644 --- a/EXILED/Exiled.API/Enums/DoorType.cs +++ b/EXILED/Exiled.API/Enums/DoorType.cs @@ -8,8 +8,7 @@ namespace Exiled.API.Enums { using Exiled.API.Features.Doors; - - using static Interactables.Interobjects.ElevatorManager; + using Interactables.Interobjects; /// /// Unique identifier for the different types of doors. @@ -133,11 +132,6 @@ public enum DoorType /// EscapeSecondary, - /// - /// Represents the SERVERS_BOTTOM door. - /// - ServersBottom, - /// /// Represents the GATE_A door. /// @@ -159,19 +153,24 @@ public enum DoorType HeavyContainmentDoor, /// - /// Represents the HID door. + /// Represents any heavy containment styled door. + /// + HeavyBulkDoor, + + /// + /// Represents the HID_CHAMBER door. /// - HID, + HIDChamber, /// - /// Represents the HID_LEFT door. + /// Represents the HID_UPPER door. /// - HIDLeft, + HIDUpper, /// - /// Represents the HID_RIGHT door. + /// Represents the HID_LOWER door. /// - HIDRight, + HIDLower, /// /// Represents the INTERCOM door. @@ -231,7 +230,12 @@ public enum DoorType /// /// Represents the Gate in the Checkpoint between EZ and HCZ. /// - CheckpointGate, + CheckpointGateA, + + /// + /// Represents the Gate in the Checkpoint between EZ and HCZ. + /// + CheckpointGateB, /// /// Represents the Gate in the Checkpoint between EZ and HCZ. @@ -269,7 +273,7 @@ public enum DoorType ElevatorGateB, /// - /// Represents the Elevator door for . + /// Represents the Elevator door for . /// ElevatorNuke, @@ -307,5 +311,10 @@ public enum DoorType /// Represents the New Gate where Scp173 spawn in the . /// Scp173NewGate, + + /// + /// Represents the ESCAPE_FINAL door. + /// + EscapeFinal, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 2ba874dd8..b2894486e 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -21,7 +21,7 @@ public enum EffectType /// /// This EffectType do not exist it's only use when not found or error. /// - None = -1, // TODO: remove = -1 + None, /// /// The player isn't able to open their inventory or reload a weapon. @@ -239,5 +239,25 @@ public enum EffectType /// . /// Slowness, + + /// + /// . + /// + Scp1344, + + /// + /// . + /// + SeveredEyes, + + /// + /// . + /// + PitDeath, + + /// + /// . + /// + Blurred, } } diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index a11f6aff6..7ec8a851c 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -16,10 +16,10 @@ public enum PrefabType { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable SA1602 // Enumeration items should be documented - [Prefab(1883254029, "Player")] + [Prefab(3816198336, "Player")] Player, - [Prefab(2295511789, "EZ BreakableDoor")] + [Prefab(1883254029, "EZ BreakableDoor")] EZBreakableDoor, [Prefab(2295511789, "HCZ BreakableDoor")] @@ -28,6 +28,42 @@ public enum PrefabType [Prefab(3038351124, "LCZ BreakableDoor")] LCZBreakableDoor, + [Prefab(400539138, "HCZ OneSided")] + HCZOneSided, + + [Prefab(2060920286, "HCZ TwoSided")] + HCZTwoSided, + + [Prefab(3343949480, "OpenHallway")] + HCZOpenHallway, + + [Prefab(3999209566, "OpenHallway Construct A")] + HCZOpenHallway_Construct_A, + + [Prefab(38976586, "OpenHallway Clutter A")] + HCZOpenHallway_Clutter_A, + + [Prefab(1687661105, "OpenHallway Clutter B")] + HCZOpenHallway_Clutter_B, + + [Prefab(147203050, "OpenHallway Clutter C")] + HCZOpenHallway_Clutter_C, + + [Prefab(1102032353, "OpenHallway Clutter D")] + HCZOpenHallway_Clutter_D, + + [Prefab(2490430134, "OpenHallway Clutter E")] + HCZOpenHallway_Clutter_E, + + [Prefab(2673083832, "OpenHallway Clutter F")] + HCZOpenHallway_Clutter_F, + + [Prefab(2536312960, "OpenHallway Clutter G")] + HCZOpenHallway_Clutter_G, + + [Prefab(2176035362, "HCZ BulkDoor")] + HCZBulkDoor, + [Prefab(1704345398, "sportTargetPrefab")] SportTarget, @@ -46,6 +82,9 @@ public enum PrefabType [Prefab(3956448839, "LightSourceToy")] LightSourceToy, + [Prefab(712426663, "SpeakerToy")] + SpeakerToy, + [Prefab(2672653014, "RegularKeycardPickup")] RegularKeycardPickup, @@ -55,6 +94,9 @@ public enum PrefabType [Prefab(248357067, "RadioPickup")] RadioPickup, + [Prefab(1925130715, "FirearmPickup")] + FirearmPickup, + [Prefab(1925130715, "Com15Pickup")] Com15Pickup, @@ -181,6 +223,9 @@ public enum PrefabType [Prefab(3532394942, "LanternPickup")] LanternPickup, + [Prefab(4143962266, "SCP1344Pickup")] + Scp1344Pickup, + [Prefab(825024811, "Amnestic Cloud Hazard")] AmnesticCloudHazard, @@ -208,9 +253,18 @@ public enum PrefabType [Prefab(3372339835, "Scp1576PedestalStructure Variant")] Scp1576PedestalStructure, + [Prefab(2399831573, "AntiScp207PedestalStructure Variant")] + AntiScp207PedestalStructure, + + [Prefab(1763950070, "Scp1344PedestalStructure Variant")] + Scp1344PedestalStructure, + [Prefab(2830750618, "LargeGunLockerStructure")] LargeGunLockerStructure, + [Prefab(2372810204, "Experimental Weapon Locker")] + ExperimentalLockerStructure, + [Prefab(3352879624, "RifleRackStructure")] RifleRackStructure, @@ -273,5 +327,14 @@ public enum PrefabType [Prefab(3721192489, "Scp3114_Ragdoll")] Scp3114Ragdoll, + + [Prefab(2588580243, "ElevatorChamber")] + ElevatorChamber, + + [Prefab(1757973841, "ElevatorChamber_Gates")] + ElevatorChamber_Gates, + + [Prefab(912031041, "ElevatorChamberNuke")] + ElevatorChamberNuke, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RespawnEffectType.cs b/EXILED/Exiled.API/Enums/RespawnEffectType.cs index 672f26d40..672abb197 100644 --- a/EXILED/Exiled.API/Enums/RespawnEffectType.cs +++ b/EXILED/Exiled.API/Enums/RespawnEffectType.cs @@ -14,23 +14,16 @@ namespace Exiled.API.Enums /// /// Layers game respawn effects. /// - /// - /// - public enum RespawnEffectType : byte + public enum RespawnEffectType { - /// - /// Plays the music to alive and . - /// - PlayChaosInsurgencyMusic = 0, - /// /// Summons the van. /// - SummonChaosInsurgencyVan = 128, + SummonChaosInsurgencyVan, /// /// Summons the NTF chopper. /// - SummonNtfChopper = 129, + SummonNtfChopper, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/RevolverChamberState.cs b/EXILED/Exiled.API/Enums/RevolverChamberState.cs new file mode 100644 index 000000000..421f18587 --- /dev/null +++ b/EXILED/Exiled.API/Enums/RevolverChamberState.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Enums +{ + using Exiled.API.Features.Items.FirearmModules.Primary; + + /// + /// States for chamber in revolver cylindric magazine. + /// + /// + public enum RevolverChamberState + { + /// + /// State for empty chamber. + /// + Empty, + + /// + /// State for chamber with a bullet. + /// + Live, + + /// + /// State for discharged chamber. + /// + Discharged, + } +} diff --git a/EXILED/Exiled.API/Enums/RoomType.cs b/EXILED/Exiled.API/Enums/RoomType.cs index 370bac2af..054029601 100644 --- a/EXILED/Exiled.API/Enums/RoomType.cs +++ b/EXILED/Exiled.API/Enums/RoomType.cs @@ -149,16 +149,6 @@ public enum RoomType /// HczTesla, - /// - /// Heavy Containment Zone's Servers room. - /// - HczServers, - - /// - /// Heavy Containment Zone's 3-way intersection. - /// - HczTCross, - /// /// Heavy Containment Zone's cruved hall. /// @@ -210,15 +200,25 @@ public enum RoomType EzCollapsedTunnel, /// - /// Entrance Zone's straight hall with Dr.L's locked room. + /// Entrance Zone's straight hall with Dr.L's or Dr. Gear's locked room. /// EzConference, /// - /// Entrance Zone's straight hall + /// Entrance Zone's straight hall with Chef's locked room. + /// + EzChef, + + /// + /// Entrance Zone's straight hall. /// EzStraight, + /// + /// Entrance Zone's straight hall with a different placement of seasonal objects. + /// + EzStraightColumn, + /// /// Entrance Zone's Cafeteria Room. /// @@ -250,7 +250,7 @@ public enum RoomType Surface, /// - /// Heavy Containment Zone's straight hall. + /// Heavy Containment Zone's straight hall with ceiling fan. /// HczStraight, @@ -260,14 +260,19 @@ public enum RoomType EzTCross, /// - /// Light Containment ZOne's SCP-330 room. + /// Light Containment Zone's SCP-330 room. /// Lcz330, /// /// Entrance Zone's straight hall before the entrance/heavy checkpoint. /// - EzCheckpointHallway, + EzCheckpointHallwayA, + + /// + /// Entrance Zone's straight hall before the entrance/heavy checkpoint. + /// + EzCheckpointHallwayB, /// /// Heavy Containment Zone's test room's straight hall. @@ -283,5 +288,45 @@ public enum RoomType /// Heavy Containment Elevator Zone's System B room. /// HczElevatorB, + + /// + /// Heavy Containment Zone's cross room with waterfall. + /// + HczCrossRoomWater, + + /// + /// Heavy Containment Zone's corner. + /// + HczCornerDeep, + + /// + /// Heavy Containment Zone's 3-way intersection with storage crates obstructing the passage. + /// + HczIntersectionJunk, + + /// + /// Heavy Containment Zone's 3-way intersection. + /// + HczIntersection, + + /// + /// Heavy Containment Zone's straight hall with pipelines and sanitary door. + /// + HczStraightC, + + /// + /// Heavy Containment Zone's straight hall with pipelines obstructing the passage. + /// + HczStraightPipeRoom, + + /// + /// Heavy Containment Zone's straight hall. + /// + HczStraightVariant, + + /// + /// Entrance Zone's straight hall with Dr.L's and conference room 9b locked room. + /// + EzSmallrooms, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/SpawnLocationType.cs b/EXILED/Exiled.API/Enums/SpawnLocationType.cs index 927542ffe..0cd2c6dde 100644 --- a/EXILED/Exiled.API/Enums/SpawnLocationType.cs +++ b/EXILED/Exiled.API/Enums/SpawnLocationType.cs @@ -142,16 +142,5 @@ public enum SpawnLocationType /// Just inside the LCZ WC door. /// InsideLczWc, - - /// - /// Just inside the door at the bottom of the server's room. - /// - InsideServersBottom, - - /// - /// Inside a random locker on the map. - /// - [Obsolete("Use LockerSpawnPoint instead")] - InsideLocker, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/SpawnableFaction.cs b/EXILED/Exiled.API/Enums/SpawnableFaction.cs new file mode 100644 index 000000000..0903253fc --- /dev/null +++ b/EXILED/Exiled.API/Enums/SpawnableFaction.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Enums +{ + /// + /// All spawnable factions. + /// + public enum SpawnableFaction + { + /// + /// Represents no wave. + /// + None, + + /// + /// Normal NTF wave. + /// + NtfWave, + + /// + /// Normal Chaos wave. + /// + ChaosWave, + + /// + /// Mini NTF wave. + /// + NtfMiniWave, + + /// + /// Mini Chaos wave. + /// + ChaosMiniWave, + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Enums/ZoneType.cs b/EXILED/Exiled.API/Enums/ZoneType.cs index 7e80190ba..382833528 100644 --- a/EXILED/Exiled.API/Enums/ZoneType.cs +++ b/EXILED/Exiled.API/Enums/ZoneType.cs @@ -51,9 +51,14 @@ public enum ZoneType /// Surface = 8, + /// + /// The Pocket Dimension. + /// + Pocket = 16, + /// /// An unknown type of zone. /// - Other = 16, + Other = 32, } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Exiled.API.csproj b/EXILED/Exiled.API/Exiled.API.csproj index e0949b7ff..988d63157 100644 --- a/EXILED/Exiled.API/Exiled.API.csproj +++ b/EXILED/Exiled.API/Exiled.API.csproj @@ -32,11 +32,10 @@ + - - $(EXILED_REFERENCES)\UnityEngine.ParticleSystemModule.dll - + diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index aba321a8d..bb2a246f1 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -49,6 +49,7 @@ public static class DamageTypeExtensions { DeathTranslations.MicroHID.Id, DamageType.MicroHid }, { DeathTranslations.Hypothermia.Id, DamageType.Hypothermia }, { DeathTranslations.MarshmallowMan.Id, DamageType.Marshmallow }, + { DeathTranslations.Scp1344.Id, DamageType.SeveredEyes }, }; private static readonly Dictionary TranslationConversionInternal = new() @@ -80,6 +81,7 @@ public static class DamageTypeExtensions { DeathTranslations.MicroHID, DamageType.MicroHid }, { DeathTranslations.Hypothermia, DamageType.Hypothermia }, { DeathTranslations.MarshmallowMan, DamageType.Marshmallow }, + { DeathTranslations.Scp1344, DamageType.SeveredEyes }, }; private static readonly Dictionary ItemConversionInternal = new() diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index f602bcdae..0b977356e 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -33,7 +33,7 @@ public static class EffectTypeExtension { EffectType.AmnesiaVision, typeof(AmnesiaVision) }, { EffectType.Asphyxiated, typeof(Asphyxiated) }, { EffectType.Bleeding, typeof(Bleeding) }, - { EffectType.Blinded, typeof(Blinded) }, + { EffectType.Blinded, typeof(Blindness) }, { EffectType.BodyshotReduction, typeof(BodyshotReduction) }, { EffectType.Burned, typeof(Burned) }, { EffectType.CardiacArrest, typeof(CardiacArrest) }, @@ -74,6 +74,10 @@ public static class EffectTypeExtension { EffectType.Ghostly, typeof(Ghostly) }, { EffectType.FogControl, typeof(FogControl) }, { EffectType.Slowness, typeof(Slowness) }, + { EffectType.Scp1344, typeof(Scp1344) }, + { EffectType.SeveredEyes, typeof(SeveredEyes) }, + { EffectType.PitDeath, typeof(PitDeath) }, + { EffectType.Blurred, typeof(Blurred) }, }); /// @@ -146,7 +150,7 @@ or EffectType.Corroding or EffectType.Decontaminating or EffectType.Hemorrhage o /// The . /// Whether the effect heals. /// - public static bool IsHealing(this EffectType effect) => effect.TryGetType(out Type type) && typeof(IHealablePlayerEffect).IsAssignableFrom(type); + public static bool IsHealing(this EffectType effect) => effect.TryGetType(out Type type) && typeof(IHealableEffect).IsAssignableFrom(type); /// /// Returns whether the provided is a negative effect. diff --git a/EXILED/Exiled.API/Extensions/ItemExtensions.cs b/EXILED/Exiled.API/Extensions/ItemExtensions.cs index c0fda94b1..3fc97516f 100644 --- a/EXILED/Exiled.API/Extensions/ItemExtensions.cs +++ b/EXILED/Exiled.API/Extensions/ItemExtensions.cs @@ -18,6 +18,7 @@ namespace Exiled.API.Extensions using InventorySystem; using InventorySystem.Items; using InventorySystem.Items.Firearms.Attachments; + using InventorySystem.Items.Firearms.Modules; using InventorySystem.Items.Pickups; using Structs; @@ -123,12 +124,12 @@ public static T GetItemBase(this ItemType type) /// /// The weapon that you want to get maximum of. /// Returns the maximum. - public static byte GetMaxAmmo(this FirearmType item) + public static int GetMaxAmmo(this FirearmType item) { if (!InventoryItemLoader.AvailableItems.TryGetValue(item.GetItemType(), out ItemBase itemBase) || itemBase is not InventorySystem.Items.Firearms.Firearm firearm) return 0; - return firearm.AmmoManagerModule.MaxAmmo; + return (firearm.Modules.FirstOrDefault(x => x is IAmmoContainerModule) as IAmmoContainerModule).AmmoMax; } /// @@ -323,5 +324,13 @@ public static uint GetBaseCode(this FirearmType type) /// The to check. /// of the specified . public static ItemCategory GetCategory(this ItemType type) => GetItemBase(type).Category; + + /// + /// Checks if the specified has the specified . + /// + /// Weapon to check. + /// Attachment to check. + /// true if weapon has the specified attachment. Otherwise, false. + public static bool HasAttachment(this Firearm firearm, AttachmentName attachment) => firearm.Attachments.FirstOrDefault(x => x.Name == attachment)?.IsEnabled ?? false; } } diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs index f8c49599f..1e8187c09 100644 --- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs +++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs @@ -19,8 +19,6 @@ namespace Exiled.API.Extensions using Features; using Features.Pools; - using InventorySystem.Items.Firearms; - using Mirror; using PlayerRoles; @@ -151,7 +149,7 @@ public static ReadOnlyDictionary RpcFullNames /// Plays a beep sound that only the target can hear. /// /// Target to play sound to. - public static void PlayBeepSound(this Player player) => SendFakeTargetRpc(player, ReferenceHub.HostHub.networkIdentity, typeof(AmbientSoundPlayer), nameof(AmbientSoundPlayer.RpcPlaySound), 7); + public static void PlayBeepSound(this Player player) => SendFakeTargetRpc(player, ReferenceHub._hostHub.networkIdentity, typeof(AmbientSoundPlayer), nameof(AmbientSoundPlayer.RpcPlaySound), 7); /// /// Set on the player that only the can see. @@ -171,6 +169,8 @@ public static ReadOnlyDictionary RpcFullNames /// GunAudioMessage's audioClipId to set (default = 0). public static void PlayGunSound(this Player player, Vector3 position, ItemType itemType, byte volume, byte audioClipId = 0) { + // TODO: Not finish + /* GunAudioMessage message = new() { Weapon = itemType, @@ -180,7 +180,7 @@ public static void PlayGunSound(this Player player, Vector3 position, ItemType i ShooterPosition = new RelativePosition(position), }; - player.Connection.Send(message); + player.Connection.Send(message);*/ } /// @@ -222,17 +222,6 @@ public static void SetName(this Player target, Player player, string name) target.SendFakeSyncVar(player.NetworkIdentity, typeof(NicknameSync), nameof(NicknameSync.Network_displayName), name); } - /// - /// Sets of a that only the player can see. - /// - /// Room to modify. - /// Only this player can see room color. - /// Light intensity multiplier to set. - [Obsolete("This features has been remove by NW", true)] - public static void SetRoomLightIntensityForTargetOnly(this Room room, Player target, float multiplier) - { - } - /// /// Change character model for appearance. /// It will continue until 's changes. @@ -462,38 +451,6 @@ public static void ScaleNetworkIdentityObject(this NetworkIdentity identity, Vec } } - /// - /// Send fake values to client's . - /// - /// Target to send. - /// of object that owns . - /// 's type. - /// Property name starting with Network. - /// Value of send to target. - [Obsolete("Use overload with type-template instead.")] - public static void SendFakeSyncVar(this Player target, NetworkIdentity behaviorOwner, Type targetType, string propertyName, object value) - { - if (!target.IsConnected) - return; - - NetworkWriterPooled writer = NetworkWriterPool.Get(); - NetworkWriterPooled writer2 = NetworkWriterPool.Get(); - MakeCustomSyncWriter(behaviorOwner, targetType, null, CustomSyncVarGenerator, writer, writer2); - target.Connection.Send(new EntityStateMessage - { - netId = behaviorOwner.netId, - payload = writer.ToArraySegment(), - }); - - NetworkWriterPool.Return(writer); - NetworkWriterPool.Return(writer2); - void CustomSyncVarGenerator(NetworkWriter targetWriter) - { - targetWriter.WriteULong(SyncVarDirtyBits[$"{targetType.Name}.{propertyName}"]); - WriterExtensions[value.GetType()]?.Invoke(null, new object[2] { targetWriter, value }); - } - } - /// /// Send fake values to client's . /// diff --git a/EXILED/Exiled.API/Extensions/RoleExtensions.cs b/EXILED/Exiled.API/Extensions/RoleExtensions.cs index c36592500..369910654 100644 --- a/EXILED/Exiled.API/Extensions/RoleExtensions.cs +++ b/EXILED/Exiled.API/Extensions/RoleExtensions.cs @@ -12,12 +12,14 @@ namespace Exiled.API.Extensions using System.Linq; using Enums; - using Exiled.API.Features.Spawn; + using Features.Spawn; + using Footprinting; using InventorySystem; using InventorySystem.Configs; using PlayerRoles; using PlayerRoles.FirstPersonControl; - + using Respawning; + using Respawning.Waves; using UnityEngine; using Team = PlayerRoles.Team; @@ -27,6 +29,22 @@ namespace Exiled.API.Extensions /// public static class RoleExtensions { + /// + /// Compares LifeIdentifier. + /// + /// The footprint to compare. + /// The other footprint. + /// If LifeIdentifier is the same (same role). + public static bool CompareLife(this Footprint footprint, Footprint other) => footprint.LifeIdentifier == other.LifeIdentifier; + + /// + /// Compares LifeIdentifier. + /// + /// The footprint to compare. + /// The hub to compare to. + /// If LifeIdentifier is the same (same role). + public static bool CompareLife(this Footprint footprint, ReferenceHub other) => footprint.LifeIdentifier == other.roleManager.CurrentRole.UniqueLifeIdentifier; + /// /// Gets a role's . /// @@ -210,5 +228,56 @@ public static Dictionary GetStartingAmmo(this RoleTypeId roleT return info.Ammo.ToDictionary(kvp => kvp.Key.GetAmmoType(), kvp => kvp.Value); } + + /// + /// Gets the of a . + /// + /// A instance. + /// associated with the wave. + public static SpawnableFaction GetSpawnableFaction(this SpawnableWaveBase waveBase) => waveBase switch + { + NtfSpawnWave => SpawnableFaction.NtfWave, + NtfMiniWave => SpawnableFaction.NtfMiniWave, + ChaosSpawnWave => SpawnableFaction.ChaosWave, + ChaosMiniWave => SpawnableFaction.ChaosMiniWave, + _ => SpawnableFaction.None + }; + + /// + /// Gets the associated with the provided . + /// + /// A member of the enum. + /// associated with the provided . + public static Faction GetFaction(this SpawnableFaction spawnableFaction) => spawnableFaction switch + { + SpawnableFaction.ChaosWave or SpawnableFaction.ChaosMiniWave => Faction.FoundationEnemy, + SpawnableFaction.NtfWave or SpawnableFaction.NtfMiniWave => Faction.FoundationStaff, + _ => Faction.Unclassified, + }; + + /// + /// Tries to get the associated with the provided and . + /// + /// A member of the enum. + /// The to return. + /// A determining whether to get a normal spawn wave or a mini one. + /// associated with the provided influenced by . + public static bool TryGetSpawnableFaction(this Faction faction, out SpawnableFaction spawnableFaction, bool mini = false) + { + switch (faction) + { + case Faction.FoundationStaff: + spawnableFaction = mini ? SpawnableFaction.NtfMiniWave : SpawnableFaction.NtfWave; + break; + case Faction.FoundationEnemy: + spawnableFaction = mini ? SpawnableFaction.ChaosMiniWave : SpawnableFaction.ChaosWave; + break; + default: + spawnableFaction = SpawnableFaction.None; + return false; + } + + return true; + } } } diff --git a/EXILED/Exiled.API/Extensions/SpawnExtensions.cs b/EXILED/Exiled.API/Extensions/SpawnExtensions.cs index 2eed0d7ea..5c1c31f89 100644 --- a/EXILED/Exiled.API/Extensions/SpawnExtensions.cs +++ b/EXILED/Exiled.API/Extensions/SpawnExtensions.cs @@ -23,7 +23,6 @@ public static class SpawnExtensions /// public static readonly SpawnLocationType[] ReversedLocations = { - SpawnLocationType.InsideServersBottom, SpawnLocationType.InsideHczArmory, SpawnLocationType.Inside079First, SpawnLocationType.InsideHidRight, @@ -103,7 +102,6 @@ public static Vector3 GetPosition(this SpawnLocationType location) SpawnLocationType.InsideSurfaceNuke => "SURFACE_NUKE", SpawnLocationType.Inside079Secondary => "079_SECOND", SpawnLocationType.Inside173Connector => "173_CONNECTOR", - SpawnLocationType.InsideServersBottom => "SERVERS_BOTTOM", SpawnLocationType.InsideEscapePrimary => "ESCAPE_PRIMARY", SpawnLocationType.InsideEscapeSecondary => "ESCAPE_SECONDARY", _ => default, diff --git a/EXILED/Exiled.API/Extensions/StringExtensions.cs b/EXILED/Exiled.API/Extensions/StringExtensions.cs index 2d0f9a0d7..1cc8dc7c3 100644 --- a/EXILED/Exiled.API/Extensions/StringExtensions.cs +++ b/EXILED/Exiled.API/Extensions/StringExtensions.cs @@ -119,10 +119,10 @@ public static string ToString(this IEnumerable enumerable, bool showIndex /// Name without brackets. public static string RemoveBracketsOnEndOfName(this string name) { - int bracketStart = name.IndexOf('(') - 1; + int bracketStart = name.IndexOf('('); if (bracketStart > 0) - name = name.Remove(bracketStart, name.Length - bracketStart); + name = name.Remove(bracketStart, name.Length - bracketStart).TrimEnd(); return name; } diff --git a/EXILED/Exiled.API/Features/BanManager.cs b/EXILED/Exiled.API/Features/BanManager.cs new file mode 100644 index 000000000..219c272eb --- /dev/null +++ b/EXILED/Exiled.API/Features/BanManager.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features +{ + using System; + + /// + /// Useful class to manage player bans. + /// + public static class BanManager + { + /// + /// Bans an offline player. + /// + /// Type of the ban (UserID/IP). + /// The UserID or IP address to ban. + /// The ban reason. + /// A representing the duration. + /// The Nickname of the ban issuer. + /// Whether the ban was successful. + public static bool OfflineBanPlayer(BanHandler.BanType banType, string id, string reason, TimeSpan duration, string issuer = "SERVER CONSOLE") => OfflineBanPlayer(banType, id, reason, duration.TotalSeconds, issuer); + + /// + /// Bans an offline player. + /// + /// Type of the ban (UserID/IP). + /// The UserID or IP address to ban. + /// The ban reason. + /// Duration in seconds. + /// The Nickname of the ban issuer. + /// Whether the ban was successful. + public static bool OfflineBanPlayer(BanHandler.BanType banType, string id, string reason, double duration, string issuer = "SERVER CONSOLE") + { + BanDetails details = new() + { + OriginalName = "Unknown - offline ban", + Id = id, + IssuanceTime = DateTime.UtcNow.Ticks, + Expires = DateTime.UtcNow.AddSeconds(duration).Ticks, + Reason = reason, + Issuer = issuer, + }; + return BanHandler.IssueBan(details, banType); + } + + /// + /// Unbans a player. + /// + /// Type of the ban (UserID/IP). + /// The UserID or IP address to ban.\ + public static void UnbanPlayer(BanHandler.BanType banType, string id) => BanHandler.RemoveBan(id, banType); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Camera.cs b/EXILED/Exiled.API/Features/Camera.cs index 5db5dd28f..6c7248573 100644 --- a/EXILED/Exiled.API/Features/Camera.cs +++ b/EXILED/Exiled.API/Features/Camera.cs @@ -77,9 +77,6 @@ public class Camera : IWrapper, IWorldSpace ["HCZ ELEV SYS B"] = CameraType.HczElevSysB, ["HCZ HALLWAY"] = CameraType.HczHallway, ["HCZ THREE-WAY"] = CameraType.HczThreeWay, - ["SERVERS BOTTOM"] = CameraType.HczServersBottom, - ["SERVERS STAIRS"] = CameraType.HczServersStairs, - ["SERVERS TOP"] = CameraType.HczServersTop, ["TESLA GATE"] = CameraType.HczTeslaGate, ["TESTROOM BRIDGE"] = CameraType.HczTestroomBridge, ["TESTROOM MAIN"] = CameraType.HczTestroomMain, @@ -124,6 +121,21 @@ public class Camera : IWrapper, IWorldSpace ["SURFACE AIRLOCK"] = CameraType.SurfaceAirlock, ["SURFACE BRIDGE"] = CameraType.SurfaceBridge, ["TUNNEL ENTRANCE"] = CameraType.TunnelEntrance, + + // new + ["JUNK MAIN"] = CameraType.HczJunkMain, + ["JUNK HALLWAY"] = CameraType.HczJunkHallway, + ["CORNER DEEP"] = CameraType.HczCornerDeep, + ["DSS-08"] = CameraType.HczDSS08, + ["MICROHID STAIRS"] = CameraType.HczMicroHIDStairs, + ["PIPES HALLWAY"] = CameraType.HczPipesHallway, + ["PIPES MAIN"] = CameraType.HczPipesMain, + ["WARHEAD STARBOARD ELEVATOR"] = CameraType.HczWarheadStarboardElevator, + ["MICROHID MAIN"] = CameraType.HczMicroHIDMain, + ["MICROHID LAB"] = CameraType.HczMicroHIDLab, + ["WARHEAD TOP ELEVATORS"] = CameraType.HczWarheadTopElevators, + ["WARHEAD CONNECTOR"] = CameraType.HczWarheadConnector, + ["WARHEAD PORT ELEVATOR"] = CameraType.HczWarheadPortElevator, }; private Room room; @@ -137,9 +149,9 @@ internal Camera(Scp079Camera camera079) Base = camera079; Camera079ToCamera.Add(camera079, this); Type = GetCameraType(); -#if Debug +#if DEBUG if (Type is CameraType.Unknown) - Log.Error($"[CAMERATYPE UNKNOWN] {this}"); + Log.Error($"[CAMERATYPE UNKNOWN] {this} BASE = {Base}"); #endif } diff --git a/EXILED/Exiled.API/Features/Components/CollisionHandler.cs b/EXILED/Exiled.API/Features/Components/CollisionHandler.cs index b98e7bb5a..54d117fe4 100644 --- a/EXILED/Exiled.API/Features/Components/CollisionHandler.cs +++ b/EXILED/Exiled.API/Features/Components/CollisionHandler.cs @@ -56,9 +56,11 @@ private void OnCollisionEnter(Collision collision) Log.Error("Grenade is null!"); if (collision is null) Log.Error("wat"); - if (collision.gameObject == null) + if (!collision.collider) + Log.Error("water"); + if (collision.collider.gameObject == null) Log.Error("pepehm"); - if (collision.gameObject == Owner || collision.gameObject.TryGetComponent(out _)) + if (collision.collider.gameObject == Owner || collision.collider.gameObject.TryGetComponent(out _)) return; Grenade.TargetTime = 0.1f; diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/ButtonSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/ButtonSetting.cs new file mode 100644 index 000000000..5144f81ff --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/ButtonSetting.cs @@ -0,0 +1,88 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + using System.Diagnostics; + + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + + /// + /// Represents a button setting. + /// + public class ButtonSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + public ButtonSetting(int id, string label, string buttonText, float holdTime = 0.0f, string hintDescription = null, HeaderSetting header = null, Action onChanged = null) + : base(new SSButton(id, label, buttonText, holdTime, hintDescription), header, onChanged) + { + Base = (SSButton)base.Base; + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal ButtonSetting(SSButton settingBase) + : base(settingBase) + { + Base = settingBase; + + if (OriginalDefinition.Is(out ButtonSetting setting)) + { + Text = setting.Text; + HoldTime = setting.HoldTime; + } + } + + /// + public new SSButton Base { get; } + + /// + /// Gets the last press time. + /// + public Stopwatch LastPress => Base.SyncLastPress; + + /// + /// Gets or sets the button text. + /// + public string Text + { + get => Base.ButtonText; + set => Base.ButtonText = value; + } + + /// + /// Gets or sets the hold time in seconds. + /// + public float HoldTime + { + get => Base.HoldTimeSeconds; + set => Base.HoldTimeSeconds = value; + } + + /// + /// Returns a representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" ={Text}= -{HoldTime}- /{LastPress}/"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/DropdownSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/DropdownSetting.cs new file mode 100644 index 000000000..f03e6c070 --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/DropdownSetting.cs @@ -0,0 +1,128 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + + /// + /// Represents a dropdown setting. + /// + public class DropdownSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public DropdownSetting( + int id, + string label, + IEnumerable options, + int defaultOptionIndex = 0, + SSDropdownSetting.DropdownEntryType dropdownEntryType = SSDropdownSetting.DropdownEntryType.Regular, + string hintDescription = null, + HeaderSetting header = null, + Action onChanged = null) + : base(new SSDropdownSetting(id, label, options.ToArray(), defaultOptionIndex, dropdownEntryType, hintDescription), header, onChanged) + { + Base = (SSDropdownSetting)base.Base; + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal DropdownSetting(SSDropdownSetting settingBase) + : base(settingBase) + { + Base = settingBase; + + if (OriginalDefinition.Is(out DropdownSetting dropdown)) + { + Options = dropdown.Options; + } + } + + /// + public new SSDropdownSetting Base { get; } + + /// + /// Gets or sets a collection of all options in dropdown. + /// + public IEnumerable Options + { + get => Base.Options; + set => Base.Options = value.ToArray(); + } + + /// + /// Gets or sets an index of default option. + /// + public int DefaultOptionIndex + { + get => Base.DefaultOptionIndex; + set => Base.DefaultOptionIndex = value; + } + + /// + /// Gets or sets a default option. + /// + public string DefaultOption + { + get => Base.Options[DefaultOptionIndex]; + set => DefaultOptionIndex = Array.IndexOf(Base.Options, value); + } + + /// + /// Gets or sets a type of dropdown. + /// + public SSDropdownSetting.DropdownEntryType DropdownType + { + get => Base.EntryType; + set => Base.EntryType = value; + } + + /// + /// Gets or sets an index of selected option. + /// + public int SelectedIndex + { + get => Base.SyncSelectionIndexRaw; + set => Base.SyncSelectionIndexRaw = value; + } + + /// + /// Gets or sets a selected option. + /// + public string SelectedOption + { + get => Base.SyncSelectionText; + set => SelectedIndex = Array.IndexOf(Base.Options, value); + } + + /// + /// Gets a string representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" ={DefaultOptionIndex}= -{SelectedIndex}- /{string.Join(";", Options)}/"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/HeaderSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/HeaderSetting.cs new file mode 100644 index 000000000..78fd4ee32 --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/HeaderSetting.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + + /// + /// Represents a header setting. + /// + public class HeaderSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public HeaderSetting(string name, string hintDescription = "", bool paddling = false) + : this(new SSGroupHeader(name, paddling, hintDescription)) + { + Base = (SSGroupHeader)base.Base; + + Base.SetId(null, name); + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal HeaderSetting(SSGroupHeader settingBase) + : base(settingBase) + { + Base = settingBase; + Base.SetId(null, settingBase.Label); + } + + /// + public new SSGroupHeader Base { get; } + + /// + /// Gets or sets a value indicating whether to reduce padding. + /// + public bool ReducedPaddling + { + get => Base.ReducedPadding; + set => Base.ReducedPadding = value; + } + + /// + /// Returns a representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" /{ReducedPaddling}/"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs new file mode 100644 index 000000000..cfb6b3bbc --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/KeybindSetting.cs @@ -0,0 +1,82 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + using UnityEngine; + + /// + /// Represents a keybind setting. + /// + public class KeybindSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + public KeybindSetting(int id, string label, KeyCode suggested, bool preventInteractionOnGUI = false, string hintDescription = "", HeaderSetting header = null, Action onChanged = null) + : base(new SSKeybindSetting(id, label, suggested, preventInteractionOnGUI, hintDescription), header, onChanged) + { + Base = (SSKeybindSetting)base.Base; + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal KeybindSetting(SSKeybindSetting settingBase) + : base(settingBase) + { + Base = settingBase; + } + + /// + public new SSKeybindSetting Base { get; } + + /// + /// Gets a value indicating whether the key is pressed. + /// + public bool IsPressed => Base.SyncIsPressed; + + /// + /// Gets or sets a value indicating whether the interaction is prevented while player is in RA, Settings etc. + /// + public bool PreventInteractionOnGUI + { + get => Base.PreventInteractionOnGUI; + set => Base.PreventInteractionOnGUI = value; + } + + /// + /// Gets or sets the assigned key. + /// + public KeyCode KeyCode + { + get => Base.SuggestedKey; + set => Base.SuggestedKey = value; + } + + /// + /// Returns a representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" /{IsPressed}/ *{KeyCode}* +{PreventInteractionOnGUI}+"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/SettingBase.cs b/EXILED/Exiled.API/Features/Core/UserSettings/SettingBase.cs new file mode 100644 index 000000000..6a9e65215 --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/SettingBase.cs @@ -0,0 +1,340 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + + using Exiled.API.Features.Pools; + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + + /// + /// A base class for all Server Specific Settings. + /// + public class SettingBase : TypeCastObject, IWrapper + { + /// + /// A that contains that were received by a players. + /// + internal static readonly Dictionary> ReceivedSettings = new(); + + /// + /// A collection that contains all settings that were sent to clients. + /// + internal static readonly List Settings = new(); + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + /// + /// + internal SettingBase(ServerSpecificSettingBase settingBase, HeaderSetting header, Action onChanged) + { + Base = settingBase; + + Header = header; + OnChanged = onChanged; + } + + /// + /// Initializes a new instance of the class. + /// + /// + internal SettingBase(ServerSpecificSettingBase settingBase) + { + Base = settingBase; + + if (OriginalDefinition != null) + { + Header = OriginalDefinition.Header; + OnChanged = OriginalDefinition.OnChanged; + Label = OriginalDefinition.Label; + HintDescription = OriginalDefinition.HintDescription; + } + } + + /// + /// Gets the list of all synced settings. + /// + public static IReadOnlyDictionary> SyncedList + => new ReadOnlyDictionary>(ReceivedSettings.ToDictionary(x => x.Key, x => x.Value.AsReadOnly())); + + /// + /// Gets the list of settings that were used as a prefabs. + /// + public static IReadOnlyCollection List => Settings; + + /// + /// Gets or sets the predicate for syncing this setting when a player joins. + /// + public static Predicate SyncOnJoin { get; set; } + + /// + public ServerSpecificSettingBase Base { get; } + + /// + /// Gets or sets the id of this setting. + /// + public int Id + { + get => Base.SettingId; + set => Base.SetId(value, string.Empty); + } + + /// + /// Gets or sets the label of this setting. + /// + public string Label + { + get => Base.Label; + set => Base.Label = value; + } + + /// + /// Gets or sets the description of this setting. + /// + public string HintDescription + { + get => Base.HintDescription; + set => Base.HintDescription = value; + } + + /// + /// Gets the response mode of this setting. + /// + public ServerSpecificSettingBase.UserResponseMode ResponseMode => Base.ResponseMode; + + /// + /// Gets the setting that was sent to players. + /// + /// Can be null if this is a prefab. + public SettingBase OriginalDefinition => Settings.Find(x => x.Id == Id); + + /// + /// Gets or sets the header of this setting. + /// + /// Can be null. + public HeaderSetting Header { get; set; } + + /// + /// Gets or sets the action to be executed when this setting is changed. + /// + public Action OnChanged { get; set; } + + /// + /// Tries to get the setting with the specified id. + /// + /// Player who has received the setting. + /// Id of the setting. + /// A instance if found. Otherwise, null. + /// Type of the setting. + /// true if the setting was found, false otherwise. + public static bool TryGetSetting(Player player, int id, out T setting) + where T : SettingBase + { + setting = null; + + if (!ReceivedSettings.TryGetValue(player, out List list)) + return false; + + setting = (T)list.FirstOrDefault(x => x.Id == id); + return setting != null; + } + + /// + /// Tries to get the setting with the specified id. + /// + /// Player who has received the setting. + /// Id of the setting. + /// A instance if found. Otherwise, null. + /// true if the setting was found, false otherwise. + public static bool TryGetSetting(Player player, int id, out SettingBase setting) => TryGetSetting(player, id, out setting); + + /// + /// Creates a new instance of this setting. + /// + /// A instance. + /// A new instance of this setting. + /// + /// This method is used only to create a new instance of from an existing instance. + /// New setting won't be synced with players. + /// + public static SettingBase Create(ServerSpecificSettingBase settingBase) => settingBase switch + { + SSButton button => new ButtonSetting(button), + SSDropdownSetting dropdownSetting => new DropdownSetting(dropdownSetting), + SSTextArea textArea => new TextInputSetting(textArea), + SSGroupHeader header => new HeaderSetting(header), + SSKeybindSetting keybindSetting => new KeybindSetting(keybindSetting), + SSTwoButtonsSetting twoButtonsSetting => new TwoButtonsSetting(twoButtonsSetting), + _ => new SettingBase(settingBase) + }; + + /// + /// Creates a new instance of this setting. + /// + /// A instance. + /// Type of the setting. + /// A new instance of this setting. + /// + /// This method is used only to create a new instance of from an existing instance. + /// New setting won't be synced with players. + /// + public static T Create(ServerSpecificSettingBase settingBase) + where T : SettingBase => (T)Create(settingBase); + + /// + /// Syncs setting with all players. + /// + public static void SendToAll() => ServerSpecificSettingsSync.SendToAll(); + + /// + /// Syncs setting with all players according to the specified predicate. + /// + /// A requirement to meet. + public static void SendToAll(Func predicate) + { + foreach (Player player in Player.List) + { + if (predicate(player)) + SendToPlayer(player); + } + } + + /// + /// Syncs setting with the specified target. + /// + /// Target player. + public static void SendToPlayer(Player player) => ServerSpecificSettingsSync.SendToPlayer(player.ReferenceHub); + + /// + /// Registers all settings from the specified collection. + /// + /// A collection of settings to register. + /// A requirement to meet when sending settings to players. + /// A of instances that were successfully registered. + /// This method is used to sync new settings with players. + public static IEnumerable Register(IEnumerable settings, Func predicate = null) + { + List list = ListPool.Pool.Get(settings); + List list2 = new(list.Count); + + while (list.Exists(x => x.Header != null)) + { + SettingBase setting = list.Find(x => x.Header != null); + SettingBase header = list.Find(x => x == setting.Header); + List range = list.FindAll(x => x.Header?.Id == setting.Header.Id); + + list2.Add(header); + list2.AddRange(range); + + list.Remove(header); + list.RemoveAll(x => x.Header?.Id == setting.Header.Id); + } + + list2.AddRange(list); + + List list3 = ListPool.Pool.Get(ServerSpecificSettingsSync.DefinedSettings ?? Array.Empty()); + list3.AddRange(list2.Select(x => x.Base)); + + ServerSpecificSettingsSync.DefinedSettings = list3.ToArray(); + Settings.AddRange(list2); + + if (predicate == null) + SendToAll(); + else + SendToAll(predicate); + + ListPool.Pool.Return(list3); + ListPool.Pool.Return(list); + + return list2; + } + + /// + /// Removes settings from players. + /// + /// Determines which players will receive this update. + /// Settings to remove. If null, all settings will be removed. + /// A of instances that were successfully removed. + /// This method is used to unsync settings from players. Using it with provides an opportunity to update synced settings. + public static IEnumerable Unregister(Func predicate = null, IEnumerable settings = null) + { + List list = ListPool.Pool.Get(ServerSpecificSettingsSync.DefinedSettings); + List list2 = new((settings ?? Settings).Where(setting => list.Remove(setting.Base))); + + ServerSpecificSettingsSync.DefinedSettings = list.ToArray(); + + if (predicate == null) + SendToAll(); + else + SendToAll(predicate); + + ListPool.Pool.Return(list); + + return list2; + } + + /// + /// Returns a string representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return $"{Id} ({Label}) [{HintDescription}] {{{ResponseMode}}} ^{Header}^"; + } + + /// + /// Internal method that fires when a setting is updated. + /// + /// that has updates the setting. + /// A new updated setting. + internal static void OnSettingUpdated(ReferenceHub hub, ServerSpecificSettingBase settingBase) + { + if (!Player.TryGet(hub, out Player player) || hub.IsHost) + return; + + SettingBase setting; + + if (!ReceivedSettings.TryGetValue(player, out List list)) + { + setting = Create(settingBase); + ReceivedSettings.Add(player, new() { setting }); + + if (setting.Is(out ButtonSetting _)) + setting.OriginalDefinition.OnChanged?.Invoke(player, setting); + + return; + } + + if (!list.Exists(x => x.Id == settingBase.SettingId)) + { + setting = Create(settingBase); + list.Add(setting); + + if (setting.Is(out ButtonSetting _)) + setting.OriginalDefinition.OnChanged?.Invoke(player, setting); + + return; + } + + setting = list.Find(x => x.Id == settingBase.SettingId); + + if (setting.OriginalDefinition == null) + { + Settings.Add(Create(settingBase.OriginalDefinition)); + } + + setting.OriginalDefinition?.OnChanged?.Invoke(player, setting); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/TextInputSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/TextInputSetting.cs new file mode 100644 index 000000000..69c7875ad --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/TextInputSetting.cs @@ -0,0 +1,93 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + using TMPro; + + /// + /// Represents a text input setting. + /// + public class TextInputSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + public TextInputSetting( + int id, + string label, + SSTextArea.FoldoutMode foldoutMode = SSTextArea.FoldoutMode.NotCollapsable, + TextAlignmentOptions alignment = TextAlignmentOptions.TopLeft, + string hintDescription = null, + HeaderSetting header = null, + Action onChanged = null) + : base(new SSTextArea(id, label, foldoutMode, hintDescription, alignment), header, onChanged) + { + Base = (SSTextArea)base.Base; + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal TextInputSetting(SSTextArea settingBase) + : base(settingBase) + { + Base = settingBase; + } + + /// + public new SSTextArea Base { get; } + + /// + /// Gets or sets the text for the setting. + /// + public new string Label + { + get => Base.Label; + set => Base.SendTextUpdate(value); + } + + /// + /// Gets or sets the foldout mode. + /// + public SSTextArea.FoldoutMode FoldoutMode + { + get => Base.Foldout; + set => Base.Foldout = value; + } + + /// + /// Gets or sets the text alignment options. + /// + public TextAlignmentOptions Alignment + { + get => Base.AlignmentOptions; + set => Base.AlignmentOptions = value; + } + + /// + /// Returns a representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" /{FoldoutMode}/ *{Alignment}*"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Core/UserSettings/TwoButtonsSetting.cs b/EXILED/Exiled.API/Features/Core/UserSettings/TwoButtonsSetting.cs new file mode 100644 index 000000000..4b2f03a0c --- /dev/null +++ b/EXILED/Exiled.API/Features/Core/UserSettings/TwoButtonsSetting.cs @@ -0,0 +1,110 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Core.UserSettings +{ + using System; + + using Exiled.API.Interfaces; + using global::UserSettings.ServerSpecific; + + /// + /// Represents a two-button setting. + /// + public class TwoButtonsSetting : SettingBase, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public TwoButtonsSetting(int id, string label, string firstOption, string secondOption, bool defaultIsSecond = false, string hintDescription = "", HeaderSetting header = null, Action onChanged = null) + : base(new SSTwoButtonsSetting(id, label, firstOption, secondOption, defaultIsSecond, hintDescription), header, onChanged) + { + Base = (SSTwoButtonsSetting)base.Base; + } + + /// + /// Initializes a new instance of the class. + /// + /// A instance. + internal TwoButtonsSetting(SSTwoButtonsSetting settingBase) + : base(settingBase) + { + Base = settingBase; + + if (OriginalDefinition.Is(out TwoButtonsSetting setting)) + { + FirstOption = setting.FirstOption; + SecondOption = setting.SecondOption; + } + } + + /// + public new SSTwoButtonsSetting Base { get; } + + /// + /// Gets or sets a value indicating whether the second option is chosen. + /// + public bool IsSecond + { + get => Base.SyncIsB; + set => Base.SyncIsB = value; + } + + /// + /// Gets or sets a value indicating whether the first option is chosen. + /// + public bool IsFirst + { + get => Base.SyncIsA; + set => Base.SyncIsB = !value; + } + + /// + /// Gets or sets a value indicating whether the second option is default. + /// + public bool IsSecondDefault + { + get => Base.DefaultIsB; + set => Base.DefaultIsB = value; + } + + /// + /// Gets or sets a label for the first option. + /// + public string FirstOption + { + get => Base.OptionA; + set => Base.OptionA = value; + } + + /// + /// Gets or sets a label for the second option. + /// + public string SecondOption + { + get => Base.OptionB; + set => Base.OptionB = value; + } + + /// + /// Returns a representation of this . + /// + /// A string in human-readable format. + public override string ToString() + { + return base.ToString() + $" /{FirstOption}/ *{SecondOption}* +{IsSecondDefault}+ '{IsFirst}'"; + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs index 115990925..67b464474 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/CustomDamageHandler.cs @@ -71,7 +71,7 @@ public CustomDamageHandler(Player target, Player attacker, float damage, DamageT Base = { Owner = attacker.ReferenceHub }, }; - CustomBase = new FirearmDamageHandler(firearm, target, new BaseFirearmHandler(firearm.Base, damage)); + CustomBase = new FirearmDamageHandler(firearm, target, new PlayerStatsSystem.FirearmDamageHandler() { Firearm = firearm.Base, Damage = damage }); } /// diff --git a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs index 152f77af2..2008936be 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs @@ -10,14 +10,12 @@ namespace Exiled.API.Features.DamageHandlers using Enums; using Footprinting; - using Items; using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.PlayableScps.Scp939; using PlayerStatsSystem; - using UnityEngine; /// @@ -92,6 +90,9 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage case DamageType.SeveredHands: Base = new UniversalDamageHandler(damage, DeathTranslations.SeveredHands, cassieAnnouncement); break; + case DamageType.SeveredEyes: + Base = new UniversalDamageHandler(damage, DeathTranslations.Scp1344, cassieAnnouncement); + break; case DamageType.Warhead: Base = new WarheadDamageHandler(); break; @@ -110,10 +111,10 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage case DamageType.MicroHid: InventorySystem.Items.MicroHID.MicroHIDItem microHidOwner = new(); microHidOwner.Owner = attacker.ReferenceHub; - Base = new MicroHidDamageHandler(microHidOwner, damage); + Base = new MicroHidDamageHandler(damage, microHidOwner); break; case DamageType.Explosion: - Base = new ExplosionDamageHandler(attacker.Footprint, UnityEngine.Vector3.zero, damage, 0); + Base = new ExplosionDamageHandler(attacker.Footprint, UnityEngine.Vector3.zero, damage, 0, ExplosionType.Grenade); break; case DamageType.Firearm: GenericFirearm(player, attacker, damage, damageType, ItemType.GunAK); @@ -155,7 +156,7 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage GenericFirearm(player, attacker, damage, damageType, ItemType.GunA7); break; case DamageType.ParticleDisruptor: - Base = new DisruptorDamageHandler(Attacker, damage); + 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); break; case DamageType.Scp096: Scp096Role curr096 = attacker.ReferenceHub.roleManager.CurrentRole as Scp096Role ?? new Scp096Role(); @@ -259,7 +260,7 @@ private void GenericFirearm(Player player, Player attacker, float amount, Damage Owner = attacker.ReferenceHub, }, }; - Base = new PlayerStatsSystem.FirearmDamageHandler(firearm.Base, amount); + Base = new PlayerStatsSystem.FirearmDamageHandler() { Firearm = firearm.Base, Damage = amount }; } } } diff --git a/EXILED/Exiled.API/Features/Doors/BreakableDoor.cs b/EXILED/Exiled.API/Features/Doors/BreakableDoor.cs index 9148067dd..862332c89 100644 --- a/EXILED/Exiled.API/Features/Doors/BreakableDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/BreakableDoor.cs @@ -92,6 +92,11 @@ public bool IgnoreRemoteAdmin set => Base._nonInteractable = value; } + /// + /// Repair the door. + /// + public void Repair() => Base.ServerRepair(); + /// /// Damages the door. /// diff --git a/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs b/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs index 9681290d8..837bd5ff7 100644 --- a/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/CheckpointDoor.cs @@ -133,6 +133,11 @@ public DoorDamageType IgnoredDamage /// internal List SubDoorsValue { get; } = new(); + /// + /// Repair the door. + /// + public void Repair() => Base.ServerRepair(); + /// /// Toggles the state of the doors from . /// diff --git a/EXILED/Exiled.API/Features/Doors/Door.cs b/EXILED/Exiled.API/Features/Doors/Door.cs index 4f949748e..63b4f62ce 100644 --- a/EXILED/Exiled.API/Features/Doors/Door.cs +++ b/EXILED/Exiled.API/Features/Doors/Door.cs @@ -14,17 +14,13 @@ namespace Exiled.API.Features.Doors using Exiled.API.Enums; using Exiled.API.Extensions; using Exiled.API.Features.Core; - using Exiled.API.Features.Hazards; using Exiled.API.Interfaces; - using global::Hazards; using Interactables.Interobjects; using Interactables.Interobjects.DoorUtils; using MEC; using Mirror; using UnityEngine; - using static Interactables.Interobjects.ElevatorManager; - using BaseBreakableDoor = Interactables.Interobjects.BreakableDoor; using BaseKeycardPermissions = Interactables.Interobjects.DoorUtils.KeycardPermissions; using Breakable = BreakableDoor; @@ -59,9 +55,9 @@ internal Door(DoorVariant door, List rooms) } Type = GetDoorType(); -#if Debug - if (Type is DoorType.Unknown) - Log.Error($"[DOORTYPE UNKNOWN] {this}"); +#if DEBUG + if (Type is DoorType.UnknownDoor or DoorType.UnknownGate or DoorType.UnknownElevator) + Log.Error($"[DOORTYPE UNKNOWN] {this} BASE = {Base}"); #endif } @@ -518,10 +514,22 @@ public void ChangeLock(DoorLockType lockType) /// The of the lockdown. public void Lock(float time, DoorLockType lockType) { - ChangeLock(lockType); + Lock(lockType); Unlock(time, lockType); } + /// + /// Locks all active locks on the door for infinite time. + /// + /// The of the lockdown. + public void Lock(DoorLockType lockType) + { + DoorLockType locks = DoorLockType; + locks |= lockType; + Base.NetworkActiveLocks = (ushort)locks; + DoorEvents.TriggerAction(Base, IsLocked ? DoorAction.Locked : DoorAction.Unlocked, null); + } + /// /// Unlocks and clears all active locks on the door. /// @@ -545,7 +553,7 @@ public void Lock(float time, DoorLockType lockType) /// Returns the Door in a human-readable format. /// /// A string containing Door-related data. - public override string ToString() => $"{Type} ({Zone}) [{Room}] *{DoorLockType}* ={RequiredPermissions.RequiredPermissions}="; + public override string ToString() => $"{Type} ({Zone}) [{Room}] *{DoorLockType}* ={RequiredPermissions?.RequiredPermissions}="; /// /// Creates the door object associated with a specific . @@ -576,38 +584,38 @@ private DoorType GetDoorType() { if (Nametag is null) { - string doorName = GameObject.name.GetBefore(' '); + string doorName = GameObject.name.GetBefore('(').TrimEnd(); + return doorName switch { - "LCZ" => Room?.Type switch - { - RoomType.LczAirlock => (Base.GetComponentInParent() != null) ? DoorType.Airlock : DoorType.LightContainmentDoor, - _ => DoorType.LightContainmentDoor, - }, - "HCZ" => DoorType.HeavyContainmentDoor, - "EZ" => DoorType.EntranceDoor, - "Prison" => DoorType.PrisonDoor, - "914" => DoorType.Scp914Door, - "Intercom" => Room?.Type switch + "LCZ PortallessBreakableDoor" => DoorType.Airlock, + "LCZ BreakableDoor" => DoorType.LightContainmentDoor, + "HCZ BreakableDoor" => DoorType.HeavyContainmentDoor, + "HCZ BulkDoor" => DoorType.HeavyBulkDoor, + "EZ BreakableDoor" => DoorType.EntranceDoor, + "Prison BreakableDoor" => DoorType.PrisonDoor, + "914 Door" => DoorType.Scp914Door, + "Intercom BreakableDoor" => Room?.Type switch { RoomType.HczEzCheckpointA => DoorType.CheckpointArmoryA, RoomType.HczEzCheckpointB => DoorType.CheckpointArmoryB, _ => DoorType.UnknownDoor, }, - "Unsecured" => Room?.Type switch + "Unsecured Pryable GateDoor" => Room?.Type switch { - RoomType.EzCheckpointHallway => DoorType.CheckpointGate, + RoomType.EzCheckpointHallwayA => DoorType.CheckpointGateA, + RoomType.EzCheckpointHallwayB => DoorType.CheckpointGateB, RoomType.Hcz049 => Position.y < -805 ? DoorType.Scp049Gate : DoorType.Scp173NewGate, _ => DoorType.UnknownGate, }, - "Elevator" => (Base as Interactables.Interobjects.ElevatorDoor)?.Group switch + "Elevator Door" or "Nuke Elevator Door" or "Elevator Door 02" => (Base as Interactables.Interobjects.ElevatorDoor)?.Group switch { - ElevatorGroup.Nuke => DoorType.ElevatorNuke, ElevatorGroup.Scp049 => DoorType.ElevatorScp049, ElevatorGroup.GateB => DoorType.ElevatorGateB, ElevatorGroup.GateA => DoorType.ElevatorGateA, ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => DoorType.ElevatorLczA, ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => DoorType.ElevatorLczB, + ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => DoorType.ElevatorNuke, _ => DoorType.UnknownElevator, }, _ => DoorType.UnknownDoor, @@ -629,7 +637,6 @@ private DoorType GetDoorType() "NUKE_ARMORY" => DoorType.NukeArmory, "LCZ_ARMORY" => DoorType.LczArmory, "SURFACE_NUKE" => DoorType.NukeSurface, - "HID" => DoorType.HID, "HCZ_ARMORY" => DoorType.HczArmory, "096" => DoorType.Scp096, "049_ARMORY" => DoorType.Scp049Armory, @@ -639,11 +646,11 @@ private DoorType GetDoorType() "079_FIRST" => DoorType.Scp079First, "GATE_B" => DoorType.GateB, "079_SECOND" => DoorType.Scp079Second, - "SERVERS_BOTTOM" => DoorType.ServersBottom, "173_CONNECTOR" => DoorType.Scp173Connector, "LCZ_WC" => DoorType.LczWc, - "HID_RIGHT" => DoorType.HIDRight, - "HID_LEFT" => DoorType.HIDLeft, + "HID_CHAMBER" => DoorType.HIDChamber, + "HID_UPPER" => DoorType.HIDUpper, + "HID_LOWER" => DoorType.HIDLower, "173_ARMORY" => DoorType.Scp173Armory, "173_GATE" => DoorType.Scp173Gate, "GR18" => DoorType.GR18Gate, @@ -652,6 +659,7 @@ private DoorType GetDoorType() "330_CHAMBER" => DoorType.Scp330Chamber, "GR18_INNER" => DoorType.GR18Inner, "939_CRYO" => DoorType.Scp939Cryo, + "ESCAPE_FINAL" => DoorType.EscapeFinal, // Doors spawned by the DoorSpawnPoint component "LCZ_CAFE" => DoorType.LczCafe, diff --git a/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs b/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs index aa011f7fe..797378312 100644 --- a/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs +++ b/EXILED/Exiled.API/Features/Doors/ElevatorDoor.cs @@ -12,6 +12,7 @@ namespace Exiled.API.Features.Doors using Exiled.API.Enums; using Interactables.Interobjects; + using UnityEngine; /// /// Represents an elevator door. @@ -28,6 +29,8 @@ internal ElevatorDoor(Interactables.Interobjects.ElevatorDoor door, List r { Base = door; Lift = Lift.Get(x => x.Group == Group).FirstOrDefault(); + + Panel = Object.FindObjectsOfType().FirstOrDefault(x => x._door == door); } /// @@ -36,29 +39,29 @@ internal ElevatorDoor(Interactables.Interobjects.ElevatorDoor door, List r public new Interactables.Interobjects.ElevatorDoor Base { get; } /// - /// Gets the that this door's belongs to. + /// Gets the that this door's belongs to. + /// + public ElevatorGroup Group => Base.Group; + + /// + /// Gets the associated with this lift. /// - public ElevatorManager.ElevatorGroup Group => Base.Group; + public ElevatorPanel Panel { get; } /// /// Gets the type according to . /// public ElevatorType ElevatorType => Group switch { - ElevatorManager.ElevatorGroup.Scp049 => ElevatorType.Scp049, - ElevatorManager.ElevatorGroup.GateA => ElevatorType.GateA, - ElevatorManager.ElevatorGroup.GateB => ElevatorType.GateB, - ElevatorManager.ElevatorGroup.LczA01 or ElevatorManager.ElevatorGroup.LczA02 => ElevatorType.LczA, - ElevatorManager.ElevatorGroup.LczB01 or ElevatorManager.ElevatorGroup.LczB02 => ElevatorType.LczB, - ElevatorManager.ElevatorGroup.Nuke => ElevatorType.Nuke, + ElevatorGroup.Scp049 => ElevatorType.Scp049, + ElevatorGroup.GateA => ElevatorType.GateA, + ElevatorGroup.GateB => ElevatorType.GateB, + ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => ElevatorType.LczA, + ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => ElevatorType.LczB, + ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => ElevatorType.Nuke, _ => ElevatorType.Unknown, }; - /// - /// Gets the target panel for this lift. - /// - public ElevatorPanel Panel => Base.TargetPanel; - /// /// Gets the associated with this elevator door. /// diff --git a/EXILED/Exiled.API/Features/Items/Armor.cs b/EXILED/Exiled.API/Features/Items/Armor.cs index 30b99bc7c..6fe2bc097 100644 --- a/EXILED/Exiled.API/Features/Items/Armor.cs +++ b/EXILED/Exiled.API/Features/Items/Armor.cs @@ -115,14 +115,9 @@ public float StaminaUseMultiplier public float StaminaRegenMultiplier { get; set; } = 1f; /// - /// Gets or sets how much the users movement speed should be affected when wearing this armor. (higher values = slower movement). + /// Gets how much the users movement speed should be affected when wearing this armor. (higher values = slower movement). /// - public float MovementSpeedMultiplier - { - get => Base._movementSpeedMultiplier; - [Obsolete("This Setter was causing desync to client", true)] - set => _ = value; - } + public float MovementSpeedMultiplier => Base._movementSpeedMultiplier; /// /// Gets how much worse and s are affected by wearing this armor. diff --git a/EXILED/Exiled.API/Features/Items/Firearm.cs b/EXILED/Exiled.API/Features/Items/Firearm.cs index 750bd9d96..98cd780c2 100644 --- a/EXILED/Exiled.API/Features/Items/Firearm.cs +++ b/EXILED/Exiled.API/Features/Items/Firearm.cs @@ -12,15 +12,15 @@ namespace Exiled.API.Features.Items using System.Linq; 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; - using Extensions; - using InventorySystem; using InventorySystem.Items; using InventorySystem.Items.Firearms; @@ -29,7 +29,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.BasicMessages; using InventorySystem.Items.Firearms.Modules; using InventorySystem.Items.Pickups; - + using MEC; using UnityEngine; using BaseFirearm = InventorySystem.Items.Firearms.Firearm; @@ -59,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); + } + } } /// @@ -68,11 +82,10 @@ public Firearm(BaseFirearm itemBase) internal Firearm(ItemType type) : this((BaseFirearm)Server.Host.Inventory.CreateItemInstance(new(type, 0), false)) { - FirearmStatusFlags firearmStatusFlags = FirearmStatusFlags.MagazineInserted; - if (Base.HasAdvantageFlag(AttachmentDescriptiveAdvantages.Flashlight)) - firearmStatusFlags |= FirearmStatusFlags.FlashlightEnabled; + FlashlightAttachment flashlight = Attachments.OfType().FirstOrDefault(); - Base.Status = new FirearmStatus(MaxAmmo, firearmStatusFlags, Base.Status.Attachments); + if (flashlight != null && flashlight.IsEnabled) + flashlight.ServerSendStatus(true); } /// . @@ -110,41 +123,94 @@ public static IReadOnlyDictionary - /// Gets or sets the amount of ammo in the firearm. + /// Gets a primaty magazine for current firearm. + /// + public PrimaryMagazine PrimaryMagazine { get; } + + /// + /// Gets a barrel magazine for current firearm. + /// + /// + /// for Revolver and ParticleDisruptor. + /// + public BarrelMagazine BarrelMagazine { get; } + + /// + /// Gets or sets the amount of ammo in the firearm magazine. + /// + public int MagazineAmmo + { + get => PrimaryMagazine.Ammo; + set => PrimaryMagazine.Ammo = value; + } + + /// + /// Gets or sets the amount of ammo in the firearm barrel. /// - public byte Ammo + /// + /// not working for Revolver and ParticleDisruptor. + /// + public int BarrelAmmo { - get => Base.Status.Ammo; - set => Base.Status = new FirearmStatus(value, Base.Status.Flags, Base.Status.Attachments); + get => BarrelMagazine?.Ammo ?? 0; + + set + { + if (BarrelMagazine != null) + BarrelMagazine.Ammo = value; + } } + /// + /// Gets the total amount of ammo in the firearm. + /// + public int TotalAmmo => Base.GetTotalStoredAmmo(); + /// /// Gets or sets the max ammo for this firearm. /// - /// Disruptor can't be used for MaxAmmo. - public byte MaxAmmo + public int MaxMagazineAmmo + { + get => PrimaryMagazine.MaxAmmo; + set => PrimaryMagazine.MaxAmmo = value; + } + + /// + /// Gets or sets the amount of max ammo in the firearm barrel. + /// + /// + /// not working for Revolver and ParticleDisruptor. + /// + public int MaxBarrelAmmo { - get => Base.AmmoManagerModule.MaxAmmo; + get => BarrelMagazine?.MaxAmmo ?? 0; + set { - switch (Base.AmmoManagerModule) - { - case TubularMagazineAmmoManager tubularMagazineAmmoManager: - tubularMagazineAmmoManager.MaxAmmo = (byte)(value - Base.AttachmentsValue(AttachmentParam.MagazineCapacityModifier) - (Base.Status.Flags.HasFlagFast(FirearmStatusFlags.Cocked) ? tubularMagazineAmmoManager.ChamberedRounds : 0)); - break; - case ClipLoadedInternalMagAmmoManager clipLoadedInternalMagAmmoManager: - clipLoadedInternalMagAmmoManager.MaxAmmo = (byte)(value - Base.AttachmentsValue(AttachmentParam.MagazineCapacityModifier)); - break; - case AutomaticAmmoManager automaticAmmoManager: - automaticAmmoManager.MaxAmmo = (byte)(value - Base.AttachmentsValue(AttachmentParam.MagazineCapacityModifier) - automaticAmmoManager.ChamberedAmount); - break; - default: - Log.Warn($"MaxAmmo can't be used for this Item: {Type} ({Base.AmmoManagerModule})"); - return; - } + if (BarrelMagazine != null) + BarrelMagazine.MaxAmmo = value; } } + /// + /// Gets the total amount of ammo in the firearm. + /// + public int TotalMaxAmmo => Base.GetTotalMaxAmmo(); + + /// + /// Gets or sets a ammo drain per shoot. + /// + /// + /// Always by default. + /// Applied on a high layer nether basegame ammo controllers. + /// + public int AmmoDrain { get; set; } = 1; + + /// + /// Gets a value indicating whether the weapon is reloading. + /// + public bool IsReloading => Base.TryGetModule(out IReloaderModule module) && module.IsReloading; + /// /// Gets the of the firearm. /// @@ -153,17 +219,17 @@ public byte MaxAmmo /// /// Gets the of the firearm. /// - public AmmoType AmmoType => Base.AmmoType.GetAmmoType(); + public AmmoType AmmoType => PrimaryMagazine.AmmoType; /// /// Gets a value indicating whether the firearm is being aimed. /// - public bool Aiming => Base.AdsModule.ServerAds; + public bool Aiming => Base.TryGetModule(out LinearAdsModule module) && module.AdsTarget; /// /// Gets a value indicating whether the firearm's flashlight module is enabled. /// - public bool FlashlightEnabled => Base.Status.Flags.HasFlagFast(FirearmStatusFlags.FlashlightEnabled); + public bool FlashlightEnabled => Base.IsEmittingLight; /// /// Gets a value indicating whether the firearm's NightVision is being used. @@ -178,7 +244,7 @@ public byte MaxAmmo /// /// Gets a value indicating whether the firearm is automatic. /// - public bool IsAutomatic => Base is AutomaticFirearm; + public bool IsAutomatic => BarrelMagazine is AutomaticBarrelMagazine; /// /// Gets the s of the firearm. @@ -202,21 +268,6 @@ public IEnumerable AttachmentIdentifiers /// public uint BaseCode => BaseCodesValue[FirearmType]; - /// - /// Gets or sets the fire rate of the firearm, if it is an automatic weapon. - /// - /// This property will not do anything if the firearm is not an automatic weapon. - /// - public float FireRate - { - get => Base is AutomaticFirearm auto ? auto._fireRate : 1f; - set - { - if (Base is AutomaticFirearm auto) - auto._fireRate = value; - } - } - /// /// Gets or sets the recoil settings of the firearm, if it's an automatic weapon. /// @@ -224,19 +275,14 @@ public float FireRate /// public RecoilSettings Recoil { - get => Base is AutomaticFirearm auto ? auto._recoil : default; + get => Base.TryGetModule(out RecoilPatternModule module) ? module.BaseRecoil : default; set { - if (Base is AutomaticFirearm auto) - auto.ActionModule = new AutomaticAction(Base, auto._semiAutomatic, auto._boltTravelTime, 1f / auto._fireRate, auto._dryfireClipId, auto._triggerClipId, auto._gunshotPitchRandomization, value, auto._recoilPattern, false, Mathf.Max(1, auto._chamberSize)); + if (Base.TryGetModule(out RecoilPatternModule module)) + module.BaseRecoil = value; } } - /// - /// Gets the firearm's . Will be for non-automatic weapons. - /// - public FirearmRecoilPattern RecoilPattern => Base is AutomaticFirearm auto ? auto._recoilPattern : null; - /// /// Gets a of and [] which contains all available attachments for all firearms. /// @@ -277,7 +323,9 @@ public void AddAttachment(AttachmentIdentifier identifier) : identifier.Code; Base.ApplyAttachmentsCode((Base.GetCurrentAttachmentsCode() & ~toRemove) | newCode, true); - Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode()); + + // TODO Not finish + // Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode()); } /// @@ -319,10 +367,12 @@ public void RemoveAttachment(AttachmentIdentifier identifier) Base.ApplyAttachmentsCode(Base.GetCurrentAttachmentsCode() & ~code, true); + // TODO: Not finish + /* if (identifier.Name == AttachmentName.Flashlight) Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags & ~FirearmStatusFlags.FlashlightEnabled, Base.GetCurrentAttachmentsCode()); else - Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode()); + Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode());*/ } /// @@ -335,10 +385,12 @@ public void RemoveAttachment(AttachmentName attachmentName) Base.ApplyAttachmentsCode(Base.GetCurrentAttachmentsCode() & ~code, true); + // TODO Not finish + /* if (attachmentName == AttachmentName.Flashlight) Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags & ~FirearmStatusFlags.FlashlightEnabled, Base.GetCurrentAttachmentsCode()); else - Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode()); + Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode());*/ } /// @@ -356,10 +408,12 @@ public void RemoveAttachment(AttachmentSlot attachmentSlot) Base.ApplyAttachmentsCode(Base.GetCurrentAttachmentsCode() & ~code, true); + // TODO Not finish + /* if (firearmAttachment.Name == AttachmentName.Flashlight) Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags & ~FirearmStatusFlags.FlashlightEnabled, Base.GetCurrentAttachmentsCode()); else - Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode()); + Base.Status = new FirearmStatus(Math.Min(Ammo, MaxAmmo), Base.Status.Flags, Base.GetCurrentAttachmentsCode());*/ } /// @@ -397,16 +451,6 @@ public void RemoveAttachment(IEnumerable attachmentSlots) /// public void ClearAttachments() => Base.ApplyAttachmentsCode(BaseCode, true); - /// - /// Creates the that based on this . - /// - /// The location to spawn the item. - /// The rotation of the item. - /// Whether the should be initially spawned. - /// The created . - public override Pickup CreatePickup(Vector3 position, Quaternion rotation = default, bool spawn = true) - => base.CreatePickup(position, rotation, spawn); // TODO: Deleted this overide - /// /// Gets a of the specified . /// @@ -602,6 +646,20 @@ public void ClearPreferences() ClearPreferences(player); } + /// + /// Reloads current . + /// + /// + /// For specific reloading logic you also can use for avaible weapons. + /// + public void Reload() + { + if (Base.TryGetModule(out AnimatorReloaderModuleBase module)) + { + module.StartReloading(); + } + } + /// /// Clones current object. /// @@ -610,14 +668,15 @@ public override Item Clone() { Firearm cloneableItem = new(Type) { - Ammo = Ammo, }; + // TODO Not finish + /* if (cloneableItem.Base is AutomaticFirearm) { cloneableItem.FireRate = FireRate; cloneableItem.Recoil = Recoil; - } + }*/ cloneableItem.AddAttachment(AttachmentIdentifiers); @@ -632,14 +691,23 @@ public override Item Clone() internal override void ChangeOwner(Player oldOwner, Player newOwner) { Base.Owner = newOwner.ReferenceHub; - - if (Base.HitregModule is StandardHitregBase hitReg) + Base._footprintCacheSet = false; + foreach (ModuleBase module in Base.Modules) { - hitReg.Hub = Base.Owner; + module.OnAdded(); } + } - Base._sendStatusNextFrame = true; - Base._footprintValid = false; + /// + internal override void ReadPickupInfo(Pickup pickup) + { + base.ReadPickupInfo(pickup); + + if (pickup is FirearmPickup firearmPickup) + { + PrimaryMagazine.MaxAmmo = firearmPickup.MaxAmmo; + AmmoDrain = firearmPickup.AmmoDrain; + } } } } diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/AutomaticBarrelMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/AutomaticBarrelMagazine.cs new file mode 100644 index 000000000..db8992d72 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/AutomaticBarrelMagazine.cs @@ -0,0 +1,105 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Barrel +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using InventorySystem.Items.Firearms.Modules; + + using UnityEngine; + + /// + /// Basic realization of barrel. + /// + public class AutomaticBarrelMagazine : BarrelMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// Target . + public AutomaticBarrelMagazine(AutomaticActionModule automaticModule) + : base(automaticModule) + { + AutomaticBarrel = automaticModule; + } + + /// + /// Gets an original . + /// + public AutomaticActionModule AutomaticBarrel { get; } + + /// + public override Firearm Firearm => Item.Get(AutomaticBarrel.Firearm); + + /// + public override int Ammo + { + get => AutomaticBarrel.AmmoStored; + + set + { + AutomaticBarrel.AmmoStored = Mathf.Max(value, 0); + Resync(); + } + } + + /// + /// + /// Will be ranged between and due basegame logic. + /// + public override int MaxAmmo + { + get => AutomaticBarrel.ChamberSize; + + set => AutomaticBarrel.ChamberSize = Mathf.Clamp(value, 0, 16); + } + + /// + public override bool IsCocked + { + get => AutomaticBarrel.Cocked; + + set + { + AutomaticBarrel.Cocked = value; + Resync(); + } + } + + /// + /// Gets a value indicating whether barrel magazine has open bolt or not. + /// + public bool IsOpenBolted => AutomaticBarrel.OpenBolt; + + /// + /// Gets or sets a value indicating whether barrel bolt is currently locked. + /// + public bool BoltLocked + { + get => AutomaticBarrel.BoltLocked; + + set + { + AutomaticBarrel.BoltLocked = value; + Resync(); + } + } + + /// + /// Gets the fire rate of the firearm. + /// + public float FireRate => AutomaticBarrel.BaseFireRate; + + /// + public override void Resync() => AutomaticBarrel.ServerResync(); + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/BarrelMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/BarrelMagazine.cs new file mode 100644 index 000000000..b1e11f758 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/BarrelMagazine.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Barrel +{ + using InventorySystem.Items.Firearms.Modules; + + /// + /// Basic abstraction of whose are logically used to be a barrels magazines. + /// + public abstract class BarrelMagazine : Magazine + { + /// + /// Initializes a new instance of the class. + /// + /// target . + public BarrelMagazine(IAmmoContainerModule module) + : base(module) + { + } + + /// + /// Gets or sets a value indicating whether barrel is cocked. + /// + public abstract bool IsCocked { get; set; } + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/PumpBarrelMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/PumpBarrelMagazine.cs new file mode 100644 index 000000000..57ab59b08 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Barrel/PumpBarrelMagazine.cs @@ -0,0 +1,91 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Barrel +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using InventorySystem.Items.Firearms.Modules; + + using UnityEngine; + + /// + /// Basic realization of barrel. + /// + public class PumpBarrelMagazine : BarrelMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// Target . + public PumpBarrelMagazine(PumpActionModule pumpModule) + : base(pumpModule) + { + PumpBarrel = pumpModule; + } + + /// + /// Gets an original . + /// + public PumpActionModule PumpBarrel { get; } + + /// + public override Firearm Firearm => Item.Get(PumpBarrel.Firearm); + + /// + public override int Ammo + { + get => PumpBarrel.SyncChambered; + + set + { + PumpBarrel.SyncChambered = Mathf.Max(value, 0); + Resync(); + } + } + + /// + /// Gets or sets an amount of bullets, that pump module will try to shot. + /// + public int CockedAmmo + { + get => PumpBarrel.SyncCocked; + + set + { + PumpBarrel.SyncCocked = Mathf.Max(value, 0); + Resync(); + } + } + + /// + public override int MaxAmmo + { + get => PumpBarrel._numberOfBarrels; + set => PumpBarrel._numberOfBarrels = Mathf.Max(value, 0); + } + + /// + public override bool IsCocked + { + get => PumpBarrel.SyncCocked > 0; + + set + { + PumpBarrel.SyncCocked = MaxAmmo; + Resync(); + } + } + + /// + public override void Resync() => PumpBarrel.ServerResync(); + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs new file mode 100644 index 000000000..50a2538c6 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Magazine.cs @@ -0,0 +1,111 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules +{ + using System; + + using Exiled.API.Features.Items.FirearmModules.Barrel; + using Exiled.API.Features.Items.FirearmModules.Primary; + + using InventorySystem.Items.Firearms.Modules; + + using UnityEngine; + + /// + /// Basic abstraction of . + /// + public abstract class Magazine + { + /// + /// Initializes a new instance of the class. + /// + /// target . + public Magazine(IAmmoContainerModule module) + { + AmmoContainerModule = module; + } + + /// + /// Gets an original . + /// + public IAmmoContainerModule AmmoContainerModule { get; } + + /// + /// Gets or sets a count of current ammo in magazine. + /// + public abstract int Ammo { get; set; } + + /// + /// Gets or sets a max avaible ammo count in magazine. + /// + public abstract int MaxAmmo { get; set; } + + /// + /// Gets target assotiated with this magazine. + /// + public abstract Firearm Firearm { get; } + + /// + /// Gets wrapper to an . + /// + /// The target . + /// The wrapper for the given . + public static Magazine Get(IAmmoContainerModule module) + { + if (module == null) + return null; + + return module switch + { + AutomaticActionModule actomatic => new AutomaticBarrelMagazine(actomatic), + PumpActionModule pump => new PumpBarrelMagazine(pump), + IPrimaryAmmoContainerModule primary => primary switch + { + MagazineModule magazine => new NormalMagazine(magazine), + CylinderAmmoModule cylinder => new CylinderMagazine(cylinder), + _ => null, + }, + _ => null, + }; + } + + /// + /// Modifies stored ammo in magazine. + /// + /// Ammo change value. + /// Whether new ammo should be clamped in range of and . + /// Resultly changed ammos. + /// + /// Just a variation of the setter. + /// + public int ModifyAmmo(int delta, bool useBorders = true) + { + int oldAmmo = Ammo; + if (useBorders) + { + Ammo = Mathf.Clamp(Ammo + delta, 0, MaxAmmo); + } + else + { + Ammo += delta; + } + + return Ammo - oldAmmo; + } + + /// + /// Fills current to . + /// + public void Fill() => Ammo = MaxAmmo; + + /// + /// Resyncs a related values with a client. + /// + public abstract void Resync(); + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/CylinderMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/CylinderMagazine.cs new file mode 100644 index 000000000..2beedd7bb --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/CylinderMagazine.cs @@ -0,0 +1,105 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Primary +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Enums; + using Exiled.API.Extensions; + + using InventorySystem.Items.Firearms.Modules; + + /// + /// Basic realization of . + /// + public class CylinderMagazine : PrimaryMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// target . + public CylinderMagazine(CylinderAmmoModule magazine) + : base(magazine) + { + CylinderModule = magazine; + } + + /// + /// Gets an original . + /// + public CylinderAmmoModule CylinderModule { get; } + + /// + public override Firearm Firearm => Item.Get(CylinderModule.Firearm); + + /// + public override int MaxAmmo + { + set + { + CylinderModule._defaultCapacity = value; + Resync(); + } + } + + /// + public override int ConstantMaxAmmo => CylinderModule._defaultCapacity; + + /// + /// Gets or sets an used for this magazine. + /// + public override AmmoType AmmoType + { + get => Magazine.AmmoType.GetAmmoType(); + set => CylinderModule.AmmoType = value.GetItemType(); + } + + /// + /// Gets a of chambers in cylindric magazine. + /// + public IEnumerable Chambers => CylinderAmmoModule.GetChambersArrayForSerial(CylinderModule.ItemSerial, MaxAmmo).Select(baseChamber => new Chamber(baseChamber)); + + /// + public override void Resync() => CylinderModule._needsResyncing = true; + + /// + /// Rotates cylindric magazine by fixed rotatins. + /// + /// Rotations count. + public void Rotate(int rotations) => CylinderModule.RotateCylinder(rotations); + + /// + /// A basic wrapper for chamber in cylinder magazine. + /// + public class Chamber + { + private CylinderAmmoModule.Chamber baseChamber; + + /// + /// Initializes a new instance of the class. + /// + /// Basic class. + internal Chamber(CylinderAmmoModule.Chamber baseChamber) + { + this.baseChamber = baseChamber; + } + + /// + /// Gets or sets an state for current chamber. + /// + public RevolverChamberState State + { + get => (RevolverChamberState)baseChamber.ContextState; + set => baseChamber.ContextState = (CylinderAmmoModule.ChamberState)value; + } + } + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/NormalMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/NormalMagazine.cs new file mode 100644 index 000000000..dd8cfaa21 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/NormalMagazine.cs @@ -0,0 +1,88 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Primary +{ + using System; + + using Exiled.API.Enums; + using Exiled.API.Extensions; + + using InventorySystem.Items.Firearms.Modules; + + /// + /// Basic realization of . + /// + public class NormalMagazine : PrimaryMagazine + { + /// + /// Initializes a new instance of the class. + /// + /// target . + public NormalMagazine(MagazineModule magazine) + : base(magazine) + { + MagazineModule = magazine; + } + + /// + /// Gets an original . + /// + public MagazineModule MagazineModule { get; } + + /// + public override Firearm Firearm => Item.Get(MagazineModule.Firearm); + + /// + public override int MaxAmmo + { + set => MagazineModule._defaultCapacity = value; + } + + /// + public override int ConstantMaxAmmo => MagazineModule._defaultCapacity; + + /// + public override AmmoType AmmoType + { + get => Magazine.AmmoType.GetAmmoType(); + + set => MagazineModule._ammoType = value.GetItemType(); + } + + /// + /// Gets or sets a value indicating whether magazine is inserted. + /// + public bool MagazineInserted + { + get => MagazineModule.MagazineInserted; + + set + { + MagazineModule.MagazineInserted = value; + Resync(); + } + } + + /// + /// Removes magazine from current . + /// + /// + /// Affects on actual ammo count. + /// Removes all ammo from magazine. + /// + public void RemoveMagazine() => MagazineModule.ServerRemoveMagazine(); + + /// + /// Inserts current magazine from current . + /// + public void InsertMagazine() => MagazineModule.ServerInsertEmptyMagazine(); + + /// + public override void Resync() => MagazineModule.ServerResyncData(); + } +} diff --git a/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/PrimaryMagazine.cs b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/PrimaryMagazine.cs new file mode 100644 index 000000000..39ff42855 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/FirearmModules/Primary/PrimaryMagazine.cs @@ -0,0 +1,63 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items.FirearmModules.Primary +{ + using System; + + using Exiled.API.Enums; + using Exiled.API.Extensions; + + using InventorySystem.Items.Firearms.Modules; + + /// + /// Basic abstraction of whose are logically used to be a primary magazines. + /// + public abstract class PrimaryMagazine : Magazine + { + /// + /// Initializes a new instance of the class. + /// + /// target . + public PrimaryMagazine(IPrimaryAmmoContainerModule magazine) + : base(magazine) + { + Magazine = magazine; + } + + /// + /// Gets an original . + /// + public IPrimaryAmmoContainerModule Magazine { get; } + + /// + public override int MaxAmmo => Magazine.AmmoMax; + + /// + /// Gets a max avaible ammo count in magazine without attachments. + /// + public abstract int ConstantMaxAmmo { get; } + + /// + public override int Ammo + { + get => Magazine.AmmoStored; + + set + { + int modifyCount = Math.Max(0, value) - Ammo; + Magazine.ServerModifyAmmo(modifyCount); + Resync(); + } + } + + /// + /// Gets or sets an used for this magazine. + /// + public abstract AmmoType AmmoType { get; set; } + } +} diff --git a/EXILED/Exiled.API/Features/Items/Flashlight.cs b/EXILED/Exiled.API/Features/Items/Flashlight.cs index 7cdf432bf..93a3876ca 100644 --- a/EXILED/Exiled.API/Features/Items/Flashlight.cs +++ b/EXILED/Exiled.API/Features/Items/Flashlight.cs @@ -45,14 +45,6 @@ internal Flashlight(ItemType type) /// Can be or . public new ToggleableLightItemBase Base { get; } - /// - [Obsolete("Use IsEmittingLight instead.")] - public bool Active - { - get => IsEmittingLight; - set => IsEmittingLight = value; - } - /// /// Gets or sets a value indicating whether the item is emitting light. /// diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 7ba1afab5..e5207c99f 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -13,10 +13,10 @@ namespace Exiled.API.Features.Items using Exiled.API.Features.Core; using Exiled.API.Features.Pickups; using Exiled.API.Interfaces; - using InventorySystem; using InventorySystem.Items; using InventorySystem.Items.Armor; + using InventorySystem.Items.Autosync; using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; @@ -26,6 +26,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.ThrowableProjectiles; using InventorySystem.Items.ToggleableLights; using InventorySystem.Items.Usables; + using InventorySystem.Items.Usables.Scp1344; using InventorySystem.Items.Usables.Scp1576; using InventorySystem.Items.Usables.Scp244; using InventorySystem.Items.Usables.Scp330; @@ -50,6 +51,10 @@ public class Item : TypeCastObject, IWrapper public Item(ItemBase itemBase) { Base = itemBase; + + if (Base is ModularAutosyncItem modularItem && modularItem.InstantiationStatus is AutosyncInstantiationStatus.Template or AutosyncInstantiationStatus.SimulatedInstance) + return; + BaseToItem.Add(itemBase, this); if (Base.ItemSerial is 0 && itemBase.Owner != null) @@ -157,7 +162,12 @@ public ushort Serial /// /// Gets a value indicating whether this item is a weapon. /// - public bool IsWeapon => this is Firearm; + public bool IsWeapon => this is Firearm || Type is ItemType.Jailbird or ItemType.MicroHID; + + /// + /// Gets a value indicating whether or not this item is a firearm. + /// + public bool IsFirearm => this is Firearm; /// /// Gets a value indicating whether this item emits light. @@ -174,6 +184,15 @@ public ushort Serial /// public Player Owner => Player.Get(Base.Owner) ?? Server.Host; + /// + /// Gets or sets a reason for adding this item to the inventory. + /// + public ItemAddReason AddReason + { + get => Base.ServerAddReason; + set => Base.ServerAddReason = value; + } + /// /// Gets an existing or creates a new instance of one. /// @@ -196,6 +215,7 @@ public static Item Get(ItemBase itemBase) Scp330Bag scp330Bag => new Scp330(scp330Bag), Scp244Item scp244Item => new Scp244(scp244Item), Scp1576Item scp1576 => new Scp1576(scp1576), + Scp1344Item scp1344 => new Scp1344(scp1344), BaseConsumable consumable => new Consumable(consumable), _ => new Usable(usable), }, @@ -213,7 +233,7 @@ public static Item Get(ItemBase itemBase) Scp018Projectile => new Scp018(throwable), _ => new Throwable(throwable), }, - _ => new Item(itemBase), + _ => new(itemBase), }; } @@ -233,6 +253,15 @@ public static T Get(ItemBase itemBase) /// Returns the Item found or if not found. public static Item Get(ushort serial) => List.FirstOrDefault(x => x.Serial == serial); + /// + /// Gets the Item belonging to the specified serial. + /// + /// The Item serial. + /// The specified type. + /// Returns the Item found or if not found. + public static T Get(ushort serial) + where T : Item => Get(serial) as T; + /// /// Creates a new with the proper inherited subclass. /// @@ -254,6 +283,7 @@ public static T Get(ItemBase itemBase) ///
- SCP-330 can be casted to . ///
- SCP-2176 can be casted to the class. ///
- SCP-1576 can be casted to the class. + ///
- SCP-1344 can be casted to the class. ///
- Jailbird can be casted to the class. ///
/// @@ -282,6 +312,7 @@ ItemType.KeycardGuard or ItemType.KeycardJanitor or ItemType.KeycardO5 or ItemTy ItemType.SCP330 => new Scp330(), ItemType.SCP2176 => new Scp2176(owner), ItemType.SCP1576 => new Scp1576(), + ItemType.SCP1344 => new Scp1344(), ItemType.Jailbird => new Jailbird(), _ => new Item(type), }; @@ -307,6 +338,7 @@ ItemType.KeycardGuard or ItemType.KeycardJanitor or ItemType.KeycardO5 or ItemTy ///
- SCP-330 can be casted to . ///
- SCP-2176 can be casted to the class. ///
- SCP-1576 can be casted to the class. + ///
- SCP-1344 can be casted to the class. ///
- Jailbird can be casted to the class. ///
/// @@ -338,11 +370,11 @@ public static Item Create(ItemType type, Player owner = null) /// The rotation of the item. /// Whether the should be initially spawned. /// The created . - public virtual Pickup CreatePickup(Vector3 position, Quaternion rotation = default, bool spawn = true) + public virtual Pickup CreatePickup(Vector3 position, Quaternion? rotation = null, bool spawn = true) { PickupSyncInfo info = new(Type, Weight, Serial); - ItemPickupBase ipb = InventoryExtensions.ServerCreatePickup(Base, info, position, rotation); + ItemPickupBase ipb = InventoryExtensions.ServerCreatePickup(Base, info, position, rotation ?? Quaternion.identity); Base.OnRemoved(ipb); diff --git a/EXILED/Exiled.API/Features/Items/Jailbird.cs b/EXILED/Exiled.API/Features/Items/Jailbird.cs index a560abba5..b7a48eae6 100644 --- a/EXILED/Exiled.API/Features/Items/Jailbird.cs +++ b/EXILED/Exiled.API/Features/Items/Jailbird.cs @@ -11,6 +11,7 @@ namespace Exiled.API.Features.Items using Exiled.API.Features.Pickups; using Exiled.API.Interfaces; + using InventorySystem.Items; using InventorySystem.Items.Autosync; using InventorySystem.Items.Jailbird; using Mirror; @@ -152,13 +153,14 @@ public float GetDamage(JailbirdWearState wearState) public void Break() { WearState = JailbirdWearState.Broken; - using (new AutosyncRpc(Base, true, out NetworkWriter networkWriter)) + ItemIdentifier identifier = new(Base); + using (new AutosyncRpc(identifier, out NetworkWriter networkWriter)) { networkWriter.WriteByte(0); networkWriter.WriteByte((byte)JailbirdWearState.Broken); } - using (new AutosyncRpc(Base, true, out NetworkWriter networkWriter2)) + using (new AutosyncRpc(identifier, out NetworkWriter networkWriter2)) { networkWriter2.WriteByte(1); } diff --git a/EXILED/Exiled.API/Features/Items/MicroHid.cs b/EXILED/Exiled.API/Features/Items/MicroHid.cs index 80bde0708..f83dab90d 100644 --- a/EXILED/Exiled.API/Features/Items/MicroHid.cs +++ b/EXILED/Exiled.API/Features/Items/MicroHid.cs @@ -7,9 +7,15 @@ namespace Exiled.API.Features.Items { - using Exiled.API.Interfaces; + using System; + using System.Reflection; + using Exiled.API.Features.Pickups; + using Exiled.API.Interfaces; using InventorySystem.Items.MicroHID; + using InventorySystem.Items.MicroHID.Modules; + + using Random = UnityEngine.Random; /// /// A wrapper class for . @@ -34,13 +40,34 @@ internal MicroHid() { } + /// + /// Gets the of the MicroHID. + /// + public EnergyManagerModule EnergyManager => Base.EnergyManager; + + /// + /// Gets the of the MicroHID. + /// + public BrokenSyncModule BrokenModule => Base.BrokenSync; + + /// + /// Gets the of the MicroHID. + /// + public InputSyncModule InputModule => Base.InputSync; + + /// + /// Gets the of the MicroHID. + /// + public CycleController CycleController => Base.CycleController; + /// /// Gets or sets the remaining energy in the MicroHID. /// + /// Maximum energy is 1. Minimum energy is 0. public float Energy { - get => Base.RemainingEnergy; - set => Base.RemainingEnergy = value; + get => EnergyManager.Energy; + set => EnergyManager.ServerSetEnergy(Serial, value); } /// @@ -49,23 +76,128 @@ public float Energy public new MicroHIDItem Base { get; } /// - /// Gets or sets the . + /// Gets or sets a value indicating whether the MicroHID is broken. /// - public HidState State + public bool IsBroken { - get => Base.State; - set => Base.State = value; + get => BrokenModule.Broken; + set => BrokenModule.ServerSetBroken(Serial, value); } + /// + /// Gets a time when this was broken. + /// + /// A time when this was broken, or 0 if it is not broken. + public float BrokeTime => BrokenSyncModule.TryGetBrokenElapsed(Serial, out float time) ? time : 0; + + /// + /// Gets or sets the . + /// + public MicroHidPhase State + { + get => CycleController.Phase; + set => CycleController.Phase = value; + } + + /// + /// Gets or sets progress of winging up. + /// + /// A value between 0 and 1. + public float WindUpProgress + { + get => CycleController.ServerWindUpProgress; + set => CycleController.ServerWindUpProgress = value; + } + + /// + /// Gets or sets the last received . + /// + public MicroHidFiringMode LastFiringMode + { + get => CycleController.LastFiringMode; + set => CycleController.LastFiringMode = value; + } + + /// + /// Gets or sets the last received . + /// + public InputSyncModule.SyncData LastReceived + { + get => InputModule._lastReceived; + set => InputModule._lastReceived = value; + } + + /// + /// Gets a value indicating whether the is . + /// + public bool IsPrimary => InputModule.Primary; + /// /// Starts firing the MicroHID. /// - public void Fire() => Base.Fire(); + /// Fire mode. + public void Fire(MicroHidFiringMode firingMode = MicroHidFiringMode.PrimaryFire) + { + switch (firingMode) + { + case MicroHidFiringMode.PrimaryFire: + if (TryGetFireController(MicroHidFiringMode.PrimaryFire, out PrimaryFireModeModule primaryFireModeModule)) + primaryFireModeModule.ServerFire(); + break; + case MicroHidFiringMode.ChargeFire: + if (TryGetFireController(MicroHidFiringMode.ChargeFire, out ChargeFireModeModule chargeFireModeModule)) + chargeFireModeModule.ServerFire(); + break; + default: + if (TryGetFireController(MicroHidFiringMode.BrokenFire, out BrokenFireModeModule brokenFireModeModule)) + brokenFireModeModule.ServerFire(); + break; + } + } /// /// Recharges the MicroHID. /// - public void Recharge() => Base.Recharge(); + public void Recharge() + { + if (IsBroken) + Energy = Random.value; + else + Energy = 1; + } + + /// + /// Explodes the MicroHID. + /// + public void Explode() + { + if (TryGetFireController(MicroHidFiringMode.ChargeFire, out ChargeFireModeModule module)) + module.ServerExplode(); + } + + /// + /// Tries to get a assosiated with the specified . + /// + /// Target firing mode. + /// Found module or null. + /// Type of module. + /// true if module was found, false otherwise. + public bool TryGetFireController(MicroHidFiringMode firingMode, out T module) + where T : FiringModeControllerModule + { + if (CycleController._firingModeControllers.Count == 0) + CycleController.RecacheFiringModes(Base); + + module = (T)CycleController._firingModeControllers.Find(x => x.AssignedMode == firingMode); + return module != null; + } + + /// + /// Tries to get a assosiated with the last . + /// + /// Found module or null. + /// true if module was found, false otherwise. + public bool TryGetLastFireController(out FiringModeControllerModule module) => TryGetFireController(LastFiringMode, out module); /// /// Clones current object. diff --git a/EXILED/Exiled.API/Features/Items/Scp1344.cs b/EXILED/Exiled.API/Features/Items/Scp1344.cs new file mode 100644 index 000000000..460aeb8c0 --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Scp1344.cs @@ -0,0 +1,89 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using Exiled.API.Interfaces; + + using InventorySystem.Items.Usables; + using InventorySystem.Items.Usables.Scp1344; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; + + /// + /// A wrapper class for . + /// + public class Scp1344 : Usable, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The base class. + public Scp1344(Scp1344Item itemBase) + : base(itemBase) + { + Base = itemBase; + } + + /// + /// Initializes a new instance of the class. + /// + internal Scp1344() + : this((Scp1344Item)Server.Host.Inventory.CreateItemInstance(new(ItemType.SCP1344, 0), false)) + { + } + + /// + /// Gets the that this class is encapsulating. + /// + public new Scp1344Item Base { get; } + + /// + /// Gets a value indicating whether the item is worn. + /// + public bool IsWorn => Base.IsWorn; + + /// + /// Gets a value indicating whether it can be started to use. + /// + public bool CanStartUsing => Base.CanStartUsing; + + /// + /// Gets or sets the status of Scp1344. + /// + public Scp1344Status Status + { + get => Base.Status; + set => Base.Status = value; + } + + /// + /// Forcefully deactivate SCP-1344. + /// + /// Whether or not 1344 should be dropped. + public void Deactivate(bool dropItem = false) + { + if (Status is not(Scp1344Status.Active or Scp1344Status.Stabbing or Scp1344Status.Dropping)) + { + return; + } + + Base.Owner.DisableWearables(WearableElements.Scp1344Goggles); + Base.ActivateFinalEffects(); + Status = Scp1344Status.Idle; + + if (dropItem) + { + Base.ServerDropItem(true); + } + } + + /// + /// Forcefully activated SCP-1344. + /// + public void Actived() => Status = Scp1344Status.Stabbing; + } +} diff --git a/EXILED/Exiled.API/Features/Items/Scp244.cs b/EXILED/Exiled.API/Features/Items/Scp244.cs index 1ed62113c..0cfea6c3a 100644 --- a/EXILED/Exiled.API/Features/Items/Scp244.cs +++ b/EXILED/Exiled.API/Features/Items/Scp244.cs @@ -82,11 +82,11 @@ public bool Primed /// The rotation of the item. /// Whether the should be initially spawned. /// The created . - public override Pickup CreatePickup(Vector3 position, Quaternion rotation = default, bool spawn = true) + public override Pickup CreatePickup(Vector3 position, Quaternion? rotation = null, bool spawn = true) { PickupSyncInfo info = new(Type, Weight, Serial); - Scp244DeployablePickup ipb = (Scp244DeployablePickup)InventoryExtensions.ServerCreatePickup(Base, info, position, rotation); + Scp244DeployablePickup ipb = (Scp244DeployablePickup)InventoryExtensions.ServerCreatePickup(Base, info, position, rotation ?? Quaternion.identity); Base.OnRemoved(ipb); diff --git a/EXILED/Exiled.API/Features/Items/Scp330.cs b/EXILED/Exiled.API/Features/Items/Scp330.cs index 159e6ccac..38c9ded76 100644 --- a/EXILED/Exiled.API/Features/Items/Scp330.cs +++ b/EXILED/Exiled.API/Features/Items/Scp330.cs @@ -87,11 +87,6 @@ internal Scp330() /// public CandyKindID ExposedType { get; set; } = CandyKindID.None; - /// - /// Gets or sets the candy that will be added to the bag. Used for events. - /// - internal CandyKindID CandyToAdd { get; set; } = CandyKindID.None; - /// /// Adds a specific candy to the bag. /// @@ -245,11 +240,11 @@ public IEnumerable DropCandy(CandyKindID type, bool dropAll = fals /// The rotation to give the item. /// Whether the should be initially spawned. /// The created . - public override Pickup CreatePickup(Vector3 position, Quaternion rotation = default, bool spawn = true) + public override Pickup CreatePickup(Vector3 position, Quaternion? rotation = null, bool spawn = true) { PickupSyncInfo info = new(Type, Weight, Serial); - InventorySystem.Items.Usables.Scp330.Scp330Pickup ipb = (InventorySystem.Items.Usables.Scp330.Scp330Pickup)InventoryExtensions.ServerCreatePickup(Base, info, position, rotation); + InventorySystem.Items.Usables.Scp330.Scp330Pickup ipb = (InventorySystem.Items.Usables.Scp330.Scp330Pickup)InventoryExtensions.ServerCreatePickup(Base, info, position, rotation ?? Quaternion.identity); Base.OnRemoved(ipb); diff --git a/EXILED/Exiled.API/Features/Items/Usable.cs b/EXILED/Exiled.API/Features/Items/Usable.cs index fe07f3c24..6ba68e2cb 100644 --- a/EXILED/Exiled.API/Features/Items/Usable.cs +++ b/EXILED/Exiled.API/Features/Items/Usable.cs @@ -109,11 +109,11 @@ public float RemainingCooldown /// The rotation of the item. /// Whether the should be initially spawned. /// The created . - public override Pickup CreatePickup(Vector3 position, Quaternion rotation = default, bool spawn = true) + public override Pickup CreatePickup(Vector3 position, Quaternion? rotation = null, bool spawn = true) { PickupSyncInfo info = new(Type, Weight, Serial); - ItemPickupBase ipb = InventoryExtensions.ServerCreatePickup(Base, info, position, rotation); + ItemPickupBase ipb = InventoryExtensions.ServerCreatePickup(Base, info, position, rotation ?? Quaternion.identity); Pickup pickup = Pickup.Get(ipb); diff --git a/EXILED/Exiled.API/Features/Lift.cs b/EXILED/Exiled.API/Features/Lift.cs index 04b15f4c3..c38e146a3 100644 --- a/EXILED/Exiled.API/Features/Lift.cs +++ b/EXILED/Exiled.API/Features/Lift.cs @@ -21,7 +21,6 @@ namespace Exiled.API.Features using UnityEngine; using static Interactables.Interobjects.ElevatorChamber; - using static Interactables.Interobjects.ElevatorManager; using Elevator = Interactables.Interobjects.ElevatorDoor; @@ -33,7 +32,7 @@ public class Lift : IWrapper, IWorldSpace /// /// A containing all known s and their corresponding . /// - internal static readonly Dictionary ElevatorChamberToLift = new(8, new ComponentsEqualityComparer()); + internal static readonly Dictionary ElevatorChamberToLift = new(9, new ComponentsEqualityComparer()); /// /// Internal list that contains all ElevatorDoor for current group. @@ -121,8 +120,8 @@ public Quaternion Rotation /// public ElevatorSequence Status { - get => Base._curSequence; - set => Base._curSequence = value; + get => Base.CurSequence; + set => Base.CurSequence = value; } /// @@ -140,7 +139,7 @@ public ElevatorSequence Status ElevatorGroup.GateB => ElevatorType.GateB, ElevatorGroup.LczA01 or ElevatorGroup.LczA02 => ElevatorType.LczA, ElevatorGroup.LczB01 or ElevatorGroup.LczB02 => ElevatorType.LczB, - ElevatorGroup.Nuke => ElevatorType.Nuke, + ElevatorGroup.Nuke01 or ElevatorGroup.Nuke02 => ElevatorType.Nuke, _ => ElevatorType.Unknown, }; @@ -162,7 +161,7 @@ public ElevatorSequence Status /// /// Gets a value indicating whether the lift is locked. /// - public bool IsLocked => Base.ActiveLocks > 0; + public bool IsLocked => Base.ActiveLocksAnyDoors > 0 || Base.ActiveLocksAllDoors > 0; /// /// Gets or sets the . @@ -196,12 +195,12 @@ public float AnimationTime /// /// Gets the . /// - public int CurrentLevel => Base.CurrentLevel; + public int CurrentLevel => Base.DestinationLevel; /// /// Gets the . /// - public Doors.ElevatorDoor CurrentDestination => Door.Get(Base.CurrentDestination); + public Doors.ElevatorDoor CurrentDestination => Door.Get(Base.DestinationDoor); /// /// Gets a of which contains all the instances from the specified . @@ -272,9 +271,8 @@ public static bool TryMeltPlayer(Player player) /// Tries to start the lift. /// /// The destination level. - /// Indicates whether the start will be forced. - /// if the lift was started successfully; otherwise, . - public bool TryStart(int level, bool isForced = false) => TrySetDestination(Group, level, isForced); + /// Allowing queing. + public void TryStart(int level, bool allowQueueing = false) => Base.ServerSetDestination(level, allowQueueing); /// /// Changes lock of the lift. @@ -295,12 +293,7 @@ public void ChangeLock(DoorLockReason lockReason) else { door.ChangeLock((DoorLockType)lockReason); - - if (CurrentLevel != 1) - TrySetDestination(Group, 1, true); } - - Base.RefreshLocks(Group, door.Base); } } diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index 6f1d288db..081999068 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -7,34 +7,26 @@ namespace Exiled.API.Features { +#pragma warning disable SA1401 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; - using Decals; using Enums; using Exiled.API.Extensions; using Exiled.API.Features.Hazards; - using Exiled.API.Features.Lockers; using Exiled.API.Features.Pickups; using Exiled.API.Features.Toys; - using global::Hazards; using InventorySystem; - using InventorySystem.Items.Firearms; - using InventorySystem.Items.Firearms.BasicMessages; using InventorySystem.Items.Pickups; using InventorySystem.Items.ThrowableProjectiles; using Items; using LightContainmentZoneDecontamination; using MapGeneration; - using MapGeneration.Distributors; - using PlayerRoles.PlayableScps.Scp939; using PlayerRoles.Ragdolls; - using RelativePositioning; using UnityEngine; using Utils; - using Utils.Networking; using Object = UnityEngine.Object; @@ -44,24 +36,14 @@ namespace Exiled.API.Features public static class Map { /// - /// A list of s on the map. + /// Gets a list of s on the map. /// - internal static readonly List TeleportsValue = new(8); + internal static List TeleportsValue = new(); private static AmbientSoundPlayer ambientSoundPlayer; private static SqueakSpawner squeakSpawner; - /// - /// Gets the tantrum prefab. - /// - public static TantrumEnvironmentalHazard TantrumPrefab => TantrumHazard.TantrumPrefab; // TODO: Remove this. - - /// - /// Gets the amnestic cloud prefab. - /// - public static Scp939AmnesticCloudInstance AmnesticCloudPrefab => AmnesticCloudHazard.AmnesticCloudPrefab; // TODO: Remove this. - /// /// Gets a value indicating whether decontamination has begun in the light containment zone. /// @@ -79,20 +61,6 @@ DecontaminationController.Singleton.NetworkDecontaminationOverride is Decontamin /// public static ReadOnlyCollection PocketDimensionTeleports { get; } = TeleportsValue.AsReadOnly(); - /// - /// Gets all objects in the current map. - /// - /// - /// This property is obsolete. Use instead to retrieve a collection of all instances. - /// - [Obsolete("Use Locker.List instead.")] - public static ReadOnlyCollection Lockers { get; } = Features.Lockers.Locker.BaseToExiledLockers.Keys.ToList().AsReadOnly(); - - /// - /// Gets all objects. - /// - public static ReadOnlyCollection Toys => AdminToy.BaseToAdminToy.Values.ToList().AsReadOnly(); // TODO: Obsolete it and make people use AdminToy.List - /// /// Gets or sets the current seed of the map. /// @@ -102,7 +70,7 @@ public static int Seed set { if (!SeedSynchronizer.MapGenerated) - SeedSynchronizer._singleton.Network_syncSeed = value; + SeedSynchronizer.Seed = value; } } @@ -121,7 +89,7 @@ public static bool IsDecontaminationEnabled /// /// Gets the . /// - public static AmbientSoundPlayer AmbientSoundPlayer => ambientSoundPlayer ??= ReferenceHub.HostHub.GetComponent(); + public static AmbientSoundPlayer AmbientSoundPlayer => ambientSoundPlayer ??= ReferenceHub._hostHub.GetComponent(); /// /// Gets the . @@ -229,16 +197,6 @@ public static void ResetLightsColor() light.NetworkOverrideColor = Color.clear; } - /// - /// Gets a random object from the current map. - /// - /// - /// This method is obsolete. Use instead to get a random instance. - /// - /// A randomly selected object. - [Obsolete("Use Locker.Random() instead.")] - public static MapGeneration.Distributors.Locker GetRandomLocker() => Lockers.GetRandomValue(); - /// /// Gets a random . /// @@ -267,15 +225,6 @@ public static void PlayAmbientSound(int id) AmbientSoundPlayer.RpcPlaySound(AmbientSoundPlayer.clips[id].index); } - /// - /// Places a Tantrum (SCP-173's ability) in the indicated position. - /// - /// The position where you want to spawn the Tantrum. - /// Whether the tantrum will apply the effect. - /// If is , the tantrum is moved slightly up from its original position. Otherwise, the collision will not be detected and the slowness will not work. - /// The instance. - public static TantrumHazard PlaceTantrum(Vector3 position, bool isActive = true) => TantrumHazard.PlaceTantrum(position, isActive); // TODO: Remove this. - /// /// Destroy all objects. /// @@ -319,7 +268,7 @@ public static void CleanAllRagdolls(IEnumerable ragDolls) /// /// The position of the blood decal. /// The direction of the blood decal. - public static void PlaceBlood(Vector3 position, Vector3 direction) => new GunDecalMessage(position, direction, DecalPoolType.Blood).SendToAuthenticated(0); + public static void PlaceBlood(Vector3 position, Vector3 direction) => _ = 0; /* new GunDecalMessage(position, direction, DecalPoolType.Blood).SendToAuthenticated(0);*/ // TODO: Not finish /// /// Gets all the near cameras. @@ -380,15 +329,17 @@ public static void ExplodeEffect(Vector3 position, ProjectileType projectileType /// The audio clip ID to play. public static void PlayGunSound(Vector3 position, ItemType firearmType, byte maxDistance = 45, byte audioClipId = 0) { + // TODO: Not finish + /* GunAudioMessage msg = new() { Weapon = firearmType, AudioClipId = audioClipId, MaxDistance = maxDistance, - ShooterHub = ReferenceHub.HostHub, + ShooterHub = ReferenceHub._hostHub, ShooterPosition = new RelativePosition(position), }; - msg.SendToAuthenticated(); + msg.SendToAuthenticated();*/ } /// @@ -413,9 +364,9 @@ internal static void ClearCache() Ragdoll.BasicRagdollToRagdoll.Clear(); - Items.Firearm.ItemTypeToFirearmInstance.Clear(); - Items.Firearm.BaseCodesValue.Clear(); - Items.Firearm.AvailableAttachmentsValue.Clear(); + Firearm.ItemTypeToFirearmInstance.Clear(); + Firearm.BaseCodesValue.Clear(); + Firearm.AvailableAttachmentsValue.Clear(); } } } diff --git a/EXILED/Exiled.API/Features/Npc.cs b/EXILED/Exiled.API/Features/Npc.cs index 28ee0d117..4055dfa6a 100644 --- a/EXILED/Exiled.API/Features/Npc.cs +++ b/EXILED/Exiled.API/Features/Npc.cs @@ -15,10 +15,12 @@ namespace Exiled.API.Features using CentralAuth; using CommandSystem; + using CommandSystem.Commands.RemoteAdmin.Dummies; using Exiled.API.Enums; using Exiled.API.Features.Components; using Exiled.API.Features.Roles; using Footprinting; + using GameCore; using MEC; using Mirror; using PlayerRoles; @@ -46,7 +48,7 @@ public Npc(GameObject gameObject) /// /// Gets a list of Npcs. /// - public static new List List => Player.List.OfType().ToList(); + public static new IReadOnlyCollection List => Dictionary.Values.OfType().ToList(); /// /// Gets or sets the player's position. @@ -62,6 +64,113 @@ public override Vector3 Position } } + /// + /// Gets or sets the player being followed. + /// + /// The npc must have . + public Player? FollowedPlayer + { + get => !GameObject.TryGetComponent(out PlayerFollower follower) ? null : Player.Get(follower._hubToFollow); + + set + { + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + { + GameObject.AddComponent()._hubToFollow = value?.ReferenceHub; + return; + } + + follower._hubToFollow = value?.ReferenceHub; + } + } + + /// + /// Gets or sets the Max Distance of the npc. + /// + /// The npc must have . + public float? MaxDistance + { + get + { + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + return null; + + return follower._maxDistance; + } + + set + { + if(!value.HasValue) + return; + + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + { + GameObject.AddComponent()._maxDistance = value.Value; + return; + } + + follower._maxDistance = value.Value; + } + } + + /// + /// Gets or sets the Min Distance of the npc. + /// + /// The npc must have . + public float? MinDistance + { + get + { + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + return null; + + return follower._minDistance; + } + + set + { + if(!value.HasValue) + return; + + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + { + GameObject.AddComponent()._minDistance = value.Value; + return; + } + + follower._minDistance = value.Value; + } + } + + /// + /// Gets or sets the Speed of the npc. + /// + /// The npc must have . + public float? Speed + { + get + { + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + return null; + + return follower._speed; + } + + set + { + if(!value.HasValue) + return; + + if (!GameObject.TryGetComponent(out PlayerFollower follower)) + { + GameObject.AddComponent()._speed = value.Value; + return; + } + + follower._speed = value.Value; + } + } + /// /// Retrieves the NPC associated with the specified ReferenceHub. /// @@ -137,74 +246,19 @@ public override Vector3 Position /// /// The name of the NPC. /// The RoleTypeId of the NPC. - /// The player ID of the NPC. - /// The userID of the NPC. - /// The position to spawn the NPC. - /// The spawned. - [Obsolete("This metod is marked as obsolet due to a bug that make player have the same id. Use Npc.Spawn(string) instead")] - public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId = PlayerAuthenticationManager.DedicatedId, Vector3? position = null) + /// The position where the NPC should spawn. + /// Docs4. + public static Npc Spawn(string name, RoleTypeId role, Vector3 position) { - GameObject newObject = UnityEngine.Object.Instantiate(Mirror.NetworkManager.singleton.playerPrefab); - - Npc npc = new(newObject) - { - IsNPC = true, - }; - - if (!RecyclablePlayerId.FreeIds.Contains(id) && RecyclablePlayerId._autoIncrement >= id) - { - Log.Warn($"{Assembly.GetCallingAssembly().GetName().Name} tried to spawn an NPC with a duplicate PlayerID. Using auto-incremented ID instead to avoid an ID clash."); - id = new RecyclablePlayerId(true).Value; - } - - try - { - if (userId == PlayerAuthenticationManager.DedicatedId) - { - npc.ReferenceHub.authManager.SyncedUserId = userId; - try - { - npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.DedicatedServer; - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - } - else - { - npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.Unverified; - npc.ReferenceHub.authManager._privUserId = userId == string.Empty ? $"Dummy@localhost" : userId; - } - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - - try - { - npc.ReferenceHub.roleManager.InitializeNewRole(RoleTypeId.None, RoleChangeReason.None); - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - - FakeConnection fakeConnection = new(id); - NetworkServer.AddPlayerForConnection(fakeConnection, newObject); - - npc.ReferenceHub.nicknameSync.Network_myNickSync = name; - Dictionary.Add(newObject, npc); + Npc npc = new(DummyUtils.SpawnDummy(name)); Timing.CallDelayed(0.5f, () => { - npc.Role.Set(role, SpawnReason.RoundStart, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory); - - if (position is not null) - npc.Position = position.Value; + npc.Role.Set(role); + npc.Position = position; }); + Dictionary.Add(npc.GameObject, npc); return npc; } @@ -214,58 +268,11 @@ public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId /// The name of the NPC. /// The RoleTypeId of the NPC, defaulting to None. /// Whether the NPC should be ignored by round ending checks. - /// The userID of the NPC for authentication. Defaults to the Dedicated ID. /// The position where the NPC should spawn. If null, the default spawn location is used. /// The spawned. - public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ignored = false, string userId = PlayerAuthenticationManager.DedicatedId, Vector3? position = null) + public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ignored = false, Vector3? position = null) { - GameObject newObject = UnityEngine.Object.Instantiate(Mirror.NetworkManager.singleton.playerPrefab); - - Npc npc = new(newObject) - { - IsNPC = true, - }; - - FakeConnection fakeConnection = new(npc.Id); - - try - { - if (userId == PlayerAuthenticationManager.DedicatedId) - { - npc.ReferenceHub.authManager.SyncedUserId = userId; - try - { - npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.DedicatedServer; - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - } - else - { - npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.Unverified; - npc.ReferenceHub.authManager._privUserId = userId == string.Empty ? $"Dummy-{npc.Id}@localhost" : userId; - } - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - - try - { - npc.ReferenceHub.roleManager.InitializeNewRole(RoleTypeId.None, RoleChangeReason.None); - } - catch (Exception e) - { - Log.Debug($"Ignore: {e.Message}"); - } - - NetworkServer.AddPlayerForConnection(fakeConnection, newObject); - - npc.ReferenceHub.nicknameSync.Network_myNickSync = name; - Dictionary.Add(newObject, npc); + Npc npc = new(DummyUtils.SpawnDummy(name)); Timing.CallDelayed(0.5f, () => { @@ -278,16 +285,38 @@ public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ign if (ignored) Round.IgnoredPlayers.Add(npc.ReferenceHub); + Dictionary.Add(npc.GameObject, npc); return npc; } /// /// Destroys all NPCs currently spawned. /// - public static void DestroyAll() + public static void DestroyAll() => DummyUtils.DestroyAllDummies(); + + /// + /// Follow a specific player. + /// + /// the Player to follow. + public void Follow(Player player) { - foreach (Npc npc in List) - npc.Destroy(); + PlayerFollower follow = !GameObject.TryGetComponent(out PlayerFollower follower) ? GameObject.AddComponent() : follower; + + follow.Init(player.ReferenceHub); + } + + /// + /// Follow a specific player. + /// + /// the Player to follow. + /// the max distance the npc will go. + /// the min distance the npc will go. + /// the speed the npc will go. + public void Follow(Player player, float maxDistance, float minDistance, float speed = 30f) + { + PlayerFollower follow = !GameObject.TryGetComponent(out PlayerFollower follower) ? GameObject.AddComponent() : follower; + + follow.Init(player.ReferenceHub, maxDistance, minDistance, speed); } /// @@ -298,11 +327,8 @@ public void Destroy() try { Round.IgnoredPlayers.Remove(ReferenceHub); - NetworkConnectionToClient conn = ReferenceHub.connectionToClient; - ReferenceHub.OnDestroy(); - CustomNetworkManager.TypedSingleton.OnServerDisconnect(conn); - Dictionary.Remove(GameObject); - Object.Destroy(GameObject); + Dictionary.Remove(ReferenceHub.gameObject); + NetworkServer.Destroy(ReferenceHub.gameObject); } catch (Exception e) { diff --git a/EXILED/Exiled.API/Features/Pickups/FirearmPickup.cs b/EXILED/Exiled.API/Features/Pickups/FirearmPickup.cs index df1fb0c6a..3db97dac8 100644 --- a/EXILED/Exiled.API/Features/Pickups/FirearmPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/FirearmPickup.cs @@ -9,7 +9,12 @@ namespace Exiled.API.Features.Pickups { using Exiled.API.Interfaces; + using InventorySystem.Items; using InventorySystem.Items.Firearms; + using InventorySystem.Items.Firearms.Attachments; + using InventorySystem.Items.Firearms.Modules; + + using UnityEngine; using BaseFirearm = InventorySystem.Items.Firearms.FirearmPickup; @@ -36,10 +41,11 @@ internal FirearmPickup(ItemType type) : base(type) { Base = (BaseFirearm)((Pickup)this).Base; - IsDistributed = true; + // TODO not finish + /* if (type is ItemType.ParticleDisruptor && Status.Ammo == 0) - Status = new FirearmStatus(5, FirearmStatusFlags.MagazineInserted, 0); + Status = new FirearmStatus(5, FirearmStatusFlags.MagazineInserted, 0);*/ } /// @@ -48,54 +54,107 @@ internal FirearmPickup(ItemType type) public new BaseFirearm Base { get; } /// - /// Gets or sets a value indicating whether the pickup is already distributed. + /// Gets a value indicating whether the pickup is already distributed. /// - public bool IsDistributed - { - get => Base.Distributed; - set => Base.Distributed = value; - } + public bool IsDistributed { get; internal set; } /// - /// Gets or sets the . + /// Gets or sets a value indicating how much ammo can contain this . /// - public FirearmStatus Status - { - get => Base.NetworkStatus; - set => Base.NetworkStatus = value; - } + public int MaxAmmo { get; set; } /// - /// Gets or sets a value indicating how many ammo have this . + /// Gets or sets a value indicating how much ammo have this . /// - public byte Ammo + public int Ammo { - get => Base.NetworkStatus.Ammo; - set => Base.NetworkStatus = new(value, Base.NetworkStatus.Flags, Base.NetworkStatus.Attachments); + get + { + if (!AttachmentPreview.TryGetOrAddInstance(Type, out Firearm baseFirearm)) + return 0; + + Items.Firearm firearm = Items.Item.Get(baseFirearm); + + ushort oldSerial = firearm.Serial; + + firearm.Serial = Serial; + + int ammo = firearm.PrimaryMagazine.Ammo; + + firearm.Serial = oldSerial; + + return ammo; + } + + set + { + if (!AttachmentPreview.TryGetOrAddInstance(Type, out Firearm baseFirearm)) + return; + + Items.Firearm firearm = Items.Item.Get(baseFirearm); + + ushort oldSerial = firearm.Serial; + + firearm.Serial = Serial; + + firearm.PrimaryMagazine.Ammo = value; + + firearm.Serial = oldSerial; + } } /// - /// Gets or sets the . + /// Gets or sets a ammo drain per shoot. /// - public FirearmStatusFlags Flags - { - get => Base.NetworkStatus.Flags; - set => Base.NetworkStatus = new(Base.NetworkStatus.Ammo, value, Base.NetworkStatus.Attachments); - } + /// + /// Always by default. + /// Applied on a high layer nether basegame ammo controllers. + /// + public int AmmoDrain { get; set; } = 1; /// /// Gets or sets a value indicating whether the attachment code have this . /// public uint Attachments { - get => Base.NetworkStatus.Attachments; - set => Base.NetworkStatus = new(Base.NetworkStatus.Ammo, Base.NetworkStatus.Flags, value); + get => Base.Worldmodel.AttachmentCode; + set => Base.Worldmodel.Setup(Base.CurId, Base.Worldmodel.WorldmodelType, value); + } + + /// + public override void Spawn() + { + base.Spawn(); + if (!IsDistributed) + Base.OnDistributed(); } /// /// Returns the FirearmPickup in a human readable format. /// /// A string containing FirearmPickup related data. - public override string ToString() => $"{Type} ({Serial}) [{Weight}] *{Scale}* |{IsDistributed}| -{Ammo}-"; + public override string ToString() => $"{Type} ({Serial}) [{Weight}] *{Scale}* |{IsDistributed}| -{/*Ammo*/0}-"; + + /// + internal override void ReadItemInfo(Items.Item item) + { + Items.Firearm firearm = (Items.Firearm)item; + MaxAmmo = firearm.PrimaryMagazine.ConstantMaxAmmo; + AmmoDrain = firearm.AmmoDrain; + base.ReadItemInfo(item); + } + + /// + protected override void InitializeProperties(ItemBase itemBase) + { + base.InitializeProperties(itemBase); + if (!(itemBase as Firearm).TryGetModule(out IPrimaryAmmoContainerModule magazine)) + { + Log.Error($"firearm prefab {itemBase.ItemTypeId} doesnt have an primary magazine module(unexpected)"); + return; + } + + MaxAmmo = magazine.AmmoMax; + } } } diff --git a/EXILED/Exiled.API/Features/Pickups/MicroHIDPickup.cs b/EXILED/Exiled.API/Features/Pickups/MicroHIDPickup.cs index 4298fece5..255c32b6a 100644 --- a/EXILED/Exiled.API/Features/Pickups/MicroHIDPickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/MicroHIDPickup.cs @@ -7,7 +7,9 @@ namespace Exiled.API.Features.Pickups { + using Exiled.API.Features.Items; using Exiled.API.Interfaces; + using InventorySystem.Items.MicroHID.Modules; using BaseMicroHID = InventorySystem.Items.MicroHID.MicroHIDPickup; @@ -40,15 +42,107 @@ internal MicroHIDPickup() /// public new BaseMicroHID Base { get; } + /// + /// Gets the of this . + /// + public CycleController CycleController => Base._cycleController; + /// /// Gets or sets the MicroHID Energy Level. /// public float Energy { - get => Base.NetworkEnergy; - set => Base.NetworkEnergy = value; + get => EnergyManagerModule.GetEnergy(Serial); + set => EnergyManagerModule.SyncEnergy[Serial] = value; + } + + /// + /// Gets or sets the . + /// + public MicroHidPhase State + { + get => CycleController.Phase; + set => CycleController.Phase = value; } + /// + /// Gets or sets progress of winging up. + /// + /// A value between 0 and 1. + public float WindUpProgress + { + get => CycleController.ServerWindUpProgress; + set => CycleController.ServerWindUpProgress = value; + } + + /// + /// Gets or sets the last received . + /// + public MicroHidFiringMode LastFiringMode + { + get => CycleController.LastFiringMode; + set => CycleController.LastFiringMode = value; + } + + /// + /// Starts firing the MicroHID. + /// + /// Fire mode. + public void Fire(MicroHidFiringMode firingMode = MicroHidFiringMode.PrimaryFire) + { + switch (firingMode) + { + case MicroHidFiringMode.PrimaryFire: + if (TryGetFireController(MicroHidFiringMode.PrimaryFire, out PrimaryFireModeModule primaryFireModeModule)) + primaryFireModeModule.ServerFire(); + break; + case MicroHidFiringMode.ChargeFire: + if (TryGetFireController(MicroHidFiringMode.ChargeFire, out ChargeFireModeModule chargeFireModeModule)) + chargeFireModeModule.ServerFire(); + break; + default: + if (TryGetFireController(MicroHidFiringMode.BrokenFire, out BrokenFireModeModule brokenFireModeModule)) + brokenFireModeModule.ServerFire(); + break; + } + } + + /// + /// Explodes the MicroHID. + /// + public void Explode() + { + if (TryGetFireController(MicroHidFiringMode.ChargeFire, out ChargeFireModeModule module)) + module.ServerExplode(); + } + + /// + /// Tries to get a assosiated with the specified . + /// + /// Target firing mode. + /// Found module or null. + /// Type of module. + /// true if module was found, false otherwise. + public bool TryGetFireController(MicroHidFiringMode firingMode, out T module) + where T : FiringModeControllerModule + { + if (CycleController._firingModeControllers.Count == 0) + { + module = null; + return false; + } + + module = (T)CycleController._firingModeControllers.Find(x => x.AssignedMode == firingMode); + return module != null; + } + + /// + /// Tries to get a assosiated with the last . + /// + /// Found module or null. + /// true if module was found, false otherwise. + public bool TryGetLastFireController(out FiringModeControllerModule module) => TryGetFireController(LastFiringMode, out module); + /// /// Returns the MicroHIDPickup in a human readable format. /// diff --git a/EXILED/Exiled.API/Features/Pickups/Pickup.cs b/EXILED/Exiled.API/Features/Pickups/Pickup.cs index 89e9df487..e4ed1b585 100644 --- a/EXILED/Exiled.API/Features/Pickups/Pickup.cs +++ b/EXILED/Exiled.API/Features/Pickups/Pickup.cs @@ -128,18 +128,9 @@ internal Pickup(ItemType type) public Room Room => Room.FindParentRoom(GameObject); /// - /// Gets or sets the pickup's PhysicsModule. + /// Gets the pickup's PhysicsModule. /// - public PickupStandardPhysics PhysicsModule - { - get => Base.PhysicsModule as PickupStandardPhysics; - [Obsolete("Unsafe.")] - set - { - Base.PhysicsModule.DestroyModule(); - Base.PhysicsModule = value; - } - } + public PickupStandardPhysics PhysicsModule => Base.PhysicsModule as PickupStandardPhysics; /// /// Gets or sets the unique serial number for the item. @@ -246,7 +237,7 @@ public PickupSyncInfo Info /// /// Gets or sets the previous owner of this item. /// - /// + /// public Player PreviousOwner { get => Player.Get(Base.PreviousOwner.Hub); @@ -269,7 +260,7 @@ public bool InUse /// /// Gets or sets the pickup position. /// - /// + /// public Vector3 Position { get => Base.Position; @@ -288,7 +279,7 @@ public RelativePosition RelativePosition /// /// Gets or sets the pickup rotation. /// - /// + /// public Quaternion Rotation { get => Base.Rotation; @@ -541,8 +532,8 @@ public static Pickup Create(ItemType type) /// The rotation to spawn the . /// An optional previous owner of the item. /// The . See documentation of for more information on casting. - /// - public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion rotation, Player previousOwner = null) => Create(type).Spawn(position, rotation, previousOwner); + /// + public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion? rotation = null, Player previousOwner = null) => Create(type).Spawn(position, rotation, previousOwner); /// /// Creates and spawns a . @@ -553,23 +544,10 @@ public static Pickup Create(ItemType type) /// An optional previous owner of the item. /// The specified type. /// The . See documentation of for more information on casting. - /// - public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion rotation, Player previousOwner = null) + /// + public static Pickup CreateAndSpawn(ItemType type, Vector3 position, Quaternion? rotation = null, Player previousOwner = null) where T : Pickup => CreateAndSpawn(type, position, rotation, previousOwner) as T; - /// - /// Spawns a . - /// - /// The too spawn. - /// The position to spawn the at. - /// The rotation to spawn the . - /// An optional previous owner of the item. - /// The Spawn. - /// - [Obsolete("Use pickup.Spawn(Vector3, Quaternion, Player) instead of this", true)] - public static Pickup Spawn(Pickup pickup, Vector3 position, Quaternion rotation, Player previousOwner = null) - => pickup.Spawn(position, rotation, previousOwner); - /// /// Returns the amount of time it will take for the provided to pick up this item, based on and active status effects. /// @@ -589,7 +567,7 @@ public float PickupTimeForPlayer(Player player) /// Spawns pickup on a server. /// /// - public void Spawn() + public virtual void Spawn() { // condition for projectiles if (!GameObject.activeSelf) @@ -610,11 +588,11 @@ public void Spawn() /// The rotation to spawn the . /// An optional previous owner of the item. /// The spawned . - /// - public Pickup Spawn(Vector3 position, Quaternion rotation, Player previousOwner = null) + /// + public Pickup Spawn(Vector3 position, Quaternion? rotation = null, Player previousOwner = null) { Position = position; - Rotation = rotation; + Rotation = rotation ?? Quaternion.identity; PreviousOwner = previousOwner; Spawn(); diff --git a/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs b/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs index e6bdb2614..17a0691b9 100644 --- a/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs +++ b/EXILED/Exiled.API/Features/Pickups/Projectiles/Projectile.cs @@ -114,19 +114,6 @@ internal Projectile(ItemType type) public static Projectile Create(ProjectileType projectiletype) where T : Projectile => Create(projectiletype) as T; - /// - /// Spawns a . - /// - /// The too spawn. - /// The position to spawn the at. - /// The rotation to spawn the . - /// Whether the should be in active state after spawn. - /// An optional previous owner of the item. - /// The Spawn. - [Obsolete("Use pickup.Spawn(Vector3, Quaternion, Player) instead of this", true)] - public static Projectile Spawn(Projectile pickup, Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null) - => pickup.Spawn(position, rotation, shouldBeActive, previousOwner); - /// /// Creates and spawns a . /// @@ -135,8 +122,8 @@ public static Projectile Spawn(Projectile pickup, Vector3 position, Quaternion r /// The rotation to spawn the . /// Whether the should be in active state after spawn. /// An optional previous owner of the item. - /// The . See documentation of for more information on casting. - public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null) => Create(type).Spawn(position, rotation, shouldBeActive, previousOwner); + /// The . See documentation of for more information on casting. + public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion? rotation = null, bool shouldBeActive = true, Player previousOwner = null) => Create(type).Spawn(position, rotation, shouldBeActive, previousOwner); /// /// Creates and spawns a . @@ -147,8 +134,8 @@ public static Projectile Spawn(Projectile pickup, Vector3 position, Quaternion r /// Whether the should be in active state after spawn. /// An optional previous owner of the item. /// The specified type. - /// The . See documentation of for more information on casting. - public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null) + /// The . See documentation of for more information on casting. + public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position, Quaternion? rotation = null, bool shouldBeActive = true, Player previousOwner = null) where T : Projectile => CreateAndSpawn(type, position, rotation, shouldBeActive, previousOwner) as T; /// @@ -164,10 +151,10 @@ public static Projectile CreateAndSpawn(ProjectileType type, Vector3 position /// Whether the should be in active state after spawn. /// An optional previous owner of the item. /// The spawned . - public Projectile Spawn(Vector3 position, Quaternion rotation, bool shouldBeActive = true, Player previousOwner = null) + public Projectile Spawn(Vector3 position, Quaternion? rotation = null, bool shouldBeActive = true, Player previousOwner = null) { Position = position; - Rotation = rotation; + Rotation = rotation ?? Quaternion.identity; PreviousOwner = previousOwner; Spawn(); diff --git a/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs b/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs index 1452a921d..f33d935a9 100644 --- a/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs +++ b/EXILED/Exiled.API/Features/Pickups/Projectiles/Scp018Projectile.cs @@ -50,18 +50,9 @@ internal Scp018Projectile() public new BaseScp018Projectile Base { get; } /// - /// Gets or sets the pickup's PhysicsModule. + /// Gets the pickup's PhysicsModule. /// - public new Scp018Physics PhysicsModule - { - get => Base.PhysicsModule as Scp018Physics; - [Obsolete("Unsafe.", true)] - set - { - Base.PhysicsModule.DestroyModule(); - Base.PhysicsModule = value; - } - } + public new Scp018Physics PhysicsModule => Base.PhysicsModule as Scp018Physics; /// /// Gets or sets the pickup's max velocity. diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 751bd9f80..778f94133 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -36,18 +36,18 @@ namespace Exiled.API.Features using InventorySystem.Disarming; using InventorySystem.Items; using InventorySystem.Items.Armor; - using InventorySystem.Items.Firearms; using InventorySystem.Items.Firearms.Attachments; - using InventorySystem.Items.Firearms.BasicMessages; + using InventorySystem.Items.Firearms.Modules; + using InventorySystem.Items.Firearms.ShotEvents; using InventorySystem.Items.Usables; using InventorySystem.Items.Usables.Scp330; using MapGeneration.Distributors; using MEC; using Mirror; using Mirror.LiteNetLib4Mirror; - using NorthwoodLib; using PlayerRoles; using PlayerRoles.FirstPersonControl; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; using PlayerRoles.RoleAssign; using PlayerRoles.Spectating; using PlayerRoles.Voice; @@ -136,7 +136,7 @@ public Player(GameObject gameObject) /// /// Gets a list of all 's on the server. /// - public static IReadOnlyCollection List => Dictionary.Values; + public static IReadOnlyCollection List => Dictionary.Values.Where(x => !x.IsNPC).ToList(); /// /// Gets a containing cached and their user ids. @@ -158,7 +158,7 @@ public Player(GameObject gameObject) public Dictionary> CustomRoleFriendlyFireMultiplier { get; set; } = DictionaryPool>.Pool.Get(); /// - /// Gets or sets a unique custom role that does not adbide to base game for this player. Used in conjunction with . + /// Gets or sets a unique custom role that does not abide to base game for this player. Used in conjunction with . /// public string UniqueRole { get; set; } = string.Empty; @@ -211,12 +211,6 @@ private set /// public bool HasHint => CurrentHint != null; - /// - /// Gets the 's , can be null. - /// - [Obsolete("Use IVoiceRole::VoiceModule instead.")] - public VoiceModuleBase VoiceModule => Role is Roles.IVoiceRole voiceRole ? voiceRole.VoiceModule : null; - /// /// Gets the 's , can be null. /// @@ -260,12 +254,6 @@ public int Id /// public string UserId => referenceHub.authManager.UserId; - /// - /// Gets or sets the player's custom user id. - /// - [Obsolete("Remove by NW", true)] - public string CustomUserId { get; set; } - /// /// Gets the player's user id without the authentication. /// @@ -308,9 +296,9 @@ public AuthenticationType AuthenticationType public bool IsVerified { get; internal set; } /// - /// Gets or sets a value indicating whether the player is a NPC. + /// Gets a value indicating whether the player is a NPC. /// - public bool IsNPC { get; set; } + public bool IsNPC => ReferenceHub.IsDummy; /// /// Gets a value indicating whether the player has an active CustomName. @@ -359,7 +347,7 @@ public string CustomInfo set { // NW Client check. - if (value.Contains('<')) + if (value.Contains('<')) { foreach (string token in value.Split('<')) { @@ -591,7 +579,7 @@ public Role Role get => role ??= Role.Create(RoleManager.CurrentRole); internal set { - PreviousRole = role.Type; + PreviousRole = role?.Type ?? RoleTypeId.None; role = value; } } @@ -625,7 +613,7 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences /// /// Gets a value indicating whether the player is reloading a weapon. /// - public bool IsReloading => CurrentItem is Firearm firearm && !firearm.Base.AmmoManagerModule.Standby; + public bool IsReloading => CurrentItem is Firearm firearm && !firearm.IsReloading; /// /// Gets a value indicating whether the player is aiming with a weapon. @@ -683,11 +671,16 @@ public ScpSpawnPreferences.SpawnPreferences ScpPreferences public bool IsDead => Role?.IsDead ?? false; /// - /// Gets a value indicating whether the player's is any NTF rank. + /// Gets a value indicating whether the player's is any Foundation Forces. /// Equivalent to checking the player's . /// - // TODO: Change logic for FacilityGuard in next major update - public bool IsNTF => Role?.Team is Team.FoundationForces; + public bool IsFoundationForces => Role?.Team is Team.FoundationForces; + + /// + /// Gets a value indicating whether the player's is any NTF rank and not a Facility Guard. + /// Equivalent to checking the player's . + /// + public bool IsNTF => Role?.Team is Team.FoundationForces && Role?.Type is not RoleTypeId.FacilityGuard; /// /// Gets a value indicating whether the player's is any Chaos rank. @@ -736,6 +729,15 @@ public bool IsBypassModeEnabled set => ReferenceHub.serverRoles.BypassMode = value; } + /// + /// Gets or sets the player's emotion. + /// + public EmotionPresetType Emotion + { + get => EmotionSync.GetEmotionPreset(ReferenceHub); + set => EmotionSync.ServerSetEmotionPreset(ReferenceHub, value); + } + /// /// Gets or sets a value indicating whether the player is muted. /// @@ -826,7 +828,7 @@ public bool IsGodModeEnabled /// /// Gets the player's unit name. /// - public string UnitName => Role.Base is PlayerRoles.HumanRole humanRole ? UnitNameMessageHandler.GetReceived(humanRole.AssignedSpawnableTeam, humanRole.UnitNameId) : string.Empty; + public string UnitName => Role is HumanRole humanRole ? humanRole.UnitName : string.Empty; /// /// Gets or sets the player's unit id. @@ -1326,7 +1328,7 @@ public static Player Get(string args) if (!player.IsVerified || player.Nickname is null) continue; - if (!player.Nickname.Contains(args, StringComparison.OrdinalIgnoreCase)) + if (!player.Nickname.ToLower().Contains(args.ToLower())) continue; string secondString = player.Nickname; @@ -1473,16 +1475,6 @@ public static Player Get(string args) /// An representing the processed players. public static IEnumerable GetProcessedData(ArraySegment args, int startIndex = 0) => GetProcessedData(args, startIndex, out string[] _); - /// - /// Adds a player's UserId to the list of reserved slots. - /// - /// This method does not permanently give a user a reserved slot. The slot will be removed if the reserved slots are reloaded. - /// The UserId of the player to add. - /// if the slot was successfully added, or if the provided UserId already has a reserved slot. - /// - // TODO: Remove this method - public static bool AddReservedSlot(string userId) => ReservedSlot.Users.Add(userId); - /// /// Adds a player's UserId to the list of reserved slots. /// @@ -1535,15 +1527,6 @@ public static bool AddToWhitelist(string userId, bool isPermanent) /// public static void ReloadWhitelist() => WhiteList.Reload(); - /// - /// Adds the player's UserId to the list of reserved slots. - /// - /// This method does not permanently give a user a reserved slot. The slot will be removed if the reserved slots are reloaded. - /// if the slot was successfully added, or if the player already has a reserved slot. - /// - // TODO: Remove this method - public bool GiveReservedSlot() => AddReservedSlot(UserId); - /// /// Adds a player's UserId to the list of reserved slots. /// @@ -1788,9 +1771,12 @@ public bool ReloadWeapon() { if (CurrentItem is Firearm firearm) { - bool result = firearm.Base.AmmoManagerModule.ServerTryReload(); + // TODO not finish + /* + bool result = firearm.Base.Ammo.ServerTryReload(); Connection.Send(new RequestMessage(firearm.Serial, RequestType.Reload)); return result; + */ } return false; @@ -2161,7 +2147,7 @@ public void Hurt(Player attacker, float amount, DamageType damageType = DamageTy /// The throw force. /// The armor penetration amount. public void Hurt(Player attacker, float damage, Vector3 force = default, int armorPenetration = 0) => - Hurt(new ExplosionDamageHandler(attacker.Footprint, force, damage, armorPenetration)); + Hurt(new ExplosionDamageHandler(attacker.Footprint, force, damage, armorPenetration, ExplosionType.Grenade)); /// /// Hurts the player. @@ -2264,7 +2250,7 @@ public void Vaporize(Player attacker = null, string cassieAnnouncement = "") if ((Role.Side != Side.Scp) && !string.IsNullOrEmpty(cassieAnnouncement)) Cassie.Message(cassieAnnouncement); - Kill(new DisruptorDamageHandler(attacker?.Footprint ?? Footprint, -1)); + Kill(new DisruptorDamageHandler(new DisruptorShotEvent(Item.Create(ItemType.ParticleDisruptor, attacker).Base as InventorySystem.Items.Firearms.Firearm, DisruptorActionModule.FiringState.FiringSingle), Vector3.up, -1)); } /// @@ -2465,17 +2451,6 @@ public ushort GetAmmoLimit(AmmoType type, bool ignoreArmor = false) return InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub); } - /// - /// Gets the maximum amount of ammo the player can hold, given the ammo . - /// - /// The of the ammo to check. - /// The maximum amount of ammo this player can carry. - [Obsolete("Use Player::GetAmmoLimit(AmmoType, bool) instead.")] - public int GetAmmoLimit(AmmoType type) - { - return (int)InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub); - } - /// /// Gets the maximum amount of ammo the player can hold, given the ammo . /// This limit will scale with the armor the player is wearing. @@ -2532,15 +2507,6 @@ public void ResetAmmoLimit(AmmoType ammoType) /// If the player has a custom limit for the specific . public bool HasCustomAmmoLimit(AmmoType ammoType) => CustomAmmoLimits.ContainsKey(ammoType); - /// - /// Gets the maximum amount of an the player can hold, based on the armor the player is wearing, as well as server configuration. - /// - /// The to check. - /// The maximum amount of items in the category that the player can hold. - [Obsolete("Use Player::GetCategoryLimit(ItemCategory, bool) instead.")] - public int GetCategoryLimit(ItemCategory category) => - InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub); - /// /// Gets the maximum amount of an the player can hold, based on the armor the player is wearing, as well as server configuration. /// @@ -2668,16 +2634,6 @@ public Item AddItem(ItemType itemType) return item; } - /// - /// Adds an item of the specified type with default durability(ammo/charge) and no mods to the player's inventory. - /// - /// The item to be added. - /// The attachments to be added to the item. - /// The given to the player. - [Obsolete("Use AddItem(ItemType) or AddItem(FirearmType, IEnumerable)", true)] - public Item AddItem(ItemType itemType, IEnumerable identifiers = null) - => itemType.GetFirearmType() is FirearmType.None ? AddItem(itemType) : AddItem(itemType.GetFirearmType(), identifiers); - /// /// Adds an firearm of the specified type with default durability(ammo/charge) and no mods to the player's inventory. /// @@ -2695,12 +2651,15 @@ public Item AddItem(FirearmType firearmType, IEnumerable i else if (Preferences is not null && Preferences.TryGetValue(firearmType, out AttachmentIdentifier[] attachments)) firearm.Base.ApplyAttachmentsCode(attachments.GetAttachmentsCode(), true); + // TODO Not finish + /* FirearmStatusFlags flags = FirearmStatusFlags.MagazineInserted; if (firearm.Attachments.Any(a => a.Name == AttachmentName.Flashlight)) flags |= FirearmStatusFlags.FlashlightEnabled; firearm.Base.Status = new FirearmStatus(firearm.MaxAmmo, flags, firearm.Base.GetCurrentAttachmentsCode()); + */ } AddItem(item); @@ -2726,17 +2685,6 @@ public IEnumerable AddItem(ItemType itemType, int amount) return items; } - /// - /// Adds the amount of items of the specified type with default durability(ammo/charge) and no mods to the player's inventory. - /// - /// The item to be added. - /// The amount of items to be added. - /// The attachments to be added to the item. - /// An containing the items given. - [Obsolete("Use AddItem(ItemType, int) or AddItem(FirearmType, int, IEnumerable)", true)] - public IEnumerable AddItem(ItemType itemType, int amount, IEnumerable identifiers) - => itemType.GetFirearmType() is FirearmType.None ? AddItem(itemType, amount) : AddItem(itemType.GetFirearmType(), amount, identifiers); - /// /// Adds the amount of firearms of the specified type with default durability(ammo/charge) and no mods to the player's inventory. /// @@ -2776,22 +2724,6 @@ public IEnumerable AddItem(IEnumerable items) return returnedItems; } - /// - /// Adds the list of items of the specified type with default durability(ammo/charge) and no mods to the player's inventory. - /// - /// The of and of to be added. - /// An containing the items given. - [Obsolete("Use AddItem(Dictionary>) instead of this", true)] - public IEnumerable AddItem(Dictionary> items) - { - List returnedItems = new(items.Count); - - foreach (KeyValuePair> item in items) - returnedItems.Add(AddItem(item.Key, item.Value)); - - return returnedItems; - } - /// /// Adds the list of items of the specified type with default durability(ammo/charge) and no mods to the player's inventory. /// @@ -2847,8 +2779,9 @@ public void AddItem(Firearm item, IEnumerable identifiers) /// Adds an item to the player's inventory. /// /// The of the item to be added. + /// The reason the item was added. /// The that was added. - public Item AddItem(Pickup pickup) => Item.Get(Inventory.ServerAddItem(pickup.Type, pickup.Serial, pickup.Base)); + public Item AddItem(Pickup pickup, ItemAddReason addReason = ItemAddReason.Undefined) => Item.Get(Inventory.ServerAddItem(pickup.Type, addReason, pickup.Serial, pickup.Base)); /// /// Adds an item to the player's inventory. @@ -2858,7 +2791,7 @@ public void AddItem(Firearm item, IEnumerable identifiers) /// The that was added. public Item AddItem(FirearmPickup pickup, IEnumerable identifiers) { - Firearm firearm = Item.Get(Inventory.ServerAddItem(pickup.Type, pickup.Serial, pickup.Base)); + Firearm firearm = Item.Get(Inventory.ServerAddItem(pickup.Type, ItemAddReason.Undefined, pickup.Serial, pickup.Base)); if (identifiers is not null) firearm.AddAttachment(identifiers); @@ -2871,12 +2804,14 @@ public Item AddItem(FirearmPickup pickup, IEnumerable iden /// /// The item to be added. /// The object of the item. + /// The reason the item was added. /// The that was added. - public Item AddItem(ItemBase itemBase, Item item = null) + public Item AddItem(ItemBase itemBase, Item item = null, ItemAddReason addReason = ItemAddReason.AdminCommand) { try { item ??= Item.Get(itemBase); + item.AddReason = addReason; Inventory.UserInventory.Items[item.Serial] = itemBase; @@ -2900,23 +2835,6 @@ public Item AddItem(ItemBase itemBase, Item item = null) return null; } - /// - /// Adds the of items to the player's inventory. - /// - /// The item to be added. - /// The amount of items to be added. - [Obsolete("Removed this method can't be functional")] - public void AddItem(Item item, int amount) => _ = item; - - /// - /// Adds the of items to the player's inventory. - /// - /// The firearm to be added. - /// The amount of items to be added. - /// The attachments to be added to the item. - [Obsolete("Removed this method can't be functional")] - public void AddItem(Firearm firearm, int amount, IEnumerable identifiers) => _ = firearm; - /// /// Adds the list of items to the player's inventory. /// @@ -3293,13 +3211,6 @@ public void EnableEffect(EffectType type, float duration = 0f, bool addDurationI public bool EnableEffect(EffectType type, byte intensity, float duration = 0f, bool addDurationIfActive = false) => TryGetEffect(type, out StatusEffectBase statusEffect) && EnableEffect(statusEffect, intensity, duration, addDurationIfActive); - /// - /// Enables a status effect on the player. - /// - /// The to enable. - [Obsolete("Use SyncEffect(Effect) instead of this")] - public void EnableEffect(Effect effect) => SyncEffect(effect); - /// /// Syncs the status effect on the player. /// @@ -3359,13 +3270,6 @@ public void EnableEffects(IEnumerable types, float duration = 0f, bo } } - /// - /// Enables a of on the player. - /// - /// The of to enable. - [Obsolete("Use SyncEffects(IEnumerable) instead of this")] - public void EnableEffects(IEnumerable effects) => SyncEffects(effects); - /// /// Syncs a of on the player. /// @@ -3785,7 +3689,7 @@ public void SetCooldownItem(float time, ItemType itemType) /// /// Explode the player. /// - public void Explode() => ExplosionUtils.ServerExplode(ReferenceHub); + public void Explode() => ExplosionUtils.ServerExplode(ReferenceHub, ExplosionType.Grenade); /// /// Explode the player. @@ -3800,6 +3704,37 @@ public void SetCooldownItem(float time, ItemType itemType) /// The projectile that will create the effect. public void ExplodeEffect(ProjectileType projectileType) => Map.ExplodeEffect(Position, projectileType); + /// + public override bool Equals(object obj) + { + Player player = obj as Player; + return (object)player != null && ReferenceHub == player.ReferenceHub; + } + + /// + public override int GetHashCode() + { + return base.GetHashCode(); + } + + /// + /// Returns whether the two players are the same. + /// + /// The first player instance. + /// The second player instance. + /// if the values are equal. +#pragma warning disable SA1201 + public static bool operator ==(Player player1, Player player2) => player1?.Equals(player2) ?? player2 is null; + + /// + /// Returns whether the two players are different. + /// + /// The first player instance. + /// The second player instance. + /// if the values are not equal. + public static bool operator !=(Player player1, Player player2) => !(player1 == player2); +#pragma warning restore SA1201 + /// /// Converts the player in a human-readable format. /// diff --git a/EXILED/Exiled.API/Features/PrefabHelper.cs b/EXILED/Exiled.API/Features/PrefabHelper.cs index 4fe664cc5..82180ac9a 100644 --- a/EXILED/Exiled.API/Features/PrefabHelper.cs +++ b/EXILED/Exiled.API/Features/PrefabHelper.cs @@ -9,8 +9,6 @@ namespace Exiled.API.Features { using System; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; using System.Reflection; using Exiled.API.Enums; @@ -23,18 +21,21 @@ namespace Exiled.API.Features /// public static class PrefabHelper { - private static readonly Dictionary Stored = new(); + /// + /// A containing all and their corresponding . + /// + internal static readonly Dictionary Prefabs = new(Enum.GetValues(typeof(PrefabType)).Length); /// - /// Gets a dictionary of to . + /// Gets a of and their corresponding . /// - public static ReadOnlyDictionary PrefabToGameObject => new(Stored); + public static IReadOnlyDictionary PrefabToGameObject => Prefabs; /// - /// Gets the prefab attribute of a prefab type. + /// Gets the from a . /// - /// The prefab type. - /// The . + /// The . + /// The corresponding . public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType) { Type type = prefabType.GetType(); @@ -42,64 +43,75 @@ public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType) } /// - /// Gets the prefab of the specified . + /// Gets the of the specified . /// - /// The to get prefab of. - /// The to get. - /// Returns the prefab component as {T}. - public static T GetPrefab(PrefabType type) - where T : Component + /// The . + /// Returns the . + public static GameObject GetPrefab(PrefabType prefabType) { - if (!Stored.TryGetValue(type, out GameObject gameObject) || !gameObject.TryGetComponent(out T component)) - return null; + if (Prefabs.TryGetValue(prefabType, out GameObject prefab)) + return prefab; - return component; + return null; } /// - /// Spawns a prefab on server. + /// Tries to get the of the specified . /// - /// The prefab type. - /// The position to spawn the prefab. - /// The rotation of the prefab. - /// The instantied. - public static GameObject Spawn(PrefabType prefabType, Vector3 position = default, Quaternion rotation = default) + /// The . + /// The of the . + /// Returns true if the was found. + public static bool TryGetPrefab(PrefabType prefabType, out GameObject gameObject) { - if (!Stored.TryGetValue(prefabType, out GameObject gameObject)) - return null; - GameObject newGameObject = UnityEngine.Object.Instantiate(gameObject, position, rotation); - NetworkServer.Spawn(newGameObject); - return newGameObject; + gameObject = GetPrefab(prefabType); + return gameObject is not null; } /// - /// Spawns a prefab on server. + /// Gets a from the of the specified . /// - /// The prefab type. - /// The position to spawn the prefab. - /// The rotation of the prefab. + /// The . /// The type. - /// The instantied. - public static T Spawn(PrefabType prefabType, Vector3 position = default, Quaternion rotation = default) + /// Returns the . + public static T GetPrefab(PrefabType prefabType) where T : Component { - T obj = UnityEngine.Object.Instantiate(GetPrefab(prefabType), position, rotation); - NetworkServer.Spawn(obj.gameObject); - return obj; + if (Prefabs.TryGetValue(prefabType, out GameObject prefab) && prefab.TryGetComponent(out T component)) + return component; + + return null; } /// - /// Loads all prefabs. + /// Spawns the of the specified . /// - internal static void LoadPrefabs() + /// The . + /// The position where the will spawn. + /// The rotation of the . + /// Returns the instantied. + public static GameObject Spawn(PrefabType prefabType, Vector3 position = default, Quaternion? rotation = null) { - Stored.Clear(); + if (!TryGetPrefab(prefabType, out GameObject gameObject)) + return null; - foreach (PrefabType prefabType in EnumUtils.Values) - { - PrefabAttribute attribute = prefabType.GetPrefabAttribute(); - Stored.Add(prefabType, NetworkClient.prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value); - } + GameObject newGameObject = UnityEngine.Object.Instantiate(gameObject, position, rotation ?? Quaternion.identity); + NetworkServer.Spawn(newGameObject); + return newGameObject; + } + + /// + /// Spawns the of the specified . + /// + /// The . + /// The position where the will spawn. + /// The rotation of the . + /// The type. + /// Returns the of the . + public static T Spawn(PrefabType prefabType, Vector3 position = default, Quaternion? rotation = null) + where T : Component + { + GameObject gameObject = Spawn(prefabType, position, rotation); + return gameObject?.GetComponent(); } } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Ragdoll.cs b/EXILED/Exiled.API/Features/Ragdoll.cs index d27c076da..8cde5d8cb 100644 --- a/EXILED/Exiled.API/Features/Ragdoll.cs +++ b/EXILED/Exiled.API/Features/Ragdoll.cs @@ -117,7 +117,7 @@ public DamageHandlerBase DamageHandler /// /// Gets a value indicating whether the ragdoll has been already cleaned up. /// - public bool IsFrozen => Base._frozen; + public bool IsFrozen => Base.Frozen; /// /// Gets or sets a value indicating whether the ragdoll can be cleaned up. @@ -358,8 +358,8 @@ public static Ragdoll CreateAndSpawn(RagdollData networkInfo) /// The rotation of the ragdoll. /// The optional owner of the ragdoll. /// The ragdoll. - public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, DamageHandlerBase damageHandler, Vector3 position, Quaternion rotation, Player owner = null) - => CreateAndSpawn(new(owner?.ReferenceHub ?? Server.Host.ReferenceHub, damageHandler, roleType, position, rotation, name, NetworkTime.time)); + public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, DamageHandlerBase damageHandler, Vector3 position, Quaternion? rotation = null, Player owner = null) + => CreateAndSpawn(new(owner?.ReferenceHub ?? Server.Host.ReferenceHub, damageHandler, roleType, position, rotation ?? Quaternion.identity, name, NetworkTime.time)); /// /// Creates and spawns a new ragdoll. @@ -371,7 +371,7 @@ public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, DamageHan /// The rotation of the ragdoll. /// The optional owner of the ragdoll. /// The ragdoll. - public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, string deathReason, Vector3 position, Quaternion rotation, Player owner = null) + public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, string deathReason, Vector3 position, Quaternion? rotation = null, Player owner = null) => CreateAndSpawn(roleType, name, new CustomReasonDamageHandler(deathReason), position, rotation, owner); /// diff --git a/EXILED/Exiled.API/Features/Recontainer.cs b/EXILED/Exiled.API/Features/Recontainer.cs index 6ebf128c3..17f59c97d 100644 --- a/EXILED/Exiled.API/Features/Recontainer.cs +++ b/EXILED/Exiled.API/Features/Recontainer.cs @@ -193,7 +193,16 @@ public static bool IsContainmentSequenceSuccessful /// /// Begins the overcharge procedure. /// - public static void BeginOvercharge() => Base.BeginOvercharge(); + /// Make than is call after the . + public static void BeginOvercharge(bool endOvercharge = true) + { + Base.BeginOvercharge(); + if (endOvercharge) + { + Base._delayStopwatch.Stop(); + Base._unlockStopwatch.Start(); + } + } /// /// Ends the overcharge procedure. diff --git a/EXILED/Exiled.API/Features/Respawn.cs b/EXILED/Exiled.API/Features/Respawn.cs index 9ac5d6812..82282435c 100644 --- a/EXILED/Exiled.API/Features/Respawn.cs +++ b/EXILED/Exiled.API/Features/Respawn.cs @@ -13,8 +13,11 @@ namespace Exiled.API.Features using CustomPlayerEffects; using Enums; + using Extensions; using PlayerRoles; using Respawning; + using Respawning.Waves; + using Respawning.Waves.Generic; using UnityEngine; /// @@ -25,6 +28,16 @@ public static class Respawn private static GameObject ntfHelicopterGameObject; private static GameObject chaosCarGameObject; + /// + /// Gets the of paused 's. + /// + public static List PausedWaves { get; } = new(); + + /// + /// Gets the containing faction influence. + /// + public static Dictionary FactionInfluence => FactionInfluenceManager.Influence; + /// /// Gets the NTF Helicopter's . /// @@ -54,174 +67,340 @@ public static GameObject ChaosVan } /// - /// Gets or sets the next known that will spawn. + /// Gets the next known that will spawn. + /// + /// This returns SpawnableFaction.None unless a respawn has already started. + public static SpawnableFaction NextKnownSpawnableFaction => WaveManager._nextWave is not null ? WaveManager._nextWave.GetSpawnableFaction() : SpawnableFaction.None; + + /// + /// Gets the current state of the . /// - public static SpawnableTeamType NextKnownTeam + public static WaveQueueState CurrentState => WaveManager.State; + + /// + /// Gets a value indicating whether the respawn process for a is currently in progress.. + /// + public static bool IsSpawning => WaveManager.State == WaveQueueState.WaveSpawning; + + /// + /// Gets or sets a value indicating whether spawn protection is enabled. + /// + public static bool ProtectionEnabled { - get => RespawnManager.Singleton.NextKnownTeam; - set => RespawnManager.Singleton.NextKnownTeam = value; + get => SpawnProtected.IsProtectionEnabled; + set => SpawnProtected.IsProtectionEnabled = value; } /// - /// Gets or sets the amount of seconds before the next respawn phase will occur. + /// Gets or sets the spawn protection time, in seconds. /// - public static float TimeUntilNextPhase + public static float ProtectionTime { - get => RespawnManager.Singleton._timeForNextSequence - (float)RespawnManager.Singleton._stopwatch.Elapsed.TotalSeconds; - set => RespawnManager.Singleton._timeForNextSequence = (float)RespawnManager.Singleton._stopwatch.Elapsed.TotalSeconds + value; + get => SpawnProtected.SpawnDuration; + set => SpawnProtected.SpawnDuration = value; } /// - /// Gets a indicating the amount of time before the next respawn wave will occur. + /// Gets or sets a value indicating whether spawn protected players can shoot. /// - public static TimeSpan TimeUntilSpawnWave => TimeSpan.FromSeconds(TimeUntilNextPhase); + public static bool ProtectedCanShoot + { + get => SpawnProtected.CanShoot; + set => SpawnProtected.CanShoot = value; + } /// - /// Gets a indicating the moment in UTC time the next respawn wave will occur. + /// Gets a of s that have spawn protection. /// - public static DateTime NextTeamTime => DateTime.UtcNow.AddSeconds(TimeUntilSpawnWave.TotalSeconds); + public static List ProtectedTeams => SpawnProtected.ProtectedTeams; /// - /// Gets a value indicating whether a team is currently being spawned or the animations are playing for a team. + /// Tries to get a . /// - public static bool IsSpawning => RespawnManager.Singleton._curSequence is RespawnManager.RespawnSequencePhase.PlayingEntryAnimations or RespawnManager.RespawnSequencePhase.SpawningSelectedTeam; + /// The found . + /// Type of . + /// true if was successfully found. Otherwise, false. + /// + public static bool TryGetWaveBase(out T spawnableWaveBase) + where T : SpawnableWaveBase => WaveManager.TryGet(out spawnableWaveBase); /// - /// Gets or sets the amount of spawn tickets belonging to the Chaos Insurgency. + /// Tries to get a . /// - /// - public static float ChaosTickets + /// A determining which wave to search for. + /// The found . + /// true if was successfully found. Otherwise, false. + /// + public static bool TryGetWaveBase(SpawnableFaction spawnableFaction, out SpawnableWaveBase spawnableWaveBase) { - get => RespawnTokensManager.Counters[0].Amount; - set => RespawnTokensManager.ModifyTokens(SpawnableTeamType.ChaosInsurgency, value); + spawnableWaveBase = WaveManager.Waves.Find(x => x.GetSpawnableFaction() == spawnableFaction); + return spawnableWaveBase is not null; } /// - /// Gets or sets the amount of spawn tickets belonging to the NTF. + /// Tries to get an of . /// - /// - public static float NtfTickets + /// A determining which waves to search for. + /// The containing found 's if there are any, otherwise null. + /// true if was successfully found. Otherwise, false. + /// + public static bool TryGetWaveBases(Faction faction, out IEnumerable spawnableWaveBases) { - get => RespawnTokensManager.Counters[1].Amount; - set => RespawnTokensManager.ModifyTokens(SpawnableTeamType.NineTailedFox, value); + List spawnableWaves = new(); + spawnableWaves.AddRange(WaveManager.Waves.Where(x => x.TargetFaction == faction)); + + if (spawnableWaves.IsEmpty()) + { + spawnableWaveBases = null; + return false; + } + + spawnableWaveBases = spawnableWaves; + return true; } /// - /// Gets or sets a value indicating whether spawn protection is enabled. + /// Advances the respawn timer for s. /// - public static bool ProtectionEnabled + /// The whose 's timers are to be advanced. + /// Number of seconds to advance the timers by. + /// This advances the timer for both the normal and mini wave. + public static void AdvanceTimer(Faction faction, float seconds) => WaveManager.AdvanceTimer(faction, seconds); + + /// + /// Advances the respawn timer for s. + /// + /// The whose 's timers are to be advanced. + /// A representing the amount of time to advance the timers by. + /// This advances the timer for both the normal and mini wave. + public static void AdvanceTimer(Faction faction, TimeSpan time) => AdvanceTimer(faction, (float)time.TotalSeconds); + + /// + /// Advances the respawn timer for s. + /// + /// The whose 's timer is to be advanced. + /// Number of seconds to advance the timers by. + public static void AdvanceTimer(SpawnableFaction spawnableFaction, float seconds) { - get => SpawnProtected.IsProtectionEnabled; - set => SpawnProtected.IsProtectionEnabled = value; + foreach (SpawnableWaveBase spawnableWaveBase in WaveManager.Waves) + { + TimeBasedWave timeBasedWave = (TimeBasedWave)spawnableWaveBase; + if (timeBasedWave.GetSpawnableFaction() == spawnableFaction) + { + timeBasedWave.Timer.AddTime(Mathf.Abs(seconds)); + } + } } /// - /// Gets or sets the spawn protection time, in seconds. + /// Advances the respawn timer for s. /// - public static float ProtectionTime + /// The whose 's timer is to be advanced. + /// A representing the amount of time to advance the timers by. + public static void AdvanceTimer(SpawnableFaction spawnableFaction, TimeSpan time) => AdvanceTimer(spawnableFaction, (float)time.TotalSeconds); + + /// + /// Play the spawn effect of a . + /// + /// The whose effect should be played. + public static void PlayEffect(SpawnableWaveBase wave) { - get => SpawnProtected.SpawnDuration; - set => SpawnProtected.SpawnDuration = value; + WaveUpdateMessage.ServerSendUpdate(wave, UpdateMessageFlags.Trigger); } /// - /// Gets or sets a value indicating whether spawn protected players can shoot. + /// Summons the NTF chopper. /// - public static bool ProtectedCanShoot + public static void SummonNtfChopper() { - get => SpawnProtected.CanShoot; - set => SpawnProtected.CanShoot = value; + if (TryGetWaveBase(SpawnableFaction.NtfWave, out SpawnableWaveBase wave)) + PlayEffect(wave); } /// - /// Gets a of that have spawn protection. + /// Summons the Chaos Insurgency van. /// - public static List ProtectedTeams => SpawnProtected.ProtectedTeams; + /// This will also trigger Music effect. + /// + public static void SummonChaosInsurgencyVan() + { + if (TryGetWaveBase(SpawnableFaction.ChaosWave, out SpawnableWaveBase wave)) + PlayEffect(wave); + } /// - /// Play an effect when a certain class spawns. + /// Grants tokens to a given 's s. /// - /// The effect to be played. - public static void PlayEffect(byte effect) => PlayEffects(new[] { effect }); + /// The to whose s to grant tokens. + /// The amount of tokens to grant. + /// true if tokens were successfully granted to an , otherwise false. + public static bool GrantTokens(Faction faction, int amount) + { + if (TryGetWaveBases(faction, out IEnumerable waveBases)) + { + foreach (ILimitedWave limitedWave in waveBases.OfType()) + { + limitedWave.RespawnTokens += amount; + } + + return true; + } + + return false; + } /// - /// Play an effect when a certain class spawns. + /// Removes tokens from a given 's s. /// - /// The effect to be played. - public static void PlayEffect(RespawnEffectType effect) => PlayEffects(new[] { effect }); + /// The from whose s to remove tokens. + /// The amount of tokens to remove. + /// true if tokens were successfully removed from an , otherwise false. + public static bool RemoveTokens(Faction faction, int amount) + { + if (TryGetWaveBases(faction, out IEnumerable waveBases)) + { + foreach (ILimitedWave limitedWave in waveBases.OfType()) + { + limitedWave.RespawnTokens = Math.Max(0, limitedWave.RespawnTokens - amount); + } + + return true; + } + + return false; + } /// - /// Play effects when a certain class spawns. + /// Modifies tokens of a given 's s by a given amount. /// - /// The effects to be played. - public static void PlayEffects(byte[] effects) + /// The whose s' tokens are to be modified. + /// The amount of tokens to add/remove. + /// true if tokens were successfully modified for an , otherwise false. + public static bool ModifyTokens(Faction faction, int amount) { - foreach (RespawnEffectsController controller in RespawnEffectsController.AllControllers) - controller?.RpcPlayEffects(effects); + if (TryGetWaveBases(faction, out IEnumerable waveBases)) + { + foreach (ILimitedWave limitedWave in waveBases.OfType()) + { + limitedWave.RespawnTokens = amount; + } + + return true; + } + + return false; } /// - /// Play effects when a certain class spawns. + /// Tries to get the tokens of a given 's . /// - /// The effects to be played. - public static void PlayEffects(RespawnEffectType[] effects) => PlayEffects(effects.Select(effect => (byte)effect).ToArray()); + /// The from whose to get the tokens. + /// The amount of tokens an has, if one was found, otherwise 0. + /// true if an was successfully found, otherwise false. + public static bool TryGetTokens(SpawnableFaction spawnableFaction, out int tokens) + { + if (TryGetWaveBase(spawnableFaction, out SpawnableWaveBase waveBase) && waveBase is ILimitedWave limitedWave) + { + tokens = limitedWave.RespawnTokens; + return true; + } + + tokens = 0; + return false; + } /// - /// Summons the NTF chopper. + /// Sets the amount of tokens of an of the given . /// - public static void SummonNtfChopper() => PlayEffects(new[] { RespawnEffectType.SummonNtfChopper }); + /// The whose 's tokens to set. + /// The amount of tokens to set. + /// true if tokens were successfully set for an , otherwise false. + public static bool SetTokens(SpawnableFaction spawnableFaction, int amount) + { + if (TryGetWaveBase(spawnableFaction, out SpawnableWaveBase waveBase) && waveBase is ILimitedWave limitedWave) + { + limitedWave.RespawnTokens = amount; + return true; + } + + return false; + } /// - /// Summons the van. + /// Starts the spawn sequence of the given . /// - /// Whether to play the Chaos Insurgency spawn music. - public static void SummonChaosInsurgencyVan(bool playMusic = true) + /// The whose wave to spawn. + /// Whether the wave should be a mini wave or not. + public static void ForceWave(Faction faction, bool isMini = false) { - PlayEffects( - playMusic - ? new[] - { - RespawnEffectType.PlayChaosInsurgencyMusic, - RespawnEffectType.SummonChaosInsurgencyVan, - } - : new[] - { - RespawnEffectType.SummonChaosInsurgencyVan, - }); + if (faction.TryGetSpawnableFaction(out SpawnableFaction spawnableFaction, isMini)) + { + ForceWave(spawnableFaction); + } } /// - /// Grants tickets to a . + /// Starts the spawn sequence of the given . /// - /// The to grant tickets to. - /// The amount of tickets to grant. - public static void GrantTickets(SpawnableTeamType team, float amount) => RespawnTokensManager.GrantTokens(team, Math.Max(0, amount)); + /// The whose wave to spawn. + public static void ForceWave(SpawnableFaction spawnableFaction) + { + if (TryGetWaveBase(spawnableFaction, out SpawnableWaveBase spawnableWaveBase)) + { + ForceWave(spawnableWaveBase); + } + } /// - /// Removes tickets from a . + /// Starts the spawn sequence of the given . /// - /// The to remove tickets from. - /// The amount of tickets to remove. - public static void RemoveTickets(SpawnableTeamType team, float amount) => RespawnTokensManager.RemoveTokens(team, Math.Max(0, amount)); + /// The to spawn. + public static void ForceWave(SpawnableWaveBase spawnableWaveBase) + { + WaveManager.Spawn(spawnableWaveBase); + } /// - /// Modify tickets from a . + /// Pauses respawn waves by removing them from WaveManager.Waves and storing them in . /// - /// The to modify tickets from. - /// The amount of tickets to modify. - public static void ModifyTickets(SpawnableTeamType team, float amount) => RespawnTokensManager.ModifyTokens(team, amount); + /// + public static void PauseWaves() + { + PausedWaves.Clear(); + PausedWaves.AddRange(WaveManager.Waves); + WaveManager.Waves.Clear(); + } /// - /// Forces a spawn of the given . + /// Resumes respawn waves by filling WaveManager.Waves with values stored in . /// - /// The to spawn. - /// Whether effects will be played with the spawn. - public static void ForceWave(SpawnableTeamType team, bool playEffects = false) + /// + /// This also clears . + public static void ResumeWaves() { - if (playEffects) - RespawnEffectsController.ExecuteAllEffects(RespawnEffectsController.EffectType.Selection, team); + WaveManager.Waves.Clear(); + WaveManager.Waves.AddRange(PausedWaves); + PausedWaves.Clear(); + } - RespawnManager.Singleton.ForceSpawnTeam(team); + /// + /// Restarts respawn waves by clearing WaveManager.Waves and filling it with new values.. + /// + /// + /// This also clears . + public static void RestartWaves() + { + WaveManager.Waves.Clear(); + WaveManager.Waves.AddRange(new List { new ChaosMiniWave(), new ChaosSpawnWave(), new NtfMiniWave(), new NtfSpawnWave() }); + PausedWaves.Clear(); } + + /// + /// Tries to get the influence value of a given . + /// + /// The whose influence to get. + /// The amount of influence a faction has. + /// Whether an entry was successfully found. + public static bool TryGetFactionInfluence(Faction faction, out float influence) => FactionInfluence.TryGetValue(faction, out influence); } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Roles/DestroyedRole.cs b/EXILED/Exiled.API/Features/Roles/DestroyedRole.cs new file mode 100644 index 000000000..42e6cfe34 --- /dev/null +++ b/EXILED/Exiled.API/Features/Roles/DestroyedRole.cs @@ -0,0 +1,36 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Roles +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + using PlayerRoles; + using PlayerRoles.Voice; + + /// + /// Defines a role that represents players with destroyed role. + /// + internal class DestroyedRole : Role + { + /// + /// Initializes a new instance of the class. + /// + /// the base . + internal DestroyedRole(PlayerRoleBase baseRole) + : base(baseRole) + { + } + + /// + public override RoleTypeId Type { get; } = RoleTypeId.Destroyed; + } +} diff --git a/EXILED/Exiled.API/Features/Roles/HumanRole.cs b/EXILED/Exiled.API/Features/Roles/HumanRole.cs index 830f7844e..8a238a3e7 100644 --- a/EXILED/Exiled.API/Features/Roles/HumanRole.cs +++ b/EXILED/Exiled.API/Features/Roles/HumanRole.cs @@ -32,19 +32,10 @@ internal HumanRole(HumanGameRole baseRole) /// public override RoleTypeId Type => Base.RoleTypeId; - /// - /// Gets or sets the . - /// - public SpawnableTeamType SpawnableTeamType - { - get => Base.AssignedSpawnableTeam; - set => Base.AssignedSpawnableTeam = value; - } - /// /// Gets the player's unit name. /// - public string UnitName => UnitNameMessageHandler.GetReceived(Base.AssignedSpawnableTeam, Base.UnitNameId); + public string UnitName => NamingRulesManager.ClientFetchReceived(Team, UnitNameId); /// /// Gets or sets the . diff --git a/EXILED/Exiled.API/Features/Roles/Role.cs b/EXILED/Exiled.API/Features/Roles/Role.cs index 6edc4f409..ef6d8dcea 100644 --- a/EXILED/Exiled.API/Features/Roles/Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Role.cs @@ -18,6 +18,7 @@ namespace Exiled.API.Features.Roles using PlayerRoles.PlayableScps.Scp049.Zombies; using UnityEngine; + using DestroyedGameRole = PlayerRoles.DestroyedRole; using FilmmakerGameRole = PlayerRoles.Filmmaker.FilmmakerRole; using HumanGameRole = PlayerRoles.HumanRole; using NoneGameRole = PlayerRoles.NoneRole; @@ -113,6 +114,11 @@ protected Role(PlayerRoleBase baseRole) /// public bool IsValid => Owner != null && Owner.IsConnected && Base == Owner.RoleManager.CurrentRole; + /// + /// Gets the life identifier for the role. + /// + public int LifeIdentifier => Base.UniqueLifeIdentifier; + /// /// Gets a random spawn position of this role. /// @@ -228,6 +234,7 @@ public virtual void Set(RoleTypeId newRole, SpawnReason reason, RoleSpawnFlags s HumanGameRole humanRole => new HumanRole(humanRole), FilmmakerGameRole filmmakerRole => new FilmMakerRole(filmmakerRole), NoneGameRole noneRole => new NoneRole(noneRole), + DestroyedGameRole destroyedRole => new DestroyedRole(destroyedRole), _ => null, }; } diff --git a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs index 2798eb50d..2480ca3d8 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp079Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp079Role.cs @@ -593,7 +593,7 @@ public void ActivateTesla(bool consumeEnergy = true) Scp079Camera cam = CurrentCameraSync.CurrentCamera; RewardManager.MarkRoom(cam.Room); - if (!TeslaGateController.Singleton.TeslaGates.TryGetFirst(x => RoomIdUtils.IsTheSameRoom(cam.Position, x.transform.position), out global::TeslaGate teslaGate)) + if (!global::TeslaGate.AllGates.TryGetFirst(x => RoomIdUtils.IsTheSameRoom(cam.Position, x.transform.position), out global::TeslaGate teslaGate)) return; if (consumeEnergy) diff --git a/EXILED/Exiled.API/Features/Roles/Scp106Role.cs b/EXILED/Exiled.API/Features/Roles/Scp106Role.cs index 24ff42992..067ee6964 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp106Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp106Role.cs @@ -13,7 +13,6 @@ namespace Exiled.API.Features.Roles using PlayerRoles; using PlayerRoles.PlayableScps; using PlayerRoles.PlayableScps.HumeShield; - using PlayerRoles.PlayableScps.Scp049; using PlayerRoles.PlayableScps.Scp106; using PlayerRoles.Subroutines; using PlayerStatsSystem; @@ -125,8 +124,12 @@ public float Vigor /// public bool IsSubmerged { - get => Base.IsSubmerged; - set => HuntersAtlasAbility.SetSubmerged(value); + get => HuntersAtlasAbility._syncSubmerged; + set + { + HuntersAtlasAbility._syncSubmerged = value; + HuntersAtlasAbility.ServerSendRpc(true); + } } /// @@ -149,11 +152,6 @@ public bool IsSubmerged /// public float SinkholeCurrentTime => SinkholeController.ElapsedToggle; - /// - /// Gets a value indicating the normalized state of the sinkhole. - /// - public float SinkholeNormalizedState => SinkholeController.NormalizedState; - /// /// Gets a value indicating whether SCP-106 is currently in the middle of an animation. /// @@ -169,63 +167,14 @@ public bool IsSubmerged /// public bool SinkholeState { - get => SinkholeController.State; - set => SinkholeController.State = value; + get => StalkAbility.StalkActive; + set => StalkAbility.ServerSetStalk(value); } /// /// Gets the sinkhole target duration. /// - public float SinkholeTargetDuration => SinkholeController.TargetDuration; - - /// - /// Gets the speed multiplier of the sinkhole. - /// - public float SinkholeSpeedMultiplier => SinkholeController.SpeedMultiplier; - - // TODO: ReAdd Setter but before making an propper way to overwrite NW constant only when the propperty has been used -#pragma warning disable SA1623 // Property summary documentation should match accessors -#pragma warning disable SA1202 - /// - /// Gets or sets how mush cost the Ability Stalk will cost per tick when being stationary. - /// - internal float VigorStalkCostStationary { get; } = Scp106StalkAbility.VigorStalkCostStationary; - - /// - /// Gets or sets how mush cost the Ability Stalk will cost per tick when moving. - /// - internal float VigorStalkCostMoving { get; } = Scp106StalkAbility.VigorStalkCostMoving; - - /// - /// Gets or sets how mush vigor will be regenerate while moving per seconds. - /// - internal float VigorRegeneration { get; } = Scp106StalkAbility.VigorRegeneration; - - /// - /// Gets or sets the duration of Corroding effect. - /// - internal float CorrodingTime { get; } = Scp106Attack.CorrodingTime; - - /// - /// Gets or sets how mush vigor Scp106 will gain when being reward for having caught a player. - /// - internal float VigorCaptureReward { get; } = Scp106Attack.VigorCaptureReward; - - /// - /// Gets or sets how mush reduction cooldown Scp106 will gain when being reward for having caught a player. - /// - internal float CooldownReductionReward { get; } = Scp106Attack.CooldownReductionReward; - - /// - /// Gets or sets the cooldown duration of it's Sinkhole ability's. - /// - internal float SinkholeCooldownDuration { get; } = Scp106SinkholeController.CooldownDuration; - - /// - /// Gets or sets how mush vigor it's ability Hunter Atlas will cost per meter. - /// - internal float HuntersAtlasCostPerMeter { get; } = Scp106HuntersAtlasAbility.CostPerMeter; -#pragma warning restore SA1623 // Property summary documentation should match accessors + public float SinkholeTargetDuration => SinkholeController.TargetTransitionDuration; /// /// Gets or sets how mush damage Scp106 will dealt when attacking a player. @@ -254,10 +203,10 @@ public float CaptureCooldown /// public float RemainingSinkholeCooldown { - get => SinkholeController.Cooldown.Remaining; + get => SinkholeController._submergeCooldown.Remaining; set { - SinkholeController.Cooldown.Remaining = value; + SinkholeController._submergeCooldown.Remaining = value; SinkholeController.ServerSendRpc(true); } } @@ -267,8 +216,8 @@ public float RemainingSinkholeCooldown /// public bool IsStalking { - get => StalkAbility.IsActive; - set => StalkAbility.IsActive = value; + get => StalkAbility.StalkActive; + set => StalkAbility.ServerSetStalk(value); } /// @@ -294,7 +243,7 @@ public bool UsePortal(Vector3 position, float cost = 0f) return false; HuntersAtlasAbility._estimatedCost = cost; - HuntersAtlasAbility.SetSubmerged(true); + HuntersAtlasAbility._syncSubmerged = true; return true; } @@ -303,22 +252,24 @@ public bool UsePortal(Vector3 position, float cost = 0f) /// Send a player to the pocket dimension. /// /// The to send. - public void CapturePlayer(Player player) // Convert to bool. + /// If the player will be capture. + public bool CapturePlayer(Player player) { if (player is null) - return; + return false; Attack._targetHub = player.ReferenceHub; DamageHandlerBase handler = new ScpDamageHandler(Attack.Owner, AttackDamage, DeathTranslations.PocketDecay); if (!Attack._targetHub.playerStats.DealDamage(handler)) - return; + return false; Attack.SendCooldown(Attack._hitCooldown); - Vigor += VigorCaptureReward; + Vigor += Scp106Attack.VigorCaptureReward; Attack.ReduceSinkholeCooldown(); Hitmarker.SendHitmarkerDirectly(Attack.Owner, 1f); player.EnableEffect(EffectType.PocketCorroding); + return true; } /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs index 05a28e0f8..ab157b92c 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs @@ -7,7 +7,6 @@ namespace Exiled.API.Features.Roles { - using System; using System.Collections.Generic; using Exiled.API.Enums; @@ -158,22 +157,12 @@ public RoleTypeId StolenRole } } - /// - /// Gets or sets the SCP-3114's Ragdoll used for it's FakeIdentity. - /// - [Obsolete("Ragdoll in Role now has other meaning. Use IdentityRagdoll instead.")] - public new Ragdoll Ragdoll - { - get => IdentityRagdoll; - set => IdentityRagdoll = value; - } - /// /// Gets or sets the SCP-3114's Ragdoll used for it's FakeIdentity. /// public Ragdoll IdentityRagdoll { - get => Ragdoll.Get(Identity.CurIdentity.Ragdoll); + get => Features.Ragdoll.Get(Identity.CurIdentity.Ragdoll); set { Identity.CurIdentity.Ragdoll = value?.Base; diff --git a/EXILED/Exiled.API/Features/Room.cs b/EXILED/Exiled.API/Features/Room.cs index fafb1d418..f0440ad64 100644 --- a/EXILED/Exiled.API/Features/Room.cs +++ b/EXILED/Exiled.API/Features/Room.cs @@ -395,7 +395,7 @@ public void UnlockAll() /// Returns the Room in a human-readable format. /// /// A string containing Room-related data. - public override string ToString() => $"{Type} ({Zone}) [{Doors.Count}] *{Cameras.Count}* |{TeslaGate != null}|"; + public override string ToString() => $"{Type} ({Zone}) [{Doors?.Count}] *{Cameras?.Count}* |{TeslaGate != null}|"; /// /// Factory method to create and add a component to a Transform. @@ -412,62 +412,73 @@ private static RoomType FindType(GameObject gameObject) // Try to remove brackets if they exist. return gameObject.name.RemoveBracketsOnEndOfName() switch { - "LCZ_Armory" => RoomType.LczArmory, - "LCZ_Curve" => RoomType.LczCurve, - "LCZ_Straight" => RoomType.LczStraight, - "LCZ_330" => RoomType.Lcz330, - "LCZ_914" => RoomType.Lcz914, - "LCZ_Crossing" => RoomType.LczCrossing, - "LCZ_TCross" => RoomType.LczTCross, + "PocketWorld" => RoomType.Pocket, + "Outside" => RoomType.Surface, "LCZ_Cafe" => RoomType.LczCafe, - "LCZ_Plants" => RoomType.LczPlants, "LCZ_Toilets" => RoomType.LczToilets, + "LCZ_TCross" => RoomType.LczTCross, "LCZ_Airlock" => RoomType.LczAirlock, - "LCZ_173" => RoomType.Lcz173, - "LCZ_ClassDSpawn" => RoomType.LczClassDSpawn, + "LCZ_ChkpA" => RoomType.LczCheckpointA, "LCZ_ChkpB" => RoomType.LczCheckpointB, + "LCZ_Plants" => RoomType.LczPlants, + "LCZ_Straight" => RoomType.LczStraight, + "LCZ_Armory" => RoomType.LczArmory, + "LCZ_Crossing" => RoomType.LczCrossing, + "LCZ_Curve" => RoomType.LczCurve, + "LCZ_173" => RoomType.Lcz173, + "LCZ_330" => RoomType.Lcz330, "LCZ_372" => RoomType.LczGlassBox, - "LCZ_ChkpA" => RoomType.LczCheckpointA, - "HCZ_079" => RoomType.Hcz079, - "HCZ_Room3ar" => RoomType.HczArmory, + "LCZ_914" => RoomType.Lcz914, + "LCZ_ClassDSpawn" => RoomType.LczClassDSpawn, + "HCZ_Nuke" => RoomType.HczNuke, + "HCZ_TArmory" => RoomType.HczArmory, + "HCZ_MicroHID_New" => RoomType.HczHid, + "HCZ_Crossroom_Water" => RoomType.HczCrossRoomWater, "HCZ_Testroom" => RoomType.HczTestRoom, - "HCZ_Hid" => RoomType.HczHid, "HCZ_049" => RoomType.Hcz049, - "HCZ_Crossing" => RoomType.HczCrossing, - "HCZ_106" => RoomType.Hcz106, - "HCZ_Nuke" => RoomType.HczNuke, - "HCZ_Tesla" => RoomType.HczTesla, - "HCZ_Servers" => RoomType.HczServers, - "HCZ_Room3" => RoomType.HczTCross, - "HCZ_457" => RoomType.Hcz096, + "HCZ_079" => RoomType.Hcz079, + "HCZ_096" => RoomType.Hcz096, + "HCZ_106_Rework" => RoomType.Hcz106, + "HCZ_939" => RoomType.Hcz939, + "HCZ_Tesla_Rework" => RoomType.HczTesla, "HCZ_Curve" => RoomType.HczCurve, + "HCZ_Crossing" => RoomType.HczCrossing, + "HCZ_Intersection" => RoomType.HczIntersection, + "HCZ_Intersection_Junk" => RoomType.HczIntersectionJunk, + "HCZ_Corner_Deep" => RoomType.HczCornerDeep, "HCZ_Straight" => RoomType.HczStraight, - "EZ_Endoof" => RoomType.EzVent, - "EZ_Intercom" => RoomType.EzIntercom, + "HCZ_Straight_C" => RoomType.HczStraightC, + "HCZ_Straight_PipeRoom"=> RoomType.HczStraightPipeRoom, + "HCZ_Straight Variant" => RoomType.HczStraightVariant, + "HCZ_ChkpA" => RoomType.HczElevatorA, + "HCZ_ChkpB" => RoomType.HczElevatorB, "EZ_GateA" => RoomType.EzGateA, - "EZ_PCs_small" => RoomType.EzDownstairsPcs, + "EZ_GateB" => RoomType.EzGateB, + "EZ_ThreeWay" => RoomType.EzTCross, + "EZ_Crossing" => RoomType.EzCrossing, "EZ_Curve" => RoomType.EzCurve, "EZ_PCs" => RoomType.EzPcs, - "EZ_Crossing" => RoomType.EzCrossing, + "EZ_upstairs" => RoomType.EzUpstairsPcs, + "EZ_Intercom" => RoomType.EzIntercom, + "EZ_Smallrooms2" => RoomType.EzSmallrooms, + "EZ_PCs_small" => RoomType.EzDownstairsPcs, + "EZ_Chef" => RoomType.EzChef, + "EZ_Endoof" => RoomType.EzVent, "EZ_CollapsedTunnel" => RoomType.EzCollapsedTunnel, - "EZ_Smallrooms2" => RoomType.EzConference, + "EZ_Smallrooms1" => RoomType.EzConference, "EZ_Straight" => RoomType.EzStraight, + "EZ_StraightColumn" => RoomType.EzStraightColumn, "EZ_Cafeteria" => RoomType.EzCafeteria, - "EZ_upstairs" => RoomType.EzUpstairsPcs, - "EZ_GateB" => RoomType.EzGateB, "EZ_Shelter" => RoomType.EzShelter, - "EZ_ThreeWay" => RoomType.EzTCross, - "PocketWorld" => RoomType.Pocket, - "Outside" => RoomType.Surface, - "HCZ_939" => RoomType.Hcz939, - "EZ Part" => RoomType.EzCheckpointHallway, - "HCZ_ChkpA" => RoomType.HczElevatorA, - "HCZ_ChkpB" => RoomType.HczElevatorB, - "HCZ Part" => gameObject.transform.parent.name switch + "EZ_HCZ_Checkpoint Part" => gameObject.transform.position.z switch { - "HCZ_EZ_Checkpoint (A)" => RoomType.HczEzCheckpointA, - "HCZ_EZ_Checkpoint (B)" => RoomType.HczEzCheckpointB, - _ => RoomType.Unknown + > 80 => RoomType.EzCheckpointHallwayA, + _ => RoomType.EzCheckpointHallwayB, + }, + "HCZ_EZ_Checkpoint Part" => gameObject.transform.position.z switch + { + > 80 => RoomType.HczEzCheckpointA, + _ => RoomType.HczEzCheckpointB }, _ => RoomType.Unknown, }; @@ -477,6 +488,9 @@ private static ZoneType FindZone(GameObject gameObject) { Transform transform = gameObject.transform; + if (gameObject.name == "PocketWorld") + return ZoneType.Pocket; + return transform.parent?.name.RemoveBracketsOnEndOfName() switch { "HeavyRooms" => ZoneType.HeavyContainment, @@ -493,14 +507,14 @@ private void InternalCreate() RoomIdentifierToRoom.Add(Identifier, this); Zone = FindZone(gameObject); -#if Debug - if (Type is RoomType.Unknown) - Log.Error($"[ZONETYPE UNKNOWN] {this}"); +#if DEBUG + if (Zone is ZoneType.Unspecified) + Log.Error($"[ZONETYPE UNKNOWN] {this} Zone : {Identifier?.Zone}"); #endif Type = FindType(gameObject); -#if Debug +#if DEBUG if (Type is RoomType.Unknown) - Log.Error($"[ROOMTYPE UNKNOWN] {this}"); + Log.Error($"[ROOMTYPE UNKNOWN] {this} Name : {gameObject?.name} Shape : {Identifier?.Shape}"); #endif RoomLightControllersValue.AddRange(gameObject.GetComponentsInChildren()); diff --git a/EXILED/Exiled.API/Features/Round.cs b/EXILED/Exiled.API/Features/Round.cs index 81a6ccca3..b6ee2b35f 100644 --- a/EXILED/Exiled.API/Features/Round.cs +++ b/EXILED/Exiled.API/Features/Round.cs @@ -44,17 +44,17 @@ public static class Round /// /// Gets a value indicating whether the round is started. /// - public static bool IsStarted => ReferenceHub.LocalHub?.characterClassManager.RoundStarted ?? false; + public static bool IsStarted => ReferenceHub.TryGetHostHub(out ReferenceHub hub) && hub.characterClassManager.RoundStarted; /// /// Gets a value indicating whether the round in progress. /// - public static bool InProgress => ReferenceHub.LocalHub != null && RoundSummary.RoundInProgress(); + public static bool InProgress => !IsEnded && RoundSummary.RoundInProgress(); /// /// Gets a value indicating whether the round is ended. /// - public static bool IsEnded => RoundSummary.singleton._roundEnded; + public static bool IsEnded => RoundSummary._singletonSet && RoundSummary.singleton._roundEnded; /// /// Gets a value indicating whether the round is lobby. @@ -68,12 +68,12 @@ public static class Round public static RoundSummary.SumInfo_ClassList LastClassList { get; internal set; } /// - /// Gets or sets a value indicating the amount of Chaos Targets remaining. + /// Gets or sets a value indicating the amount of Extra Targets remaining. /// - public static int ChaosTargetCount + public static int ExtraTargetCount { - get => RoundSummary.singleton.Network_chaosTargetCount; - set => RoundSummary.singleton.Network_chaosTargetCount = value; + get => RoundSummary.singleton.Network_extraTargets; + set => RoundSummary.singleton.Network_extraTargets = value; } /// @@ -122,14 +122,9 @@ public static int Kills } /// - /// Gets or sets the number of surviving SCPs. + /// Gets the number of surviving SCPs. /// - public static int SurvivingSCPs - { - get => RoundSummary.SurvivingSCPs; - [Obsolete("This value is rewritten by NW every time it's used", true)] - set => RoundSummary.SurvivingSCPs = value; - } + public static int SurvivingSCPs => RoundSummary.SurvivingSCPs; /// /// Gets or sets the number of kills made by SCPs. diff --git a/EXILED/Exiled.API/Features/Server.cs b/EXILED/Exiled.API/Features/Server.cs index af596f631..c79d0c4c1 100644 --- a/EXILED/Exiled.API/Features/Server.cs +++ b/EXILED/Exiled.API/Features/Server.cs @@ -267,14 +267,6 @@ public static bool ShutdownRedirect(ushort redirectPort) return true; } - /// - /// Runs a server command. - /// - /// The command to be run. - /// The running the command. - [Obsolete("Use Server.ExecuteCommand() instead.")] - public static void RunCommand(string command, CommandSender sender = null) => GameCore.Console.singleton.TypeCommand(command, sender); - /// /// Executes a server command. /// diff --git a/EXILED/Exiled.API/Features/Toys/AdminToy.cs b/EXILED/Exiled.API/Features/Toys/AdminToy.cs index 71cbc8557..01f54e8d2 100644 --- a/EXILED/Exiled.API/Features/Toys/AdminToy.cs +++ b/EXILED/Exiled.API/Features/Toys/AdminToy.cs @@ -98,7 +98,7 @@ public Quaternion Rotation set { AdminToyBase.transform.rotation = value; - AdminToyBase.NetworkRotation = new LowPrecisionQuaternion(value); + AdminToyBase.NetworkRotation = value; } } @@ -155,6 +155,7 @@ public static AdminToy Get(AdminToyBase adminToyBase) LightSourceToy lightSourceToy => new Light(lightSourceToy), PrimitiveObjectToy primitiveObjectToy => new Primitive(primitiveObjectToy), ShootingTarget shootingTarget => new ShootingTargetToy(shootingTarget), + SpeakerToy speakerToy => new Speaker(speakerToy), _ => throw new System.NotImplementedException() }; } diff --git a/EXILED/Exiled.API/Features/Toys/Light.cs b/EXILED/Exiled.API/Features/Toys/Light.cs index b1361a4c6..757480e90 100644 --- a/EXILED/Exiled.API/Features/Toys/Light.cs +++ b/EXILED/Exiled.API/Features/Toys/Light.cs @@ -7,7 +7,6 @@ namespace Exiled.API.Features.Toys { - using System; using System.Linq; using AdminToys; @@ -32,6 +31,11 @@ internal Light(LightSourceToy lightSourceToy) Base = lightSourceToy; } + /// + /// Gets the prefab. + /// + public static LightSourceToy Prefab => PrefabHelper.GetPrefab(PrefabType.LightSourceToy); + /// /// Gets the base . /// @@ -55,6 +59,33 @@ public float Range set => Base.NetworkLightRange = value; } + /// + /// Gets or sets the angle of the light. + /// + public float SpotAngle + { + get => Base.NetworkSpotAngle; + set => Base.NetworkSpotAngle = value; + } + + /// + /// Gets or sets the inner angle of the light. + /// + public float InnerSpotAngle + { + get => Base.NetworkInnerSpotAngle; + set => Base.NetworkInnerSpotAngle = value; + } + + /// + /// Gets or sets the shadow strength of the light. + /// + public float ShadowStrength + { + get => Base.NetworkShadowStrength; + set => Base.NetworkShadowStrength = value; + } + /// /// Gets or sets the color of the primitive. /// @@ -67,10 +98,19 @@ public Color Color /// /// Gets or sets a value indicating whether the light should cause shadows from other objects. /// - public bool ShadowEmission + public LightShape LightShape + { + get => Base.NetworkLightShape; + set => Base.NetworkLightShape = value; + } + + /// + /// Gets or sets a value indicating whether the light should cause shadows from other objects. + /// + public LightType LightType { - get => Base.NetworkLightShadows; - set => Base.NetworkLightShadows = value; + get => Base.NetworkLightType; + set => Base.NetworkLightType = value; } /// @@ -95,11 +135,12 @@ public static Light Create(Vector3? position = null, Vector3? rotation = null, V /// The new . public static Light Create(Vector3? position /*= null*/, Vector3? rotation /*= null*/, Vector3? scale /*= null*/, bool spawn /*= true*/, Color? color /*= null*/) { - Light light = new(UnityEngine.Object.Instantiate(ToysHelper.LightBaseObject)); - - light.Position = position ?? Vector3.zero; - light.Rotation = Quaternion.Euler(rotation ?? Vector3.zero); - light.Scale = scale ?? Vector3.one; + Light light = new(UnityEngine.Object.Instantiate(Prefab)) + { + Position = position ?? Vector3.zero, + Rotation = Quaternion.Euler(rotation ?? Vector3.zero), + Scale = scale ?? Vector3.one, + }; if (spawn) light.Spawn(); @@ -116,8 +157,8 @@ public static Light Create(Vector3? position /*= null*/, Vector3? rotation /*= n /// The corresponding instance. public static Light Get(LightSourceToy lightSourceToy) { - AdminToy adminToy = Map.Toys.FirstOrDefault(x => x.AdminToyBase == lightSourceToy); - return adminToy is not null ? adminToy as Light : new Light(lightSourceToy); + AdminToy adminToy = List.FirstOrDefault(x => x.AdminToyBase == lightSourceToy); + return adminToy is not null ? adminToy as Light : new(lightSourceToy); } } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Toys/Primitive.cs b/EXILED/Exiled.API/Features/Toys/Primitive.cs index b90588d8f..9ca95036d 100644 --- a/EXILED/Exiled.API/Features/Toys/Primitive.cs +++ b/EXILED/Exiled.API/Features/Toys/Primitive.cs @@ -31,6 +31,11 @@ public class Primitive : AdminToy, IWrapper internal Primitive(PrimitiveObjectToy toyAdminToyBase) : base(toyAdminToyBase, AdminToyType.PrimitiveObject) => Base = toyAdminToyBase; + /// + /// Gets the prefab. + /// + public static PrimitiveObjectToy Prefab => PrefabHelper.GetPrefab(PrefabType.PrimitiveObjectToy); + /// /// Gets the base . /// @@ -115,17 +120,16 @@ public static Primitive Create(PrimitiveType primitiveType = PrimitiveType.Spher /// The new . public static Primitive Create(Vector3? position /*= null*/, Vector3? rotation /*= null*/, Vector3? scale /*= null*/, bool spawn /*= true*/, Color? color /*= null*/) { - Primitive primitive = new(Object.Instantiate(ToysHelper.PrimitiveBaseObject)); + Primitive primitive = new(Object.Instantiate(Prefab)); primitive.Position = position ?? Vector3.zero; primitive.Rotation = Quaternion.Euler(rotation ?? Vector3.zero); primitive.Scale = scale ?? Vector3.one; + primitive.Color = color ?? Color.gray; if (spawn) primitive.Spawn(); - primitive.Color = color ?? Color.gray; - return primitive; } @@ -141,18 +145,18 @@ public static Primitive Create(Vector3? position /*= null*/, Vector3? rotation / /// The new . public static Primitive Create(PrimitiveType primitiveType /*= PrimitiveType.Sphere*/, Vector3? position /*= null*/, Vector3? rotation /*= null*/, Vector3? scale /*= null*/, bool spawn /*= true*/, Color? color /*= null*/) { - Primitive primitive = new(Object.Instantiate(ToysHelper.PrimitiveBaseObject)); + Primitive primitive = new(Object.Instantiate(Prefab)); primitive.Position = position ?? Vector3.zero; primitive.Rotation = Quaternion.Euler(rotation ?? Vector3.zero); primitive.Scale = scale ?? Vector3.one; - if (spawn) - primitive.Spawn(); - primitive.Base.NetworkPrimitiveType = primitiveType; primitive.Color = color ?? Color.gray; + if (spawn) + primitive.Spawn(); + return primitive; } @@ -169,19 +173,19 @@ public static Primitive Create(PrimitiveType primitiveType /*= PrimitiveType.Sph /// The new . public static Primitive Create(PrimitiveType primitiveType /*= PrimitiveType.Sphere*/, PrimitiveFlags flags, Vector3? position /*= null*/, Vector3? rotation /*= null*/, Vector3? scale /*= null*/, bool spawn /*= true*/, Color? color /*= null*/) { - Primitive primitive = new(Object.Instantiate(ToysHelper.PrimitiveBaseObject)); + Primitive primitive = new(Object.Instantiate(Prefab)); primitive.Position = position ?? Vector3.zero; primitive.Rotation = Quaternion.Euler(rotation ?? Vector3.zero); primitive.Scale = scale ?? Vector3.one; primitive.Flags = flags; - if (spawn) - primitive.Spawn(); - primitive.Base.NetworkPrimitiveType = primitiveType; primitive.Color = color ?? Color.gray; + if (spawn) + primitive.Spawn(); + return primitive; } @@ -192,20 +196,20 @@ public static Primitive Create(PrimitiveType primitiveType /*= PrimitiveType.Sph /// The new . public static Primitive Create(PrimitiveSettings primitiveSettings) { - Primitive primitive = new(Object.Instantiate(ToysHelper.PrimitiveBaseObject)); + Primitive primitive = new(Object.Instantiate(Prefab)); primitive.Position = primitiveSettings.Position; primitive.Rotation = Quaternion.Euler(primitiveSettings.Rotation); primitive.Scale = primitiveSettings.Scale; primitive.Flags = primitiveSettings.Flags; - if (primitiveSettings.Spawn) - primitive.Spawn(); - primitive.Base.NetworkPrimitiveType = primitiveSettings.PrimitiveType; primitive.Color = primitiveSettings.Color; primitive.IsStatic = primitiveSettings.IsStatic; + if (primitiveSettings.Spawn) + primitive.Spawn(); + return primitive; } @@ -216,8 +220,8 @@ public static Primitive Create(PrimitiveSettings primitiveSettings) /// The corresponding instance. public static Primitive Get(PrimitiveObjectToy primitiveObjectToy) { - AdminToy adminToy = Map.Toys.FirstOrDefault(x => x.AdminToyBase == primitiveObjectToy); - return adminToy is not null ? adminToy as Primitive : new Primitive(primitiveObjectToy); + AdminToy adminToy = List.FirstOrDefault(x => x.AdminToyBase == primitiveObjectToy); + return adminToy is not null ? adminToy as Primitive : new(primitiveObjectToy); } } } diff --git a/EXILED/Exiled.API/Features/Toys/ShootingTargetToy.cs b/EXILED/Exiled.API/Features/Toys/ShootingTargetToy.cs index 70bcf6f12..2951459bc 100644 --- a/EXILED/Exiled.API/Features/Toys/ShootingTargetToy.cs +++ b/EXILED/Exiled.API/Features/Toys/ShootingTargetToy.cs @@ -46,6 +46,21 @@ internal ShootingTargetToy(ShootingTarget target) Type = TypeLookup.TryGetValue(Base.gameObject.name.Substring(0, Base.gameObject.name.Length - 7), out ShootingTargetType type) ? type : ShootingTargetType.Unknown; } + /// + /// Gets the prefab for Sport Shooting Target. + /// + public static ShootingTarget SportShootingTargetPrefab => PrefabHelper.GetPrefab(PrefabType.SportTarget); + + /// + /// Gets the prefab for DBoy Shooting Target. + /// + public static ShootingTarget DboyShootingTargetPrefab => PrefabHelper.GetPrefab(PrefabType.DBoyTarget); + + /// + /// Gets the prefab for Binary Shooting Target. + /// + public static ShootingTarget BinaryShootingTargetPrefab => PrefabHelper.GetPrefab(PrefabType.BinaryTarget); + /// /// Gets the base-game for this target. /// @@ -165,19 +180,19 @@ public static ShootingTargetToy Create(ShootingTargetType type, Vector3? positio { case ShootingTargetType.ClassD: { - shootingTargetToy = new ShootingTargetToy(Object.Instantiate(ToysHelper.DboyShootingTargetObject)); + shootingTargetToy = new(Object.Instantiate(DboyShootingTargetPrefab)); break; } case ShootingTargetType.Binary: { - shootingTargetToy = new ShootingTargetToy(Object.Instantiate(ToysHelper.BinaryShootingTargetObject)); + shootingTargetToy = new(Object.Instantiate(BinaryShootingTargetPrefab)); break; } default: { - shootingTargetToy = new ShootingTargetToy(Object.Instantiate(ToysHelper.SportShootingTargetObject)); + shootingTargetToy = new(Object.Instantiate(SportShootingTargetPrefab)); break; } } @@ -199,8 +214,8 @@ public static ShootingTargetToy Create(ShootingTargetType type, Vector3? positio /// The corresponding instance. public static ShootingTargetToy Get(ShootingTarget shootingTarget) { - AdminToy adminToy = Map.Toys.FirstOrDefault(x => x.AdminToyBase == shootingTarget); - return adminToy is not null ? adminToy as ShootingTargetToy : new ShootingTargetToy(shootingTarget); + AdminToy adminToy = List.FirstOrDefault(x => x.AdminToyBase == shootingTarget); + return adminToy is not null ? adminToy as ShootingTargetToy : new(shootingTarget); } /// diff --git a/EXILED/Exiled.API/Features/Toys/Speaker.cs b/EXILED/Exiled.API/Features/Toys/Speaker.cs new file mode 100644 index 000000000..2ca0b2907 --- /dev/null +++ b/EXILED/Exiled.API/Features/Toys/Speaker.cs @@ -0,0 +1,144 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Toys +{ + using System.Collections.Generic; + + using AdminToys; + using Enums; + using Exiled.API.Interfaces; + using UnityEngine; + using VoiceChat.Networking; + using VoiceChat.Playbacks; + + /// + /// A wrapper class for . + /// + public class Speaker : AdminToy, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The of the toy. + internal Speaker(SpeakerToy speakerToy) + : base(speakerToy, AdminToyType.Speaker) => Base = speakerToy; + + /// + /// Gets the prefab. + /// + public static SpeakerToy Prefab => PrefabHelper.GetPrefab(PrefabType.SpeakerToy); + + /// + /// Gets the base . + /// + public SpeakerToy Base { get; } + + /// + /// Gets or sets the volume of the audio source. + /// + /// + /// A representing the volume level of the audio source, + /// where 0.0 is silent and 1.0 is full volume. + /// + public float Volume + { + get => Base.NetworkVolume; + set => Base.NetworkVolume = Mathf.Clamp01(value); + } + + /// + /// Gets or sets a value indicating whether the audio source is spatialized. + /// + /// + /// A where true means the audio source is spatial, allowing + /// for 3D audio positioning relative to the listener; false means it is non-spatial. + /// + public bool IsSpatial + { + get => Base.NetworkIsSpatial; + set => Base.NetworkIsSpatial = value; + } + + /// + /// Gets or sets the maximum distance at which the audio source can be heard. + /// + /// + /// A representing the maximum hearing distance for the audio source. + /// Beyond this distance, the audio will not be audible. + /// + public float MaxDistance + { + get => Base.NetworkMaxDistance; + set => Base.NetworkMaxDistance = value; + } + + /// + /// Gets or sets the minimum distance at which the audio source reaches full volume. + /// + /// + /// A representing the distance from the source at which the audio is heard at full volume. + /// Within this range, volume will not decrease with proximity. + /// + public float MinDistance + { + get => Base.NetworkMinDistance; + set => Base.NetworkMinDistance = value; + } + + /// + /// Gets or sets the controller ID of speaker. + /// + public byte ControllerId + { + get => Base.NetworkControllerId; + set => Base.NetworkControllerId = value; + } + + /// + /// Creates a new . + /// + /// The position of the . + /// The rotation of the . + /// The scale of the . + /// Whether the should be initially spawned. + /// The new . + public static Speaker Create(Vector3? position, Vector3? rotation, Vector3? scale, bool spawn) + { + Speaker speaker = new(UnityEngine.Object.Instantiate(Prefab)) + { + Position = position ?? Vector3.zero, + Rotation = Quaternion.Euler(rotation ?? Vector3.zero), + Scale = scale ?? Vector3.one, + }; + + if (spawn) + speaker.Spawn(); + + return speaker; + } + + /// + /// Plays audio through this speaker. + /// + /// An instance. + /// Targets who will hear the audio. If null, audio will be sent to all players. + public static void Play(AudioMessage message, IEnumerable targets = null) + { + foreach (Player target in targets ?? Player.List) + target.Connection.Send(message); + } + + /// + /// Plays audio through this speaker. + /// + /// Audio samples. + /// The length of the samples array. + /// Targets who will hear the audio. If null, audio will be sent to all players. + public void Play(byte[] samples, int? length = null, IEnumerable targets = null) => Play(new AudioMessage(ControllerId, samples, length ?? samples.Length), targets); + } +} diff --git a/EXILED/Exiled.API/Features/Toys/ToysHelper.cs b/EXILED/Exiled.API/Features/Toys/ToysHelper.cs deleted file mode 100644 index 5ebcfc42f..000000000 --- a/EXILED/Exiled.API/Features/Toys/ToysHelper.cs +++ /dev/null @@ -1,142 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.API.Features.Toys -{ - using AdminToys; - - using Mirror; - - using UnityEngine; - - /// - /// A helper class for interacting with toys. - /// - public static class ToysHelper - { - private static PrimitiveObjectToy primitiveBaseObject; - private static LightSourceToy lightBaseObject; - private static ShootingTarget sportShootingTargetObject; - private static ShootingTarget dboyShootingTargetObject; - private static ShootingTarget binaryShootingTargetObject; - - /// - /// Gets the base to instantiate when creating a new primitive. - /// - public static PrimitiveObjectToy PrimitiveBaseObject - { - get - { - if (primitiveBaseObject is null) - { - foreach (GameObject gameObject in NetworkClient.prefabs.Values) - { - if (gameObject.TryGetComponent(out PrimitiveObjectToy component)) - { - primitiveBaseObject = component; - break; - } - } - } - - return primitiveBaseObject; - } - } - - /// - /// Gets the base to instantiate when creating a new light. - /// - public static LightSourceToy LightBaseObject - { - get - { - if (lightBaseObject is null) - { - foreach (GameObject gameObject in NetworkClient.prefabs.Values) - { - if (gameObject.TryGetComponent(out LightSourceToy component)) - { - lightBaseObject = component; - break; - } - } - } - - return lightBaseObject; - } - } - - /// - /// Gets the base to instantiate when creating a new sport shooting target. - /// - public static ShootingTarget SportShootingTargetObject - { - get - { - if (sportShootingTargetObject is null) - { - foreach (GameObject gameObject in NetworkClient.prefabs.Values) - { - if ((gameObject.name == "sportTargetPrefab") && gameObject.TryGetComponent(out ShootingTarget shootingTarget)) - { - sportShootingTargetObject = shootingTarget; - break; - } - } - } - - return sportShootingTargetObject; - } - } - - /// - /// Gets the base to instantiate when creating a new dboy shooting target. - /// - public static ShootingTarget DboyShootingTargetObject - { - get - { - if (dboyShootingTargetObject is null) - { - foreach (GameObject gameObject in NetworkClient.prefabs.Values) - { - if ((gameObject.name == "dboyTargetPrefab") && gameObject.TryGetComponent(out ShootingTarget shootingTarget)) - { - dboyShootingTargetObject = shootingTarget; - break; - } - } - } - - return dboyShootingTargetObject; - } - } - - /// - /// Gets the base to instantiate when creating a new binary shooting target. - /// - public static ShootingTarget BinaryShootingTargetObject - { - get - { - if (binaryShootingTargetObject is null) - { - foreach (GameObject gameObject in NetworkClient.prefabs.Values) - { - if ((gameObject.name == "binaryTargetPrefab") && gameObject.TryGetComponent(out ShootingTarget shootingTarget)) - { - binaryShootingTargetObject = shootingTarget; - break; - } - } - } - - return binaryShootingTargetObject; - } - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Warhead.cs b/EXILED/Exiled.API/Features/Warhead.cs index 52ecea92e..a7369cfab 100644 --- a/EXILED/Exiled.API/Features/Warhead.cs +++ b/EXILED/Exiled.API/Features/Warhead.cs @@ -113,7 +113,7 @@ public static WarheadStatus Status /// /// Gets a value indicating whether the warhead has already been detonated. /// - public static bool IsDetonated => Controller._alreadyDetonated; + public static bool IsDetonated => Controller.AlreadyDetonated; /// /// Gets a value indicating whether the warhead detonation is in progress. diff --git a/EXILED/Exiled.API/Features/Waves/TimedWave.cs b/EXILED/Exiled.API/Features/Waves/TimedWave.cs new file mode 100644 index 000000000..346bcd6c1 --- /dev/null +++ b/EXILED/Exiled.API/Features/Waves/TimedWave.cs @@ -0,0 +1,198 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Waves +{ + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Enums; + using PlayerRoles; + using Respawning; + using Respawning.Announcements; + using Respawning.Waves; + + /// + /// Represents a timed wave. + /// + public class TimedWave + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The that this class should be based off of. + /// + public TimedWave(TimeBasedWave wave) => Base = wave; + + /// + /// Gets the base . + /// + public TimeBasedWave Base { get; } + + /// + /// Gets the name of the wave timer. + /// + public string Name => Base.GetType().Name; + + /// + /// Gets a value indicating whether the wave is a mini wave. + /// + public bool IsMiniWave => Base is IMiniWave; + + /// + /// Gets the wave timer instance. + /// + public WaveTimer Timer => new(Base.Timer); + + /// + /// Gets the faction of this wave. + /// + public Faction Faction => Base.TargetFaction; + + /// + /// Gets the team of this wave. + /// + public Team Team => Base.TargetFaction.GetSpawnableTeam(); + + /// + /// Gets the spawnable faction for this wave. + /// + public SpawnableFaction SpawnableFaction => Faction switch + { + Faction.FoundationStaff when IsMiniWave => SpawnableFaction.NtfMiniWave, + Faction.FoundationStaff => SpawnableFaction.NtfWave, + Faction.FoundationEnemy when IsMiniWave => SpawnableFaction.ChaosMiniWave, + _ => SpawnableFaction.ChaosWave + }; + + /// + /// Gets the maximum amount of people that can spawn in this wave. + /// + public int MaxAmount => Base.MaxWaveSize; + + /// + /// Gets the for this wave. + /// + /// Wave must implement . + public WaveAnnouncementBase Announcement => Base is IAnnouncedWave announcedWave ? announcedWave.Announcement : null; + + /// + /// Get the timed waves for the specified faction. + /// + /// + /// The faction to get the waves for. + /// + /// + /// The waves if found. + /// + /// + /// A value indicating whether the wave were found. + /// + public static bool TryGetTimedWaves(Faction faction, out List waves) + { + List spawnableWaveBases = WaveManager.Waves.Where(w => w is TimeBasedWave wave && wave.TargetFaction == faction).ToList(); + if(!spawnableWaveBases.Any()) + { + waves = null; + return false; + } + + waves = spawnableWaveBases.Select(w => new TimedWave((TimeBasedWave)w)).ToList(); + return true; + } + + /// + /// Get the timed waves for the specified faction. + /// + /// The faction to get the waves for. + /// The waves if found. + /// A value indicating whether the wave were found. + public static bool TryGetTimedWaves(Team team, out List waves) + { + List spawnableWaveBases = WaveManager.Waves.Where(w => w is TimeBasedWave wave && wave.TargetFaction.GetSpawnableTeam() == team).ToList(); + if(!spawnableWaveBases.Any()) + { + waves = null; + return false; + } + + waves = spawnableWaveBases.Select(w => new TimedWave((TimeBasedWave)w)).ToList(); + return true; + } + + /// + /// Get the timed wave for the specified type. + /// + /// + /// The wave type to get. + /// + /// + /// The type of wave to get. Must be a . I.e. or . + /// + /// + /// A value indicating whether the wave was found. + /// + public static bool TryGetTimedWave(out TimedWave wave) + where T : TimeBasedWave + { + foreach (SpawnableWaveBase waveBase in WaveManager.Waves) + { + if (waveBase is not TimeBasedWave timeWave || timeWave.GetType() != typeof(T)) + continue; + + wave = new TimedWave(timeWave); + return true; + } + + wave = null; + return false; + } + + /// + /// Get all timed waves. + /// + /// + /// A list of all timed waves. + /// + public static List GetTimedWaves() + { + List waves = new(); + foreach (SpawnableWaveBase wave in WaveManager.Waves) + { + if (wave is TimeBasedWave timeBasedWave) + { + waves.Add(new TimedWave(timeBasedWave)); + } + } + + return waves; + } + + /// + /// Destroys this wave. + /// + public void Destroy() => Base.Destroy(); + + /// + /// Populates this wave with the specified amount of roles. + /// + /// + /// The queue to populate. + /// + /// + /// The amount of people to populate. + /// + public void PopulateQueue(Queue queue, int amount) => Base.PopulateQueue(queue, amount); + + /// + /// Plays the announcement for this wave. + /// + /// Wave must implement . + public void PlayAnnouncement() => Announcement?.PlayAnnouncement(); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Waves/WaveTimer.cs b/EXILED/Exiled.API/Features/Waves/WaveTimer.cs new file mode 100644 index 000000000..b99f2cf2b --- /dev/null +++ b/EXILED/Exiled.API/Features/Waves/WaveTimer.cs @@ -0,0 +1,193 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Waves +{ + using System; + + using System.Collections.Generic; + + using System.Linq; + + using PlayerRoles; + + using Respawning; + + using Respawning.Waves; + + /// + /// Represents a wave timer. + /// + public class WaveTimer + { + /// + /// Initializes a new instance of the class. + /// + /// The that this class should be based off of. + public WaveTimer(Respawning.Waves.WaveTimer wave) => Base = wave; + + /// + /// Gets the base . + /// + public Respawning.Waves.WaveTimer Base { get; } + + /// + /// Gets the name of the wave timer. + /// + public string Name => Base._wave.GetType().Name; + + /// + /// Gets a value indicating whether the wave is a mini wave. + /// + public bool IsMiniWave => Base._wave is IMiniWave; + + /// + /// Gets the amount of time left before the wave spawns. + /// + public TimeSpan TimeLeft => TimeSpan.FromSeconds(Base.TimeLeft); + + /// + /// Gets the amount of time passed since the last wave spawned. + /// + public TimeSpan TimePassed => TimeSpan.FromSeconds(Base.TimePassed); + + /// + /// Gets the amount of time left before this wave unpause. + /// + public TimeSpan PauseTimeLeft => TimeSpan.FromSeconds(Base.PauseTimeLeft); + + /// + /// Gets the amount of time this wave has been paused for. + /// + public TimeSpan PausedFor => TimeSpan.FromSeconds(Base._pauseTimer); + + /// + /// Gets a value indicating whether this wave is paused. + /// + public bool IsPaused => Base.IsPaused; + + /// + /// Gets a value indicating whether this wave is ready to spawn. + /// + public bool IsReady => Base.IsReadyToSpawn; + + /// + /// Gets a value indicating whether this wave is out of respawns. + /// + public bool IsRespawnable => !Base.IsOutOfRespawns; + + /// + /// Gets the default amount of time between a respawn of this wave. + /// + public float DefaultSpawnInterval => Base.DefaultSpawnInterval; + + /// + /// Gets the actual amount of time between a respawn of this wave. + /// + public float SpawnInterval => Base.SpawnIntervalSeconds; + + /// + /// Get the wave timers for the specified faction. + /// + /// The faction. + /// The waves, if any. + /// A bool indicating if waves were found. + public static bool TryGetWaveTimers(Faction faction, out List waves) + { + if (!TimedWave.TryGetTimedWaves(faction, out List timedWaves)) + { + waves = null; + return false; + } + + waves = timedWaves.Select(wave => wave.Timer).ToList(); + return true; + } + + /// + /// Get the wave timers for the specified faction. + /// + /// The team. + /// The waves, if any. + /// A bool indicating if waves were found. + public static bool TryGetWaveTimers(Team team, out List waves) + { + if (!TimedWave.TryGetTimedWaves(team, out List timedWaves)) + { + waves = null; + return false; + } + + waves = timedWaves.Select(wave => wave.Timer).ToList(); + return true; + } + + /// + /// Gets all wave timers. + /// + /// A list of all wave timers. + public static List GetWaveTimers() + { + return TimedWave.GetTimedWaves().Select(l => l.Timer).ToList(); + } + + /// + /// Destroys this wave timer. + /// + public void Destroy() => Base.Destroy(); + + /// + /// Pauses this wave timer. + /// + /// + /// The amount of time to pause this wave timer for. + /// + public void Pause(float seconds) => Base.Pause(seconds); + + /// + /// Unpauses this wave timer. + /// + public void Unpause() => Base.Pause(0); + + /// + /// Resets this wave timer. + /// + /// + /// A value indicating whether the should be reset. + /// + public void Reset(bool resetInterval = true) => Base.Reset(resetInterval); + + /// + /// Update the timer. + /// + public void Update() => Base.Update(); + + /// + /// Add time to the wave timer. + /// + /// + /// The amount of time to add in seconds. + /// + public void AddTime(float seconds) => Base.AddTime(seconds); + + /// + /// Set the amount of time before the wave spawns. + /// + /// + /// The amount of time before the wave spawns. + /// + public void SetTime(TimeSpan time) => SetTime((float)time.TotalSeconds); + + /// + /// Set the amount of time before the wave spawns. + /// + /// + /// The amount of time before the wave spawns, in seconds. + /// + public void SetTime(float seconds) => Base.SetTime(seconds); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Window.cs b/EXILED/Exiled.API/Features/Window.cs index 19e978148..a84767e1e 100644 --- a/EXILED/Exiled.API/Features/Window.cs +++ b/EXILED/Exiled.API/Features/Window.cs @@ -38,9 +38,9 @@ internal Window(BreakableWindow window, Room room) Base = window; Room = room; Type = GetGlassType(); -#if Debug +#if DEBUG if (Type is GlassType.Unknown) - Log.Error($"[GLASSTYPE UNKNOWN] {this}"); + Log.Error($"[GLASSTYPE UNKNOWN] {this} BASE = {Base}"); #endif } @@ -132,10 +132,10 @@ public bool DisableScpDamage /// /// Gets or sets a value indicating whether this window is broken. /// - public BreakableWindow.BreakableWindowStatus SyncStatus + public bool SyncStatus { - get => Base.NetworksyncStatus; - set => Base.NetworksyncStatus = value; + get => Base.prevStatus; + set => Base.prevStatus = value; } /// @@ -220,7 +220,7 @@ public void DamageWindow(float amount, DamageHandlerBase handler) RoomType.LczGlassBox => GlassType.GR18, RoomType.LczPlants => GlassType.Plants, RoomType.Hcz049 => GlassType.Scp049, - RoomType.Hcz079 => Recontainer.Base._activatorGlass == Base ? GlassType.Scp079Trigger : GlassType.Scp079, + RoomType.Hcz079 => Base._preventScpDamage ? GlassType.Scp079Trigger : GlassType.Scp079, RoomType.HczHid => GlassType.MicroHid, RoomType.HczTestRoom => GlassType.TestRoom, RoomType.HczEzCheckpointA => GlassType.HczEzCheckpointA, diff --git a/EXILED/Exiled.API/Interfaces/IDamageableDoor.cs b/EXILED/Exiled.API/Interfaces/IDamageableDoor.cs index d5de3d106..f98eebde9 100644 --- a/EXILED/Exiled.API/Interfaces/IDamageableDoor.cs +++ b/EXILED/Exiled.API/Interfaces/IDamageableDoor.cs @@ -39,6 +39,11 @@ public interface IDamageableDoor /// public DoorDamageType IgnoredDamage { get; set; } + /// + /// Repair the door. + /// + public void Repair(); + /// /// Damages the door. /// diff --git a/EXILED/Exiled.API/Interfaces/IWrapper.cs b/EXILED/Exiled.API/Interfaces/IWrapper.cs index 56667c836..c2ee03b01 100644 --- a/EXILED/Exiled.API/Interfaces/IWrapper.cs +++ b/EXILED/Exiled.API/Interfaces/IWrapper.cs @@ -7,14 +7,11 @@ namespace Exiled.API.Interfaces { - using UnityEngine; - /// /// Defines the contract for classes that wrap a base-game object. /// /// The base-game class that is being wrapped. public interface IWrapper - where T : MonoBehaviour { /// /// Gets the base that this class is wrapping. diff --git a/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj b/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj index adc9595c8..9382489fb 100644 --- a/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj +++ b/EXILED/Exiled.CreditTags/Exiled.CreditTags.csproj @@ -43,6 +43,4 @@ if [[ ! -z "$EXILED_DEV_REFERENCES" ]]; then cp "$(OutputPath)$(AssemblyName).dll" "$EXILED_DEV_REFERENCES/Plugins/"; fi - - diff --git a/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs b/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs index 1c81585fa..2fc89ef33 100644 --- a/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs +++ b/EXILED/Exiled.CustomItems/API/EventArgs/OwnerEscapingEventArgs.cs @@ -30,20 +30,7 @@ public class OwnerEscapingEventArgs : EscapingEventArgs /// /// The instance. public OwnerEscapingEventArgs(Item item, EscapingEventArgs ev) - : this(item, ev.Player, ev.NewRole, ev.EscapeScenario, ev.RespawnTickets) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - /// - public OwnerEscapingEventArgs(Item item, Player player, RoleTypeId newRole, EscapeScenario escapeScenario, KeyValuePair respawnTickets = default) - : base(player, newRole, escapeScenario, respawnTickets) + : base(ev.Player, ev.NewRole, ev.EscapeScenario) { Item = item; } diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs b/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs index bf3c48d37..48d725ce7 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomGrenade.cs @@ -94,7 +94,7 @@ public virtual Pickup Throw(Vector3 position, float force, float weight, float f 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), force, throwable.Base.FullThrowSettings.UpwardsFactor); + throwable.Base.PropelBody(component, throwable.Base.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 feba8be32..5eea6969b 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomItem.cs @@ -53,7 +53,6 @@ namespace Exiled.CustomItems.API.Features /// public abstract class CustomItem { - private static Dictionary typeLookupTable = new(); private static Dictionary stringLookupTable = new(); private static Dictionary idLookupTable = new(); @@ -121,19 +120,6 @@ public virtual ItemType Type [YamlIgnore] public virtual bool ShouldMessageOnGban { get; } = false; - /// - /// Gets a with a specific ID. - /// - /// The ID. - /// The matching the search, if not registered. - [Obsolete("Use Get(uint) instead.", true)] - public static CustomItem? Get(int id) - { - if (!idLookupTable.ContainsKey((uint)id)) - idLookupTable.Add((uint)id, Registered.FirstOrDefault(i => i.Id == id)); - return idLookupTable[(uint)id]; - } - /// /// Gets a with a specific ID. /// @@ -159,16 +145,11 @@ public virtual ItemType Type } /// - /// Gets a with a specific type. + /// Retrieves a collection of instances that match a specified type. /// /// The type. - /// The matching the search, if not registered. - public static CustomItem? Get(Type t) - { - if (!typeLookupTable.ContainsKey(t)) - typeLookupTable.Add(t, Registered.FirstOrDefault(i => i.GetType() == t)); - return typeLookupTable[t]; - } + /// An containing all registered of the specified type. + public static IEnumerable Get(Type t) => Registered.Where(i => i.GetType() == t); /// /// Tries to get a with a specific ID. @@ -201,16 +182,16 @@ public static bool TryGet(string name, out CustomItem? customItem) } /// - /// Tries to get a with a specific type. + /// Attempts to retrieve a collection of instances of a specified type. /// /// The of the item to look for. - /// The found , if not registered. - /// Returns a value indicating whether the was found. - public static bool TryGet(Type t, out CustomItem? customItem) + /// An output parameter that will contain the found instances, or an empty collection if none are registered. + /// A boolean value indicating whether any instances of the specified type were found. + public static bool TryGet(Type t, out IEnumerable customItems) { - customItem = Get(t); + customItems = Get(t); - return customItem is not null; + return customItems.Any(); } /// @@ -345,23 +326,6 @@ public static bool TryGive(Player player, uint id, bool displayMessage = true) return true; } - /// - /// Gives to a specific a specic . - /// - /// The to give the item to. - /// The of the item to give. - /// Indicates a value whether will be called when the player receives the or not. - /// Returns a value indicating if the player was given the or not. - public static bool TryGive(Player player, Type t, bool displayMessage = true) - { - if (!TryGet(t, out CustomItem? item)) - return false; - - item?.Give(player, displayMessage); - - return true; - } - /// /// Registers all the 's present in the current assembly. /// @@ -619,20 +583,17 @@ public virtual uint Spawn(IEnumerable spawnPoints, uint limit) spawned++; -#pragma warning disable CS0618 // Type or member is obsolete \\ TODO: REMOVE THIS - if (spawnPoint is DynamicSpawnPoint dynamicSpawnPoint && dynamicSpawnPoint.Location == SpawnLocationType.InsideLocker) + /*if (spawnPoint is DynamicSpawnPoint dynamicSpawnPoint && dynamicSpawnPoint.Location == SpawnLocationType.InsideLocker) { for (int i = 0; i < 50; i++) { - if (Map.Lockers is null) + if (Exiled.API.Features.Lockers.Locker.List is null) { Log.Debug($"{nameof(Spawn)}: Locker list is null."); continue; } - Locker locker = - Map.Lockers[ - Loader.Random.Next(Map.Lockers.Count)]; + Locker locker = Exiled.API.Features.Lockers.Locker.Random(); if (locker is null) { @@ -683,8 +644,20 @@ public virtual uint Spawn(IEnumerable spawnPoints, uint limit) } Log.Debug($"Spawned {Name} at {spawnPoint.Position} ({spawnPoint.Name})"); + }*/ + + Pickup? pickup = Spawn(spawnPoint.Position); + + if (pickup == null) + continue; + + if (spawnPoint is LockerSpawnPoint) + pickup.IsLocked = true; + + if (pickup.Is(out Exiled.API.Features.Pickups.FirearmPickup firearmPickup) && this is CustomWeapon customWeapon) + { + // set MaxAmmo if synced TODO } -#pragma warning restore CS0618 // Type or member is obsolete } return spawned; @@ -725,7 +698,7 @@ public virtual void Give(Player player, Item item, bool displayMessage = true) { try { - Log.Debug($"{Name}.{nameof(Give)}: Item Serial: {item.Serial} Ammo: {(item is Firearm firearm ? firearm.Ammo : -1)}"); + Log.Debug($"{Name}.{nameof(Give)}: Item Serial: {item.Serial} Ammo: {(item is Firearm firearm ? firearm.MagazineAmmo : -1)}"); player.AddItem(item); @@ -761,7 +734,6 @@ public virtual void Give(Player player, Item item, bool displayMessage = true) /// public virtual void Init() { - typeLookupTable.Add(GetType(), this); stringLookupTable.Add(Name, this); idLookupTable.Add(Id, this); @@ -775,7 +747,6 @@ public virtual void Destroy() { UnsubscribeEvents(); - typeLookupTable.Remove(GetType()); stringLookupTable.Remove(Name); idLookupTable.Remove(Id); } @@ -1002,7 +973,7 @@ protected virtual void ShowSelectedMessage(Player player) private void OnInternalOwnerChangingRole(ChangingRoleEventArgs ev) { - if (ev.Reason == SpawnReason.Escaped) + if (ev.Reason is SpawnReason.Escaped or SpawnReason.Destroyed) return; foreach (Item item in ev.Player.Items.ToList()) diff --git a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs index 8151b4d55..dea5aec5c 100644 --- a/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs +++ b/EXILED/Exiled.CustomItems/API/Features/CustomWeapon.cs @@ -76,8 +76,8 @@ public override ItemType Type if (!Attachments.IsEmpty()) firearm.AddAttachment(Attachments); - firearm.Ammo = ClipSize; - firearm.MaxAmmo = ClipSize; + firearm.MagazineAmmo = ClipSize; + firearm.MaxMagazineAmmo = ClipSize; Pickup? pickup = firearm.CreatePickup(position); @@ -104,8 +104,8 @@ public override ItemType Type if (!Attachments.IsEmpty()) firearm.AddAttachment(Attachments); - byte ammo = firearm.Ammo; - firearm.MaxAmmo = ClipSize; + int ammo = firearm.MagazineAmmo; + firearm.MaxMagazineAmmo = ClipSize; Log.Debug($"{nameof(Name)}.{nameof(Spawn)}: Spawning weapon with {ammo} ammo."); Pickup? pickup = firearm.CreatePickup(position); pickup.Scale = Scale; @@ -130,8 +130,8 @@ public override void Give(Player player, bool displayMessage = true) if (!Attachments.IsEmpty()) firearm.AddAttachment(Attachments); - firearm.Ammo = ClipSize; - firearm.MaxAmmo = ClipSize; + firearm.MagazineAmmo = ClipSize; + firearm.MaxMagazineAmmo = ClipSize; } Log.Debug($"{nameof(Give)}: Adding {item.Serial} to tracker."); @@ -214,7 +214,7 @@ private void OnInternalReloading(ReloadingWeaponEventArgs ev) Log.Debug($"{nameof(Name)}.{nameof(OnInternalReloading)}: Continuing with internal reload.."); ev.IsAllowed = false; - byte remainingClip = ((Firearm)ev.Player.CurrentItem).Ammo; + int remainingClip = ((Firearm)ev.Player.CurrentItem).MagazineAmmo; if (remainingClip >= ClipSize) return; @@ -229,7 +229,7 @@ private void OnInternalReloading(ReloadingWeaponEventArgs ev) return; } - ev.Player.Connection.Send(new RequestMessage(ev.Firearm.Serial, RequestType.Reload)); + ev.Firearm.Reload(); byte amountToReload = (byte)Math.Min(ClipSize - remainingClip, ev.Player.Ammo[ammoType.GetItemType()]); @@ -241,9 +241,9 @@ private void OnInternalReloading(ReloadingWeaponEventArgs ev) ev.Player.Ammo[ammoType.GetItemType()] -= amountToReload; ev.Player.Inventory.SendAmmoNextFrame = true; - ((Firearm)ev.Player.CurrentItem).Ammo = (byte)(((Firearm)ev.Player.CurrentItem).Ammo + amountToReload); + ((Firearm)ev.Player.CurrentItem).MagazineAmmo = (byte)(((Firearm)ev.Player.CurrentItem).MagazineAmmo + amountToReload); - Log.Debug($"{ev.Player.Nickname} ({ev.Player.UserId}) [{ev.Player.Role}] reloaded a {Name} ({Id}) [{Type} ({((Firearm)ev.Player.CurrentItem).Ammo}/{ClipSize})]!"); + Log.Debug($"{ev.Player.Nickname} ({ev.Player.UserId}) [{ev.Player.Role}] reloaded a {Name} ({Id}) [{Type} ({((Firearm)ev.Player.CurrentItem).MagazineAmmo}/{ClipSize})]!"); } private void OnInternalShooting(ShootingEventArgs ev) diff --git a/EXILED/Exiled.CustomItems/Commands/Give.cs b/EXILED/Exiled.CustomItems/Commands/Give.cs index 31151934a..cc63ed222 100644 --- a/EXILED/Exiled.CustomItems/Commands/Give.cs +++ b/EXILED/Exiled.CustomItems/Commands/Give.cs @@ -18,6 +18,8 @@ namespace Exiled.CustomItems.Commands using Exiled.Permissions.Extensions; using RemoteAdmin; + using UnityStandardAssets.Effects; + using Utils; /// /// The command to give a player an item. @@ -97,22 +99,27 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s response = $"Custom item {item?.Name} given to all players who can receive them ({eligiblePlayers.Count} players)"; return true; default: - if (Player.Get(identifier) is not { } player) - { - response = $"Unable to find player: {identifier}."; - return false; - } + break; + } - if (!CheckEligible(player)) - { - response = "Player cannot receive custom items!"; - return false; - } + IEnumerable list = Player.GetProcessedData(arguments, 1); + + if (list.IsEmpty()) + { + response = "Cannot find player! Try using the player ID!"; + return false; + } + foreach (Player player in list) + { + if (CheckEligible(player)) + { item?.Give(player); - response = $"{item?.Name} given to {player.Nickname} ({player.UserId})"; - return true; + } } + + response = $"{item?.Name} given to {list.Count()} players!"; + return true; } /// @@ -120,4 +127,4 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s /// private bool CheckEligible(Player player) => player.IsAlive && !player.IsCuffed && (player.Items.Count < 8); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.CustomRoles/API/Features/ActiveAbility.cs b/EXILED/Exiled.CustomRoles/API/Features/ActiveAbility.cs index de4869800..cadc7c63f 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/ActiveAbility.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/ActiveAbility.cs @@ -227,14 +227,6 @@ protected virtual void AbilityEnded(Player player) { } - /// - /// Called when the ability is successfully used. - /// - /// The using the ability. - [Obsolete("The Keypress Activator will already do this, you do not need to call this unless you are overwriting the keypress activator.", true)] - protected virtual void ShowMessage(Player player) => - player.ShowHint(string.Format(CustomRoles.Instance!.Config.UsedAbilityHint.Content, Name, Description), CustomRoles.Instance.Config.UsedAbilityHint.Duration); - /// /// Called when the ability is selected. /// diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 56f3e5895..b8217fb41 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -926,6 +926,9 @@ private void OnInternalSpawning(SpawningEventArgs ev) private void OnInternalChangingRole(ChangingRoleEventArgs ev) { + if(ev.Reason == SpawnReason.Destroyed) + return; + if (Check(ev.Player) && ((ev.NewRole == RoleTypeId.Spectator && !KeepRoleOnDeath) || (ev.NewRole != RoleTypeId.Spectator && ev.NewRole != Role && !KeepRoleOnChangingRole))) { RemoveRole(ev.Player); diff --git a/EXILED/Exiled.CustomRoles/Commands/Give.cs b/EXILED/Exiled.CustomRoles/Commands/Give.cs index ed52669f8..4eb357feb 100644 --- a/EXILED/Exiled.CustomRoles/Commands/Give.cs +++ b/EXILED/Exiled.CustomRoles/Commands/Give.cs @@ -19,6 +19,7 @@ namespace Exiled.CustomRoles.Commands using Exiled.Permissions.Extensions; using RemoteAdmin; + using Utils; /// /// The command to give a role to player(s). @@ -96,16 +97,24 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s ListPool.Pool.Return(players); return true; default: - if (Player.Get(identifier) is not Player ply) - { - response = $"Unable to find a player: {identifier}"; - return false; - } - - role.AddRole(ply); - response = $"{role.Name} given to {ply.Nickname}."; - return true; + break; + } + + IEnumerable list = Player.GetProcessedData(arguments, 1); + if (list.IsEmpty()) + { + response = "Cannot find player! Try using the player ID!"; + return false; } + + foreach (Player player in list) + { + role.AddRole(player); + } + + response = $"Customrole {role.Name} given to {list.Count()} players!"; + + return true; } catch (Exception e) { diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IItemEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IItemEvent.cs index 5e838badd..c2fcb61da 100644 --- a/EXILED/Exiled.Events/EventArgs/Interfaces/IItemEvent.cs +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IItemEvent.cs @@ -12,7 +12,7 @@ namespace Exiled.Events.EventArgs.Interfaces /// /// Event args used for all related events. /// - public interface IItemEvent : IExiledEvent + public interface IItemEvent : IPlayerEvent { /// /// Gets the triggering the event. diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1344Event.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1344Event.cs new file mode 100644 index 000000000..c2009ae7d --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IScp1344Event.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + using Exiled.API.Features.Items; + + /// + /// Event args used for all related events. + /// + public interface IScp1344Event : IItemEvent + { + /// + /// Gets the triggering the event. + /// + public Scp1344 Scp1344 { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs index 7e4d21b1c..342d4b311 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/ChargingJailbirdEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Item { - using System; - using Exiled.API.Features; using Exiled.API.Features.Items; using Exiled.Events.EventArgs.Interfaces; @@ -16,7 +14,7 @@ namespace Exiled.Events.EventArgs.Item /// /// Contains all information before a player charges a . /// - public class ChargingJailbirdEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent + public class ChargingJailbirdEventArgs : IItemEvent { /// /// Initializes a new instance of the class. @@ -49,13 +47,8 @@ public ChargingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.Item public Item Item => Jailbird; /// - /// Gets or sets a value indicating whether the Jailbird can be charged. + /// Gets a value indicating whether the Jailbird can be charged. /// - public bool IsAllowed - { - get; - [Obsolete("This event cannot be denied as it will cause desync.")] - set; - } + public bool IsAllowed { get; } } } diff --git a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs index 0a63b6c9b..0d97d9da1 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs @@ -14,7 +14,7 @@ namespace Exiled.Events.EventArgs.Item /// /// Contains all information before a player swings a . /// - public class SwingingEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent + public class SwingingEventArgs : IItemEvent, IDeniableEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingChaosEntranceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingChaosEntranceEventArgs.cs new file mode 100644 index 000000000..e0e7fb893 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingChaosEntranceEventArgs.cs @@ -0,0 +1,46 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Map +{ + using System.Text; + + using Exiled.API.Features.Waves; + using Exiled.Events.EventArgs.Interfaces; + using Respawning.Announcements; + + /// + /// Contains all information before Chaos wave entrance. + /// + public class AnnouncingChaosEntranceEventArgs : IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public AnnouncingChaosEntranceEventArgs(WaveAnnouncementBase announcement, StringBuilder builder) + { + Wave = TimedWave.GetTimedWaves().Find(x => x.Announcement == announcement); + Words = builder; + } + + /// + /// Gets the entering wave. + /// + public TimedWave Wave { get; } + + /// + /// Gets the of the words that C.A.S.S.I.E will say. + /// It doesn't affect the subtitle part that will be sent to the client. + /// + public StringBuilder Words { get; } + + /// + public bool IsAllowed { get; set; } = true; + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingNtfEntranceEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingNtfEntranceEventArgs.cs index f961a19de..40a9fd315 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/AnnouncingNtfEntranceEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/AnnouncingNtfEntranceEventArgs.cs @@ -7,7 +7,9 @@ namespace Exiled.Events.EventArgs.Map { + using Exiled.API.Features.Waves; using Interfaces; + using Respawning.Announcements; /// /// Contains all information before C.A.S.S.I.E announces the NTF entrance. @@ -17,26 +19,23 @@ public class AnnouncingNtfEntranceEventArgs : IDeniableEvent /// /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public AnnouncingNtfEntranceEventArgs(int scpsLeft, string unitName, int unitNumber, bool isAllowed = true) + /// + /// + /// + /// + public AnnouncingNtfEntranceEventArgs(WaveAnnouncementBase announcement, int scpsLeft, string unitName, int unitNumber) { + Wave = TimedWave.GetTimedWaves().Find(x => x.Announcement == announcement); ScpsLeft = scpsLeft; UnitName = unitName; UnitNumber = unitNumber; - IsAllowed = isAllowed; } + /// + /// Gets the entering wave. + /// + public TimedWave Wave { get; } + /// /// Gets or sets the number of SCPs left. /// @@ -55,6 +54,6 @@ public AnnouncingNtfEntranceEventArgs(int scpsLeft, string unitName, int unitNum /// /// Gets or sets a value indicating whether the NTF spawn will be announced by C.A.S.S.I.E. /// - public bool IsAllowed { get; set; } + public bool IsAllowed { get; set; } = true; } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/ChangedIntoGrenadeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/ChangedIntoGrenadeEventArgs.cs index d1f4cd82a..94f5b93a3 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/ChangedIntoGrenadeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/ChangedIntoGrenadeEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Map { - using System; - using Exiled.API.Features.Pickups; using Exiled.API.Features.Pickups.Projectiles; using Exiled.Events.EventArgs.Interfaces; @@ -26,8 +24,8 @@ public class ChangedIntoGrenadeEventArgs : IExiledEvent /// The . public ChangedIntoGrenadeEventArgs(TimedGrenadePickup pickup, ThrownProjectile projectile) { - Pickup = (GrenadePickup)API.Features.Pickups.Pickup.Get(pickup); - Projectile = (Projectile)API.Features.Pickups.Pickup.Get(projectile); + Pickup = API.Features.Pickups.Pickup.Get(pickup); + Projectile = API.Features.Pickups.Pickup.Get(projectile); } /// @@ -39,11 +37,5 @@ public ChangedIntoGrenadeEventArgs(TimedGrenadePickup pickup, ThrownProjectile p /// Gets a value indicating the projectile that spawned. /// public Projectile Projectile { get; } - - /// - /// Gets or sets a value indicating how long the fuse of the changed grenade will be. - /// - [Obsolete("Use Projectile.Is(Projectile, out TimeGrenadeProjectile timeGrenadeProjectile) ? timeGrenadeProjectile.FuseTime : 0 instead of this", true)] - public double FuseTime { get; set; } } } diff --git a/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs index 6bd4343a1..27b0bc165 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/ExplodingGrenadeEventArgs.cs @@ -39,7 +39,7 @@ public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionG Player = Player.Get(thrower.Hub); Projectile = Pickup.Get(grenade); Position = position; - TargetsToAffect = ListPool.Pool.Get(); + TargetsToAffect = HashSetPool.Pool.Get(); if (Projectile.Base is not ExplosionGrenade) return; @@ -59,8 +59,7 @@ public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionG { if (Server.FriendlyFire || IndividualFriendlyFire.CheckFriendlyFirePlayer(thrower, hub)) { - if (!TargetsToAffect.Contains(player)) - TargetsToAffect.Add(player); + TargetsToAffect.Add(player); } } @@ -69,8 +68,7 @@ public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionG { if (Server.FriendlyFire || thrower.Hub == Server.Host.ReferenceHub || HitboxIdentity.IsEnemy(thrower.Role, hub.roleManager.CurrentRole.RoleTypeId)) { - if (!TargetsToAffect.Contains(player)) - TargetsToAffect.Add(player); + TargetsToAffect.Add(player); } } @@ -94,12 +92,12 @@ public ExplodingGrenadeEventArgs(Footprint thrower, Vector3 position, ExplosionG /// /// /// - public ExplodingGrenadeEventArgs(Player thrower, EffectGrenade grenade, List targetsToAffect, bool isAllowed = true) + public ExplodingGrenadeEventArgs(Player thrower, EffectGrenade grenade, HashSet targetsToAffect, bool isAllowed = true) { Player = thrower ?? Server.Host; Projectile = Pickup.Get(grenade); Position = Projectile.Position; - TargetsToAffect = ListPool.Pool.Get(targetsToAffect ?? new()); + TargetsToAffect = HashSetPool.Pool.Get(targetsToAffect ?? new HashSet()); IsAllowed = isAllowed; } @@ -108,7 +106,7 @@ public ExplodingGrenadeEventArgs(Player thrower, EffectGrenade grenade, List ~ExplodingGrenadeEventArgs() { - ListPool.Pool.Return(TargetsToAffect); + HashSetPool.Pool.Return(TargetsToAffect); } /// @@ -119,7 +117,7 @@ public ExplodingGrenadeEventArgs(Player thrower, EffectGrenade grenade, List /// Gets the players who could be affected by the grenade, if any, and the damage that be dealt. /// - public List TargetsToAffect { get; } + public HashSet TargetsToAffect { get; } /// /// Gets the grenade that is exploding. diff --git a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs index 794aae85f..66043379d 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/FillingLockerEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Map { - using System; - using Exiled.API.Features.Lockers; using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Interfaces; @@ -40,12 +38,6 @@ public FillingLockerEventArgs(ItemPickupBase pickupBase, LockerChamber lockerCha /// public Pickup Pickup { get; } - /// - /// Gets a value indicating the target locker chamber. - /// - [Obsolete("Use Chamber instead.")] - public LockerChamber LockerChamber => Chamber.Base; - /// /// Gets a locker which is containing . /// diff --git a/EXILED/Exiled.Events/EventArgs/Map/PlacingBloodEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/PlacingBloodEventArgs.cs deleted file mode 100644 index 673b51915..000000000 --- a/EXILED/Exiled.Events/EventArgs/Map/PlacingBloodEventArgs.cs +++ /dev/null @@ -1,64 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Map -{ - using API.Features; - - using Interfaces; - - using UnityEngine; - - /// - /// Contains all information before placing a blood decal. - /// - public class PlacingBloodEventArgs : IPlayerEvent, IDeniableEvent - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public PlacingBloodEventArgs(Player player, Player target, RaycastHit hit, bool isAllowed = true) - { - Player = player; - Target = target; - Position = hit.point; - IsAllowed = isAllowed; - } - - /// - /// Gets the who's placing the blood. - /// - public Player Player { get; } - - /// - /// Gets the target's instance. - /// - public Player Target { get; } - - /// - /// Gets or sets the blood placing position. - /// - public Vector3 Position { get; set; } - - /// - /// Gets or sets a value indicating whether the blood can be placed. - /// - public bool IsAllowed { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/PlacingBulletHoleEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/PlacingBulletHoleEventArgs.cs index 2e8fed7e3..8a066fbaf 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/PlacingBulletHoleEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/PlacingBulletHoleEventArgs.cs @@ -8,7 +8,7 @@ namespace Exiled.Events.EventArgs.Map { using API.Features; - + using Exiled.API.Features.Items; using Interfaces; using UnityEngine; @@ -16,20 +16,21 @@ namespace Exiled.Events.EventArgs.Map /// /// Contains all information before placing a bullet hole decal. /// - public class PlacingBulletHoleEventArgs : IPlayerEvent, IDeniableEvent + public class PlacingBulletHoleEventArgs : IFirearmEvent, IPlayerEvent, IDeniableEvent { /// /// Initializes a new instance of the class. /// - /// - /// + /// + /// /// /// /// /// - public PlacingBulletHoleEventArgs(Player owner, RaycastHit hit) + public PlacingBulletHoleEventArgs(Item firearm, RaycastHit hit) { - Player = owner; + Firearm = firearm.As(); + Player = Firearm.Owner; Position = hit.point; Rotation = Quaternion.LookRotation(hit.normal); } @@ -53,5 +54,11 @@ public PlacingBulletHoleEventArgs(Player owner, RaycastHit hit) /// Gets the decal owner. /// public Player Player { get; } + + /// + public Firearm Firearm { get; } + + /// + public Item Item => Firearm; } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Map/SpawningTeamVehicleEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Map/SpawningTeamVehicleEventArgs.cs index 16b31daac..2e455ff30 100644 --- a/EXILED/Exiled.Events/EventArgs/Map/SpawningTeamVehicleEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Map/SpawningTeamVehicleEventArgs.cs @@ -9,6 +9,7 @@ namespace Exiled.Events.EventArgs.Map { using Exiled.Events.EventArgs.Interfaces; using Respawning; + using Respawning.Waves; /// /// Contains all information before the server spawns a team's respawn vehicle. @@ -24,7 +25,7 @@ public class SpawningTeamVehicleEventArgs : IDeniableEvent /// /// /// - public SpawningTeamVehicleEventArgs(SpawnableTeamType team, bool isAllowed = true) + public SpawningTeamVehicleEventArgs(SpawnableWaveBase team, bool isAllowed = true) { Team = team; IsAllowed = isAllowed; @@ -33,7 +34,7 @@ public SpawningTeamVehicleEventArgs(SpawnableTeamType team, bool isAllowed = tru /// /// Gets or sets which vehicle should spawn. /// - public SpawnableTeamType Team { get; set; } + public SpawnableWaveBase Team { get; set; } /// /// Gets or sets a value indicating whether the vehicle can be spawned. diff --git a/EXILED/Exiled.Events/EventArgs/Player/AimingDownSightEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/AimingDownSightEventArgs.cs index 79cf3c5cb..945295631 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/AimingDownSightEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/AimingDownSightEventArgs.cs @@ -12,33 +12,27 @@ namespace Exiled.Events.EventArgs.Player using Interfaces; + using FirearmBase = InventorySystem.Items.Firearms.Firearm; + /// /// Contains all information when a player aims. /// - // TODO: remove stupid AdsIn/AdsOut propetry, and let exists only one public class AimingDownSightEventArgs : IPlayerEvent, IFirearmEvent { /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// /// /// /// - /// - /// - /// - public AimingDownSightEventArgs(Player player, Firearm firearm, bool adsIn, bool adsOut) + public AimingDownSightEventArgs(FirearmBase firearm, bool adsIn) { - Firearm = firearm; - Player = player; + Firearm = Item.Get(firearm); + Player = Firearm.Owner; AdsIn = adsIn; - AdsOut = adsOut; } /// @@ -46,11 +40,6 @@ public AimingDownSightEventArgs(Player player, Firearm firearm, bool adsIn, bool /// public bool AdsIn { get; } - /// - /// Gets a value indicating whether the player is aiming down sight out. - /// - public bool AdsOut { get; } - /// /// Gets the used to trigger the aim action. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangedEmotionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangedEmotionEventArgs.cs new file mode 100644 index 000000000..cd5e3447a --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangedEmotionEventArgs.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; + + /// + /// Contains all the information after the player's emotion. + /// + public class ChangedEmotionEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public ChangedEmotionEventArgs(ReferenceHub hub, EmotionPresetType emotionPresetType) + { + Player = Player.Get(hub); + EmotionPresetType = emotionPresetType; + } + + /// + /// Gets the player's emotion. + /// + public EmotionPresetType EmotionPresetType { get; } + + /// + public Player Player { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangedItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangedItemEventArgs.cs index 44f032779..238125690 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ChangedItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangedItemEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; - using API.Features; using API.Features.Items; @@ -19,7 +17,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information after a player's held item changes. /// - public class ChangedItemEventArgs : IPlayerEvent, IItemEvent + public class ChangedItemEventArgs : IItemEvent { /// /// Initializes a new instance of the class. @@ -42,12 +40,6 @@ public ChangedItemEventArgs(Player player, ItemBase oldItem) /// public Item OldItem { get; } - /// - /// Gets the new item. - /// - [Obsolete("Use ev.Item instead of this")] - public Item NewItem => Item; - /// /// Gets the new item. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingDisruptorModeEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingDisruptorModeEventArgs.cs new file mode 100644 index 000000000..68fe52816 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingDisruptorModeEventArgs.cs @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Enums; + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before disruptor's mode is changed. + /// + public class ChangingDisruptorModeEventArgs : IFirearmEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public ChangingDisruptorModeEventArgs(Item firearm, bool mode) + { + Firearm = firearm.As(); + NewMode = mode ? DisruptorMode.Disintegrator : DisruptorMode.BurstFire; + } + + /// + public Item Item => Firearm; + + /// + public Firearm Firearm { get; } + + /// + /// Gets a new disruptor's fire mode. + /// + public DisruptorMode NewMode { get; } + + /// + public Player Player => Item.Owner; + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingEmotionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingEmotionEventArgs.cs new file mode 100644 index 000000000..759f1fa9e --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingEmotionEventArgs.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; + + /// + /// Contains all the information before the player's emotion changes. + /// + public class ChangingEmotionEventArgs : IDeniableEvent, IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public ChangingEmotionEventArgs(ReferenceHub hub, EmotionPresetType newEmotionPresetType, EmotionPresetType oldEmotionPresetType, bool isAllowed = true) + { + Player = Player.Get(hub); + NewEmotionPresetType = newEmotionPresetType; + OldEmotionPresetType = oldEmotionPresetType; + IsAllowed = isAllowed; + } + + /// + public bool IsAllowed { get; set; } + + /// + /// Gets the old player's emotion. + /// + public EmotionPresetType OldEmotionPresetType { get; } + + /// + /// Gets or sets the new player's emotion. + /// + public EmotionPresetType NewEmotionPresetType { get; set; } + + /// + public Player Player { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs index 038724137..f472a7096 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingMicroHIDStateEventArgs.cs @@ -7,42 +7,35 @@ namespace Exiled.Events.EventArgs.Player { + using System; + using API.Features; using API.Features.Items; - using Interfaces; - using InventorySystem.Items.MicroHID; + using InventorySystem.Items.MicroHID.Modules; /// /// Contains all information before MicroHID state is changed. /// - public class ChangingMicroHIDStateEventArgs : IPlayerEvent, IDeniableEvent + public class ChangingMicroHIDStateEventArgs : IDeniableEvent, IItemEvent { /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - /// - /// - /// - /// - /// + /// + /// /// /// /// /// - public ChangingMicroHIDStateEventArgs(Player player, MicroHIDItem microHID, HidState oldState, HidState newState, bool isAllowed = true) + public ChangingMicroHIDStateEventArgs(Item microHID, MicroHidPhase newPhase, bool isAllowed = true) { - Player = player; - MicroHID = Item.Get(microHID); - OldState = oldState; - NewState = newState; + MicroHID = microHID.As(); + NewPhase = newPhase; IsAllowed = isAllowed; } @@ -51,24 +44,20 @@ public ChangingMicroHIDStateEventArgs(Player player, MicroHIDItem microHID, HidS /// public MicroHid MicroHID { get; } - /// - /// Gets the old MicroHID state. - /// - public HidState OldState { get; } - /// /// Gets or sets the new MicroHID state. /// - public HidState NewState { get; set; } + public MicroHidPhase NewPhase { get; set; } /// /// Gets or sets a value indicating whether the MicroHID state can be changed. /// public bool IsAllowed { get; set; } - /// - /// Gets the player who's using the MicroHID. - /// - public Player Player { get; } + /// + public Item Item => MicroHID; + + /// + public Player Player => MicroHID.Owner; } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingMoveStateEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingMoveStateEventArgs.cs index 3be8dd579..36d524015 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ChangingMoveStateEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingMoveStateEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; - using API.Features; using Interfaces; @@ -18,7 +16,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information before changing movement state. /// - public class ChangingMoveStateEventArgs : IPlayerEvent, IDeniableEvent + public class ChangingMoveStateEventArgs : IPlayerEvent { /// /// Initializes a new instance of the class. @@ -32,16 +30,11 @@ public class ChangingMoveStateEventArgs : IPlayerEvent, IDeniableEvent /// /// /// - /// - /// - /// - public ChangingMoveStateEventArgs(Player player, PlayerMovementState oldState, PlayerMovementState newState, bool isAllowed = true) + public ChangingMoveStateEventArgs(Player player, PlayerMovementState oldState, PlayerMovementState newState) { Player = player; OldState = oldState; -#pragma warning disable CS0618 NewState = newState; -#pragma warning restore CS0618 } /// @@ -55,21 +48,8 @@ public ChangingMoveStateEventArgs(Player player, PlayerMovementState oldState, P public PlayerMovementState OldState { get; } /// - /// Gets or sets the new state. - /// - // TODO: remove setter - public PlayerMovementState NewState - { - get; - [Obsolete("Setter was removed due to desync problems.")] - set; - } - - /// - /// Gets or sets a value indicating whether the player can change the movement state. + /// Gets the new state. /// - // TODO: remove - [Obsolete("Property was removed due to desync problems.")] - public bool IsAllowed { get; set; } = true; + public PlayerMovementState NewState { get; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs index b48a8b764..c00696a75 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ChangingRadioPresetEventArgs.cs @@ -21,7 +21,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information before radio preset is changed. /// - public class ChangingRadioPresetEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent + public class ChangingRadioPresetEventArgs : IItemEvent, IDeniableEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Player/DroppingItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DroppingItemEventArgs.cs index 4ff31bde6..cf15df90d 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/DroppingItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/DroppingItemEventArgs.cs @@ -19,7 +19,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information before a player drops an item. /// - public class DroppingItemEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent + public class DroppingItemEventArgs : IItemEvent, IDeniableEvent { private bool isAllowed = true; diff --git a/EXILED/Exiled.Events/EventArgs/Player/DryfiringWeaponEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DryfiringWeaponEventArgs.cs index 26a4fb91d..2073d6267 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/DryfiringWeaponEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/DryfiringWeaponEventArgs.cs @@ -12,6 +12,8 @@ namespace Exiled.Events.EventArgs.Player using Interfaces; + using BaseFirearm = InventorySystem.Items.Firearms.Firearm; + /// /// Contains all information before a player's weapon is dryfired. /// @@ -20,26 +22,19 @@ public class DryfiringWeaponEventArgs : IPlayerEvent, IFirearmEvent, IDeniableEv /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - /// - /// - /// - public DryfiringWeaponEventArgs(Player player, Firearm firearm, bool isAllowed = true) + public DryfiringWeaponEventArgs(BaseFirearm firearm) { - Firearm = firearm; - Player = player; - IsAllowed = isAllowed; + Firearm = Item.Get(firearm); + Player = Firearm.Owner; } /// /// Gets or sets a value indicating whether the weapon can be dryfired. /// - public bool IsAllowed { get; set; } + public bool IsAllowed { get; set; } = true; /// /// Gets the being dryfired. diff --git a/EXILED/Exiled.Events/EventArgs/Player/DyingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/DyingEventArgs.cs index 2ac0a0695..9919ac089 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/DyingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/DyingEventArgs.cs @@ -7,7 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; using System.Collections.Generic; using System.Linq; @@ -45,14 +44,9 @@ public DyingEventArgs(Player target, DamageHandlerBase damageHandler) } /// - /// Gets or sets the list of items to be dropped. + /// Gets the list of items to be dropped. /// - public List ItemsToDrop - { - get; - [Obsolete("This setter has been deprecated")] - set; - } + public List ItemsToDrop { get; } /// /// Gets the dying player. diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapedEventArgs.cs index 9f74663cd..71df7a008 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapedEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapedEventArgs.cs @@ -8,14 +8,11 @@ namespace Exiled.Events.EventArgs.Player { using System; - using System.Collections.Generic; using Exiled.API.Enums; using Exiled.API.Features; using Exiled.API.Features.Roles; using Exiled.Events.EventArgs.Interfaces; - using PlayerRoles; - using Respawning; /// /// Contains all information after player has escaped. @@ -28,13 +25,10 @@ public class EscapedEventArgs : IPlayerEvent /// /// /// - /// , . - public EscapedEventArgs(Player player, EscapeScenario escapeScenario, Role role, KeyValuePair kvp) + public EscapedEventArgs(Player player, EscapeScenario escapeScenario, Role role) { Player = player; EscapeScenario = escapeScenario; - Team = kvp.Key; - Tickets = kvp.Value; OldRole = role; EscapeTime = (int)Math.Ceiling(role.ActiveTime.TotalSeconds); } @@ -47,16 +41,6 @@ public EscapedEventArgs(Player player, EscapeScenario escapeScenario, Role role, /// public EscapeScenario EscapeScenario { get; } - /// - /// Gets the that gained tickets for this escape. - /// - public SpawnableTeamType Team { get; } - - /// - /// Gets the amount of tickets gained for this escape. - /// - public float Tickets { get; } - /// /// Gets the previous role for this player. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs index b8076e288..a10eea692 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/EscapingEventArgs.cs @@ -42,52 +42,6 @@ public EscapingEventArgs(Player player, RoleTypeId newRole, EscapeScenario escap IsAllowed = escapeScenario is not EscapeScenario.CustomEscape; } - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public EscapingEventArgs(Player player, RoleTypeId newRole, EscapeScenario escapeScenario, KeyValuePair respawnTickets) - : this(player, newRole, escapeScenario) - { - RespawnTickets = respawnTickets; - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// A that will be initialized with. - /// - /// - /// A that will be initialized with. - /// - public EscapingEventArgs(Player player, RoleTypeId newRole, EscapeScenario escapeScenario, SpawnableTeamType teamToGrantTickets, float ticketsToGrant) - : this(player, newRole, escapeScenario) - { - if (teamToGrantTickets != SpawnableTeamType.None) - RespawnTickets = new KeyValuePair(teamToGrantTickets, ticketsToGrant); - } - /// /// Gets the player who's escaping. /// @@ -103,12 +57,6 @@ public EscapingEventArgs(Player player, RoleTypeId newRole, EscapeScenario escap /// public EscapeScenario EscapeScenario { get; set; } - /// - /// Gets or sets the RespawnTickets that will represent the amount of tickets granted to a specific after the player escapes. - /// - /// - public KeyValuePair RespawnTickets { get; set; } - /// /// Gets or sets a value indicating whether the player can escape. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/InteractingElevatorEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/InteractingElevatorEventArgs.cs index b8bda532d..5a3edb3ad 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/InteractingElevatorEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/InteractingElevatorEventArgs.cs @@ -28,14 +28,18 @@ public class InteractingElevatorEventArgs : IPlayerEvent, IDeniableEvent /// /// /// + /// + /// + /// /// /// /// - public InteractingElevatorEventArgs(Player player, ElevatorChamber elevator, bool isAllowed = true) + public InteractingElevatorEventArgs(Player player, ElevatorChamber elevator, bool isCalledFromInside, bool isAllowed = true) { Player = player; Lift = Lift.Get(elevator); Elevator = elevator; + IsCalledFromInside = isCalledFromInside; IsAllowed = isAllowed; } @@ -54,6 +58,11 @@ public InteractingElevatorEventArgs(Player player, ElevatorChamber elevator, boo /// public bool IsAllowed { get; set; } + /// + /// Gets a value indicating whether the player as interact with the elevator from the inside. + /// + public bool IsCalledFromInside { get; } + /// /// Gets the player who's interacting with the elevator. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs index 2be075af6..b7cc7f3b5 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/InteractingLockerEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; - using API.Features; using Exiled.API.Features.Lockers; using Interfaces; @@ -36,23 +34,11 @@ public class InteractingLockerEventArgs : IPlayerEvent, IDeniableEvent public InteractingLockerEventArgs(Player player, MapGeneration.Distributors.Locker locker, byte colliderId, bool isAllowed) { Player = player; - InteractingLocker = API.Features.Lockers.Locker.Get(locker); - InteractingChamber = API.Features.Lockers.Chamber.Get(locker.Chambers[colliderId]); + InteractingLocker = Locker.Get(locker); + InteractingChamber = Chamber.Get(locker.Chambers[colliderId]); IsAllowed = isAllowed; } - /// - /// Gets the instance. - /// - [Obsolete("Use InteractingLocker instead.")] - public MapGeneration.Distributors.Locker Locker => InteractingLocker.Base; - - /// - /// Gets the interacting chamber. - /// - [Obsolete("Use InteractingChamber instead.")] - public MapGeneration.Distributors.LockerChamber Chamber => InteractingChamber.Base; - /// /// Gets the locker which is containing . /// @@ -63,12 +49,6 @@ public InteractingLockerEventArgs(Player player, MapGeneration.Distributors.Lock /// public Chamber InteractingChamber { get; } - /// - /// Gets the chamber id. - /// - [Obsolete("Use Chamber::Id instead.")] - public byte ChamberId => InteractingChamber.Id; - /// /// Gets or sets a value indicating whether the player can interact with the locker. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/ItemAddedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ItemAddedEventArgs.cs index 68c5aca0d..694188c1c 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ItemAddedEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ItemAddedEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information after adding an item to a player's inventory. /// - public class ItemAddedEventArgs : IPlayerEvent, IItemEvent, IPickupEvent + public class ItemAddedEventArgs : IItemEvent, IPickupEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Player/ItemRemovedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ItemRemovedEventArgs.cs index ef0dc9a53..f14eb31d2 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ItemRemovedEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ItemRemovedEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information after removing an item from a player's inventory. /// - public class ItemRemovedEventArgs : IPlayerEvent, IItemEvent, IPickupEvent + public class ItemRemovedEventArgs : IItemEvent, IPickupEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Player/KickingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/KickingEventArgs.cs index 736a52e6c..036b2aa4c 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/KickingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/KickingEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; - using System.Linq; using System.Reflection; using API.Features; @@ -76,14 +74,9 @@ public Player Target public string Reason { get; set; } /// - /// Gets or sets the full kick message. + /// Gets the full kick message. /// - public string FullMessage - { - get => startkickmessage + Reason; - [Obsolete("this will be remove use Reason instead of FullMessage")] - set => Reason = value.StartsWith(startkickmessage) ? value.Remove(0, startkickmessage.Count()) : value; - } + public string FullMessage => startkickmessage + Reason; /// /// Gets or sets a value indicating whether action is taken against the target. diff --git a/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs deleted file mode 100644 index d575cb310..000000000 --- a/EXILED/Exiled.Events/EventArgs/Player/KillingPlayerEventArgs.cs +++ /dev/null @@ -1,42 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.EventArgs.Player -{ - using System; - - using Interfaces; - using PlayerStatsSystem; - - /// - /// Contains all information before player data to kill player is sent. - /// - [Obsolete] - public class KillingPlayerEventArgs : IPlayerEvent - { - /// - /// Initializes a new instance of the class. - /// - /// Current player. - /// DamageHandler instance. - public KillingPlayerEventArgs(API.Features.Player player, ref DamageHandlerBase handler) - { - Player = player; - Handler = handler; - } - - /// - /// Gets or sets current player. - /// - public API.Features.Player Player { get; set; } - - /// - /// Gets or sets current Damage Handler. - /// - public DamageHandlerBase Handler { get; set; } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/RotatingRevolverEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/RotatingRevolverEventArgs.cs new file mode 100644 index 000000000..515d8c7b0 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/RotatingRevolverEventArgs.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using API.Features; + using API.Features.Items; + + using Exiled.API.Features.Items.FirearmModules.Primary; + + using Interfaces; + + using InventorySystem.Items.Firearms.Modules; + + using FirearmBase = InventorySystem.Items.Firearms.Firearm; + + /// + /// Contains all information when a player rotates revolver. + /// + public class RotatingRevolverEventArgs : IPlayerEvent, IFirearmEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + public RotatingRevolverEventArgs(FirearmBase firearm, int rotations) + { + Firearm = Item.Get(firearm); + Player = Firearm.Owner; + Rotations = rotations; + } + + /// + /// Gets or sets a rotations count(per chamber). + /// + public int Rotations { get; set; } + + /// + /// Gets a value indicating whether the rotation will have an effect. + /// + /// + /// checks rotations and chambers counts equality by mod of chambers counts. Rotations % Chambers.Length == 0 + /// + public bool HasEffect => Firearm.PrimaryMagazine.MaxAmmo % Rotations == 0; + + /// + public Firearm Firearm { get; } + + /// + public Item Item => Firearm; + + /// + public Player Player { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ShootingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ShootingEventArgs.cs index 177b3c5a6..3c2f9d12b 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ShootingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ShootingEventArgs.cs @@ -8,106 +8,72 @@ namespace Exiled.Events.EventArgs.Player { using API.Features; - using Exiled.API.Features.Items; - using Interfaces; - - using InventorySystem.Items.Firearms.BasicMessages; - - using RelativePositioning; - + using InventorySystem.Items.Firearms.Modules.Misc; using UnityEngine; using BaseFirearm = InventorySystem.Items.Firearms.Firearm; /// /// Contains all information before a player fires a weapon. + /// ClaimedTarget and Player transform values are modified by according to sent by the Player and do not match the actual values. /// public class ShootingEventArgs : IPlayerEvent, IDeniableEvent, IFirearmEvent { /// /// Initializes a new instance of the class. /// - /// - /// - /// /// - /// + /// The that is being fired. /// - /// - /// + /// + /// sent by the client. /// - public ShootingEventArgs(Player shooter, BaseFirearm firearm, ShotMessage msg) + public ShootingEventArgs(BaseFirearm firearm, ref ShotBacktrackData shotBacktrackData) { - Player = shooter; - Firearm = Item.Get(firearm).As(); - ShotMessage = msg; + Firearm = (Firearm)Item.Get(firearm); + Player = Firearm.Owner; + ShotBacktrackData = shotBacktrackData; } /// - /// Gets the player who's shooting. + /// Gets the player who is shooting. /// public Player Player { get; } /// - /// Gets the target . + /// Gets the target that client claims it hit. /// - public Firearm Firearm { get; } - - /// - public Item Item => Firearm; + /// This value is controlled by the shooting player and should not be trusted. Can be null. + public Player ClaimedTarget => ShotBacktrackData.HasPrimaryTarget ? Player.Get(ShotBacktrackData.PrimaryTargetHub) : null; /// - /// Gets or sets the for the event. + /// Gets the . This object contains the data sent by the client to the server. /// - public ShotMessage ShotMessage { get; set; } + /// Values are controlled by the shooting player and should not be trusted. + public ShotBacktrackData ShotBacktrackData { get; } /// - /// Gets or sets the position of the shot. + /// Gets or sets the exact direction of the shot before the bullet spread is applied. /// - public Vector3 ShotPosition + public Vector3 Direction { - get => ShotMessage.TargetPosition.Position; - set - { - ShotMessage msg = ShotMessage; - ShotMessage = new ShotMessage - { - ShooterPosition = msg.ShooterPosition, - ShooterCameraRotation = msg.ShooterCameraRotation, - ShooterWeaponSerial = msg.ShooterWeaponSerial, - TargetPosition = new RelativePosition(value), - TargetRotation = msg.TargetRotation, - TargetNetId = msg.TargetNetId, - }; - } + get => Player.CameraTransform.forward; + set => Player.CameraTransform.forward = value; // It is going to be reset by FpcBacktracker the same frame, so why we can set it freely. } /// - /// Gets or sets the netId of the target of the shot. + /// Gets the firearm that is being fired. /// - public uint TargetNetId - { - get => ShotMessage.TargetNetId; - set - { - ShotMessage msg = ShotMessage; - ShotMessage = new ShotMessage - { - ShooterPosition = msg.ShooterPosition, - ShooterCameraRotation = msg.ShooterCameraRotation, - ShooterWeaponSerial = msg.ShooterWeaponSerial, - TargetPosition = msg.TargetPosition, - TargetRotation = msg.TargetRotation, - TargetNetId = value, - }; - } - } + public Firearm Firearm { get; } + + /// + public Item Item => Firearm; /// /// Gets or sets a value indicating whether the shot can be fired. /// public bool IsAllowed { get; set; } = true; } -} +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs index 18ff833b4..0eb6a5c69 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ShotEventArgs.cs @@ -10,7 +10,7 @@ namespace Exiled.Events.EventArgs.Player using API.Features; using Exiled.API.Features.Items; using Interfaces; - + using InventorySystem.Items.Firearms.Modules; using UnityEngine; /// @@ -19,44 +19,36 @@ namespace Exiled.Events.EventArgs.Player public class ShotEventArgs : IPlayerEvent, IFirearmEvent { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// The hit. - /// - /// - /// - /// - /// - /// - public ShotEventArgs(Player shooter, Firearm firearm, RaycastHit hit, IDestructible destructible, float damage) + /// Hitreg module that calculated the shot. + /// Raycast hit info. + /// The firearm used. + /// The IDestructible that was hit. Can be null. + public ShotEventArgs(HitscanHitregModuleBase hitregModule, RaycastHit hitInfo, InventorySystem.Items.Firearms.Firearm firearm, IDestructible destructible) { - Player = shooter; - Firearm = firearm; - Damage = damage; - Distance = hit.distance; - Position = hit.point; - RaycastHit = hit; - - if (destructible is HitboxIdentity identity) + HitregModule = hitregModule; + RaycastHit = hitInfo; + Destructible = destructible; + Firearm = Item.Get(firearm); + + Player = Firearm.Owner; + Damage = Destructible is not null ? HitregModule.DamageAtDistance(hitInfo.distance) : 0f; + + if (Destructible is HitboxIdentity hitboxIdentity) { - Hitbox = identity; + Hitbox = hitboxIdentity; Target = Player.Get(Hitbox.TargetHub); } } /// - /// Gets the player who shot. + /// Gets the player who fired the shot. /// public Player Player { get; } /// - /// Gets the firearm used to shoot. + /// Gets the firearm used to fire the shot. /// public Firearm Firearm { get; } @@ -64,38 +56,53 @@ public ShotEventArgs(Player shooter, Firearm firearm, RaycastHit hit, IDestructi public Item Item => Firearm; /// - /// Gets the hitbox type of the shot. Can be !. + /// Gets the firearm hitreg module responsible for the shot. /// - public HitboxIdentity Hitbox { get; } + public HitscanHitregModuleBase HitregModule { get; } /// - /// Gets or sets the inflicted damage. + /// Gets the raycast info. /// - public float Damage { get; set; } + public RaycastHit RaycastHit { get; } /// - /// Gets the shot distance. + /// Gets the bullet travel distance. /// - public float Distance { get; } + public float Distance => RaycastHit.distance; /// - /// Gets the shot position. + /// Gets the position of the hit. /// - public Vector3 Position { get; } + public Vector3 Position => RaycastHit.point; /// - /// Gets the raycast result. + /// Gets the firearm base damage at the hit distance. Actual inflicted damage may vary. /// - public RaycastHit RaycastHit { get; } + public float Damage { get; } /// - /// Gets the target of the shot. Can be !. + /// Gets the target player. Can be null. /// public Player Target { get; } /// - /// Gets or sets a value indicating whether the shot can hurt the target. + /// Gets the component of the target player that was hit. Can be null. + /// + public HitboxIdentity Hitbox { get; } + + /// + /// Gets the component of the hit collider. Can be null. + /// + public IDestructible Destructible { get; } + + /// + /// Gets or sets a value indicating whether the shot can deal damage. /// public bool CanHurt { get; set; } = true; + + /// + /// Gets or sets a value indicating whether the shot can produce impact effects (e.g. bullet holes). + /// + public bool CanSpawnImpactEffects { get; set; } = true; } } diff --git a/EXILED/Exiled.Events/EventArgs/Player/SpawningEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SpawningEventArgs.cs index 1e4c28346..785ff5a3c 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/SpawningEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/SpawningEventArgs.cs @@ -7,11 +7,12 @@ namespace Exiled.Events.EventArgs.Player { + using System; + using Exiled.API.Features; using Exiled.API.Features.Roles; using Exiled.Events.EventArgs.Interfaces; using PlayerRoles; - using UnityEngine; /// @@ -31,15 +32,15 @@ public class SpawningEventArgs : IPlayerEvent /// /// /// - /// - /// the spawned player's old role. + /// + /// the spawned player's new role. /// - public SpawningEventArgs(Player player, Vector3 position, float rotation, PlayerRoleBase oldRole) + public SpawningEventArgs(Player player, Vector3 position, float rotation, PlayerRoleBase newRole) { Player = player; Position = position; HorizontalRotation = rotation; - OldRole = Role.Create(oldRole); + NewRole = Role.Create(newRole); } /// @@ -66,6 +67,12 @@ public SpawningEventArgs(Player player, Vector3 position, float rotation, Player /// /// Gets the player's old role. /// - public Role OldRole { get; } + [Obsolete("Removed because the method is no longer provide OldRole since version 14.0. Use Player.Role instead")] + public Role OldRole => Player.Role; + + /// + /// Gets the player's new role. + /// + public Role NewRole { get; } } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs index 586cc15f5..ee1b36558 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ThrowingRequestEventArgs.cs @@ -17,7 +17,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information before receving a throwing request. /// - public class ThrowingRequestEventArgs : IPlayerEvent, IItemEvent + public class ThrowingRequestEventArgs : IItemEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs index 7da1528af..14ab42de1 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/ThrownProjectileEventArgs.cs @@ -18,7 +18,7 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information after a player throws a grenade. /// - public class ThrownProjectileEventArgs : IPlayerEvent, IItemEvent, IPickupEvent + public class ThrownProjectileEventArgs : IItemEvent, IPickupEvent { /// /// Initializes a new instance of the class. diff --git a/EXILED/Exiled.Events/EventArgs/Player/TogglingWeaponFlashlightEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TogglingWeaponFlashlightEventArgs.cs index ccc8a6fd3..3c6f2f788 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/TogglingWeaponFlashlightEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/TogglingWeaponFlashlightEventArgs.cs @@ -12,6 +12,8 @@ namespace Exiled.Events.EventArgs.Player using Interfaces; + using BaseFirearm = InventorySystem.Items.Firearms.Firearm; + /// /// Contains all information before a player toggles the weapon's flashlight. /// @@ -20,24 +22,17 @@ public class TogglingWeaponFlashlightEventArgs : IPlayerEvent, IFirearmEvent, ID /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - /// + /// /// /// - /// - /// - /// - public TogglingWeaponFlashlightEventArgs(Player player, Firearm firearm, bool newState, bool isAllowed = true) + public TogglingWeaponFlashlightEventArgs(BaseFirearm firearm, bool oldState) { - Firearm = firearm; - Player = player; - NewState = newState; - IsAllowed = isAllowed; + Firearm = Item.Get(firearm); + Player = Firearm.Owner; + NewState = !oldState; } /// @@ -48,7 +43,7 @@ public TogglingWeaponFlashlightEventArgs(Player player, Firearm firearm, bool ne /// /// Gets or sets a value indicating whether the weapon's flashlight can be toggled. /// - public bool IsAllowed { get; set; } + public bool IsAllowed { get; set; } = true; /// /// Gets the being held. diff --git a/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs index f8e4419d0..96e1ffde4 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/TransmittingEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Player { - using System; - using Exiled.API.Features; using Exiled.Events.EventArgs.Interfaces; @@ -48,12 +46,6 @@ public TransmittingEventArgs(Player player, VoiceModuleBase voiceModule, bool is /// public VoiceModuleBase VoiceModule { get; } - /// - /// Gets a value indicating whether the player is transmitting. - /// - [Obsolete("IsTransmitting is always true.")] - public bool IsTransmitting => true; - /// /// Gets or sets a value indicating whether the player can transmit. /// diff --git a/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs index d4203283f..cbf292d86 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Player/UsingMicroHIDEnergyEventArgs.cs @@ -17,32 +17,24 @@ namespace Exiled.Events.EventArgs.Player /// /// Contains all information before MicroHID energy is changed. /// - public class UsingMicroHIDEnergyEventArgs : IPlayerEvent, IDeniableEvent, IItemEvent + public class UsingMicroHIDEnergyEventArgs : IDeniableEvent, IItemEvent { /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - /// - /// - /// - /// + /// /// /// /// /// /// - public UsingMicroHIDEnergyEventArgs(Player player, MicroHIDItem microHIDitem, HidState currentState, float drain, bool isAllowed = true) + public UsingMicroHIDEnergyEventArgs(MicroHIDItem microHIDitem, float newEnergy, bool isAllowed = true) { - Player = player; MicroHID = Item.Get(microHIDitem); - CurrentState = currentState; - Drain = drain; + Drain = MicroHID.Energy - newEnergy; IsAllowed = isAllowed; } @@ -54,11 +46,6 @@ public UsingMicroHIDEnergyEventArgs(Player player, MicroHIDItem microHIDitem, Hi /// public Item Item => MicroHID; - /// - /// Gets the current state of the MicroHID. - /// - public HidState CurrentState { get; } - /// /// Gets or sets the MicroHID energy drain. /// @@ -69,9 +56,7 @@ public UsingMicroHIDEnergyEventArgs(Player player, MicroHIDItem microHIDitem, Hi /// public bool IsAllowed { get; set; } - /// - /// Gets the player who's using the MicroHID. - /// - public Player Player { get; } + /// + public Player Player => MicroHID.Owner; } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs index e350a746d..c8ae4fdae 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp049/ActivatingSenseEventArgs.cs @@ -7,10 +7,7 @@ namespace Exiled.Events.EventArgs.Scp049 { - using System; - using API.Features; - using Exiled.API.Features.Roles; using Exiled.Events.EventArgs.Interfaces; using Scp049Role = API.Features.Roles.Scp049Role; @@ -54,12 +51,6 @@ public ActivatingSenseEventArgs(Player player, Player target, bool isAllowed = t /// public float FailedCooldown { get; set; } - /// - /// Gets or sets the cooldown of the ability. - /// - [Obsolete("Use FailedCooldown instead of this")] - public float Cooldown { get => FailedCooldown; set => FailedCooldown = value; } - /// /// Gets or sets the duration of the Effect. /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumedCorpseEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumedCorpseEventArgs.cs index e27675ed3..56aff95ac 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumedCorpseEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp0492/ConsumedCorpseEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Scp0492 { - using System; - using API.Features; using Exiled.API.Features.Roles; using Interfaces; diff --git a/EXILED/Exiled.Events/EventArgs/Scp079/ElevatorTeleportingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp079/ElevatorTeleportingEventArgs.cs index da8aae174..85907c0db 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp079/ElevatorTeleportingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp079/ElevatorTeleportingEventArgs.cs @@ -29,18 +29,18 @@ public class ElevatorTeleportingEventArgs : IScp079Event, IRoomEvent, IDeniableE /// /// /// - /// + /// /// /// /// /// /// - public ElevatorTeleportingEventArgs(Player player, RoomIdentifier room, ElevatorDoor elevatorDoor, float auxiliaryPowerCost) + public ElevatorTeleportingEventArgs(Player player, RoomIdentifier room, ElevatorChamber elevatorChamber, float auxiliaryPowerCost) { Player = player; Scp079 = player.Role.As(); Room = Room.Get(room); - Lift = Lift.Get(elevatorDoor.TargetPanel.AssignedChamber); + Lift = Lift.Get(elevatorChamber); AuxiliaryPowerCost = auxiliaryPowerCost; IsAllowed = auxiliaryPowerCost <= Scp079.Energy; } diff --git a/EXILED/Exiled.Events/EventArgs/Scp106/ExitStalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp106/ExitStalkingEventArgs.cs index 0f86698bf..b501c112c 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp106/ExitStalkingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp106/ExitStalkingEventArgs.cs @@ -7,11 +7,8 @@ namespace Exiled.Events.EventArgs.Scp106 { - using System; - using API.Features; using Interfaces; - using PlayerRoles.PlayableScps.Scp106; using Scp106Role = API.Features.Roles.Scp106Role; diff --git a/EXILED/Exiled.Events/EventArgs/Scp106/StalkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp106/StalkingEventArgs.cs index 1ed03bc42..b94a3db6f 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp106/StalkingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp106/StalkingEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Scp106 { - using System; - using API.Features; using Interfaces; using PlayerRoles.PlayableScps.Scp106; @@ -24,32 +22,14 @@ public class StalkingEventArgs : IScp106Event, IDeniableEvent /// Initializes a new instance of the class. /// /// - /// - public StalkingEventArgs(Player player, bool isAllowed = true) + public StalkingEventArgs(Player player) { Player = player; Scp106 = player.Role.As(); - IsAllowed = isAllowed; + IsAllowed = true; MinimumVigor = Scp106StalkAbility.MinVigorToSubmerge; } - /// - /// Gets the . - /// - [Obsolete("Use Scp106.StalkAbility instead of this")] - public Scp106StalkAbility Scp106StalkAbility => Scp106.StalkAbility; - - /// - /// Gets or sets the current vigor when SCP-106 starts to stalk. - /// - public float Vigor - { - [Obsolete("Use Scp106.Vigor instead of this")] - get => Scp106.Vigor; - [Obsolete("Use Scp106.Vigor instead of this")] - set => Scp106.Vigor = value; - } - /// /// Gets or sets the required minimum vigor to stalk. /// @@ -66,6 +46,7 @@ public float Vigor /// /// Gets or sets a value indicating whether SCP-106 can stalk. /// + /// IsAllowed doesn't indicate whether vigor is sufficient for Stalking. needs to be changed to override the base game check. public bool IsAllowed { get; set; } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp1344/ChangedStatusEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1344/ChangedStatusEventArgs.cs new file mode 100644 index 000000000..11afddf79 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp1344/ChangedStatusEventArgs.cs @@ -0,0 +1,55 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp1344 +{ + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Usables.Scp1344; + + /// + /// Contains all information after SCP-1344 status changing. + /// + public class ChangedStatusEventArgs : IScp1344Event, IPlayerEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public ChangedStatusEventArgs(Item item, Scp1344Status scp1344Status) + { + Item = item; + Scp1344 = item as Scp1344; + Player = item.Owner; + Scp1344Status = scp1344Status; + } + + /// + /// Gets the new state. + /// + public Scp1344Status Scp1344Status { get; } + + /// + /// Gets the item. + /// + public Item Item { get; } + + /// + /// Gets the player in owner of the item. + /// + public Exiled.API.Features.Player Player { get; } + + /// + /// Gets Scp1344 item. + /// + public Scp1344 Scp1344 { get; } + + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/EventArgs/Scp1344/ChangingStatusEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1344/ChangingStatusEventArgs.cs new file mode 100644 index 000000000..89329e073 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp1344/ChangingStatusEventArgs.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp1344 +{ + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.Usables.Scp1344; + + /// + /// Contains all information before SCP-1344 status changing. + /// + public class ChangingStatusEventArgs : IPlayerEvent, IScp1344Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public ChangingStatusEventArgs(Item item, Scp1344Status scp1344StatusNew, Scp1344Status scp1344StatusOld, bool isAllowed = true) + { + Item = item; + Scp1344 = item as Scp1344; + Player = item.Owner; + Scp1344StatusNew = scp1344StatusNew; + Scp1344StatusOld = scp1344StatusOld; + IsAllowed = isAllowed; + } + + /// + /// Gets the current status. + /// + public Scp1344Status Scp1344StatusOld { get; } + + /// + /// Gets or sets the new state. + /// + public Scp1344Status Scp1344StatusNew { get; set; } + + /// + /// Gets the item. + /// + public Item Item { get; } + + /// + /// Gets the player in owner of the item. + /// + public Exiled.API.Features.Player Player { get; } + + /// + /// Gets Scp1344 item. + /// + public Scp1344 Scp1344 { get; } + + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatedEventArgs.cs new file mode 100644 index 000000000..79ec6925e --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatedEventArgs.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp1344 +{ + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information after deactivating. + /// + public class DeactivatedEventArgs : IPlayerEvent, IScp1344Event + { + /// + /// Initializes a new instance of the class. + /// + /// + public DeactivatedEventArgs(Item item) + { + Item = item; + Scp1344 = item as Scp1344; + Player = item.Owner; + } + + /// + /// Gets the item. + /// + public Item Item { get; } + + /// + /// Gets the player in owner of the item. + /// + public Exiled.API.Features.Player Player { get; } + + /// + /// Gets Scp1344 item. + /// + public Scp1344 Scp1344 { get; } + } +} diff --git a/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatingEventArgs.cs new file mode 100644 index 000000000..96bcbc211 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp1344/DeactivatingEventArgs.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp1344 +{ + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before deactivating. + /// + public class DeactivatingEventArgs : IPlayerEvent, IScp1344Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public DeactivatingEventArgs(Item item, bool isAllowed = true) + { + Item = item; + Scp1344 = item as Scp1344; + Player = item.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the item. + /// + public Item Item { get; } + + /// + /// Gets the player in owner of the item. + /// + public Exiled.API.Features.Player Player { get; } + + /// + /// Gets Scp1344 item. + /// + public Scp1344 Scp1344 { get; } + + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/EventArgs/Scp1344/TryingDeactivatingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp1344/TryingDeactivatingEventArgs.cs new file mode 100644 index 000000000..f236851f1 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp1344/TryingDeactivatingEventArgs.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp1344 +{ + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before trying deactivating. + /// + public class TryingDeactivatingEventArgs : IPlayerEvent, IScp1344Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public TryingDeactivatingEventArgs(Item item, bool isAllowed = true) + { + Item = item; + Scp1344 = item as Scp1344; + Player = item.Owner; + IsAllowed = isAllowed; + } + + /// + /// Gets the item. + /// + public Item Item { get; } + + /// + /// Gets the player in owner of the item. + /// + public Exiled.API.Features.Player Player { get; } + + /// + /// Gets Scp1344 item. + /// + public Scp1344 Scp1344 { get; } + + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp173/BlinkingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp173/BlinkingEventArgs.cs index ef697602d..95f3e2a08 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp173/BlinkingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp173/BlinkingEventArgs.cs @@ -58,8 +58,7 @@ public BlinkingEventArgs(Player player, List targets, Vector3 blinkPos) /// /// Gets a of players who have triggered SCP-173. /// - // TODO: convert to ReadOnlyCollection - public List Targets { get; } + public IReadOnlyCollection Targets { get; } /// /// Gets or sets a value indicating whether the player is allowed to blink. diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs index 1542d6aa0..0ead45776 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp330/DroppingScp330EventArgs.cs @@ -39,9 +39,9 @@ public DroppingScp330EventArgs(Player player, Scp330Bag scp330, CandyKindID cand } /// - /// Gets or sets a value representing the being picked up. + /// Gets a value representing the being picked up. /// - public Scp330 Scp330 { get; set; } // Todo Remove set + public Scp330 Scp330 { get; } /// public Item Item => Scp330; diff --git a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs index 526042dd9..dc39d420c 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp330/InteractingScp330EventArgs.cs @@ -12,7 +12,6 @@ namespace Exiled.Events.EventArgs.Scp330 using Interfaces; using InventorySystem.Items.Usables.Scp330; - using YamlDotNet.Core.Tokens; /// /// Contains all information before a player interacts with SCP-330. @@ -35,6 +34,7 @@ public InteractingScp330EventArgs(Player player, int usage) ShouldSever = usage >= 2; ShouldPlaySound = true; IsAllowed = Player.IsHuman; + Candy = Scp330Candies.GetRandom(); if (Scp330Bag.TryGetBag(player.ReferenceHub, out Scp330Bag scp330Bag)) { @@ -46,8 +46,6 @@ public InteractingScp330EventArgs(Player player, int usage) Scp330.RemoveAllCandy(); player.AddItem(Scp330); } - - Scp330.CandyToAdd = Scp330Candies.GetRandom(); } /// @@ -55,15 +53,6 @@ public InteractingScp330EventArgs(Player player, int usage) /// public int UsageCount { get; } - /// - /// Gets or sets a value indicating the type of candy that will be received from this interaction. - /// - public CandyKindID Candy - { - get => Scp330.CandyToAdd; - set => Scp330.CandyToAdd = value; - } - /// /// Gets or sets a value indicating whether the player's hands should get severed. /// @@ -75,6 +64,11 @@ public CandyKindID Candy /// It won't work if = . public bool ShouldPlaySound { get; set; } + /// + /// Gets or sets a value indicating the type of candy that will be received from this interaction. + /// + public CandyKindID Candy { get; set; } + /// /// Gets or sets a value indicating whether the player is allowed to interact with SCP-330. /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingInventoryItemEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingInventoryItemEventArgs.cs index 18247e605..667320e57 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingInventoryItemEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingInventoryItemEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Scp914 { - using System; - using API.Features; using API.Features.Items; using global::Scp914; @@ -18,7 +16,7 @@ namespace Exiled.Events.EventArgs.Scp914 /// /// Contains all information before SCP-914 upgrades an item. /// - public class UpgradingInventoryItemEventArgs : IPlayerEvent, IItemEvent, IDeniableEvent + public class UpgradingInventoryItemEventArgs : IItemEvent, IDeniableEvent { /// /// Initializes a new instance of the class. @@ -43,12 +41,6 @@ public UpgradingInventoryItemEventArgs(Player player, ItemBase item, Scp914KnobS IsAllowed = isAllowed; } - /// - /// Gets the instance. - /// - [Obsolete("Use Scp914::Scp914Controller instead.")] - public Scp914Controller Scp914 => API.Features.Scp914.Scp914Controller; - /// /// Gets or sets SCP-914 working knob setting. /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPickupEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPickupEventArgs.cs index cf374690a..691db20a1 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPickupEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPickupEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Scp914 { - using System; - using Exiled.API.Features.Pickups; using Exiled.Events.EventArgs.Interfaces; using global::Scp914; @@ -44,12 +42,6 @@ public UpgradingPickupEventArgs(ItemPickupBase item, Vector3 newPos, Scp914KnobS /// public Pickup Pickup { get; } - /// - /// Gets the instance. - /// - [Obsolete("Use Scp914::Scp914Controller instead.")] - public Scp914Controller Scp914 => API.Features.Scp914.Scp914Controller; - /// /// Gets or sets the position the item will be output to. /// diff --git a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPlayerEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPlayerEventArgs.cs index 9dedafb5a..cf4487ecc 100644 --- a/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPlayerEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Scp914/UpgradingPlayerEventArgs.cs @@ -31,16 +31,16 @@ public class UpgradingPlayerEventArgs : IPlayerEvent, IDeniableEvent /// /// /// - /// - /// + /// + /// /// - public UpgradingPlayerEventArgs(Player player, bool upgradeItems, bool heldOnly, Scp914KnobSetting setting, Vector3 moveVector) + public UpgradingPlayerEventArgs(Player player, bool upgradeItems, bool heldOnly, Scp914KnobSetting setting, Vector3 outputPos) { Player = player; UpgradeItems = upgradeItems; HeldOnly = heldOnly; KnobSetting = setting; - OutputPosition = player.Position + moveVector; + OutputPosition = outputPos; } /// diff --git a/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs index 5c72d299b..216676772 100644 --- a/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/EndingRoundEventArgs.cs @@ -7,8 +7,6 @@ namespace Exiled.Events.EventArgs.Server { - using System; - using API.Enums; using Interfaces; @@ -20,24 +18,24 @@ public class EndingRoundEventArgs : IDeniableEvent /// /// Initializes a new instance of the class. /// - /// - /// - /// /// /// /// - /// - /// + /// + /// /// /// /// /// - public EndingRoundEventArgs(RoundSummary.LeadingTeam leadingTeam, RoundSummary.SumInfo_ClassList classList, bool isAllowed, bool isForceEnded) + /// + /// + /// + public EndingRoundEventArgs(LeadingTeam leadingTeam, RoundSummary.SumInfo_ClassList classList, bool isForceEnded, bool isAllowed) { + LeadingTeam = leadingTeam; ClassList = classList; - LeadingTeam = (LeadingTeam)leadingTeam; - IsRoundEnded = isAllowed; IsForceEnded = isForceEnded; + IsAllowed = isAllowed; } /// @@ -51,22 +49,13 @@ public EndingRoundEventArgs(RoundSummary.LeadingTeam leadingTeam, RoundSummary.S public LeadingTeam LeadingTeam { get; set; } /// - /// Gets or sets a value indicating whether the round is going to finish. - /// - public bool IsRoundEnded { get; set; } // TODO: Obsolete this in Exiled 10 - - /// - /// Gets or Sets a value indicating whether the round is ended by API call. + /// Gets or sets a value indicating whether the round is ended by API call. /// public bool IsForceEnded { get; set; } /// - /// Gets or sets a value indicating whether the event can be executed. + /// Gets or sets a value indicating whether the round is going to finish or not. /// - public bool IsAllowed - { - get => IsRoundEnded; - set => IsRoundEnded = value; - } -} + public bool IsAllowed { get; set; } + } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/LocalReportingEventArgs.cs similarity index 95% rename from EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs rename to EXILED/Exiled.Events/EventArgs/Server/LocalReportingEventArgs.cs index d937a5fef..02d1d6b98 100644 --- a/EXILED/Exiled.Events/EventArgs/Player/LocalReportingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/LocalReportingEventArgs.cs @@ -5,7 +5,7 @@ // // ----------------------------------------------------------------------- -namespace Exiled.Events.EventArgs.Player // TODO: Wrong namespace should be Server +namespace Exiled.Events.EventArgs.Server { using API.Features; diff --git a/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs index cbc6886cf..d3d62667a 100644 --- a/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/RespawnedTeamEventArgs.cs @@ -13,6 +13,7 @@ namespace Exiled.Events.EventArgs.Server using Exiled.API.Features; using Exiled.Events.EventArgs.Interfaces; using Respawning; + using Respawning.Waves; /// /// Contains all information after team spawns. @@ -23,11 +24,11 @@ public class RespawnedTeamEventArgs : IExiledEvent /// Initializes a new instance of the class. /// /// - /// - public RespawnedTeamEventArgs(SpawnableTeamType team, IEnumerable hubs) + /// + public RespawnedTeamEventArgs(SpawnableWaveBase wave, IEnumerable hubs) { Players = hubs.Select(Player.Get); - Team = team; + Wave = wave; } /// @@ -38,6 +39,6 @@ public RespawnedTeamEventArgs(SpawnableTeamType team, IEnumerable /// /// Gets the spawned team. /// - public SpawnableTeamType Team { get; } + public SpawnableWaveBase Wave { get; } } } diff --git a/EXILED/Exiled.Events/EventArgs/Server/RespawningTeamEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/RespawningTeamEventArgs.cs index ab0234c2a..e65bdbf03 100644 --- a/EXILED/Exiled.Events/EventArgs/Server/RespawningTeamEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/RespawningTeamEventArgs.cs @@ -10,19 +10,17 @@ namespace Exiled.Events.EventArgs.Server using System.Collections.Generic; using Exiled.API.Features; + using Exiled.API.Features.Waves; using Exiled.Events.EventArgs.Interfaces; - using PlayerRoles; - using Respawning; + using Respawning.Waves; /// - /// Contains all information before spawning a wave of or - /// . + /// Contains all information before spawning a wave. /// public class RespawningTeamEventArgs : IDeniableEvent { - private SpawnableTeamType nextKnownTeam; private int maximumRespawnAmount; /// @@ -34,21 +32,16 @@ public class RespawningTeamEventArgs : IDeniableEvent /// /// /// - /// + /// /// /// - /// - /// - /// - public RespawningTeamEventArgs(List players, int maxRespawn, SpawnableTeamType nextKnownTeam, bool isAllowed = true) + public RespawningTeamEventArgs(List players, int maxRespawn, SpawnableWaveBase wave) { Players = players; MaximumRespawnAmount = maxRespawn; - - this.nextKnownTeam = nextKnownTeam; - SpawnQueue = new(); - SpawnableTeam.GenerateQueue(SpawnQueue, players.Count); - IsAllowed = isAllowed; + SpawnQueue = WaveSpawner.SpawnQueue; + Wave = new TimedWave((TimeBasedWave)wave); + IsAllowed = true; } /// @@ -75,32 +68,14 @@ public int MaximumRespawnAmount } /// - /// Gets or sets a value indicating what the next respawnable team is. + /// Gets or sets a value indicating what the next wave is. /// - public SpawnableTeamType NextKnownTeam - { - get => nextKnownTeam; - set - { - nextKnownTeam = value; - - if (!RespawnManager.SpawnableTeams.TryGetValue(value, out SpawnableTeamHandlerBase spawnableTeam)) - { - MaximumRespawnAmount = 0; - return; - } - - MaximumRespawnAmount = spawnableTeam.MaxWaveSize; - if (RespawnManager.SpawnableTeams.TryGetValue(nextKnownTeam, out SpawnableTeamHandlerBase @base)) - @base.GenerateQueue(SpawnQueue, Players.Count); - } - } + public TimedWave Wave { get; set; } /// - /// Gets the current spawnable team. + /// Gets a value indicating what the next respawnable team is. /// - public SpawnableTeamHandlerBase SpawnableTeam - => RespawnManager.SpawnableTeams.TryGetValue(NextKnownTeam, out SpawnableTeamHandlerBase @base) ? @base : null; + public Faction NextKnownTeam => Wave.Faction; /// /// Gets or sets a value indicating whether the spawn can occur. diff --git a/EXILED/Exiled.Events/EventArgs/Server/SelectingRespawnTeamEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Server/SelectingRespawnTeamEventArgs.cs index 63f27d345..dd6294777 100644 --- a/EXILED/Exiled.Events/EventArgs/Server/SelectingRespawnTeamEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Server/SelectingRespawnTeamEventArgs.cs @@ -7,29 +7,36 @@ namespace Exiled.Events.EventArgs.Server { - using System; - - using Exiled.API.Features; + using Exiled.API.Enums; + using Exiled.API.Features.Waves; using Exiled.Events.EventArgs.Interfaces; - using Respawning; + using Respawning.Waves; /// /// Contains all information before selecting the team to respawn next. /// - public class SelectingRespawnTeamEventArgs : IExiledEvent + public class SelectingRespawnTeamEventArgs : IDeniableEvent { /// /// Initializes a new instance of the class. /// - /// The used as the starting value for this event. - public SelectingRespawnTeamEventArgs(SpawnableTeamType type) + /// . + public SelectingRespawnTeamEventArgs(SpawnableWaveBase wave) { - Team = type; + Wave = new TimedWave((TimeBasedWave)wave); } /// - /// Gets or sets that represents the team chosen to spawn. + /// Gets that represents the team chosen to spawn. /// - public SpawnableTeamType Team { get; set; } + public SpawnableFaction Team => Wave.SpawnableFaction; + + /// + /// Gets or sets that is selected. + /// + public TimedWave Wave { get; set; } + + /// + public bool IsAllowed { get; set; } = true; } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Events.cs b/EXILED/Exiled.Events/Events.cs index f11eab2e1..ac37f5528 100644 --- a/EXILED/Exiled.Events/Events.cs +++ b/EXILED/Exiled.Events/Events.cs @@ -13,16 +13,17 @@ namespace Exiled.Events using API.Enums; using API.Features; using CentralAuth; + using Exiled.API.Features.Core.UserSettings; using Exiled.Events.Features; using HarmonyLib; using InventorySystem.Items.Pickups; using InventorySystem.Items.Usables; - using PlayerRoles.Ragdolls; using PlayerRoles.RoleAssign; using PluginAPI.Events; using Respawning; using UnityEngine.SceneManagement; + using UserSettings.ServerSpecific; /// /// Patch and unpatch events into the game. @@ -59,8 +60,9 @@ public override void OnEnabled() Log.Info($"{(Config.UseDynamicPatching ? "Non-event" : "All")} patches completed in {watch.Elapsed}"); PlayerAuthenticationManager.OnInstanceModeChanged -= RoleAssigner.CheckLateJoin; + CustomNetworkManager.OnClientStarted += Handlers.Internal.ClientStarted.OnClientStarted; SceneManager.sceneUnloaded += Handlers.Internal.SceneUnloaded.OnSceneUnloaded; - MapGeneration.SeedSynchronizer.OnMapGenerated += Handlers.Internal.MapGenerated.OnMapGenerated; + MapGeneration.SeedSynchronizer.OnGenerationFinished += Handlers.Internal.MapGenerated.OnMapGenerated; UsableItemsController.ServerOnUsingCompleted += Handlers.Internal.Round.OnServerOnUsingCompleted; Handlers.Server.WaitingForPlayers += Handlers.Internal.Round.OnWaitingForPlayers; Handlers.Server.RestartingRound += Handlers.Internal.Round.OnRestartingRound; @@ -71,7 +73,7 @@ public override void OnEnabled() Handlers.Map.ChangedIntoGrenade += Handlers.Internal.ExplodingGrenade.OnChangedIntoGrenade; CharacterClassManager.OnRoundStarted += Handlers.Server.OnRoundStarted; - RespawnManager.ServerOnRespawned += Handlers.Server.OnRespawnedTeam; + WaveManager.OnWaveSpawned += Handlers.Server.OnRespawnedTeam; InventorySystem.InventoryExtensions.OnItemAdded += Handlers.Player.OnItemAdded; InventorySystem.InventoryExtensions.OnItemRemoved += Handlers.Player.OnItemRemoved; @@ -81,6 +83,8 @@ public override void OnEnabled() ItemPickupBase.OnPickupDestroyed += Handlers.Internal.PickupEvent.OnRemovedPickup; ServerConsole.ReloadServerName(); + ServerSpecificSettingsSync.ServerOnSettingValueReceived += SettingBase.OnSettingUpdated; + EventManager.RegisterEvents(this); } @@ -91,8 +95,9 @@ public override void OnDisabled() Unpatch(); + CustomNetworkManager.OnClientStarted -= Handlers.Internal.ClientStarted.OnClientStarted; SceneManager.sceneUnloaded -= Handlers.Internal.SceneUnloaded.OnSceneUnloaded; - MapGeneration.SeedSynchronizer.OnMapGenerated -= Handlers.Internal.MapGenerated.OnMapGenerated; + MapGeneration.SeedSynchronizer.OnGenerationFinished -= Handlers.Internal.MapGenerated.OnMapGenerated; UsableItemsController.ServerOnUsingCompleted -= Handlers.Internal.Round.OnServerOnUsingCompleted; Handlers.Server.WaitingForPlayers -= Handlers.Internal.Round.OnWaitingForPlayers; Handlers.Server.RestartingRound -= Handlers.Internal.Round.OnRestartingRound; @@ -106,12 +111,14 @@ public override void OnDisabled() InventorySystem.InventoryExtensions.OnItemAdded -= Handlers.Player.OnItemAdded; InventorySystem.InventoryExtensions.OnItemRemoved -= Handlers.Player.OnItemRemoved; - RespawnManager.ServerOnRespawned -= Handlers.Server.OnRespawnedTeam; + WaveManager.OnWaveSpawned -= Handlers.Server.OnRespawnedTeam; RagdollManager.OnRagdollSpawned -= Handlers.Internal.RagdollList.OnSpawnedRagdoll; RagdollManager.OnRagdollRemoved -= Handlers.Internal.RagdollList.OnRemovedRagdoll; ItemPickupBase.OnPickupAdded -= Handlers.Internal.PickupEvent.OnSpawnedPickup; ItemPickupBase.OnPickupDestroyed -= Handlers.Internal.PickupEvent.OnRemovedPickup; + ServerSpecificSettingsSync.ServerOnSettingValueReceived -= SettingBase.OnSettingUpdated; + EventManager.UnregisterEvents(this); } diff --git a/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs new file mode 100644 index 000000000..a260cf495 --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs @@ -0,0 +1,53 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers.Internal +{ + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Enums; + using Exiled.API.Features; + using Exiled.API.Features.Attributes; + using Mirror; + using PlayerRoles.Ragdolls; + using UnityEngine; + + /// + /// Handles on client started event. + /// + internal static class ClientStarted + { + /// + /// Called once when the client is started. + /// + public static void OnClientStarted() + { + PrefabHelper.Prefabs.Clear(); + + Dictionary prefabs = new(); + + foreach (KeyValuePair prefab in NetworkClient.prefabs) + { + if(!prefabs.ContainsKey(prefab.Key)) + prefabs.Add(prefab.Key, prefab.Value); + } + + foreach (NetworkIdentity ragdollPrefab in RagdollManager.AllRagdollPrefabs) + { + if(!prefabs.ContainsKey(ragdollPrefab.assetId)) + prefabs.Add(ragdollPrefab.assetId, ragdollPrefab.gameObject); + } + + foreach (PrefabType prefabType in EnumUtils.Values) + { + PrefabAttribute attribute = prefabType.GetPrefabAttribute(); + PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value); + } + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs index 68c47a99d..1320ad76a 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs @@ -7,25 +7,14 @@ namespace Exiled.Events.Handlers.Internal { - using System; using System.Collections.Generic; using System.Linq; using API.Features; - using API.Features.Items; - using API.Features.Pools; - using API.Structs; - - using Exiled.API.Enums; - using Exiled.API.Extensions; using Exiled.API.Features.Lockers; - using InventorySystem.Items.Firearms.Attachments; - using InventorySystem.Items.Firearms.Attachments.Components; using MEC; - using Utils.NonAllocLINQ; - /// /// Handles event. /// @@ -46,7 +35,6 @@ internal static class MapGenerated public static void OnMapGenerated() { Map.ClearCache(); - PrefabHelper.LoadPrefabs(); Locker.ClearCache(); // TODO: Fix For (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/377) @@ -54,54 +42,7 @@ public static void OnMapGenerated() PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.OtherAlive] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.Tutorial); PlayerRoles.RoleAssign.HumanSpawner.Handlers[PlayerRoles.Team.Dead] = new PlayerRoles.RoleAssign.OneRoleHumanSpawner(PlayerRoles.RoleTypeId.Spectator); - GenerateAttachments(); - Timing.CallDelayed(1, GenerateCache); - } - - private static void GenerateCache() - { - Handlers.Map.OnGenerated(); - - Timing.CallDelayed(0.1f, Handlers.Server.OnWaitingForPlayers); - } - - private static void GenerateAttachments() - { - foreach (FirearmType firearmType in EnumUtils.Values) - { - if (firearmType == FirearmType.None) - continue; - - if (Item.Create(firearmType.GetItemType()) is not Firearm firearm) - continue; - - Firearm.ItemTypeToFirearmInstance.Add(firearmType, firearm); - - List attachmentIdentifiers = ListPool.Pool.Get(); - HashSet attachmentsSlots = HashSetPool.Pool.Get(); - - uint code = 1; - - foreach (Attachment attachment in firearm.Attachments) - { - attachmentsSlots.Add(attachment.Slot); - attachmentIdentifiers.Add(new(code, attachment.Name, attachment.Slot)); - code *= 2U; - } - - uint baseCode = 0; - - attachmentsSlots - .ForEach(slot => baseCode += attachmentIdentifiers - .Where(attachment => attachment.Slot == slot) - .Min(slot => slot.Code)); - - Firearm.BaseCodesValue.Add(firearmType, baseCode); - Firearm.AvailableAttachmentsValue.Add(firearmType, attachmentIdentifiers.ToArray()); - - ListPool.Pool.Return(attachmentIdentifiers); - HashSetPool.Pool.Return(attachmentsSlots); - } + Timing.CallDelayed(1, Handlers.Map.OnGenerated); } } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Internal/Round.cs b/EXILED/Exiled.Events/Handlers/Internal/Round.cs index 5c9ff4c5f..9d04e5c4c 100644 --- a/EXILED/Exiled.Events/Handlers/Internal/Round.cs +++ b/EXILED/Exiled.Events/Handlers/Internal/Round.cs @@ -7,20 +7,29 @@ namespace Exiled.Events.Handlers.Internal { + using System.Collections.Generic; using System.Linq; using CentralAuth; + using Exiled.API.Enums; using Exiled.API.Extensions; using Exiled.API.Features; + using Exiled.API.Features.Core.UserSettings; + using Exiled.API.Features.Items; + using Exiled.API.Features.Pools; using Exiled.API.Features.Roles; + using Exiled.API.Structs; using Exiled.Events.EventArgs.Player; using Exiled.Events.EventArgs.Scp049; using Exiled.Loader; using Exiled.Loader.Features; using InventorySystem; + using InventorySystem.Items.Firearms.Attachments; + using InventorySystem.Items.Firearms.Attachments.Components; using InventorySystem.Items.Usables; using PlayerRoles; using PlayerRoles.RoleAssign; + using Utils.NonAllocLINQ; /// /// Handles some round clean-up events and some others related to players. @@ -33,6 +42,7 @@ internal static class Round /// public static void OnWaitingForPlayers() { + GenerateAttachments(); MultiAdminFeatures.CallEvent(MultiAdminFeatures.EventType.WAITING_FOR_PLAYERS); if (Events.Instance.Config.ShouldReloadConfigsAtRoundRestart) @@ -86,6 +96,9 @@ public static void OnVerified(VerifiedEventArgs ev) { RoleAssigner.CheckLateJoin(ev.Player.ReferenceHub, ClientInstanceMode.ReadyClient); + if (SettingBase.SyncOnJoin != null && SettingBase.SyncOnJoin(ev.Player)) + SettingBase.SendToPlayer(ev.Player); + // TODO: Remove if this has been fixed for https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/52 foreach (Room room in Room.List.Where(current => current.AreLightsOff)) { @@ -93,5 +106,42 @@ public static void OnVerified(VerifiedEventArgs ev) ev.Player.SendFakeSyncVar(room.RoomLightControllerNetIdentity, typeof(RoomLightController), nameof(RoomLightController.NetworkLightsEnabled), false); } } + + private static void GenerateAttachments() + { + foreach (FirearmType firearmType in EnumUtils.Values) + { + if (firearmType == FirearmType.None) + continue; + + if (Item.Create(firearmType.GetItemType()) is not Firearm firearm) + continue; + + Firearm.ItemTypeToFirearmInstance.Add(firearmType, firearm); + + List attachmentIdentifiers = ListPool.Pool.Get(); + HashSet attachmentsSlots = HashSetPool.Pool.Get(); + + uint code = 1; + + foreach (Attachment attachment in firearm.Attachments) + { + attachmentsSlots.Add(attachment.Slot); + attachmentIdentifiers.Add(new(code, attachment.Name, attachment.Slot)); + code *= 2U; + } + + uint baseCode = 0; + attachmentsSlots.ForEach(slot => baseCode += attachmentIdentifiers + .Where(attachment => attachment.Slot == slot) + .Min(slot => slot.Code)); + + Firearm.BaseCodesValue.Add(firearmType, baseCode); + Firearm.AvailableAttachmentsValue.Add(firearmType, attachmentIdentifiers.ToArray()); + + ListPool.Pool.Return(attachmentIdentifiers); + HashSetPool.Pool.Return(attachmentsSlots); + } + } } } diff --git a/EXILED/Exiled.Events/Handlers/Map.cs b/EXILED/Exiled.Events/Handlers/Map.cs index eaaf3703e..3036d4ede 100644 --- a/EXILED/Exiled.Events/Handlers/Map.cs +++ b/EXILED/Exiled.Events/Handlers/Map.cs @@ -25,11 +25,6 @@ public static class Map /// public static Event PlacingBulletHole { get; set; } = new(); - /// - /// Invoked before placing blood. - /// - public static Event PlacingBlood { get; set; } = new(); - /// /// Invoked before announcing the light containment zone decontamination. /// @@ -45,6 +40,11 @@ public static class Map /// public static Event AnnouncingNtfEntrance { get; set; } = new(); + /// + /// Invoked before announcing the Chaos entrance. + /// + public static Event AnnouncingChaosEntrance { get; set; } = new(); + /// /// Invoked before a has been activated. /// @@ -121,12 +121,6 @@ public static class Map /// The instance. public static void OnPlacingBulletHole(PlacingBulletHoleEventArgs ev) => PlacingBulletHole.InvokeSafely(ev); - /// - /// Called before placing bloods. - /// - /// The instance. - public static void OnPlacingBlood(PlacingBloodEventArgs ev) => PlacingBlood.InvokeSafely(ev); - /// /// Called before announcing the light containment zone decontamination. /// @@ -145,6 +139,12 @@ public static class Map /// The instance. public static void OnAnnouncingNtfEntrance(AnnouncingNtfEntranceEventArgs ev) => AnnouncingNtfEntrance.InvokeSafely(ev); + /// + /// Called before announcing the Chaos entrance. + /// + /// The instance. + public static void OnAnnouncingChaosEntrance(AnnouncingChaosEntranceEventArgs ev) => AnnouncingChaosEntrance.InvokeSafely(ev); + /// /// Called before a has been activated. /// diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 2d277ce6a..4efe258a3 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -70,12 +70,16 @@ public class Player public static Event EarningAchievement { get; set; } = new(); /// - /// Invoked before using an . + /// Invoked before the player starts to use an . In other words, it is invoked just before the animation starts. /// + /// + /// Will be invoked even if the is on cooldown. + /// Candies are the only that do not invoke this event. + /// public static Event UsingItem { get; set; } = new(); /// - /// Invoked after a uses an . + /// Invoked before a finishes using a . In other words, it is invoked after the animation finishes but before the is actually used. /// public static Event UsingItemCompleted { get; set; } = new (); @@ -501,8 +505,8 @@ public class Player /// /// Invoked before a damage a Window. - /// // TODO: DamagingWindow instead of PlayerDamageWindow - public static Event PlayerDamageWindow { get; set; } = new(); + /// + public static Event DamagingWindow { get; set; } = new(); /// /// Invoked before a damage a Door. @@ -519,12 +523,6 @@ public class Player /// public static Event ItemRemoved { get; set; } = new(); - /// - /// Invoked before KillPlayer is called. - /// - [Obsolete("Use DyingEventArgs")] - public static Event KillingPlayer { get; set; } = new(); - /// /// Invoked before a enters in an environmental hazard. /// @@ -545,6 +543,38 @@ public class Player /// public static Event ChangingNickname { get; set; } = new(); + /// + /// Invoked before a player's emotion changed. + /// + public static Event ChangingEmotion { get; set; } = new(); + + /// + /// Invoked after a player's emotion changed. + /// + public static Event ChangedEmotion { get; set; } = new(); + + /// + /// Invoked before a 's rotates the revolver. + /// + public static Event RotatingRevolver { get; set; } = new(); + + /// + /// Invoked before disruptor's mode is changed. + /// + public static Event ChangingDisruptorMode { get; set; } = new(); + + /// + /// Called before a player's emotion changed. + /// + /// The instance. + public static void OnChangingEmotion(ChangingEmotionEventArgs ev) => ChangingEmotion.InvokeSafely(ev); + + /// + /// Called after a player's emotion changed. + /// + /// The instance. + public static void OnChangedEmotion(ChangedEmotionEventArgs ev) => ChangedEmotion.InvokeSafely(ev); + /// /// Called before reserved slot is resolved for a . /// @@ -676,8 +706,7 @@ public class Player /// Called before throwing a grenade. /// /// The instance. - // TODO: rename that to OnThrownProjectile - public static void OnThrowingProjectile(ThrownProjectileEventArgs ev) => ThrownProjectile.InvokeSafely(ev); + public static void OnThrownProjectile(ThrownProjectileEventArgs ev) => ThrownProjectile.InvokeSafely(ev); /// /// Called before receving a throwing request. @@ -985,13 +1014,6 @@ public class Player /// The instance. public static void OnSendingAdminChatMessage(SendingAdminChatMessageEventsArgs ev) => SendingAdminChatMessage.InvokeSafely(ev); - /// - /// Called before KillPlayer is called. - /// - /// The event handler. - [Obsolete("Use DyingEventArgs")] - public static void OnKillPlayer(KillingPlayerEventArgs ev) => KillingPlayer.InvokeSafely(ev); - /// /// Called after a has an item added to their inventory. /// @@ -1018,11 +1040,12 @@ public static void OnItemAdded(ReferenceHub referenceHub, InventorySystem.Items. public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Items.ItemBase itemBase, InventorySystem.Items.Pickups.ItemPickupBase pickupBase) { ItemRemovedEventArgs ev = new(referenceHub, itemBase, pickupBase); - ItemRemoved.InvokeSafely(ev); ev.Player.ItemsValue.Remove(ev.Item); API.Features.Items.Item.BaseToItem.Remove(itemBase); + + ItemRemoved.InvokeSafely(ev); } /// @@ -1047,7 +1070,7 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// Called before a damage a window. /// /// The instance. - public static void OnPlayerDamageWindow(DamagingWindowEventArgs ev) => PlayerDamageWindow.InvokeSafely(ev); + public static void OnDamagingWindow(DamagingWindowEventArgs ev) => DamagingWindow.InvokeSafely(ev); /// /// Called before a damage a window. @@ -1175,6 +1198,18 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// The instance. public static void OnChangingNickname(ChangingNicknameEventArgs ev) => ChangingNickname.InvokeSafely(ev); + /// + /// Called before a 's rotates the revolver. + /// + /// The instance. + public static void OnRotatingRevolver(RotatingRevolverEventArgs ev) => RotatingRevolver.InvokeSafely(ev); + + /// + /// Called before disruptor's mode is changed. + /// + /// The instance. + public static void OnChangingDisruptorMode(ChangingDisruptorModeEventArgs ev) => ChangingDisruptorMode.InvokeSafely(ev); + /// /// Called before pre-authenticating a . /// diff --git a/EXILED/Exiled.Events/Handlers/Scp1344.cs b/EXILED/Exiled.Events/Handlers/Scp1344.cs new file mode 100644 index 000000000..e3cd688c7 --- /dev/null +++ b/EXILED/Exiled.Events/Handlers/Scp1344.cs @@ -0,0 +1,75 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Handlers +{ +#pragma warning disable SA1623 // Property summary documentation should match accessors + + using Exiled.Events.EventArgs.Scp1344; + using Exiled.Events.Features; + + /// + /// SCP-1344 related events. + /// + public static class Scp1344 + { + /// + /// Invoked before SCP-1344 status changing. + /// + public static Event ChangingStatus { get; set; } = new(); + + /// + /// Invoked after SCP-1344 status changing. + /// + public static Event ChangedStatus { get; set; } = new(); + + /// + /// Invoked after trying deactivating SCP-1344. + /// + public static Event TryingDeactivating { get; set; } = new(); + + /// + /// Invoked before deactivating SCP-1344. + /// + public static Event Deactivating { get; set; } = new(); + + /// + /// Invoked after deactivating SCP-1344. + /// + public static Event Deactivated { get; set; } = new(); + + /// + /// Called after deactivating SCP-1344. + /// + /// The instance. + public static void OnDeactivated(DeactivatedEventArgs ev) => Deactivated.InvokeSafely(ev); + + /// + /// Called before deactivating SCP-1344. + /// + /// The instance. + public static void OnDeactivating(DeactivatingEventArgs ev) => Deactivating.InvokeSafely(ev); + + /// + /// Called after trying deactivating SCP-1344. + /// + /// The instance. + public static void OnTryingDeactivating(TryingDeactivatingEventArgs ev) => TryingDeactivating.InvokeSafely(ev); + + /// + /// Called before SCP-1344 status changing. + /// + /// The instance. + public static void OnChangingStatus(ChangingStatusEventArgs ev) => ChangingStatus.InvokeSafely(ev); + + /// + /// Called after SCP-1344 status changing. + /// + /// The instance. + public static void OnChangedStatus(ChangedStatusEventArgs ev) => ChangedStatus.InvokeSafely(ev); + } +} diff --git a/EXILED/Exiled.Events/Handlers/Server.cs b/EXILED/Exiled.Events/Handlers/Server.cs index f7032f6ed..c86a8adee 100644 --- a/EXILED/Exiled.Events/Handlers/Server.cs +++ b/EXILED/Exiled.Events/Handlers/Server.cs @@ -10,9 +10,10 @@ namespace Exiled.Events.Handlers using System.Collections.Generic; using Respawning; + using Respawning.Waves; + #pragma warning disable SA1623 // Property summary documentation should match accessors - using Exiled.Events.EventArgs.Player; using Exiled.Events.EventArgs.Server; using Exiled.Events.Features; @@ -163,9 +164,9 @@ public static class Server /// /// Called after team spawns. /// - /// + /// /// - public static void OnRespawnedTeam(SpawnableTeamType teamType, List hubs) => RespawnedTeam.InvokeSafely(new RespawnedTeamEventArgs(teamType, hubs)); + public static void OnRespawnedTeam(SpawnableWaveBase teamType, List hubs) => RespawnedTeam.InvokeSafely(new RespawnedTeamEventArgs(teamType, hubs)); /// /// Called before adding an unit name. diff --git a/EXILED/Exiled.Events/Patches/Events/Item/ChangingAmmo.cs b/EXILED/Exiled.Events/Patches/Events/Item/ChangingAmmo.cs index 2d020b250..7ef8824da 100644 --- a/EXILED/Exiled.Events/Patches/Events/Item/ChangingAmmo.cs +++ b/EXILED/Exiled.Events/Patches/Events/Item/ChangingAmmo.cs @@ -23,13 +23,15 @@ namespace Exiled.Events.Patches.Events.Item using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Item), nameof(Item.ChangingAmmo))] - [HarmonyPatch(typeof(Firearm), nameof(Firearm.Status), MethodType.Setter)] + + // [HarmonyPatch(typeof(Firearm), nameof(Firearm.Status), MethodType.Setter)] internal static class ChangingAmmo { + /* private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); @@ -137,5 +139,6 @@ private static IEnumerable Transpiler(IEnumerable.Pool.Return(newInstructions); } + */ } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/ReceivingPreference.cs b/EXILED/Exiled.Events/Patches/Events/Item/ReceivingPreference.cs index 1558c49fe..96b9907b3 100644 --- a/EXILED/Exiled.Events/Patches/Events/Item/ReceivingPreference.cs +++ b/EXILED/Exiled.Events/Patches/Events/Item/ReceivingPreference.cs @@ -39,7 +39,8 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldloc_1); + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; LocalBuilder ev = generator.DeclareLocal(typeof(ReceivingPreferenceEventArgs)); LocalBuilder curCode = generator.DeclareLocal(typeof(uint)); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs new file mode 100644 index 000000000..1bf2c9c02 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingChaosEntrance.cs @@ -0,0 +1,84 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Map +{ + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + using System.Text; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Map; + using HarmonyLib; + using Respawning.Announcements; + + using static HarmonyLib.AccessTools; + + /// + /// Patches and + /// to add event. + /// + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] + [HarmonyPatch] + internal static class AnnouncingChaosEntrance + { + private static IEnumerable TargetMethods() + { + yield return Method(typeof(ChaosWaveAnnouncement), nameof(ChaosWaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(ChaosMiniwaveAnnouncement), nameof(ChaosMiniwaveAnnouncement.CreateAnnouncementString)); + } + + private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instruction); + + Label continueLabel = generator.DefineLabel(); + + LocalBuilder ev = generator.DeclareLocal(typeof(AnnouncingChaosEntranceEventArgs)); + + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldloca_S); + + newInstructions.InsertRange(index, new[] + { + // WaveAnnouncementBase + new(OpCodes.Ldarg_0), + + // builder + new(OpCodes.Ldarg_1), + + // new AnnouncingChaosEntranceEventArgs(WaveAnnouncementBase, StringBuilder) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AnnouncingChaosEntranceEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Map.OnAnnouncingChaosEntrance(ev) + new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnAnnouncingChaosEntrance))), + + // if (!ev.IsAllowed) + // builder.Clear(); + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(AnnouncingChaosEntranceEventArgs), nameof(AnnouncingChaosEntranceEventArgs.IsAllowed))), + new(OpCodes.Brtrue_S, continueLabel), + + new(OpCodes.Ldarg_1), + new(OpCodes.Callvirt, Method(typeof(StringBuilder), nameof(StringBuilder.Clear))), + new(OpCodes.Pop), + new(OpCodes.Ret), + + new CodeInstruction(OpCodes.Nop).WithLabels(continueLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs index 558362a9b..f9663ecc7 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/AnnouncingNtfEntrance.cs @@ -8,29 +8,34 @@ namespace Exiled.Events.Patches.Events.Map { using System.Collections.Generic; + using System.Reflection; using System.Reflection.Emit; using System.Text.RegularExpressions; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Map; - using Handlers; - using HarmonyLib; - + using Respawning.Announcements; using Respawning.NamingRules; using static HarmonyLib.AccessTools; /// - /// Patch the . + /// Patch the and . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.AnnouncingNtfEntrance))] - [HarmonyPatch(typeof(NineTailedFoxNamingRule), nameof(NineTailedFoxNamingRule.PlayEntranceAnnouncement))] + [HarmonyPatch] internal static class AnnouncingNtfEntrance { + private static IEnumerable TargetMethods() + { + yield return Method(typeof(NtfWaveAnnouncement), nameof(NtfWaveAnnouncement.CreateAnnouncementString)); + yield return Method(typeof(NtfMiniwaveAnnouncement), nameof(NtfMiniwaveAnnouncement.CreateAnnouncementString)); + } + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); @@ -40,31 +45,21 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Stloc_1) + offset; - - // int scpsLeft = ReferenceHub.GetAllHubs().Values.Count(x => x.characterClassManager.CurRole.team == Team.SCP && x.characterClassManager.CurClass != RoleTypeId.Scp0492); - // string unitNameClear = Regex.Replace(unitName, "<[^>]*?>", string.Empty); - // string[] unitInformation = unitNameClear.Split('-'); - // - // AnnouncingNtfEntranceEventArgs ev = new(scpsLeft, unitInformation[0], int.Parse(unitInformation[1])); - // Map.OnAnnouncingNtfEntrance(ev); - // - // if (!ev.IsAllowed) - // return; - // - // unitName = $"{ev.UnitName}-{ev.UnitNumber}; - // cassieUnitName = this.GetCassieUnitName(unitName); - // scpsLeft = ev.ScpsLeft; + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Stloc_3) + offset; + newInstructions.InsertRange( index, - new[] + new CodeInstruction[] { + // WaveAnnouncementBase + new(OpCodes.Ldarg_0), + // int scpsLeft = ReferenceHub.GetAllHubs().Values.Count(x => x.characterClassManager.CurRole.team == Team.SCP && x.characterClassManager.CurClass != RoleTypeId.Scp0492); - new CodeInstruction(OpCodes.Ldloc_1), + new(OpCodes.Ldloc_3), // string[] unitInformation = unitNameClear.Split('-'); - new(OpCodes.Ldarg_1), + new(OpCodes.Ldloc_1), new(OpCodes.Ldstr, "<[^>]*?>"), new(OpCodes.Ldsfld, Field(typeof(string), nameof(string.Empty))), new(OpCodes.Call, Method(typeof(Regex), nameof(Regex.Replace), new System.Type[] { typeof(string), typeof(string), typeof(string) })), @@ -87,7 +82,6 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Map +{ + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + using System.Text; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Map; + using HarmonyLib; + using Respawning.Announcements; + + using static HarmonyLib.AccessTools; + + /// + /// Patches to prevent cassie from playing empty string. + /// + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingNtfEntrance))] + [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.AnnouncingChaosEntrance))] + [HarmonyPatch(typeof(WaveAnnouncementBase), nameof(WaveAnnouncementBase.PlayAnnouncement))] + internal static class AnnouncingTeamEntrance + { + private static IEnumerable Transpiler(IEnumerable instruction, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instruction); + + Label returnLabel = generator.DefineLabel(); + + int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldsfld); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // if (stringReturn == "") + // return; + new(OpCodes.Ldloc_S, 4), + new(OpCodes.Ldstr, string.Empty), + new(OpCodes.Ceq), + new(OpCodes.Brtrue_S, returnLabel), + }); + + newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/BreakingScp2176.cs b/EXILED/Exiled.Events/Patches/Events/Map/BreakingScp2176.cs index 6707f5b82..8236e2c48 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/BreakingScp2176.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/BreakingScp2176.cs @@ -56,8 +56,8 @@ private static IEnumerable Transpiler(IEnumerable, bool) - new(OpCodes.Newobj, DeclaredConstructor(typeof(ExplodingGrenadeEventArgs), new[] { typeof(Player), typeof(EffectGrenade), typeof(List), typeof(bool) })), + // new ExplodingGrenadeEventArgs(Player, EffectGrenade, HashSet, bool) + new(OpCodes.Newobj, DeclaredConstructor(typeof(ExplodingGrenadeEventArgs), new[] { typeof(Player), typeof(EffectGrenade), typeof(HashSet), typeof(bool) })), new(OpCodes.Dup), // Handlers.Map.OnExplodingGrenade(ev); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs index 3237e5603..4413d1829 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs @@ -12,8 +12,10 @@ namespace Exiled.Events.Patches.Events.Map using API.Features; using API.Features.Pools; + using Exiled.API.Extensions; using Exiled.Events.EventArgs.Map; using Exiled.Events.Patches.Generic; + using Footprinting; using HarmonyLib; using InventorySystem.Items.ThrowableProjectiles; using UnityEngine; @@ -61,15 +63,14 @@ private static IEnumerable Transpiler(IEnumerable targetToAffect = ListPool.Pool.Get(); - foreach (ReferenceHub referenceHub in ReferenceHub.AllHubs) + HashSet targetToAffect = HashSetPool.Pool.Get(); + foreach (Player player in Player.List) { - Player player = Player.Get(referenceHub); - if ((instance.transform.position - referenceHub.transform.position).sqrMagnitude >= distance) + if ((instance.transform.position - player.Position).sqrMagnitude >= distance) continue; - if (!ExiledEvents.Instance.Config.CanFlashbangsAffectThrower && instance.PreviousOwner.SameLife(new(referenceHub))) + if (!ExiledEvents.Instance.Config.CanFlashbangsAffectThrower && instance.PreviousOwner.CompareLife(player.ReferenceHub)) continue; - if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && !instance.PreviousOwner.SameLife(new(referenceHub))) + if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && !instance.PreviousOwner.CompareLife(player.ReferenceHub)) continue; if (Physics.Linecast(instance.transform.position, player.CameraTransform.position, instance._blindingMask)) continue; @@ -79,7 +80,7 @@ private static void ProcessEvent(FlashbangGrenade instance, float distance) ExplodingGrenadeEventArgs explodingGrenadeEvent = new(Player.Get(instance.PreviousOwner.Hub), instance, targetToAffect); - ListPool.Pool.Return(targetToAffect); + HashSetPool.Pool.Return(targetToAffect); Handlers.Map.OnExplodingGrenade(explodingGrenadeEvent); diff --git a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFragGrenade.cs b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFragGrenade.cs index 60faf8a97..37a8bef64 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFragGrenade.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/ExplodingFragGrenade.cs @@ -26,7 +26,7 @@ namespace Exiled.Events.Patches.Events.Map using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.ExplodingGrenade))] diff --git a/EXILED/Exiled.Events/Patches/Events/Map/FillingLocker.cs b/EXILED/Exiled.Events/Patches/Events/Map/FillingLocker.cs index 2ec49178a..0816e0934 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/FillingLocker.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/FillingLocker.cs @@ -37,14 +37,14 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(HashSet), nameof(HashSet.Add), new[] { typeof(ItemPickupBase) }))) + offset; + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(List), nameof(List.Add), new[] { typeof(ItemPickupBase) }))) + offset; newInstructions.InsertRange( index, new[] { // FillingLockerEventArgs ev = new(ItemPickupBase, loockerChamber) - new(OpCodes.Ldloc_S, 4), + new(OpCodes.Ldloc_S, 5), new(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Newobj, GetDeclaredConstructors(typeof(FillingLockerEventArgs))[0]), new(OpCodes.Dup), diff --git a/EXILED/Exiled.Events/Patches/Events/Map/PlacingBlood.cs b/EXILED/Exiled.Events/Patches/Events/Map/PlacingBlood.cs deleted file mode 100644 index f8703fe0b..000000000 --- a/EXILED/Exiled.Events/Patches/Events/Map/PlacingBlood.cs +++ /dev/null @@ -1,110 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) ExMod Team. All rights reserved. -// Licensed under the CC BY-SA 3.0 license. -// -// ----------------------------------------------------------------------- - -namespace Exiled.Events.Patches.Events.Map -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - using API.Features.Pools; - using Exiled.Events.Attributes; - using Exiled.Events.EventArgs.Map; - - using HarmonyLib; - - using InventorySystem.Items.Firearms.Modules; - - using UnityEngine; - - using static HarmonyLib.AccessTools; - - using ExiledEvents = Exiled.Events.Events; - - /// - /// Patches . - /// Adds the event. - /// - [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.PlacingBlood))] - [HarmonyPatch(typeof(StandardHitregBase), nameof(StandardHitregBase.PlaceBloodDecal))] - internal static class PlacingBlood - { - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - List newInstructions = ListPool.Pool.Get(instructions); - - Label returnLabel = generator.DefineLabel(); - - LocalBuilder ev = generator.DeclareLocal(typeof(PlacingBloodEventArgs)); - - // if (!ExiledEvents.Instance.Config.CanSpawnBlood) - // return; - // - // PlacingBloodEventArgs ev = new(Player.Get(this.Hub), Player.Get(target.NetworkId), hit, true); - // - // Handlers.Map.OnPlacingBlood(ev); - // - // if (!ev.IsAllowed) - // return; - // - // hit.point = ev.Position; - newInstructions.InsertRange( - 0, - new[] - { - // if (!ExiledEvents.Instance.Config.CanSpawnBlood) - // return; - new CodeInstruction(OpCodes.Call, PropertyGetter(typeof(ExiledEvents), nameof(ExiledEvents.Instance))), - new(OpCodes.Callvirt, PropertyGetter(typeof(ExiledEvents), nameof(ExiledEvents.Config))), - new(OpCodes.Callvirt, PropertyGetter(typeof(Config), nameof(Config.CanSpawnBlood))), - new(OpCodes.Brfalse_S, returnLabel), - - // Player.Get(this.Hub) - new(OpCodes.Ldarg_0), - new(OpCodes.Callvirt, PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.Hub))), - new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })), - - // Player.Get(target.NetworkId) - new(OpCodes.Ldarg_3), - new(OpCodes.Callvirt, PropertyGetter(typeof(IDestructible), nameof(IDestructible.NetworkId))), - new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(uint) })), - - // hit - new(OpCodes.Ldarg_2), - - // true - new(OpCodes.Ldc_I4_1), - - // PlacingBloodEventArgs ev = new(Player, Player, RaycastHit, bool) - new(OpCodes.Newobj, GetDeclaredConstructors(typeof(PlacingBloodEventArgs))[0]), - new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc_S, ev.LocalIndex), - - // Handlers.Map.OnPlacingBlood(ev) - new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnPlacingBlood))), - - // if (!ev.isAllowed) - // return; - new(OpCodes.Callvirt, PropertyGetter(typeof(PlacingBloodEventArgs), nameof(PlacingBloodEventArgs.IsAllowed))), - new(OpCodes.Brfalse_S, returnLabel), - - // hit.info = ev.Position - new(OpCodes.Ldarga_S, 2), - new(OpCodes.Ldloc_S, ev.LocalIndex), - new(OpCodes.Callvirt, PropertyGetter(typeof(PlacingBloodEventArgs), nameof(PlacingBloodEventArgs.Position))), - new(OpCodes.Callvirt, PropertySetter(typeof(RaycastHit), nameof(RaycastHit.point))), - }); - - newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); - - for (int z = 0; z < newInstructions.Count; z++) - yield return newInstructions[z]; - - ListPool.Pool.Return(newInstructions); - } - } -} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Map/PlacingBulletHole.cs b/EXILED/Exiled.Events/Patches/Events/Map/PlacingBulletHole.cs index fd20be131..16a1b96e8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/PlacingBulletHole.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/PlacingBulletHole.cs @@ -8,19 +8,18 @@ namespace Exiled.Events.Patches.Events.Map { using System.Collections.Generic; + using System.Linq; + using System.Reflection; using System.Reflection.Emit; using API.Features.Pools; - + using Decals; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Map; - using Handlers; - using HarmonyLib; - + using InventorySystem.Items; using InventorySystem.Items.Firearms.Modules; - using UnityEngine; using static HarmonyLib.AccessTools; @@ -28,11 +27,11 @@ namespace Exiled.Events.Patches.Events.Map using Player = API.Features.Player; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Map), nameof(Map.PlacingBulletHole))] - [HarmonyPatch(typeof(StandardHitregBase), nameof(StandardHitregBase.PlaceBulletholeDecal))] + [HarmonyPatch(typeof(ImpactEffectsModule), nameof(ImpactEffectsModule.ServerSendImpactDecal))] internal static class PlacingBulletHole { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -48,15 +47,15 @@ private static IEnumerable Transpiler(IEnumerable x.Name == "Get").First()), // hit new(OpCodes.Ldarg_2), - // PlacingBulletHole ev = new(Player, RaycastHit) + // PlacingBulletHole ev = new(Item, RaycastHit) new(OpCodes.Newobj, GetDeclaredConstructors(typeof(PlacingBulletHoleEventArgs))[0]), new(OpCodes.Dup), new(OpCodes.Dup), diff --git a/EXILED/Exiled.Events/Patches/Events/Map/SpawningTeamVehicle.cs b/EXILED/Exiled.Events/Patches/Events/Map/SpawningTeamVehicle.cs index 7edd27513..08926e5be 100644 --- a/EXILED/Exiled.Events/Patches/Events/Map/SpawningTeamVehicle.cs +++ b/EXILED/Exiled.Events/Patches/Events/Map/SpawningTeamVehicle.cs @@ -21,11 +21,11 @@ namespace Exiled.Events.Patches.Events.Map using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Handlers.Map), nameof(Handlers.Map.SpawningTeamVehicle))] - [HarmonyPatch(typeof(RespawnEffectsController), nameof(RespawnEffectsController.ExecuteAllEffects))] + [HarmonyPatch(typeof(WaveUpdateMessage), nameof(WaveUpdateMessage.ServerSendUpdate))] internal static class SpawningTeamVehicle { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -35,28 +35,30 @@ private static IEnumerable Transpiler(IEnumerable x.opcode == OpCodes.Newobj) + offset; + + newInstructions.InsertRange(index, new[] { + new(OpCodes.Stloc_S, msg.LocalIndex), + // if (type != RespawnEffectsController.EffectType.Selection) // goto continueLabel; - new(OpCodes.Ldarg_0), - new(OpCodes.Ldc_I4_0), - new(OpCodes.Ceq), + new(OpCodes.Ldloca_S, msg.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(WaveUpdateMessage), nameof(WaveUpdateMessage.IsTrigger))), new(OpCodes.Brfalse_S, continueLabel), - // team - new(OpCodes.Ldarg_1), + // wave + new(OpCodes.Ldarg_0), // true new(OpCodes.Ldc_I4_1), - // SpawningTeamVehicleEventArgs ev = new(SpawnableTeamType, bool); + // SpawningTeamVehicleEventArgs ev = new(SpawnableWaveBase, bool); new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SpawningTeamVehicleEventArgs))[0]), new(OpCodes.Dup), - new(OpCodes.Dup), - new(OpCodes.Stloc_S, ev.LocalIndex), // Handlers.Map.OnSpawningTeamVehicle(ev); new(OpCodes.Call, Method(typeof(Handlers.Map), nameof(Handlers.Map.OnSpawningTeamVehicle))), @@ -66,12 +68,7 @@ private static IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Extensions; + using Exiled.API.Features.Pools; + + using Exiled.Events.Attributes; + + using Exiled.Events.EventArgs.Player; + + using Exiled.Events.Handlers; + + using HarmonyLib; + using InventorySystem.Items.Firearms.Modules; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add event. + /// + [EventPatch(typeof(Player), nameof(Player.AimingDownSight))] + [HarmonyPatch(typeof(LinearAdsModule), nameof(LinearAdsModule.ServerProcessCmd))] + internal class Aiming + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder ads = generator.DeclareLocal(typeof(bool)); + + int offset = 0; + int index = newInstructions.FindIndex(x => x.StoresField(Field(typeof(LinearAdsModule), nameof(LinearAdsModule._userInput)))) + offset; + + newInstructions.InsertRange( + index, + new[] + { + // read bool value + new CodeInstruction(OpCodes.Stloc_S, ads.LocalIndex), + + // this.Firearm; + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(LinearAdsModule), nameof(LinearAdsModule.Firearm))), + + // userInput + new(OpCodes.Ldloc_S, ads.LocalIndex), + + // AimingDownSightEventArgs ev = new(firearm, userInput); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(AimingDownSightEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Player.OnAimingDownSight(ev); + new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnAimingDownSight))), + + // loads AdsIn + new(OpCodes.Callvirt, PropertyGetter(typeof(AimingDownSightEventArgs), nameof(AimingDownSightEventArgs.AdsIn))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingDisruptorMode.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingDisruptorMode.cs new file mode 100644 index 000000000..37aa6376b --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingDisruptorMode.cs @@ -0,0 +1,71 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Linq; + using System.Reflection.Emit; + + using Exiled.API.Features.Items; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Player; + using HarmonyLib; + using InventorySystem.Items; + using InventorySystem.Items.Firearms.Modules; + using Mirror; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add event. + /// + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ChangingDisruptorMode))] + [HarmonyPatch(typeof(DisruptorModeSelector), nameof(DisruptorModeSelector.ServerProcessCmd))] + internal static class ChangingDisruptorMode + { + private static IEnumerable Transpiler(IEnumerable instructions) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_0); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // Item.Get(this.Firearm); + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(DisruptorModeSelector), nameof(DisruptorModeSelector.Firearm))), + new(OpCodes.Call, GetDeclaredMethods(typeof(Item)).Find(x => !x.IsGenericMethod && x.GetParameters().FirstOrDefault()?.ParameterType == typeof(ItemBase))), + + // reader.ReadBool(); + new(OpCodes.Ldarg_1), + new(OpCodes.Call, Method(typeof(NetworkReaderExtensions), nameof(NetworkReaderExtensions.ReadBool))), + + // ChangerDisruptorModeEventArgs ev = new(Item.Get(this.Firearm), reader.ReadBool(), true); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingDisruptorModeEventArgs))[0]), + + // Handlers.Player.OnChangingDisruptorMode(ev); + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangingDisruptorMode))), + + // reader.Position--; + new(OpCodes.Ldarg_1), + new(OpCodes.Ldarg_1), + new(OpCodes.Ldfld, Field(typeof(NetworkReader), nameof(NetworkReader.Position))), + new(OpCodes.Ldc_I4_M1), + new(OpCodes.Add), + new(OpCodes.Stfld, Field(typeof(NetworkReader), nameof(NetworkReader.Position))), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingItem.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingItem.cs index 9fa2a4f1b..fa964cad8 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/ChangingItem.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingItem.cs @@ -42,8 +42,8 @@ private static IEnumerable Transpiler(IEnumerable instruction.Calls(Method(typeof(EquipDequipModifierExtensions), nameof(EquipDequipModifierExtensions.CanEquip)))) + offset; + int index = newInstructions.FindIndex( + instruction => instruction.Calls(PropertyGetter(typeof(ItemBase), nameof(ItemBase.AllowEquip)))) + offset; newInstructions.InsertRange( index, diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingMicroHIDState.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingMicroHIDState.cs index f203bf349..c45000b67 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/ChangingMicroHIDState.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingMicroHIDState.cs @@ -8,89 +8,72 @@ namespace Exiled.Events.Patches.Events.Player { using System.Collections.Generic; + using System.Linq; using System.Reflection.Emit; - using API.Features; + using API.Features.Items; using API.Features.Pools; using Exiled.Events.Attributes; using Exiled.Events.EventArgs.Player; - using HarmonyLib; - using InventorySystem.Items.MicroHID; + using InventorySystem.Items.MicroHID.Modules; using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ChangingMicroHIDState))] - [HarmonyPatch(typeof(MicroHIDItem), nameof(MicroHIDItem.ExecuteServerside))] + [HarmonyPatch(typeof(CycleController), nameof(CycleController.Phase), MethodType.Setter)] internal static class ChangingMicroHIDState { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { List newInstructions = ListPool.Pool.Get(instructions); - Label skipLabel = generator.DefineLabel(); - Label continueLabel = generator.DefineLabel(); + Label returnLabel = generator.DefineLabel(); LocalBuilder ev = generator.DeclareLocal(typeof(ChangingMicroHIDStateEventArgs)); - List instructionsToAdd = new() - { - // Player.Get(this.Owner); - new CodeInstruction(OpCodes.Ldarg_0), - new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(MicroHIDItem), nameof(MicroHIDItem.Owner))), - new CodeInstruction(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), - - // this - new CodeInstruction(OpCodes.Ldarg_0), + int offset = 1; + int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Ret) + offset; - // state - new CodeInstruction(OpCodes.Ldloc_0), + newInstructions.InsertRange(index, new[] + { + // Item.Get(this.Serial); + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Ldfld, Field(typeof(CycleController), nameof(CycleController.Serial))), + new(OpCodes.Call, GetDeclaredMethods(typeof(Item)).Find(x => !x.IsGenericMethod && x.IsStatic && x.GetParameters().FirstOrDefault()?.ParameterType == typeof(ushort))), - // this.State - new CodeInstruction(OpCodes.Ldarg_0), - new CodeInstruction(OpCodes.Ldfld, Field(typeof(MicroHIDItem), nameof(MicroHIDItem.State))), + // value + new(OpCodes.Ldarg_1), // true - new CodeInstruction(OpCodes.Ldc_I4_1), + new(OpCodes.Ldc_I4_1), - // ChangingMicroHIDStateEventArgs ev = new(Player, MicroHIDItem, HidState, HidState, bool) - new CodeInstruction(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingMicroHIDStateEventArgs))[0]), - new CodeInstruction(OpCodes.Dup), - new CodeInstruction(OpCodes.Dup), - new CodeInstruction(OpCodes.Stloc_S, ev.LocalIndex), + // ChangerMicroHIDStateEventArgs ev = new(Item.Get(this.Serial), value, true); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingMicroHIDStateEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), // Handlers.Player.OnChangingMicroHIDState(ev); - new CodeInstruction(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangingMicroHIDState))), + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangingMicroHIDState))), // if (!ev.IsAllowed) - // goto skipLabel; - new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(ChangingMicroHIDStateEventArgs), nameof(ChangingMicroHIDStateEventArgs.IsAllowed))), - new CodeInstruction(OpCodes.Brfalse_S, skipLabel), - - // this.State = ev.NewState - new CodeInstruction(OpCodes.Ldarg_0), - new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex), - new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(ChangingMicroHIDStateEventArgs), nameof(ChangingMicroHIDStateEventArgs.NewState))), - new CodeInstruction(OpCodes.Stfld, Field(typeof(MicroHIDItem), nameof(MicroHIDItem.State))), - new CodeInstruction(OpCodes.Br, continueLabel), - - // this.State = state; - new CodeInstruction(OpCodes.Ldarg_0).WithLabels(skipLabel), - new CodeInstruction(OpCodes.Ldloc_0), - new CodeInstruction(OpCodes.Stfld, Field(typeof(MicroHIDItem), nameof(MicroHIDItem.State))), + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingMicroHIDStateEventArgs), nameof(ChangingMicroHIDStateEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, returnLabel), - new CodeInstruction(OpCodes.Nop).WithLabels(continueLabel), - }; - - int offset = 1; + // value = ev.NewPhase; + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingMicroHIDStateEventArgs), nameof(ChangingMicroHIDStateEventArgs.NewPhase))), + new(OpCodes.Starg_S, 1), + }); - foreach (CodeInstruction instruction in newInstructions.FindAll(i => i.StoresField(Field(typeof(MicroHIDItem), nameof(MicroHIDItem.State))))) - newInstructions.InsertRange(newInstructions.IndexOf(instruction) + offset, instructionsToAdd); + newInstructions[newInstructions.Count - 1].labels.Add(returnLabel); for (int z = 0; z < newInstructions.Count; z++) yield return newInstructions[z]; diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ChangingMoveState.cs b/EXILED/Exiled.Events/Patches/Events/Player/ChangingMoveState.cs index b65d6e5c9..5c9879f7c 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/ChangingMoveState.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/ChangingMoveState.cs @@ -58,10 +58,7 @@ private static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable list = new(); + List list = new List(); if (inventory.TryGetBodyArmor(out BodyArmor bodyArmor)) bodyArmor.DontRemoveExcessOnDrop = true; - while (inventory.UserInventory.Items.Count > 0) + HashSet hashSet = HashSetPool.Pool.Get(); + foreach (KeyValuePair item2 in inventory.UserInventory.Items) { - int startCount = inventory.UserInventory.Items.Count; - ushort key = inventory.UserInventory.Items.ElementAt(0).Key; - ItemPickupBase item = inventory.ServerDropItem(key); - - // If the list wasn't changed, we need to manually remove the item to avoid a softlock. - if (startCount == inventory.UserInventory.Items.Count) - inventory.UserInventory.Items.Remove(key); + if (item2.Value is Scp1344Item scp1344Item) + scp1344Item.Status = Scp1344Status.Idle; else - list.Add(item); + hashSet.Add(item2.Key); } + foreach (ushort item in hashSet) + list.Add(inventory.ServerDropItem(item)); + + HashSetPool.Pool.Return(hashSet); InventoryItemProvider.PreviousInventoryPickups[ev.Player.ReferenceHub] = list; } else { while (inventory.UserInventory.Items.Count > 0) - { - int startCount = inventory.UserInventory.Items.Count; - ushort key = inventory.UserInventory.Items.ElementAt(0).Key; - inventory.ServerRemoveItem(key, null); - - // If the list wasn't changed, we need to manually remove the item to avoid a softlock. - if (startCount == inventory.UserInventory.Items.Count) - inventory.UserInventory.Items.Remove(key); - } + inventory.ServerRemoveItem(inventory.UserInventory.Items.ElementAt(0).Key, null); inventory.UserInventory.ReserveAmmo.Clear(); inventory.SendAmmoNextFrame = true; } - foreach (ItemType item in ev.Items) - inventory.ServerAddItem(item); + if (!StartingInventories.DefinedInventories.TryGetValue(ev.NewRole, out InventoryRoleInfo value)) + return; - foreach (KeyValuePair keyValuePair in ev.Ammo) - inventory.ServerAddAmmo(keyValuePair.Key, keyValuePair.Value); + foreach (KeyValuePair item in value.Ammo) + inventory.ServerAddAmmo(item.Key, item.Value); - foreach (KeyValuePair item in inventory.UserInventory.Items) - InventoryItemProvider.OnItemProvided?.Invoke(ev.Player.ReferenceHub, item.Value); + for (int i = 0; i < value.Items.Length; i++) + { + ItemBase arg = inventory.ServerAddItem(value.Items[i], ItemAddReason.StartingItem, 0); + InventoryItemProvider.OnItemProvided?.Invoke(ev.Player.ReferenceHub, arg); + } - InventoryItemProvider.SpawnPreviousInventoryPickups(ev.Player.ReferenceHub); + InventoryItemProvider.InventoriesToReplenish.Enqueue(ev.Player.ReferenceHub); } catch (Exception exception) { @@ -254,4 +240,4 @@ private static void ChangeInventory(ChangingRoleEventArgs ev) } } } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.Events/Patches/Events/Player/DamagingDoor.cs b/EXILED/Exiled.Events/Patches/Events/Player/DamagingDoor.cs index 2d8d52176..2f5135a56 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/DamagingDoor.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/DamagingDoor.cs @@ -24,7 +24,7 @@ namespace Exiled.Events.Patches.Events.Player using static HarmonyLib.AccessTools; /// - /// Patch the . + /// Patch the . /// Adds the event. /// [EventPatch(typeof(Player), nameof(Player.DamagingDoor))] diff --git a/EXILED/Exiled.Events/Patches/Events/Player/DamagingWindow.cs b/EXILED/Exiled.Events/Patches/Events/Player/DamagingWindow.cs index df26d055b..097127383 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/DamagingWindow.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/DamagingWindow.cs @@ -25,9 +25,9 @@ namespace Exiled.Events.Patches.Events.Player /// /// Patch the . - /// Adds the event. + /// Adds the event. /// - [EventPatch(typeof(Player), nameof(Player.PlayerDamageWindow))] + [EventPatch(typeof(Player), nameof(Player.DamagingWindow))] [HarmonyPatch(typeof(BreakableWindow), nameof(BreakableWindow.Damage))] internal static class DamagingWindow { @@ -62,7 +62,7 @@ private static IEnumerable Transpiler(IEnumerable +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ +#pragma warning disable SA1402 +#pragma warning disable SA1600 +#pragma warning disable SA1649 + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + + using Exiled.API.Extensions; + using Exiled.API.Features.Pools; + + using Exiled.Events.Attributes; + + using Exiled.Events.EventArgs.Player; + + using Exiled.Events.Handlers; + + using HarmonyLib; + + using InventorySystem.Items.Firearms; + using InventorySystem.Items.Firearms.Modules; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add event for automatic firearms. + /// + [EventPatch(typeof(Player), nameof(Player.DryfiringWeapon))] + [HarmonyPatch(typeof(AutomaticActionModule), nameof(AutomaticActionModule.UpdateServer))] + internal class DryFireAutomatic + { + internal static IEnumerable GetInstructions(CodeInstruction start, Label ret) + { + // this.Firearm + yield return new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(start); + yield return new(OpCodes.Callvirt, PropertyGetter(typeof(FirearmSubcomponentBase), nameof(FirearmSubcomponentBase.Firearm))); + + // DryfiringWeaponEventArgs ev = new(firearm); + yield return new(OpCodes.Newobj, GetDeclaredConstructors(typeof(DryfiringWeaponEventArgs))[0]); + yield return new(OpCodes.Dup); + + // Handlers.Player.OnDryfiringWeapon(ev); + yield return new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnDryfiringWeapon))); + + // if (!ev.IsAllowed) + // return; + yield return new(OpCodes.Callvirt, PropertyGetter(typeof(DryfiringWeaponEventArgs), nameof(DryfiringWeaponEventArgs.IsAllowed))); + yield return new(OpCodes.Brfalse_S, ret); + } + + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + // for returning we will goto ServerSendResponse method, it is necessarily + int offset = -3; + Label ret = newInstructions[newInstructions.Count - 1 + offset].labels[0]; + + offset = -2; + int index = newInstructions.FindIndex(x => x.Calls(PropertyGetter(typeof(AutomaticActionModule), nameof(AutomaticActionModule.Cocked)))) + offset; + + newInstructions.InsertRange(index, GetInstructions(newInstructions[index], ret)); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches + /// to add event for double shots. + /// + [EventPatch(typeof(Player), nameof(Player.DryfiringWeapon))] + [HarmonyPatch(typeof(DoubleActionModule), nameof(DoubleActionModule.FireDry))] + internal class DryFireDouble + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label ret = generator.DefineLabel(); + + newInstructions.InsertRange(0, DryFireAutomatic.GetInstructions(newInstructions[0], ret)); + + newInstructions[newInstructions.Count - 1].labels.Add(ret); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } + + /// + /// Patches + /// to add event for double shots. + /// + [EventPatch(typeof(Player), nameof(Player.DryfiringWeapon))] + [HarmonyPatch(typeof(PumpActionModule), nameof(PumpActionModule.ShootOneBarrel))] + internal class DryFirePump + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label ret = generator.DefineLabel(); + + int offset = -7; + int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Stloc_1) + offset; + + // firstly, set `flag` to a false, and then if `IsAllowed == false` we could return without problems + newInstructions.InsertRange(index, new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldc_I4_0), + new(OpCodes.Stloc_1), + }.Concat(DryFireAutomatic.GetInstructions(newInstructions[0], ret))); + + // place return label to a ldloc instruction, to return `flag` variables + newInstructions[newInstructions.Count - 2].labels.Add(ret); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Emotion.cs b/EXILED/Exiled.Events/Patches/Events/Player/Emotion.cs new file mode 100644 index 000000000..a7d447569 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Player/Emotion.cs @@ -0,0 +1,87 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Player; + using HarmonyLib; + using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event and + /// event. + /// + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ChangingEmotion))] + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ChangedEmotion))] + [HarmonyPatch(typeof(EmotionSync), nameof(EmotionSync.ServerSetEmotionPreset))] + internal static class Emotion + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label ret = generator.DefineLabel(); + LocalBuilder ev = generator.DeclareLocal(typeof(ChangingEmotionEventArgs)); + + int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Ldsfld); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // ChangingEmotionEventArgs ev = new(hub, preset, EmotionSync.GetEmotionPreset(hub), true); + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Ldarg_1), + new(OpCodes.Ldarg_0), + new(OpCodes.Call, Method(typeof(EmotionSync), nameof(EmotionSync.GetEmotionPreset))), + new(OpCodes.Ldc_I4_1), + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingEmotionEventArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev), + + // Handlers.Player.OnChangingEmotion(ev); + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangingEmotion))), + + // if (!ev.IsAllowed) + // return; + new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingEmotionEventArgs), nameof(ChangingEmotionEventArgs.IsAllowed))), + new(OpCodes.Brfalse, ret), + + // preset = ev.EmotionPresetTypeNew + new(OpCodes.Ldloc_S, ev), + new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingEmotionEventArgs), nameof(ChangingEmotionEventArgs.NewEmotionPresetType))), + new(OpCodes.Starg_S, 1), + }); + + newInstructions.InsertRange(newInstructions.Count - 1, new CodeInstruction[] + { + // ChangedEmotionEventArgs ev = new(hub, EmotionSync.GetEmotionPreset(hub)); + new CodeInstruction(OpCodes.Ldarg_0), + new(OpCodes.Ldarg_0), + new(OpCodes.Call, Method(typeof(EmotionSync), nameof(EmotionSync.GetEmotionPreset))), + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangedEmotionEventArgs))[0]), + + // Handlers.Player.OnChangedEmotion(ev); + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangedEmotion))), + }); + + newInstructions[newInstructions.Count - 1].labels.Add(ret); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} diff --git a/EXILED/Exiled.Events/Patches/Events/Player/EnteringKillerCollision.cs b/EXILED/Exiled.Events/Patches/Events/Player/EnteringKillerCollision.cs index 9ecb86df8..59259d210 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/EnteringKillerCollision.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/EnteringKillerCollision.cs @@ -19,11 +19,11 @@ namespace Exiled.Events.Patches.Events.Player using static HarmonyLib.AccessTools; /// - /// Patches . + /// Patches . /// Adds the event. /// [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.EnteringKillerCollision))] - [HarmonyPatch(typeof(CheckpointKiller), nameof(CheckpointKiller.OnTriggerEnter))] + [HarmonyPatch(typeof(PitKiller), nameof(PitKiller.OnTriggerEnter))] internal static class EnteringKillerCollision { private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -32,8 +32,7 @@ private static IEnumerable Transpiler(IEnumerable instruction.opcode == OpCodes.Newobj) + offset; + int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldarg_0); newInstructions.InsertRange( index, diff --git a/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs b/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs index 9bf3bb35f..c078ac2dc 100644 --- a/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs +++ b/EXILED/Exiled.Events/Patches/Events/Player/EscapingAndEscaped.cs @@ -10,10 +10,7 @@ namespace Exiled.Events.Patches.Events.Player #pragma warning disable SA1402 // File may only contain a single type #pragma warning disable IDE0060 - using System; using System.Collections.Generic; - using System.Linq; - using System.Reflection; using System.Reflection.Emit; using API.Enums; @@ -24,7 +21,6 @@ namespace Exiled.Events.Patches.Events.Player using Exiled.Events.Attributes; using HarmonyLib; using PlayerRoles.FirstPersonControl; - using Respawning; using static HarmonyLib.AccessTools; @@ -40,7 +36,6 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - List [EventPatch(typeof(Scp914), nameof(Scp914.UpgradingPlayer))] @@ -36,27 +36,21 @@ private static IEnumerable Transpiler(IEnumerable newInstructions = ListPool.Pool.Get(instructions); - // Find override position - const int offset = -3; - int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(FpcExtensionMethods), nameof(FpcExtensionMethods.TryOverridePosition)))) + offset; - Label returnLabel = generator.DefineLabel(); LocalBuilder curSetting = generator.DeclareLocal(typeof(Scp914KnobSetting)); LocalBuilder ev = generator.DeclareLocal(typeof(UpgradingPlayerEventArgs)); - // Move labels from override - 3 position (Right after a branch) - List internal void CheckUpdate() { - using HttpClient client = CreateHttpClient(); - if (Busy = FindUpdate(client, !File.Exists(Path.Combine(Paths.Dependencies, "Exiled.API.dll")), out NewVersion newVersion)) - Update(client, newVersion); + try + { + using HttpClient client = CreateHttpClient(); + if (Busy = FindUpdate(client, !PluginAPI.Loader.AssemblyLoader.Dependencies.Exists(x => x.GetName().Name == "Exiled.API"), out NewVersion newVersion)) + Update(client, newVersion); + } + catch (Exception e) + { + Log.Error(e); + } } /// @@ -144,6 +152,7 @@ private bool FindUpdate(HttpClient client, bool forced, out NewVersion newVersio { try { + Thread.Sleep(5000); // Wait for the assemblies to load ExiledLib smallestVersion = ExiledLib.Min(); Log.Info($"Found the smallest version of Exiled - {smallestVersion.Library.GetName().Name}:{smallestVersion.Version}"); diff --git a/EXILED/Exiled.Permissions/Extensions/Permissions.cs b/EXILED/Exiled.Permissions/Extensions/Permissions.cs index 6d5708bf3..b03271b4b 100644 --- a/EXILED/Exiled.Permissions/Extensions/Permissions.cs +++ b/EXILED/Exiled.Permissions/Extensions/Permissions.cs @@ -21,7 +21,7 @@ namespace Exiled.Permissions.Extensions using Features; using Properties; - + using Query; using RemoteAdmin; using YamlDotNet.Core; @@ -176,7 +176,7 @@ public static bool CheckPermission(this CommandSender sender, string permission) { return true; } - else if (sender is PlayerCommandSender || sender is UserPrint) + else if (sender is PlayerCommandSender || sender is QueryCommandSender) { if (Player.Get(sender.SenderId) is not Player player) return false; diff --git a/EXILED/Exiled/Exiled.nuspec b/EXILED/Exiled/Exiled.nuspec index abb547bd1..388d8ae0e 100644 --- a/EXILED/Exiled/Exiled.nuspec +++ b/EXILED/Exiled/Exiled.nuspec @@ -7,7 +7,7 @@ $version$ ExMod-Team ExMod-Team - Copyright © Exiled Official 2024 - $year$ + Copyright © ExMod Team 2024 - $year$ false https://github.com/ExMod-Team/EXILED/blob/master/LICENSE diff --git a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md index 819221096..d08dbef3d 100644 --- a/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md +++ b/EXILED/docs/articles/SCPSLRessources/NW_Documentation.md @@ -25,28 +25,33 @@ Last Update (13.5.0.1) - [Damage Handlers](#damagehandlers) - [AchievementName](#achievementname) - [ActionCategory](#actioncategory) -- [ActionModuleResponse](#actionmoduleresponse) - [ActionName](#actionname) - [Activity](#activity) - [AdminFlags](#adminflags) - [AlphaPanelOperations](#alphapaneloperations) +- [AnimItemLayer3p](#animitemlayer3p) +- [AnimState3p](#animstate3p) - [AttachmentDescriptiveAdvantages](#attachmentdescriptiveadvantages) - [AttachmentDescriptiveDownsides](#attachmentdescriptivedownsides) - [AttachmentEditorsTranslation](#attachmenteditorstranslation) - [AttachmentName](#attachmentname) - [AttachmentParam](#attachmentparam) +- [AttachmentParamState](#attachmentparamstate) - [AttachmentSlot](#attachmentslot) +- [AttachmentStatus](#attachmentstatus) - [AttackResult](#attackresult) - [AttackType](#attacktype) - [AttackType](#attacktype) -- [AudioMixerChannelType](#audiomixerchanneltype) - [AuthenticationResponseFlags](#authenticationresponseflags) +- [Authorization](#authorization) - [AutoHideType](#autohidetype) +- [AutosyncInstantiationStatus](#autosyncinstantiationstatus) - [BadgePreferences](#badgepreferences) - [BadgeVisibilityPreferences](#badgevisibilitypreferences) - [BanType](#bantype) - [BlockedInteraction](#blockedinteraction) - [BroadcastFlags](#broadcastflags) +- [BuoyancyMode](#buoyancymode) - [CallType](#calltype) - [CandyKindID](#candykindid) - [CassieAnnouncementType](#cassieannouncementtype) @@ -54,15 +59,19 @@ Last Update (13.5.0.1) - [CentralAuthPreauthFlags](#centralauthpreauthflags) - [ChallengeState](#challengestate) - [ChallengeType](#challengetype) +- [ChamberState](#chamberstate) - [CheckpointErrorType](#checkpointerrortype) - [CheckpointSequenceStage](#checkpointsequencestage) +- [ClientFlags](#clientflags) - [ClientInstanceMode](#clientinstancemode) +- [ClientReceivedContentType](#clientreceivedcontenttype) - [ClientSwitchState](#clientswitchstate) - [ClientType](#clienttype) - [CloudState](#cloudstate) - [CmdTeleportData](#cmdteleportdata) - [CollectionDeserializeToBehaviour](#collectiondeserializetobehaviour) - [CollisionsDisablingReasons](#collisionsdisablingreasons) +- [ColorMode](#colormode) - [CommandOperationMode](#commandoperationmode) - [Condition](#condition) - [ConfigShare](#configshare) @@ -72,7 +81,6 @@ Last Update (13.5.0.1) - [ConnectRequestResult](#connectrequestresult) - [ConsoleLogType](#consolelogtype) - [ConsumeError](#consumeerror) -- [CurrentAction](#currentaction) - [CursorOverrideMode](#cursoroverridemode) - [DataType](#datatype) - [DebugLevel](#debuglevel) @@ -91,26 +99,35 @@ Last Update (13.5.0.1) - [DoorDamageType](#doordamagetype) - [DoorLockMode](#doorlockmode) - [DoorLockReason](#doorlockreason) +- [DropdownEntryType](#dropdownentrytype) - [DtoaMode](#dtoamode) - [EffectClassification](#effectclassification) -- [EffectType](#effecttype) - [ElevatorGroup](#elevatorgroup) - [ElevatorSequence](#elevatorsequence) +- [EmotionBlendshape](#emotionblendshape) +- [EmotionPresetType](#emotionpresettype) - [EncryptedChannel](#encryptedchannel) - [Entry](#entry) - [EscapeScenarioType](#escapescenariotype) - [EType](#etype) +- [ExampleId](#exampleid) +- [ExampleId](#exampleid) +- [ExampleId](#exampleid) +- [ExplosionType](#explosiontype) - [FacilityZone](#facilityzone) - [Faction](#faction) - [FailReason](#failreason) - [FalloffType](#fallofftype) - [FastDtoaMode](#fastdtoamode) - [FilmmakerBlendPreset](#filmmakerblendpreset) -- [FirearmAudioFlags](#firearmaudioflags) -- [FirearmStatusFlags](#firearmstatusflags) +- [FirearmAnim](#firearmanim) +- [FirearmCategory](#firearmcategory) +- [FirearmWorldmodelType](#firearmworldmodeltype) +- [FiringState](#firingstate) - [Flags](#flags) - [Flags](#flags) - [FogType](#fogtype) +- [FoldoutMode](#foldoutmode) - [FootstepLoudness](#footsteploudness) - [FpcViewMode](#fpcviewmode) - [FreezingMode](#freezingmode) @@ -136,11 +153,15 @@ Last Update (13.5.0.1) - [HotkeysTranslation](#hotkeystranslation) - [HttpQueryMode](#httpquerymode) - [IcomText](#icomtext) +- [IconType](#icontype) - [IndicatorType](#indicatortype) - [InputActivationMode](#inputactivationmode) - [IntercomState](#intercomstate) +- [InventoryGuiAction](#inventoryguiaction) +- [InventoryGuiTranslation](#inventoryguitranslation) - [InvisibilityFlags](#invisibilityflags) - [IPAddressType](#ipaddresstype) +- [ItemAddReason](#itemaddreason) - [ItemCategory](#itemcategory) - [ItemDescriptionType](#itemdescriptiontype) - [ItemTierFlags](#itemtierflags) @@ -155,12 +176,20 @@ Last Update (13.5.0.1) - [LocalAddrType](#localaddrtype) - [LoggingState](#loggingstate) - [MainBoolsSettings](#mainboolssettings) +- [MapGenerationPhase](#mapgenerationphase) - [MappingLifetime](#mappinglifetime) +- [MessageHeader](#messageheader) +- [MessageHeader](#messageheader) - [MessageImportance](#messageimportance) +- [MessageType](#messagetype) +- [MessageType](#messagetype) - [MiscControlsSetting](#misccontrolssetting) - [MiscPrivacySetting](#miscprivacysetting) - [MiscVideoSetting](#miscvideosetting) +- [MixerChannel](#mixerchannel) - [Mode](#mode) +- [Mode](#mode) +- [ModifierMode](#modifiermode) - [Modules](#modules) - [NatAddressType](#nataddresstype) - [NetLogLevel](#netloglevel) @@ -175,6 +204,7 @@ Last Update (13.5.0.1) - [OpusCtlGetRequest](#opusctlgetrequest) - [OpusCtlSetRequest](#opusctlsetrequest) - [OpusStatusCode](#opusstatuscode) +- [OtherCondition](#othercondition) - [OutputCodes](#outputcodes) - [PacketProperty](#packetproperty) - [ParameterMixingMode](#parametermixingmode) @@ -188,6 +218,7 @@ Last Update (13.5.0.1) - [PlayerMovementState](#playermovementstate) - [PlayerPermissions](#playerpermissions) - [PlayerSorting](#playersorting) +- [PopupState](#popupstate) - [PortMapper](#portmapper) - [PrimitiveFlags](#primitiveflags) - [ProcessCreationFlags](#processcreationflags) @@ -195,22 +226,29 @@ Last Update (13.5.0.1) - [RadioCommand](#radiocommand) - [RadioRangeLevel](#radiorangelevel) - [RejectionReason](#rejectionreason) +- [RemoteAdminResponseFlags](#remoteadminresponseflags) +- [RemovalMode](#removalmode) - [ReproProjectAssetType](#reproprojectassettype) - [RequestType](#requesttype) -- [RequestType](#requesttype) -- [RespawnSequencePhase](#respawnsequencephase) +- [RespawnSetting](#respawnsetting) - [ResurrectError](#resurrecterror) - [RoleChangeReason](#rolechangereason) - [RoleSpawnFlags](#rolespawnflags) - [RoleTypeId](#roletypeid) - [RoomName](#roomname) - [RoomShape](#roomshape) -- [RoomType](#roomtype) +- [RootCullablePriority](#rootcullablepriority) - [RoundRestartType](#roundrestarttype) +- [RpcHeader](#rpcheader) - [RpcStateMsg](#rpcstatemsg) - [RpcType](#rpctype) - [RpcType](#rpctype) - [RpcType](#rpctype) +- [RpcType](#rpctype) +- [RpcType](#rpctype) +- [RpcType](#rpctype) +- [RpcType](#rpctype) +- [RpcType](#rpctype) - [ScanSequenceStep](#scansequencestep) - [Scp0492SoundId](#scp0492soundid) - [Scp079HudTranslation](#scp079hudtranslation) @@ -218,6 +256,7 @@ Last Update (13.5.0.1) - [Scp096HitResult](#scp096hitresult) - [Scp096HudTranslation](#scp096hudtranslation) - [Scp096RageState](#scp096ragestate) +- [Scp1344Status](#scp1344status) - [Scp173SoundId](#scp173soundid) - [Scp244State](#scp244state) - [Scp3114HudTranslation](#scp3114hudtranslation) @@ -231,25 +270,34 @@ Last Update (13.5.0.1) - [SecurityLevel](#securitylevel) - [SensitivitySetting](#sensitivitysetting) - [ServerLogType](#serverlogtype) +- [ServerOperativeSystem](#serveroperativesystem) - [ServerRateLimit](#serverratelimit) +- [ServerReceivedContentType](#serverreceivedcontenttype) - [ServerShutdownState](#servershutdownstate) +- [ServerType](#servertype) - [SettingType](#settingtype) - [ShutdownResult](#shutdownresult) +- [SpawnableRoomConnectorType](#spawnableroomconnectortype) - [SpawnableTeamType](#spawnableteamtype) - [SpectatableListElementType](#spectatablelistelementtype) - [SpectatorSpawnReason](#spectatorspawnreason) - [States](#states) - [StatusType](#statustype) +- [SteamLobbyPrivacy](#steamlobbyprivacy) +- [StorageLocation](#storagelocation) - [StructureType](#structuretype) - [SubtitleType](#subtitletype) +- [SyncDataFlags](#syncdataflags) - [SyncMode](#syncmode) - [TargetButton](#targetbutton) - [Team](#team) -- [ThirdpersonItemAnimationName](#thirdpersonitemanimationname) - [TrackerMessage](#trackermessage) -- [TriggerState](#triggerstate) +- [TransitionStatus](#transitionstatus) +- [TurnStatus](#turnstatus) - [UISetting](#uisetting) - [UnconnectedMessageType](#unconnectedmessagetype) +- [UpdateMessageFlags](#updatemessageflags) +- [UserResponseMode](#userresponsemode) - [ValidationError](#validationerror) - [ValidationError](#validationerror) - [ValidationError](#validationerror) @@ -262,6 +310,10 @@ Last Update (13.5.0.1) - [VoiceChatSupportMode](#voicechatsupportmode) - [VoiceLinesName](#voicelinesname) - [VolumeSliderSetting](#volumeslidersetting) +- [WarheadScenarioType](#warheadscenariotype) +- [WaveQueueState](#wavequeuestate) +- [WearableElements](#wearableelements) +- [WearableSlot](#wearableslot) - [WorkstationStatus](#workstationstatus) ### AchievementName @@ -302,6 +354,24 @@ Last Update (13.5.0.1) [30] = IllPassThanks [31] = Overcurrent [32] = PropertyOfChaos + [33] = Overtime + [34] = RuleBreaker + [35] = CompleteTheMission + [36] = ArmyOfOne + [37] = LMGG + [38] = OnSpeakingTerms + [39] = HatsOffToYou + [40] = Hawkeye + [41] = AmnesticAmbush + [42] = AfterlifeCommunicator + [43] = TheEnemyOfMyEnemy + [44] = SignalLost + [45] = ThinkFast + [46] = TrilateralTermination + [47] = MutuallyAssuredDestruction + [48] = UndeadSpaceProgram + [49] = ArizonaRanger + [50] = Matador ``` @@ -322,18 +392,6 @@ Last Update (13.5.0.1) -### ActionModuleResponse - -
InventorySystem.Items.Firearms.Modules.ActionModuleResponse - -``` - [0] = Idle - [1] = Shoot - [2] = Dry -``` - -
- ### ActionName
ActionName @@ -360,7 +418,7 @@ Last Update (13.5.0.1) [18] = Noclip [19] = GameConsole [21] = InspectItem - [22] = RevolverCockHammer + [22] = WeaponAlt [23] = ThrowItem [27] = HideGUI [28] = NoClipFogToggle @@ -413,6 +471,37 @@ Last Update (13.5.0.1)
+### AnimItemLayer3p + +
InventorySystem.Items.Thirdperson.AnimItemLayer3p + +``` + [0] = Left + [1] = Right + [2] = Middle + [3] = Additive + [4] = PreMovement +``` + +
+ +### AnimState3p + +
InventorySystem.Items.Thirdperson.AnimState3p + +``` + [0] = Override0 + [1] = Override1 + [2] = Override2 + [3] = Additive0 + [4] = Additive1 + [5] = Additive2 + [6] = RunForward + [7] = SprintForward +``` + +
+ ### AttachmentDescriptiveAdvantages
InventorySystem.Items.Firearms.Attachments.AttachmentDescriptiveAdvantages @@ -423,6 +512,7 @@ Last Update (13.5.0.1) [4] = AmmoCounter [8] = FlashSuppression [16] = NightVision + [32] = ShotgunShells ```
@@ -434,6 +524,7 @@ Last Update (13.5.0.1) ``` [0] = None [2] = Laser + [4] = NoHeadshots ``` @@ -547,6 +638,21 @@ Last Update (13.5.0.1) [19] = AmmoConsumptionMultiplier [20] = ReloadSpeedMultiplier [21] = PreventReload + [22] = RunningInaccuracyMultiplier + [23] = DoubleActionSpeedMultiplier +``` + + + +### AttachmentParamState + +
InventorySystem.Items.Firearms.Attachments.AttachmentParamState + +``` + [0] = Disabled + [2] = UserInterface + [4] = SilentlyActive + [6] = ActiveAndDisplayed ```
@@ -569,6 +675,19 @@ Last Update (13.5.0.1) +### AttachmentStatus + +
InventorySystem.Items.Firearms.Extensions.ConditionalEvaluator+AttachmentStatus + +``` + [0] = Disabled + [1] = Enabled + [2] = EnabledAndReady + [3] = EnabledAndNotReady +``` + +
+ ### AttackResult
PlayerRoles.PlayableScps.Subroutines.AttackResult @@ -607,29 +726,27 @@ Last Update (13.5.0.1)
-### AudioMixerChannelType +### AuthenticationResponseFlags -
AudioPooling.AudioMixerChannelType +
CentralAuth.AuthenticationResponseFunctions+AuthenticationResponseFlags ``` - [0] = DefaultSfx - [1] = Interface - [2] = Weapons - [3] = VoiceChat - [4] = NoDucking + [1] = AuthToken + [2] = BadgeToken + [4] = DoNotTrack + [8] = HideBadge ```
-### AuthenticationResponseFlags +### Authorization -
CentralAuth.AuthenticationResponseFunctions+AuthenticationResponseFlags +
InventorySystem.Items.Firearms.Modules.IReloadUnloadValidatorModule+Authorization ``` - [1] = AuthToken - [2] = BadgeToken - [4] = DoNotTrack - [8] = HideBadge + [0] = Idle + [1] = Allowed + [2] = Vetoed ```
@@ -646,6 +763,19 @@ Last Update (13.5.0.1)
+### AutosyncInstantiationStatus + +
InventorySystem.Items.Autosync.AutosyncInstantiationStatus + +``` + [0] = Unspecified + [1] = Template + [2] = InventoryInstance + [3] = SimulatedInstance +``` + +
+ ### BadgePreferences
ServerRoles+BadgePreferences @@ -693,6 +823,7 @@ Last Update (13.5.0.1) [8] = GrabItems [16] = ItemPrimaryAction [48] = ItemUsage + [64] = UndisarmPlayers [255] = All ``` @@ -710,6 +841,21 @@ Last Update (13.5.0.1)
+### BuoyancyMode + +
WaterPhysics.BuoyancyMode + +``` + [0] = SuperHeavy + [1] = NonBuoyant + [2] = ShortTimeFloaters + [3] = LongTimeFloaters + [4] = Floater + [5] = SuperLight +``` + +
+ ### CallType
LiteNetLib.Utils.NetSerializer+CallType @@ -806,6 +952,18 @@ Last Update (13.5.0.1)
+### ChamberState + +
InventorySystem.Items.Firearms.Modules.CylinderAmmoModule+ChamberState + +``` + [0] = Empty + [1] = Live + [2] = Discharged +``` + +
+ ### CheckpointErrorType
Interactables.Interobjects.CheckpointDoor+CheckpointErrorType @@ -831,6 +989,22 @@ Last Update (13.5.0.1)
+### ClientFlags + +
Query.QueryHandshake+ClientFlags + +``` + [0] = None + [1] = SuppressRaResponses + [2] = SubscribeServerConsole + [4] = SubscribeServerLogs + [8] = RemoteAdminMetadata + [16] = RestrictPermissions + [32] = SpecifyLogUsername +``` + +
+ ### ClientInstanceMode
CentralAuth.ClientInstanceMode @@ -840,6 +1014,22 @@ Last Update (13.5.0.1) [1] = ReadyClient [2] = Host [3] = DedicatedServer + [4] = Dummy +``` + +
+ +### ClientReceivedContentType + +
Query.QueryMessage+ClientReceivedContentType + +``` + [0] = ConsoleString + [1] = CommandException + [2] = QueryMessage + [3] = RemoteAdminSerializedResponse + [4] = RemoteAdminPlaintextResponse + [5] = RemoteAdminUnsuccessfulPlaintextResponse ```
@@ -912,6 +1102,18 @@ Last Update (13.5.0.1)
+### ColorMode + +
InventorySystem.Drawers.AlertContent+ColorMode + +``` + [0] = White + [1] = Role + [2] = Accented +``` + +
+ ### CommandOperationMode
Misc+CommandOperationMode @@ -1037,18 +1239,6 @@ Last Update (13.5.0.1)
-### CurrentAction - -
InventorySystem.Items.Firearms.Modules.TubularMagazineAmmoManager+CurrentAction - -``` - [0] = Idle - [1] = Reloading - [2] = Unloading -``` - -
- ### CursorOverrideMode
CursorManagement.CursorOverrideMode @@ -1122,6 +1312,7 @@ Last Update (13.5.0.1) [1] = Bullet [2] = Blood [3] = Buckshot + [4] = GlassCrack ```
@@ -1286,6 +1477,7 @@ Last Update (13.5.0.1) [4] = Grenade [8] = Weapon [16] = Scp096 + [32] = ParticleDisruptor ``` @@ -1323,6 +1515,20 @@ Last Update (13.5.0.1) +### DropdownEntryType + +
UserSettings.ServerSpecific.SSDropdownSetting+DropdownEntryType + +``` + [0] = Regular + [1] = Scrollable + [2] = ScrollableLoop + [3] = Hybrid + [4] = HybridLoop +``` + +
+ ### DtoaMode
Utf8Json.Internal.DoubleConversion.DoubleToStringConverter+DtoaMode @@ -1346,20 +1552,9 @@ Last Update (13.5.0.1)
-### EffectType - -
Respawning.RespawnEffectsController+EffectType - -``` - [0] = Selection - [1] = UponRespawn -``` - -
- ### ElevatorGroup -
Interactables.Interobjects.ElevatorManager+ElevatorGroup +
Interactables.Interobjects.ElevatorGroup ``` [0] = GateA @@ -1368,8 +1563,9 @@ Last Update (13.5.0.1) [3] = LczA02 [4] = LczB01 [5] = LczB02 - [6] = Nuke + [6] = Nuke01 [7] = Scp049 + [8] = Nuke02 ```
@@ -1388,6 +1584,54 @@ Last Update (13.5.0.1)
+### EmotionBlendshape + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.EmotionBlendshape + +``` + [0] = Undefined + [1] = Frown + [2] = BrowRaise + [3] = EyeTapLeft + [4] = EyeTapRight + [5] = EyeCloseLeft + [6] = EyeCloseRight + [7] = EyeOpenLeft + [8] = EyeOpenRight + [9] = EyesBottom + [10] = Worried + [11] = MouthOpen + [12] = JawDrop + [13] = Grin + [14] = SmileOpen + [15] = Disgusted + [16] = Angry + [17] = LipsTop + [18] = LipsNormalBottom + [19] = LipsStretchBottom + [20] = Ogre + [21] = Chad + [22] = MixClosedEyes +``` + +
+ +### EmotionPresetType + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.EmotionPresetType + +``` + [0] = Neutral + [1] = Happy + [2] = AwkwardSmile + [3] = Scared + [4] = Angry + [5] = Chad + [6] = Ogre +``` + +
+ ### EncryptedChannel
EncryptedChannelManager+EncryptedChannel @@ -1443,6 +1687,77 @@ Last Update (13.5.0.1)
+### ExampleId + +
UserSettings.ServerSpecific.Examples.SSAbilitiesExample+ExampleId + +``` + [0] = SpeedBoostKey + [1] = SpeedBoostToggle + [2] = HealAlly +``` + +
+ +### ExampleId + +
UserSettings.ServerSpecific.Examples.SSLightSpawnerExample+ExampleId + +``` + [0] = IntensitySlider + [1] = RangeSlider + [2] = ColorPresetDropdown + [3] = CustomColor + [4] = ColorInfo + [5] = ShadowType + [6] = ShadowStrength + [7] = LightType + [8] = LightShape + [9] = SpotAngle + [10] = InnerSpotAngle + [11] = ConfirmButton + [12] = DestroyAllButton +``` + +
+ +### ExampleId + +
UserSettings.ServerSpecific.Examples.SSPrimitiveSpawnerExample+ExampleId + +``` + [0] = ConfirmButton + [1] = DestroyAllButton + [2] = TypeDropdown + [3] = ColorPresetDropdown + [4] = ColorField + [5] = ColorAlphaSlider + [6] = CollisionsToggle + [7] = RendererToggle + [8] = ColorInfo + [9] = ScaleSliderX + [10] = ScaleSliderY + [11] = ScaleSliderZ +``` + +
+ +### ExplosionType + +
ExplosionType + +``` + [0] = Grenade + [1] = SCP018 + [2] = PinkCandy + [3] = Cola + [4] = Disruptor + [5] = Jailbird + [6] = Custom +``` + +
+ ### FacilityZone
MapGeneration.FacilityZone @@ -1523,30 +1838,54 @@ Last Update (13.5.0.1)
-### FirearmAudioFlags +### FirearmAnim -
InventorySystem.Items.Firearms.FirearmAudioFlags +
InventorySystem.Items.Firearms.Thirdperson.FirearmThirdpersonItem+FirearmAnim ``` - [0] = None - [2] = ScaleDistance - [4] = IsGunshot - [8] = SendToPlayers - [16] = UseDedicatedAudioChannel + [0] = Ads + [1] = Hip + [2] = Reload ```
-### FirearmStatusFlags +### FirearmCategory -
InventorySystem.Items.Firearms.FirearmStatusFlags +
InventorySystem.Items.Firearms.FirearmCategory + +``` + [0] = Unclassified + [1] = Pistol + [2] = Revolver + [3] = SubmachineGun + [4] = Rifle + [5] = LightMachineGun + [6] = Shotgun +``` + +
+ +### FirearmWorldmodelType + +
InventorySystem.Items.Firearms.FirearmWorldmodelType + +``` + [0] = Pickup + [1] = Thirdperson + [2] = Presentation +``` + +
+ +### FiringState + +
InventorySystem.Items.Firearms.Modules.DisruptorActionModule+FiringState ``` [0] = None - [2] = Cocked - [4] = MagazineInserted - [8] = FlashlightEnabled - [16] = Chambered + [1] = FiringRapid + [2] = FiringSingle ```
@@ -1598,6 +1937,20 @@ Last Update (13.5.0.1)
+### FoldoutMode + +
UserSettings.ServerSpecific.SSTextArea+FoldoutMode + +``` + [0] = NotCollapsable + [1] = CollapseOnEntry + [2] = ExtendOnEntry + [3] = CollapsedByDefault + [4] = ExtendedByDefault +``` + +
+ ### FootstepLoudness
PlayerRoles.FirstPersonControl.Thirdperson.AnimatedCharacterModel+FootstepLoudness @@ -1975,6 +2328,20 @@ Last Update (13.5.0.1)
+### IconType + +
InventorySystem.Items.Firearms.Extensions.DisruptorDualCamExtension+IconType + +``` + [0] = None + [1] = DesintegratorMode + [2] = BurstMode + [3] = CriticalWarn + [4] = CrashWarn +``` + +
+ ### IndicatorType
PlayerRoles.PlayableScps.Scp079.Map.Scp079TeammateIndicators+IndicatorType @@ -2012,6 +2379,52 @@ Last Update (13.5.0.1)
+### InventoryGuiAction + +
InventorySystem.GUI.InventoryGuiAction + +``` + [0] = None + [1] = Drop + [2] = Select +``` + +
+ +### InventoryGuiTranslation + +
InventorySystem.GUI.InventoryGuiTranslation + +``` + [0] = FirearmAmmo + [1] = FirearmDamage + [2] = FirearmFireRate + [3] = FirearmHipAcc + [4] = FirearmAdsAcc + [5] = Weight + [6] = Length + [7] = DropAmmo + [8] = ArmorHelmetEfficacy + [9] = ArmorVestEfficacy + [10] = ArmorStaminaUsage + [11] = ArmorMovementSpeed + [12] = ArmorItemLimits + [13] = ArmorAmmoLimits + [14] = ArmorTotal + [15] = ArmorPenetration + [16] = RunningInaccuracy + [17] = MarshmallowCackleHint + [18] = RemainingCharge + [19] = RemainingAmmo + [20] = MicroHidPrimaryHint + [21] = MicroHidSecondaryHint + [22] = DisruptorToggleModeHint + [23] = JailbirdAttackHint + [24] = JailbirdChargeHint +``` + +
+ ### InvisibilityFlags
PlayerRoles.Visibility.InvisibilityFlags @@ -2039,6 +2452,21 @@ Last Update (13.5.0.1)
+### ItemAddReason + +
InventorySystem.Items.ItemAddReason + +``` + [0] = Undefined + [1] = PickedUp + [2] = AdminCommand + [3] = StartingItem + [4] = Scp914Upgrade + [5] = StatusEffect +``` + +
+ ### ItemCategory
ItemCategory @@ -2051,7 +2479,7 @@ Last Update (13.5.0.1) [4] = Firearm [5] = Grenade [6] = SCPItem - [7] = MicroHID + [7] = SpecialWeapon [8] = Ammo [9] = Armor ``` @@ -2146,6 +2574,7 @@ Last Update (13.5.0.1) [52] = GunFRMG0 [53] = GunA7 [54] = Lantern + [55] = SCP1344 [-1] = None ``` @@ -2315,6 +2744,21 @@ Last Update (13.5.0.1)
+### MapGenerationPhase + +
MapGeneration.MapGenerationPhase + +``` + [0] = ParentRoomRegistration + [1] = RelativePositioningWaypoints + [2] = ComplexDecorationsAndClutter + [3] = SimpleDecorations + [4] = CullingCaching + [5] = SpawnableStructures +``` + +
+ ### MappingLifetime
LiteNetLib4Mirror.Open.Nat.MappingLifetime @@ -2328,6 +2772,35 @@ Last Update (13.5.0.1)
+### MessageHeader + +
InventorySystem.Items.Firearms.Modules.AnimatorReloaderModuleBase+MessageHeader + +``` + [0] = Custom + [1] = Reload + [2] = Unload + [3] = Stop + [4] = RequestRejected +``` + +
+ +### MessageHeader + +
InventorySystem.Items.Firearms.Modules.AutomaticActionModule+MessageHeader + +``` + [0] = CmdShoot + [1] = RpcPublicSync + [2] = RpcResponse + [3] = RpcFire + [4] = RpcDryFire + [5] = RpcNewPlayerSync +``` + +
+ ### MessageImportance
MessageImportance @@ -2341,6 +2814,40 @@ Last Update (13.5.0.1)
+### MessageType + +
InventorySystem.Items.Firearms.Modules.DisruptorActionModule+MessageType + +``` + [0] = RpcRequireReloadTrue + [1] = RpcRequireReloadFalse + [2] = RpcRequireReloadFullResync + [3] = RpcStartFiring + [4] = RpcOnShot + [5] = CmdRequestStartFiring + [6] = CmdConfirmDischarge +``` + +
+ +### MessageType + +
InventorySystem.Items.Firearms.Modules.DoubleActionModule+MessageType + +``` + [0] = RpcNewPlayerResync + [1] = RpcSetCockedTrue + [2] = RpcSetCockedFalse + [3] = RpcFire + [4] = RpcDryFire + [5] = CmdUpdatePulling + [6] = CmdShoot + [7] = StartPulling + [8] = StartCocking +``` + +
+ ### MiscControlsSetting
UserSettings.ControlsSettings.MiscControlsSetting @@ -2383,6 +2890,32 @@ Last Update (13.5.0.1) [1] = ExplosionShake [2] = HeadBobbing [3] = FlashbangDarkMode + [4] = ShowNeedles +``` + +
+ +### MixerChannel + +
AudioPooling.MixerChannel + +``` + [0] = DefaultSfx + [1] = Interface + [2] = Weapons + [3] = VoiceChat + [4] = NoDucking +``` + +
+ +### Mode + +
InventorySystem.Items.Firearms.Extensions.ViewmodelReloadOnlyLayerExtension+Mode + +``` + [0] = DuringReloadsAndUnloads + [1] = OutsideReloadsAndUnloads ```
@@ -2392,13 +2925,26 @@ Last Update (13.5.0.1)
InventorySystem.Items.Autosync.AutosyncRpc+Mode ``` - [0] = Local + [0] = SpecificClient [1] = AllClients [2] = Conditional ```
+### ModifierMode + +
InventorySystem.Items.Firearms.Modules.Misc.StatModifier+ModifierMode + +``` + [0] = Inactive + [1] = Add + [2] = Multiply + [3] = Override +``` + +
+ ### Modules
ServerLogs+Modules @@ -2409,9 +2955,12 @@ Last Update (13.5.0.1) [2] = ClassChange [3] = Permissions [4] = Administrative - [5] = Logger + [5] = GameLogic [6] = DataAccess [7] = Detector + [8] = Throwable + [9] = Door + [10] = Elevator ```
@@ -2603,6 +3152,19 @@ Last Update (13.5.0.1)
+### OtherCondition + +
InventorySystem.Items.Firearms.Extensions.ConditionalEvaluator+OtherCondition + +``` + [0] = Equipped + [1] = Firstperson + [2] = Pickup + [3] = Thirdperson +``` + +
+ ### OutputCodes
ServerOutput.OutputCodes @@ -2695,6 +3257,8 @@ Last Update (13.5.0.1) [5] = AOQuality [6] = BloodDecalsEnabled [7] = BulletDecalsEnabled + [8] = BloodDecalsLimit + [9] = BulletDecalsLimits ```
@@ -2818,6 +3382,7 @@ Last Update (13.5.0.1) [67108864] = Effects [134217728] = FriendlyFireDetectorImmunity [268435456] = FriendlyFireDetectorTempDisable + [536870912] = ServerLogLiveFeed ``` @@ -2835,6 +3400,19 @@ Last Update (13.5.0.1) +### PopupState + +
Interactables.Interobjects.PopupInterobject+PopupState + +``` + [0] = Off + [1] = Enabling + [2] = On + [3] = Disabling +``` + +
+ ### PortMapper
LiteNetLib4Mirror.Open.Nat.PortMapper @@ -2953,6 +3531,28 @@ Last Update (13.5.0.1)
+### RemoteAdminResponseFlags + +
RemoteAdminResponse+RemoteAdminResponseFlags + +``` + [1] = Successful + [2] = LogInConsole +``` + +
+ +### RemovalMode + +
InventorySystem.Items.Firearms.Extensions.WorldmodelMagazineExtension+RemovalMode + +``` + [0] = DeactivateObject + [1] = SetScaleZero +``` + +
+ ### ReproProjectAssetType
ReproProjectAssetType @@ -2979,33 +3579,13 @@ Last Update (13.5.0.1)
-### RequestType - -
InventorySystem.Items.Firearms.BasicMessages.RequestType - -``` - [0] = Unload - [1] = Reload - [2] = AdsIn - [3] = AdsOut - [4] = Dryfire - [5] = ToggleFlashlight - [6] = ReloadStop - [7] = RequestStatuses - [8] = Inspect -``` - -
- -### RespawnSequencePhase +### RespawnSetting -
Respawning.RespawnManager+RespawnSequencePhase +
Respawning.Graphics.RespawnSetting ``` - [0] = RespawnCooldown - [1] = SelectingTeam - [2] = PlayingEntryAnimations - [3] = SpawningSelectedTeam + [0] = RespawnInterfaceVisible + [1] = ObjectiveFeedVisible ```
@@ -3039,6 +3619,7 @@ Last Update (13.5.0.1) [6] = Revived [7] = RemoteAdmin [8] = Destroyed + [9] = RespawnMiniwave ```
@@ -3085,6 +3666,7 @@ Last Update (13.5.0.1) [21] = Overwatch [22] = Filmmaker [23] = Scp3114 + [24] = Destroyed [-1] = None ``` @@ -3152,17 +3734,14 @@ Last Update (13.5.0.1) -### RoomType +### RootCullablePriority -
MapGeneration.ImageGenerator+RoomType +
ProgressiveCulling.RootCullablePriority ``` - [0] = Straight - [1] = Curve - [2] = RoomT - [3] = Cross - [4] = Endoff - [5] = Prison + [0] = PreCull + [1] = Rooms + [2] = Dynamic ```
@@ -3179,6 +3758,17 @@ Last Update (13.5.0.1)
+### RpcHeader + +
InventorySystem.Items.Firearms.Modules.AnimationToggleableReloaderModule+RpcHeader + +``` + [0] = SyncLoadable + [1] = Cancel +``` + +
+ ### RpcStateMsg
PlayerRoles.PlayableScps.Scp939.Mimicry.MimicPointController+RpcStateMsg @@ -3218,6 +3808,18 @@ Last Update (13.5.0.1) ### RpcType +
PlayerRoles.PlayableScps.Scp106.Scp106StalkAbility+RpcType + +``` + [0] = StalkActive + [1] = StalkInactive + [2] = NotEnoughVigor +``` + +
+ +### RpcType +
InventorySystem.Items.MarshmallowMan.MarshmallowItem+RpcType ``` @@ -3228,6 +3830,57 @@ Last Update (13.5.0.1)
+### RpcType + +
InventorySystem.Items.Firearms.Modules.EventBasedEquipperModule+RpcType + +``` + [0] = SeedSync + [1] = FirstTimeTrue + [2] = FirstTimeFalse + [3] = ResyncAllFirstTime +``` + +
+ +### RpcType + +
InventorySystem.Items.Firearms.Modules.ImpactEffectsModule+RpcType + +``` + [0] = ImpactDecal + [1] = TracerDefault + [2] = TracerOverride + [3] = PlayerHit +``` + +
+ +### RpcType + +
InventorySystem.Items.Firearms.Modules.PumpActionModule+RpcType + +``` + [0] = ResyncOne + [1] = ResyncAll + [2] = Shoot + [3] = SchedulePump +``` + +
+ +### RpcType + +
InventorySystem.Items.Firearms.Attachments.FlashlightAttachment+RpcType + +``` + [0] = Enabled + [1] = Disabled + [2] = FullResync +``` + +
+ ### ScanSequenceStep
PlayerRoles.PlayableScps.Scp079.Scp079ScannerSequence+ScanSequenceStep @@ -3412,6 +4065,24 @@ Last Update (13.5.0.1)
+### Scp1344Status + +
InventorySystem.Items.Usables.Scp1344.Scp1344Status + +``` + [0] = Idle + [1] = Equipping + [2] = Activating + [3] = Stabbing + [4] = Active + [5] = Dropping + [6] = Deactivating + [7] = CancelingDeactivation + [8] = Inspecting +``` + +
+ ### Scp173SoundId
PlayerRoles.PlayableScps.Scp173.Scp173AudioPlayer+Scp173SoundId @@ -3630,10 +4301,22 @@ Last Update (13.5.0.1) [3] = KillLog [4] = GameEvent [5] = InternalMessage - [6] = RateLimit + [6] = AuthRateLimit [7] = Teamkill [8] = Suicide [9] = AdminChat + [10] = Query +``` + +
+ +### ServerOperativeSystem + +
Steam.ServerOperativeSystem + +``` + [108] = Linux + [119] = Windows ```
@@ -3649,6 +4332,16 @@ Last Update (13.5.0.1)
+### ServerReceivedContentType + +
Query.QueryMessage+ServerReceivedContentType + +``` + [0] = Command +``` + +
+ ### ServerShutdownState
ServerShutdown+ServerShutdownState @@ -3662,6 +4355,18 @@ Last Update (13.5.0.1)
+### ServerType + +
Steam.ServerType + +``` + [100] = Dedicated + [108] = Listen + [112] = SourceTV +``` + +
+ ### SettingType
UserSettings.GUIElements.UserSettingDependency+Dependency+SettingType @@ -3686,6 +4391,31 @@ Last Update (13.5.0.1)
+### SpawnableRoomConnectorType + +
MapGeneration.RoomConnectors.SpawnableRoomConnectorType + +``` + [0] = None + [1] = EzStandardDoor + [2] = HczStandardDoor + [3] = LczStandardDoor + [4] = HczOneSidedWall + [5] = HczTwoSidedWall + [6] = OpenHallway + [7] = OpenHallwayClutterA + [8] = OpenHallwayClutterB + [9] = OpenHallwayClutterC + [10] = OpenHallwayConstructA + [11] = HczBulkDoor + [12] = OpenHallwayClutterD + [13] = OpenHallwayClutterE + [14] = OpenHallwayClutterF + [15] = OpenHallwayClutterG +``` + +
+ ### SpawnableTeamType
Respawning.SpawnableTeamType @@ -3748,6 +4478,30 @@ Last Update (13.5.0.1)
+### SteamLobbyPrivacy + +
UserSettings.OtherSettings.SteamLobbyPrivacy + +``` + [0] = Private + [1] = Friends + [2] = Public +``` + +
+ +### StorageLocation + +
FavoriteAndHistory+StorageLocation + +``` + [0] = History + [1] = Favorites + [2] = IPHistory +``` + +
+ ### StructureType
MapGeneration.Distributors.StructureType @@ -3759,6 +4513,7 @@ Last Update (13.5.0.1) [3] = Scp079Generator [4] = SmallWallCabinet [5] = Workstation + [6] = ExperimentalWeaponLocker ```
@@ -3802,6 +4557,23 @@ Last Update (13.5.0.1) +### SyncDataFlags + +
InventorySystem.Items.Firearms.Modules.AutomaticActionModule+SyncDataFlags + +``` + [0] = None + [1] = AmmoChamberedBit0 + [2] = AmmoChamberedBit1 + [4] = AmmoChamberedBit2 + [8] = AmmoChamberedBit3 + [15] = AmmoChamberedFilter + [16] = Cocked + [32] = BoltLocked +``` + +
+ ### SyncMode
PlayerStatsSystem.SyncedStatBase+SyncMode @@ -3846,31 +4618,6 @@ Last Update (13.5.0.1)
-### ThirdpersonItemAnimationName - -
InventorySystem.Items.Thirdperson.ThirdpersonItemAnimationName - -``` - [0] = Override0 - [1] = Override1 - [2] = Override2 - [3] = IdlePoseAdditive - [4] = SprintLeftAdditive - [5] = SprintRightAdditive - [6] = SprintStraightAdditive - [7] = SprintBackAdditive - [8] = WalkLeftAdditive - [9] = WalkRightAdditive - [10] = WalkStraightAdditive - [11] = WalkBackAdditive - [12] = PrimaryAdditive - [13] = SecAdditive0 - [14] = SecAdditive1 - [15] = SecAdditive2 -``` - -
- ### TrackerMessage
PlayerRoles.PlayableScps.Scp079.Scp079ScannerSequence+TrackerMessage @@ -3885,14 +4632,26 @@ Last Update (13.5.0.1)
-### TriggerState +### TransitionStatus + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.InventorySubcontroller+TransitionStatus + +``` + [0] = RetractingPrevious + [1] = EquippingNew + [2] = Done +``` + +
+ +### TurnStatus -
InventorySystem.Items.Firearms.Modules.DoubleAction+TriggerState +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.IdlePoseRetainerSubcontroller+TurnStatus ``` - [0] = Released - [1] = Pulling - [2] = SearLock + [0] = Idle + [1] = TurningRight + [2] = TurningLeft ```
@@ -3909,6 +4668,8 @@ Last Update (13.5.0.1) [4] = HideIP [5] = FlashTaskbar [6] = PhotosensitivityDoNotShow + [7] = ImperialUnits + [8] = InaccuracyAsDispersion ```
@@ -3924,6 +4685,33 @@ Last Update (13.5.0.1) +### UpdateMessageFlags + +
Respawning.UpdateMessageFlags + +``` + [0] = None + [1] = Timer + [2] = Pause + [4] = Trigger + [8] = Tokens + [11] = All +``` + +
+ +### UserResponseMode + +
UserSettings.ServerSpecific.ServerSpecificSettingBase+UserResponseMode + +``` + [0] = None + [1] = ChangeOnly + [2] = AcquisitionAndChange +``` + +
+ ### ValidationError
PlayerRoles.PlayableScps.Scp079.Scp079BlackoutRoomAbility+ValidationError @@ -4095,6 +4883,54 @@ Last Update (13.5.0.1)
+### WarheadScenarioType + +
WarheadScenarioType + +``` + [0] = Start + [1] = Resume + [2] = DeadmanSwitch +``` + +
+ +### WaveQueueState + +
Respawning.WaveManager+WaveQueueState + +``` + [0] = Idle + [1] = WaveSelected + [2] = WaveSpawning +``` + +
+ +### WearableElements + +
PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.WearableElements + +``` + [0] = None + [1] = Scp268Hat + [2] = Scp1344Goggles +``` + +
+ +### WearableSlot + +
InventorySystem.Items.WearableSlot + +``` + [0] = Body + [1] = Eyes + [2] = Hat +``` + +
+ ### WorkstationStatus
InventorySystem.Items.Firearms.Attachments.WorkstationController+WorkstationStatus @@ -4148,6 +4984,7 @@ Last Update (13.5.0.1) | 21 | Overwatch | Dead | None | Draw | | 22 | Filmmaker | Dead | None | Draw | | 23 | Scp3114 | SCPs | Scp | Anomalies | +| 24 | Destroyed | Dead | None | Draw | ```