Skip to content

Commit

Permalink
Merge pull request #390 from Kandiyaki/Syndizine
Browse files Browse the repository at this point in the history
Subjuzine
  • Loading branch information
formlessnameless authored Oct 1, 2024
2 parents 57d3aa4 + 703a2eb commit 673a9e2
Show file tree
Hide file tree
Showing 17 changed files with 360 additions and 3 deletions.
121 changes: 121 additions & 0 deletions Content.Server/EntityEffects/Effects/MakeSyndient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Content.Server.Forensics;
using Content.Server.Chat.Managers;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Speech.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.EntityEffects;
using Content.Shared.Humanoid;
using Content.Shared.Mind.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Random;
using Robust.Shared.Prototypes;
using YamlDotNet.Core.Tokens;
using System.Linq;
using Content.Server.Atmos.EntitySystems;

namespace Content.Server.EntityEffects.Effects;

public sealed partial class MakeSyndient : EntityEffect
{
//this is basically completely copied from MakeSentient, but with a bit of changes to how the ghost roles are listed
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability));

[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;

public override void Effect(EntityEffectBaseArgs args)
{

var entityManager = args.EntityManager;
var uid = args.TargetEntity;


// Let affected entities speak normally to make this effect different from, say, the "random sentience" event
// This also works on entities that already have a mind
// We call this before the mind check to allow things like player-controlled mice to be able to benefit from the effect
entityManager.RemoveComponent<ReplacementAccentComponent>(uid);
entityManager.RemoveComponent<MonkeyAccentComponent>(uid);

// Stops from adding a ghost role to things like people who already have a mind
if (entityManager.TryGetComponent<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
{
return;
}

//slightly hacky way to make sure it doesn't work on humanoid ghost roles that haven't been claimed yet
if (entityManager.TryGetComponent<HumanoidAppearanceComponent>(uid, out HumanoidAppearanceComponent? component))
{
return;
}
var forensicSys = args.EntityManager.System<ForensicsSystem>();

//hide your children, it's time to figure out whose blood is in this shit
if (args is EntityEffectReagentArgs reagentArgs)
{
//get all DNAs stored in the injected solution
List<DnaData> dnaDataList = new List<DnaData>();
if (reagentArgs.Source != null)
{
foreach (var reagent in reagentArgs.Source.Contents)
{
foreach (var data in reagent.Reagent.EnsureReagentData())
{
if (data is DnaData)
{
dnaDataList.Add(((DnaData)data));
}
}
}
//we have all the DNA in the activated subjuzine. get a random one and find the DNA's source.
if (dnaDataList.Count > 0)
{
DnaData chosenOne = dnaDataList[0];

String chosenName = forensicSys.GetNameFromDNA(chosenOne.DNA);
//we FINALLY have the name of the injector. jesus fuck.
//now, we build the role name, description, etc.

//Don't add a ghost role to things that already have ghost roles

String rules = (Loc.GetString("ghost-role-information-subjuzine-rules-1"));
rules = rules + chosenName;
rules = rules + (Loc.GetString("ghost-role-information-subjuzine-rules-2"));

if (entityManager.TryGetComponent(uid, out GhostRoleComponent? ghostRole))
{
//if there already was a ghost role, change the role description and rules to make it clear it's been injected with subjuzine
ghostRole = entityManager.GetComponent<GhostRoleComponent>(uid);
ghostRole.RoleDescription = Loc.GetString("ghost-role-information-subjuzine-description");
ghostRole.RoleRules = rules;
return;
}

ghostRole = entityManager.AddComponent<GhostRoleComponent>(uid);
entityManager.EnsureComponent<GhostTakeoverAvailableComponent>(uid);

var entityData = entityManager.GetComponent<MetaDataComponent>(uid);
ghostRole.RoleName = entityData.EntityName;
ghostRole.RoleDescription = Loc.GetString("ghost-role-information-subjuzine-description");
ghostRole.RoleRules = rules;


}
else //if there's no DNA in the DNA list, just act as if it was normal cognizine.
{
//Don't add a ghost role to things that already have ghost roles
if (entityManager.TryGetComponent(uid, out GhostRoleComponent? ghostRole))
{
return;
}

ghostRole = entityManager.AddComponent<GhostRoleComponent>(uid);
entityManager.EnsureComponent<GhostTakeoverAvailableComponent>(uid);

var entityData = entityManager.GetComponent<MetaDataComponent>(uid);
ghostRole.RoleName = entityData.EntityName;
ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
}
}
}
}
}
21 changes: 21 additions & 0 deletions Content.Server/Forensics/Systems/ForensicsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Robust.Shared.Random;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
using Robust.Shared.GameObjects;

namespace Content.Server.Forensics
{
Expand Down Expand Up @@ -134,6 +135,26 @@ public void CopyForensicsFrom(ForensicsComponent src, EntityUid target)
dest.Fingerprints.Add(print);
}
}
public string GetNameFromDNA(string DNA)
{
var query = EntityQueryEnumerator<DnaComponent>();

String outputName = "OH GOD OH FUCK IT'S BROKEN";
//iterate over every DNAcomponent in the server until you find one that matches the given DNA
while (query.MoveNext(out var sourceUID, out var sourceComp))
{
if (sourceComp.DNA.Equals(DNA))
{

if (EntityManager.TryGetComponent(sourceUID, out MetaDataComponent? metaData))
{
//output the name of the entity with the given DNA
outputName = metaData.EntityName;
}
}
}
return outputName;
}

