Добби свободен

This commit is contained in:
Vigers Ray 2025-08-13 16:00:32 +03:00
parent 7bdec90a3f
commit c9709e38f1
195 changed files with 302 additions and 3972 deletions

View file

@ -1,47 +0,0 @@
using Content.Client.Alerts;
using Content.Client.UserInterface.Systems.Alerts.Controls;
using Content.Shared.Changeling;
using Content.Shared.StatusIcon.Components;
using Robust.Shared.Prototypes;
namespace Content.Client.Changeling;
public sealed partial class ChangelingSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ChangelingComponent, UpdateAlertSpriteEvent>(OnUpdateAlert);
SubscribeLocalEvent<ChangelingComponent, GetStatusIconsEvent>(GetChanglingIcon);
}
private void OnUpdateAlert(EntityUid uid, ChangelingComponent comp, ref UpdateAlertSpriteEvent args)
{
var stateNormalized = 0f;
// hardcoded because uhh umm i don't know. send help.
switch (args.Alert.AlertKey.AlertType)
{
case "ChangelingChemicals":
stateNormalized = (int)(comp.Chemicals / comp.MaxChemicals * 18);
break;
case "ChangelingBiomass":
stateNormalized = (int)(comp.Biomass / comp.MaxBiomass * 16);
break;
default:
return;
}
var sprite = args.SpriteViewEnt.Comp;
sprite.LayerSetState(AlertVisualLayers.Base, $"{stateNormalized}");
}
private void GetChanglingIcon(Entity<ChangelingComponent> ent, ref GetStatusIconsEvent args)
{
if (HasComp<HivemindComponent>(ent) && _prototype.TryIndex(ent.Comp.StatusIcon, out var iconPrototype))
args.StatusIcons.Add(iconPrototype);
}
}

View file

@ -3,7 +3,7 @@ using Content.Shared.Chemistry.Reagent;
namespace Content.Client._Sunrise.SolutionRegenerationSwitcher;
public sealed class ClientSolutionRegenerationSwitcherSystem : SharedSolutionRegenerationSwitcherSystem
public sealed class SolutionRegenerationSwitcherSystem : SharedSolutionRegenerationSwitcherSystem
{
protected override void SwitchToNextReagent(EntityUid uid,
SolutionRegenerationSwitcherComponent component,

View file

@ -200,19 +200,6 @@ public sealed partial class AdminVerbSystem
args.Verbs.Add(paradox);
// Sunrise-Start
Verb ling = new()
{
Text = Loc.GetString("admin-verb-text-make-changeling"),
Category = VerbCategory.Antag,
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Changeling/changeling_abilities.rsi"), "transform"),
Act = () =>
{
_antag.ForceMakeAntag<ChangelingRuleComponent>(targetPlayer, DefaultChangelingRule);
},
Impact = LogImpact.High,
Message = Loc.GetString("admin-verb-make-changeling"),
};
args.Verbs.Add(ling);
Verb vampire = new()
{

View file

@ -1,660 +0,0 @@
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
}

View file

@ -1,666 +0,0 @@
using Content.Server.DoAfter;
using Content.Server.Forensics;
using Content.Server.Polymorph.Systems;
using Content.Server.Popups;
using Content.Server.Store.Systems;
using Content.Server.Zombies;
using Content.Shared.Alert;
using Content.Shared.Changeling;
using Content.Shared.Chemistry.Components;
using Content.Shared.Cuffs.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition.Components;
using Content.Shared.Store.Components;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Random;
using Content.Shared.Popups;
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
using Content.Server.Body.Systems;
using Content.Shared.Actions;
using Content.Shared.Polymorph;
using Robust.Shared.Serialization.Manager;
using Content.Server.Actions;
using Content.Server.Humanoid;
using Content.Server.Polymorph.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Server.Flash;
using Content.Server.Emp;
using Robust.Server.GameObjects;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Inventory;
using Content.Shared.Movement.Systems;
using Content.Shared.Damage.Systems;
using Content.Shared.Mind;
using Content.Server.Objectives.Components;
using Content.Server.Light.EntitySystems;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.StatusEffect;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Cuffs;
using Content.Shared.Fluids;
using Content.Shared.Revolutionary.Components;
using Robust.Shared.Player;
using System.Numerics;
using Content.Shared.Camera;
using Robust.Shared.Timing;
using Content.Shared.Damage.Components;
using Content.Server.Gravity;
using Content.Shared.Mobs.Components;
using Content.Server.Stunnable;
using Content.Shared.Jittering;
using System.Linq;
using Content.Server.Damage.Systems;
using Content.Shared._RMC14.Xenonids.Screech;
using Content.Shared.Forensics.Components;
using Content.Shared.Radio;
namespace Content.Server.Changeling;
public sealed partial class ChangelingSystem : EntitySystem
{
// this is one hell of a star wars intro text
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly IRobustRandom _rand = default!;
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly PolymorphSystem _polymorph = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly DamageableSystem _damage = default!;
[Dependency] private readonly BloodstreamSystem _blood = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly FlashSystem _flash = default!;
[Dependency] private readonly EmpSystem _emp = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly PoweredLightSystem _light = default!;
[Dependency] private readonly ISharedPlayerManager _player = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
[Dependency] private readonly StaminaSystem _stamina = default!;
[Dependency] private readonly GravitySystem _gravity = default!;
[Dependency] private readonly BlindableSystem _blindable = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
[Dependency] private readonly PullingSystem _pull = default!;
[Dependency] private readonly SharedCuffableSystem _cuffs = default!;
[Dependency] private readonly SharedPuddleSystem _puddle = default!;
[Dependency] private readonly StunSystem _stun = default!;
[Dependency] private readonly SharedJitteringSystem _jitter = default!;
public EntProtoId ArmbladePrototype = "ArmBladeChangeling";
public EntProtoId FakeArmbladePrototype = "FakeArmBladeChangeling";
public EntProtoId ShieldPrototype = "ChangelingShield";
public EntProtoId BoneShardPrototype = "ThrowingStarChangeling";
public EntProtoId ArmorPrototype = "ChangelingClothingOuterArmor";
public EntProtoId ArmorHelmetPrototype = "ChangelingClothingHeadHelmet";
public EntProtoId SpacesuitPrototype = "ChangelingClothingOuterHardsuit";
public EntProtoId SpacesuitHelmetPrototype = "ChangelingClothingHeadHelmetHardsuit";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ChangelingComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<ChangelingComponent, MobStateChangedEvent>(OnMobStateChange);
SubscribeLocalEvent<ChangelingComponent, DamageChangedEvent>(OnDamageChange);
SubscribeLocalEvent<ChangelingComponent, ComponentRemove>(OnComponentRemove);
SubscribeAbilities();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!_timing.IsFirstTimePredicted)
return;
foreach (var comp in EntityManager.EntityQuery<ChangelingComponent>())
{
var uid = comp.Owner;
if (_timing.CurTime < comp.UpdateTimer)
continue;
comp.UpdateTimer = _timing.CurTime + TimeSpan.FromSeconds(comp.UpdateCooldown);
Cycle(uid, comp);
}
}
public void Cycle(EntityUid uid, ChangelingComponent comp)
{
UpdateChemicals(uid, comp);
comp.BiomassUpdateTimer += 1;
if (comp.BiomassUpdateTimer >= comp.BiomassUpdateCooldown)
{
comp.BiomassUpdateTimer = 0;
UpdateBiomass(uid, comp);
}
UpdateAbilities(uid, comp);
}
private void UpdateChemicals(EntityUid uid, ChangelingComponent comp, float? amount = null)
{
var chemicals = comp.Chemicals;
// either amount or regen
chemicals += amount ?? 1 + comp.BonusChemicalRegen;
comp.Chemicals = Math.Clamp(chemicals, 0, comp.MaxChemicals);
Dirty(uid, comp);
_alerts.ShowAlert(uid, "ChangelingChemicals");
}
private void UpdateBiomass(EntityUid uid, ChangelingComponent comp, float? amount = null)
{
comp.Biomass += amount ?? 0;
comp.Biomass = Math.Clamp(comp.Biomass, 0, comp.MaxBiomass);
Dirty(uid, comp);
_alerts.ShowAlert(uid, "ChangelingBiomass");
var random = (int) _rand.Next(1, 3);
if (comp.Biomass <= 0)
// game over, man
_damage.TryChangeDamage(uid, new DamageSpecifier(_proto.Index(AbsorbedDamageGroup), 50), true);
if (comp.Biomass <= comp.MaxBiomass / 10)
{
// THE FUNNY ITCH IS REAL!!
comp.BonusChemicalRegen = 3f;
_popup.PopupEntity(Loc.GetString("popup-changeling-biomass-deficit-high"), uid, uid, PopupType.LargeCaution);
_jitter.DoJitter(uid, TimeSpan.FromSeconds(comp.BiomassUpdateCooldown), true, amplitude: 5, frequency: 10);
}
else if (comp.Biomass <= comp.MaxBiomass / 3)
{
// vomit blood
if (random == 1)
{
_stun.TryAddStunDuration(uid, TimeSpan.FromSeconds(1.5f));
var solution = new Solution();
var vomitAmount = 15f;
_blood.TryModifyBloodLevel(uid, -vomitAmount);
solution.AddReagent("Blood", vomitAmount);
_puddle.TrySplashSpillAt(uid, Transform(uid).Coordinates, solution, out _);
_popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid);
}
// the funny itch is not real
if (random == 3)
{
_popup.PopupEntity(Loc.GetString("popup-changeling-biomass-deficit-medium"), uid, uid, PopupType.MediumCaution);
_jitter.DoJitter(uid, TimeSpan.FromSeconds(.5f), true, amplitude: 5, frequency: 10);
}
}
else if (comp.Biomass <= comp.MaxBiomass / 2 && random == 3)
{
if (random == 1)
_popup.PopupEntity(Loc.GetString("popup-changeling-biomass-deficit-low"), uid, uid, PopupType.SmallCaution);
}
else comp.BonusChemicalRegen = 0f;
}
private void UpdateAbilities(EntityUid uid, ChangelingComponent comp)
{
var stamina = EnsureComp<StaminaComponent>(uid);
if (comp.StrainedMusclesActive)
{
_stamina.TakeStaminaDamage(uid, 7.5f, visual: false);
if (stamina.StaminaDamage >= stamina.CritThreshold || _gravity.IsWeightless(uid))
ToggleStrainedMuscles(uid, comp);
}
if (comp.StealthEnabled)
{
if (comp.Chemicals > comp.StealthDrain)
comp.Chemicals -= comp.StealthDrain;
else
{
_stamina.TakeStaminaDamage(uid, 35f, visual: false);
if (stamina.StaminaDamage >= stamina.CritThreshold)
ToggleChameleonSkin(uid, comp, false);
}
}
if (comp.IsInStasis)
{
if (comp.Biomass > comp.StasisDrain)
comp.Biomass -= comp.StasisDrain;
else
{
comp.IsInStasis = false;
_mobState.ChangeMobState(uid, MobState.Dead);
}
}
}
#region Helper Methods
public void PlayMeatySound(EntityUid uid, ChangelingComponent comp)
{
var rand = _rand.Next(0, comp.SoundPool.Count - 1);
var sound = comp.SoundPool.ToArray()[rand];
_audio.PlayPvs(sound, uid, AudioParams.Default.WithVolume(-3f));
}
public void DoScreech(EntityUid uid, ChangelingComponent comp)
{
_audio.PlayPvs(comp.ShriekSound, uid);
// Sunrise edit start
StartScreech(uid, playSound: false);
// Sunrise edit end
var center = Transform(uid).MapPosition;
var gamers = Filter.Empty();
gamers.AddInRange(center, comp.ShriekPower, _player, EntityManager);
foreach (var gamer in gamers.Recipients)
{
if (gamer.AttachedEntity == null)
continue;
var pos = Transform(gamer.AttachedEntity!.Value).WorldPosition;
var delta = center.Position - pos;
if (delta.EqualsApprox(Vector2.Zero))
delta = new(.01f, 0);
_recoil.KickCamera(uid, -delta.Normalized());
}
}
/// <summary>
/// Check if a target is crit/dead or cuffed. For absorbing.
/// </summary>
public bool IsIncapacitated(EntityUid uid)
{
if (_mobState.IsIncapacitated(uid)
|| (TryComp<CuffableComponent>(uid, out var cuffs) && cuffs.CuffedHandCount > 0))
return true;
return false;
}
public bool TryUseAbility(EntityUid uid, ChangelingComponent comp, BaseActionEvent action)
{
if (action.Handled)
return false;
if (!TryComp<ChangelingActionComponent>(action.Action, out var lingAction))
return false;
if (comp.Biomass < 1 && lingAction.RequireBiomass)
{
_popup.PopupEntity(Loc.GetString("changeling-biomass-deficit"), uid, uid);
return false;
}
if (!lingAction.UseInLesserForm && comp.IsInLesserForm)
{
_popup.PopupEntity(Loc.GetString("changeling-action-fail-lesserform"), uid, uid);
return false;
}
if (comp.Chemicals < lingAction.ChemicalCost)
{
_popup.PopupEntity(Loc.GetString("changeling-chemicals-deficit"), uid, uid);
return false;
}
if (lingAction.RequireAbsorbed > comp.TotalAbsorbedEntities)
{
var delta = lingAction.RequireAbsorbed - comp.TotalAbsorbedEntities;
_popup.PopupEntity(Loc.GetString("changeling-action-fail-absorbed", ("number", delta)), uid, uid);
return false;
}
UpdateChemicals(uid, comp, -lingAction.ChemicalCost);
UpdateBiomass(uid, comp, -lingAction.BiomassCost);
action.Handled = true;
return true;
}
public bool TrySting(EntityUid uid, ChangelingComponent comp, EntityTargetActionEvent action, bool overrideMessage = false)
{
if (!TryUseAbility(uid, comp, action))
return false;
var target = action.Target;
// can't get his dna if he doesn't have it!
if (!HasComp<AbsorbableComponent>(target) || HasComp<AbsorbedComponent>(target))
{
_popup.PopupEntity(Loc.GetString("changeling-sting-extract-fail"), uid, uid);
return false;
}
if (HasComp<ChangelingComponent>(target))
{
_popup.PopupEntity(Loc.GetString("changeling-sting-fail-self", ("target", Identity.Entity(target, EntityManager))), uid, uid);
_popup.PopupEntity(Loc.GetString("changeling-sting-fail-ling"), target, target);
return false;
}
if (!overrideMessage)
_popup.PopupEntity(Loc.GetString("changeling-sting", ("target", Identity.Entity(target, EntityManager))), uid, uid);
return true;
}
public bool TryInjectReagents(EntityUid uid, List<(string, FixedPoint2)> reagents)
{
var solution = new Solution();
foreach (var reagent in reagents)
solution.AddReagent(reagent.Item1, reagent.Item2);
if (!_solution.TryGetInjectableSolution(uid, out var targetSolution, out var _))
return false;
if (!_solution.TryAddSolution(targetSolution.Value, solution))
return false;
return true;
}
public bool TryReagentSting(EntityUid uid, ChangelingComponent comp, EntityTargetActionEvent action, List<(string, FixedPoint2)> reagents)
{
var target = action.Target;
if (!TrySting(uid, comp, action))
return false;
if (!TryInjectReagents(target, reagents))
return false;
return true;
}
public bool TryToggleItem(EntityUid uid, EntProtoId proto, ChangelingComponent comp, string? clothingSlot = null)
{
if (!comp.Equipment.TryGetValue(proto.Id, out var item))
{
item = Spawn(proto, Transform(uid).Coordinates);
if (clothingSlot != null)
{
if (!_inventory.TryEquip(uid, (EntityUid) item, clothingSlot, force: true))
{
QueueDel(item);
return false;
}
comp.Equipment.Add(proto.Id, item);
return true;
}
else if (!_hands.TryForcePickupAnyHand(uid, (EntityUid) item))
{
_popup.PopupEntity(Loc.GetString("changeling-fail-hands"), uid, uid);
QueueDel(item);
return false;
}
comp.Equipment.Add(proto.Id, item);
return true;
}
QueueDel(item);
// assuming that it exists
comp.Equipment.Remove(proto.Id);
return true;
}
public bool TryStealDNA(EntityUid uid, EntityUid target, ChangelingComponent comp, bool countObjective = false)
{
if (!TryComp<HumanoidAppearanceComponent>(target, out var appearance)
|| !TryComp<MetaDataComponent>(target, out var metadata)
|| !TryComp<DnaComponent>(target, out var dna)
|| !TryComp<FingerprintComponent>(target, out var fingerprint))
return false;
foreach (var storedDNA in comp.AbsorbedDNA)
{
if (storedDNA.DNA != null && storedDNA.DNA == dna.DNA)
return false;
}
if (dna.DNA == null)
return false;
var data = new TransformData
{
Name = metadata.EntityName,
DNA = dna.DNA,
Appearance = appearance
};
if (fingerprint.Fingerprint != null)
data.Fingerprint = fingerprint.Fingerprint;
if (comp.AbsorbedDNA.Count >= comp.MaxAbsorbedDNA)
_popup.PopupEntity(Loc.GetString("changeling-sting-extract-max"), uid, uid);
else comp.AbsorbedDNA.Add(data);
if (countObjective
&& _mind.TryGetMind(uid, out var mindId, out var mind)
&& _mind.TryGetObjectiveComp<StealDNAConditionComponent>(mindId, out var objective, mind))
{
objective.DNAStolen += 1;
}
comp.TotalStolenDNA++;
return true;
}
private ChangelingComponent? CopyChangelingComponent(EntityUid target, ChangelingComponent comp)
{
var newComp = EnsureComp<ChangelingComponent>(target);
newComp.AbsorbedDNA = comp.AbsorbedDNA;
newComp.AbsorbedDNAIndex = comp.AbsorbedDNAIndex;
newComp.Chemicals = comp.Chemicals;
newComp.MaxChemicals = comp.MaxChemicals;
newComp.Biomass = comp.Biomass;
newComp.MaxBiomass = comp.MaxBiomass;
newComp.IsInLesserForm = comp.IsInLesserForm;
newComp.CurrentForm = comp.CurrentForm;
newComp.TotalAbsorbedEntities = comp.TotalAbsorbedEntities;
newComp.TotalStolenDNA = comp.TotalStolenDNA;
return comp;
}
private EntityUid? TransformEntity(EntityUid uid, TransformData? data = null, EntProtoId? protoId = null, ChangelingComponent? comp = null, bool persistentDna = false)
{
EntProtoId? pid = null;
if (data != null)
{
if (!_proto.TryIndex(data.Appearance.Species, out var species))
return null;
pid = species.Prototype;
}
else if (protoId != null)
pid = protoId;
else return null;
var config = new PolymorphConfiguration()
{
Entity = (EntProtoId) pid,
TransferDamage = true,
Forced = true,
Inventory = PolymorphInventoryChange.Transfer,
RevertOnCrit = false,
RevertOnDeath = false
};
var newUid = _polymorph.PolymorphEntity(uid, config);
if (newUid == null)
return null;
var newEnt = newUid.Value;
if (data != null)
{
Comp<FingerprintComponent>(newEnt).Fingerprint = data.Fingerprint;
Comp<DnaComponent>(newEnt).DNA = data.DNA;
_humanoid.CloneAppearance(data.Appearance.Owner, newEnt);
_metaData.SetEntityName(newEnt, data.Name);
var message = Loc.GetString("changeling-transform-finish", ("target", data.Name));
_popup.PopupEntity(message, newEnt, newEnt);
}
RemCompDeferred<PolymorphedEntityComponent>(newEnt);
if (comp != null)
{
// copy our stuff
var newLingComp = CopyChangelingComponent(newEnt, comp);
if (!persistentDna && data != null)
newLingComp?.AbsorbedDNA.Remove(data);
RemCompDeferred<ChangelingComponent>(uid);
if (TryComp<StoreComponent>(uid, out var storeComp))
{
var storeCompCopy = _serialization.CreateCopy(storeComp, notNullableOverride: true);
RemComp<StoreComponent>(newUid.Value);
EntityManager.AddComponent(newUid.Value, storeCompCopy);
}
}
// exceptional comps check
// there's no foreach for types i believe so i gotta thug it out yandev style.
if (HasComp<HeadRevolutionaryComponent>(uid))
EnsureComp<HeadRevolutionaryComponent>(newEnt);
if (HasComp<RevolutionaryComponent>(uid))
EnsureComp<RevolutionaryComponent>(newEnt);
QueueDel(uid);
return newUid;
}
public bool TryTransform(EntityUid target, ChangelingComponent comp, bool sting = false, bool persistentDna = false)
{
if (HasComp<AbsorbedComponent>(target))
{
_popup.PopupEntity(Loc.GetString("changeling-transform-fail-absorbed"), target, target);
return false;
}
var data = comp.SelectedForm;
if (data == null)
{
_popup.PopupEntity(Loc.GetString("changeling-transform-fail-self"), target, target);
return false;
}
if (data == comp.CurrentForm)
{
_popup.PopupEntity(Loc.GetString("changeling-transform-fail-choose"), target, target);
return false;
}
var locName = Identity.Entity(target, EntityManager);
EntityUid? newUid = null;
if (sting)
newUid = TransformEntity(target, data: data, persistentDna: persistentDna);
else newUid = TransformEntity(target, data: data, comp: comp, persistentDna: persistentDna);
if (newUid != null)
{
PlayMeatySound((EntityUid) newUid, comp);
var loc = Loc.GetString("changeling-transform-others", ("user", locName));
_popup.PopupEntity(loc, (EntityUid) newUid, PopupType.LargeCaution);
}
return true;
}
public void RemoveAllChangelingEquipment(EntityUid target, ChangelingComponent comp)
{
// check if there's no entities or all entities are null
if (comp.Equipment.Values.Count == 0
|| comp.Equipment.Values.All(ent => ent == null ? true : false))
return;
foreach (var equip in comp.Equipment.Values)
QueueDel(equip);
PlayMeatySound(target, comp);
}
#endregion
#region Event Handlers
private void OnStartup(EntityUid uid, ChangelingComponent comp, ref ComponentStartup args)
{
RemComp<HungerComponent>(uid);
RemComp<ThirstComponent>(uid);
EnsureComp<ZombieImmuneComponent>(uid);
// Sunrise edit start
EnsureComp<XenoScreechComponent>(uid);
// Sunrise edit end
// add actions
foreach (var actionId in comp.BaseChangelingActions)
_actions.AddAction(uid, actionId);
// making sure things are right in this world
comp.Chemicals = comp.MaxChemicals;
comp.Biomass = comp.MaxBiomass;
// show alerts
UpdateChemicals(uid, comp, 0);
UpdateBiomass(uid, comp, 0);
// make their blood unreal
_blood.ChangeBloodReagent(uid, "BloodChangeling");
}
private void OnMobStateChange(EntityUid uid, ChangelingComponent comp, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
RemoveAllChangelingEquipment(uid, comp);
}
private void OnDamageChange(Entity<ChangelingComponent> ent, ref DamageChangedEvent args)
{
var target = args.Damageable;
if (!TryComp<MobStateComponent>(ent, out var mobState))
return;
if (mobState.CurrentState != MobState.Dead)
return;
if (!args.DamageIncreased)
return;
target.Damage.ClampMax(200); // we never die. UNLESS??
}
private void OnComponentRemove(Entity<ChangelingComponent> ent, ref ComponentRemove args)
{
RemoveAllChangelingEquipment(ent, ent.Comp);
}
#endregion
}

