Merge branch 'DeltaV-Station:master' into seer

This commit is contained in:
SolStar 2024-11-11 18:24:43 -05:00 committed by GitHub
commit e53253f659
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 649 additions and 340 deletions

View File

@ -0,0 +1,5 @@
using Content.Shared.Abilities.Psionics;
namespace Content.Client.Abilities.Psionics;
public sealed class TelegnosisPowerSystem : SharedTelegnosisPowerSystem;

View File

@ -1,12 +1,10 @@
using Content.Server.Nyanotrasen.Cloning;
using Content.Server.DeltaV.Cloning;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Random;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.DeltaV;
[TestFixture]
[TestOf(typeof(MetempsychoticMachineSystem))]
public sealed class MetempsychosisTest
{
[Test]
@ -23,18 +21,22 @@ public sealed class MetempsychosisTest
await server.WaitAssertion(() =>
{
prototypeManager.TryIndex<WeightedRandomPrototype>(metemComponent.MetempsychoticHumanoidPool,
prototypeManager.TryIndex(metemComponent.MetempsychoticHumanoidPool,
out var humanoidPool);
prototypeManager.TryIndex<WeightedRandomPrototype>(metemComponent.MetempsychoticNonHumanoidPool,
prototypeManager.TryIndex(metemComponent.MetempsychoticNonHumanoidPool,
out var nonHumanoidPool);
Assert.That(humanoidPool, Is.Not.Null, "MetempsychoticHumanoidPool is null!");
Assert.That(nonHumanoidPool, Is.Not.Null, "MetempsychoticNonHumanoidPool is null!");
Assert.That(humanoidPool.Weights, Is.Not.Empty,
"MetempsychoticHumanoidPool has no valid prototypes!");
Assert.That(nonHumanoidPool.Weights, Is.Not.Empty,
"MetempsychoticNonHumanoidPool has no valid prototypes!");
Assert.Multiple(() =>
{
Assert.That(humanoidPool, Is.Not.Null, "MetempsychoticHumanoidPool is null!");
Assert.That(nonHumanoidPool, Is.Not.Null, "MetempsychoticNonHumanoidPool is null!");
Assert.That(humanoidPool.Weights,
Is.Not.Empty,
"MetempsychoticHumanoidPool has no valid prototypes!");
Assert.That(nonHumanoidPool.Weights,
Is.Not.Empty,
"MetempsychoticNonHumanoidPool has no valid prototypes!");
});
foreach (var key in humanoidPool.Weights.Keys)
{

View File

@ -9,6 +9,8 @@ using Content.Server.Jobs;
using Content.Server.Materials;
using Content.Server.Popups;
using Content.Server.Power.EntitySystems;
using Content.Server.Psionics; // DeltaV
using Content.Server.Traits.Assorted; // DeltaV
using Content.Shared.Atmos;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Components;
@ -33,26 +35,10 @@ using Robust.Shared.Containers;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Content.Server.Traits.Assorted; //Nyano - Summary: allows the potential psionic ability to be written to the character.
using Content.Server.Psionics; //DeltaV needed for Psionic Systems
using Content.Shared.Speech; //DeltaV Start Metem Usings
using Content.Shared.Tag;
using Content.Shared.Preferences;
using Content.Shared.Emoting;
using Content.Server.Speech.Components;
using Content.Server.StationEvents.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Nyanotrasen.Cloning;
using Content.Shared.Humanoid.Prototypes;
using Robust.Shared.GameObjects.Components.Localization; //DeltaV End Metem Usings
using Content.Server.EntityList;
using Content.Shared.SSDIndicator;
using Content.Shared.Damage.ForceSay;
using Content.Server.Polymorph.Components;
namespace Content.Server.Cloning
{
public sealed class CloningSystem : EntitySystem
public sealed partial class CloningSystem : EntitySystem // DeltaV - Set to partial, see CloningSystem.Metempsychosis.cs
{
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
[Dependency] private readonly IPlayerManager _playerManager = null!;
@ -76,8 +62,6 @@ namespace Content.Server.Cloning
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
[Dependency] private readonly MetempsychoticMachineSystem _metem = default!; //DeltaV
[Dependency] private readonly TagSystem _tag = default!; //DeltaV
public readonly Dictionary<MindComponent, EntityUid> ClonesWaitingForMind = new();
public const float EasyModeCloningCost = 0.7f;
@ -158,6 +142,10 @@ namespace Content.Server.Cloning
if (!Resolve(uid, ref clonePod))
return false;
// DeltaV - This method should use Entity<CloningPodComponent> pod instead
// But I don't want to completely mangle it so we do this here
var podEnt = new Entity<CloningPodComponent>(uid, clonePod);
if (HasComp<ActiveCloningPodComponent>(uid))
return false;
@ -244,13 +232,13 @@ namespace Content.Server.Cloning
AddComp<ActiveCloningPodComponent>(uid);
return true;
}
// End Nyano-code.
}
// end of genetic damage checks
var mob = FetchAndSpawnMob(clonePod, pref, speciesPrototype, humanoid, bodyToClone, karmaBonus); //DeltaV Replaces CloneAppearance with Metem/Clone via FetchAndSpawnMob
// DeltaV - Replaces CloneAppearance with Metem/Clone via FetchAndSpawnMob
var mob = FetchAndSpawnMob(podEnt, pref, speciesPrototype, humanoid, bodyToClone, karmaBonus);
///Nyano - Summary: adds the potential psionic trait to the reanimated mob.
// Nyano - Summary: adds the potential psionic trait to the reanimated mob.
EnsureComp<PotentialPsionicComponent>(mob);
var ev = new CloningEvent(bodyToClone, mob);
@ -348,6 +336,7 @@ namespace Content.Server.Cloning
var transform = Transform(uid);
var indices = _transformSystem.GetGridTilePositionOrDefault((uid, transform));
var tileMix = _atmosphereSystem.GetTileMixture(transform.GridUid, null, indices, true);
if (HasComp<EmaggedComponent>(uid))
{
_audio.PlayPvs(clonePod.ScreamSound, uid);
@ -375,84 +364,6 @@ namespace Content.Server.Cloning
RemCompDeferred<ActiveCloningPodComponent>(uid);
}
/// <summary>
/// Start Nyano Code: Handles fetching the mob and any appearance stuff...
/// </summary>
private EntityUid FetchAndSpawnMob(CloningPodComponent clonePod, HumanoidCharacterProfile pref, SpeciesPrototype speciesPrototype, HumanoidAppearanceComponent humanoid, EntityUid bodyToClone, float karmaBonus)
{
List<Sex> sexes = new();
bool switchingSpecies = false;
bool applyKarma = false;
var toSpawn = speciesPrototype.Prototype;
TryComp<MetempsychosisKarmaComponent>(bodyToClone, out var oldKarma);
if (TryComp<MetempsychoticMachineComponent>(clonePod.Owner, out var metem))
{
toSpawn = _metem.GetSpawnEntity(clonePod.Owner, karmaBonus, metem, speciesPrototype, out var newSpecies, oldKarma?.Score);
applyKarma = true;
if (newSpecies != null)
{
sexes = newSpecies.Sexes;
if (speciesPrototype.ID != newSpecies.ID)
switchingSpecies = true;
speciesPrototype = newSpecies;
}
}
var mob = Spawn(toSpawn, _transformSystem.GetMapCoordinates(clonePod.Owner));
if (TryComp<HumanoidAppearanceComponent>(mob, out var newHumanoid))
{
if (switchingSpecies || HasComp<MetempsychosisKarmaComponent>(bodyToClone))
{
pref = HumanoidCharacterProfile.RandomWithSpecies(newHumanoid.Species);
if (sexes.Contains(humanoid.Sex))
pref = pref.WithSex(humanoid.Sex);
pref = pref.WithGender(humanoid.Gender);
pref = pref.WithAge(humanoid.Age);
}
_humanoidSystem.LoadProfile(mob, pref);
}
if (applyKarma)
{
var karma = EnsureComp<MetempsychosisKarmaComponent>(mob);
karma.Score++;
if (oldKarma != null)
karma.Score += oldKarma.Score;
}
var ev = new CloningEvent(bodyToClone, mob);
RaiseLocalEvent(bodyToClone, ref ev);
if (!ev.NameHandled)
_metaSystem.SetEntityName(mob, MetaData(bodyToClone).EntityName);
var grammar = EnsureComp<GrammarComponent>(mob);
grammar.ProperNoun = true;
grammar.Gender = humanoid.Gender;
Dirty(mob, grammar);
EnsureComp<PotentialPsionicComponent>(mob);
EnsureComp<SpeechComponent>(mob);
EnsureComp<DamageForceSayComponent>(mob);
EnsureComp<EmotingComponent>(mob);
EnsureComp<MindContainerComponent>(mob);
EnsureComp<SSDIndicatorComponent>(mob);
RemComp<ReplacementAccentComponent>(mob);
RemComp<MonkeyAccentComponent>(mob);
RemComp<SentienceTargetComponent>(mob);
RemComp<GhostTakeoverAvailableComponent>(mob);
_tag.AddTag(mob, "DoorBumpOpener");
return mob;
}
//End Nyano Code
public void Reset(RoundRestartCleanupEvent ev)
{
ClonesWaitingForMind.Clear();

View File

@ -0,0 +1,79 @@
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
using Robust.Shared.Audio;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.Prototypes;
namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.Fun)]
public sealed class AnnounceCustomCommand : IConsoleCommand
{
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IResourceManager _res = default!;
public string Command => "announcecustom";
public string Description => Loc.GetString("cmd-announcecustom-desc");
public string Help => Loc.GetString("cmd-announcecustom-help", ("command", Command));
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var chat = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ChatSystem>();
switch (args.Length)
{
case 0:
shell.WriteError(Loc.GetString("shell-need-minimum-one-argument"));
return;
case > 4:
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
return;
}
var message = args[0];
var sender = "Central Command";
var color = Color.Gold;
var sound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg");
// Optional sender argument
if (args.Length >= 2)
sender = args[1];
// Optional color argument
if (args.Length >= 3)
{
try
{
color = Color.FromHex(args[2]);
}
catch
{
shell.WriteError(Loc.GetString("shell-invalid-color-hex"));
return;
}
}
// Optional sound argument
if (args.Length >= 4)
sound = new SoundPathSpecifier(args[3]);
chat.DispatchGlobalAnnouncement(message, sender, true, sound, color);
shell.WriteLine(Loc.GetString("shell-command-success"));
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
return args.Length switch
{
1 => CompletionResult.FromHint(Loc.GetString("cmd-announcecustom-arg-message")),
2 => CompletionResult.FromHint(Loc.GetString("shell-argument-username-optional-hint")),
3 => CompletionResult.FromHint(Loc.GetString("cmd-announcecustom-arg-color")),
4 => CompletionResult.FromHintOptions(
CompletionHelper.AudioFilePath(args[3], _protoManager, _res),
Loc.GetString("cmd-announcecustom-arg-sound")
),
_ => CompletionResult.Empty
};
}
}

View File

@ -1,5 +1,5 @@
using Content.Server.Bible.Components;
using Content.Server.Nyanotrasen.Cloning;
using Content.Server.DeltaV.Cloning;
using Content.Shared.Abilities.Psionics;
using Content.Shared.Administration.Logs;
using Content.Shared.Body.Components;

View File

@ -0,0 +1,172 @@
using Content.Server.DeltaV.Cloning;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
using Content.Shared.Speech;
using Content.Shared.Emoting;
using Content.Shared.Damage.ForceSay;
using Content.Shared.SSDIndicator;
using Content.Server.Speech.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.StationEvents.Components;
using Content.Server.Psionics;
using Robust.Shared.Random;
using Content.Shared.Mind.Components;
using Content.Shared.Tag;
using Content.Shared.Cloning;
using Content.Shared.Random.Helpers;
using Robust.Shared.GameObjects.Components.Localization;
namespace Content.Server.Cloning;
public sealed partial class CloningSystem
{
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly GrammarSystem _grammar = default!;
/// <summary>
/// Gets the entity prototype to spawn for a clone based on karma and chance calculations.
/// </summary>
private string GetSpawnEntity(Entity<MetempsychoticMachineComponent> ent, float karmaBonus, SpeciesPrototype oldSpecies, out SpeciesPrototype? species, int karma = 0)
{
// First time being cloned - return original species
if (karma == 0)
{
species = oldSpecies;
return oldSpecies.Prototype;
}
var chance = ent.Comp.HumanoidBaseChance + karmaBonus;
chance -= (1 - ent.Comp.HumanoidBaseChance) * karma;
// Perfect clone chance
if (chance > 1 && _robustRandom.Prob(chance - 1))
{
species = oldSpecies;
return oldSpecies.Prototype;
}
// Roll for humanoid vs non-humanoid
chance = Math.Clamp(chance, 0, 1);
if (_robustRandom.Prob(chance))
{
if (_prototype.TryIndex(ent.Comp.MetempsychoticHumanoidPool, out var humanoidPool))
{
var protoId = humanoidPool.Pick();
if (_prototype.TryIndex<SpeciesPrototype>(protoId, out var speciesPrototype))
{
species = speciesPrototype;
return speciesPrototype.Prototype;
}
}
}
else if (_prototype.TryIndex(ent.Comp.MetempsychoticNonHumanoidPool, out var nonHumanoidPool))
{
// For non-humanoids, return the entity prototype directly
species = null;
return nonHumanoidPool.Pick();
}
// Fallback to original species if prototype indexing fails
Log.Error("Failed to get valid clone type - falling back to original species");
species = oldSpecies;
return oldSpecies.Prototype;
}
/// <summary>
/// Handles fetching the mob and managing appearance for cloning with metempsychosis mechanics
/// </summary>
private EntityUid FetchAndSpawnMob(
Entity<CloningPodComponent> pod,
HumanoidCharacterProfile pref,
SpeciesPrototype speciesPrototype,
HumanoidAppearanceComponent humanoid,
EntityUid bodyToClone,
float karmaBonus)
{
List<Sex> sexes = [];
var switchingSpecies = false;
var applyKarma = false;
var toSpawn = speciesPrototype.Prototype;
// Get existing karma score or start at 0
var karmaScore = 0;
if (TryComp<MetempsychosisKarmaComponent>(bodyToClone, out var oldKarma))
{
karmaScore = oldKarma.Score;
}
if (TryComp<MetempsychoticMachineComponent>(pod.Owner, out var metem))
{
var metemEntity = new Entity<MetempsychoticMachineComponent>(pod.Owner, metem);
toSpawn = GetSpawnEntity(metemEntity, karmaBonus, speciesPrototype, out var newSpecies, karmaScore);
applyKarma = true;
if (newSpecies != null)
{
sexes = newSpecies.Sexes;
speciesPrototype = newSpecies;
if (speciesPrototype.ID != newSpecies.ID)
switchingSpecies = true;
}
}
var mob = Spawn(toSpawn, _transformSystem.GetMapCoordinates(pod.Owner));
// Only try to handle humanoid appearance if we have a humanoid component
if (TryComp<HumanoidAppearanceComponent>(mob, out var newHumanoid))
{
if (switchingSpecies || HasComp<MetempsychosisKarmaComponent>(bodyToClone))
{
pref = HumanoidCharacterProfile.RandomWithSpecies(newHumanoid.Species);
if (sexes.Contains(humanoid.Sex))
pref = pref.WithSex(humanoid.Sex);
pref = pref.WithGender(humanoid.Gender);
pref = pref.WithAge(humanoid.Age);
}
_humanoidSystem.LoadProfile(mob, pref);
}
if (applyKarma)
{
var karma = EnsureComp<MetempsychosisKarmaComponent>(mob);
karma.Score = karmaScore + 1; // Increment karma score
}
var ev = new CloningEvent(bodyToClone, mob);
RaiseLocalEvent(bodyToClone, ref ev);
if (!ev.NameHandled)
_metaSystem.SetEntityName(mob, MetaData(bodyToClone).EntityName);
var grammar = EnsureComp<GrammarComponent>(mob);
var grammarEnt = new Entity<GrammarComponent>(mob, grammar);
_grammar.SetProperNoun(grammarEnt, true);
_grammar.SetGender(grammarEnt, humanoid.Gender);
Dirty(mob, grammar);
SetupBasicComponents(mob);
return mob;
}
// I hate this
private void SetupBasicComponents(EntityUid mob)
{
EnsureComp<PotentialPsionicComponent>(mob);
EnsureComp<SpeechComponent>(mob);
EnsureComp<DamageForceSayComponent>(mob);
EnsureComp<EmotingComponent>(mob);
EnsureComp<MindContainerComponent>(mob);
EnsureComp<SSDIndicatorComponent>(mob);
RemComp<ReplacementAccentComponent>(mob);
RemComp<MonkeyAccentComponent>(mob);
RemComp<SentienceTargetComponent>(mob);
RemComp<GhostTakeoverAvailableComponent>(mob);
_tag.AddTag(mob, "DoorBumpOpener");
}
}

View File

@ -0,0 +1,11 @@
namespace Content.Server.DeltaV.Cloning;
/// <summary>
/// This tracks how many times you have already been cloned and lowers your chance of getting a humanoid each time.
/// </summary>
[RegisterComponent]
public sealed partial class MetempsychosisKarmaComponent : Component
{
[DataField]
public int Score;
}

View File

@ -0,0 +1,27 @@
using Content.Shared.Random;
using Robust.Shared.Prototypes;
namespace Content.Server.DeltaV.Cloning;
[RegisterComponent]
public sealed partial class MetempsychoticMachineComponent : Component
{
/// <summary>
/// Base probability of remaining humanoid during cloning. Higher karma reduces this chance.
/// </summary>
[DataField]
public float HumanoidBaseChance = 0.75f;
/// <summary>
/// Species prototypes pool to use for humanoids.
/// </summary>
[DataField]
public ProtoId<WeightedRandomPrototype> MetempsychoticHumanoidPool = "MetempsychoticHumanoidPool";
/// <summary>
/// Entitiy prototypes pool to use for non-humanoids.
/// </summary>
[DataField]
public ProtoId<WeightedRandomPrototype> MetempsychoticNonHumanoidPool = "MetempsychoticNonhumanoidPool";
}

View File

@ -1,42 +1,60 @@
using Content.Shared.Chemistry.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Fluids.Components;
using JetBrains.Annotations;
namespace Content.Server.Destructible.Thresholds.Behaviors
namespace Content.Server.Destructible.Thresholds.Behaviors;
[UsedImplicitly]
[DataDefinition]
public sealed partial class SpillBehavior : IThresholdBehavior
{
[UsedImplicitly]
[DataDefinition]
public sealed partial class SpillBehavior : IThresholdBehavior
/// <summary>
/// Optional fallback solution name if SpillableComponent is not present.
/// </summary>
[DataField]
public string? Solution;
/// <summary>
/// When triggered, spills the entity's solution onto the ground.
/// Will first try to use the solution from a SpillableComponent if present,
/// otherwise falls back to the solution specified in the behavior's data fields.
/// The solution is properly drained/split before spilling to prevent double-spilling with other behaviors.
/// </summary>
/// <param name="owner">Entity whose solution will be spilled</param>
/// <param name="system">System calling this behavior</param>
/// <param name="cause">Optional entity that caused this behavior to trigger</param>
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{
[DataField]
public string? Solution;
var solutionContainerSystem = system.EntityManager.System<SharedSolutionContainerSystem>();
var spillableSystem = system.EntityManager.System<PuddleSystem>();
var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
/// <summary>
/// If there is a SpillableComponent on EntityUidowner use it to create a puddle/smear.
/// Or whatever solution is specified in the behavior itself.
/// If none are available do nothing.
/// </summary>
/// <param name="owner">Entity on which behavior is executed</param>
/// <param name="system">system calling the behavior</param>
/// <param name="cause"></param>
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
Solution targetSolution;
// First try to get solution from SpillableComponent
if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out var solution, out var compSolution))
{
var solutionContainerSystem = system.EntityManager.System<SharedSolutionContainerSystem>();
var spillableSystem = system.EntityManager.System<PuddleSystem>();
var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out _, out var compSolution))
{
spillableSystem.TrySplashSpillAt(owner, coordinates, compSolution, out _, false, user: cause);
}
else if (Solution != null &&
solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution))
{
spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause);
}
// If entity is drainable, drain the solution. Otherwise just split it.
// Both methods ensure the solution is properly removed.
targetSolution = system.EntityManager.HasComponent<DrainableSolutionComponent>(owner)
? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent<DrainableSolutionComponent>(owner)), solution.Value, compSolution.Volume)
: compSolution.SplitSolution(compSolution.Volume);
}
// Fallback to solution specified in behavior data
else if (Solution != null &&
solutionContainerSystem.TryGetSolution(owner, Solution, out var solutionEnt, out var behaviorSolution))
{
targetSolution = system.EntityManager.HasComponent<DrainableSolutionComponent>(owner)
? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent<DrainableSolutionComponent>(owner)), solutionEnt.Value, behaviorSolution.Volume)
: behaviorSolution.SplitSolution(behaviorSolution.Volume);
}
else
return;
// Spill the solution that was drained/split
spillableSystem.TrySplashSpillAt(owner, coordinates, targetSolution, out _, false, cause);
}
}

