fish-station/Content.Server/Changeling/ChangelingSystem.Abilities.cs
2025-08-13 14:27:23 +03:00

660 lines
24 KiB
C#

using Content.Shared.Changeling;
using Content.Shared.Chemistry.Components;
using Content.Shared.Cuffs.Components;
using Content.Shared.DoAfter;
using Content.Shared.FixedPoint;
using Content.Shared.IdentityManagement;
using Content.Shared.Mobs;
using Content.Shared.Store.Components;
using Content.Shared.Popups;
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
using Content.Shared.Damage.Prototypes;
using Content.Server.Objectives.Components;
using Content.Server.Light.Components;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Stealth.Components;
using Content.Shared.Damage.Components;
using Content.Server.Radio.Components;
using Content.Shared._Sunrise.CollectiveMind;
using Content.Shared._RMC14.Xenonids.Screech;
using Content.Shared.Coordinates;
using Content.Shared.Flash.Components;
using Content.Shared.Light.Components;
namespace Content.Server.Changeling;
public sealed partial class ChangelingSystem : EntitySystem
{
public void SubscribeAbilities()
{
SubscribeLocalEvent<ChangelingComponent, OpenEvolutionMenuEvent>(OnOpenEvolutionMenu);
SubscribeLocalEvent<ChangelingComponent, AbsorbDNAEvent>(OnAbsorb);
SubscribeLocalEvent<ChangelingComponent, AbsorbDNADoAfterEvent>(OnAbsorbDoAfter);
SubscribeLocalEvent<ChangelingComponent, StingExtractDNAEvent>(OnStingExtractDNA);
SubscribeLocalEvent<ChangelingComponent, ChangelingTransformCycleEvent>(OnTransformCycle);
SubscribeLocalEvent<ChangelingComponent, ChangelingTransformEvent>(OnTransform);
SubscribeLocalEvent<ChangelingComponent, EnterStasisEvent>(OnEnterStasis);
SubscribeLocalEvent<ChangelingComponent, ExitStasisEvent>(OnExitStasis);
SubscribeLocalEvent<ChangelingComponent, ToggleArmbladeEvent>(OnToggleArmblade);
SubscribeLocalEvent<ChangelingComponent, CreateBoneShardEvent>(OnCreateBoneShard);
SubscribeLocalEvent<ChangelingComponent, ToggleChitinousArmorEvent>(OnToggleArmor);
SubscribeLocalEvent<ChangelingComponent, ToggleOrganicShieldEvent>(OnToggleShield);
SubscribeLocalEvent<ChangelingComponent, ShriekDissonantEvent>(OnShriekDissonant);
SubscribeLocalEvent<ChangelingComponent, ShriekResonantEvent>(OnShriekResonant);
SubscribeLocalEvent<ChangelingComponent, ToggleStrainedMusclesEvent>(OnToggleStrainedMuscles);
SubscribeLocalEvent<ChangelingComponent, StingBlindEvent>(OnStingBlind);
SubscribeLocalEvent<ChangelingComponent, StingCryoEvent>(OnStingCryo);
SubscribeLocalEvent<ChangelingComponent, StingLethargicEvent>(OnStingLethargic);
SubscribeLocalEvent<ChangelingComponent, StingMuteEvent>(OnStingMute);
SubscribeLocalEvent<ChangelingComponent, StingTransformEvent>(OnStingTransform);
SubscribeLocalEvent<ChangelingComponent, StingFakeArmbladeEvent>(OnStingFakeArmblade);
SubscribeLocalEvent<ChangelingComponent, ActionAnatomicPanaceaEvent>(OnAnatomicPanacea);
SubscribeLocalEvent<ChangelingComponent, ActionAugmentedEyesightEvent>(OnAugmentedEyesight);
SubscribeLocalEvent<ChangelingComponent, ActionBiodegradeEvent>(OnBiodegrade);
SubscribeLocalEvent<ChangelingComponent, ActionChameleonSkinEvent>(OnChameleonSkin);
SubscribeLocalEvent<ChangelingComponent, ActionEphedrineOverdoseEvent>(OnEphedrineOverdose);
SubscribeLocalEvent<ChangelingComponent, ActionFleshmendEvent>(OnHealUltraSwag);
SubscribeLocalEvent<ChangelingComponent, ActionLastResortEvent>(OnLastResort);
SubscribeLocalEvent<ChangelingComponent, ActionLesserFormEvent>(OnLesserForm);
SubscribeLocalEvent<ChangelingComponent, ActionSpacesuitEvent>(OnSpacesuit);
SubscribeLocalEvent<ChangelingComponent, ActionHivemindAccessEvent>(OnHivemindAccess);
}
#region Basic Abilities
private void OnOpenEvolutionMenu(EntityUid uid, ChangelingComponent comp, ref OpenEvolutionMenuEvent args)
{
if (!TryComp<StoreComponent>(uid, out var store))
return;
_store.ToggleUi(uid, uid, store);
}
private void OnAbsorb(EntityUid uid, ChangelingComponent comp, ref AbsorbDNAEvent args)
{
var target = args.Target;
if (!IsIncapacitated(target))
{
_popup.PopupEntity(Loc.GetString("changeling-absorb-fail-incapacitated"), uid, uid);
return;
}
if (HasComp<AbsorbedComponent>(target))
{
_popup.PopupEntity(Loc.GetString("changeling-absorb-fail-absorbed"), uid, uid);
return;
}
if (!HasComp<AbsorbableComponent>(target))
{
_popup.PopupEntity(Loc.GetString("changeling-absorb-fail-unabsorbable"), uid, uid);
return;
}
if (!TryUseAbility(uid, comp, args))
return;
var popupOthers = Loc.GetString("changeling-absorb-start", ("user", Identity.Entity(uid, EntityManager)), ("target", Identity.Entity(target, EntityManager)));
_popup.PopupEntity(popupOthers, uid, PopupType.LargeCaution);
PlayMeatySound(uid, comp);
var dargs = new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(15), new AbsorbDNADoAfterEvent(), uid, target)
{
DistanceThreshold = 1.5f,
BreakOnDamage = true,
BreakOnHandChange = false,
BreakOnMove = true,
BreakOnWeightlessMove = true,
AttemptFrequency = AttemptFrequency.StartAndEnd
};
_doAfter.TryStartDoAfter(dargs);
}
public ProtoId<DamageGroupPrototype> AbsorbedDamageGroup = "Genetic";
private void OnAbsorbDoAfter(EntityUid uid, ChangelingComponent comp, ref AbsorbDNADoAfterEvent args)
{
if (args.Args.Target == null)
return;
var target = args.Args.Target.Value;
if (args.Cancelled || !IsIncapacitated(target) || HasComp<AbsorbedComponent>(target))
return;
PlayMeatySound(args.User, comp);
UpdateBiomass(uid, comp, comp.MaxBiomass - comp.TotalAbsorbedEntities);
var dmg = new DamageSpecifier(_proto.Index(AbsorbedDamageGroup), 180);
_damage.TryChangeDamage(target, dmg, false, false);
_blood.ChangeBloodReagent(target, "FerrochromicAcid");
_blood.SpillAllSolutions(target);
EnsureComp<AbsorbedComponent>(target);
var popup = Loc.GetString("changeling-absorb-end-self-ling");
var bonusChemicals = 0f;
var bonusEvolutionPoints = 0f;
if (TryComp<ChangelingComponent>(target, out var targetComp))
{
bonusChemicals += targetComp.MaxChemicals / 2;
bonusEvolutionPoints += 10;
comp.MaxBiomass += targetComp.MaxBiomass / 2;
}
else
{
popup = Loc.GetString("changeling-absorb-end-self");
bonusChemicals += 10;
bonusEvolutionPoints += 2;
}
TryStealDNA(uid, target, comp, true);
comp.TotalAbsorbedEntities++;
_popup.PopupEntity(popup, args.User, args.User);
comp.MaxChemicals += bonusChemicals;
if (TryComp<StoreComponent>(args.User, out var store))
{
_store.TryAddCurrency(new Dictionary<string, FixedPoint2> { { "EvolutionPoint", bonusEvolutionPoints } }, args.User, store);
_store.UpdateUserInterface(args.User, args.User, store);
}
if (_mind.TryGetMind(uid, out var mindId, out var mind))
if (_mind.TryGetObjectiveComp<AbsorbConditionComponent>(mindId, out var objective, mind))
objective.Absorbed += 1;
}
private void OnStingExtractDNA(EntityUid uid, ChangelingComponent comp, ref StingExtractDNAEvent args)
{
if (!TrySting(uid, comp, args, true))
return;
var target = args.Target;
if (!TryStealDNA(uid, target, comp, true))
{
_popup.PopupEntity(Loc.GetString("changeling-sting-extract-fail"), uid, uid);
// royal cashback
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
}
else _popup.PopupEntity(Loc.GetString("changeling-sting", ("target", Identity.Entity(target, EntityManager))), uid, uid);
}
private void OnTransformCycle(EntityUid uid, ChangelingComponent comp, ref ChangelingTransformCycleEvent args)
{
comp.AbsorbedDNAIndex += 1;
if (comp.AbsorbedDNAIndex >= comp.MaxAbsorbedDNA || comp.AbsorbedDNAIndex >= comp.AbsorbedDNA.Count)
comp.AbsorbedDNAIndex = 0;
if (comp.AbsorbedDNA.Count == 0)
{
_popup.PopupEntity(Loc.GetString("changeling-transform-cycle-empty"), uid, uid);
return;
}
var selected = comp.AbsorbedDNA.ToArray()[comp.AbsorbedDNAIndex];
comp.SelectedForm = selected;
_popup.PopupEntity(Loc.GetString("changeling-transform-cycle", ("target", selected.Name)), uid, uid);
}
private void OnTransform(EntityUid uid, ChangelingComponent comp, ref ChangelingTransformEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (!TryTransform(uid, comp))
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
}
private void OnEnterStasis(EntityUid uid, ChangelingComponent comp, ref EnterStasisEvent args)
{
if (comp.IsInStasis || HasComp<AbsorbedComponent>(uid))
{
_popup.PopupEntity(Loc.GetString("changeling-stasis-enter-fail"), uid, uid);
return;
}
if (!TryUseAbility(uid, comp, args))
return;
comp.Chemicals = 0f;
ToggleChameleonSkin(uid, comp, false);
if (_mobState.IsAlive(uid))
{
// fake our death
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", uid));
_popup.PopupEntity(othersMessage, uid, Robust.Shared.Player.Filter.PvsExcept(uid), true);
var selfMessage = Loc.GetString("changeling-stasis-enter");
_popup.PopupEntity(selfMessage, uid, uid);
}
if (!_mobState.IsDead(uid))
_mobState.ChangeMobState(uid, MobState.Dead);
comp.IsInStasis = true;
args.Handled = true;
}
private void OnExitStasis(EntityUid uid, ChangelingComponent comp, ref ExitStasisEvent args)
{
if (!comp.IsInStasis)
{
_popup.PopupEntity(Loc.GetString("changeling-stasis-exit-fail"), uid, uid);
return;
}
if (HasComp<AbsorbedComponent>(uid))
{
_popup.PopupEntity(Loc.GetString("changeling-stasis-exit-fail-dead"), uid, uid);
return;
}
if (!TryUseAbility(uid, comp, args))
return;
if (!TryComp<DamageableComponent>(uid, out var damageable))
return;
// heal of everything
_damage.SetAllDamage(uid, damageable, 0);
_mobState.ChangeMobState(uid, MobState.Alive);
_blood.TryModifyBloodLevel(uid, 1000);
_blood.TryModifyBleedAmount(uid, -1000);
_popup.PopupEntity(Loc.GetString("changeling-stasis-exit"), uid, uid);
// Sunrise edit start
StartScreech(uid);
// Sunrise edit end
comp.IsInStasis = false;
args.Handled = true;
}
#endregion
#region Combat Abilities
private void OnToggleArmblade(EntityUid uid, ChangelingComponent comp, ref ToggleArmbladeEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (!TryToggleItem(uid, ArmbladePrototype, comp))
return;
PlayMeatySound(uid, comp);
}
private void OnCreateBoneShard(EntityUid uid, ChangelingComponent comp, ref CreateBoneShardEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
var star = Spawn(BoneShardPrototype, Transform(uid).Coordinates);
_hands.TryPickupAnyHand(uid, star);
PlayMeatySound(uid, comp);
}
private void OnToggleArmor(EntityUid uid, ChangelingComponent comp, ref ToggleChitinousArmorEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (!TryToggleItem(uid, ArmorPrototype, comp, "outerClothing")
|| !TryToggleItem(uid, ArmorHelmetPrototype, comp, "head"))
{
_popup.PopupEntity(Loc.GetString("changeling-equip-armor-fail"), uid, uid);
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
return;
}
PlayMeatySound(uid, comp);
}
private void OnToggleShield(EntityUid uid, ChangelingComponent comp, ref ToggleOrganicShieldEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (!TryToggleItem(uid, ShieldPrototype, comp))
return;
PlayMeatySound(uid, comp);
}
private void OnShriekDissonant(EntityUid uid, ChangelingComponent comp, ref ShriekDissonantEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
DoScreech(uid, comp);
var pos = _transform.GetMapCoordinates(uid);
var power = comp.ShriekPower;
_emp.EmpPulse(pos, power, 5000f, power * 2);
}
private void OnShriekResonant(EntityUid uid, ChangelingComponent comp, ref ShriekResonantEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
DoScreech(uid, comp);
var power = comp.ShriekPower;
_flash.FlashArea(uid, uid, power, TimeSpan.FromSeconds(5));
var lookup = _lookup.GetEntitiesInRange(uid, power);
var lights = GetEntityQuery<PoweredLightComponent>();
foreach (var ent in lookup)
if (lights.HasComponent(ent))
_light.TryDestroyBulb(ent);
}
private void OnToggleStrainedMuscles(EntityUid uid, ChangelingComponent comp, ref ToggleStrainedMusclesEvent args)
{
if (!TryUseAbility(uid, comp, args) || _gravity.IsWeightless(uid))
return;
ToggleStrainedMuscles(uid, comp);
}
private void ToggleStrainedMuscles(EntityUid uid, ChangelingComponent comp)
{
if (!comp.StrainedMusclesActive)
{
_speed.ChangeBaseSpeed(uid, 4f, 7.5f, 20f);
_popup.PopupEntity(Loc.GetString("changeling-muscles-start"), uid, uid);
comp.StrainedMusclesActive = true;
}
else
{
_speed.ChangeBaseSpeed(uid, 2.5f, 4.5f, 20f);
_popup.PopupEntity(Loc.GetString("changeling-muscles-end"), uid, uid);
comp.StrainedMusclesActive = false;
}
PlayMeatySound(uid, comp);
}
#endregion
#region Stings
private void OnStingBlind(EntityUid uid, ChangelingComponent comp, ref StingBlindEvent args)
{
if (!TrySting(uid, comp, args))
return;
var target = args.Target;
if (!TryComp<BlindableComponent>(target, out var blindable) || blindable.IsBlind)
return;
_blindable.AdjustEyeDamage((target, blindable), 2);
var timeSpan = TimeSpan.FromSeconds(5f);
_statusEffect.TryAddStatusEffect(target, TemporaryBlindnessSystem.BlindingStatusEffect, timeSpan, false, TemporaryBlindnessSystem.BlindingStatusEffect);
}
private void OnStingCryo(EntityUid uid, ChangelingComponent comp, ref StingCryoEvent args)
{
var reagents = new List<(string, FixedPoint2)>()
{
("Fresium", 20f),
("ChloralHydrate", 10f)
};
if (!TryReagentSting(uid, comp, args, reagents))
return;
}
private void OnStingLethargic(EntityUid uid, ChangelingComponent comp, ref StingLethargicEvent args)
{
var reagents = new List<(string, FixedPoint2)>()
{
("Impedrezene", 10f),
("MuteToxin", 5f)
};
if (!TryReagentSting(uid, comp, args, reagents))
return;
}
private void OnStingMute(EntityUid uid, ChangelingComponent comp, ref StingMuteEvent args)
{
var reagents = new List<(string, FixedPoint2)>()
{
("MuteToxin", 15f)
};
if (!TryReagentSting(uid, comp, args, reagents))
return;
}
private void OnStingTransform(EntityUid uid, ChangelingComponent comp, ref StingTransformEvent args)
{
if (!TrySting(uid, comp, args, true))
return;
var target = args.Target;
if (!TryTransform(target, comp, true, true))
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
}
private void OnStingFakeArmblade(EntityUid uid, ChangelingComponent comp, ref StingFakeArmbladeEvent args)
{
if (!TrySting(uid, comp, args))
return;
var target = args.Target;
var fakeArmblade = EntityManager.SpawnEntity(FakeArmbladePrototype, Transform(target).Coordinates);
if (!_hands.TryPickupAnyHand(target, fakeArmblade))
{
QueueDel(fakeArmblade);
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
_popup.PopupEntity(Loc.GetString("changeling-sting-fail-simplemob"), uid, uid);
return;
}
PlayMeatySound(target, comp);
}
#endregion
#region Utilities
private void OnAnatomicPanacea(EntityUid uid, ChangelingComponent comp, ref ActionAnatomicPanaceaEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
var reagents = new List<(string, FixedPoint2)>()
{
("Diphenhydramine", 5f),
("Arithrazine", 5f),
("Ethylredoxrazine", 5f)
};
if (TryInjectReagents(uid, reagents))
_popup.PopupEntity(Loc.GetString("changeling-panacea"), uid, uid);
else return;
PlayMeatySound(uid, comp);
}
private void OnAugmentedEyesight(EntityUid uid, ChangelingComponent comp, ref ActionAugmentedEyesightEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (HasComp<FlashImmunityComponent>(uid))
{
_popup.PopupEntity(Loc.GetString("changeling-passive-active"), uid, uid);
return;
}
EnsureComp<FlashImmunityComponent>(uid);
_popup.PopupEntity(Loc.GetString("changeling-passive-activate"), uid, uid);
}
private void OnBiodegrade(EntityUid uid, ChangelingComponent comp, ref ActionBiodegradeEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (TryComp<CuffableComponent>(uid, out var cuffs) && cuffs.Container.ContainedEntities.Count > 0)
{
var cuff = cuffs.LastAddedCuffs;
_cuffs.Uncuff(uid, cuffs.LastAddedCuffs, cuff);
QueueDel(cuff);
}
var soln = new Solution();
soln.AddReagent("PolytrinicAcid", 10f);
if (_pull.IsPulled(uid))
{
var puller = Comp<PullableComponent>(uid).Puller;
if (puller != null)
{
_puddle.TrySplashSpillAt((EntityUid) puller, Transform((EntityUid) puller).Coordinates, soln, out _);
return;
}
}
_puddle.TrySplashSpillAt(uid, Transform(uid).Coordinates, soln, out _);
}
private void OnChameleonSkin(EntityUid uid, ChangelingComponent comp, ref ActionChameleonSkinEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (comp.StealthEnabled && HasComp<StealthComponent>(uid) && HasComp<StealthOnMoveComponent>(uid))
ToggleChameleonSkin(uid, comp, false);
else
ToggleChameleonSkin(uid, comp, true);
}
public void ToggleChameleonSkin(EntityUid uid, ChangelingComponent comp, bool toState)
{
if (!toState)
{
RemComp<StealthComponent>(uid);
RemComp<StealthOnMoveComponent>(uid);
_popup.PopupEntity(Loc.GetString("changeling-chameleon-end"), uid, uid);
comp.StealthEnabled = false;
}
else
{
EnsureComp<StealthComponent>(uid);
var stealthonmove = EnsureComp<StealthOnMoveComponent>(uid);
stealthonmove.PassiveVisibilityRate = -0.37f;
_popup.PopupEntity(Loc.GetString("changeling-chameleon-start"), uid, uid);
comp.StealthEnabled = true;
}
}
private void OnEphedrineOverdose(EntityUid uid, ChangelingComponent comp, ref ActionEphedrineOverdoseEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
var stam = EnsureComp<StaminaComponent>(uid);
stam.StaminaDamage = 0;
var reagents = new List<(string, FixedPoint2)>()
{
("Ephedrine", 15f)
};
if (TryInjectReagents(uid, reagents))
_popup.PopupEntity(Loc.GetString("changeling-inject"), uid, uid);
else
{
_popup.PopupEntity(Loc.GetString("changeling-inject-fail"), uid, uid);
return;
}
}
// john space made me do this
private void OnHealUltraSwag(EntityUid uid, ChangelingComponent comp, ref ActionFleshmendEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
var reagents = new List<(string, FixedPoint2)>()
{
("Ichor", 10f),
("TranexamicAcid", 5f)
};
if (TryInjectReagents(uid, reagents))
_popup.PopupEntity(Loc.GetString("changeling-fleshmend"), uid, uid);
else
return;
PlayMeatySound(uid, comp);
}
public void OnLastResort(EntityUid uid, ChangelingComponent comp, ref ActionLastResortEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
// todo: implement
}
public void OnLesserForm(EntityUid uid, ChangelingComponent comp, ref ActionLesserFormEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
var newUid = TransformEntity(uid, protoId: "MobMonkey", comp: comp);
if (newUid == null)
{
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
return;
}
PlayMeatySound((EntityUid) newUid, comp);
var loc = Loc.GetString("changeling-transform-others", ("user", Identity.Entity((EntityUid) newUid, EntityManager)));
_popup.PopupEntity(loc, (EntityUid) newUid, PopupType.LargeCaution);
comp.IsInLesserForm = true;
}
public void OnSpacesuit(EntityUid uid, ChangelingComponent comp, ref ActionSpacesuitEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (!TryToggleItem(uid, SpacesuitPrototype, comp, "outerClothing")
|| !TryToggleItem(uid, SpacesuitHelmetPrototype, comp, "head"))
{
_popup.PopupEntity(Loc.GetString("changeling-equip-armor-fail"), uid, uid);
comp.Chemicals += Comp<ChangelingActionComponent>(args.Action).ChemicalCost;
return;
}
PlayMeatySound(uid, comp);
}
public void OnHivemindAccess(EntityUid uid, ChangelingComponent comp, ref ActionHivemindAccessEvent args)
{
if (!TryUseAbility(uid, comp, args))
return;
if (HasComp<HivemindComponent>(uid))
{
_popup.PopupEntity(Loc.GetString("changeling-passive-active"), uid, uid);
return;
}
EnsureComp<HivemindComponent>(uid);
var collectiveMindComponent = EnsureComp<CollectiveMindComponent>(uid);
if (!collectiveMindComponent.Minds.Contains("Changeling"))
collectiveMindComponent.Minds.Add("Changeling");
_popup.PopupEntity(Loc.GetString("changeling-hivemind-start"), uid, uid);
}
#endregion
// Sunrise edit start
private void StartScreech(EntityUid uid, XenoScreechComponent? component = null, bool playSound = true)
{
if (!Resolve(uid, ref component))
return;
if (playSound)
_audio.PlayPvs(component.Sound, uid);
SpawnAttachedTo(component.Effect, uid.ToCoordinates());
}
// Sunrise edit end
}