View file

@ -1,123 +0,0 @@
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Objectives;
using Content.Shared.Changeling;
using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Systems;
using Content.Shared.Roles;
using Content.Shared.Store;
using Content.Shared.Store.Components;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using System.Text;
using Content.Shared.Roles.Components;
namespace Content.Server.GameTicking.Rules;
public sealed partial class ChangelingRuleSystem : GameRuleSystem<ChangelingRuleComponent>
{
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly SharedRoleSystem _role = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly ObjectivesSystem _objective = default!;
public readonly SoundSpecifier BriefingSound = new SoundPathSpecifier("/Audio/Ambience/Antag/changeling_start.ogg");
public readonly ProtoId<AntagPrototype> ChangelingPrototypeId = "Changeling";
public readonly ProtoId<NpcFactionPrototype> ChangelingFactionId = "Changeling";
public readonly ProtoId<NpcFactionPrototype> NanotrasenFactionId = "NanoTrasen";
public readonly ProtoId<CurrencyPrototype> Currency = "EvolutionPoint";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ChangelingRuleComponent, AfterAntagEntitySelectedEvent>(OnSelectAntag);
SubscribeLocalEvent<ChangelingRuleComponent, ObjectivesTextPrependEvent>(OnTextPrepend);
}
private void OnSelectAntag(EntityUid uid, ChangelingRuleComponent comp, ref AfterAntagEntitySelectedEvent args)
{
MakeChangeling(args.EntityUid, comp);
}
public bool MakeChangeling(EntityUid target, ChangelingRuleComponent rule)
{
if (!_mind.TryGetMind(target, out var mindId, out var mind))
return false;
// briefing
if (TryComp<MetaDataComponent>(target, out var metaData))
{
var briefing = Loc.GetString("changeling-role-greeting", ("name", metaData?.EntityName ?? "Unknown"));
var briefingShort = Loc.GetString("changeling-role-greeting-short", ("name", metaData?.EntityName ?? "Unknown"));
_antag.SendBriefing(target, briefing, Color.Yellow, BriefingSound);
_role.MindHasRole<Roles.ChangelingRoleComponent>(mindId, out var changelingRole);
_role.MindHasRole<RoleBriefingComponent>(mindId, out var briefingComp);
if (changelingRole is not null && briefingComp is null)
{
AddComp<RoleBriefingComponent>(changelingRole.Value.Owner);
Comp<RoleBriefingComponent>(changelingRole.Value.Owner).Briefing = briefing;
}
}
// hivemind stuff
_npcFaction.RemoveFaction(target, NanotrasenFactionId, false);
_npcFaction.AddFaction(target, ChangelingFactionId);
// make sure it's initial chems are set to max
EnsureComp<ChangelingComponent>(target);
// add store
var store = EnsureComp<StoreComponent>(target);
foreach (var category in rule.StoreCategories)
store.Categories.Add(category);
store.CurrencyWhitelist.Add(Currency);
store.Balance.Add(Currency, 16);
rule.ChangelingMinds.Add(mindId);
foreach (var objective in rule.Objectives)
_mind.TryAddObjective(mindId, mind, objective);
return true;
}
private void OnTextPrepend(EntityUid uid, ChangelingRuleComponent comp, ref ObjectivesTextPrependEvent args)
{
var mostAbsorbedName = string.Empty;
var mostStolenName = string.Empty;
var mostAbsorbed = 0f;
var mostStolen = 0f;
foreach (var ling in EntityQuery<ChangelingComponent>())
{
if (!_mind.TryGetMind(ling.Owner, out var mindId, out var mind))
continue;
if (!TryComp<MetaDataComponent>(ling.Owner, out var metaData))
continue;
if (ling.TotalAbsorbedEntities > mostAbsorbed)
{
mostAbsorbed = ling.TotalAbsorbedEntities;
mostAbsorbedName = _objective.GetTitle((mindId, mind), metaData.EntityName);
}
if (ling.TotalStolenDNA > mostStolen)
{
mostStolen = ling.TotalStolenDNA;
mostStolenName = _objective.GetTitle((mindId, mind), metaData.EntityName);
}
}
var sb = new StringBuilder();
sb.AppendLine(Loc.GetString($"roundend-prepend-changeling-absorbed{(!string.IsNullOrWhiteSpace(mostAbsorbedName) ? "-named" : "")}", ("name", mostAbsorbedName), ("number", mostAbsorbed)));
sb.AppendLine(Loc.GetString($"roundend-prepend-changeling-stolen{(!string.IsNullOrWhiteSpace(mostStolenName) ? "-named" : "")}", ("name", mostStolenName), ("number", mostStolen)));
args.Text = sb.ToString();
}
}

