using Content.Shared.Clothing;
using Content.Shared.Hands.Components;
using Content.Shared.Humanoid;
+using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Content.Shared.Preferences;
[Dependency] private readonly InventorySystem _invSystem = default!;
[Dependency] private readonly SharedStationSpawningSystem _spawningSystem = default!;
- public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null)
+ public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null, bool unremovable = false)
{
if (!EntityManager.TryGetComponent(target, out InventoryComponent? inventoryComponent))
return false;
}
_invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
+ if (unremovable)
+ EnsureComp<UnremoveableComponent>(equipmentEntity);
onEquipped?.Invoke(target, equipmentEntity);
}
using Content.Shared.Chat.Prototypes;
using Robust.Shared.Random;
using Content.Shared.Stunnable;
-using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
using Content.Server.Emoting.Systems;
public sealed class CluwneSystem : EntitySystem
{
- private static readonly ProtoId<DamageGroupPrototype> GeneticDamageGroup = "Genetic";
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
/// <summary>
/// On death removes active comps and gives genetic damage to prevent cloning, reduce this to allow cloning.
/// </summary>
- private void OnMobState(EntityUid uid, CluwneComponent component, MobStateChangedEvent args)
+ private void OnMobState(Entity<CluwneComponent> ent, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
{
- RemComp<CluwneComponent>(uid);
- RemComp<ClumsyComponent>(uid);
- RemComp<AutoEmoteComponent>(uid);
- var damageSpec = new DamageSpecifier(_prototypeManager.Index(GeneticDamageGroup), 300);
- _damageableSystem.TryChangeDamage(uid, damageSpec);
+ RemComp<CluwneComponent>(ent.Owner);
+ RemComp<ClumsyComponent>(ent.Owner);
+ RemComp<AutoEmoteComponent>(ent.Owner);
+ _damageableSystem.TryChangeDamage(ent.Owner, ent.Comp.RevertDamage);
}
}
/// <summary>
/// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
/// </summary>
- private void OnComponentStartup(EntityUid uid, CluwneComponent component, ComponentStartup args)
+ private void OnComponentStartup(Entity<CluwneComponent> ent, ref ComponentStartup args)
{
- if (component.EmoteSoundsId == null)
+ if (ent.Comp.EmoteSoundsId == null)
return;
- _prototypeManager.TryIndex(component.EmoteSoundsId, out EmoteSounds);
- EnsureComp<AutoEmoteComponent>(uid);
- _autoEmote.AddEmote(uid, "CluwneGiggle");
- EnsureComp<ClumsyComponent>(uid);
+ _prototypeManager.TryIndex(ent.Comp.EmoteSoundsId, out EmoteSounds);
- _popupSystem.PopupEntity(Loc.GetString("cluwne-transform", ("target", uid)), uid, PopupType.LargeCaution);
- _audio.PlayPvs(component.SpawnSound, uid);
- _nameMod.RefreshNameModifiers(uid);
+ if (ent.Comp.RandomEmote && ent.Comp.AutoEmoteId != null)
+ {
+ EnsureComp<AutoEmoteComponent>(ent.Owner);
+ _autoEmote.AddEmote(ent.Owner, ent.Comp.AutoEmoteId);
+ }
+
+ EnsureComp<ClumsyComponent>(ent.Owner);
+
+ var transformMessage = Loc.GetString(ent.Comp.TransformMessage, ("target", ent.Owner));
+
+ _popupSystem.PopupEntity(transformMessage, ent.Owner, PopupType.LargeCaution);
+ _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
+
+ _nameMod.RefreshNameModifiers(ent.Owner);
- _outfitSystem.SetOutfit(uid, "CluwneGear");
+
+ _outfitSystem.SetOutfit(ent.Owner, ent.Comp.OutfitId, unremovable: true);
}
/// <summary>
/// Handles the timing on autoemote as well as falling over and honking.
/// </summary>
- private void OnEmote(EntityUid uid, CluwneComponent component, ref EmoteEvent args)
+ private void OnEmote(Entity<CluwneComponent> ent, ref EmoteEvent args)
{
if (args.Handled)
return;
- args.Handled = _chat.TryPlayEmoteSound(uid, EmoteSounds, args.Emote);
- if (_robustRandom.Prob(component.GiggleRandomChance))
+ if (!ent.Comp.RandomEmote)
+ return;
+
+ args.Handled = _chat.TryPlayEmoteSound(ent.Owner, EmoteSounds, args.Emote);
+
+ if (_robustRandom.Prob(ent.Comp.GiggleRandomChance))
{
- _audio.PlayPvs(component.SpawnSound, uid);
- _chat.TrySendInGameICMessage(uid, "honks", InGameICChatType.Emote, ChatTransmitRange.Normal);
+ _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
+ _chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.GiggleEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
}
- else if (_robustRandom.Prob(component.KnockChance))
+ else if (_robustRandom.Prob(ent.Comp.KnockChance))
{
- _audio.PlayPvs(component.KnockSound, uid);
- _stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(component.ParalyzeTime));
- _chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
+ _audio.PlayPvs(ent.Comp.KnockSound, ent.Owner);
+ _stunSystem.TryUpdateParalyzeDuration(ent.Owner, TimeSpan.FromSeconds(ent.Comp.ParalyzeTime));
+ _chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.KnockEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
}
}
/// <summary>
/// Applies "Cluwnified" prefix
/// </summary>
- private void OnRefreshNameModifiers(Entity<CluwneComponent> entity, ref RefreshNameModifiersEvent args)
+ private void OnRefreshNameModifiers(Entity<CluwneComponent> ent, ref RefreshNameModifiersEvent args)
{
- args.AddModifier("cluwne-name-prefix");
+ args.AddModifier(ent.Comp.NamePrefix);
}
}
using Robust.Shared.Audio;
using Content.Shared.Chat.Prototypes;
+using Content.Shared.Damage;
+using Content.Shared.Roles;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Cluwne;
/// <summary>
/// timings for giggles and knocks.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
public TimeSpan DamageGiggleCooldown = TimeSpan.FromSeconds(2);
- [ViewVariables(VVAccess.ReadWrite)]
+ /// <summary>
+ /// Amount of genetic damage dealt when they revert
+ /// </summary>
+ [DataField]
+ public DamageSpecifier RevertDamage = new()
+ {
+ DamageDict = new()
+ {
+ { "Genetic", 300.0 },
+ },
+ };
+
+ /// <summary>
+ /// Chance that the Cluwne will be knocked over and paralyzed.
+ /// </summary>
+ [DataField]
public float KnockChance = 0.05f;
- [ViewVariables(VVAccess.ReadWrite)]
+ /// <summary>
+ /// Chance that the Cluwne will randomly giggle
+ /// </summary>
+ [DataField]
public float GiggleRandomChance = 0.1f;
- [DataField("emoteId", customTypeSerializer: typeof(PrototypeIdSerializer<EmoteSoundsPrototype>))]
- public string? EmoteSoundsId = "Cluwne";
+ /// <summary>
+ /// Enable random emoting?
+ /// </summary>
+ [DataField]
+ public bool RandomEmote = true;
+
+ /// <summary>
+ /// Emote sound collection that the Cluwne should use.
+ /// </summary>
+ [DataField("emoteId")]
+ public ProtoId<EmoteSoundsPrototype>? EmoteSoundsId = "Cluwne";
+
+ /// <summary>
+ /// Emote to use for the Cluwne Giggling
+ /// </summary>
+ [DataField]
+ public ProtoId<AutoEmotePrototype>? AutoEmoteId = "CluwneGiggle";
+
+ /// <summary>
+ /// Message to popup when the Cluwne is transformed
+ /// </summary>
+ [DataField]
+ public LocId TransformMessage = "cluwne-transform";
+
+ /// <summary>
+ /// Name prefix for the Cluwne.
+ /// Example "Urist McHuman" will be "Cluwned Urist McHuman"
+ /// </summary>
+ [DataField]
+ public LocId NamePrefix = "cluwne-name-prefix";
+
+ /// <summary>
+ /// Outfit ID that the cluwne will spawn with.
+ /// </summary>
+ [DataField]
+ public ProtoId<StartingGearPrototype> OutfitId = "CluwneGear";
/// <summary>
/// Amount of time cluwne is paralyzed for when falling over.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
public float ParalyzeTime = 2f;
/// <summary>
[DataField("spawnsound")]
public SoundSpecifier SpawnSound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
- [DataField("knocksound")]
+ /// <summary>
+ /// Emote to use for the cluwne giggling
+ /// </summary>
+ [DataField]
+ public LocId GiggleEmote = "cluwne-giggle-emote";
+
+ /// <summary>
+ /// Sound to play when the Cluwne is knocked over and paralyzed
+ /// </summary>
+ [DataField]
public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Items/airhorn.ogg");
+
+ /// <summary>
+ /// Emote thats used when the cluwne getting knocked over
+ /// </summary>
+ [DataField]
+ public LocId KnockEmote = "cluwne-knock-emote";
}