View File

@ -3,6 +3,7 @@ using Content.Server.Body.Systems;
using Content.Server.Kitchen.Components;
using Content.Server.Popups;
using Content.Shared.Chat;
using Content.Shared.Body.Part; // DeltaV
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.DoAfter;
@ -160,9 +161,12 @@ namespace Content.Server.Kitchen.EntitySystems
_transform.SetCoordinates(victimUid, Transform(uid).Coordinates);
// THE WHAT?
// TODO: Need to be able to leave them on the spike to do DoT, see ss13.
var gibs = _bodySystem.GibBody(victimUid);
var gibs = _bodySystem.GibBody(victimUid, gibOrgans: true); // DeltaV: spawn organs
foreach (var gib in gibs) {
QueueDel(gib);
// Begin DeltaV changes: Only delete limbs instead of organs
if (HasComp<BodyPartComponent>(gib))
QueueDel(gib);
// End DeltaV changes
}
_audio.PlayEntity(component.SpikeSound, Filter.Pvs(uid), uid, true);

View File

@ -9,7 +9,7 @@ using Content.Shared.Actions.Events;
namespace Content.Server.Abilities.Psionics
{
public sealed class TelegnosisPowerSystem : EntitySystem
public sealed class TelegnosisPowerSystem : SharedTelegnosisPowerSystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;

View File

@ -1,12 +0,0 @@
namespace Content.Server.Nyanotrasen.Cloning
{
/// <summary>
/// This tracks how many times you have already been cloned and lowers your chance of getting a humanoid each time.
/// </summary>
[RegisterComponent]
public sealed partial class MetempsychosisKarmaComponent : Component
{
[DataField("score")]
public int Score = 0;
}
}

View File

@ -1,22 +0,0 @@
using Content.Shared.Random;
namespace Content.Server.Nyanotrasen.Cloning
{
[RegisterComponent]
public sealed partial class MetempsychoticMachineComponent : Component
{
/// <summary>
/// Chance you will spawn as a humanoid instead of a non humanoid.
/// </summary>
[DataField("humanoidBaseChance")]
public float HumanoidBaseChance = 0.75f;
[ValidatePrototypeId<WeightedRandomPrototype>]
[DataField("metempsychoticHumanoidPool")]
public string MetempsychoticHumanoidPool = "MetempsychoticHumanoidPool";
[ValidatePrototypeId<WeightedRandomPrototype>]
[DataField("metempsychoticNonHumanoidPool")]
public string MetempsychoticNonHumanoidPool = "MetempsychoticNonhumanoidPool";
}
}

View File

@ -1,47 +0,0 @@
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Robust.Shared.Random;
using Robust.Shared.Prototypes;
namespace Content.Server.Nyanotrasen.Cloning
{
public sealed class MetempsychoticMachineSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private ISawmill _sawmill = default!;
public string GetSpawnEntity(EntityUid uid, float karmaBonus, MetempsychoticMachineComponent component, SpeciesPrototype oldSpecies, out SpeciesPrototype? species, int? karma = null)
{
var chance = component.HumanoidBaseChance + karmaBonus;
if (karma != null)
chance -= ((1 - component.HumanoidBaseChance) * (float) karma);
if (chance > 1 && _random.Prob(chance - 1))
{
species = oldSpecies;
return oldSpecies.Prototype;
}
else
chance = 1;
chance = Math.Clamp(chance, 0, 1);
if (_random.Prob(chance) &&
_prototypeManager.TryIndex<WeightedRandomPrototype>(component.MetempsychoticHumanoidPool, out var humanoidPool) &&
_prototypeManager.TryIndex<SpeciesPrototype>(humanoidPool.Pick(), out var speciesPrototype))
{
species = speciesPrototype;
return speciesPrototype.Prototype;
}
else
{
species = null;
_sawmill.Error("Could not index species for metempsychotic machine...");
return "MobHuman";
}
}
}
}