View file

@ -1,27 +1,7 @@
using Content.Shared.NPC.Prototypes;
using Content.Shared.Roles;
using Content.Shared.Store;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.GameTicking.Rules.Components;
namespace Content.Server.GameTicking.Rules.Components;
[RegisterComponent, Access(typeof(ChangelingRuleSystem))]
public sealed partial class ChangelingRuleComponent : Component
{
public readonly List<EntityUid> ChangelingMinds = new();
public readonly List<ProtoId<StoreCategoryPrototype>> StoreCategories = new()
{
"ChangelingAbilityCombat",
"ChangelingAbilitySting",
"ChangelingAbilityUtility"
};
public readonly List<ProtoId<EntityPrototype>> Objectives = new()
{
"ChangelingSurviveObjective",
"ChangelingStealDNAObjective",
"EscapeIdentityObjective"
};
}
/// <summary>
/// Gamerule component for handling a changeling antagonist.
/// </summary>
[RegisterComponent]
public sealed partial class ChangelingRuleComponent : Component;

View file

@ -1,11 +0,0 @@
using Content.Server.Changeling;
using Content.Server.Objectives.Systems;
namespace Content.Server.Objectives.Components;
[RegisterComponent, Access(typeof(ChangelingObjectiveSystem), typeof(ChangelingSystem))]
public sealed partial class AbsorbConditionComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Absorbed = 0f;
}

View file

@ -1,29 +0,0 @@
using Content.Server.Objectives.Systems;
namespace Content.Server.Objectives.Components;
/// <summary>
/// Requires that you have the same identity a target for a certain length of time before the round ends.
/// Obviously the agent id will work for this, but it's assumed that you will kill the target to prevent suspicion.
/// Depends on <see cref="TargetObjectiveComponent"/> to function.
/// </summary>
[RegisterComponent, Access(typeof(ImpersonateConditionSystem))]
public sealed partial class ImpersonateConditionComponent : Component
{
/// <summary>
/// Name that must match your identity for greentext.
/// This is stored once after the objective is assigned:
/// 1. to be a tiny bit more efficient
/// 2. to prevent the name possibly changing when borging or anything else and messing you up
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string? Name;
/// <summary>
/// Mind this objective got assigned to, used to continiously checkd impersonation.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public EntityUid? MindId;
public bool Completed = false;
}

View file

@ -1,11 +0,0 @@
using Content.Server.Changeling;
using Content.Server.Objectives.Systems;
namespace Content.Server.Objectives.Components;
[RegisterComponent, Access(typeof(ChangelingObjectiveSystem), typeof(ChangelingSystem))]
public sealed partial class StealDNAConditionComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float DNAStolen = 0f;
}

View file

@ -1,32 +0,0 @@
using Content.Server.Objectives.Components;
using Content.Shared.Objectives.Components;
namespace Content.Server.Objectives.Systems;
public sealed partial class ChangelingObjectiveSystem : EntitySystem
{
[Dependency] private readonly NumberObjectiveSystem _number = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AbsorbConditionComponent, ObjectiveGetProgressEvent>(OnAbsorbGetProgress);
SubscribeLocalEvent<StealDNAConditionComponent, ObjectiveGetProgressEvent>(OnStealDNAGetProgress);
}
private void OnAbsorbGetProgress(EntityUid uid, AbsorbConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
var target = _number.GetTarget(uid);
if (target != 0)
args.Progress = MathF.Min(comp.Absorbed / target, 1f);
else args.Progress = 1f;
}
private void OnStealDNAGetProgress(EntityUid uid, StealDNAConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
var target = _number.GetTarget(uid);
if (target != 0)
args.Progress = MathF.Min(comp.DNAStolen / target, 1f);
else args.Progress = 1f;
}
}

View file

@ -1,76 +0,0 @@
using Content.Server.Objectives.Components;
using Content.Server.Shuttles.Systems;
using Content.Shared.Cuffs.Components;
using Content.Shared.Mind;
using Content.Shared.Objectives.Components;
namespace Content.Server.Objectives.Systems;
/// <summary>
/// Handles escaping on the shuttle while being another person detection.
/// </summary>
public sealed class ImpersonateConditionSystem : EntitySystem
{
[Dependency] private readonly TargetObjectiveSystem _target = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ImpersonateConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<ImpersonateConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<ImpersonateConditionComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (comp.Name == null || comp.MindId == null)
continue;
if (!TryComp<MindComponent>(comp.MindId, out var mind) || mind.OwnedEntity == null)
continue;
if (!TryComp<MetaDataComponent>(mind.CurrentEntity, out var metaData))
continue;
if (metaData.EntityName == comp.Name)
comp.Completed = true;
else comp.Completed = false;
}
}
private void OnAfterAssign(EntityUid uid, ImpersonateConditionComponent comp, ref ObjectiveAfterAssignEvent args)
{
if (!_target.GetTarget(uid, out var target))
return;
if (!TryComp<MindComponent>(target, out var targetMind) || targetMind.CharacterName == null)
return;
comp.Name = targetMind.CharacterName;
comp.MindId = args.MindId;
}
// copypasta from escape shittle objective. eh.
private void OnGetProgress(EntityUid uid, ImpersonateConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
args.Progress = GetProgress(args.Mind, comp);
}
public float GetProgress(MindComponent mind, ImpersonateConditionComponent comp)
{
// not escaping alive if you're deleted/dead
if (mind.OwnedEntity == null || _mind.IsCharacterDeadIc(mind))
return 0f;
// You're not escaping if you're restrained!
if (TryComp<CuffableComponent>(mind.OwnedEntity, out var cuffed) && cuffed.CuffedHandCount > 0)
return 0f;
return (_emergencyShuttle.IsTargetEscaping(mind.OwnedEntity.Value) ? .5f : 0f) + (comp.Completed ? .5f : 0f);
}
}

View file

@ -1,8 +0,0 @@
using Content.Shared.Roles.Components;
namespace Content.Server.Roles;
[RegisterComponent]
public sealed partial class ChangelingRoleComponent : BaseMindRoleComponent
{
}

View file

@ -1,128 +0,0 @@
using Content.Shared._Starlight.Weapon.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Toolshed.Commands.Values;
using Robust.Shared.Utility;
namespace Content.Server.Weapons.Ranged.Systems;
public sealed partial class GunSystem
{
protected override void InitializeCartridge()
{
base.InitializeCartridge();
SubscribeLocalEvent<CartridgeAmmoComponent, ExaminedEvent>(OnCartridgeExamine);
SubscribeLocalEvent<CartridgeAmmoComponent, DamageExamineEvent>(OnCartridgeDamageExamine);
SubscribeLocalEvent<HitScanCartridgeAmmoComponent, ExaminedEvent>(OnHitScanCartridgeExamine);
SubscribeLocalEvent<HitScanCartridgeAmmoComponent, DamageExamineEvent>(OnHitScanCartridgeDamageExamine);
}
private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent component, ref DamageExamineEvent args)
{
var damageSpec = GetProjectileDamage(component.Prototype);
if (damageSpec == null)
return;
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-projectile"));
}
private DamageSpecifier? GetProjectileDamage(string proto)
{
if (!ProtoManager.TryIndex<EntityPrototype>(proto, out var entityProto))
return null;
if (entityProto.Components
.TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
{
var p = (ProjectileComponent) projectile.Component;
if (!p.Damage.Empty)
{
return p.Damage * Damageable.UniversalProjectileDamageModifier;
}
}
return null;
}
private void OnCartridgeExamine(EntityUid uid, CartridgeAmmoComponent component, ExaminedEvent args)
{
if (component.Spent)
{
args.PushMarkup(Loc.GetString("gun-cartridge-spent"));
}
else
{
args.PushMarkup(Loc.GetString("gun-cartridge-unspent"));
}
}
private void OnHitScanCartridgeDamageExamine(EntityUid uid, HitScanCartridgeAmmoComponent component, ref DamageExamineEvent args) {
var damageSpec = GetHitscanProjectileDamage(component.Hitscan);
if (damageSpec == null)
return;
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-projectile"));
var ArmorMessage = GetArmorPenetrationExplain(component.Hitscan);
args.Message.AddMessage(ArmorMessage);
}
private FormattedMessage GetArmorPenetrationExplain(string proto) {
var msg = new FormattedMessage();
if (!ProtoManager.TryIndex<HitscanPrototype>(proto,out var entityProto))
return msg;
if (entityProto.ArmorPenetration == 0) {
return msg;
}
if (entityProto.ArmorPenetration > 0){
msg.PushNewline();
msg.TryAddMarkup(Loc.GetString("damage-examine-penetration-positive",("penetration", MathF.Round(entityProto.ArmorPenetration * 100, 1))), out var error);
}
if(entityProto.ArmorPenetration < 0) {
msg.PushNewline();
msg.TryAddMarkup(Loc.GetString("damage-examine-penetration-negative",("penetration", MathF.Round(entityProto.ArmorPenetration * -100, 1))), out var error);
}
return msg;
}
private DamageSpecifier? GetHitscanProjectileDamage(string proto) {
if (!ProtoManager.TryIndex<HitscanPrototype>(proto,out var entityProto))
return null;
if (entityProto.Damage == null) {
return null;
}
if (!entityProto.Damage.Empty) {
return entityProto.Damage * Damageable.UniversalHitscanDamageModifier;
}
return null;
}
private void OnHitScanCartridgeExamine(EntityUid uid, HitScanCartridgeAmmoComponent component, ExaminedEvent args)
{
if (component.Spent)
{
args.PushMarkup(Loc.GetString("gun-cartridge-spent"));
}
else
{
args.PushMarkup(Loc.GetString("gun-cartridge-unspent"));
}
}
}

View file

@ -15,7 +15,6 @@ namespace Content.Server._Sunrise.NPC.HTN;
public sealed partial class CloseBoltOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly HandsSystem _handsSystem = default!;
private GunSystem _gunSystem = default!;
[DataField("shutdownState")]
@ -34,7 +33,9 @@ public sealed partial class CloseBoltOperator : HTNOperator
if (!_entManager.TryGetComponent<HandsComponent>(owner, out var hands))
return HTNOperatorStatus.Failed;
var heldEntity = _handsSystem.GetActiveItem((owner, hands));
var handsSystem = _entManager.System<HandsSystem>();
var heldEntity = handsSystem.GetActiveItem((owner, hands));
if (heldEntity == null)
return HTNOperatorStatus.Failed;

View file

@ -9,7 +9,6 @@ namespace Content.Server._Sunrise.NPC.HTN;
public sealed partial class IsBoltOpenPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly HandsSystem _handsSystem = default!;
public override bool IsMet(NPCBlackboard blackboard)
{
@ -17,7 +16,9 @@ public sealed partial class IsBoltOpenPrecondition : HTNPrecondition
if (!_entManager.TryGetComponent<HandsComponent>(owner, out var hands))
return false;
var heldEntity = _handsSystem.GetActiveItem((owner, hands));
var handsSystem = _entManager.System<HandsSystem>();
var heldEntity = handsSystem.GetActiveItem((owner, hands));
if (!_entManager.TryGetComponent<ChamberMagazineAmmoProviderComponent>(heldEntity, out var chamber))
return false;

View file

@ -13,12 +13,12 @@ namespace Content.Server._Sunrise.ReplacementVocal;
[RegisterComponent]
public sealed partial class ReplacementVocalComponent : Component
{
[DataField(customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer<Sex, EmoteSoundsPrototype>), required: true)]
[DataField(required: true)]
public Dictionary<Sex, ProtoId<EmoteSoundsPrototype>> Vocal;
[DataField]
public HashSet<string> AddedEmotes = new();
[DataField(customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer<Sex, EmoteSoundsPrototype>))]
[DataField]
public Dictionary<Sex, ProtoId<EmoteSoundsPrototype>>? PreviousVocal;
}

