Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f52b453
Added doll species
Citrea-Lingua Feb 20, 2026
a6e9e53
Guidebook update
Citrea-Lingua Feb 21, 2026
3b7ca8a
Name list changes in preparation to fill in the rest
Citrea-Lingua Mar 13, 2026
6cde9e8
Male names pt 2
Citrea-Lingua Mar 16, 2026
019c2da
Action icons and new markings
Citrea-Lingua May 31, 2026
52eba66
Expanded name lists
Citrea-Lingua Jun 22, 2026
1c7105a
Shell refining
Citrea-Lingua Jun 22, 2026
a6816bf
namespacing fixes
Citrea-Lingua Jun 22, 2026
72e805c
Further merge fixes
Citrea-Lingua Jun 22, 2026
64309cc
More Names!
Citrea-Lingua Jul 4, 2026
552d384
Dolls can no longer ventcrawl or break out of their own shells. Infra…
Citrea-Lingua Aug 21, 2026
240a08f
Dolls can no longer discard their head shell for Heterochromia
Citrea-Lingua Aug 21, 2026
d3cbb58
Assigned doll appearance as dollPrototype for dolls (that won't get c…
Citrea-Lingua Aug 21, 2026
f99891b
Doll organs can metabolise again
Citrea-Lingua Aug 21, 2026
553284d
Doll surgery steps no longer show as error
Citrea-Lingua Aug 21, 2026
4c6ec4a
Added resources for marking colours
Citrea-Lingua Aug 21, 2026
1d77078
Human snout markings really don't fit dolls so they don't get them an…
Citrea-Lingua Aug 23, 2026
b3470d8
markings
SevenShadesofStarlight Aug 26, 2026
cbbe621
Cleaned up duplicate survival boxes
Citrea-Lingua Aug 27, 2026
e246ea5
readonlyn't data fields
Citrea-Lingua Aug 28, 2026
0f28376
Some review changes
Citrea-Lingua Aug 28, 2026
36b60dc
Undid unrelated change
Citrea-Lingua Aug 28, 2026
2cbedb3
Un-jank vent crawling hopefully?
Citrea-Lingua Aug 28, 2026
c852cf2
More readonlyn't
Citrea-Lingua Aug 28, 2026
2e5f3de
Whitespace cleanup
Citrea-Lingua Aug 28, 2026
9d7c2c4
Removed resharper suppress APPARENTLY THAT IS NOT JUST A DAMN IDE SET…
Citrea-Lingua Aug 28, 2026
51e2aaa
Removed resharper suppress APPARENTLY THAT IS NOT JUST A DAMN IDE SET…
Citrea-Lingua Aug 28, 2026
72c84e4
Merge remote-tracking branch 'Citrea/Doll-Species' into Doll-Species
Citrea-Lingua Aug 28, 2026
b2072a0
fixed loadout ID mismatch
Citrea-Lingua Aug 28, 2026
9f511d0
Merge branch 'starlight-dev' into Doll-Species
Citrea-Lingua Aug 29, 2026
7f53ff1
Fixed mismatched variable name
Citrea-Lingua Aug 29, 2026
ddc6608
Could have sworn we had more names
Citrea-Lingua Aug 30, 2026
3780d88
Proto fixes
Citrea-Lingua Aug 30, 2026
4d32932
Fixed misnumbered doll name
Citrea-Lingua Aug 30, 2026
b1c82aa
yml fixes
Citrea-Lingua Aug 30, 2026
8a73931
More yml fixes, hopefully last
Citrea-Lingua Aug 30, 2026
53b8b31
Merge branch 'starlight-dev' into Doll-Species
Citrea-Lingua Sep 2, 2026
203809d
Meat anomaly cores can now be cooked into empty dolls
Citrea-Lingua Sep 2, 2026
0c162cb
Update Resources/Prototypes/_Starlight/Entities/Mobs/Species/doll.yml
walksanatora Sep 3, 2026
af9f8d1
Merge branch 'starlight-dev' into Doll-Species
walksanatora Sep 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Content.Server/Mobs/CritMobActionsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private void OnSuccumb(EntityUid uid, MobStateActionsComponent component, CritSu

private void OnFakeDeath(EntityUid uid, MobStateActionsComponent component, CritFakeDeathEvent args)
{
if (!_mobState.IsCritical(uid))
if (_mobState.IsDead(uid)) //Starlight - changed to checking if the creature is *dead*, rather than not critical, now we can use the same action to fake death on anyone still alive.
return;

//Starlight Start
Expand Down
27 changes: 27 additions & 0 deletions Content.Server/_Starlight/Actions/EntitySystems/ShellSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Content.Shared.Actions;
using Content.Shared._Starlight.Actions.Components;

namespace Content.Server._Starlight.Actions.EntitySystems;

public sealed class ShellSystem : EntitySystem

Check warning on line 6 in Content.Server/_Starlight/Actions/EntitySystems/ShellSystem.cs

View workflow job for this annotation

GitHub Actions / build

[C# diagnostics] reported by reviewdog 🐶 Type 'Content.Server._Starlight.Actions.EntitySystems.ShellSystem' has [Dependency] fields but is not partial. This will be required in the future. Raw Output: {"level":"warning","locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///home/runner/work/space-station-14/space-station-14/Content.Server/_Starlight/Actions/EntitySystems/ShellSystem.cs"},"region":{"endColumn":20,"endLine":6,"startColumn":15,"startLine":6}}}],"message":{"text":"Type 'Content.Server._Starlight.Actions.EntitySystems.ShellSystem' has [Dependency] fields but is not partial. This will be required in the future."},"properties":{},"ruleId":"RA0049","ruleIndex":571}
{
[Dependency] private SharedActionsSystem _actionsSystem = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ShellComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<ShellComponent, ComponentShutdown>(OnCompRemove);
}

private void OnMapInit(EntityUid uid, ShellComponent comp, MapInitEvent args)
{
_actionsSystem.AddAction(uid, ref comp.GenerateShellPieceActionEntity, comp.GenerateShellPieceAction);
}

private void OnCompRemove(EntityUid uid, ShellComponent comp, ComponentShutdown args)
{
_actionsSystem.RemoveAction(uid, comp.GenerateShellPieceActionEntity);
}
}
178 changes: 163 additions & 15 deletions Content.Server/_Starlight/Medical/Surgery/OrganSystem.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
using System.Linq;
using Content.Server._Starlight.Language;
using Content.Server.Humanoid;
using Content.Shared._Starlight.Actions.Components;
using Content.Shared.Actions;
using Content.Shared.Body.Part;
using Content.Shared.Body.Systems;
using Content.Shared._Starlight.Medical.Body.Part;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Radio.Components;
using Content.Shared.Speech.Muting;
using Content.Shared._Starlight.Cybernetics;
Expand All @@ -22,6 +27,7 @@
using Content.Shared._Starlight.VentCrawl.Components;
using Content.Shared._Starlight.Medical.Surgery.Components;
using Content.Shared._Starlight.Antags.Abductor.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;

namespace Content.Server._Starlight.Medical.Surgery;
Expand All @@ -36,7 +42,9 @@ public sealed partial class OrganSystem : EntitySystem
[Dependency] private LanguageSystem _language = default!;
[Dependency] private SharedContainerSystem _container = default!;
[Dependency] private IGameTiming _timing = default!;
[Dependency] private SharedActionsSystem _actions = default!;
[Dependency] private MarkingManager _markingManager = default!;
[Dependency] private SharedBodySystem _body = default!;
[Dependency] private SharedActionsSystem _actionsSystem = default!;
[Dependency] private ISerializationManager _serialization = default!;
[Dependency] private SharedSurgerySystem _surgery = default!;

Expand All @@ -49,8 +57,14 @@ public override void Initialize()
SubscribeLocalEvent<TaggedOrganComponent, SurgeryOrganImplantationCompleted>(OnTaggedOrganImplanted);
SubscribeLocalEvent<TaggedOrganComponent, SurgeryOrganExtracted>(OnTaggedOrganExtracted);

SubscribeLocalEvent<StorageOrganComponent, SurgeryOrganImplantationCompleted>(OnStorageOrganImplanted);
SubscribeLocalEvent<StorageOrganComponent, SurgeryOrganExtracted>(OnStorageOrganExtracted);
SubscribeLocalEvent<MarkingOrganComponent, SurgeryOrganImplantationCompleted>(OnMarkingOrganImplanted);
SubscribeLocalEvent<MarkingOrganComponent, SurgeryOrganExtracted>(OnMarkingOrganExtracted);

SubscribeLocalEvent<DamageModifierOrganComponent, SurgeryOrganImplantationCompleted>(OnDamageModifierOrganImplanted);
SubscribeLocalEvent<DamageModifierOrganComponent, SurgeryOrganExtracted>(OnDamageModifierOrganExtracted);

SubscribeLocalEvent<OrganShellComponent, SurgeryOrganImplantationCompleted>(OnShellImplanted);
SubscribeLocalEvent<OrganShellComponent, SurgeryOrganExtracted>(OnShellExtracted);

SubscribeLocalEvent<OrganEyesComponent, SurgeryOrganImplantationCompleted>(OnEyeImplanted);
SubscribeLocalEvent<OrganEyesComponent, SurgeryOrganExtracted>(OnEyeExtracted);
Expand Down Expand Up @@ -106,7 +120,7 @@ private void OnFunctionalOrganExtracted(Entity<FunctionalOrganComponent> ent, re

private void UpdateEntity(EntityUid ent, IComponent comp, EntityUid? implant = null)
{
//For all those components where the enity needs to be updated in their own way after adding or removing a component
//For all those components where the entity needs to be updated in their own way after adding or removing a component
switch (comp)
{
case IntrinsicTranslatorComponent _:
Expand Down Expand Up @@ -147,27 +161,131 @@ private void OnTaggedOrganExtracted(Entity<TaggedOrganComponent> ent, ref Surger

//

private void OnStorageOrganImplanted(Entity<StorageOrganComponent> ent, ref SurgeryOrganImplantationCompleted args)
private void OnMarkingOrganImplanted(Entity<MarkingOrganComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
if(ent.Comp.Markings.Count > 0)
{
var addedMarkings = new List<ProtoId<MarkingPrototype>>();
foreach(var marking in ent.Comp.Markings)
{
_humanoidAppearanceSystem.AddMarking(args.Body, marking.Key, marking.Value.markingColors, marking.Value.isGlowing, forced: true);
addedMarkings.Add(marking.Key);
}
foreach(var key in addedMarkings)
ent.Comp.Markings.Remove(key);
}
else
foreach(var markingProto in ent.Comp.AppliedMarkings)
UpdateMarking(ent, args.Body, args.Part, markingProto, true);

UpdateEntity(args.Body, ent.Comp);
}

private void OnMarkingOrganExtracted(Entity<MarkingOrganComponent> ent, ref SurgeryOrganExtracted args)
{
if(ent.Comp.StoreMarkings)
{
if (!TryComp(args.Body, out HumanoidAppearanceComponent? appearance))
return;

if (!TryComp(args.Part, out BodyPartComponent? part))
return;

var resolvedLayers = ResolveBodyPartLayers(part.PartType, part.Symmetry);
if (!resolvedLayers.Any())
return;

var removedMarkings = new List<string>();
foreach (var markingSet in appearance.MarkingSet.Markings)
foreach (var marking in markingSet.Value)
{
if (!_markingManager.Markings.TryGetValue(marking.MarkingId, out var prototype))
continue;
if (!resolvedLayers.Contains(prototype.BodyPart))
continue;
ent.Comp.Markings.TryAdd(prototype, (marking.IsGlowing, marking.MarkingColors));
removedMarkings.Add(prototype.ID);
}
Comment thread
Citrea-Lingua marked this conversation as resolved.
foreach(var key in removedMarkings)
_humanoidAppearanceSystem.RemoveMarking(args.Body, key);
}
else
foreach(var markingProto in ent.Comp.AppliedMarkings)
UpdateMarking(ent, args.Body, args.Part, markingProto, false);

UpdateEntity(args.Body, ent.Comp);
}

private static IEnumerable<HumanoidVisualLayers> ResolveBodyPartLayers(BodyPartType partType, BodyPartSymmetry symmetry = BodyPartSymmetry.Right)
{
// The results of the container change are already networked on their own
if (_timing.ApplyingState)
switch(partType)
{
case BodyPartType.Torso:
yield return HumanoidVisualLayers.Chest;
break;
case BodyPartType.Head:
yield return HumanoidVisualLayers.Head;
yield return HumanoidVisualLayers.HeadSide;
yield return HumanoidVisualLayers.HeadTop;
break;
case BodyPartType.Arm:
yield return symmetry == BodyPartSymmetry.Left ? HumanoidVisualLayers.LArm : HumanoidVisualLayers.RArm;
break;
case BodyPartType.Hand:
yield return symmetry == BodyPartSymmetry.Left ? HumanoidVisualLayers.LHand : HumanoidVisualLayers.RHand;
break;
case BodyPartType.Leg:
yield return symmetry == BodyPartSymmetry.Left ? HumanoidVisualLayers.LLeg : HumanoidVisualLayers.RLeg;
break;
case BodyPartType.Foot:
yield return symmetry == BodyPartSymmetry.Left ? HumanoidVisualLayers.LFoot : HumanoidVisualLayers.RFoot;
break;
case BodyPartType.Tail:
yield return HumanoidVisualLayers.Tail;
break;
default:
break;
}
}

private void UpdateMarking(Entity<MarkingOrganComponent> ent, EntityUid targetBody, EntityUid targetPart, string marking, bool add = true)
{
if (!_markingManager.Markings.TryGetValue(marking, out var prototype))
return;

Dirty(ent);
if(!TryComp(targetPart, out BodyPartComponent? part))
return;

if (ent.Comp.OrganAction != null)
_actions.AddAction(args.Body, ref ent.Comp.ActionEntity, ent.Comp.OrganAction, ent.Owner);
if(!ResolveBodyPartLayers(part.PartType, part.Symmetry).Contains(prototype.BodyPart))
return;

if(add)
_humanoidAppearanceSystem.AddMarking(targetBody, marking, ent.Comp.IsGlowing, forced: true);
else
_humanoidAppearanceSystem.RemoveMarking(targetBody, marking);

}

private void OnStorageOrganExtracted(Entity<StorageOrganComponent> ent, ref SurgeryOrganExtracted args)
//

private void OnDamageModifierOrganImplanted(Entity<DamageModifierOrganComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
// The results of the container change are already networked on their own
if (_timing.ApplyingState)
if (!TryComp(args.Body, out DamageableComponent? damage))
return;

_actions.RemoveAction(args.Body, ent.Comp.ActionEntity);
ent.Comp.ActionEntity = null;
_damageableSystem.AddAdditiveModifierSet((args.Body, damage), ent, ent.Comp.Modifiers);

UpdateEntity(args.Body, ent.Comp);
}

private void OnDamageModifierOrganExtracted(Entity<DamageModifierOrganComponent> ent, ref SurgeryOrganExtracted args)
{
if (!TryComp(args.Body, out DamageableComponent? damage))
return;

_damageableSystem.RemoveAdditiveModifierSet((args.Body, damage), ent, ent.Comp.Modifiers);

UpdateEntity(args.Body, ent.Comp);
}

//
Expand Down Expand Up @@ -200,6 +318,36 @@ private void OnOrganExtracted(Entity<DamageableComponent> ent, ref SurgeryOrganE

//

private void OnShellImplanted(Entity<OrganShellComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
if(!TryComp(args.Body, out ShellComponent? shell))
return;

if(!_body.GetBodyOrgans(args.Body).Where(o => TryComp(o.Id, out OrganShellComponent? _)).Any())
return;

if(shell.NoShellComponents != null)
EntityManager.RemoveComponents(args.Body, shell.NoShellComponents);

_actionsSystem.AddAction(args.Body, ref shell.GenerateShellPieceActionEntity, shell.GenerateShellPieceAction);
}

private void OnShellExtracted(Entity<OrganShellComponent> ent, ref SurgeryOrganExtracted args)
{
if(!TryComp(args.Body, out ShellComponent? shell))
return;

if(_body.GetBodyOrgans(args.Body).Where(o => TryComp(o.Id, out OrganShellComponent? _)).Any())
return;

if(shell.NoShellComponents != null)
EntityManager.AddComponents(args.Body, shell.NoShellComponents, removeExisting: false);

_actionsSystem.RemoveAction(args.Body, shell.GenerateShellPieceActionEntity);
}

//

private void OnAbductorOrganImplanted(Entity<AbductorOrganComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
if (TryComp<AbductorVictimComponent>(args.Body, out var victim))
Expand Down
16 changes: 16 additions & 0 deletions Content.Shared/Damage/Components/DamageableComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@

[DataField]
public FixedPoint2? HealthBarThreshold;

#region Starlight

/// <summary>
/// Additive changes to damage coefficients. See also: <see cref="DamageModifierSet"/>
/// </summary>
[DataField]
public Dictionary<(EntityUid Source, string ModifierKey), float> AdditiveCoefficients = [];

Check warning on line 100 in Content.Shared/Damage/Components/DamageableComponent.cs

View workflow job for this annotation

GitHub Actions / build

[C# diagnostics] reported by reviewdog 🐶 Avoid multiple blank lines Raw Output: {"level":"warning","locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///home/runner/work/space-station-14/space-station-14/Content.Shared/Damage/Components/DamageableComponent.cs"},"region":{"endColumn":1,"endLine":100,"startColumn":1,"startLine":100}}}],"message":{"text":"Avoid multiple blank lines"},"properties":{},"relatedLocations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///home/runner/work/space-station-14/space-station-14/Content.Shared/Damage/Components/DamageableComponent.cs"},"region":{"endColumn":6,"endLine":105,"startColumn":5,"startLine":105}}}],"ruleId":"IDE2000","ruleIndex":508}

/// <summary>
/// Additive changes to damage modifiers. See also: <see cref="DamageModifierSet"/>
/// </summary>
[DataField]
public Dictionary<(EntityUid Source, string ModifierKey), float> AdditiveModifiers = [];
Comment thread
Citrea-Lingua marked this conversation as resolved.
#endregion Starlight
}

[Serializable, NetSerializable]
Expand Down
59 changes: 58 additions & 1 deletion Content.Shared/Damage/Systems/DamageableSystem.API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,34 @@ public DamageSpecifier ChangeDamage(
// Apply resistances
if (!ignoreResistances)
{
//Starlight Start
var computedModifiers = new DamageModifierSet();
if (
ent.Comp.DamageModifierSetId != null &&
_prototypeManager.Resolve(ent.Comp.DamageModifierSetId, out var modifierSet)
)
damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet, armorPenetration, canHeal); // starlight
{
foreach (var coefficient in modifierSet.Coefficients)
computedModifiers.Coefficients.Add(coefficient.Key, modifierSet.Coefficients[coefficient.Key]);

foreach (var modifier in modifierSet.FlatReductions)
computedModifiers.FlatReductions.Add(modifier.Key, modifierSet.FlatReductions[modifier.Key]);
}

foreach(var additiveCoefficient in ent.Comp.AdditiveCoefficients)
if(computedModifiers.Coefficients.ContainsKey(additiveCoefficient.Key.ModifierKey))
computedModifiers.Coefficients[additiveCoefficient.Key.ModifierKey] += additiveCoefficient.Value;
else
computedModifiers.Coefficients.Add( additiveCoefficient.Key.ModifierKey, 1.0f + additiveCoefficient.Value);

foreach(var additiveModifier in ent.Comp.AdditiveModifiers)
if(computedModifiers.FlatReductions.ContainsKey(additiveModifier.Key.ModifierKey))
computedModifiers.FlatReductions[additiveModifier.Key.ModifierKey] += additiveModifier.Value;
else
computedModifiers.FlatReductions.Add( additiveModifier.Key.ModifierKey, 0.0f + additiveModifier.Value);

damage = DamageSpecifier.ApplyModifierSet(damage, computedModifiers, armorPenetration, canHeal);
//Starlight End

// TODO DAMAGE
// byref struct event.
Expand Down Expand Up @@ -471,4 +494,38 @@ public void SetDamageContainerID(Entity<DamageableComponent?> ent, ProtoId<Damag
Dirty(ent);
}
// End Stellar

#region Starlight

/// <summary>
/// Adds to the additive damage modifiers of the DamageableComponent
/// </summary>
public void AddAdditiveModifierSet(Entity<DamageableComponent?> ent, EntityUid source, DamageModifierSet mods)
{
if(!Resolve(ent, ref ent.Comp))
return;

foreach (var coefficient in mods.Coefficients)
ent.Comp.AdditiveCoefficients.TryAdd((source, coefficient.Key), coefficient.Value);

foreach (var modifier in mods.FlatReductions)
ent.Comp.AdditiveModifiers.TryAdd((source, modifier.Key), modifier.Value);
}

/// <summary>
/// Subtracts from the additive damage modifiers of the DamageableComponent
/// </summary>
public void RemoveAdditiveModifierSet(Entity<DamageableComponent?> ent, EntityUid source, DamageModifierSet mods)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
if(!Resolve(ent, ref ent.Comp))
return;

foreach (var coefficient in mods.Coefficients)
ent.Comp.AdditiveCoefficients.Remove((source, coefficient.Key));

foreach (var modifier in mods.FlatReductions)
ent.Comp.AdditiveModifiers.Remove((source, modifier.Key));
}

#endregion Starlight
}
4 changes: 4 additions & 0 deletions Content.Shared/Magic/SharedMagicSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,11 @@ private void OnSpawnItemInHand(SpawnItemInHandEvent ev)
if(!result && ev.RequiresFreeHand)
Del(spawnedEntity); // abort!
else
{
if(ev.SelfDamage != null) //For dolls
_damageable.ChangeDamage(user, ev.SelfDamage, true);
ev.Handled = true;
}
}

private void OnTowerOfBabel(TowerOfBabelEvent ev)
Expand Down
Loading
Loading