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