View file

@ -1,12 +0,0 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Changeling;
/// <summary>
/// Component that indicates that a person can be absorbed by a changeling.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class AbsorbableComponent : Component
{
}

View file

@ -1,13 +0,0 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Changeling;
/// <summary>
/// Component that indicates that a person's DNA has been absorbed by a changeling.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(AbsorbedSystem))]
public sealed partial class AbsorbedComponent : Component
{
}

View file

@ -1,27 +0,0 @@
using Content.Shared.Examine;
using Content.Shared.Mobs;
namespace Content.Shared.Changeling;
public sealed partial class AbsorbedSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AbsorbedComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<AbsorbedComponent, MobStateChangedEvent>(OnMobStateChange);
}
private void OnExamine(Entity<AbsorbedComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("changeling-absorb-onexamine"));
}
private void OnMobStateChange(Entity<AbsorbedComponent> ent, ref MobStateChangedEvent args)
{
// in case one somehow manages to dehusk someone
if (args.NewMobState != MobState.Dead)
RemComp<AbsorbedComponent>(ent);
}
}

View file

@ -1,69 +0,0 @@
using Content.Shared.Actions;
using Robust.Shared.GameStates;
namespace Content.Shared.Changeling;
[RegisterComponent, NetworkedComponent]
public sealed partial class ChangelingActionComponent : Component
{
[DataField] public bool RequireBiomass = true;
[DataField] public float ChemicalCost = 0;
[DataField] public float BiomassCost = 0;
[DataField] public bool UseInLesserForm = false;
[DataField] public float RequireAbsorbed = 0;
}
#region Events - Basic
public sealed partial class OpenEvolutionMenuEvent : InstantActionEvent { }
public sealed partial class AbsorbDNAEvent : EntityTargetActionEvent { }
public sealed partial class StingExtractDNAEvent : EntityTargetActionEvent { }
public sealed partial class ChangelingTransformCycleEvent : InstantActionEvent { }
public sealed partial class ChangelingTransformEvent : InstantActionEvent { }
public sealed partial class EnterStasisEvent : InstantActionEvent { }
public sealed partial class ExitStasisEvent : InstantActionEvent { }
#endregion
#region Events - Combat
public sealed partial class ToggleArmbladeEvent : InstantActionEvent { }
public sealed partial class CreateBoneShardEvent : InstantActionEvent { }
public sealed partial class ToggleChitinousArmorEvent : InstantActionEvent { }
public sealed partial class ToggleOrganicShieldEvent : InstantActionEvent { }
public sealed partial class ShriekDissonantEvent : InstantActionEvent { }
public sealed partial class ShriekResonantEvent : InstantActionEvent { }
public sealed partial class ToggleStrainedMusclesEvent : InstantActionEvent { }
#endregion
#region Events - Sting
public sealed partial class StingBlindEvent : EntityTargetActionEvent { }
public sealed partial class StingCryoEvent : EntityTargetActionEvent { }
public sealed partial class StingLethargicEvent : EntityTargetActionEvent { }
public sealed partial class StingMuteEvent : EntityTargetActionEvent { }
public sealed partial class StingFakeArmbladeEvent : EntityTargetActionEvent { }
public sealed partial class StingTransformEvent : EntityTargetActionEvent { }
#endregion
#region Events - Utility
public sealed partial class ActionAnatomicPanaceaEvent : InstantActionEvent { }
public sealed partial class ActionAugmentedEyesightEvent : InstantActionEvent { }
public sealed partial class ActionBiodegradeEvent : InstantActionEvent { }
public sealed partial class ActionChameleonSkinEvent : InstantActionEvent { }
public sealed partial class ActionEphedrineOverdoseEvent : InstantActionEvent { }
public sealed partial class ActionFleshmendEvent : InstantActionEvent { }
public sealed partial class ActionLastResortEvent : InstantActionEvent { }
public sealed partial class ActionLesserFormEvent : InstantActionEvent { }
public sealed partial class ActionSpacesuitEvent : InstantActionEvent { }
public sealed partial class ActionHivemindAccessEvent : InstantActionEvent { }
public sealed partial class ActionContortBodyEvent : InstantActionEvent { }
#endregion

View file

@ -1,7 +0,0 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;
namespace Content.Shared.Changeling;
[Serializable, NetSerializable]
public sealed partial class AbsorbDNADoAfterEvent : SimpleDoAfterEvent { }

View file

@ -1,12 +0,0 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Changeling;
/// <summary>
/// Used for identifying other changelings.
/// Indicates that a changeling has bought the hivemind access ability.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class HivemindComponent : Component
{
}

View file

@ -10,7 +10,7 @@ namespace Content.Shared.Chemistry.Components;
/// Passively increases a solution's quantity of a reagent.
/// </summary>
[RegisterComponent, AutoGenerateComponentPause, AutoGenerateComponentState, NetworkedComponent]
[Access(typeof(SolutionRegenerationSystem), typeof(SolutionRegenerationSwitcherSystem))] // Sunrise-Edit
[Access(typeof(SolutionRegenerationSystem), typeof(SharedSolutionRegenerationSwitcherSystem))] // Sunrise-Edit
public sealed partial class SolutionRegenerationComponent : Component
{
/// <summary>

View file

@ -2,7 +2,6 @@ using Content.Shared.Administration.Logs;
using Content.Shared.Body.Components;
using Content.Shared.Body.Systems;
using System.Linq;
using Content.Server.Medical.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;

View file

@ -1,73 +0,0 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.Medical.Components
{
/// <summary>
/// Applies a damage change to the target when used in an interaction.
/// </summary>
[RegisterComponent]
public sealed partial class HealingComponent : Component
{
[DataField("damage", required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = default!;
/// <remarks>
/// This should generally be negative,
/// since you're, like, trying to heal damage.
/// </remarks>
[DataField("bloodlossModifier")]
[ViewVariables(VVAccess.ReadWrite)]
public float BloodlossModifier = 0.0f;
/// <summary>
/// Restore missing blood.
/// </summary>
[DataField("ModifyBloodLevel")]
[ViewVariables(VVAccess.ReadWrite)]
public float ModifyBloodLevel = 0.0f;
/// <remarks>
/// The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. For a
/// HealingComponent this filters what damage container type this component should work on. If null,
/// all damage container types are supported.
/// </remarks>
[DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageContainerPrototype>))]
public List<string>? DamageContainers;
/// <summary>
/// How long it takes to apply the damage.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("delay")]
public float Delay = 3f;
/// <summary>
/// Delay multiplier when healing yourself.
/// </summary>
[DataField("selfHealPenaltyMultiplier")]
public float SelfHealPenaltyMultiplier = 3f;
/// <summary>
/// Sound played on healing begin
/// </summary>
[DataField("healingBeginSound")]
public SoundSpecifier? HealingBeginSound = null;
/// <summary>
/// Sound played on healing end
/// </summary>
[DataField("healingEndSound")]
public SoundSpecifier? HealingEndSound = null;
[DataField]
public bool SolutionDrain = false;
[DataField]
public List<ReagentQuantity> ReagentsToDrain = new();
}
}

View file

@ -1,6 +1,6 @@
using System.Linq;
using Content.Server.Medical.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Medical.Healing;
namespace Content.Shared.Medical;

View file

@ -1,3 +1,4 @@
using Content.Shared._Starlight.Weapon.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.Damage.Systems;
@ -5,6 +6,7 @@ using Content.Shared.Examine;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared.Weapons.Ranged.Systems;
@ -17,6 +19,9 @@ public abstract partial class SharedGunSystem
{
SubscribeLocalEvent<CartridgeAmmoComponent, ExaminedEvent>(OnCartridgeExamine);
SubscribeLocalEvent<CartridgeAmmoComponent, DamageExamineEvent>(OnCartridgeDamageExamine);
SubscribeLocalEvent<HitScanCartridgeAmmoComponent, ExaminedEvent>(OnHitScanCartridgeExamine);
SubscribeLocalEvent<HitScanCartridgeAmmoComponent, DamageExamineEvent>(OnHitScanCartridgeDamageExamine);
}
private void OnCartridgeExamine(Entity<CartridgeAmmoComponent> ent, ref ExaminedEvent args)
@ -26,6 +31,13 @@ public abstract partial class SharedGunSystem
: Loc.GetString("gun-cartridge-unspent"));
}
private void OnHitScanCartridgeExamine(Entity<HitScanCartridgeAmmoComponent> ent, ref ExaminedEvent args)
{
args.PushMarkup(ent.Comp.Spent
? Loc.GetString("gun-cartridge-spent")
: Loc.GetString("gun-cartridge-unspent"));
}
private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent component, ref DamageExamineEvent args)
{
var damageSpec = GetProjectileDamage(component.Prototype);
@ -36,16 +48,68 @@ public abstract partial class SharedGunSystem
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-projectile"));
}
private DamageSpecifier? GetProjectileDamage(EntProtoId proto)
private DamageSpecifier? GetProjectileDamage(string proto)
{
if (!ProtoManager.TryIndex(proto, out var entityProto))
if (!ProtoManager.TryIndex<EntityPrototype>(proto, out var entityProto))
return null;
if (!entityProto.TryGetComponent<ProjectileComponent>(out var projectile, Factory))
if (entityProto.Components
.TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
{
var p = (ProjectileComponent) projectile.Component;
if (!p.Damage.Empty)
{
return p.Damage * Damageable.UniversalProjectileDamageModifier;
}
}
return null;
}
private void OnHitScanCartridgeDamageExamine(EntityUid uid, HitScanCartridgeAmmoComponent component, ref DamageExamineEvent args) {
var damageSpec = GetHitscanProjectileDamage(component.Hitscan);
if (damageSpec == null)
return;
_damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-projectile"));
var ArmorMessage = GetArmorPenetrationExplain(component.Hitscan);
args.Message.AddMessage(ArmorMessage);
}
private FormattedMessage GetArmorPenetrationExplain(string proto) {
var msg = new FormattedMessage();
if (!ProtoManager.TryIndex<HitscanPrototype>(proto,out var entityProto))
return msg;
if (entityProto.ArmorPenetration == 0) {
return msg;
}
if (entityProto.ArmorPenetration > 0){
msg.PushNewline();
msg.TryAddMarkup(Loc.GetString("damage-examine-penetration-positive",("penetration", MathF.Round(entityProto.ArmorPenetration * 100, 1))), out var error);
}
if(entityProto.ArmorPenetration < 0) {
msg.PushNewline();
msg.TryAddMarkup(Loc.GetString("damage-examine-penetration-negative",("penetration", MathF.Round(entityProto.ArmorPenetration * -100, 1))), out var error);
}
return msg;
}
private DamageSpecifier? GetHitscanProjectileDamage(string proto) {
if (!ProtoManager.TryIndex<HitscanPrototype>(proto,out var entityProto))
return null;
if (!projectile.Damage.Empty)
return projectile.Damage * Damageable.UniversalProjectileDamageModifier;
if (entityProto.Damage == null) {
return null;
}
if (!entityProto.Damage.Empty) {
return entityProto.Damage * Damageable.UniversalHitscanDamageModifier;
}
return null;
}

View file

@ -1,79 +0,0 @@
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Popups;
namespace Content.Shared._Sunrise.SolutionRegenerationSwitcher
{
public sealed class SolutionRegenerationSwitcherSystem : SharedSolutionRegenerationSwitcherSystem
{
[Dependency] private readonly SharedSolutionContainerSystem _solutionSystem = null!;
[Dependency] private readonly SharedPopupSystem _popups = null!;
private ISawmill _sawmill = null!;
public override void Initialize()
{
base.Initialize();
_sawmill = Logger.GetSawmill("chemistry");
}
protected override void SwitchToNextReagent(EntityUid uid,
SolutionRegenerationSwitcherComponent component,
EntityUid user)
{
component.CurrentIndex = (component.CurrentIndex + 1) % component.Options.Count;
var nextReagent = component.Options[component.CurrentIndex];
SwitchReagent(uid, nextReagent, component, user);
}
protected override void SwitchReagent(EntityUid uid,
ReagentQuantity reagent,
SolutionRegenerationSwitcherComponent component,
EntityUid user)
{
if (!TryComp<SolutionRegenerationComponent>(uid, out var solutionRegenerationComponent))
{
_sawmill.Warning($"{ToPrettyString(uid)} has no SolutionRegenerationComponent.");
return;
}
if (!_solutionSystem.TryGetSolution(uid, solutionRegenerationComponent.SolutionName, out var solution))
{
_sawmill.Error($"Can't get SolutionRegeneration.Solution for {ToPrettyString(uid)}");
return;
}
if (!TryComp<SolutionRegenerationComponent>(uid, out var solutionRegeneration))
{
_sawmill.Error($"Entity {ToPrettyString(uid)} not have SolutionRegenerationComponent");
return;
}
if (solutionRegeneration.Generated.ContainsReagent(reagent.Reagent))
{
_popups.PopupEntity(Loc.GetString("solution-regeneration-switcher-already-select"), user, user);
return;
}
// Empty out the current solution.
if (!component.KeepSolution)
_solutionSystem.RemoveAllSolution(solution.Value);
solutionRegeneration.ChangeGenerated(reagent);
if (!PrototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto))
{
_sawmill.Error(
$"Can't get get reagent prototype {reagent.Reagent.Prototype} for {ToPrettyString(uid)}");
return;
}
_popups.PopupEntity(
Loc.GetString("solution-regeneration-switcher-switched", ("reagent", proto.LocalizedName)),
user,
user);
}
}
}