View File

@ -0,0 +1,19 @@
using Content.Shared.Interaction.Events;
namespace Content.Shared.Abilities.Psionics;
public abstract class SharedTelegnosisPowerSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TelegnosticProjectionComponent, InteractionAttemptEvent>(OnInteractionAttempt);
}
private void OnInteractionAttempt(Entity<TelegnosticProjectionComponent> ent, ref InteractionAttemptEvent args)
{
// no astrally stealing someones shoes
args.Cancelled = true;
}
}

View File

@ -5,7 +5,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.Abilities.Psionics
{
[RegisterComponent]
[RegisterComponent, Access(typeof(SharedTelegnosisPowerSystem))]
public sealed partial class TelegnosisPowerComponent : Component
{
[DataField("prototype")]
@ -20,4 +20,4 @@ namespace Content.Shared.Abilities.Psionics
[DataField("telegnosisActionEntity")]
public EntityUid? TelegnosisActionEntity;
}
}
}

View File

@ -1,6 +1,4 @@
namespace Content.Shared.Abilities.Psionics
{
[RegisterComponent]
public sealed partial class TelegnosticProjectionComponent : Component
{}
}
namespace Content.Shared.Abilities.Psionics;
[RegisterComponent, Access(typeof(SharedTelegnosisPowerSystem))]
public sealed partial class TelegnosticProjectionComponent : Component;

