diff --git a/EXILED/Exiled.API/Enums/DamageType.cs b/EXILED/Exiled.API/Enums/DamageType.cs index 9aec9fc64..4fe1976d6 100644 --- a/EXILED/Exiled.API/Enums/DamageType.cs +++ b/EXILED/Exiled.API/Enums/DamageType.cs @@ -249,5 +249,21 @@ public enum DamageType /// Damage caused by the marshmallow man. /// Marshmallow, + + /// + /// Generic damage. No CASSIE message will be sent. + /// + Silent, + + /// + /// Damage caused by Spicy Flame. + /// + /// + SpicyFlame, + + /// + /// Damage caused by Metal Pipe. + /// + MetalPipe, } } diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 61b4a43d7..d44edec10 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,9 +216,13 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - [Obsolete("Not functional in-game")] Marshmallow, + /// + /// Makes you metal. + /// + Metal, + /// /// The effect that is given to the player when getting attacked by SCP-3114's Strangle ability. /// diff --git a/EXILED/Exiled.API/Enums/PrefabType.cs b/EXILED/Exiled.API/Enums/PrefabType.cs index fbcd3dcbf..c661f3248 100644 --- a/EXILED/Exiled.API/Enums/PrefabType.cs +++ b/EXILED/Exiled.API/Enums/PrefabType.cs @@ -273,5 +273,11 @@ public enum PrefabType [Prefab(3721192489, "Scp3114_Ragdoll")] Scp3114Ragdoll, + + [Prefab(1891631329, "PrismaticCloud")] + PrismaticCloud, + + [Prefab(2157375951, "TantrumObj (Brown Candy)")] + TantrumBrownCandy } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs index c8f0975ac..69459c105 100644 --- a/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs +++ b/EXILED/Exiled.API/Extensions/DamageTypeExtensions.cs @@ -26,7 +26,7 @@ public static class DamageTypeExtensions { DeathTranslations.Bleeding.Id, DamageType.Bleeding }, { DeathTranslations.Crushed.Id, DamageType.Crushed }, { DeathTranslations.Decontamination.Id, DamageType.Decontamination }, - { DeathTranslations.Explosion.Id, DamageType.Explosion }, + { DeathTranslations.Explosion.Id, DamageType.SpicyFlame }, { DeathTranslations.Falldown.Id, DamageType.Falldown }, { DeathTranslations.Poisoned.Id, DamageType.Poison }, { DeathTranslations.Recontained.Id, DamageType.Recontainment }, @@ -49,6 +49,7 @@ public static class DamageTypeExtensions { DeathTranslations.MicroHID.Id, DamageType.MicroHid }, { DeathTranslations.Hypothermia.Id, DamageType.Hypothermia }, { DeathTranslations.MarshmallowMan.Id, DamageType.Marshmallow }, + { DeathTranslations.MetalPipe.Id, DamageType.MetalPipe }, }; private static readonly Dictionary TranslationConversionInternal = new() @@ -57,7 +58,7 @@ public static class DamageTypeExtensions { DeathTranslations.Bleeding, DamageType.Bleeding }, { DeathTranslations.Crushed, DamageType.Crushed }, { DeathTranslations.Decontamination, DamageType.Decontamination }, - { DeathTranslations.Explosion, DamageType.Explosion }, + { DeathTranslations.Explosion, DamageType.SpicyFlame }, { DeathTranslations.Falldown, DamageType.Falldown }, { DeathTranslations.Poisoned, DamageType.Poison }, { DeathTranslations.Recontained, DamageType.Recontainment }, @@ -80,6 +81,7 @@ public static class DamageTypeExtensions { DeathTranslations.MicroHID, DamageType.MicroHid }, { DeathTranslations.Hypothermia, DamageType.Hypothermia }, { DeathTranslations.MarshmallowMan, DamageType.Marshmallow }, + { DeathTranslations.MetalPipe, DamageType.MetalPipe }, }; private static readonly Dictionary ItemConversionInternal = new() @@ -162,6 +164,10 @@ public static DamageType GetDamageType(DamageHandlerBase damageHandlerBase) { switch (damageHandlerBase) { + case SilentDamageHandler: + return DamageType.Silent; + case MetalPipeDamageHandler: + return DamageType.MetalPipe; case CustomReasonDamageHandler: return DamageType.Custom; case WarheadDamageHandler: diff --git a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs index 209515d9c..3a4843273 100644 --- a/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs +++ b/EXILED/Exiled.API/Extensions/EffectTypeExtension.cs @@ -67,13 +67,12 @@ public static class EffectTypeExtension { EffectType.AntiScp207, typeof(AntiScp207) }, { EffectType.Scanned, typeof(Scanned) }, { EffectType.SilentWalk, typeof(SilentWalk) }, -#pragma warning disable CS0618 { EffectType.Marshmallow, typeof(MarshmallowEffect) }, -#pragma warning restore CS0618 { EffectType.Strangled, typeof(Strangled) }, { EffectType.Ghostly, typeof(Ghostly) }, { EffectType.FogControl, typeof(FogControl) }, { EffectType.Slowness, typeof(Slowness) }, + { EffectType.Metal, typeof(Metal) }, { EffectType.OrangeCandy, typeof(OrangeCandy) }, { EffectType.Prismatic, typeof(Prismatic) }, { EffectType.SlowMetabolism, typeof(SlowMetabolism) }, diff --git a/EXILED/Exiled.API/Features/CustomHealthStat.cs b/EXILED/Exiled.API/Features/CustomHealthStat.cs index 9cd59ae56..dbe99a948 100644 --- a/EXILED/Exiled.API/Features/CustomHealthStat.cs +++ b/EXILED/Exiled.API/Features/CustomHealthStat.cs @@ -14,12 +14,29 @@ namespace Exiled.API.Features /// public class CustomHealthStat : HealthStat { + private float customMaxValue; + /// public override float MaxValue => CustomMaxValue == default ? base.MaxValue : CustomMaxValue; /// /// Gets or sets the maximum amount of health the player will have. /// - public float CustomMaxValue { get; set; } + public float CustomMaxValue + { + get + { + if (Hub.playerStats.TryGetModule(out MaxHealthStat maxHealthStat)) + return maxHealthStat.CurValue; + return customMaxValue; + } + + set + { + customMaxValue = value; + if (Hub.playerStats.TryGetModule(out MaxHealthStat maxHealthStat)) + maxHealthStat.CurValue = value; + } + } } } \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs index c4eed3f05..842642c9c 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/DamageHandlerBase.cs @@ -98,6 +98,10 @@ public virtual DamageType Type switch (Base) { + case SilentDamageHandler: + return DamageType.Silent; + case MetalPipeDamageHandler: + return DamageType.MetalPipe; case CustomReasonDamageHandler: return DamageType.Custom; case WarheadDamageHandler: diff --git a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs index 56c6ad282..10bd84e88 100644 --- a/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs +++ b/EXILED/Exiled.API/Features/DamageHandlers/GenericDamageHandler.cs @@ -62,6 +62,15 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage switch (damageType) { + case DamageType.Silent: + Base = new SilentDamageHandler() + { + Damage = damage, + }; + break; + case DamageType.MetalPipe: + Base = new MetalPipeDamageHandler(attacker.ReferenceHub, Damage); + break; case DamageType.Falldown: Base = new UniversalDamageHandler(damage, DeathTranslations.Falldown, cassieAnnouncement); break; @@ -113,6 +122,7 @@ public GenericDamageHandler(Player player, Player attacker, float damage, Damage Base = new MicroHidDamageHandler(microHidOwner, damage); break; case DamageType.Explosion: + case DamageType.SpicyFlame: Base = new ExplosionDamageHandler(attacker.Footprint, UnityEngine.Vector3.zero, damage, 0); break; case DamageType.Firearm: diff --git a/EXILED/Exiled.API/Features/Hazards/Hazard.cs b/EXILED/Exiled.API/Features/Hazards/Hazard.cs index 09bd880d3..7493a40e3 100644 --- a/EXILED/Exiled.API/Features/Hazards/Hazard.cs +++ b/EXILED/Exiled.API/Features/Hazards/Hazard.cs @@ -125,6 +125,7 @@ public static Hazard Get(EnvironmentalHazard environmentalHazard) => TantrumEnvironmentalHazard tantrumEnvironmentalHazard => new TantrumHazard(tantrumEnvironmentalHazard), Scp939AmnesticCloudInstance scp939AmnesticCloudInstance => new AmnesticCloudHazard(scp939AmnesticCloudInstance), SinkholeEnvironmentalHazard sinkholeEnvironmentalHazard => new SinkholeHazard(sinkholeEnvironmentalHazard), + PrismaticCloud prismaticCloud => new PrismaticCloudHazard(prismaticCloud), global::Hazards.TemporaryHazard temporaryHazard => new TemporaryHazard(temporaryHazard), _ => new Hazard(environmentalHazard) }; diff --git a/EXILED/Exiled.API/Features/Hazards/PrismaticCloudHazard.cs b/EXILED/Exiled.API/Features/Hazards/PrismaticCloudHazard.cs new file mode 100644 index 000000000..b66563670 --- /dev/null +++ b/EXILED/Exiled.API/Features/Hazards/PrismaticCloudHazard.cs @@ -0,0 +1,108 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Hazards +{ + using System.Collections.Generic; + using System.Linq; + + using Exiled.API.Enums; + using global::Hazards; + using Mirror; + using RelativePositioning; + using UnityEngine; + + /// + /// A wrapper for . + /// + public class PrismaticCloudHazard : TemporaryHazard + { + /// + /// Initializes a new instance of the class. + /// + /// The instance. + public PrismaticCloudHazard(PrismaticCloud hazard) + : base(hazard) + { + Base = hazard; + } + + /// + /// Gets the . + /// + public new PrismaticCloud Base { get; } + + /// + public override HazardType Type => HazardType.Tantrum; + + /// + /// Gets the decay speed. + /// + public float DecaySpeed => Base.DecaySpeed; + + /// + /// Gets distance of explode. + /// + public float ExplodeDistance => Base._explodeDistance; + + /// + /// Gets or sets the ignored targets. + /// + public IEnumerable IgnoredTargets + { + get => Base.IgnoredTargets.Select(Player.Get); + set => Base.IgnoredTargets = value.Select(x => x.ReferenceHub).ToList(); + } + + /// + /// Gets or sets the synced position. + /// + public RelativePosition SynchronisedPosition + { + get => Base.SynchronizedPosition; + set => Base.SynchronizedPosition = value; + } + + /// + /// Gets or sets the correct position of tantrum hazard. + /// + public Transform CorrectPosition + { + get => Base._correctPosition; + set => Base._correctPosition = value; + } + + /// + /// Places a Prismatic (Halloween's ability) in the indicated position. + /// + /// The position where you want to spawn the Tantrum. + /// Whether or not 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 PrismaticCloudHazard PlaceTantrum(Vector3 position, bool isActive = true) + { + PrismaticCloud prismatic = Object.Instantiate(PrefabHelper.GetPrefab(PrefabType.PrismaticCloud)); + + if (!isActive) + prismatic.SynchronizedPosition = new(position); + else + prismatic.SynchronizedPosition = new(position + (Vector3.up * 0.25f)); + + prismatic._destroyed = !isActive; + + NetworkServer.Spawn(prismatic.gameObject); + + return Get(prismatic); + } + + /// + /// Enables effects for target. + /// + /// Target to affect. + public void EnableEffects(Player player) => Base.ServerEnableEffect(player.ReferenceHub); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs b/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs index 906bd4faf..dae3ec889 100644 --- a/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs +++ b/EXILED/Exiled.API/Features/Hazards/TantrumHazard.cs @@ -10,6 +10,7 @@ namespace Exiled.API.Features.Hazards using Exiled.API.Enums; using global::Hazards; using Mirror; + using PlayerRoles; using RelativePositioning; using UnityEngine; @@ -61,6 +62,11 @@ public bool PlaySizzle set => Base.PlaySizzle = value; } + /// + /// Gets the teams that will be affected by the tantrum. + /// + public Team[] TargetedTeams => Base._targetedTeams; + /// /// Gets or sets the synced position. /// diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 96d02257f..12a54f643 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -283,6 +283,7 @@ ItemType.KeycardGuard or ItemType.KeycardJanitor or ItemType.KeycardO5 or ItemTy ItemType.SCP2176 => new Scp2176(owner), ItemType.SCP1576 => new Scp1576(), ItemType.Jailbird => new Jailbird(), + ItemType.Marshmallow => new Marshmallow(), _ => new Item(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs new file mode 100644 index 000000000..f713a2cde --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Marshmallow.cs @@ -0,0 +1,68 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled 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.MarshmallowMan; + + /// + /// A wrapper for . + /// + public class Marshmallow : Item, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// A instance. + public Marshmallow(MarshmallowItem itemBase) + : base(itemBase) + { + Base = itemBase; + } + + /// + /// Initializes a new instance of the class. + /// + internal Marshmallow() + : this((MarshmallowItem)Server.Host.Inventory.CreateItemInstance(new(ItemType.Marshmallow, 0), false)) + { + } + + /// + public new MarshmallowItem Base { get; } + + /// + /// Gets or sets a value indicating whether the evil mode is enabled. + /// + public bool EvilMode + { + get => Base.EvilMode; + set + { + Base.EvilMode = value; + + if (value) + ReleaseEvil(); + } + } + + /// + /// Gets or sets the attack cooldown. + /// + public float AttackCooldown + { + get => Base._attackCooldown; + set => Base._attackCooldown = value; + } + + /// + /// Releases the evil mode. + /// + public void ReleaseEvil() => Base.ReleaseEvil(); + } +} \ No newline at end of file diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs index d0b31f391..5e14862a5 100644 --- a/EXILED/Exiled.API/Features/Map.cs +++ b/EXILED/Exiled.API/Features/Map.cs @@ -49,6 +49,7 @@ public static class Map internal static readonly List TeleportsValue = new(8); private static AmbientSoundPlayer ambientSoundPlayer; + private static SkyboxHubert skyboxHubert; private static SqueakSpawner squeakSpawner; @@ -62,6 +63,22 @@ public static class Map /// public static Scp939AmnesticCloudInstance AmnesticCloudPrefab => AmnesticCloudHazard.AmnesticCloudPrefab; // TODO: Remove this. + /// + /// Gets the Hubert Sky prefab. + /// + public static SkyboxHubert SkyboxHubert + { + get + { + if (skyboxHubert == null) + { + skyboxHubert = Object.FindObjectOfType(); + } + + return skyboxHubert; + } + } + /// /// Gets a value indicating whether decontamination has begun in the light containment zone. /// @@ -128,6 +145,15 @@ public static bool IsDecontaminationEnabled /// public static SqueakSpawner SqueakSpawner => squeakSpawner ??= Object.FindObjectOfType(); + /// + /// Gets or sets a value indicating whether the hubert sky is enabled. + /// + public static bool IsHubertSky + { + get => SkyboxHubert.Hubert; + set => SkyboxHubert.NetworkHubert = value; + } + /// /// Broadcasts a message to all players. /// @@ -371,6 +397,19 @@ public static void ExplodeEffect(Vector3 position, ProjectileType projectileType ExplosionUtils.ServerSpawnEffect(position, item); } + /// + /// Spawn projectile effect HalloweenOnly. + /// + /// The position where effect will be created. + /// The projectile that will create the effect. + public static void ExplodeEffectHalloween(Vector3 position, ProjectileType projectileType) + { + ItemType item; + if ((item = projectileType.GetItemType()) is ItemType.None) + return; + ExplosionUtils.ServerSpawnEffect(position, item, true); + } + /// /// Plays a gun sound at the specified position. /// diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs index 9e55712ee..7843a3701 100644 --- a/EXILED/Exiled.API/Features/Player.cs +++ b/EXILED/Exiled.API/Features/Player.cs @@ -3744,6 +3744,11 @@ public void SetCooldownItem(float time, ItemType itemType) /// public void Explode() => ExplosionUtils.ServerExplode(ReferenceHub); + /// + /// Explode the player. + /// + public void ExplodeHalloween() => ExplosionUtils.ServerExplode(ReferenceHub, true); + /// /// Explode the player. /// @@ -3757,6 +3762,12 @@ public void SetCooldownItem(float time, ItemType itemType) /// The projectile that will create the effect. public void ExplodeEffect(ProjectileType projectileType) => Map.ExplodeEffect(Position, projectileType); + /// + /// Shakes camera with metal pipe falling shake effect. + /// + /// Intensity of the shake. + public void ShakeCameraPipe(float intensity) => referenceHub.connectionToClient.Send(new ShakeCameraMessage(intensity / 100f), 0); + /// /// Converts the player in a human-readable format. /// diff --git a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs index 89dcefa15..40a48eaed 100644 --- a/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs +++ b/EXILED/Exiled.API/Features/Roles/Scp3114Role.cs @@ -260,6 +260,6 @@ public void PlaySound(Scp3114VoiceLines.VoiceLinesName voiceLine = Scp3114VoiceL /// /// The List of Roles already spawned. /// The Spawn Chance. - public float GetSpawnChance(List alreadySpawned) => Base is ISpawnableScp spawnableScp ? spawnableScp.GetSpawnChance(alreadySpawned) : 0; + public float GetSpawnChance(List alreadySpawned) => Scp3114Spawner.SpawnChance; } } \ No newline at end of file