View file

@ -1,5 +1,4 @@
roles-antag-changeling-name = Changeling
roles-antag-changeling-objective = A intelligent predator that assumes the identities of its victims.
roles-antag-changeling-objective = A intelligent predator that assumes the identities of its victims.
changeling-devour-attempt-failed-rotting = This corpse has only rotted biomass.
changeling-devour-attempt-failed-protected = This victim's biomass is protected.

View file

@ -30,7 +30,6 @@ roles-antag-thief-name = Вор
roles-antag-thief-objective = Пополните свою личную коллекцию имуществом Nanotrasen, не прибегая к насилию.
roles-antag-dragon-name = Космический дракон
roles-antag-dragon-objective = Создайте армию карпов для захвата квадранта.
roles-antag-changeling-name = Генокрад
roles-antag-changeling-description = Используйте свои способности к превращению, чтобы выполнить свои задачи.
roles-antag-terminator-name = Терминатор
roles-antag-terminator-objective = Убейте цель любой ценой, от этого зависит будущее.

View file

@ -10982,8 +10982,6 @@ entities:
- type: Transform
pos: -36.5,-14.5
parent: 1
- type: Advertise
enabled: False
- proto: VendingMachineMedical
entities:
- uid: 1438
@ -10991,8 +10989,6 @@ entities:
- type: Transform
pos: -35.5,-5.5
parent: 1
- type: Advertise
enabled: False
- proto: VendingMachineSalvage
entities:
- uid: 1525

View file

@ -1,5 +1,3 @@
# abilities
- type: entity
parent: BaseAction
id: ActionRetractableItemArmBlade
@ -22,602 +20,3 @@
retractSounds:
collection: gib # Placeholder
# starting
- type: entity
parent: BaseAction
id: ActionEvolutionMenu
name: Open evolution menu
description: Opens the evolution menu.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: evolution_menu
- type: ChangelingAction
requireBiomass: false
useInLesserForm: true
- type: InstantAction
event: !type:OpenEvolutionMenuEvent {}
- type: entity
parent: BaseAction
id: ActionAbsorbDNA
name: Absorb DNA
description: Absorb the target's DNA, husking them in the process. Costs 25 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 5
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: absorb_dna
- type: ChangelingAction
chemicalCost: 5
requireBiomass: false
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
canTargetSelf: false
whitelist:
components:
- Body
event: !type:AbsorbDNAEvent {}
- type: entity
parent: BaseAction
id: ActionStingExtractDNA
name: Extract DNA sting
description: Steal your target's genetic information. Costs 25 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_extractdna
- type: ChangelingAction
chemicalCost: 15
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
canTargetSelf: false
whitelist:
components:
- Body
event: !type:StingExtractDNAEvent {}
- type: entity
parent: BaseAction
id: ActionChangelingTransformCycle
name: Cycle DNA
description: Cycle your available DNA.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: transform_cycle
- type: ChangelingAction
requireBiomass: false
useInLesserForm: true
- type: InstantAction
event: !type:ChangelingTransformCycleEvent {}
- type: entity
parent: BaseAction
id: ActionChangelingTransform
name: Transform
description: Transform into another humanoid. Doesn't come with clothes. Costs 5 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 5
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: transform
- type: ChangelingAction
chemicalCost: 5
useInLesserForm: true
- type: InstantAction
event: !type:ChangelingTransformEvent {}
- type: entity
parent: BaseAction
id: ActionEnterStasis
name: Enter regenerative stasis
description: Fake your death and start regenerating. Drains all your chemicals. Consumes biomass.
categories: [ HideSpawnMenu ]
components:
- type: Action
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: stasis_enter
- type: ChangelingAction
biomassCost: 1
useInLesserForm: true
- type: InstantAction
event: !type:EnterStasisEvent {}
- type: entity
parent: BaseAction
id: ActionExitStasis
name: Exit stasis
description: Rise from the dead with full health. Costs 60 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: stasis_exit
- type: ChangelingAction
chemicalCost: 50
useInLesserForm: true
- type: InstantAction
event: !type:ExitStasisEvent {}
# combat
- type: entity
parent: BaseAction
id: ActionToggleArmblade
name: Toggle Arm Blade
description: Reform one of your arms into a strong blade, composed of bone and flesh. Retract on secondary use. Costs 15 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 2
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: armblade
- type: ChangelingAction
chemicalCost: 15
# requireAbsorbed: 1
- type: InstantAction
event: !type:ToggleArmbladeEvent {}
- type: entity
parent: BaseAction
id: ActionCreateBoneShard
name: Form Bone Shard
description: Break off shards of your bone and shape them into a throwing star. Costs 15 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 1
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: bone_shard
- type: ChangelingAction
chemicalCost: 15
- type: InstantAction
event: !type:CreateBoneShardEvent {}
- type: entity
parent: BaseAction
id: ActionToggleChitinousArmor
name: Toggle Armor
description: Inflate your body into an all-consuming chitinous mass of armor. Costs 25 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 2
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: chitinous_armor
- type: ChangelingAction
chemicalCost: 20 #Use for equip and uneuip
# requireAbsorbed: 1
- type: InstantAction
event: !type:ToggleChitinousArmorEvent {}
- type: entity
parent: BaseAction
id: ActionToggleOrganicShield
name: Form Shield
description: Reform one of your arms into a large, fleshy shield. Costs 20 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 2
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: organic_shield
- type: ChangelingAction
chemicalCost: 15
# requireAbsorbed: 1
- type: InstantAction
event: !type:ToggleOrganicShieldEvent {}
- type: entity
parent: BaseAction
id: ActionShriekDissonant
name: Dissonant Shriek
description: Emit an EMP blast, with just your voice. Costs 30 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 25
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: shriek_dissonant
- type: ChangelingAction
chemicalCost: 30
useInLesserForm: true
# requireAbsorbed: 1
- type: InstantAction
event: !type:ShriekDissonantEvent {}
- type: entity
parent: BaseAction
id: ActionShriekResonant
name: Resonant Shriek
description: Disorient people and break lights, with just your voice. Costs 30 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 10
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: shriek_resonant
- type: ChangelingAction
chemicalCost: 10
useInLesserForm: true
# requireAbsorbed: 1
- type: InstantAction
event: !type:ShriekResonantEvent {}
- type: entity
parent: BaseAction
id: ActionToggleStrainedMuscles
name: Strain Muscles
description: Move at extremely fast speeds. Deals stamina damage.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 1
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: strained_muscles
- type: ChangelingAction
chemicalCost: 20
useInLesserForm: true
- type: InstantAction
event: !type:ToggleStrainedMusclesEvent {}
# stings
- type: entity
parent: BaseAction
id: ActionStingBlind
name: Blind Sting
description: Silently sting your target, blinding them for a short time and rendering them near sighted. Costs 35 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_blind
- type: ChangelingAction
chemicalCost: 35
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
canTargetSelf: false
whitelist:
components:
- Body
event: !type:StingBlindEvent {}
- type: entity
parent: BaseAction
id: ActionStingCryo
name: Cryogenic Sting
description: Silently sting your target, constantly slowing and freezing them. Costs 35 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_cryo
- type: ChangelingAction
chemicalCost: 45
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
canTargetSelf: false
whitelist:
components:
- Body
event: !type:StingCryoEvent {}
- type: entity
parent: BaseAction
id: ActionStingLethargic
name: Lethargic Sting
description: Silently inject a cocktail of anesthetics into the target. Costs 35 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_lethargic
- type: ChangelingAction
chemicalCost: 45
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
whitelist:
components:
- Body
canTargetSelf: false
event: !type:StingLethargicEvent {}
- type: entity
parent: BaseAction
id: ActionStingMute
name: Mute Sting
description: Silently sting your target, completely silencing them for a short time. Costs 35 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_mute
- type: ChangelingAction
chemicalCost: 35
useInLesserForm: true
- type: TargetAction
interactOnMiss: false
- type: EntityTargetAction
whitelist:
components:
- Body
canTargetSelf: false
event: !type:StingMuteEvent {}
- type: entity
parent: BaseAction
id: ActionStingFakeArmblade
name: Fake Armblade Sting
description: Silently sting your target, making them grow a dull armblade for a short time. Costs 50 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: sting_armblade
- type: TargetAction
interactOnMiss: false
- type: ChangelingAction
chemicalCost: 40
useInLesserForm: true
- type: EntityTargetAction
whitelist:
components:
- Body
canTargetSelf: false
event: !type:StingFakeArmbladeEvent {}
#- type: entity
# id: ActionStingTransform
# name: Transformation Sting
# description: Silently sting your target, transforming them into a person of your choosing. Costs 75 chemicals.
# categories: [ HideSpawnMenu ]
# components:
# - type: EntityTargetAction
# whitelist:
# components:
# - Body
# canTargetSelf: false
# interactOnMiss: false
# itemIconStyle: NoItem
# icon:
# sprite: Changeling/changeling_abilities.rsi
# state: sting_transform
# event: !type:StingTransformEvent {}
# - type: ChangelingAction
# chemicalCost: 75
# useInLesserForm: true
# utility
- type: entity
parent: BaseAction
id: ActionAnatomicPanacea
name: Anatomic Panacea
description: Cure yourself of diseases, disabilities, radiation, toxins, drunkedness and brain damage. Costs 30 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 30
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: anatomic_panacea
- type: ChangelingAction
chemicalCost: 20
useInLesserForm: true
- type: InstantAction
event: !type:ActionAnatomicPanaceaEvent {}
- type: entity
parent: BaseAction
id: ActionAugmentedEyesight
name: Augmented Eyesight
description: Toggle flash protection.
categories: [ HideSpawnMenu ]
components:
- type: Action
checkCanInteract: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: augmented_eyesight
- type: ChangelingAction
chemicalCost: 0
- type: InstantAction
event: !type:ActionAugmentedEyesightEvent {}
- type: entity
parent: BaseAction
id: ActionBiodegrade
name: Biodegrade
description: Vomit a caustic substance onto any restraints, or someone's face. Costs 30 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 5
checkCanInteract: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: biodegrade
- type: ChangelingAction
chemicalCost: 10
- type: InstantAction
event: !type:ActionBiodegradeEvent {}
- type: entity
parent: BaseAction
id: ActionChameleonSkin
name: Chameleon Skin
description: Slowly blend in with the environment. Costs 25 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 1
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: chameleon_skin
- type: ChangelingAction
chemicalCost: 8 #need lower to turn off
- type: InstantAction
event: !type:ActionChameleonSkinEvent {}
- type: entity
parent: BaseAction
id: ActionEphedrineOverdose
name: Ephedrine Overdose
description: Inject some stimulants into yourself. Costs 30 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 10
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: epinephrine_overdose
- type: ChangelingAction
chemicalCost: 25
useInLesserForm: true
- type: InstantAction
event: !type:ActionEphedrineOverdoseEvent {}
- type: entity
parent: BaseAction
id: ActionFleshmend
name: Fleshmend
description: Rapidly heal yourself. Costs 35 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 30
checkCanInteract: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: fleshmend
- type: ChangelingAction
chemicalCost: 35
useInLesserForm: true
- type: InstantAction
event: !type:ActionFleshmendEvent {}
- type: entity
parent: BaseAction
id: ActionToggleLesserForm
name: Lesser Form
description: Abandon your current form and transform into a monkey. Costs 20 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 5
checkCanInteract: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: lesser_form
- type: ChangelingAction
chemicalCost: 10
- type: InstantAction
event: !type:ActionLesserFormEvent {}
- type: entity
parent: BaseAction
id: ActionToggleSpacesuit
name: Toggle Space Suit
description: Make your body space proof. Costs 20 chemicals.
categories: [ HideSpawnMenu ]
components:
- type: Action
useDelay: 2
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: space_adaptation
- type: ChangelingAction
chemicalCost: 20
- type: InstantAction
event: !type:ActionSpacesuitEvent {}
- type: entity
parent: BaseAction
id: ActionHivemindAccess
name: Hivemind Access
description: Tune your chemical receptors for hivemind communication.
categories: [ HideSpawnMenu ]
components:
- type: Action
checkCanInteract: false
checkConsciousness: false
itemIconStyle: NoItem
icon:
sprite: Changeling/changeling_abilities.rsi
state: hivemind_access
- type: ChangelingAction
chemicalCost: 0
useInLesserForm: true
- type: InstantAction
event: !type:ActionHivemindAccessEvent {}

View file