View File

@ -1,74 +1,4 @@
Entries:
- author: Ygg01
changes:
- message: Digging dirt.
type: Add
id: 158
time: '2023-12-06T15:58:00.0000000+00:00'
- author: Velcroboy
changes:
- message: Buffed Food Cart storage. Get out there and slang some burgers, chefs!
type: Tweak
id: 159
time: '2023-12-06T15:58:43.0000000+00:00'
- author: ps3moira
changes:
- message: Added mouse operative reinforcements, which can be bought from the Syndicate
uplink
type: Add
id: 160
time: '2023-12-06T16:03:07.0000000+00:00'
- author: evilexecutive
changes:
- message: Harpies now have a visual indication when they're playing a Midi.
type: Add
- message: Harpies have been re-balanced so that they now actually have a numerical
positive.
type: Tweak
id: 161
time: '2023-12-06T20:10:49.0000000+00:00'
- author: DebugOk
changes:
- message: Due to abuse, prisoners now require whitelist to play.
type: Tweak
id: 162
time: '2023-12-07T13:22:03.0000000+00:00'
- author: ps3moira
changes:
- message: Removed bionic syrinx implanter from surplus crate.
type: Remove
id: 163
time: '2023-12-11T23:11:41.0000000+00:00'
- author: ps3moira
changes:
- message: Removed Carpotoxin from Sashimi, now they are sushi-grade!
type: Remove
id: 164
time: '2023-12-13T20:12:46.0000000+00:00'
- author: Adrian16199
changes:
- message: Crew has learned how to make a straw hat out of wheat bushels!
type: Add
id: 165
time: '2023-12-13T20:13:45.0000000+00:00'
- author: IamVelcroboy
changes:
- message: Added Yule! Happy Holidays!
type: Add
id: 166
time: '2023-12-13T20:21:34.0000000+00:00'
- author: ps3moira
changes:
- message: Added Fish n' Chips. Thank the British!
type: Add
id: 167
time: '2023-12-13T20:32:51.0000000+00:00'
- author: Adrian16199
changes:
- message: Felinids now meow out their words. They can also sigh now.
type: Tweak
id: 168
time: '2023-12-13T21:28:39.0000000+00:00'
- author: VMSolidus
changes:
- message: Harpies no longer choke on completely breathable air
@ -3714,3 +3644,84 @@
id: 657
time: '2024-11-08T13:38:47.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2148
- author: Aikakakah
changes:
- message: Added a black turtleneck!
type: Add
id: 658
time: '2024-11-08T20:50:40.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1905
- author: deltanedas
changes:
- message: Butchering people now drops organs.
type: Tweak
id: 659
time: '2024-11-09T04:40:16.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2154
- author: MilonPL
changes:
- message: The metempsychosis will always use your player character on the first
cloning attempt.
type: Tweak
- message: Fixed metempsychosis never selecting non-humanoid characters.
type: Fix
id: 660
time: '2024-11-09T10:47:17.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2156
- author: MilonPL
changes:
- message: Fixed beaker solutions duplicating whenever it's thrown.
type: Fix
id: 661
time: '2024-11-09T12:46:34.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2157
- author: deltanedas
changes:
- message: The Synthesis Specialist's vendor can now be restocked.
type: Tweak
id: 662
time: '2024-11-09T13:16:44.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2143
- author: deltanedas
changes:
- message: Fixed telegnostic projections being able to interact with things.
type: Tweak
id: 663
time: '2024-11-09T19:27:59.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2117
- author: Unkn0wnGh0st333
changes:
- message: Synthesis Specialist ghost rules have been slightly adjusted.
type: Tweak
id: 664
time: '2024-11-09T19:44:28.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2152
- author: Colin-Tel
changes:
- message: Removed the "Raise Glimmer" objective for traitors.
type: Remove
id: 665
time: '2024-11-10T20:18:53.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2107
- author: Colin-Tel
changes:
- message: Adjusted antagonist rule C3 and the line about bribery in C1.
type: Tweak
id: 666
time: '2024-11-10T20:20:26.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2164
- author: Stop-Signs
changes:
- message: Removed the T3 Lockout on epi techs
type: Remove
id: 667
time: '2024-11-11T02:57:13.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2144
- author: Radezolid
changes:
- message: The syringe gun is now a researcheable technology in the T2 civilian
category. Get it from the medical techfab once it's researched.
type: Tweak
id: 668
time: '2024-11-11T15:41:44.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2169

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
## AnnounceCustomCommand
cmd-announcecustom-desc = Send an in-game announcement with custom color and sound.
cmd-announcecustom-help = {$command} <message> [sender] [color] [sound] - Send announcement. Sender defaults to CentCom, color to Gold, sound to announce.ogg
# Completion hints
cmd-announcecustom-arg-message = message
cmd-announcecustom-arg-color = color in #RRGGBB format (optional)
cmd-announcecustom-arg-sound = sound path (optional)