public List<string> GetSolutionsDNA(EntityUid uid)
{
Expand Down
24 changes: 22 additions & 2 deletions Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,27 @@ private List<string> PerformReaction(Entity<SolutionComponent> soln, ReactionPro

var energy = reaction.ConserveEnergy ? solution.GetThermalEnergy(_prototypeManager) : 0;

List<ReagentData> dnaDataList = new List<ReagentData>();

//save reactant DNA to DNAlist
if (reaction.PreserveDNA)
{

foreach (var reagent in solution.Contents)
{

foreach (var data in reagent.Reagent.EnsureReagentData())
{
if (data is DnaData)
{
dnaDataList.Add((data));
}
}
}
}

//Remove reactants
foreach (var reactant in reaction.Reactants)
foreach (KeyValuePair<string, ReactantPrototype> reactant in reaction.Reactants)
{
if (!reactant.Value.Catalyst)
{
Expand All @@ -181,7 +200,7 @@ private List<string> PerformReaction(Entity<SolutionComponent> soln, ReactionPro
foreach (var product in reaction.Products)
{
products.Add(product.Key);
solution.AddReagent(product.Key, product.Value * unitReactions);
solution.AddReagent(new ReagentId(product.Key, dnaDataList), product.Value * unitReactions);
}

if (reaction.ConserveEnergy)
Expand All @@ -191,6 +210,7 @@ private List<string> PerformReaction(Entity<SolutionComponent> soln, ReactionPro
solution.Temperature = energy / newCap;
}


OnReaction(soln, reaction, null, unitReactions);

return products;
Expand Down
6 changes: 6 additions & 0 deletions Content.Shared/Chemistry/Reaction/ReactionPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public sealed partial class ReactionPrototype : IPrototype, IComparable<Reaction
/// </summary>
[DataField("effects", serverOnly: true)] public List<EntityEffect> Effects = new();

/// <summary>
/// If true, this reaction will attempt to transfer any DNA from the input chemicals to the output chemical.
/// </summary>
[DataField("preserveDNA")]
public bool PreserveDNA = false;

/// <summary>
/// How dangerous is this effect? Stuff like bicaridine should be low, while things like methamphetamine
/// or potas/water should be high.
Expand Down
7 changes: 7 additions & 0 deletions Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ ghost-role-information-giant-spider-rules = You are a [color=red][bold]Team Anta
ghost-role-information-cognizine-description = Made conscious with the magic of cognizine.
ghost-role-information-subjuzine-description = Made obedient with the magic of subjuzine.
ghost-role-information-subjuzine-rules-1 = You are a [color=#6495ed][bold]Familiar[/bold][/color] under the control of [color=red][bold]
ghost-role-information-subjuzine-rules-2 = [/bold][/color]. Follow your master's orders and keep their identity secret.
You don't remember any of your previous life, and you don't remember anything you learned as a ghost.
You are allowed to remember knowledge about the game in general, such as how to cook, how to use objects, etc.
You are absolutely [color=red]NOT[/color] allowed to remember, say, the name, appearance, etc. of your previous character.
ghost-role-information-hamster-name = Hamster
ghost-role-information-hamster-description = A grumpy little ball of fluff.
Expand Down
6 changes: 6 additions & 0 deletions Resources/Locale/en-US/paper/paper-misc.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ book-text-agrichemkit-manual = Thank you for choosing the safe-for-all-ages Nano
Unstable mutagen is entirely safe when used as a fertilizer, and NanoTrasen takes no responsibility for dead crops, excessive water bills, newly sentient plants asking existential questions, or flora-strangled farmhands that may coincidentally occur while using it.
Do not drink unstable mutagen. Wash your hands thoroughly after handing. Wash your eyes if you have looked at unstable mutagen for over 30 minutes in a 24 hour period. Store in a dark room between 293–295K. Do not use on corporate holidays. If you begin hearing voices telling you to drink unstable mutagen, please contact your doctor, head of personnel, or exorcist.
book-text-animal-friends-kit = Thank you for choosing the Animal Friends Kit!
Enclosed is a vial of dormant Subjuzine. Use the included syringe to draw 5 units of your blood, and put it into the vial to activate!
Injecting any non-sentient creature with Subjuzine will not only force them to follow your commands, but give them the gift of speech!
Good luck, Agent. Go make some animal friends!
book-text-combat-bakery-kit = Thank you for choosing our combat bakery kit!
Enclosed are two (2) CyberSun patented Throwing Croissants, and one (1) patent-pending Baguette Sword.
The included Donk Co. microwave board can construct a microwave capable of baking more weapons.
Expand Down
3 changes: 3 additions & 0 deletions Resources/Locale/en-US/reagents/meta/medicine.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ reagent-desc-ethylredoxrazine = Neutralises the effects of alcohol in the blood
reagent-name-cognizine = cognizine
reagent-desc-cognizine = A mysterious chemical which is able to make any non-sentient creature sentient.
reagent-name-subjuzine = subjuzine
reagent-desc-subjuzine = A devious alteration of cognizine that bends the creature's will to that of whoever injected them.
reagent-name-ethyloxyephedrine = ethyloxyephedrine
reagent-desc-ethyloxyephedrine = A mildly unstable medicine derived from desoxyephedrine, primarily used to combat narcolepsy.
Expand Down
4 changes: 4 additions & 0 deletions Resources/Locale/en-US/store/uplink-catalog.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ uplink-holoclown-kit-desc = A joint venture between Cybersun and Honk.co. Contai
uplink-holster-name = Shoulder Holster
uplink-holster-desc = A deep shoulder holster capable of holding many types of ballistics.
uplink-animal-friends-kit-name = Animal Friends Kit
uplink-animal-friends-kit-desc = A box containing 4 doses of subjuzine, an alteration of cognizine that forces the injected creature to your will. Also contains an empty syringe and two mice to use it on.
uplink-chest-rig-name = Chest Rig
uplink-chest-rig-desc = Explosion-resistant tactical webbing used for holding traitor goods.
Expand Down
18 changes: 18 additions & 0 deletions Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@
- id: DeathRattleImplanter
amount: 6

- type: entity
parent: [BoxCardboard, BaseSyndicateContraband]
id: AnimalFriendsKit
name: animal friends kit
description: Contains 5 doses of Subjuzine to convert animals into your henchmen. Just add blood!
components:
- type: Sprite
layers:
- state: box_of_doom
- state: syringe
- type: StorageFill
contents:
- id: MouseCube
amount: 2
- id: Syringe
- id: SubjuzineChemistryVial
- id: PaperWrittenAnimalFriendsKit

- type: entity
parent: [BoxCardboard, BaseSyndicateContraband]
id: CombatBakeryKit
Expand Down
11 changes: 10 additions & 1 deletion Resources/Prototypes/Catalog/Fills/Paper/manuals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,20 @@
- type: Paper
content: book-text-agrichemkit-manual

- type: entity
id: PaperWrittenAnimalFriendsKit
name: "animal friends kit instructions"
description: A small, handwritten note detailing how to use the animal friends kit.
parent: Paper
components:
- type: Paper
content: book-text-animal-friends-kit

- type: entity
id: PaperWrittenCombatBakeryKit
name: "combat bakery kit instructions"
description: "Eat note after reading."
parent: Paper
components:
- type: Paper
content: book-text-combat-bakery-kit
content: book-text-combat-bakery-kit
11 changes: 11 additions & 0 deletions Resources/Prototypes/Catalog/uplink_catalog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,17 @@
tags:
- NukeOpsUplink

- type: listing
id: UplinkAnimalFriendsKit
name: uplink-animal-friends-kit-name
description: uplink-animal-friends-kit-desc
icon: { sprite: /Textures/Mobs/Animals/mouse.rsi, state: icon-2 }
productEntity: AnimalFriendsKit
cost:
Telecrystal: 6
categories:
- UplinkAllies

- type: listing
id: UplinkReinforcementRadioSyndicate
name: uplink-reinforcement-radio-name
Expand Down
15 changes: 15 additions & 0 deletions Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,18 @@
reagents:
- ReagentId: Chlorine
Quantity: 5

- type: entity
id: SubjuzineChemistryVial
name: subjuzine vial
parent: BaseChemistryEmptyVial
components:
- type: SolutionContainerManager
solutions:
beaker:
maxVol: 30
reagents:
- ReagentId: Subjuzine
Quantity: 20
- type: Tag
tags: []
34 changes: 34 additions & 0 deletions Resources/Prototypes/Reagents/medicine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,40 @@
- !type:ReagentThreshold
min: 5

- type: reagent
id: Subjuzine
name: reagent-name-subjuzine
desc: reagent-desc-subjuzine
group: Medicine
physicalDesc: reagent-physical-desc-enigmatic
flavor: magical
color: "#a50ed8"
metabolisms:
Medicine:
effects:
- !type:MakeSentient
conditions:
- !type:ReagentThreshold
min: 5


- type: reagent
id: ActivatedSubjuzine
name: reagent-name-subjuzine
desc: reagent-desc-subjuzine
group: Medicine
physicalDesc: reagent-physical-desc-enigmatic
flavor: magical
color: "#911d06"
metabolisms:
Medicine:
effects:
- !type:MakeSyndient
conditions:
- !type:ReagentThreshold
min: 5


- type: reagent
id: Ethyloxyephedrine
name: reagent-name-ethyloxyephedrine
Expand Down
Loading

0 comments on commit 673a9e2

Please sign in to comment.