@ -1,35 +0,0 @@
- type: alert
id: ChangelingChemicals
icons:
- sprite: /Textures/Changeling/changeling_chemicals.rsi
state: 0
alertViewEntity: AlertChangelingChemicalsSpriteView
name: alerts-changeling-chemicals-name
description: alerts-changeling-chemicals-desc
- type: alert
id: ChangelingBiomass
icons:
- sprite: /Textures/Changeling/changeling_biomass.rsi
state: 0
alertViewEntity: AlertChangelingBiomassSpriteView
name: alerts-changeling-biomass-name
description: alerts-changeling-biomass-desc
- type: entity
id: AlertChangelingChemicalsSpriteView
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: /Textures/Changeling/changeling_chemicals.rsi
layers:
- map: [ "enum.AlertVisualLayers.Base" ]
- type: entity
id: AlertChangelingBiomassSpriteView
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: /Textures/Changeling/changeling_biomass.rsi
layers:
- map: [ "enum.AlertVisualLayers.Base" ]

View file

@ -169,7 +169,7 @@
- id: HoloprojectorSecurity
- id: BoxEvidenceMarkers
- id: HandLabeler
- id: PortableSurveillanceCameraMonitor # Sunrise-edit
- id: PortableSurveillanceCameraMonitor # Sunrise-edit
- type: entity
id: ClosetBombFilled

View file

@ -1049,20 +1049,3 @@
color: "#f4ffad"
radius: 5
energy: 2
- type: entity
parent: ClothingHeadHardsuitBase
id: ChangelingClothingHeadHelmetHardsuit
name: organic space helmet
description: A spaceworthy biomass of pressure and temperature resistant tissue.
suffix: Unremoveable
components:
- type: Item
- type: Sprite
sprite: Changeling/ling_spacesuit_helmet.rsi
- type: Clothing
sprite: Changeling/ling_spacesuit_helmet.rsi
- type: PressureProtection
highPressureMultiplier: 0.225
lowPressureMultiplier: 1000
- type: Unremoveable

View file

@ -625,24 +625,3 @@
- type: Construction
graph: cardHelmet
node: cardhelmet
- type: entity
parent: ClothingHeadBase
id: ChangelingClothingHeadHelmet
name: chitinous helmet
description: An all-consuming chitinous mass of armor.
suffix: Unremoveable
components:
- type: Sprite
sprite: Changeling/ling_armor_helmet.rsi
- type: Clothing
sprite: Changeling/ling_armor_helmet.rsi
- type: Pierceable
level: Metal
- type: Armor
modifiers:
coefficients:
Blunt: 0.9
Slash: 0.9
Piercing: 0.9
Heat: 0.9
- type: Unremoveable

View file

@ -593,39 +593,3 @@
- type: Construction
graph: cardArmour
node: cardarmour
- type: entity
parent: ClothingOuterBaseLarge
id: ChangelingClothingOuterArmor
name: chitinous armor
description: An all-consuming chitinous mass of armor.
suffix: Unremoveable
components:
- type: Sprite
sprite: Changeling/ling_armor.rsi
- type: Clothing
sprite: Changeling/ling_armor.rsi
- type: Pierceable
level: Metal
- type: Armor
modifiers:
coefficients:
Blunt: 0.5
Slash: 0.5
Piercing: 0.5
Heat: 0.5
Radiation: 0.5
Caustic: 0.5
- type: ClothingSpeedModifier
walkModifier: 0.7
sprintModifier: 0.65
- type: HeldSpeedModifier
- type: ExplosionResistance
damageCoefficient: 0.5
- type: GroupExamine
- type: Unremoveable
# Sunrise-Start
- type: Tag
tags:
- FullBodyOuter
- WhitelistChameleon
# Sunrise-End

View file

@ -1218,37 +1218,3 @@
- type: HeldSpeedModifier
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitSanta
- type: entity
parent: [ ClothingOuterBaseLarge, AllowSuitStorageClothing ]
id: ChangelingClothingOuterHardsuit
name: organic space suit
description: A spaceworthy biomass of pressure and temperature resistant tissue.
suffix: Unremoveable
components:
- type: Sprite
sprite: Changeling/ling_spacesuit.rsi
- type: Clothing
sprite: Changeling/ling_spacesuit.rsi
- type: PressureProtection
highPressureMultiplier: 0.225
lowPressureMultiplier: 1000
- type: TemperatureProtection
heatingCoefficient: 0.01
coolingCoefficient: 0.01
- type: ExplosionResistance
damageCoefficient: 0.2
- type: Pierceable
level: Flesh
- type: Armor
modifiers:
coefficients:
Blunt: 0.95
Slash: 0.95
Piercing: 1
Heat: 0.5
- type: ClothingSpeedModifier
walkModifier: 0.9
sprintModifier: 0.9
- type: HeldSpeedModifier
- type: Unremoveable

View file

@ -1,9 +0,0 @@
- type: entity
id: GuidebookChangelingFluff
name: guidebook changeling
description: you shouldn't be seeing this normally.
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: Changeling/Guidebook/guidebook_changeling.rsi
state: icon

View file

@ -123,7 +123,7 @@
preventSuicide: true
mobState:
- Critical
- type: OnUseTimerTrigger
- type: TimerTrigger
delay: 3
initialBeepDelay: 0
beepInterval: 3

View file

@ -8,7 +8,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: Body
prototype: Arachnid
requiredLegs: 2 # It would be funny if arachnids could use their little back limbs to move around once they lose their legs, but just something to consider post-woundmed

View file

@ -393,7 +393,6 @@
- type: Body
prototype: Human
requiredLegs: 2
- type: Absorbable
- type: UserInterface
interfaces:
enum.HumanoidMarkingModifierKey.Key: # sure, this can go here too

View file

@ -5,7 +5,6 @@
id: BaseMobDiona
abstract: true
components:
- type: Absorbable
- type: HumanoidAppearance
species: Diona
- type: Hunger

View file

@ -8,7 +8,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: Hunger
- type: Thirst
baseDecayRate: 0.2

View file

@ -5,7 +5,6 @@
id: BaseMobGingerbread
abstract: true
components:
- type: Absorbable
- type: HumanoidAppearance
species: Gingerbread
- type: Icon

View file

@ -8,7 +8,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: Hunger
- type: Icon # It will not have an icon in the adminspawn menu without this. Body parts seem fine for whatever reason.
sprite: _Sunrise/Mobs/Species/Human/Basic/parts.rsi

View file

@ -8,7 +8,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: HumanoidAppearance
species: Moth
hideLayersOnEquip:

View file

@ -8,7 +8,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: HumanoidAppearance
species: Reptilian
hideLayersOnEquip:

View file

@ -47,7 +47,6 @@
type: SurgeryBui
enum.VampireMutationUiKey.Key:
type: VampireMutationBoundUserInterface
- type: Absorbable
# Sunrise-end
- type: UseDelay
delay: 0.5

View file

@ -6,7 +6,6 @@
# SUNRISE EDIT
- type: Interactions
# SUNRISE EDIT
- type: Absorbable
- type: Hunger
- type: Thirst
dehydrationDamage:

View file

@ -145,7 +145,7 @@
- type: TriggerOnMobstateChange
mobState:
- Critical
- type: Rattle
- type: RattleOnTrigger
radioChannel: "CentCom"
#Sunrise-end
@ -260,11 +260,11 @@
components:
- type: SubdermalImplant
implantAction: ActionActivateSmokeGrenadeImplant
- type: TriggerImplantAction
- type: TriggerOnActivateImplant
- type: SmokeOnTrigger
duration: 20
spreadAmount: 30
- type: SoundOnTrigger
- type: EmitSoundOnTrigger
sound: /Audio/Items/smoke_grenade_smoke.ogg
#Sunrise-end
@ -477,7 +477,7 @@
description: This implant will inform the Centcomm radio channel should the user fall into critical condition or die.
categories: [ HideSpawnMenu ]
components:
- type: Rattle
- type: RattleOnTrigger
radioChannel: BlueShield
- type: entity

View file

@ -105,9 +105,9 @@
sprite: _Sunrise/Objects/Weapons/Melee/shields.rsi
layers:
- state: riot-icon
map: [ "enum.FlashVisuals.BaseLayer" ]
map: [ "enum.FlashVisualLayers.BaseLayer" ]
- state: flashing
map: [ "enum.FlashVisuals.LightLayer" ]
map: [ "enum.FlashVisualLayers.LightLayer" ]
visible: false
shader: unshaded
- type: Flash
@ -131,10 +131,10 @@
- type: GenericVisualizer
visuals:
enum.FlashVisuals.Burnt:
enum.FlashVisuals.BaseLayer:
enum.FlashVisualLayers.BaseLayer:
True: {state: burnt}
enum.FlashVisuals.Flashing:
enum.FlashVisuals.LightLayer:
enum.FlashVisualLayers.LightLayer:
True: {visible: true}
False: {visible: false}
- type: StaticPrice
@ -713,35 +713,3 @@
max: 2
- type: StaticPrice
price: 150
- type: entity
parent: BaseShield
id: ChangelingShield
name: oraganic shield
description: A large, fleshy shield.
suffix: Unremoveable
components:
- type: Unremoveable
- type: Sprite
sprite: Changeling/shields.rsi
state: ling-icon
- type: Item
sprite: Changeling/shields.rsi
heldPrefix: ling
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 120
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTrigger
damage: 110
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak

View file

@ -680,7 +680,7 @@
- item: GasAnalyzer
- item: HolofanProjectorBorg
- item: GeigerCounter
- AtmosAlertsMonitorUnpowered
- item: AtmosAlertsMonitorUnpowered
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: rcd-module }

View file

@ -1576,7 +1576,7 @@
Blunt: 5
deleteOnCollide: false
- type: StartTimerOnShoot
- type: OnUseTimerTrigger
- type: TimerTrigger
delay: 2
- type: Fixtures
fixtures:

View file

@ -113,21 +113,9 @@
- type: StaticPrice
price: 500
# Sunrise start
- type: MeleeWeapon
wideAnimationRotation: -135
damage:
types:
Piercing: 15
Bloodloss: 2
angle: 0
animation: WeaponArcThrust
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Gun
pump: true
fireRate: 1
- type: AltFireMelee
attackType: Heavy
# Sunrise end
- type: entity

View file

@ -1,47 +0,0 @@
- type: entity
parent: ArmBlade
id: ArmBladeChangeling
suffix: Unremoveable
components:
- type: Sharp
- type: Sprite
sprite: Changeling/arm_blade.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 90
attackRate: 0.75
damage:
types:
Slash: 20
Piercing: 10
Structural: 20
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Item
size: Ginormous
sprite: Changeling/arm_blade.rsi
- type: Prying
pryPowered: true
- type: Unremoveable
- type: Tool
qualities:
- Slicing
- Prying
- type: DisarmMalus
malus: 0
- type: entity
parent: ArmBladeChangeling
id: FakeArmBladeChangeling
components:
- type: MeleeWeapon
wideAnimationRotation: 90
attackRate: 0.75
damage:
types:
Blunt: 1
Slash: 1
Piercing: 1
Structural: 1
- type: TimedDespawn
lifetime: 60

View file

@ -495,7 +495,7 @@
- timer
duration: 45 # Sunrise-Edit
spreadAmount: 50
- type: SoundOnTrigger
- type: EmitSoundOnTrigger
sound:
path: /Audio/_Sunrise/sg_explode.ogg # Sunrise-Edit
params:
@ -652,7 +652,7 @@
sound:
path: /Audio/Effects/Emotes/parp1.ogg
- type: Appearance
- type: OnUseTimerTrigger
- type: TimerTrigger
beepSound:
path: "/Audio/Effects/beep1.ogg"
params:

View file

@ -51,16 +51,3 @@
# also limits the crew's use
- type: TimedDespawn
lifetime: 30
- type: entity
parent: ThrowingStar
id: ThrowingStarChangeling
name: bone shard
components:
- type: Sprite
sprite: Changeling/bone_shard.rsi
layers:
- state: icon
map: ["base"]
- type: TimedDespawn
lifetime: 30

View file

@ -303,7 +303,7 @@
suffix: Mining(Salvage)
components:
- type: Sprite
sprite: _Sunrise/Structures/Doors/Airlocks/Glass/mining.rsi
sprite: Structures/Doors/Airlocks/Glass/mining.rsi
- type: Paintable
group: null

View file

@ -22,8 +22,6 @@
rules:
- id: Thief
prob: 0.3
- id: Changeling
prob: 0.3
- id: Vampire
prob: 0.3
- id: SubWizard
@ -37,8 +35,6 @@
rules:
- id: Thief
prob: 0.3
- id: Changeling
prob: 0.3
- id: Vampire
prob: 0.3

View file

@ -1,23 +0,0 @@
- type: entity
abstract: true
parent: BaseObjective
id: BaseChangelingObjective
components:
- type: Objective
issuer: objective-issuer-changeling
difficulty: 1
- type: RoleRequirement
roles:
- ChangelingRole
- type: entity
parent: [BaseChangelingObjective, BaseSurviveObjective]
id: ChangelingSurviveObjective
name: Survive.
description: We must stay alive at all cost.
components:
- type: Objective
difficulty: 1
icon:
sprite: Mobs/Species/Human/organs.rsi
state: heart-on

View file

@ -253,31 +253,3 @@
damage:
types:
Cellular: 2
- type: reagent
parent: Blood
id: BloodChangeling
- type: reaction
id: ChangelingBloodBreakdown
source: true
requiredMixerCategories:
- Centrifuge
reactants:
BloodChangeling:
amount: 5
products:
Water: 11
Iron: 0.5
Sugar: 2
CarbonDioxide: 3
Protein: 4
effects:
- !type:CreateEntityReactionEffect
entity: FleshKudzu
- !type:ExplosionReactionEffect
explosionType: Default
maxIntensity: 2
intensityPerUnit: 0.5
intensitySlope: 4
maxTotalIntensity: 1