View File

@ -30,12 +30,13 @@ ghost-role-information-silvia-rules = Keep the medical team company and help out
ghost-role-information-synthesis-name = Synthesis Specialist
ghost-role-information-synthesis-description = You are a member of Interdyne Pharmaceutics! You are provided all the tools to manufacture a variety of medical cocktails. Establish your craft, peddle your poisons, and make profit.
ghost-role-information-synthesis-rules =
Brew deadly poisons, marvelous medicines, and anything in between.
Sell your concoctions to local agents, crew, and anyone with supplies.
Stay on your ship, it is your lifeblood!
You are a [color=yellow][bold]Free-Agent[/bold][/color]. You are free to act as either an antagonist or a non-antagonist.
You are just a chemist so do not act like a full-on antagonist, i.e. no killing people yourself unless your ship is in danger.
Brew deadly poisons, marvelous medicines, and anything in between.
Sell your concoctions to [color=red]local agents[/color], crew, and anyone with supplies.
Stay on your ship; it is your job, home, and lifeblood.
ghost-role-information-closet-skeleton-rules = You are a old member of the station, try to get your previous job back or dwell in the maintenance tunnels!.
You are a [color=green][bold]Non-antagonist[/bold][/color]. You should generally not seek to harm the station and its crew.
You're allowed some minor mischief.