View file

@ -146,12 +146,15 @@
metabolisms:
Medicine:
effects:
#Sunrise-Start
- !type:HealthChange
damage:
types:
Mangleness: 0.1
#Sunrise-End
- !type:EvenHealthChange
damage:
types: #Sunrise-Edit
Mangleness: 0.1 #Sunrise-Edit
groups:
Brute: -1.5
Brute: -1.5
- !type:HealthChange
conditions:
- !type:ReagentThreshold

View file

@ -163,10 +163,6 @@
# Exosuit
- type: latheCategory
id: Mech
name: lathe-category-mechs
- type: latheCategory
id: Vim
name: lathe-category-mechs-vim

View file

@ -45,19 +45,7 @@
icon:
sprite: /Textures/Interface/Misc/job_icons.rsi
state: HeadRevolutionary
- type: factionIcon
id: HivemindFaction
isShaded: true
priority: 11
showTo:
components:
- ShowAntagIcons
- Hivemind
icon:
sprite: /Textures/Interface/Misc/job_icons.rsi
state: Changeling
- type: factionIcon
id: VampireFaction
isShaded: true

View file

@ -108,20 +108,3 @@
id: DiscountedItems
name: store-discounted-items
priority: 200
# changeling
- type: storeCategory
id: ChangelingAbilityCombat
name: store-ling-category-combat
priority: 0
- type: storeCategory
id: ChangelingAbilitySting
name: store-ling-category-sting
priority: 1
- type: storeCategory
id: ChangelingAbilityUtility
name: store-ling-category-utility
priority: 2

View file

@ -43,8 +43,3 @@
- type: currency
id: DebugDollar
displayName: store-currency-display-debugdollar
- type: currency
id: EvolutionPoint
displayName: store-currency-display-evolutionpoints
canWithdraw: false

View file

@ -150,8 +150,9 @@
interactFailureString: petting-failure-medibot
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: Advertise
pack: MedibotAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: MedibotAds
- type: Inventory
templateId: medibot

View file

@ -1017,8 +1017,8 @@
polymorph: AdmemeForcedJohnToe
- type: TriggerOnCollide
fixtureID: projectile
- type: TriggerWhitelist
whitelist:
- type: WhitelistTriggerCondition
userWhitelist:
components:
- Body

View file

@ -16,7 +16,7 @@
suffix: Gravity
parent: GlandEffectBase
components:
- type: SoundOnTrigger
- type: EmitSoundOnTrigger
removeOnTrigger: true
sound:
path: /Audio/Effects/Grenades/Supermatter/supermatter_start.ogg

View file

@ -266,7 +266,7 @@
preventSuicide: true
mobState:
- Critical
- type: OnUseTimerTrigger
- type: TimerTrigger
delay: 3
initialBeepDelay: 0
beepInterval: 3
@ -377,7 +377,7 @@
preventSuicide: true
mobState:
- Critical
- type: OnUseTimerTrigger
- type: TimerTrigger
delay: 3
initialBeepDelay: 0
beepInterval: 3

View file

@ -8,7 +8,6 @@
id: BaseMobAbductor
abstract: true
components:
#- type: Absorbable Starlight: Done on purpose so the abductors don't get absorbed.
- type: Muted
- type: HumanoidAppearance
species: Abductor

View file

@ -6,7 +6,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: HumanoidAppearance
species: Demon
- type: Hunger

View file

@ -7,7 +7,6 @@
components:
- type: Interactions
- type: MultiHandedItem
- type: Absorbable
- type: OwOAccent
- type: Speech
speechVerb: Felinid

View file

@ -6,7 +6,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: Respirator
damage:
types:

View file

@ -6,7 +6,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: Hunger
- type: Icon # It will not have an icon in the adminspawn menu without this. Body parts seem fine for whatever reason.
sprite: _Sunrise/Mobs/Species/Predator/parts.rsi

View file

@ -5,7 +5,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: HumanoidAppearance
species: Swine
- type: Hunger

View file

@ -4,7 +4,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: HumanoidAppearance
species: Tajaran
hideLayersOnEquip:

View file

@ -14,7 +14,6 @@
abstract: true
components:
- type: Interactions
- type: Absorbable
- type: Speech
speechVerb: Vulpkanin
allowedEmotes: ['Growl', 'Bark', 'Howl', 'Whines']

View file

@ -5,7 +5,7 @@
id: FakeGrenade
parent: GrenadeBase
components:
- type: OnUseTimerTrigger
- type: TimerTrigger
delay: 3
beepInterval: 0.46
beepSound:

View file

@ -8,10 +8,10 @@
- state: NT
- state: icon-NT
- type: ItemBorgModule
items:
- WeaponPulseCarbineBorg
- WeaponPulseCarbineBorg
- PinpointerNuclear
hands:
- item: WeaponPulseCarbineBorg
- item: WeaponPulseCarbineBorg
- item: PinpointerNuclear
- type: BorgModuleIcon
icon: {sprite: Objects/Weapons/Guns/Battery/pulse_carbine.rsi, state: base}
@ -25,10 +25,10 @@
- state: NT
- state: icon-NT
- type: ItemBorgModule
items:
- StunbatonBorg
- WeaponDisablerSMGBorg
- FlashBorg
hands:
- item: StunbatonBorg
- item: WeaponDisablerSMGBorg
- item: FlashBorg
- type: BorgModuleIcon
icon: {sprite: Objects/Weapons/Melee/stunbaton.rsi, state: stunbaton_off}
@ -42,12 +42,12 @@
- state: NT
- state: icon-NT
- type: ItemBorgModule
items:
- JawsOfLife
- PowerDrill
- Multitool
- WelderBorg
- RemoteSignallerAdvanced
hands:
- item: JawsOfLife
- item: PowerDrill
- item: Multitool
- item: WelderBorg
- item: RemoteSignallerAdvanced
- type: BorgModuleIcon
icon: {sprite: Interface/Actions/actions_borg.rsi, state: adv-tools-module}
@ -61,11 +61,11 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- LaserMinigunBorg
- HeavyRifleBorg
- WeaponLauncherDusterBorg
- PinpointerNuclear
hands:
- item: LaserMinigunBorg
- item: HeavyRifleBorg
- item: WeaponLauncherDusterBorg
- item: PinpointerNuclear
- type: entity
id: BorgScoutModuleSyndicateCombat
@ -77,10 +77,10 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- WeaponIAR52Borg
- CombatKnife
- HypoBorgSaboteurSyndicate
hands:
- item: WeaponIAR52Borg
- item: CombatKnife
- item: HypoBorgSaboteurSyndicate
- type: entity
id: BorgScoutModuleSyndicateTool
@ -92,13 +92,13 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- RadioJammerBorg
- JetpackVoidFilled
- trayScanner
- WelderExperimental
- Multitool
- PowerDrill
hands:
- item: RadioJammerBorg
- item: JetpackVoidFilled
- item: trayScanner
- item: WelderExperimental
- item: Multitool
- item: PowerDrill
- type: entity
id: BaseBorgModuleSecurity
@ -128,10 +128,10 @@
- state: security
- state: icon-stuh
- type: ItemBorgModule
items:
- WeaponDisablerBorg
- StunbatonBorg
- FlashBorg
hands:
- item: WeaponDisablerBorg
- item: StunbatonBorg
- item: FlashBorg
- type: entity
id: BorgModuleAdvancedCombat
@ -143,11 +143,11 @@
- state: security
- state: icon-combat
- type: ItemBorgModule
items:
- Truncheon
- WeaponLaserBorg
- WeaponLaserBorg
- HoloprojectorSecurityBorg
hands:
- item: Truncheon
- item: WeaponLaserBorg
- item: WeaponLaserBorg
- item: HoloprojectorSecurityBorg
- type: entity
id: BorgModuleCombat
@ -159,11 +159,11 @@
- state: security
- state: icon-combat
- type: ItemBorgModule
items:
- CombatKnife
- WeaponLaserBorg
- FlashBorg
- HoloprojectorSecurityBorg
hands:
- item: CombatKnife
- item: WeaponLaserBorg
- item: FlashBorg
- item: HoloprojectorSecurityBorg
- type: entity
id: BorgModulePeace
@ -175,9 +175,9 @@
- state: security
- state: icon-peace
- type: ItemBorgModule
items:
- FlashBorg
- HypoBorgPeace
hands:
- item: FlashBorg
- item: HypoBorgPeace
- type: entity
id: BorgModuleMiningCombat
@ -189,9 +189,9 @@
- state: cargo
- state: icon-mining
- type: ItemBorgModule
items:
- WeaponProtoKineticAcceleratorBorg
- WeaponCrusherDagger
hands:
- item: WeaponProtoKineticAcceleratorBorg
- item: WeaponCrusherDagger
- type: BorgModuleIcon
icon: { sprite: Objects/Weapons/Guns/Basic/kinetic_accelerator.rsi, state: icon }
@ -205,8 +205,8 @@
- state: cargo
- state: icon-mining
- type: ItemBorgModule
items:
- JetpackVoidFilled
hands:
- item: JetpackVoidFilled
- type: BorgModuleIcon
icon: { sprite: Objects/Tanks/Jetpacks/void.rsi, state: icon }
@ -220,10 +220,10 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- SyndicateJawsOfLife
- PinpointerNuclear
- HypoBorgStandardSyndicate
hands:
- item: SyndicateJawsOfLife
- item: PinpointerNuclear
- item: HypoBorgStandardSyndicate
- type: entity
id: BorgModuleSyndicateMedical
@ -235,11 +235,11 @@
- state: syndicate
- state: icon-syndicate-treatment
- type: ItemBorgModule
items:
- SawAdvanced
- WeaponPistolEchis #Todo: Заменить на вариант Шприцемета с выбором снарядов
- HypoBorgMedicalSyndicate
- DefibrillatorOneHandedUnpowered
hands:
- item: SawAdvanced
- item: WeaponPistolEchis #Todo: Заменить на вариант Шприцемета с выбором снарядов
- item: HypoBorgMedicalSyndicate
- item: DefibrillatorOneHandedUnpowered
- type: entity
id: BorgModuleSyndicateCombat
@ -251,10 +251,10 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- WeaponLightMachineGunL6C
- EnergySword
- PinpointerNuclear
hands:
- item: WeaponLightMachineGunL6C
- item: EnergySword
- item: PinpointerNuclear
- type: entity
id: BorgModuleStandart
@ -266,10 +266,10 @@
- state: generic
- state: icon-fire-extinguisher
- type: ItemBorgModule
items:
- CrowbarBorg
- FireExtinguisherBorg
- HypoBorgStandard
hands:
- item: CrowbarBorg
- item: FireExtinguisherBorg
- item: HypoBorgStandard
- type: entity
id: BorgERTModuleStandard
@ -281,9 +281,9 @@
- state: NT
- state: icon-NT
- type: ItemBorgModule
items:
- CrowbarBorg
- FireExtinguisherBorg
- HypoBorgStandardERT
hands:
- item: CrowbarBorg
- item: FireExtinguisherBorg
- item: HypoBorgStandardERT
- type: BorgModuleIcon
icon: { sprite: _Sunrise/Objects/Tools/items_cyborg.rsi, state: crowbar_cyborg }

View file

@ -89,9 +89,9 @@
sprite: Objects/Weapons/Melee/flash.rsi
layers:
- state: burnt
map: [ "enum.FlashVisuals.BaseLayer" ]
map: [ "enum.FlashVisualLayers.BaseLayer" ]
- state: flashing
map: [ "enum.FlashVisuals.LightLayer" ]
map: [ "enum.FlashVisualLayers.LightLayer" ]
visible: false
shader: unshaded
- type: LimitedCharges

View file

@ -232,7 +232,7 @@
- type: EmitSoundOnTrigger
sound:
path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 3.5
@ -345,17 +345,14 @@
- state: primed
- type: FlashOnTrigger
range: 7
- type: SoundOnTrigger
- type: EmitSoundOnTrigger
sound:
path: "/Audio/_Sunrise/flashbang.ogg" # Sunrise-Edit
params:
volume: 20
- type: EmitSoundOnTrigger
sound:
path: "/Audio/Effects/flash_bang.ogg"
- type: SpawnOnTrigger
proto: GrenadeFlashEffect
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 2.75
@ -384,7 +381,7 @@
- type: EmitSoundOnTrigger
sound:
path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 5
@ -415,7 +412,7 @@
path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
- type: SpawnOnTrigger
proto: GrenadeFlashEffect
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 3.5
@ -445,7 +442,7 @@
path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg"
- type: SpawnOnTrigger
proto: GrenadeFlashEffect
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 3.5
@ -475,7 +472,7 @@
path: "/Audio/Effects/flash_bang.ogg"
- type: SpawnOnTrigger
proto: GrenadeFlashEffect
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 2
delay: 3.5

View file

@ -23,7 +23,7 @@
intensitySlope: 3
totalIntensity: 100
canCreateVacuum: false
- type: OnUseTimerTrigger
- type: TimerTrigger
beepSound:
path: "/Audio/Effects/beep1.ogg"
params:

View file