View File

@ -5,3 +5,4 @@ research-technology-energy-gun = Energy Guns
research-technology-energy-gun-advance = Advanced Energy Manipulation
research-technology-advance-laser = Advanced Laser Manipulation
research-technology-robust-melee = Robust Melee
research-technology-syringe-gun = Syringe Gun

View File

@ -16,6 +16,7 @@
ClothingOuterPonchoClassic: 2
ClothingUniformJumpsuitKilt: 3 # DeltaV - SCOTTTTLANDDDDD FURREVERRRRR!!
ClothingEyesEyepatch: 2 # Delta-V Yarrr
ClothingUniformBlackTurtleneck : 2 # DeltaV - Clothing addition
ClothingHeadHatPwig: 2
ClothingOuterRobesJudge: 2
ClothingOuterPoncho: 2

View File

@ -0,0 +1,45 @@
- type: entity
parent: CrateEngineering
id: CrateEngineEssentials
name: engine essentials crate
description: Everything you need to power the station, in a superposition of containing both a singularity and a tesla.
suffix: 1 per map MAX
components:
- type: EntityTableContainerFill
containers:
entity_storage: !type:GroupSelector
children:
- !type:NestedSelector
tableId: TeslaEssentials
- !type:NestedSelector
tableId: SingularityEssentials
- type: entityTable
id: TeslaEssentials
table: !type:AllSelector
children:
- id: TeslaGeneratorFlatpack
- id: TeslaGeneratorFlatpack
prob: 0.3 # Small chance of a free backup
- id: TeslaCoilFlatpack
amount: !type:RangeNumberSelector
range: 4, 6
- id: TeslaGroundingRodFlatpack
amount: !type:ConstantNumberSelector
value: 4
- type: entityTable
id: SingularityEssentials
table: !type:AllSelector
children:
- id: SingularityGeneratorFlatpack
- id: SingularityGeneratorFlatpack
prob: 0.3 # Small chance of a free backup
# intentionally separate rolls so they are probably mismatched
# you might get spare tanks you might have to get more from the tank dispenser
- id: RadiationCollectorFlatpack
amount: !type:RangeNumberSelector
range: 8, 12
- id: PlasmaTankFilled
amount: !type:RangeNumberSelector
range: 8, 12