@ -13,7 +13,7 @@
capacity: 20
fillPrototype: SyndyFlashGrenade
distance: 4
- type: OnUseTimerTrigger
- type: TimerTrigger
initialBeepDelay: 0
beepInterval: 0.5
delay: 3.5
@ -49,7 +49,7 @@
fillPrototype: SyndieMiniBomb
distance: 4
capacity: 3
- type: OnUseTimerTrigger
- type: TimerTrigger
beepSound:
path: "/Audio/Effects/minibombcountdown.ogg"
params:

View file

@ -9,8 +9,9 @@
offState: off
brokenState: broken
normalState: normal-unshaded
- type: Advertise
pack: BarberAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: BarberAds
- type: AccessReader
access: [["Barber", "Service"]]
- type: SpeakOnUIClosed
@ -41,8 +42,9 @@
brokenState: broken
normalState: normal-unshaded
initialStockQuality: 0.33
- type: Advertise
pack: DiscountDansAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: DiscountDansAds
- type: SpeakOnUIClosed
pack: DiscountDansGoodbyes
- type: Speech
@ -75,8 +77,9 @@
normalState: normal-unshaded
ejectState: eject-unshaded
denyState: deny-unshaded
- type: Advertise
pack: HonkersAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: HonkersAds
- type: AccessReader
access: [["Theatre"]]
- type: SpeakOnUIClosed

View file

@ -316,7 +316,7 @@
- type: TriggerOnMobstateChange
mobState:
- Dead
- type: TriggerImplantAction
- type: TriggerOnActivateImplant
- type: ExplodeOnTrigger
- type: Explosive
explosionType: Flesh

View file

@ -1,25 +1,40 @@
- type: entity
parent: SpiderWeb
parent: SpiderWebBase
id: FleshSpiderWeb
name: spider web
description: It's stringy and sticky.
placement:
mode: SnapgridCenter
snap:
- Wall
components:
- type: Sprite
sprite: _Sunrise/FleshCult/fleshspiderweb.rsi
layers:
- state: spider_web_1
map: [ "spiderWebLayer" ]
drawdepth: WallMountedItems
- type: GenericVisualizer
visuals:
enum.SpiderWebVisuals.Variant:
spiderWebLayer:
1: {state: spider_web_1}
2: {state: spider_web_2}
color: "#f02b1d"
- type: Fixtures
fixtures:
fix1:
hard: false
density: 7
shape:
!type:PhysShapeAabb
bounds: "-0.5,-0.5,0.5,0.5"
layer:
- MidImpassable
- type: Destructible
thresholds:
- trigger: # Excess damage, don't spawn entities
!type:DamageTrigger
damage: 50
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- trigger:
!type:DamageTrigger
damage: 10
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:SpawnEntitiesBehavior
spawn:
MaterialWebSilk:
min: 0
max: 1
- type: SpeedModifierContacts
walkSpeedModifier: 0.2
sprintSpeedModifier: 0.2

View file

@ -1,30 +1,3 @@
- type: entity
parent: BaseGameRule
id: Changeling
components:
- type: GameRule
delay:
min: 600
max: 900
- type: ChangelingRule
- type: AntagObjectives
objectives:
- ChangelingStealDNAObjective
- ChangelingSurviveObjective
- type: AntagRandomObjectives
sets:
- groups: ChangelingObjectiveGroups
maxDifficulty: 7
- type: AntagSelection
agentName: changeling-roundend-name
definitions:
- prefRoles: [ Changeling ]
max: 3
playerRatio: 30
lateJoinAdditional: true
mindRoles:
- MindRoleChangeling
- type: entity
parent: BaseGameRule
id: Vampire

View file

@ -1,197 +0,0 @@
- type: entity
abstract: true
parent: BaseObjective
id: BaseChangelingObjective
components:
- type: Objective
difficulty: 1.5
issuer: objective-issuer-hivemind
- type: RoleRequirement
roles:
- ChangelingRole
- type: entity
parent: [BaseChangelingObjective, BaseSurviveObjective]
id: ChangelingSurviveObjective
name: Survive
description: I must survive no matter what.
components:
- type: Objective
icon:
sprite: Changeling/changeling_abilities.rsi
state: stasis_exit
#Kill
- type: entity
parent: [BaseChangelingObjective, BaseKillObjective]
id: ChangelingKillRandomPersonObjective
description: Do it however you like, just make sure they don't make it to centcomm.
components:
- type: Objective
difficulty: 2.5
unique: false
- type: TargetObjective
title: objective-condition-kill-person-title
- type: PickRandomPerson
- type: KillPersonCondition
requireDead: true
- type: entity
parent: [BaseChangelingObjective, BaseKillObjective]
id: ChangelingKillRandomAntagObjective
description:
components:
- type: Objective
difficulty: 3.0
unique: true
- type: TargetObjective
title: objective-condition-kill-antag-title
- type: PickRandomAntag
- type: KillPersonCondition
requireDead: true
- type: entity
parent: BaseChangelingObjective
id: ChangelingAbsorbObjective
components:
- type: Objective
difficulty: 0
icon:
sprite: Mobs/Demons/abomination.rsi
state: dead
- type: NumberObjective
min: 2
max: 4
title: objective-condition-absorb-title
description: objective-condition-absorb-description
- type: AbsorbCondition
- type: entity
parent: BaseChangelingObjective
id: ChangelingStealDNAObjective
components:
- type: Objective
difficulty: 0
icon:
sprite: Mobs/Species/Human/organs.rsi
state: brain
- type: NumberObjective
min: 6
max: 9
title: objective-condition-stealdna-title
description: objective-condition-stealdna-description
- type: StealDNACondition
- type: entity
parent: BaseChangelingObjective
id: EscapeIdentityObjective
description: I need to escape on the evacuation shuttle. Undercover.
components:
- type: Objective
difficulty: 0
icon:
sprite: Objects/Magic/magicactions.rsi
state: blink
- type: ImpersonateCondition
- type: TargetObjective
title: objective-condition-escape-identity-title
- type: PickRandomPerson
- type: entity
abstract: true
parent: [BaseChangelingObjective, BaseStealObjective]
id: BaseChangelingStealObjective
components:
- type: StealCondition
verifyMapExistence: true
- type: Objective
difficulty: 2.75
- type: ObjectiveLimit
limit: 2
- type: entity
parent: BaseChangelingStealObjective
id: CMOHyposprayChangelingStealObjective
components:
- type: NotJobRequirement
job: ChiefMedicalOfficer
- type: StealCondition
owner: job-name-cmo
stealGroup: Hypospray
- type: entity
parent: BaseChangelingStealObjective
id: RDHardsuitChangelingStealObjective
components:
- type: NotJobRequirement
job: ResearchDirector
- type: StealCondition
owner: job-name-rd
stealGroup: ClothingOuterHardsuitRd
- type: Objective
difficulty: 1
- type: entity
parent: BaseChangelingStealObjective
id: EnergyShotgunChangelingStealObjective
components:
- type: Objective
difficulty: 2
- type: NotJobRequirement
job: HeadOfSecurity
- type: StealCondition
stealGroup: WeaponEnergyShotgun
owner: job-name-hos
- type: entity
parent: BaseChangelingStealObjective
id: MagbootsChangelingStealObjective
components:
- type: NotJobRequirement
job: ChiefEngineer
- type: StealCondition
stealGroup: ClothingShoesBootsMagAdv
owner: job-name-ce
- type: entity
parent: BaseChangelingStealObjective
id: ClipboardChangelingStealObjective
components:
- type: NotJobRequirement
job: Quartermaster
- type: StealCondition
stealGroup: BoxFolderQmClipboard
owner: job-name-qm
- type: entity
abstract: true
parent: BaseChangelingStealObjective
id: BaseCaptainChangelingObjective
components:
- type: Objective
difficulty: 2.5
- type: NotJobRequirement
job: Captain
- type: entity
parent: BaseCaptainChangelingObjective
id: CaptainIDChangelingStealObjective
components:
- type: StealCondition
stealGroup: CaptainIDCard
- type: entity
parent: BaseCaptainChangelingObjective
id: CaptainJetpackChangelingStealObjective
components:
- type: StealCondition
stealGroup: JetpackCaptainFilled
- type: entity
parent: BaseCaptainChangelingObjective
id: CaptainGunChangelingStealObjective
components:
- type: StealCondition
stealGroup: WeaponAntiqueLaser
owner: job-name-captain

View file

@ -42,17 +42,6 @@
roleType: TeamAntagonist
- type: PlanetPrisonerRole
- type: entity
parent: BaseMindRoleAntag
id: MindRoleChangeling
name: Changeling Role
components:
- type: MindRole
antagPrototype: Changeling
exclusiveAntag: true
roleType: SoloAntagonist
- type: ChangelingRole
- type: entity
parent: BaseMindRoleAntag
id: MindRoleVampire

View file

@ -93,8 +93,9 @@
visible: false
- type: Computer
board: FPIATMComputerCircuitboard
- type: Advertise
pack: ATMAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: ATMAds
minimumWait: 120
maximumWait: 240
- type: SpeakOnUIClosed

View file

@ -31,8 +31,9 @@
# brokenState: broken
# normalState: normal-unshaded
# ejectState: eject-unshaded No sprite, see chefvend/dinnerware/BODA/etc for expamples
#- type: Advertise
# pack: MailDrobeAds
# - type: Vocalizer
# - type: DatasetVocalizer
# dataset: MailDrobeAds
- type: Sprite
sprite: _Sunrise/Structures/Machines/VendingMachines/maildrobe.rsi
layers:
@ -80,8 +81,9 @@
brokenState: broken
normalState: normal-unshaded
denyState: deny-unshaded
- type: Advertise
pack: PaintVendAds
- type: Vocalizer
- type: DatasetVocalizer
dataset: PaintVendAds
- type: Sprite
sprite: _Sunrise/Structures/Machines/VendingMachines/paintvend.rsi
layers:

View file

@ -1,21 +1,3 @@
- type: npcFaction
id: Changeling
hostile:
- NanoTrasen
- Syndicate
- SimpleHostile
- Xeno
- Zombie
- PetsNT
- Revolutionary
- AllHostile
- Thief
- Carps
- Vampire
- Flesh
- FleshHuman
- BloodCult
- type: npcFaction
id: Thief
hostile:
@ -26,7 +8,6 @@
- Zombie
- AllHostile
- Carps
- Changeling
- Vampire
- Flesh
- FleshHuman
@ -47,7 +28,6 @@
- AllHostile
- Thief
- Vampire
- Changeling
- Flesh
- FleshHuman
- BloodCult
@ -65,7 +45,6 @@
- AllHostile
- Thief
- Carps
- Changeling
- Flesh
- FleshHuman
- BloodCult

View file

@ -3,51 +3,51 @@
- type: weightedRandom
id: SunriseSecret
weights:
Traitor: 0.47
BloodCult: 0.10
AssaultOps: 0.10
Revolutionary: 0.10
Nukeops: 0.10
Extra: 0.10
Traitor: 0.2
BloodCult: 0.1
AssaultOps: 0.1
Revolutionary: 0.1
Nukeops: 0.1
Changeling: 0.1
FleshCult: 0.1
Wizard: 0.01
Zombie: 0.01
Wizard: 0.1
Zombie: 0.1
- type: weightedRandom
id: FishSecret
weights:
Traitor: 0.47
BloodCult: 0.10
AssaultOps: 0.10
Revolutionary: 0.10
Nukeops: 0.10
Extra: 0.10
Traitor: 0.2
BloodCult: 0.1
AssaultOps: 0.1
Revolutionary: 0.1
Nukeops: 0.1
Changeling: 0.1
FleshCult: 0.1
Wizard: 0.01
Zombie: 0.01
Wizard: 0.1
Zombie: 0.1
- type: weightedRandom
id: LustSpectralSecret
weights:
Traitor: 0.47
BloodCult: 0.10
AssaultOps: 0.10
Revolutionary: 0.10
Nukeops: 0.10
Extra: 0.10
Traitor: 0.2
BloodCult: 0.1
AssaultOps: 0.1
Revolutionary: 0.1
Nukeops: 0.1
Changeling: 0.1
FleshCult: 0.1
Wizard: 0.01
Zombie: 0.01
Wizard: 0.1
Zombie: 0.1
- type: weightedRandom
id: LustVenusSecret
weights:
Traitor: 0.47
BloodCult: 0.10
AssaultOps: 0.10
Revolutionary: 0.10
Nukeops: 0.10
Extra: 0.10
Traitor: 0.2
BloodCult: 0.1
AssaultOps: 0.1
Revolutionary: 0.1
Nukeops: 0.1
Changeling: 0.1
FleshCult: 0.1
Wizard: 0.01
Zombie: 0.01
Wizard: 0.1
Zombie: 0.1

View file

@ -13,7 +13,6 @@
- Wizard
# Sunrise Edit
- Thief
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -34,7 +33,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- Flesh
- BloodCult
@ -80,7 +78,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -104,7 +101,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -126,7 +122,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -149,7 +144,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -167,7 +161,6 @@
- Dragon
# Sunrise Edit
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -192,7 +185,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -217,7 +209,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh
@ -243,7 +234,6 @@
# Sunrise Edit
- Thief
- Carps
- Changeling
- Vampire
- FleshHuman
- Flesh

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Some files were not shown because too many files have changed in this diff Show more