View File

@ -397,3 +397,13 @@
- type: Clothing
sprite: DeltaV/Clothing/Uniforms/Jumpsuit/prosecutorred.rsi
- type: entity
parent: ClothingUniformFoldableBase
id: ClothingUniformBlackTurtleneck
name: black turtleneck
description: A simple black turtleneck. Perfect for any wannabe spy.
components:
- type: Sprite
sprite: DeltaV/Clothing/Uniforms/Jumpsuit/black_turtleneck.rsi
- type: Clothing
sprite: DeltaV/Clothing/Uniforms/Jumpsuit/black_turtleneck.rsi

View File

@ -38,4 +38,12 @@
sprite: DeltaV/Structures/Wallmounts/signs.rsi
state: direction_court
- type: entity
parent: BaseSignDirectional
id: SignDirectionaAI
name: AI sign
description: A direction sign, pointing out which way the AI core is.
components:
- type: Sprite
sprite: DeltaV/Structures/Wallmounts/signs.rsi
state: direction_aicore

View File

@ -5,3 +5,20 @@
materials:
Steel: 300
Glass: 100
- type: latheRecipe
id: LauncherSyringe
result: LauncherSyringe
completetime: 3
materials:
Steel: 1000
Glass: 500
Plastic: 500
- type: latheRecipe
id: MiniSyringe
result: MiniSyringe
completetime: 1
materials:
Plastic: 150
Steel: 50

View File

@ -0,0 +1,12 @@
- type: technology
id: SyringeGun
name: research-technology-syringe-gun
icon:
sprite: Objects/Weapons/Guns/Cannons/syringe_gun.rsi
state: syringe_gun
discipline: CivilianServices
tier: 2
cost: 10000
recipeUnlocks:
- LauncherSyringe
- MiniSyringe

View File

@ -482,6 +482,7 @@
- type: VendingMachineRestock
canRestock:
- ChemVendInventory
- ChemVendInventorySyndicate # DeltaV: Let it restock synthesis/nukie vendor
- type: Sprite
layers:
- state: base

View File

@ -436,6 +436,8 @@
- MagazineBoxSpecialHoly
- MagazineBoxSpecialMindbreaker
- AdvancedTruncheon
- LauncherSyringe
- MiniSyringe
# End DeltaV additions
- type: entity
@ -1066,6 +1068,10 @@
- WhiteCane
- AACTablet # DeltaV
dynamicRecipes:
# Begin DeltaV additions
- LauncherSyringe
- MiniSyringe
# End DeltaV additions
- ChemicalPayload
- CryostasisBeaker
- BluespaceBeaker

View File

@ -2160,7 +2160,7 @@
parent: VendingMachineChemicals
id: VendingMachineChemicalsSyndicate
name: SyndieJuice
description: Not made with freshly squeezed syndies I hope.
description: Not made with freshly squeezed syndies I hope. Backwards compatible with standard ChemVend restocks. # DeltaV: Add chemvend part
components:
- type: VendingMachine
pack: ChemVendInventorySyndicate

View File

@ -50,18 +50,3 @@
# components:
# - BecomePsionicCondition
# - type: BecomeGolemCondition
- type: entity
id: RaiseGlimmerObjective
parent: BaseTraitorObjective
name: Raise Glimmer.
description: Get the glimmer above the specified amount.
components:
- type: Objective
difficulty: 2.5
#unique: false
icon:
sprite: Nyanotrasen/Icons/psi.rsi
state: psi
- type: RaiseGlimmerCondition
target: 500

View File

@ -49,8 +49,6 @@
weights:
RandomTraitorAliveObjective: 1
RandomTraitorProgressObjective: 1
RaiseGlimmerObjective: 0.5 # Nyanotrasen - Raise glimmer to a target amount, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
#Thief groups
- type: weightedRandom

View File

@ -5,10 +5,11 @@
icon:
sprite: Interface/Misc/research_disciplines.rsi
state: industrial
lockoutTier: 4 # DeltaV: Lockout occurs at t4
tierPrerequisites:
1: 0
2: 0.75
3: 0.75
2: 1 # DeltaV: raised to 1
3: 1 # DeltaV: raised to 1
- type: techDiscipline
id: Arsenal
@ -17,10 +18,11 @@
icon:
sprite: Interface/Misc/research_disciplines.rsi
state: arsenal
lockoutTier: 4 # DeltaV: Lockout occurs at t4
tierPrerequisites:
1: 0
2: 0.75
3: 0.75
2: 1 # DeltaV: raised to 1
3: 1 # DeltaV: raised to 1
- type: techDiscipline
id: Experimental
@ -29,10 +31,11 @@
icon:
sprite: Interface/Misc/research_disciplines.rsi
state: experimental
lockoutTier: 4 # DeltaV: Lockout occurs at t4
tierPrerequisites:
1: 0
2: 0.75
3: 0.75
2: 1 # DeltaV: raised to 1
3: 1 # DeltaV: raised to 1
- type: techDiscipline
id: CivilianServices
@ -41,7 +44,8 @@
icon:
sprite: Interface/Misc/research_disciplines.rsi
state: civilianservices
lockoutTier: 4 # DeltaV: Lockout occurs at t4
tierPrerequisites:
1: 0
2: 0.75
3: 0.75
2: 1 # DeltaV: raised to 1
3: 1 # DeltaV: raised to 1

View File

@ -116,7 +116,6 @@
- Giving a character additional access or a job because you are friends with the player who is playing that character.
- Trusting a character because you are friends with the player who is playing that character.
- Not fighting a character because you are friends with the player who is playing that character.
- Ignoring your objective to kill a character because your character and theirs became friends in a previous round.
## Metagrudging Examples
These are all examples of things that are prohibited by at least one metashield item that is never revealed IC.

View File

@ -4,7 +4,7 @@ Security, Justice, and Command roles are held to a higher standard of roleplay,
- Your character must act in a manner that NanoTrasen would reasonably hire them to this position.
- Your character is presumed to be sane, competent in their duties, and able to make decisions to the benefit of the station.
- Giving away Traitor objective items and sensitive equipment should be avoided in these roles. Your character should value them deeply.
- Leeway is given to making deals with criminals if the deal benefits the safety or situation of the crew and station.
- Leeway is given to making deals with criminals if the deal benefits the safety or situation of the crew and station OR if the deal involves items of a primarily sentimental value (e.g. HoP's Ian scrapbook, LO's lucky dollar).
- Leeway can be given in [color=#ff0000]extreme circumstances[/color] of emergency/crisis.
- The three departments are required to read and follow Delta-V Space Law, Standard Operating Procedure, Alert Procedure, and Company Policy to the best of their ability.
- [color=#ff0000]Circumstances and context may permit you to break these laws. However, the fact that this rule is malleable is not an excuse to ignore it entirely.[/color]

View File

@ -1,9 +1,12 @@
<Document>
# Rule C3: Antagonist Guidelines
[color=#ffff00]Being an antagonist does not allow you to stop playing a character. Determine how your character would react to being given these objectives, and work through it appropriately.[/color]
Through engaging in antagonistic activity, you should seek to make the round more engaging and fun as the primary driver of the narrative of a round. Succeeding as an antagonist should not be your goal, but rather telling the most interesting story for everyone involved.
- [color=#ff0000]Antagonists are free to complete their objectives through committing proportional damage. Through roleplay, damage becomes more proportional.[/color] Example: Holding the singulo hostage for a theft objective is acceptable, while simply singuloosing and using that chaos is unacceptable.
- Killing players unrelated to your immediate objective in a manner that results in their round removal should be avoided. Crew that do not make an attempt at self preservation, or engage in valid-hunting, are exempt from this.
- If you are concerned as to whether or not what you're about to do is allowed, feel free to AHelp and ask an admin for clarification. [color=#ff0000]Lack of administrator response does not constitute approval.[/color]
- While antagonists are [color=#ffff00]not required[/color] to complete their objectives, they are still encouraged to act as an antagonist in the round while roleplaying.
- Other antagonists are not necessarily your friends. Other antagonists are often free agents that you may negotiate with at your own risk.
- If you are a team antagonist, you must work with your partners to complete any shared objectives.
- Excessively lame tactics are strictly forbidden for all antags except for station-destroying antags, such as nuclear operatives or space dragons. Examples include:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

View File

@ -0,0 +1,30 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"copyright": "Created by Aikakakah (github) for Delta-V",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "equipped-INNERCLOTHING",
"directions": 4
},
{
"name": "rolled-equipped-INNERCLOTHING",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

View File

@ -23,6 +23,10 @@
"name": "direction_justice",
"directions": 4
},
{
"name": "direction_aicore",
"directions": 4
},
{
"name": "chapel"
}