/Content.*/Stunnable/ @Princess-Cheeseballs
/Content.*/Nutrition/ @Princess-Cheeseballs
+/Content.*/EntityEffects @Princess-Cheeseballs @sowelipililimute
# SKREEEE
/Content.*.Database/ @PJB3005 @DrSmugleaf
SOLUTION_PATH = Path("..") / "SpaceStation14.sln"
# If this doesn't match the saved version we overwrite them all.
-CURRENT_HOOKS_VERSION = "3"
+CURRENT_HOOKS_VERSION = "4"
QUIET = len(sys.argv) == 2 and sys.argv[1] == "--quiet"
-#!/bin/bash
+#!/usr/bin/env bash
gitroot=$(git rev-parse --show-toplevel)
-#!/bin/bash
+#!/usr/bin/env bash
# Just call post-checkout since it does the same thing.
gitroot=$(git rev-parse --git-path hooks)
<DefaultWindow xmlns="https://spacestation14.io"
MinSize="650 290">
<BoxContainer Orientation="Vertical">
+ <!-- Privileged and target IDs, crew manifest button. -->
<GridContainer Columns="2">
<GridContainer Columns="3" HorizontalExpand="True">
<Label Text="{Loc 'id-card-console-window-privileged-id'}" />
</BoxContainer>
</GridContainer>
<Control MinSize="0 8" />
+ <!-- Full name and job title editing. -->
<GridContainer Columns="3" HSeparationOverride="4">
<Label Name="FullNameLabel" Text="{Loc 'id-card-console-window-full-name-label'}" />
<LineEdit Name="FullNameLineEdit" HorizontalExpand="True" />
<Button Name="JobTitleSaveButton" Text="{Loc 'id-card-console-window-save-button'}" Disabled="True" />
</GridContainer>
<Control MinSize="0 8" />
- <GridContainer Columns="2">
- <Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
- <OptionButton Name="JobPresetOptionButton" />
- </GridContainer>
+ <!-- Job preset selection, grant/revoke all access buttons. -->
+ <BoxContainer Margin="0 8 0 4">
+ <BoxContainer>
+ <Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
+ <OptionButton Name="JobPresetOptionButton" />
+ </BoxContainer>
+ <Control HorizontalExpand="True"/>
+ <BoxContainer>
+ <Button Name="SelectAllButton" Text="{Loc 'id-card-console-window-select-all-button'}" />
+ <Button Name="DeselectAllButton" Text="{Loc 'id-card-console-window-deselect-all-button'}" />
+ </BoxContainer>
+ </BoxContainer>
+ <!-- Individual access buttons -->
<Control Name="AccessLevelControlContainer" />
</BoxContainer>
</DefaultWindow>
JobPresetOptionButton.AddItem(Loc.GetString(job.Name), _jobPrototypeIds.Count - 1);
}
+ SelectAllButton.OnPressed += _ =>
+ {
+ SetAllAccess(true);
+ SubmitData();
+ };
+
+ DeselectAllButton.OnPressed += _ =>
+ {
+ SetAllAccess(false);
+ SubmitData();
+ };
+
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
_accessButtons.Populate(accessLevels, prototypeManager);
AccessLevelControlContainer.AddChild(_accessButtons);
}
}
- private void ClearAllAccess()
+ /// <param name="enabled">If true, every individual access button will be pressed. If false, each will be depressed.</param>
+ private void SetAllAccess(bool enabled)
{
foreach (var button in _accessButtons.ButtonsList.Values)
{
- if (button.Pressed)
- {
- button.Pressed = false;
- }
+ if (!button.Disabled && button.Pressed != enabled)
+ button.Pressed = enabled;
}
}
JobTitleLineEdit.Text = Loc.GetString(job.Name);
args.Button.SelectId(args.Id);
- ClearAllAccess();
+ SetAllAccess(false);
// this is a sussy way to do this
foreach (var access in job.Access)
var roleGroupCheckbox = new Button
{
Name = $"{groupName}GroupCheckbox",
- Text = "Ban all",
+ Text = Loc.GetString("role-bans-ban-group"),
Margin = new Thickness(0, 0, 5, 0),
ToggleMode = true,
};
TimeLine.Text = args.Text;
if (!double.TryParse(args.Text, out var result))
{
- ExpiresLabel.Text = "err";
+ ExpiresLabel.Text = Loc.GetString("ban-panel-expiry-error");
ErrorLevel |= ErrorLevelEnum.Minutes;
TimeLine.ModulateSelfOverride = Color.Red;
UpdateSubmitEnabled();
ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
{
Maximized = false,
- Title = "Admin Logs",
+ Title = Loc.GetString("admin-logs-title"),
Monitor = monitor,
Width = 1100,
Height = 400
+++ /dev/null
-using Content.Shared.Crayon;
-using Robust.Shared.GameObjects;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Client.Crayon
-{
- [RegisterComponent]
- public sealed partial class CrayonComponent : SharedCrayonComponent
- {
- [ViewVariables(VVAccess.ReadWrite)] public bool UIUpdateNeeded;
- [ViewVariables] public int Charges { get; set; }
- [ViewVariables] public int Capacity { get; set; }
- }
-}
using Content.Client.Items;
using Content.Client.Message;
using Content.Client.Stylesheets;
+using Content.Shared.Charges.Components;
+using Content.Shared.Charges.Systems;
using Content.Shared.Crayon;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
-using Robust.Shared.GameObjects;
-using Robust.Shared.GameStates;
-using Robust.Shared.Localization;
using Robust.Shared.Timing;
namespace Content.Client.Crayon;
public sealed class CrayonSystem : SharedCrayonSystem
{
- // Didn't do in shared because I don't think most of the server stuff can be predicted.
+ [Dependency] private readonly SharedChargesSystem _charges = default!;
+ [Dependency] private readonly EntityManager _entityManager = default!;
+
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState);
- Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent));
- }
-
- private static void OnCrayonHandleState(EntityUid uid, CrayonComponent component, ref ComponentHandleState args)
- {
- if (args.Current is not CrayonComponentState state) return;
- component.Color = state.Color;
- component.SelectedState = state.State;
- component.Charges = state.Charges;
- component.Capacity = state.Capacity;
-
- component.UIUpdateNeeded = true;
+ Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent, _charges, _entityManager));
}
private sealed class StatusControl : Control
{
- private readonly CrayonComponent _parent;
+ private readonly Entity<CrayonComponent> _crayon;
+ private readonly SharedChargesSystem _charges;
private readonly RichTextLabel _label;
+ private readonly int _capacity;
- public StatusControl(CrayonComponent parent)
+ public StatusControl(Entity<CrayonComponent> crayon, SharedChargesSystem charges, EntityManager entityManage)
{
- _parent = parent;
+ _crayon = crayon;
+ _charges = charges;
+ _capacity = entityManage.GetComponent<LimitedChargesComponent>(_crayon.Owner).MaxCharges;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
-
- parent.UIUpdateNeeded = true;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
- if (!_parent.UIUpdateNeeded)
- {
- return;
- }
-
- _parent.UIUpdateNeeded = false;
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label",
- ("color",_parent.Color),
- ("state",_parent.SelectedState),
- ("charges", _parent.Charges),
- ("capacity",_parent.Capacity)));
+ ("color",_crayon.Comp.Color),
+ ("state",_crayon.Comp.SelectedState),
+ ("charges", _charges.GetCurrentCharges(_crayon.Owner)),
+ ("capacity", _capacity)));
}
}
}
var container = new BoxContainer { Orientation = LayoutOrientation.Horizontal };
- var previousPageButton = new Button { Text = "Previous Page" };
+ var previousPageButton = new Button { Text = Loc.GetString("credits-window-previous-page-button") };
previousPageButton.OnPressed +=
_ => PopulateAttributions(attributionsContainer, count - AttributionsSourcesPerPage);
- var nextPageButton = new Button { Text = "Next Page" };
+ var nextPageButton = new Button { Text = Loc.GetString("credits-window-next-page-button") };
nextPageButton.OnPressed +=
_ => PopulateAttributions(attributionsContainer, count + AttributionsSourcesPerPage);
StyleClasses="LabelBig" />
<BoxContainer Orientation="Horizontal"
Margin="0 0 0 5">
- <Label Text="{Loc 'crew-monitoring-user-interface-job'}"
+ <Label Text="{Loc 'crew-monitoring-ui-job-label'}"
FontColorOverride="DarkGray" />
<TextureRect Name="PersonJobIcon"
TextureScale="2 2"
--- /dev/null
+using Content.Shared.Damage.Systems;
+
+namespace Content.Client.Damage.Systems;
+
+public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem;
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<humanoid:MarkingPicker Name="MarkingPickerWidget" />
<BoxContainer>
- <CheckBox Name="MarkingForced" Text="Force" Pressed="True" />
- <CheckBox Name="MarkingIgnoreSpecies" Text="Ignore Species" Pressed="True" />
+ <CheckBox Name="MarkingForced" Text="{Loc humanoid-marking-modifier-force}" Pressed="True" />
+ <CheckBox Name="MarkingIgnoreSpecies" Text="{Loc humanoid-marking-modifier-ignore-species}" Pressed="True" />
</BoxContainer>
<Collapsible HorizontalExpand="True">
- <CollapsibleHeading Title="Base layers" />
+ <CollapsibleHeading Title="{Loc humanoid-marking-modifier-base-layers}" />
<CollapsibleBody HorizontalExpand="True">
<BoxContainer Name="BaseLayersContainer" Orientation="Vertical" HorizontalExpand="True" />
</CollapsibleBody>
});
_enable = new CheckBox
{
- Text = "Enable",
+ Text = Loc.GetString("humanoid-marking-modifier-enable"),
HorizontalAlignment = HAlignment.Right
};
OnStateChanged!();
};
- var lineEditBox = new BoxContainer();
- lineEditBox.AddChild(new Label { Text = "Prototype id: "});
+ var lineEditBox = new BoxContainer { SeparationOverride = 4 };
+ lineEditBox.AddChild(new Label { Text = Loc.GetString("humanoid-marking-modifier-prototype-id") });
// TODO: This line edit should really be an options / dropdown selector, not text.
_lineEdit = new() { MinWidth = 200 };
_species.Clear();
_species.AddRange(_prototypeManager.EnumeratePrototypes<SpeciesPrototype>().Where(o => o.RoundStart));
+ _species.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
var speciesIds = _species.Select(o => o.ID).ToList();
for (var i = 0; i < _species.Count; i++)
continue;
if (!LocalizedNames.TryGetValue(netEntity, out var name))
- name = "Unknown";
+ name = Loc.GetString("navmap-unknown-entity");
var message = name + "\n" + Loc.GetString("navmap-location",
("x", MathF.Round(blip.Coordinates.X)),
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.Medical.CrewMonitoring"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
- Title="{Loc 'crew-monitoring-user-interface-title'}"
+ Title="{Loc crew-monitoring-ui-title}"
Resizable="False"
SetSize="1210 700"
MinSize="1210 700">
<BoxContainer Orientation="Vertical" Margin="0 0 10 0">
<controls:StripeBack>
<PanelContainer>
- <Label Name="StationName" Text="Unknown station" Align="Center" Margin="0 5 0 3"/>
+ <Label Name="StationName" Text="{Loc crew-monitoring-ui-no-station-label}" Align="Center" Margin="0 5 0 3"/>
</PanelContainer>
</controls:StripeBack>
<LineEdit Name="SearchLineEdit" HorizontalExpand="True"
- PlaceHolder="{Loc crew-monitor-filter-line-placeholder}" />
+ PlaceHolder="{Loc crew-monitoring-ui-filter-line-placeholder}" />
<ScrollContainer Name="SensorScroller"
VerticalExpand="True"
<!-- Table rows are filled by code -->
</BoxContainer>
<Label Name="NoServerLabel"
- Text="{Loc 'crew-monitoring-user-interface-no-server'}"
+ Text="{Loc crew-monitoring-ui-no-server-label}"
StyleClasses="LabelHeading"
FontColorOverride="Red"
HorizontalAlignment="Center"
<BoxContainer Orientation="Vertical">
<PanelContainer StyleClasses="LowDivider" />
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
- <Label Text="{Loc 'crew-monitoring-user-interface-flavor-left'}" StyleClasses="WindowFooterText" />
- <Label Text="{Loc 'crew-monitoring-user-interface-flavor-right'}" StyleClasses="WindowFooterText"
+ <Label Text="{Loc crew-monitoring-ui-flavor-left-label}" StyleClasses="WindowFooterText" />
+ <Label Text="{Loc crew-monitoring-ui-flavor-right-label}" StyleClasses="WindowFooterText"
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
HorizontalExpand = true,
};
- deparmentLabel.SetMessage(Loc.GetString("crew-monitoring-user-interface-no-department"));
+ deparmentLabel.SetMessage(Loc.GetString("crew-monitoring-ui-no-department-label"));
deparmentLabel.StyleClasses.Add(StyleNano.StyleClassTooltipActionDescription);
SensorsTable.AddChild(deparmentLabel);
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
- Title="NPC debug"
+ Title="{Loc npc-debug-overlay-window-title}"
MinSize="200 200">
<BoxContainer Name="Options" Orientation="Vertical" Margin="8 8">
<controls:StripeBack>
- <Label Text="NPC" HorizontalAlignment="Center"/>
+ <Label Text="{Loc npc-debug-overlay-window-section-npc-label}" HorizontalAlignment="Center"/>
</controls:StripeBack>
<BoxContainer Name="NPCBox" Orientation="Vertical">
- <CheckBox Name="NPCThonk" Text="Thonk"/>
+ <CheckBox Name="NPCThonk" Text="{Loc npc-debug-overlay-window-show-htn-tree-checkbox}"/>
</BoxContainer>
<controls:StripeBack>
- <Label Text="Pathfinder" HorizontalAlignment="Center"/>
+ <Label Text="{Loc npc-debug-overlay-window-section-pathfinder-label}" HorizontalAlignment="Center"/>
</controls:StripeBack>
<BoxContainer Name="PathfinderBox" Orientation="Vertical">
- <CheckBox Name="PathCrumbs" Text="Breadcrumbs"/>
- <CheckBox Name="PathPolys" Text="Polygons"/>
- <CheckBox Name="PathNeighbors" Text="Neighbors"/>
- <CheckBox Name="PathRouteCosts" Text="Route costs"/>
- <CheckBox Name="PathRoutes" Text="Routes"/>
+ <CheckBox Name="PathCrumbs" Text="{Loc npc-debug-overlay-window-path-breadcrumbs-checkbox}"/>
+ <CheckBox Name="PathPolys" Text="{Loc npc-debug-overlay-window-path-polygons-checkbox}"/>
+ <CheckBox Name="PathNeighbors" Text="{Loc npc-debug-overlay-window-path-neighbors-checkbox}"/>
+ <CheckBox Name="PathRouteCosts" Text="{Loc npc-debug-overlay-window-path-route-costs-checkbox}"/>
+ <CheckBox Name="PathRoutes" Text="{Loc npc-debug-overlay-window-path-routes-checkbox}"/>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>
+++ /dev/null
-using Content.Shared.PAI;
-
-namespace Content.Client.PAI
-{
- public sealed class PAISystem : SharedPAISystem
- {
- }
-}
if (xform.MapID != args.MapId)
continue;
- var other = _entManager.GetEntity(visuals.Target);
+ var other = visuals.Target;
if (!xformQuery.TryGetComponent(other, out var otherXform))
continue;
continue;
var texture = spriteSystem.Frame0(visuals.Sprite);
- var width = texture.Width / (float) EyeManager.PixelsPerMeter;
+ var width = texture.Width / (float)EyeManager.PixelsPerMeter;
var coordsA = xform.Coordinates;
var coordsB = otherXform.Coordinates;
var posA = xformSystem.ToMapCoordinates(coordsA).Position;
var posB = xformSystem.ToMapCoordinates(coordsB).Position;
- var diff = (posB - posA);
+ var diff = posB - posA;
var length = diff.Length();
var midPoint = diff / 2f + posA;
<!-- Station name -->
<controls:StripeBack>
<PanelContainer>
- <Label Name="StationName" Text="Unknown station" StyleClasses="LabelBig" Align="Center"/>
+ <Label Name="StationName" Text="{Loc 'station-map-unknown-station'}" StyleClasses="LabelBig" Align="Center"/>
</PanelContainer>
</controls:StripeBack>
}
}
- if (prototype.SpriteBodyMovementState is { } movementState)
- {
- var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
- spriteMovement.NoMovementLayers.Clear();
- spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
- {
- State = prototype.SpriteBodyState,
- };
- spriteMovement.MovementLayers.Clear();
- spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
- {
- State = movementState,
- };
- }
- else
- {
- RemComp<SpriteMovementComponent>(entity);
- }
-
base.UpdateEntityAppearance(entity, prototype);
}
}
--- /dev/null
+using Content.Shared.Silicons.Bots;
+
+namespace Content.Client.Silicons.Bots;
+
+public sealed partial class HugBotSystem : SharedHugBotSystem;
--- /dev/null
+using Content.Shared.Temperature.Systems;
+
+namespace Content.Client.Temperature.Systems;
+
+/// <summary>
+/// This exists so <see cref="SharedTemperatureSystem"/> runs on client/>
+/// </summary>
+public sealed class TemperatureSystem : SharedTemperatureSystem;
public StatValuesEui()
{
_window = new StatsWindow();
- _window.Title = "Melee stats";
+ _window.Title = Loc.GetString("stat-values-ui-title");
_window.OpenCentered();
_window.OnClose += Closed;
}
helper.ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
{
Maximized = false,
- Title = "Admin Help",
+ Title = Loc.GetString("bwoink-admin-title"),
Monitor = monitor,
Width = 900,
Height = 500
-<DefaultWindow Title="{Loc Make Ghost Role}"
+<DefaultWindow Title="{Loc make-ghost-roles-window-title}"
xmlns="https://spacestation14.io">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
- <Label Name="RoleEntityLabel" Text="Entity" />
+ <Label Name="RoleEntityLabel" Text="{Loc make-ghost-roles-window-entity-label}" />
<Label Name="RoleEntity" Text="" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RoleNameLabel" Text="Role Name" />
+ <Label Name="RoleNameLabel" Text="{Loc make-ghost-roles-window-role-name-label}" />
<LineEdit Name="RoleName" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RoleDescriptionLabel" Text="Role Description" />
+ <Label Name="RoleDescriptionLabel" Text="{Loc make-ghost-roles-window-role-description-label}" />
<LineEdit Name="RoleDescription" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RoleRulesLabel" Text="Role Rules" />
+ <Label Name="RoleRulesLabel" Text="{Loc make-ghost-roles-window-role-rules-label}" />
<LineEdit Name="RoleRules" HorizontalExpand="True" Text="{Loc ghost-role-component-default-rules}" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="MakeSentientLabel" Text="Make Sentient" />
+ <Label Name="MakeSentientLabel" Text="{Loc make-ghost-roles-window-make-sentient-label}" />
<CheckBox Name="MakeSentientCheckbox" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RaffleLabel" Text="Raffle Role?" />
+ <Label Name="RaffleLabel" Text="{Loc make-ghost-roles-window-raffle-role-label}" />
<OptionButton Name="RaffleButton" />
</BoxContainer>
<BoxContainer Name="RaffleCustomSettingsContainer" Orientation="Vertical" Visible="False">
<BoxContainer Orientation="Horizontal">
- <Label Name="RaffleInitialDurationLabel" Text="Initial Duration (s)" />
+ <Label Name="RaffleInitialDurationLabel" Text="{Loc make-ghost-roles-window-initial-duration-label}" />
<SpinBox Name="RaffleInitialDuration" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RaffleJoinExtendsDurationByLabel" Text="Joins Extend By (s)" />
+ <Label Name="RaffleJoinExtendsDurationByLabel" Text="{Loc make-ghost-roles-window-join-extends-by-label}" />
<SpinBox Name="RaffleJoinExtendsDurationBy" HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Label Name="RaffleMaxDurationLabel" Text="Max Duration (s)" />
+ <Label Name="RaffleMaxDurationLabel" Text="{Loc make-ghost-roles-window-max-duration-label}" />
<SpinBox Name="RaffleMaxDuration" HorizontalExpand="True" />
</BoxContainer>
</BoxContainer>
<BoxContainer Orientation="Horizontal">
- <Button Name="MakeButton" Text="Make" />
+ <Button Name="MakeButton" Text="{Loc make-ghost-roles-window-make-button}" />
</BoxContainer>
</BoxContainer>
RaffleMaxDuration.ValueChanged += OnRaffleDurationChanged;
- RaffleButton.AddItem("Don't raffle", RaffleDontRaffleId);
- RaffleButton.AddItem("Custom settings", RaffleCustomRaffleId);
+ RaffleButton.AddItem(Loc.GetString("make-ghost-roles-window-raffle-not-button"), RaffleDontRaffleId);
+ RaffleButton.AddItem(Loc.GetString("make-ghost-roles-window-raffle-custom-settings-button"), RaffleCustomRaffleId);
var raffleProtos =
_prototypeManager.EnumeratePrototypes<GhostRoleRaffleSettingsPrototype>();
_rafflePrototypes.Add(raffleProto);
var s = raffleProto.Settings;
var label =
- $"{raffleProto.ID} (initial {s.InitialDuration}s, max {s.MaxDuration}s, join adds {s.JoinExtendsDurationBy}s)";
+ Loc.GetString("make-ghost-roles-window-raffle-settings-label", ("id", raffleProto.ID), ("initialDuration", s.InitialDuration), ("maxDuration", s.MaxDuration), ("joinExtendsDurationBy", s.JoinExtendsDurationBy));
RaffleButton.AddItem(label, idx++);
}
if (RaffleInitialDuration.Value > RaffleMaxDuration.Value)
{
MakeButton.Disabled = true;
- MakeButton.ToolTip = "The initial duration must not exceed the maximum duration.";
+ MakeButton.ToolTip = Loc.GetString("make-ghost-roles-window-raffle-warning-tooltip");
}
else
{
HorizontalExpand = true,
Name = "StorageLabel",
ClipText = true,
- Text = "Dummy",
+ Text = Loc.GetString("comp-storage-window-dummy"),
StyleClasses =
{
"FancyWindowTitle",
[
"BaseChemistryEmptyVial", "DrinkShotGlass", "SodiumLightTube", "DrinkGlassCoupeShaped",
"LedLightBulb", "ExteriorLightTube", "LightTube", "DrinkGlass", "DimLightBulb", "LightBulb", "LedLightTube",
- "SheetRGlass1", "ChemistryEmptyBottle01", "WarmLightBulb",
+ "ChemistryEmptyBottle01", "WarmLightBulb",
];
private readonly HashSet<string> _compositionArbitrageIgnore =
{
Verb bolt = new()
{
- Text = bolts.BoltsDown ? "Unbolt" : "Bolt",
+ Text = Loc.GetString(bolts.BoltsDown ? "admin-verbs-unbolt" : "admin-verbs-bolt"),
Category = VerbCategory.Tricks,
Icon = bolts.BoltsDown
? new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/unbolt.png"))
{
Verb emergencyAccess = new()
{
- Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
+ Text = Loc.GetString(airlockComp.EmergencyAccess ? "admin-verbs-emergency-access-off" : "admin-verbs-emergency-access-on"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
Act = () =>
{
Verb rejuvenate = new()
{
- Text = "Rejuvenate",
+ Text = Loc.GetString("admin-verbs-rejuvenate"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rejuvenate.png")),
Act = () =>
{
Verb makeIndestructible = new()
{
- Text = "Make Indestructible",
+ Text = Loc.GetString("admin-verbs-make-indestructible"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
Act = () =>
{
Verb makeVulnerable = new()
{
- Text = "Make Vulnerable",
+ Text = Loc.GetString("admin-verbs-make-vulnerable"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
Act = () =>
{
Verb refillBattery = new()
{
- Text = "Refill Battery",
+ Text = Loc.GetString("admin-verbs-refill-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
Act = () =>
Verb drainBattery = new()
{
- Text = "Drain Battery",
+ Text = Loc.GetString("admin-verbs-drain-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
Act = () =>
Verb infiniteBattery = new()
{
- Text = "Infinite Battery",
+ Text = Loc.GetString("admin-verbs-infinite-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
Act = () =>
{
Verb blockUnanchor = new()
{
- Text = "Block Unanchoring",
+ Text = Loc.GetString("admin-verbs-block-unanchoring"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
Act = () =>
{
Verb refillInternalsO2 = new()
{
- Text = "Refill Internals Oxygen",
+ Text = Loc.GetString("admin-verbs-refill-internals-oxygen"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
Act = () =>
Verb refillInternalsN2 = new()
{
- Text = "Refill Internals Nitrogen",
+ Text = Loc.GetString("admin-verbs-refill-internals-nitrogen"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
Act = () =>
Verb refillInternalsPlasma = new()
{
- Text = "Refill Internals Plasma",
+ Text = Loc.GetString("admin-verbs-refill-internals-plasma"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
Act = () =>
{
Verb refillInternalsO2 = new()
{
- Text = "Refill Internals Oxygen",
+ Text = Loc.GetString("admin-verbs-refill-internals-oxygen"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
Act = () => RefillEquippedTanks(args.User, Gas.Oxygen),
Verb refillInternalsN2 = new()
{
- Text = "Refill Internals Nitrogen",
+ Text = Loc.GetString("admin-verbs-refill-internals-nitrogen"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
Act = () => RefillEquippedTanks(args.User, Gas.Nitrogen),
Verb refillInternalsPlasma = new()
{
- Text = "Refill Internals Plasma",
+ Text = Loc.GetString("admin-verbs-refill-internals-plasma"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
Act = () => RefillEquippedTanks(args.User, Gas.Plasma),
Verb sendToTestArena = new()
{
- Text = "Send to test arena",
+ Text = Loc.GetString("admin-verbs-send-to-test-arena"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
{
Verb grantAllAccess = new()
{
- Text = "Grant All Access",
+ Text = Loc.GetString("admin-verbs-grant-all-access"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
Act = () =>
Verb revokeAllAccess = new()
{
- Text = "Revoke All Access",
+ Text = Loc.GetString("admin-verbs-revoke-all-access"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
Act = () =>
{
Verb grantAllAccess = new()
{
- Text = "Grant All Access",
+ Text = Loc.GetString("admin-verbs-grant-all-access"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
Act = () =>
Verb revokeAllAccess = new()
{
- Text = "Revoke All Access",
+ Text = Loc.GetString("admin-verbs-revoke-all-access"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
Act = () =>
{
Verb adjustStack = new()
{
- Text = "Adjust Stack",
+ Text = Loc.GetString("admin-verbs-adjust-stack"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/adjust-stack.png")),
Act = () =>
{
// Unbounded intentionally.
- _quickDialog.OpenDialog(player, "Adjust stack", $"Amount (max {_stackSystem.GetMaxCount(stack)})", (int newAmount) =>
+ _quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-adjust-stack"), Loc.GetString("admin-verbs-dialog-adjust-stack-amount", ("max", _stackSystem.GetMaxCount(stack))), (int newAmount) =>
{
_stackSystem.SetCount(args.Target, newAmount, stack);
});
Verb fillStack = new()
{
- Text = "Fill Stack",
+ Text = Loc.GetString("admin-verbs-fill-stack"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill-stack.png")),
Act = () =>
Verb rename = new()
{
- Text = "Rename",
+ Text = Loc.GetString("admin-verbs-rename"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename.png")),
Act = () =>
{
- _quickDialog.OpenDialog(player, "Rename", "Name", (string newName) =>
+ _quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-rename-title"), Loc.GetString("admin-verbs-dialog-rename-name"), (string newName) =>
{
_metaSystem.SetEntityName(args.Target, newName);
});
Verb redescribe = new()
{
- Text = "Redescribe",
+ Text = Loc.GetString("admin-verbs-redescribe"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/redescribe.png")),
Act = () =>
{
- _quickDialog.OpenDialog(player, "Redescribe", "Description", (LongString newDescription) =>
+ _quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-redescribe-title"), Loc.GetString("admin-verbs-dialog-redescribe-description"), (LongString newDescription) =>
{
_metaSystem.SetEntityDescription(args.Target, newDescription.String);
});
Verb renameAndRedescribe = new()
{
- Text = "Redescribe",
+ Text = Loc.GetString("admin-verbs-rename-and-redescribe"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
Act = () =>
{
- _quickDialog.OpenDialog(player, "Rename & Redescribe", "Name", "Description",
+ _quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-rename-and-redescribe-title"), Loc.GetString("admin-verbs-dialog-rename-name"), Loc.GetString("admin-verbs-dialog-redescribe-description"),
(string newName, LongString newDescription) =>
{
var meta = MetaData(args.Target);
{
Verb barJobSlots = new()
{
- Text = "Bar job slots",
+ Text = Loc.GetString("admin-verbs-bar-job-slots"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bar_jobslots.png")),
Act = () =>
Verb locateCargoShuttle = new()
{
- Text = "Locate Cargo Shuttle",
+ Text = Loc.GetString("admin-verbs-locate-cargo-shuttle"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
Act = () =>
{
Verb refillBattery = new()
{
- Text = "Refill Battery",
+ Text = Loc.GetString("admin-verbs-refill-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
Act = () =>
Verb drainBattery = new()
{
- Text = "Drain Battery",
+ Text = Loc.GetString("admin-verbs-drain-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
Act = () =>
Verb infiniteBattery = new()
{
- Text = "Infinite Battery",
+ Text = Loc.GetString("admin-verbs-infinite-battery"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
Act = () =>
{
Verb haltMovement = new()
{
- Text = "Halt Movement",
+ Text = Loc.GetString("admin-verbs-halt-movement"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/halt.png")),
Act = () =>
{
Verb unpauseMap = new()
{
- Text = "Unpause Map",
+ Text = Loc.GetString("admin-verbs-unpause-map"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
Act = () =>
{
Verb pauseMap = new()
{
- Text = "Pause Map",
+ Text = Loc.GetString("admin-verbs-pause-map"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
Act = () =>
{
Verb snapJoints = new()
{
- Text = "Snap Joints",
+ Text = Loc.GetString("admin-verbs-snap-joints"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/snap_joints.png")),
Act = () =>
{
Verb minigunFire = new()
{
- Text = "Make Minigun",
+ Text = Loc.GetString("admin-verbs-make-minigun"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
Act = () =>
{
Verb setCapacity = new()
{
- Text = "Set Bullet Amount",
+ Text = Loc.GetString("admin-verbs-set-bullet-amount"),
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
Act = () =>
{
- _quickDialog.OpenDialog(player, "Set Bullet Amount", $"Amount (standard {ballisticAmmo.Capacity}):", (string amount) =>
+ _quickDialog.OpenDialog(player, Loc.GetString("admin-verbs-dialog-set-bullet-amount-title"), Loc.GetString("admin-verbs-dialog-set-bullet-amount-amount", ("cap", ballisticAmmo.Capacity)), (string amount) =>
{
if (!int.TryParse(amount, out var result))
return;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components;
using Content.Server.Stunnable;
-using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Server.Damage.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.FixedPoint;
using Content.Shared.Hands;
+using Content.Shared.Temperature.Components;
using Robust.Server.Audio;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Content.Server.Atmos.EntitySystems;
-using Content.Server.Temperature.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Rotting;
using Content.Shared.Body.Events;
using Content.Shared.Damage;
+using Content.Shared.Temperature.Components;
using Robust.Server.Containers;
using Robust.Shared.Physics.Components;
using Robust.Shared.Timing;
/// <summary>
/// Handles metabolizing various reagents with given effects.
/// </summary>
- [RegisterComponent, Access(typeof(MetabolizerSystem))]
+ [RegisterComponent, AutoGenerateComponentPause, Access(typeof(MetabolizerSystem))]
public sealed partial class MetabolizerComponent : Component
{
/// <summary>
/// The next time that reagents will be metabolized.
/// </summary>
- [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [DataField, AutoPausedField]
public TimeSpan NextUpdate;
/// <summary>
using Content.Server.Body.Components;
-using Content.Shared.Administration.Logs;
using Content.Shared.Body.Events;
using Content.Shared.Body.Organ;
+using Content.Shared.Body.Prototypes;
using Content.Shared.Body.Systems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Database;
+using Content.Shared.EntityConditions;
+using Content.Shared.EntityConditions.Conditions;
+using Content.Shared.EntityConditions.Conditions.Body;
using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Body;
+using Content.Shared.EntityEffects.Effects.Solution;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
-namespace Content.Server.Body.Systems
+namespace Content.Server.Body.Systems;
+
+/// <inheritdoc/>
+public sealed class MetabolizerSystem : SharedMetabolizerSystem
{
- /// <inheritdoc/>
- public sealed class MetabolizerSystem : SharedMetabolizerSystem
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
+ [Dependency] private readonly SharedEntityConditionsSystem _entityConditions = default!;
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
+
+ private EntityQuery<OrganComponent> _organQuery;
+ private EntityQuery<SolutionContainerManagerComponent> _solutionQuery;
+ private static readonly ProtoId<MetabolismGroupPrototype> Gas = "Gas";
+
+ public override void Initialize()
{
- [Dependency] private readonly IGameTiming _gameTiming = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
- [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
-
- private EntityQuery<OrganComponent> _organQuery;
- private EntityQuery<SolutionContainerManagerComponent> _solutionQuery;
+ base.Initialize();
- public override void Initialize()
- {
- base.Initialize();
+ _organQuery = GetEntityQuery<OrganComponent>();
+ _solutionQuery = GetEntityQuery<SolutionContainerManagerComponent>();
- _organQuery = GetEntityQuery<OrganComponent>();
- _solutionQuery = GetEntityQuery<SolutionContainerManagerComponent>();
+ SubscribeLocalEvent<MetabolizerComponent, ComponentInit>(OnMetabolizerInit);
+ SubscribeLocalEvent<MetabolizerComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<MetabolizerComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
+ }
- SubscribeLocalEvent<MetabolizerComponent, ComponentInit>(OnMetabolizerInit);
- SubscribeLocalEvent<MetabolizerComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<MetabolizerComponent, EntityUnpausedEvent>(OnUnpaused);
- SubscribeLocalEvent<MetabolizerComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
- }
+ private void OnMapInit(Entity<MetabolizerComponent> ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.AdjustedUpdateInterval;
+ }
- private void OnMapInit(Entity<MetabolizerComponent> ent, ref MapInitEvent args)
+ private void OnMetabolizerInit(Entity<MetabolizerComponent> entity, ref ComponentInit args)
+ {
+ if (!entity.Comp.SolutionOnBody)
{
- ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.AdjustedUpdateInterval;
+ _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName, out _);
}
-
- private void OnUnpaused(Entity<MetabolizerComponent> ent, ref EntityUnpausedEvent args)
+ else if (_organQuery.CompOrNull(entity)?.Body is { } body)
{
- ent.Comp.NextUpdate += args.PausedTime;
+ _solutionContainerSystem.EnsureSolution(body, entity.Comp.SolutionName, out _);
}
+ }
- private void OnMetabolizerInit(Entity<MetabolizerComponent> entity, ref ComponentInit args)
- {
- if (!entity.Comp.SolutionOnBody)
- {
- _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName, out _);
- }
- else if (_organQuery.CompOrNull(entity)?.Body is { } body)
- {
- _solutionContainerSystem.EnsureSolution(body, entity.Comp.SolutionName, out _);
- }
- }
+ private void OnApplyMetabolicMultiplier(Entity<MetabolizerComponent> ent, ref ApplyMetabolicMultiplierEvent args)
+ {
+ ent.Comp.UpdateIntervalMultiplier = args.Multiplier;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
- private void OnApplyMetabolicMultiplier(Entity<MetabolizerComponent> ent, ref ApplyMetabolicMultiplierEvent args)
+ var metabolizers = new ValueList<(EntityUid Uid, MetabolizerComponent Component)>(Count<MetabolizerComponent>());
+ var query = EntityQueryEnumerator<MetabolizerComponent>();
+
+ while (query.MoveNext(out var uid, out var comp))
{
- ent.Comp.UpdateIntervalMultiplier = args.Multiplier;
+ metabolizers.Add((uid, comp));
}
- public override void Update(float frameTime)
+ foreach (var (uid, metab) in metabolizers)
{
- base.Update(frameTime);
+ // Only update as frequently as it should
+ if (_gameTiming.CurTime < metab.NextUpdate)
+ continue;
- var metabolizers = new ValueList<(EntityUid Uid, MetabolizerComponent Component)>(Count<MetabolizerComponent>());
- var query = EntityQueryEnumerator<MetabolizerComponent>();
+ metab.NextUpdate += metab.AdjustedUpdateInterval;
+ TryMetabolize((uid, metab));
+ }
+ }
- while (query.MoveNext(out var uid, out var comp))
- {
- metabolizers.Add((uid, comp));
- }
+ private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, SolutionContainerManagerComponent?> ent)
+ {
+ _organQuery.Resolve(ent, ref ent.Comp2, logMissing: false);
+
+ // First step is get the solution we actually care about
+ var solutionName = ent.Comp1.SolutionName;
+ Solution? solution = null;
+ Entity<SolutionComponent>? soln = default!;
+ EntityUid? solutionEntityUid = null;
- foreach (var (uid, metab) in metabolizers)
+ if (ent.Comp1.SolutionOnBody)
+ {
+ if (ent.Comp2?.Body is { } body)
{
- // Only update as frequently as it should
- if (_gameTiming.CurTime < metab.NextUpdate)
- continue;
+ if (!_solutionQuery.Resolve(body, ref ent.Comp3, logMissing: false))
+ return;
- metab.NextUpdate += metab.AdjustedUpdateInterval;
- TryMetabolize((uid, metab));
+ _solutionContainerSystem.TryGetSolution((body, ent.Comp3), solutionName, out soln, out solution);
+ solutionEntityUid = body;
}
}
+ else
+ {
+ if (!_solutionQuery.Resolve(ent, ref ent.Comp3, logMissing: false))
+ return;
- private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, SolutionContainerManagerComponent?> ent)
+ _solutionContainerSystem.TryGetSolution((ent, ent), solutionName, out soln, out solution);
+ solutionEntityUid = ent;
+ }
+
+ if (solutionEntityUid is null
+ || soln is null
+ || solution is null
+ || solution.Contents.Count == 0)
{
- _organQuery.Resolve(ent, ref ent.Comp2, logMissing: false);
+ return;
+ }
- // First step is get the solution we actually care about
- var solutionName = ent.Comp1.SolutionName;
- Solution? solution = null;
- Entity<SolutionComponent>? soln = default!;
- EntityUid? solutionEntityUid = null;
+ // randomize the reagent list so we don't have any weird quirks
+ // like alphabetical order or insertion order mattering for processing
+ var list = solution.Contents.ToArray();
+ _random.Shuffle(list);
- if (ent.Comp1.SolutionOnBody)
+ int reagents = 0;
+ foreach (var (reagent, quantity) in list)
+ {
+ if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var proto))
+ continue;
+
+ var mostToRemove = FixedPoint2.Zero;
+ if (proto.Metabolisms is null)
{
- if (ent.Comp2?.Body is { } body)
+ if (ent.Comp1.RemoveEmpty)
{
- if (!_solutionQuery.Resolve(body, ref ent.Comp3, logMissing: false))
- return;
-
- _solutionContainerSystem.TryGetSolution((body, ent.Comp3), solutionName, out soln, out solution);
- solutionEntityUid = body;
+ solution.RemoveReagent(reagent, FixedPoint2.New(1));
}
- }
- else
- {
- if (!_solutionQuery.Resolve(ent, ref ent.Comp3, logMissing: false))
- return;
- _solutionContainerSystem.TryGetSolution((ent, ent), solutionName, out soln, out solution);
- solutionEntityUid = ent;
+ continue;
}
- if (solutionEntityUid is null
- || soln is null
- || solution is null
- || solution.Contents.Count == 0)
- {
+ // we're done here entirely if this is true
+ if (reagents >= ent.Comp1.MaxReagentsProcessable)
return;
- }
- // randomize the reagent list so we don't have any weird quirks
- // like alphabetical order or insertion order mattering for processing
- var list = solution.Contents.ToArray();
- _random.Shuffle(list);
- int reagents = 0;
- foreach (var (reagent, quantity) in list)
+ // loop over all our groups and see which ones apply
+ if (ent.Comp1.MetabolismGroups is null)
+ continue;
+
+ // TODO: Kill MetabolismGroups!
+ foreach (var group in ent.Comp1.MetabolismGroups)
{
- if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var proto))
+ if (!proto.Metabolisms.TryGetValue(group.Id, out var entry))
continue;
- var mostToRemove = FixedPoint2.Zero;
- if (proto.Metabolisms is null)
- {
- if (ent.Comp1.RemoveEmpty)
- {
- solution.RemoveReagent(reagent, FixedPoint2.New(1));
- }
+ var rate = entry.MetabolismRate * group.MetabolismRateModifier;
- continue;
- }
-
- // we're done here entirely if this is true
- if (reagents >= ent.Comp1.MaxReagentsProcessable)
- return;
+ // Remove $rate, as long as there's enough reagent there to actually remove that much
+ mostToRemove = FixedPoint2.Clamp(rate, 0, quantity);
+ var scale = (float) mostToRemove;
- // loop over all our groups and see which ones apply
- if (ent.Comp1.MetabolismGroups is null)
- continue;
+ // TODO: This is a very stupid workaround to lungs heavily relying on scale = reagent quantity. Needs lung and metabolism refactors to remove.
+ // TODO: Lungs just need to have their scale be equal to the mols consumed, scale needs to be not hardcoded either and configurable per metabolizer...
+ if (group.Id != Gas)
+ scale /= (float) entry.MetabolismRate;
- foreach (var group in ent.Comp1.MetabolismGroups)
+ // if it's possible for them to be dead, and they are,
+ // then we shouldn't process any effects, but should probably
+ // still remove reagents
+ if (TryComp<MobStateComponent>(solutionEntityUid.Value, out var state))
{
- if (!proto.Metabolisms.TryGetValue(group.Id, out var entry))
+ if (!proto.WorksOnTheDead && _mobStateSystem.IsDead(solutionEntityUid.Value, state))
continue;
+ }
- var rate = entry.MetabolismRate * group.MetabolismRateModifier;
+ var actualEntity = ent.Comp2?.Body ?? solutionEntityUid.Value;
- // Remove $rate, as long as there's enough reagent there to actually remove that much
- mostToRemove = FixedPoint2.Clamp(rate, 0, quantity);
+ // do all effects, if conditions apply
+ foreach (var effect in entry.Effects)
+ {
+ if (scale < effect.MinScale)
+ continue;
- float scale = (float) mostToRemove / (float) rate;
+ // See if conditions apply
+ if (effect.Conditions != null && !CanMetabolizeEffect(actualEntity, ent, soln.Value, effect.Conditions))
+ continue;
- // if it's possible for them to be dead, and they are,
- // then we shouldn't process any effects, but should probably
- // still remove reagents
- if (TryComp<MobStateComponent>(solutionEntityUid.Value, out var state))
- {
- if (!proto.WorksOnTheDead && _mobStateSystem.IsDead(solutionEntityUid.Value, state))
- continue;
- }
+ ApplyEffect(effect);
- var actualEntity = ent.Comp2?.Body ?? solutionEntityUid.Value;
- var args = new EntityEffectReagentArgs(actualEntity, EntityManager, ent, solution, mostToRemove, proto, null, scale);
+ }
- // do all effects, if conditions apply
- foreach (var effect in entry.Effects)
+ // TODO: We should have to do this with metabolism. ReagentEffect struct needs refactoring and so does metabolism!
+ void ApplyEffect(EntityEffect effect)
+ {
+ switch (effect)
{
- if (!effect.ShouldApply(args, _random))
- continue;
-
- if (effect.ShouldLog)
- {
- _adminLogger.Add(
- LogType.ReagentEffect,
- effect.LogImpact,
- $"Metabolism effect {effect.GetType().Name:effect}"
- + $" of reagent {proto.LocalizedName:reagent}"
- + $" applied on entity {actualEntity:entity}"
- + $" at {Transform(actualEntity).Coordinates:coordinates}"
- );
- }
-
- effect.Effect(args);
+ case ModifyLungGas:
+ _entityEffects.ApplyEffect(ent, effect, scale);
+ break;
+ case AdjustReagent:
+ _entityEffects.ApplyEffect(soln.Value, effect, scale);
+ break;
+ default:
+ _entityEffects.ApplyEffect(actualEntity, effect, scale);
+ break;
}
}
+ }
- // remove a certain amount of reagent
- if (mostToRemove > FixedPoint2.Zero)
- {
- solution.RemoveReagent(reagent, mostToRemove);
+ // remove a certain amount of reagent
+ if (mostToRemove > FixedPoint2.Zero)
+ {
+ solution.RemoveReagent(reagent, mostToRemove);
- // We have processed a reagant, so count it towards the cap
- reagents += 1;
- }
+ // We have processed a reagant, so count it towards the cap
+ reagents += 1;
}
+ }
- _solutionContainerSystem.UpdateChemicals(soln.Value);
+ _solutionContainerSystem.UpdateChemicals(soln.Value);
+ }
+
+ /// <summary>
+ /// Public API to check if a certain metabolism effect can be applied to an entity.
+ /// TODO: With metabolism refactor make this logic smarter and unhardcode the old hardcoding entity effects used to have for metabolism!
+ /// </summary>
+ /// <param name="body">The body metabolizing the effects</param>
+ /// <param name="organ">The organ doing the metabolizing</param>
+ /// <param name="solution">The solution we are metabolizing from</param>
+ /// <param name="conditions">The conditions that need to be met to metabolize</param>
+ /// <returns>True if we can metabolize! False if we cannot!</returns>
+ public bool CanMetabolizeEffect(EntityUid body, EntityUid organ, Entity<SolutionComponent> solution, EntityCondition[] conditions)
+ {
+ foreach (var condition in conditions)
+ {
+ switch (condition)
+ {
+ // Need specific handling of specific conditions since Metabolism is funny like that.
+ // TODO: MetabolizerTypes should be handled well before this stage by metabolism itself.
+ case MetabolizerTypeCondition:
+ if (_entityConditions.TryCondition(organ, condition))
+ continue;
+ break;
+ case ReagentCondition:
+ if (_entityConditions.TryCondition(solution, condition))
+ continue;
+ break;
+ default:
+ if (_entityConditions.TryCondition(body, condition))
+ continue;
+ break;
+ }
+
+ return false;
}
+
+ return true;
}
}
+
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Chat.Systems;
-using Content.Server.EntityEffects;
using Content.Shared.Body.Systems;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Database;
+using Content.Shared.EntityConditions;
+using Content.Shared.EntityConditions.Conditions.Body;
using Content.Shared.EntityEffects;
-using Content.Shared.EntityEffects.EffectConditions;
using Content.Shared.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects.Body;
using Content.Shared.Mobs.Systems;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmosSys = default!;
[Dependency] private readonly BodySystem _bodySystem = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly DamageableSystem _damageableSys = default!;
[Dependency] private readonly LungSystem _lungSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
- [Dependency] private readonly IPrototypeManager _protoMan = default!;
+ [Dependency] private readonly SharedEntityConditionsSystem _entityConditions = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
- [Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly EntityEffectSystem _entityEffect = default!;
private static readonly ProtoId<MetabolismGroupPrototype> GasId = new("Gas");
}
}
- // TODO generalize condition checks
// this is pretty janky, but I just want to bodge a method that checks if an entity can breathe a gas mixture
// Applying actual reaction effects require a full ReagentEffectArgs struct.
bool CanMetabolize(EntityEffect effect)
if (effect.Conditions == null)
return true;
+ // TODO: Use Metabolism Public API to do this instead, once that API has been built.
foreach (var cond in effect.Conditions)
{
- if (cond is OrganType organ && !_entityEffect.OrganCondition(organ, lung))
+ if (cond is MetabolizerTypeCondition organ && !_entityConditions.TryCondition(lung, organ))
return false;
}
using Content.Server.Body.Components;
-using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.ActionBlocker;
+using Content.Shared.Temperature.Components;
using Robust.Shared.Timing;
namespace Content.Server.Body.Systems;
using Content.Server.Botany.Components;
using Content.Server.Botany.Systems;
-using Content.Server.EntityEffects;
+using Content.Server.EntityEffects.Effects.Botany;
using Content.Shared.Atmos;
using Content.Shared.Database;
+using Content.Shared.EntityEffects;
using Content.Shared.Random;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
[DataField("Inherent")] public bool Inherent = true;
}
-// TODO reduce the number of friends to a reasonable level. Requires ECS-ing things like plant holder component.
+// TODO Make Botany ECS and give it a proper API. I removed the limited access of this class because it's egregious how many systems needed access to it due to a lack of an actual API.
+/// <remarks>
+/// SeedData is no longer restricted because the number of friends is absolutely unreasonable.
+/// This entire data definition is unreasonable. I felt genuine fear looking at this, this is horrific. Send help.
+/// </remarks>
+// TODO: Hit Botany with hammers
[Virtual, DataDefinition]
-[Access(typeof(BotanySystem), typeof(PlantHolderSystem), typeof(SeedExtractorSystem), typeof(PlantHolderComponent), typeof(EntityEffectSystem), typeof(MutationSystem))]
public partial class SeedData
{
#region Tracking
public sealed partial class BotanySystem
{
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
+
public void ProduceGrown(EntityUid uid, ProduceComponent produce)
{
if (!TryGetSeed(produce, out var seed))
foreach (var mutation in seed.Mutations)
{
if (mutation.AppliesToProduce)
- {
- var args = new EntityEffectBaseArgs(uid, EntityManager);
- mutation.Effect.Effect(args);
- }
+ _entityEffects.TryApplyEffect(uid, mutation.Effect);
}
if (!_solutionContainerSystem.EnsureSolution(uid,
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
private RandomPlantMutationListPrototype _randomMutations = default!;
public override void Initialize()
if (Random(Math.Min(mutation.BaseOdds * severity, 1.0f)))
{
if (mutation.AppliesToPlant)
- {
- var args = new EntityEffectBaseArgs(plantHolder, EntityManager);
- mutation.Effect.Effect(args);
- }
+ _entityEffects.TryApplyEffect(plantHolder, mutation.Effect);
+
// Stat adjustments do not persist by being an attached effect, they just change the stat.
if (mutation.Persists && !seed.Mutations.Any(m => m.Name == mutation.Name))
seed.Mutations.Add(mutation);
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Content.Shared.Administration.Logs;
+using Content.Shared.Chemistry.Reaction;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
+using Content.Shared.EntityEffects;
using Content.Shared.Kitchen.Components;
using Content.Shared.Labels.Components;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
public const float HydroponicsSpeedMultiplier = 1f;
public const float HydroponicsConsumptionMultiplier = 2f;
foreach (var entry in _solutionContainerSystem.RemoveEachReagent(component.SoilSolution.Value, amt))
{
var reagentProto = _prototype.Index<ReagentPrototype>(entry.Reagent.Prototype);
- reagentProto.ReactionPlant(uid, entry, solution, EntityManager, _random, _adminLogger);
+ _entityEffects.ApplyEffects(uid, reagentProto.PlantMetabolisms.ToArray());
}
}
if (autoEmotePrototype.WithChat)
{
- _chatSystem.TryEmoteWithChat(uid, autoEmotePrototype.EmoteId, autoEmotePrototype.HiddenFromChatWindow ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal);
+ _chatSystem.TryEmoteWithChat(uid,
+ autoEmotePrototype.EmoteId,
+ autoEmotePrototype.HiddenFromChatWindow ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal,
+ ignoreActionBlocker: autoEmotePrototype.IgnoreActionBlocker,
+ forceEmote: autoEmotePrototype.Force);
}
else
{
{
foreach (var effect in entry.Effects)
{
- shell.WriteLine(effect.GuidebookEffectDescription(_prototype, EntityManager.EntitySysManager) ??
+ shell.WriteLine(reagent.GuidebookReagentEffectDescription(_prototype, EntityManager.EntitySysManager, effect, entry.MetabolismRate) ??
Loc.GetString($"cmd-dumpreagentguidetext-skipped", ("effect", effect.GetType())));
}
}
using Content.Shared.Clothing;
using Content.Shared.Hands.Components;
using Content.Shared.Humanoid;
+using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Content.Shared.Preferences;
[Dependency] private readonly InventorySystem _invSystem = default!;
[Dependency] private readonly SharedStationSpawningSystem _spawningSystem = default!;
- public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null)
+ public bool SetOutfit(EntityUid target, string gear, Action<EntityUid, EntityUid>? onEquipped = null, bool unremovable = false)
{
if (!EntityManager.TryGetComponent(target, out InventoryComponent? inventoryComponent))
return false;
}
_invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
+ if (unremovable)
+ EnsureComp<UnremoveableComponent>(equipmentEntity);
onEquipped?.Invoke(target, equipmentEntity);
}
using Content.Shared.Chat.Prototypes;
using Robust.Shared.Random;
using Content.Shared.Stunnable;
-using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
using Content.Server.Emoting.Systems;
public sealed class CluwneSystem : EntitySystem
{
- private static readonly ProtoId<DamageGroupPrototype> GeneticDamageGroup = "Genetic";
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
/// <summary>
/// On death removes active comps and gives genetic damage to prevent cloning, reduce this to allow cloning.
/// </summary>
- private void OnMobState(EntityUid uid, CluwneComponent component, MobStateChangedEvent args)
+ private void OnMobState(Entity<CluwneComponent> ent, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
{
- RemComp<CluwneComponent>(uid);
- RemComp<ClumsyComponent>(uid);
- RemComp<AutoEmoteComponent>(uid);
- var damageSpec = new DamageSpecifier(_prototypeManager.Index(GeneticDamageGroup), 300);
- _damageableSystem.TryChangeDamage(uid, damageSpec);
+ RemComp<CluwneComponent>(ent.Owner);
+ RemComp<ClumsyComponent>(ent.Owner);
+ RemComp<AutoEmoteComponent>(ent.Owner);
+ _damageableSystem.TryChangeDamage(ent.Owner, ent.Comp.RevertDamage);
}
}
/// <summary>
/// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
/// </summary>
- private void OnComponentStartup(EntityUid uid, CluwneComponent component, ComponentStartup args)
+ private void OnComponentStartup(Entity<CluwneComponent> ent, ref ComponentStartup args)
{
- if (component.EmoteSoundsId == null)
+ if (ent.Comp.EmoteSoundsId == null)
return;
- _prototypeManager.TryIndex(component.EmoteSoundsId, out EmoteSounds);
- EnsureComp<AutoEmoteComponent>(uid);
- _autoEmote.AddEmote(uid, "CluwneGiggle");
- EnsureComp<ClumsyComponent>(uid);
+ _prototypeManager.TryIndex(ent.Comp.EmoteSoundsId, out EmoteSounds);
- _popupSystem.PopupEntity(Loc.GetString("cluwne-transform", ("target", uid)), uid, PopupType.LargeCaution);
- _audio.PlayPvs(component.SpawnSound, uid);
- _nameMod.RefreshNameModifiers(uid);
+ if (ent.Comp.RandomEmote && ent.Comp.AutoEmoteId != null)
+ {
+ EnsureComp<AutoEmoteComponent>(ent.Owner);
+ _autoEmote.AddEmote(ent.Owner, ent.Comp.AutoEmoteId);
+ }
+
+ EnsureComp<ClumsyComponent>(ent.Owner);
+
+ var transformMessage = Loc.GetString(ent.Comp.TransformMessage, ("target", ent.Owner));
+
+ _popupSystem.PopupEntity(transformMessage, ent.Owner, PopupType.LargeCaution);
+ _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
+
+ _nameMod.RefreshNameModifiers(ent.Owner);
- _outfitSystem.SetOutfit(uid, "CluwneGear");
+
+ _outfitSystem.SetOutfit(ent.Owner, ent.Comp.OutfitId, unremovable: true);
}
/// <summary>
/// Handles the timing on autoemote as well as falling over and honking.
/// </summary>
- private void OnEmote(EntityUid uid, CluwneComponent component, ref EmoteEvent args)
+ private void OnEmote(Entity<CluwneComponent> ent, ref EmoteEvent args)
{
if (args.Handled)
return;
- args.Handled = _chat.TryPlayEmoteSound(uid, EmoteSounds, args.Emote);
- if (_robustRandom.Prob(component.GiggleRandomChance))
+ if (!ent.Comp.RandomEmote)
+ return;
+
+ args.Handled = _chat.TryPlayEmoteSound(ent.Owner, EmoteSounds, args.Emote);
+
+ if (_robustRandom.Prob(ent.Comp.GiggleRandomChance))
{
- _audio.PlayPvs(component.SpawnSound, uid);
- _chat.TrySendInGameICMessage(uid, "honks", InGameICChatType.Emote, ChatTransmitRange.Normal);
+ _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
+ _chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.GiggleEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
}
- else if (_robustRandom.Prob(component.KnockChance))
+ else if (_robustRandom.Prob(ent.Comp.KnockChance))
{
- _audio.PlayPvs(component.KnockSound, uid);
- _stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(component.ParalyzeTime));
- _chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
+ _audio.PlayPvs(ent.Comp.KnockSound, ent.Owner);
+ _stunSystem.TryUpdateParalyzeDuration(ent.Owner, TimeSpan.FromSeconds(ent.Comp.ParalyzeTime));
+ _chat.TrySendInGameICMessage(ent.Owner, Loc.GetString(ent.Comp.KnockEmote), InGameICChatType.Emote, ChatTransmitRange.Normal);
}
}
/// <summary>
/// Applies "Cluwnified" prefix
/// </summary>
- private void OnRefreshNameModifiers(Entity<CluwneComponent> entity, ref RefreshNameModifiersEvent args)
+ private void OnRefreshNameModifiers(Entity<CluwneComponent> ent, ref RefreshNameModifiersEvent args)
{
- args.AddModifier("cluwne-name-prefix");
+ args.AddModifier(ent.Comp.NamePrefix);
}
}
using Content.Shared.Radio.EntitySystems;
using Content.Shared.Stacks;
using Content.Shared.Temperature;
+using Content.Shared.Temperature.Components;
using Content.Shared.Tools.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
+++ /dev/null
-using Content.Server.UserInterface;
-using Content.Shared.Crayon;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-
-namespace Content.Server.Crayon
-{
- [RegisterComponent]
- public sealed partial class CrayonComponent : SharedCrayonComponent
- {
- [DataField("useSound")] public SoundSpecifier? UseSound;
-
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("selectableColor")]
- public bool SelectableColor { get; set; }
-
- [ViewVariables(VVAccess.ReadWrite)]
- public int Charges { get; set; }
-
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("capacity")]
- public int Capacity { get; set; } = 30;
-
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("deleteEmpty")]
- public bool DeleteEmpty = true;
- }
-}
using Content.Server.Administration.Logs;
using Content.Server.Decals;
using Content.Server.Popups;
+using Content.Shared.Charges.Systems;
using Content.Shared.Crayon;
using Content.Shared.Database;
using Content.Shared.Decals;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
-using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Server.Crayon;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedChargesSystem _charges = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent<CrayonComponent, ComponentInit>(OnCrayonInit);
+
+ SubscribeLocalEvent<CrayonComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI);
SubscribeLocalEvent<CrayonComponent, CrayonColorMessage>(OnCrayonBoundUIColor);
SubscribeLocalEvent<CrayonComponent, UseInHandEvent>(OnCrayonUse, before: new[] { typeof(FoodSystem) });
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(OnCrayonAfterInteract, after: new[] { typeof(FoodSystem) });
SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped);
- SubscribeLocalEvent<CrayonComponent, ComponentGetState>(OnCrayonGetState);
}
- private static void OnCrayonGetState(EntityUid uid, CrayonComponent component, ref ComponentGetState args)
+ private void OnMapInit(Entity<CrayonComponent> ent, ref MapInitEvent args)
{
- args.State = new CrayonComponentState(component.Color, component.SelectedState, component.Charges, component.Capacity);
+ // Get the first one from the catalog and set it as default
+ var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
+ ent.Comp.SelectedState = decal?.ID ?? string.Empty;
+ Dirty(ent);
}
private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, AfterInteractEvent args)
if (args.Handled || !args.CanReach)
return;
- if (component.Charges <= 0)
+ if (_charges.IsEmpty(uid))
{
if (component.DeleteEmpty)
UseUpCrayon(uid, args.User);
if (component.UseSound != null)
_audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f));
- // Decrease "Ammo"
- component.Charges--;
- Dirty(uid, component);
+ _charges.TryUseCharge(uid);
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
args.Handled = true;
- if (component.DeleteEmpty && component.Charges <= 0)
+ if (component.DeleteEmpty && _charges.IsEmpty(uid))
UseUpCrayon(uid, args.User);
else
- _uiSystem.ServerSendUiMessage(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
+ _uiSystem.ServerSendUiMessage(uid, CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
}
private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
if (args.Handled)
return;
- if (!_uiSystem.HasUi(uid, SharedCrayonComponent.CrayonUiKey.Key))
- {
+ if (!_uiSystem.HasUi(uid, CrayonUiKey.Key))
return;
- }
- _uiSystem.TryToggleUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
+ _uiSystem.TryToggleUi(uid, CrayonUiKey.Key, args.User);
- _uiSystem.SetUiState(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color));
+ _uiSystem.SetUiState(uid, CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color));
args.Handled = true;
}
return;
component.SelectedState = args.State;
-
Dirty(uid, component);
}
private void OnCrayonBoundUIColor(EntityUid uid, CrayonComponent component, CrayonColorMessage args)
{
- // you still need to ensure that the given color is a valid color
+ // Ensure that the given color can be changed or already matches
if (!component.SelectableColor || args.Color == component.Color)
return;
component.Color = args.Color;
Dirty(uid, component);
-
- }
-
- private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentInit args)
- {
- component.Charges = component.Capacity;
-
- // Get the first one from the catalog and set it as default
- var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
- component.SelectedState = decal?.ID ?? string.Empty;
- Dirty(uid, component);
}
private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args)
{
// TODO: Use the existing event.
- _uiSystem.CloseUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
+ _uiSystem.CloseUi(uid, CrayonUiKey.Key, args.User);
}
private void UseUpCrayon(EntityUid uid, EntityUid user)
+++ /dev/null
-using Content.Server.Damage.Systems;
-using Content.Shared.Damage;
-
-namespace Content.Server.Damage.Components
-{
- [Access(typeof(DamageOtherOnHitSystem))]
- [RegisterComponent]
- public sealed partial class DamageOtherOnHitComponent : Component
- {
- [DataField("ignoreResistances")]
- [ViewVariables(VVAccess.ReadWrite)]
- public bool IgnoreResistances = false;
-
- [DataField("damage", required: true)]
- [ViewVariables(VVAccess.ReadWrite)]
- public DamageSpecifier Damage = default!;
-
- }
-}
using Content.Server.Administration.Logs;
-using Content.Server.Damage.Components;
using Content.Server.Weapons.Ranged.Systems;
-using Content.Shared.CombatMode.Pacification;
using Content.Shared.Camera;
using Content.Shared.Damage;
-using Content.Shared.Damage.Events;
+using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.Effects;
using Content.Shared.Mobs.Components;
using Content.Shared.Throwing;
-using Content.Shared.Wires;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
-namespace Content.Server.Damage.Systems
-{
- public sealed class DamageOtherOnHitSystem : EntitySystem
- {
- [Dependency] private readonly IAdminLogManager _adminLogger = default!;
- [Dependency] private readonly GunSystem _guns = default!;
- [Dependency] private readonly DamageableSystem _damageable = default!;
- [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
- [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
- [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
+namespace Content.Server.Damage.Systems;
- public override void Initialize()
- {
- SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
- SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
- SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
- }
+public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem
+{
+ [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly GunSystem _guns = default!;
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+ [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
+ [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
- private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
- {
- if (TerminatingOrDeleted(args.Target))
- return;
+ public override void Initialize()
+ {
+ base.Initialize();
- var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
+ SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
+ }
- // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
- if (dmg != null && HasComp<MobStateComponent>(args.Target))
- _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
+ private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
+ {
+ if (TerminatingOrDeleted(args.Target))
+ return;
- if (dmg is { Empty: false })
- {
- _color.RaiseEffect(Color.Red, new List<EntityUid>() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager));
- }
+ var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
- _guns.PlayImpactSound(args.Target, dmg, null, false);
- if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
- {
- var direction = body.LinearVelocity.Normalized();
- _sharedCameraRecoil.KickCamera(args.Target, direction);
- }
- }
+ // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
+ if (dmg != null && HasComp<MobStateComponent>(args.Target))
+ _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
- private void OnDamageExamine(EntityUid uid, DamageOtherOnHitComponent component, ref DamageExamineEvent args)
+ if (dmg is { Empty: false })
{
- _damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(component.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
+ _color.RaiseEffect(Color.Red, [args.Target], Filter.Pvs(args.Target, entityManager: EntityManager));
}
- /// <summary>
- /// Prevent players with the Pacified status effect from throwing things that deal damage.
- /// </summary>
- private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
+ _guns.PlayImpactSound(args.Target, dmg, null, false);
+ if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
{
- args.Cancel("pacified-cannot-throw");
+ var direction = body.LinearVelocity.Normalized();
+ _sharedCameraRecoil.KickCamera(args.Target, direction);
}
}
}
--- /dev/null
+using Content.Server.Body.Components;
+using Content.Server.Body.Systems;
+using Content.Shared.EntityConditions;
+using Content.Shared.EntityConditions.Conditions.Body;
+
+namespace Content.Server.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this entity is both able to breathe and is currently breathing.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class IsBreathingEntityConditionSystem : EntityConditionSystem<RespiratorComponent, BreathingCondition>
+{
+ [Dependency] private readonly RespiratorSystem _respirator = default!;
+ protected override void Condition(Entity<RespiratorComponent> entity, ref EntityConditionEvent<BreathingCondition> args)
+ {
+ args.Result = _respirator.IsBreathing(entity.AsNullable());
+ }
+}
--- /dev/null
+using System.Linq;
+using Content.Server.Body.Components;
+using Content.Shared.EntityConditions;
+using Content.Shared.EntityConditions.Conditions.Body;
+
+namespace Content.Server.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this entity has any of the listed metabolizer types.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class MetabolizerTypeEntityConditionSystem : EntityConditionSystem<MetabolizerComponent, MetabolizerTypeCondition>
+{
+ protected override void Condition(Entity<MetabolizerComponent> entity, ref EntityConditionEvent<MetabolizerTypeCondition> args)
+ {
+ if (entity.Comp.MetabolizerTypes == null)
+ return;
+
+ args.Result = entity.Comp.MetabolizerTypes.Overlaps(args.Condition.Type);
+ }
+}
--- /dev/null
+using Content.Server.Atmos.EntitySystems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Atmos;
+
+namespace Content.Server.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// This effect adjusts a gas at the tile this entity is currently on.
+/// The amount changed is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class CreateGasEntityEffectSystem : EntityEffectSystem<TransformComponent, CreateGas>
+{
+ [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<CreateGas> args)
+ {
+ var tileMix = _atmosphere.GetContainingMixture(entity.AsNullable(), false, true);
+
+ tileMix?.AdjustMoles(args.Effect.Gas, args.Scale * args.Effect.Moles);
+ }
+}
--- /dev/null
+using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Atmos.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Atmos;
+
+namespace Content.Server.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// Adds a number of FireStacks modified by scale to this entity.
+/// The amount of FireStacks added is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class FlammableEntityEffectSystem : EntityEffectSystem<FlammableComponent, Flammable>
+{
+ [Dependency] private readonly FlammableSystem _flammable = default!;
+
+ protected override void Effect(Entity<FlammableComponent> entity, ref EntityEffectEvent<Flammable> args)
+ {
+ // The multiplier is determined by if the entity is already on fire, and if the multiplier for existing FireStacks has a value.
+ // If both of these are true, we use the MultiplierOnExisting value, otherwise we use the standard Multiplier.
+ var multiplier = entity.Comp.FireStacks == 0f || args.Effect.MultiplierOnExisting == null ? args.Effect.Multiplier : args.Effect.MultiplierOnExisting.Value;
+
+ _flammable.AdjustFireStacks(entity, args.Scale * multiplier, entity.Comp);
+ }
+}
--- /dev/null
+using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Atmos.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Atmos;
+
+namespace Content.Server.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// Sets this entity on fire.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class IngiteEntityEffectSystem : EntityEffectSystem<FlammableComponent, Ignite>
+{
+ [Dependency] private readonly FlammableSystem _flammable = default!;
+
+ protected override void Effect(Entity<FlammableComponent> entity, ref EntityEffectEvent<Ignite> args)
+ {
+ // TODO: Proper BodySystem Metabolism Effect relay...
+ // TODO: If this fucks over downstream shitmed, I give you full approval to use whatever shitcode method you need to fix it. Metabolism is awful.
+ _flammable.Ignite(entity, entity, flammable: entity.Comp);
+ }
+}
+
--- /dev/null
+using Content.Server.Body.Components;
+using Content.Server.Body.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Body;
+
+namespace Content.Server.EntityEffects.Effects.Body;
+
+/// <summary>
+/// This effect adjusts a respirator's saturation value.
+/// The saturation adjustment is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class OxygenateEntityEffectsSystem : EntityEffectSystem<RespiratorComponent, Oxygenate>
+{
+ [Dependency] private readonly RespiratorSystem _respirator = default!;
+ protected override void Effect(Entity<RespiratorComponent> entity, ref EntityEffectEvent<Oxygenate> args)
+ {
+ _respirator.UpdateSaturation(entity, args.Scale * args.Effect.Factor, entity.Comp);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustHealthEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustHealth>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustHealth> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.MutationLevel += args.Effect.Amount * entity.Comp.MutationMod;
+ _plantHolder.CheckHealth(entity, entity.Comp);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustMutationLevelEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustMutationLevel>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustMutationLevel> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.Health += args.Effect.Amount;
+ _plantHolder.CheckHealth(entity, entity.Comp);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustMutationModEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustMutationMod>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustMutationMod> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.MutationMod += args.Effect.Amount;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustNutritionEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustNutrition>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustNutrition> args)
+ {
+ _plantHolder.AdjustNutrient(entity, args.Effect.Amount, entity);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustPestsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustPests>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustPests> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.PestLevel += args.Effect.Amount;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustPotencyEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustPotency>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustPotency> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ _plantHolder.EnsureUniqueSeed(entity, entity.Comp);
+ entity.Comp.Seed.Potency = Math.Max(entity.Comp.Seed.Potency + args.Effect.Amount, 1);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustToxinsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustToxins>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustToxins> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.Toxins += args.Effect.Amount;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustWaterEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustWater>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustWater> args)
+ {
+ _plantHolder.AdjustWater(entity, args.Effect.Amount, entity.Comp);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustWeedsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAdjustWeeds>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAdjustWeeds> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ entity.Comp.WeedLevel += args.Effect.Amount;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAffectGrowthEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantAffectGrowth>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantAffectGrowth> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ _plantHolder.AffectGrowth(entity, (int)args.Effect.Amount, entity);
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// This system mutates an inputted stat for a PlantHolder, only works for floats, integers, and bools.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class PlantChangeStatEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantChangeStat>
+{
+ // TODO: This is awful. I do not have the strength to refactor this. I want it gone.
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantChangeStat> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ var effect = args.Effect;
+ var member = entity.Comp.Seed.GetType().GetField(args.Effect.TargetValue);
+
+ if (member == null)
+ {
+ Log.Error($"{ effect.GetType().Name } Error: Member { args.Effect.TargetValue} not found on { entity.Comp.Seed.GetType().Name }. Did you misspell it?");
+ return;
+ }
+
+ var currentValObj = member.GetValue(entity.Comp.Seed);
+ if (currentValObj == null)
+ return;
+
+ if (member.FieldType == typeof(float))
+ {
+ var floatVal = (float)currentValObj;
+ MutateFloat(ref floatVal, args.Effect.MinValue, args.Effect.MaxValue, args.Effect.Steps);
+ member.SetValue(entity.Comp.Seed, floatVal);
+ }
+ else if (member.FieldType == typeof(int))
+ {
+ var intVal = (int)currentValObj;
+ MutateInt(ref intVal, (int)args.Effect.MinValue, (int)args.Effect.MaxValue, args.Effect.Steps);
+ member.SetValue(entity.Comp.Seed, intVal);
+ }
+ else if (member.FieldType == typeof(bool))
+ {
+ var boolVal = (bool)currentValObj;
+ boolVal = !boolVal;
+ member.SetValue(entity.Comp.Seed, boolVal);
+ }
+ }
+
+ // Mutate reference 'val' between 'min' and 'max' by pretending the value
+ // is representable by a thermometer code with 'bits' number of bits and
+ // randomly flipping some of them.
+ private void MutateFloat(ref float val, float min, float max, int bits)
+ {
+ if (min == max)
+ {
+ val = min;
+ return;
+ }
+
+ // Starting number of bits that are high, between 0 and bits.
+ // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
+ int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
+ // val may be outside the range of min/max due to starting prototype values, so clamp.
+ valInt = Math.Clamp(valInt, 0, bits);
+
+ // Probability that the bit flip increases n.
+ // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it.
+ // In other words, it tends to go to the middle.
+ float probIncrease = 1 - (float)valInt / bits;
+ int valIntMutated;
+ if (_random.Prob(probIncrease))
+ {
+ valIntMutated = valInt + 1;
+ }
+ else
+ {
+ valIntMutated = valInt - 1;
+ }
+
+ // Set value based on mutated thermometer code.
+ float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max);
+ val = valMutated;
+ }
+
+ private void MutateInt(ref int val, int min, int max, int bits)
+ {
+ if (min == max)
+ {
+ val = min;
+ return;
+ }
+
+ // Starting number of bits that are high, between 0 and bits.
+ // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
+ int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
+ // val may be outside the range of min/max due to starting prototype values, so clamp.
+ valInt = Math.Clamp(valInt, 0, bits);
+
+ // Probability that the bit flip increases n.
+ // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it.
+ // In other words, it tends to go to the middle.
+ float probIncrease = 1 - (float)valInt / bits;
+ int valMutated;
+ if (_random.Prob(probIncrease))
+ {
+ valMutated = val + 1;
+ }
+ else
+ {
+ valMutated = val - 1;
+ }
+
+ valMutated = Math.Clamp(valMutated, min, max);
+ val = valMutated;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantCryoxadoneEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantCryoxadone>
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantCryoxadone> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ var deviation = 0;
+ var seed = entity.Comp.Seed;
+ if (seed == null)
+ return;
+ if (entity.Comp.Age > seed.Maturation)
+ deviation = (int) Math.Max(seed.Maturation - 1, entity.Comp.Age - _random.Next(7, 10));
+ else
+ deviation = (int) (seed.Maturation / seed.GrowthStages);
+ entity.Comp.Age -= deviation;
+ entity.Comp.LastProduce = entity.Comp.Age;
+ entity.Comp.SkipAging++;
+ entity.Comp.ForceUpdate = true;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Server.Popups;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+using Content.Shared.Popups;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantDestroySeedsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantDestroySeeds>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantDestroySeeds> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead || entity.Comp.Seed.Immutable)
+ return;
+
+ if (entity.Comp.Seed.Seedless)
+ return;
+
+ _plantHolder.EnsureUniqueSeed(entity, entity.Comp);
+ _popup.PopupEntity(
+ Loc.GetString("botany-plant-seedsdestroyed"),
+ entity,
+ PopupType.SmallCaution
+ );
+ entity.Comp.Seed.Seedless = true;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantDiethylamineEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantDiethylamine>
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantDiethylamine> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead || entity.Comp.Seed.Immutable)
+ return;
+
+ if (_random.Prob(0.1f))
+ {
+ _plantHolder.EnsureUniqueSeed(entity, entity);
+ entity.Comp.Seed!.Lifespan++;
+ }
+
+ if (_random.Prob(0.1f))
+ {
+ _plantHolder.EnsureUniqueSeed(entity, entity);
+ entity.Comp.Seed!.Endurance++;
+ }
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantPhalanximineEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantPhalanximine>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantPhalanximine> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead || entity.Comp.Seed.Immutable)
+ return;
+
+ entity.Comp.Seed.Viable = true;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Server.Popups;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantRestoreSeedsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantRestoreSeeds>
+{
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantRestoreSeeds> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead || entity.Comp.Seed.Immutable)
+ return;
+
+ if (!entity.Comp.Seed.Seedless)
+ return;
+
+ _plantHolder.EnsureUniqueSeed(entity, entity.Comp);
+ _popup.PopupEntity(Loc.GetString("botany-plant-seedsrestored"), entity);
+ entity.Comp.Seed.Seedless = false;
+ }
+}
--- /dev/null
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// This effect directly increases the potency of a PlantHolder's plant provided it exists and isn't dead.
+/// Potency directly correlates to the size of the plant's produce.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class RobustHarvestEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, RobustHarvest>
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<RobustHarvest> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Dead)
+ return;
+
+ if (entity.Comp.Seed.Potency < args.Effect.PotencyLimit)
+ {
+ _plantHolder.EnsureUniqueSeed(entity, entity.Comp);
+ entity.Comp.Seed.Potency = Math.Min(entity.Comp.Seed.Potency + args.Effect.PotencyIncrease, args.Effect.PotencyLimit);
+
+ if (entity.Comp.Seed.Potency > args.Effect.PotencySeedlessThreshold)
+ {
+ entity.Comp.Seed.Seedless = true;
+ }
+ }
+ else if (entity.Comp.Seed.Yield > 1 && _random.Prob(0.1f))
+ {
+ // Too much of a good thing reduces yield
+ _plantHolder.EnsureUniqueSeed(entity, entity.Comp);
+ entity.Comp.Seed.Yield--;
+ }
+ }
+}
--- /dev/null
+using Content.Server.Botany;
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany;
+
+public sealed partial class PlantMutateChemicalsEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantMutateChemicals>
+{
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantMutateChemicals> args)
+ {
+ if (entity.Comp.Seed == null)
+ return;
+
+ var chemicals = entity.Comp.Seed.Chemicals;
+ var randomChems = _proto.Index(args.Effect.RandomPickBotanyReagent).Fills;
+
+ // Add a random amount of a random chemical to this set of chemicals
+ var pick = _random.Pick(randomChems);
+ var chemicalId = _random.Pick(pick.Reagents);
+ var amount = _random.Next(1, (int)pick.Quantity);
+ var seedChemQuantity = new SeedChemQuantity();
+ if (chemicals.ContainsKey(chemicalId))
+ {
+ seedChemQuantity.Min = chemicals[chemicalId].Min;
+ seedChemQuantity.Max = chemicals[chemicalId].Max + amount;
+ }
+ else
+ {
+ seedChemQuantity.Min = 1;
+ seedChemQuantity.Max = 1 + amount;
+ seedChemQuantity.Inherent = false;
+ }
+ var potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max);
+ seedChemQuantity.PotencyDivisor = potencyDivisor;
+ chemicals[chemicalId] = seedChemQuantity;
+ }
+}
--- /dev/null
+using System.Linq;
+using Content.Server.Botany.Components;
+using Content.Shared.Atmos;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany;
+
+public sealed partial class PlantMutateExudeGasesEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantMutateExudeGases>
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantMutateExudeGases> args)
+ {
+ if (entity.Comp.Seed == null)
+ return;
+
+ var gasses = entity.Comp.Seed.ExudeGasses;
+
+ // Add a random amount of a random gas to this gas dictionary
+ float amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
+ var gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
+
+ if (!gasses.TryAdd(gas, amount))
+ {
+ gasses[gas] += amount;
+ }
+ }
+}
+
+public sealed partial class PlantMutateConsumeGasesEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantMutateConsumeGases>
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantMutateConsumeGases> args)
+ {
+ if (entity.Comp.Seed == null)
+ return;
+
+ var gasses = entity.Comp.Seed.ConsumeGasses;
+
+ // Add a random amount of a random gas to this gas dictionary
+ var amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
+ var gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
+
+ if (!gasses.TryAdd(gas, amount))
+ {
+ gasses[gas] += amount;
+ }
+ }
+}
+
--- /dev/null
+using Content.Server.Botany;
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany;
+
+namespace Content.Server.EntityEffects.Effects.Botany;
+
+public sealed partial class PlantMutateHarvestEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantMutateHarvest>
+{
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantMutateHarvest> args)
+ {
+ if (entity.Comp.Seed == null)
+ return;
+
+ switch (entity.Comp.Seed.HarvestRepeat)
+ {
+ case HarvestType.NoRepeat:
+ entity.Comp.Seed.HarvestRepeat = HarvestType.Repeat;
+ break;
+ case HarvestType.Repeat:
+ entity.Comp.Seed.HarvestRepeat = HarvestType.SelfHarvest;
+ break;
+ }
+ }
+}
--- /dev/null
+using Content.Server.Botany;
+using Content.Server.Botany.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Botany;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.EntityEffects.Effects.Botany;
+
+public sealed partial class PlantMutateSpeciesChangeEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantMutateSpeciesChange>
+{
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantMutateSpeciesChange> args)
+ {
+ if (entity.Comp.Seed == null || entity.Comp.Seed.MutationPrototypes.Count == 0)
+ return;
+
+ var targetProto = _random.Pick(entity.Comp.Seed.MutationPrototypes);
+ _proto.TryIndex(targetProto, out SeedPrototype? protoSeed);
+
+ if (protoSeed == null)
+ {
+ Log.Error($"Seed prototype could not be found: {targetProto}!");
+ return;
+ }
+
+ entity.Comp.Seed = entity.Comp.Seed.SpeciesChange(protoSeed);
+ }
+}
--- /dev/null
+using Content.Server.Chat.Systems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects;
+
+namespace Content.Server.EntityEffects.Effects;
+
+/// <summary>
+/// Makes this entity emote.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class EmoteEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Emote>
+{
+ [Dependency] private readonly ChatSystem _chat = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Emote> args)
+ {
+ if (args.Effect.ShowInChat)
+ _chat.TryEmoteWithChat(entity, args.Effect.EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: args.Effect.Force);
+ else
+ _chat.TryEmoteWithoutChat(entity, args.Effect.EmoteId);
+ }
+}
--- /dev/null
+using Content.Server.Ghost.Roles.Components;
+using Content.Server.Speech.Components;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects;
+using Content.Shared.Mind.Components;
+
+namespace Content.Server.EntityEffects.Effects;
+
+/// <summary>
+/// Makes this entity sentient. Allows ghost to take it over if it's not already occupied.
+/// Optionally also allows this entity to speak.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class MakeSentientEntityEffectSystem : EntityEffectSystem<MetaDataComponent, MakeSentient>
+{
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<MakeSentient> args)
+ {
+ // 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
+ if (args.Effect.AllowSpeech)
+ {
+ RemComp<ReplacementAccentComponent>(entity);
+ // TODO: Make MonkeyAccent a replacement accent and remove MonkeyAccent code-smell.
+ RemComp<MonkeyAccentComponent>(entity);
+ }
+
+ // Stops from adding a ghost role to things like people who already have a mind
+ if (TryComp<MindContainerComponent>(entity, out var mindContainer) && mindContainer.HasMind)
+ return;
+
+ // Don't add a ghost role to things that already have ghost roles
+ if (TryComp(entity, out GhostRoleComponent? ghostRole))
+ return;
+
+ ghostRole = AddComp<GhostRoleComponent>(entity);
+ EnsureComp<GhostTakeoverAvailableComponent>(entity);
+
+ ghostRole.RoleName = entity.Comp.EntityName;
+ ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
+ }
+}
--- /dev/null
+using Content.Server.Polymorph.Components;
+using Content.Server.Polymorph.Systems;
+using Content.Shared.EntityEffects;
+
+namespace Content.Server.EntityEffects.Effects;
+
+/// <summary>
+/// Polymorphs this entity into another entity.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class PolymorphEntityEffectSystem : EntityEffectSystem<PolymorphableComponent, Shared.EntityEffects.Effects.Polymorph>
+{
+ [Dependency] private readonly PolymorphSystem _polymorph = default!;
+
+ protected override void Effect(Entity<PolymorphableComponent> entity, ref EntityEffectEvent<Shared.EntityEffects.Effects.Polymorph> args)
+ {
+ _polymorph.PolymorphEntity(entity, args.Effect.Prototype);
+ }
+}
--- /dev/null
+using Content.Server.Fluids.EntitySystems;
+using Content.Server.Spreader;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Solution;
+using Content.Shared.Maps;
+using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Map;
+
+namespace Content.Server.EntityEffects.Effects.Solution;
+
+/// <summary>
+/// This effect creates smoke at this solution's position.
+/// The amount of smoke created is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class AreaReactionEntityEffectsSystem : EntityEffectSystem<SolutionComponent, AreaReactionEffect>
+{
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
+ [Dependency] private readonly SharedTransformSystem _xform = default!;
+ [Dependency] private readonly SmokeSystem _smoke = default!;
+ [Dependency] private readonly SpreaderSystem _spreader = default!;
+ [Dependency] private readonly TurfSystem _turf = default!;
+
+ // TODO: A sane way to make Smoke without a solution.
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<AreaReactionEffect> args)
+ {
+ var xform = Transform(entity);
+ var mapCoords = _xform.GetMapCoordinates(entity);
+ var spreadAmount = (int) Math.Max(0, Math.Ceiling(args.Scale / args.Effect.OverflowThreshold));
+ var effect = args.Effect;
+
+ if (!_mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
+ !_map.TryGetTileRef(gridUid, grid, xform.Coordinates, out var tileRef))
+ return;
+
+ if (_spreader.RequiresFloorToSpread(effect.PrototypeId.ToString()) && _turf.IsSpace(tileRef))
+ return;
+
+ var coords = _map.MapToGrid(gridUid, mapCoords);
+ var ent = Spawn(args.Effect.PrototypeId, coords.SnapToGrid());
+
+ _smoke.StartSmoke(ent, entity.Comp.Solution, args.Effect.Duration, spreadAmount);
+
+ _audio.PlayPvs(args.Effect.Sound, entity, AudioParams.Default.WithVariation(0.25f));
+ }
+}
--- /dev/null
+using Content.Server.Explosion.EntitySystems;
+using Content.Shared.EntityEffects;
+using Content.Shared.EntityEffects.Effects.Transform;
+
+namespace Content.Server.EntityEffects.Effects.Transform;
+
+/// <summary>
+/// Creates an explosion at this entity's position.
+/// Intensity is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ExplosionEntityEffectSystem : EntityEffectSystem<TransformComponent, ExplosionEffect>
+{
+ [Dependency] private readonly ExplosionSystem _explosion = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<ExplosionEffect> args)
+ {
+ var intensity = MathF.Min(args.Effect.IntensityPerUnit * args.Scale, args.Effect.MaxTotalIntensity);
+
+ _explosion.QueueExplosion(
+ entity,
+ args.Effect.ExplosionType,
+ intensity,
+ args.Effect.IntensitySlope,
+ args.Effect.MaxIntensity,
+ args.Effect.TileBreakScale);
+ }
+}
+++ /dev/null
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using Content.Server.Atmos.EntitySystems;
-using Content.Server.Body.Components;
-using Content.Server.Body.Systems;
-using Content.Server.Botany.Components;
-using Content.Server.Botany.Systems;
-using Content.Server.Botany;
-using Content.Server.Chat.Systems;
-using Content.Server.Emp;
-using Content.Server.Explosion.EntitySystems;
-using Content.Server.Fluids.EntitySystems;
-using Content.Server.Ghost.Roles.Components;
-using Content.Server.Polymorph.Components;
-using Content.Server.Polymorph.Systems;
-using Content.Server.Speech.Components;
-using Content.Server.Spreader;
-using Content.Server.Temperature.Components;
-using Content.Server.Temperature.Systems;
-using Content.Server.Zombies;
-using Content.Shared.Atmos;
-using Content.Shared.Atmos.Components;
-using Content.Shared.Body.Components;
-using Content.Shared.Coordinates.Helpers;
-using Content.Shared.EntityEffects.EffectConditions;
-using Content.Shared.EntityEffects.Effects.PlantMetabolism;
-using Content.Shared.EntityEffects.Effects;
-using Content.Shared.EntityEffects;
-using Content.Shared.Flash;
-using Content.Shared.Maps;
-using Content.Shared.Medical;
-using Content.Shared.Mind.Components;
-using Content.Shared.Popups;
-using Content.Shared.Random;
-using Content.Shared.Traits.Assorted;
-using Content.Shared.Zombies;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Map;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-using TemperatureCondition = Content.Shared.EntityEffects.EffectConditions.Temperature; // disambiguate the namespace
-using PolymorphEffect = Content.Shared.EntityEffects.Effects.Polymorph;
-
-namespace Content.Server.EntityEffects;
-
-public sealed class EntityEffectSystem : EntitySystem
-{
- private static readonly ProtoId<WeightedRandomFillSolutionPrototype> RandomPickBotanyReagent = "RandomPickBotanyReagent";
-
- [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
- [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
- [Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly EmpSystem _emp = default!;
- [Dependency] private readonly ExplosionSystem _explosion = default!;
- [Dependency] private readonly FlammableSystem _flammable = default!;
- [Dependency] private readonly SharedFlashSystem _flash = default!;
- [Dependency] private readonly IMapManager _mapManager = default!;
- [Dependency] private readonly IPrototypeManager _protoManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly SharedMapSystem _map = default!;
- [Dependency] private readonly MutationSystem _mutation = default!;
- [Dependency] private readonly NarcolepsySystem _narcolepsy = default!;
- [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
- [Dependency] private readonly PolymorphSystem _polymorph = default!;
- [Dependency] private readonly RespiratorSystem _respirator = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedPointLightSystem _pointLight = default!;
- [Dependency] private readonly SharedPopupSystem _popup = default!;
- [Dependency] private readonly SmokeSystem _smoke = default!;
- [Dependency] private readonly SpreaderSystem _spreader = default!;
- [Dependency] private readonly TemperatureSystem _temperature = default!;
- [Dependency] private readonly SharedTransformSystem _xform = default!;
- [Dependency] private readonly VomitSystem _vomit = default!;
- [Dependency] private readonly TurfSystem _turf = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<CheckEntityEffectConditionEvent<TemperatureCondition>>(OnCheckTemperature);
- SubscribeLocalEvent<CheckEntityEffectConditionEvent<Breathing>>(OnCheckBreathing);
- SubscribeLocalEvent<CheckEntityEffectConditionEvent<OrganType>>(OnCheckOrganType);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustHealth>>(OnExecutePlantAdjustHealth);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustMutationLevel>>(OnExecutePlantAdjustMutationLevel);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustMutationMod>>(OnExecutePlantAdjustMutationMod);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustNutrition>>(OnExecutePlantAdjustNutrition);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustPests>>(OnExecutePlantAdjustPests);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustPotency>>(OnExecutePlantAdjustPotency);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustToxins>>(OnExecutePlantAdjustToxins);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustWater>>(OnExecutePlantAdjustWater);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustWeeds>>(OnExecutePlantAdjustWeeds);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAffectGrowth>>(OnExecutePlantAffectGrowth);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantChangeStat>>(OnExecutePlantChangeStat);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantCryoxadone>>(OnExecutePlantCryoxadone);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantDestroySeeds>>(OnExecutePlantDestroySeeds);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantDiethylamine>>(OnExecutePlantDiethylamine);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantPhalanximine>>(OnExecutePlantPhalanximine);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantRestoreSeeds>>(OnExecutePlantRestoreSeeds);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<RobustHarvest>>(OnExecuteRobustHarvest);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<AdjustTemperature>>(OnExecuteAdjustTemperature);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<AreaReactionEffect>>(OnExecuteAreaReactionEffect);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<CauseZombieInfection>>(OnExecuteCauseZombieInfection);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ChemCleanBloodstream>>(OnExecuteChemCleanBloodstream);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ChemVomit>>(OnExecuteChemVomit);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<CreateEntityReactionEffect>>(OnExecuteCreateEntityReactionEffect);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<CreateGas>>(OnExecuteCreateGas);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<CureZombieInfection>>(OnExecuteCureZombieInfection);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<Emote>>(OnExecuteEmote);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<EmpReactionEffect>>(OnExecuteEmpReactionEffect);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ExplosionReactionEffect>>(OnExecuteExplosionReactionEffect);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<FlammableReaction>>(OnExecuteFlammableReaction);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<FlashReactionEffect>>(OnExecuteFlashReactionEffect);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<Ignite>>(OnExecuteIgnite);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<MakeSentient>>(OnExecuteMakeSentient);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyBleedAmount>>(OnExecuteModifyBleedAmount);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyBloodLevel>>(OnExecuteModifyBloodLevel);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyLungGas>>(OnExecuteModifyLungGas);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<Oxygenate>>(OnExecuteOxygenate);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateChemicals>>(OnExecutePlantMutateChemicals);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateConsumeGasses>>(OnExecutePlantMutateConsumeGasses);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateExudeGasses>>(OnExecutePlantMutateExudeGasses);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateHarvest>>(OnExecutePlantMutateHarvest);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantSpeciesChange>>(OnExecutePlantSpeciesChange);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<PolymorphEffect>>(OnExecutePolymorph);
- SubscribeLocalEvent<ExecuteEntityEffectEvent<ResetNarcolepsy>>(OnExecuteResetNarcolepsy);
- }
-
- private void OnCheckTemperature(ref CheckEntityEffectConditionEvent<TemperatureCondition> args)
- {
- args.Result = false;
- if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
- {
- if (temp.CurrentTemperature >= args.Condition.Min && temp.CurrentTemperature <= args.Condition.Max)
- args.Result = true;
- }
- }
-
- private void OnCheckBreathing(ref CheckEntityEffectConditionEvent<Breathing> args)
- {
- if (!TryComp(args.Args.TargetEntity, out RespiratorComponent? respiratorComp))
- {
- args.Result = !args.Condition.IsBreathing;
- return;
- }
-
- var breathingState = _respirator.IsBreathing((args.Args.TargetEntity, respiratorComp));
- args.Result = args.Condition.IsBreathing == breathingState;
- }
-
- private void OnCheckOrganType(ref CheckEntityEffectConditionEvent<OrganType> args)
- {
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.OrganEntity == null)
- {
- args.Result = false;
- return;
- }
-
- args.Result = OrganCondition(args.Condition, reagentArgs.OrganEntity.Value);
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- public bool OrganCondition(OrganType condition, Entity<MetabolizerComponent?> metabolizer)
- {
- metabolizer.Comp ??= EntityManager.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
- if (metabolizer.Comp != null
- && metabolizer.Comp.MetabolizerTypes != null
- && metabolizer.Comp.MetabolizerTypes.Contains(condition.Type))
- return condition.ShouldHave;
- return !condition.ShouldHave;
- }
-
- /// <summary>
- /// Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
- /// </summary>
- /// <param name="plantHolder">The entity holding the plant</param>
- /// <param name="plantHolderComponent">The plant holder component</param>
- /// <param name="entityManager">The entity manager</param>
- /// <param name="mustHaveAlivePlant">Whether to check if it has an alive plant or not</param>
- /// <returns></returns>
- private bool CanMetabolizePlant(EntityUid plantHolder, [NotNullWhen(true)] out PlantHolderComponent? plantHolderComponent,
- bool mustHaveAlivePlant = true, bool mustHaveMutableSeed = false)
- {
- plantHolderComponent = null;
-
- if (!TryComp(plantHolder, out plantHolderComponent))
- return false;
-
- if (mustHaveAlivePlant && (plantHolderComponent.Seed == null || plantHolderComponent.Dead))
- return false;
-
- if (mustHaveMutableSeed && (plantHolderComponent.Seed == null || plantHolderComponent.Seed.Immutable))
- return false;
-
- return true;
- }
-
- private void OnExecutePlantAdjustHealth(ref ExecuteEntityEffectEvent<PlantAdjustHealth> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.Health += args.Effect.Amount;
- _plantHolder.CheckHealth(args.Args.TargetEntity, plantHolderComp);
- }
-
- private void OnExecutePlantAdjustMutationLevel(ref ExecuteEntityEffectEvent<PlantAdjustMutationLevel> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.MutationLevel += args.Effect.Amount * plantHolderComp.MutationMod;
- }
-
- private void OnExecutePlantAdjustMutationMod(ref ExecuteEntityEffectEvent<PlantAdjustMutationMod> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.MutationMod += args.Effect.Amount;
- }
-
- private void OnExecutePlantAdjustNutrition(ref ExecuteEntityEffectEvent<PlantAdjustNutrition> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveAlivePlant: false))
- return;
-
- _plantHolder.AdjustNutrient(args.Args.TargetEntity, args.Effect.Amount, plantHolderComp);
- }
-
- private void OnExecutePlantAdjustPests(ref ExecuteEntityEffectEvent<PlantAdjustPests> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.PestLevel += args.Effect.Amount;
- }
-
- private void OnExecutePlantAdjustPotency(ref ExecuteEntityEffectEvent<PlantAdjustPotency> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- if (plantHolderComp.Seed == null)
- return;
-
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- plantHolderComp.Seed.Potency = Math.Max(plantHolderComp.Seed.Potency + args.Effect.Amount, 1);
- }
-
- private void OnExecutePlantAdjustToxins(ref ExecuteEntityEffectEvent<PlantAdjustToxins> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.Toxins += args.Effect.Amount;
- }
-
- private void OnExecutePlantAdjustWater(ref ExecuteEntityEffectEvent<PlantAdjustWater> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveAlivePlant: false))
- return;
-
- _plantHolder.AdjustWater(args.Args.TargetEntity, args.Effect.Amount, plantHolderComp);
- }
-
- private void OnExecutePlantAdjustWeeds(ref ExecuteEntityEffectEvent<PlantAdjustWeeds> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- plantHolderComp.WeedLevel += args.Effect.Amount;
- }
-
- private void OnExecutePlantAffectGrowth(ref ExecuteEntityEffectEvent<PlantAffectGrowth> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- _plantHolder.AffectGrowth(args.Args.TargetEntity, (int) args.Effect.Amount, plantHolderComp);
- }
-
- // Mutate reference 'val' between 'min' and 'max' by pretending the value
- // is representable by a thermometer code with 'bits' number of bits and
- // randomly flipping some of them.
- private void MutateFloat(ref float val, float min, float max, int bits)
- {
- if (min == max)
- {
- val = min;
- return;
- }
-
- // Starting number of bits that are high, between 0 and bits.
- // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
- int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
- // val may be outside the range of min/max due to starting prototype values, so clamp.
- valInt = Math.Clamp(valInt, 0, bits);
-
- // Probability that the bit flip increases n.
- // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it.
- // In other words, it tends to go to the middle.
- float probIncrease = 1 - (float)valInt / bits;
- int valIntMutated;
- if (_random.Prob(probIncrease))
- {
- valIntMutated = valInt + 1;
- }
- else
- {
- valIntMutated = valInt - 1;
- }
-
- // Set value based on mutated thermometer code.
- float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max);
- val = valMutated;
- }
-
- private void MutateInt(ref int val, int min, int max, int bits)
- {
- if (min == max)
- {
- val = min;
- return;
- }
-
- // Starting number of bits that are high, between 0 and bits.
- // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
- int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
- // val may be outside the range of min/max due to starting prototype values, so clamp.
- valInt = Math.Clamp(valInt, 0, bits);
-
- // Probability that the bit flip increases n.
- // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it.
- // In other words, it tends to go to the middle.
- float probIncrease = 1 - (float)valInt / bits;
- int valMutated;
- if (_random.Prob(probIncrease))
- {
- valMutated = val + 1;
- }
- else
- {
- valMutated = val - 1;
- }
-
- valMutated = Math.Clamp(valMutated, min, max);
- val = valMutated;
- }
-
- private void OnExecutePlantChangeStat(ref ExecuteEntityEffectEvent<PlantChangeStat> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- if (plantHolderComp.Seed == null)
- return;
-
- var member = plantHolderComp.Seed.GetType().GetField(args.Effect.TargetValue);
-
- if (member == null)
- {
- _mutation.Log.Error(args.Effect.GetType().Name + " Error: Member " + args.Effect.TargetValue + " not found on " + plantHolderComp.Seed.GetType().Name + ". Did you misspell it?");
- return;
- }
-
- var currentValObj = member.GetValue(plantHolderComp.Seed);
- if (currentValObj == null)
- return;
-
- if (member.FieldType == typeof(float))
- {
- var floatVal = (float)currentValObj;
- MutateFloat(ref floatVal, args.Effect.MinValue, args.Effect.MaxValue, args.Effect.Steps);
- member.SetValue(plantHolderComp.Seed, floatVal);
- }
- else if (member.FieldType == typeof(int))
- {
- var intVal = (int)currentValObj;
- MutateInt(ref intVal, (int)args.Effect.MinValue, (int)args.Effect.MaxValue, args.Effect.Steps);
- member.SetValue(plantHolderComp.Seed, intVal);
- }
- else if (member.FieldType == typeof(bool))
- {
- var boolVal = (bool)currentValObj;
- boolVal = !boolVal;
- member.SetValue(plantHolderComp.Seed, boolVal);
- }
- }
-
- private void OnExecutePlantCryoxadone(ref ExecuteEntityEffectEvent<PlantCryoxadone> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- var deviation = 0;
- var seed = plantHolderComp.Seed;
- if (seed == null)
- return;
- if (plantHolderComp.Age > seed.Maturation)
- deviation = (int) Math.Max(seed.Maturation - 1, plantHolderComp.Age - _random.Next(7, 10));
- else
- deviation = (int) (seed.Maturation / seed.GrowthStages);
- plantHolderComp.Age -= deviation;
- plantHolderComp.LastProduce = plantHolderComp.Age;
- plantHolderComp.SkipAging++;
- plantHolderComp.ForceUpdate = true;
- }
-
- private void OnExecutePlantDestroySeeds(ref ExecuteEntityEffectEvent<PlantDestroySeeds> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
- return;
-
- if (plantHolderComp.Seed!.Seedless == false)
- {
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- _popup.PopupEntity(
- Loc.GetString("botany-plant-seedsdestroyed"),
- args.Args.TargetEntity,
- PopupType.SmallCaution
- );
- plantHolderComp.Seed.Seedless = true;
- }
- }
-
- private void OnExecutePlantDiethylamine(ref ExecuteEntityEffectEvent<PlantDiethylamine> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
- return;
-
- if (_random.Prob(0.1f))
- {
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- plantHolderComp.Seed!.Lifespan++;
- }
-
- if (_random.Prob(0.1f))
- {
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- plantHolderComp.Seed!.Endurance++;
- }
- }
-
- private void OnExecutePlantPhalanximine(ref ExecuteEntityEffectEvent<PlantPhalanximine> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
- return;
-
- plantHolderComp.Seed!.Viable = true;
- }
-
- private void OnExecutePlantRestoreSeeds(ref ExecuteEntityEffectEvent<PlantRestoreSeeds> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
- return;
-
- if (plantHolderComp.Seed!.Seedless)
- {
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- _popup.PopupEntity(Loc.GetString("botany-plant-seedsrestored"), args.Args.TargetEntity);
- plantHolderComp.Seed.Seedless = false;
- }
- }
-
- private void OnExecuteRobustHarvest(ref ExecuteEntityEffectEvent<RobustHarvest> args)
- {
- if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
- return;
-
- if (plantHolderComp.Seed == null)
- return;
-
- if (plantHolderComp.Seed.Potency < args.Effect.PotencyLimit)
- {
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- plantHolderComp.Seed.Potency = Math.Min(plantHolderComp.Seed.Potency + args.Effect.PotencyIncrease, args.Effect.PotencyLimit);
-
- if (plantHolderComp.Seed.Potency > args.Effect.PotencySeedlessThreshold)
- {
- plantHolderComp.Seed.Seedless = true;
- }
- }
- else if (plantHolderComp.Seed.Yield > 1 && _random.Prob(0.1f))
- {
- // Too much of a good thing reduces yield
- _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
- plantHolderComp.Seed.Yield--;
- }
- }
-
- private void OnExecuteAdjustTemperature(ref ExecuteEntityEffectEvent<AdjustTemperature> args)
- {
- if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
- {
- var amount = args.Effect.Amount;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- amount *= reagentArgs.Scale.Float();
- }
-
- _temperature.ChangeHeat(args.Args.TargetEntity, amount, true, temp);
- }
- }
-
- private void OnExecuteAreaReactionEffect(ref ExecuteEntityEffectEvent<AreaReactionEffect> args)
- {
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.Source == null)
- return;
-
- var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / args.Effect.OverflowThreshold).Float()));
- var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
- var transform = Comp<TransformComponent>(reagentArgs.TargetEntity);
- var mapCoords = _xform.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
-
- if (!_mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
- !_map.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef))
- {
- return;
- }
-
- if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && _turf.IsSpace(tileRef))
- return;
-
- var coords = _map.MapToGrid(gridUid, mapCoords);
- var ent = Spawn(args.Effect.PrototypeId, coords.SnapToGrid());
-
- _smoke.StartSmoke(ent, splitSolution, args.Effect.Duration, spreadAmount);
-
- _audio.PlayPvs(args.Effect.Sound, reagentArgs.TargetEntity, AudioParams.Default.WithVariation(0.25f));
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- private void OnExecuteCauseZombieInfection(ref ExecuteEntityEffectEvent<CauseZombieInfection> args)
- {
- EnsureComp<ZombifyOnDeathComponent>(args.Args.TargetEntity);
- EnsureComp<PendingZombieComponent>(args.Args.TargetEntity);
- }
-
- private void OnExecuteChemCleanBloodstream(ref ExecuteEntityEffectEvent<ChemCleanBloodstream> args)
- {
- var cleanseRate = args.Effect.CleanseRate;
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.Source == null || reagentArgs.Reagent == null)
- return;
-
- cleanseRate *= reagentArgs.Scale.Float();
- _bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent, cleanseRate);
- }
- else
- {
- _bloodstream.FlushChemicals(args.Args.TargetEntity, null, cleanseRate);
- }
- }
-
- private void OnExecuteChemVomit(ref ExecuteEntityEffectEvent<ChemVomit> args)
- {
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- if (reagentArgs.Scale != 1f)
- return;
-
- _vomit.Vomit(args.Args.TargetEntity, args.Effect.ThirstAmount, args.Effect.HungerAmount);
- }
-
- private void OnExecuteCreateEntityReactionEffect(ref ExecuteEntityEffectEvent<CreateEntityReactionEffect> args)
- {
- var transform = Comp<TransformComponent>(args.Args.TargetEntity);
- var quantity = (int)args.Effect.Number;
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- quantity *= reagentArgs.Quantity.Int();
-
- for (var i = 0; i < quantity; i++)
- {
- var uid = Spawn(args.Effect.Entity, _xform.GetMapCoordinates(args.Args.TargetEntity, xform: transform));
- _xform.AttachToGridOrMap(uid);
-
- // TODO figure out how to properly spawn inside of containers
- // e.g. cheese:
- // if the user is holding a bowl milk & enzyme, should drop to floor, not attached to the user.
- // if reaction happens in a backpack, should insert cheese into backpack.
- // --> if it doesn't fit, iterate through parent storage until it attaches to the grid (again, DON'T attach to players).
- // if the reaction happens INSIDE a stomach? the bloodstream? I have no idea how to handle that.
- // presumably having cheese materialize inside of your blood would have "disadvantages".
- }
- }
-
- private void OnExecuteCreateGas(ref ExecuteEntityEffectEvent<CreateGas> args)
- {
- var tileMix = _atmosphere.GetContainingMixture(args.Args.TargetEntity, false, true);
-
- if (tileMix != null)
- {
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- tileMix.AdjustMoles(args.Effect.Gas, reagentArgs.Quantity.Float() * args.Effect.Multiplier);
- }
- else
- {
- tileMix.AdjustMoles(args.Effect.Gas, args.Effect.Multiplier);
- }
- }
- }
-
- private void OnExecuteCureZombieInfection(ref ExecuteEntityEffectEvent<CureZombieInfection> args)
- {
- if (HasComp<IncurableZombieComponent>(args.Args.TargetEntity))
- return;
-
- RemComp<ZombifyOnDeathComponent>(args.Args.TargetEntity);
- RemComp<PendingZombieComponent>(args.Args.TargetEntity);
-
- if (args.Effect.Innoculate)
- {
- EnsureComp<ZombieImmuneComponent>(args.Args.TargetEntity);
- }
- }
-
- private void OnExecuteEmote(ref ExecuteEntityEffectEvent<Emote> args)
- {
- if (args.Effect.EmoteId == null)
- return;
-
- if (args.Effect.ShowInChat)
- _chat.TryEmoteWithChat(args.Args.TargetEntity, args.Effect.EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: args.Effect.Force);
- else
- _chat.TryEmoteWithoutChat(args.Args.TargetEntity, args.Effect.EmoteId);
- }
-
- private void OnExecuteEmpReactionEffect(ref ExecuteEntityEffectEvent<EmpReactionEffect> args)
- {
- var transform = Comp<TransformComponent>(args.Args.TargetEntity);
-
- var range = args.Effect.EmpRangePerUnit;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- range = MathF.Min((float) (reagentArgs.Quantity * args.Effect.EmpRangePerUnit), args.Effect.EmpMaxRange);
- }
-
- _emp.EmpPulse(_xform.GetMapCoordinates(args.Args.TargetEntity, xform: transform),
- range,
- args.Effect.EnergyConsumption,
- args.Effect.DisableDuration);
- }
-
- private void OnExecuteExplosionReactionEffect(ref ExecuteEntityEffectEvent<ExplosionReactionEffect> args)
- {
- var intensity = args.Effect.IntensityPerUnit;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- intensity = MathF.Min((float) reagentArgs.Quantity * args.Effect.IntensityPerUnit, args.Effect.MaxTotalIntensity);
- }
-
- _explosion.QueueExplosion(
- args.Args.TargetEntity,
- args.Effect.ExplosionType,
- intensity,
- args.Effect.IntensitySlope,
- args.Effect.MaxIntensity,
- args.Effect.TileBreakScale);
- }
-
- private void OnExecuteFlammableReaction(ref ExecuteEntityEffectEvent<FlammableReaction> args)
- {
- if (!TryComp(args.Args.TargetEntity, out FlammableComponent? flammable))
- return;
-
- // Sets the multiplier for FireStacks to MultiplierOnExisting is 0 or greater and target already has FireStacks
- var multiplier = flammable.FireStacks != 0f && args.Effect.MultiplierOnExisting >= 0 ? args.Effect.MultiplierOnExisting : args.Effect.Multiplier;
- var quantity = 1f;
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- quantity = reagentArgs.Quantity.Float();
- _flammable.AdjustFireStacks(args.Args.TargetEntity, quantity * multiplier, flammable);
- if (reagentArgs.Reagent != null)
- reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
- }
- else
- {
- _flammable.AdjustFireStacks(args.Args.TargetEntity, multiplier, flammable);
- }
- }
-
- private void OnExecuteFlashReactionEffect(ref ExecuteEntityEffectEvent<FlashReactionEffect> args)
- {
- var transform = Comp<TransformComponent>(args.Args.TargetEntity);
-
- var range = 1f;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- range = MathF.Min((float)(reagentArgs.Quantity * args.Effect.RangePerUnit), args.Effect.MaxRange);
-
- _flash.FlashArea(
- args.Args.TargetEntity,
- null,
- range,
- args.Effect.Duration,
- slowTo: args.Effect.SlowTo,
- sound: args.Effect.Sound);
-
- if (args.Effect.FlashEffectPrototype == null)
- return;
-
- var uid = EntityManager.SpawnEntity(args.Effect.FlashEffectPrototype, _xform.GetMapCoordinates(transform));
- _xform.AttachToGridOrMap(uid);
-
- if (!TryComp<PointLightComponent>(uid, out var pointLightComp))
- return;
-
- _pointLight.SetRadius(uid, MathF.Max(1.1f, range), pointLightComp);
- }
-
- private void OnExecuteIgnite(ref ExecuteEntityEffectEvent<Ignite> args)
- {
- if (!TryComp(args.Args.TargetEntity, out FlammableComponent? flammable))
- return;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- _flammable.Ignite(reagentArgs.TargetEntity, reagentArgs.OrganEntity ?? reagentArgs.TargetEntity, flammable: flammable);
- }
- else
- {
- _flammable.Ignite(args.Args.TargetEntity, args.Args.TargetEntity, flammable: flammable);
- }
- }
-
- private void OnExecuteMakeSentient(ref ExecuteEntityEffectEvent<MakeSentient> args)
- {
- var uid = args.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
- RemComp<ReplacementAccentComponent>(uid);
- RemComp<MonkeyAccentComponent>(uid);
-
- // Stops from adding a ghost role to things like people who already have a mind
- if (TryComp<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
- {
- return;
- }
-
- // Don't add a ghost role to things that already have ghost roles
- if (TryComp(uid, out GhostRoleComponent? ghostRole))
- {
- return;
- }
-
- ghostRole = AddComp<GhostRoleComponent>(uid);
- EnsureComp<GhostTakeoverAvailableComponent>(uid);
-
- var entityData = Comp<MetaDataComponent>(uid);
- ghostRole.RoleName = entityData.EntityName;
- ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
- }
-
- private void OnExecuteModifyBleedAmount(ref ExecuteEntityEffectEvent<ModifyBleedAmount> args)
- {
- if (TryComp<BloodstreamComponent>(args.Args.TargetEntity, out var blood))
- {
- var amt = args.Effect.Amount;
- if (args.Args is EntityEffectReagentArgs reagentArgs) {
- if (args.Effect.Scaled)
- amt *= reagentArgs.Quantity.Float();
- amt *= reagentArgs.Scale.Float();
- }
-
- _bloodstream.TryModifyBleedAmount((args.Args.TargetEntity, blood), amt);
- }
- }
-
- private void OnExecuteModifyBloodLevel(ref ExecuteEntityEffectEvent<ModifyBloodLevel> args)
- {
- if (TryComp<BloodstreamComponent>(args.Args.TargetEntity, out var blood))
- {
- var amt = args.Effect.Amount;
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- if (args.Effect.Scaled)
- amt *= reagentArgs.Quantity;
- amt *= reagentArgs.Scale;
- }
-
- _bloodstream.TryModifyBloodLevel((args.Args.TargetEntity, blood), amt);
- }
- }
-
- private void OnExecuteModifyLungGas(ref ExecuteEntityEffectEvent<ModifyLungGas> args)
- {
- LungComponent? lung;
- float amount = 1f;
-
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- if (!TryComp<LungComponent>(reagentArgs.OrganEntity, out var organLung))
- return;
- lung = organLung;
- amount = reagentArgs.Quantity.Float();
- }
- else
- {
- if (!TryComp<LungComponent>(args.Args.TargetEntity, out var organLung)) //Likely needs to be modified to ensure it works correctly
- return;
- lung = organLung;
- }
-
- if (lung != null)
- {
- foreach (var (gas, ratio) in args.Effect.Ratios)
- {
- var quantity = ratio * amount / Atmospherics.BreathMolesToReagentMultiplier;
- if (quantity < 0)
- quantity = Math.Max(quantity, -lung.Air[(int) gas]);
- lung.Air.AdjustMoles(gas, quantity);
- }
- }
- }
-
- private void OnExecuteOxygenate(ref ExecuteEntityEffectEvent<Oxygenate> args)
- {
- var multiplier = 1f;
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- {
- multiplier = reagentArgs.Quantity.Float();
- }
-
- if (TryComp<RespiratorComponent>(args.Args.TargetEntity, out var resp))
- {
- _respirator.UpdateSaturation(args.Args.TargetEntity, multiplier * args.Effect.Factor, resp);
- }
- }
-
- private void OnExecutePlantMutateChemicals(ref ExecuteEntityEffectEvent<PlantMutateChemicals> args)
- {
- var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
-
- if (plantholder.Seed == null)
- return;
-
- var chemicals = plantholder.Seed.Chemicals;
- var randomChems = _protoManager.Index(RandomPickBotanyReagent).Fills;
-
- // Add a random amount of a random chemical to this set of chemicals
- if (randomChems != null)
- {
- var pick = _random.Pick<RandomFillSolution>(randomChems);
- var chemicalId = _random.Pick(pick.Reagents);
- var amount = _random.Next(1, (int)pick.Quantity);
- var seedChemQuantity = new SeedChemQuantity();
- if (chemicals.ContainsKey(chemicalId))
- {
- seedChemQuantity.Min = chemicals[chemicalId].Min;
- seedChemQuantity.Max = chemicals[chemicalId].Max + amount;
- }
- else
- {
- seedChemQuantity.Min = 1;
- seedChemQuantity.Max = 1 + amount;
- seedChemQuantity.Inherent = false;
- }
- var potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max);
- seedChemQuantity.PotencyDivisor = potencyDivisor;
- chemicals[chemicalId] = seedChemQuantity;
- }
- }
-
- private void OnExecutePlantMutateConsumeGasses(ref ExecuteEntityEffectEvent<PlantMutateConsumeGasses> args)
- {
- var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
-
- if (plantholder.Seed == null)
- return;
-
- var gasses = plantholder.Seed.ConsumeGasses;
-
- // Add a random amount of a random gas to this gas dictionary
- float amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
- Gas gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
- if (gasses.ContainsKey(gas))
- {
- gasses[gas] += amount;
- }
- else
- {
- gasses.Add(gas, amount);
- }
- }
-
- private void OnExecutePlantMutateExudeGasses(ref ExecuteEntityEffectEvent<PlantMutateExudeGasses> args)
- {
- var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
-
- if (plantholder.Seed == null)
- return;
-
- var gasses = plantholder.Seed.ExudeGasses;
-
- // Add a random amount of a random gas to this gas dictionary
- float amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
- Gas gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
- if (gasses.ContainsKey(gas))
- {
- gasses[gas] += amount;
- }
- else
- {
- gasses.Add(gas, amount);
- }
- }
-
- private void OnExecutePlantMutateHarvest(ref ExecuteEntityEffectEvent<PlantMutateHarvest> args)
- {
- var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
-
- if (plantholder.Seed == null)
- return;
-
- if (plantholder.Seed.HarvestRepeat == HarvestType.NoRepeat)
- plantholder.Seed.HarvestRepeat = HarvestType.Repeat;
- else if (plantholder.Seed.HarvestRepeat == HarvestType.Repeat)
- plantholder.Seed.HarvestRepeat = HarvestType.SelfHarvest;
- }
-
- private void OnExecutePlantSpeciesChange(ref ExecuteEntityEffectEvent<PlantSpeciesChange> args)
- {
- var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
- if (plantholder.Seed == null)
- return;
-
- if (plantholder.Seed.MutationPrototypes.Count == 0)
- return;
-
- var targetProto = _random.Pick(plantholder.Seed.MutationPrototypes);
- if (!_protoManager.TryIndex(targetProto, out SeedPrototype? protoSeed))
- {
- Log.Error($"Seed prototype could not be found: {targetProto}!");
- return;
- }
-
- plantholder.Seed = plantholder.Seed.SpeciesChange(protoSeed);
- }
-
- private void OnExecutePolymorph(ref ExecuteEntityEffectEvent<PolymorphEffect> args)
- {
- // Make it into a prototype
- EnsureComp<PolymorphableComponent>(args.Args.TargetEntity);
- _polymorph.PolymorphEntity(args.Args.TargetEntity, args.Effect.PolymorphPrototype);
- }
-
- private void OnExecuteResetNarcolepsy(ref ExecuteEntityEffectEvent<ResetNarcolepsy> args)
- {
- if (args.Args is EntityEffectReagentArgs reagentArgs)
- if (reagentArgs.Scale != 1f)
- return;
-
- _narcolepsy.AdjustNarcolepsyTimer(args.Args.TargetEntity, args.Effect.TimerReset);
- }
-}
using Robust.Shared.Random;
using Robust.Shared.Timing;
using System.Linq;
-
+using Content.Shared.EntityEffects.Effects.Solution;
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
namespace Content.Server.Fluids.EntitySystems;
{
if (reagentQuantity.Quantity == FixedPoint2.Zero)
continue;
- var reagentProto = _prototype.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
- _reactive.ReactionEntity(entity, ReactionMethod.Touch, reagentProto, reagentQuantity, transferSolution);
+ _reactive.ReactionEntity(entity, ReactionMethod.Touch, reagentQuantity);
if (!blockIngestion)
- _reactive.ReactionEntity(entity, ReactionMethod.Ingestion, reagentProto, reagentQuantity, transferSolution);
+ _reactive.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity);
}
if (blockIngestion)
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
+using Content.Shared.EntityConditions;
using Content.Shared.EntityEffects;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
Converters =
{
new UniversalJsonConverter<EntityEffect>(),
- new UniversalJsonConverter<EntityEffectCondition>(),
+ new UniversalJsonConverter<EntityCondition>(),
new UniversalJsonConverter<ReagentEffectsEntry>(),
new UniversalJsonConverter<DamageSpecifier>(),
new FixedPointJsonConverter()
proto.Products
.Select(x => KeyValuePair.Create(x.Key, x.Value.Float()))
.ToDictionary(x => x.Key, x => x.Value);
- Effects = proto.Effects;
+ Effects = proto.Effects.ToList();
}
}
if (!this.IsPowered(entity, EntityManager))
return;
+ if (HasComp<StationAiCoreComponent>(entity))
+ return;
+
if (!TryComp<TelephoneComponent>(entity, out var entityTelephone) ||
_telephoneSystem.IsTelephoneEngaged((entity, entityTelephone)))
return;
using Content.Server.Construction.Components;
using Content.Shared.Chat;
using Content.Shared.Damage;
+using Content.Shared.Temperature.Components;
using Robust.Shared.Utility;
namespace Content.Server.Kitchen.EntitySystems
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
-using Content.Server.Temperature.Components;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.MedicalScanner;
+using Content.Shared.Temperature.Components;
using Content.Shared.UserInterface;
using Robust.Shared.Containers;
using Content.Server.Medical.Components;
using Content.Server.PowerCell;
-using Content.Server.Temperature.Components;
using Content.Shared.Body.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.MedicalScanner;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
+using Content.Shared.Temperature.Components;
using Content.Shared.Traits.Assorted;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
--- /dev/null
+using Content.Shared.Emag.Systems;
+
+namespace Content.Server.NPC.HTN.Preconditions;
+
+/// <summary>
+/// A precondition which is met if the NPC is emagged with <see cref="EmagType"/>, as computed by
+/// <see cref="EmagSystem.CheckFlag"/>. This is useful for changing NPC behavior in the case that the NPC is emagged,
+/// eg. like a helper NPC bot turning evil.
+/// </summary>
+public sealed partial class IsEmaggedPrecondition : HTNPrecondition
+{
+ private EmagSystem _emag;
+
+ /// <summary>
+ /// The type of emagging to check for.
+ /// </summary>
+ [DataField]
+ public EmagType EmagType = EmagType.Interaction;
+
+ public override void Initialize(IEntitySystemManager sysManager)
+ {
+ base.Initialize(sysManager);
+ _emag = sysManager.GetEntitySystem<EmagSystem>();
+ }
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+ return _emag.CheckFlag(owner, EmagType);
+ }
+}
--- /dev/null
+using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Interactions;
+using Content.Shared.CombatMode;
+using Content.Shared.Weapons.Melee;
+
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee;
+
+/// <summary>
+/// Something between <see cref="MeleeOperator"/> and <see cref="InteractWithOperator"/>, this operator causes the NPC
+/// to attempt a SINGLE <see cref="SharedMeleeWeaponSystem.AttemptLightAttack">melee attack</see> on the specified
+/// <see cref="TargetKey">target</see>.
+/// </summary>
+public sealed partial class MeleeAttackOperator : HTNOperator
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+ private SharedMeleeWeaponSystem _melee;
+
+ /// <summary>
+ /// Key that contains the target entity.
+ /// </summary>
+ [DataField(required: true)]
+ public string TargetKey = default!;
+
+ public override void Initialize(IEntitySystemManager sysManager)
+ {
+ base.Initialize(sysManager);
+ _melee = sysManager.GetEntitySystem<SharedMeleeWeaponSystem>();
+ }
+
+ public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
+ {
+ base.TaskShutdown(blackboard, status);
+
+ ExitCombatMode(blackboard);
+ }
+
+ public override void PlanShutdown(NPCBlackboard blackboard)
+ {
+ base.PlanShutdown(blackboard);
+
+ ExitCombatMode(blackboard);
+ }
+
+ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+ {
+ var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+
+ if (!_entManager.TryGetComponent<CombatModeComponent>(owner, out var combatMode) ||
+ !_melee.TryGetWeapon(owner, out var weaponUid, out var weapon))
+ {
+ return HTNOperatorStatus.Failed;
+ }
+
+ _entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, true, combatMode);
+
+
+ if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager) ||
+ !_melee.AttemptLightAttack(owner, weaponUid, weapon, target))
+ {
+ return HTNOperatorStatus.Continuing;
+ }
+
+ return HTNOperatorStatus.Finished;
+ }
+
+ private void ExitCombatMode(NPCBlackboard blackboard)
+ {
+ var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
+ _entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false);
+ }
+}
using Content.Server.Chat.Systems;
+using Content.Shared.Dataset;
+using Content.Shared.Random.Helpers;
+using JetBrains.Annotations;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using static Content.Server.NPC.HTN.PrimitiveTasks.Operators.SpeakOperator.SpeakOperatorSpeech;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
public sealed partial class SpeakOperator : HTNOperator
{
private ChatSystem _chat = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
[DataField(required: true)]
- public string Speech = string.Empty;
+ public SpeakOperatorSpeech Speech;
/// <summary>
/// Whether to hide message from chat window and logs.
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
-
_chat = sysManager.GetEntitySystem<ChatSystem>();
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
+ LocId speechLocId;
+ switch (Speech)
+ {
+ case LocalizedSetSpeakOperatorSpeech localizedDataSet:
+ if (!_proto.TryIndex(localizedDataSet.LineSet, out var speechSet))
+ return HTNOperatorStatus.Failed;
+ speechLocId = _random.Pick(speechSet);
+ break;
+ case SingleSpeakOperatorSpeech single:
+ speechLocId = single.Line;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(Speech));
+ }
+
var speaker = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
- _chat.TrySendInGameICMessage(speaker, Loc.GetString(Speech), InGameICChatType.Speak, hideChat: Hidden, hideLog: Hidden);
+ _chat.TrySendInGameICMessage(
+ speaker,
+ Loc.GetString(speechLocId),
+ InGameICChatType.Speak,
+ hideChat: Hidden,
+ hideLog: Hidden
+ );
return base.Update(blackboard, frameTime);
}
+
+ [ImplicitDataDefinitionForInheritors, MeansImplicitUse]
+ public abstract partial class SpeakOperatorSpeech
+ {
+ public sealed partial class SingleSpeakOperatorSpeech : SpeakOperatorSpeech
+ {
+ [DataField(required: true)]
+ public string Line;
+ }
+
+ public sealed partial class LocalizedSetSpeakOperatorSpeech : SpeakOperatorSpeech
+ {
+ [DataField(required: true)]
+ public ProtoId<LocalizedDatasetPrototype> LineSet;
+ }
+ }
}
--- /dev/null
+namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
+
+/// <summary>
+/// Raises an <see cref="HTNRaisedEvent"/> on the <see cref="NPCBlackboard.Owner">owner</see>. The event will contain
+/// the specified <see cref="Args"/>, and if not null, the value of <see cref="TargetKey"/>.
+/// </summary>
+public sealed partial class RaiseEventForOwnerOperator : HTNOperator
+{
+ [Dependency] private readonly IEntityManager _entMan = default!;
+
+ /// <summary>
+ /// The conceptual "target" of this event. Note that this is NOT the entity for which the event is raised. If null,
+ /// <see cref="HTNRaisedEvent.Target"/> will be null.
+ /// </summary>
+ [DataField]
+ public string? TargetKey;
+
+ /// <summary>
+ /// The data contained in the raised event. Since <see cref="HTNRaisedEvent"/> is itself pretty meaningless, this is
+ /// included to give some context of what the event is actually supposed to mean.
+ /// </summary>
+ [DataField(required: true)]
+ public EntityEventArgs Args;
+
+ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
+ {
+ _entMan.EventBus.RaiseLocalEvent(
+ blackboard.GetValue<EntityUid>(NPCBlackboard.Owner),
+ new HTNRaisedEvent(
+ blackboard.GetValue<EntityUid>(NPCBlackboard.Owner),
+ TargetKey is { } targetKey ? blackboard.GetValue<EntityUid>(targetKey) : null,
+ Args
+ )
+ );
+
+ return HTNOperatorStatus.Finished;
+ }
+}
+
+public sealed partial class HTNRaisedEvent(EntityUid owner, EntityUid? target, EntityEventArgs args) : EntityEventArgs
+{
+ // Owner and target are both included here in case we want to add a "RaiseEventForTargetOperator" in the future
+ // while reusing this event.
+ public EntityUid Owner = owner;
+ public EntityUid? Target = target;
+ public EntityEventArgs Args = args;
+}
/// </summary>
[DataField("components", required: true)]
public ComponentRegistry Components = new();
+
+ /// <summary>
+ /// If true, this filter retains entities with ALL of the specified components. If false, this filter removes
+ /// entities with ANY of the specified components.
+ /// </summary>
+ [DataField]
+ public bool RetainWithComp = true;
}
using Content.Server.NPC.Queries.Curves;
using Content.Server.NPC.Queries.Queries;
using Content.Server.Nutrition.Components;
-using Content.Server.Temperature.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Robust.Shared.Utility;
using Content.Shared.Atmos.Components;
using System.Linq;
+using Content.Shared.Temperature.Components;
namespace Content.Server.NPC.Systems;
{
foreach (var comp in compFilter.Components)
{
- if (HasComp(ent, comp.Value.Component.GetType()))
- continue;
-
- _entityList.Add(ent);
- break;
+ var hasComp = HasComp(ent, comp.Value.Component.GetType());
+ if (!compFilter.RetainWithComp == hasComp)
+ {
+ _entityList.Add(ent);
+ break;
+ }
}
}
using Content.Server.Ninja.Systems;
using Content.Server.Objectives.Systems;
+using Content.Shared.Whitelist;
namespace Content.Server.Objectives.Components;
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public EntityUid? Target;
+
+ /// <summary>
+ /// Tags that should be used to exclude Warp Points
+ /// from the list of valid bombing targets
+ /// </summary>
+ [DataField]
+ public EntityWhitelist? Blacklist;
}
using Content.Server.Objectives.Components;
using Content.Shared.Objectives.Components;
-using Content.Shared.Ninja.Components;
using Content.Shared.Roles;
using Content.Shared.Roles.Components;
using Content.Shared.Warps;
+using Content.Shared.Whitelist;
using Robust.Shared.Random;
namespace Content.Server.Objectives.Systems;
/// </summary>
public sealed class NinjaConditionsSystem : EntitySystem
{
+ [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly NumberObjectiveSystem _number = default!;
[Dependency] private readonly IRobustRandom _random = default!;
// choose spider charge detonation point
var warps = new List<EntityUid>();
- var query = EntityQueryEnumerator<BombingTargetComponent, WarpPointComponent>();
- while (query.MoveNext(out var warpUid, out _, out var warp))
+ var allEnts = EntityQueryEnumerator<WarpPointComponent>();
+ var bombingBlacklist = comp.Blacklist;
+
+ while (allEnts.MoveNext(out var warpUid, out var warp))
{
- if (warp.Location != null)
+ if (_whitelist.IsBlacklistFail(bombingBlacklist, warpUid)
+ && !string.IsNullOrWhiteSpace(warp.Location))
{
warps.Add(warpUid);
}
using Content.Server.Ghost.Roles.Components;
using Content.Server.Instruments;
using Content.Server.Kitchen.Components;
-using Content.Server.Store.Systems;
using Content.Shared.Interaction.Events;
using Content.Shared.Mind.Components;
using Content.Shared.PAI;
using Content.Shared.Popups;
-using Content.Shared.Store;
-using Content.Shared.Store.Components;
using Content.Shared.Instruments;
using Robust.Shared.Random;
-using Robust.Shared.Prototypes;
using System.Text;
namespace Content.Server.PAI;
-public sealed class PAISystem : SharedPAISystem
+public sealed class PAISystem : EntitySystem
{
[Dependency] private readonly InstrumentSystem _instrumentSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
- [Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly ToggleableGhostRoleSystem _toggleableGhostRole = default!;
/// <summary>
SubscribeLocalEvent<PAIComponent, MindAddedMessage>(OnMindAdded);
SubscribeLocalEvent<PAIComponent, MindRemovedMessage>(OnMindRemoved);
SubscribeLocalEvent<PAIComponent, BeingMicrowavedEvent>(OnMicrowaved);
-
- SubscribeLocalEvent<PAIComponent, PAIShopActionEvent>(OnShop);
}
private void OnUseInHand(EntityUid uid, PAIComponent component, UseInHandEvent args)
var val = Loc.GetString("pai-system-pai-name-raw", ("name", name.ToString()));
_metaData.SetEntityName(uid, val);
}
-
- private void OnShop(Entity<PAIComponent> ent, ref PAIShopActionEvent args)
- {
- if (!TryComp<StoreComponent>(ent, out var store))
- return;
-
- _store.ToggleUi(args.Performer, ent, store);
- }
-
public void PAITurningOff(EntityUid uid)
{
// Close the instrument interface if it was open
if (!Resolve(uid, ref battery))
return 0;
- var newValue = Math.Clamp(0, battery.CurrentCharge + value, battery.MaxCharge);
+ var newValue = Math.Clamp(battery.CurrentCharge + value, 0, battery.MaxCharge);
var delta = newValue - battery.CurrentCharge;
battery.CurrentCharge = newValue;
if (!transform.Anchored)
continue;
- _battery.SetCharge(entity, battery.CurrentCharge + networkLoad.NetworkLoad.ReceivingPower / 1000, battery);
+ _battery.ChangeCharge(entity, networkLoad.NetworkLoad.ReceivingPower * frameTime, battery);
var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
using System.Numerics;
using Content.Server.Actions;
using Content.Server.GameTicking;
-using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.Stunnable;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
-using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Revenant.EntitySystems;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly VisibilitySystem _visibility = default!;
[Dependency] private readonly TurfSystem _turf = default!;
-
- private static readonly EntProtoId RevenantShopId = "ActionRevenantShop";
-
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RevenantComponent, ComponentStartup>(OnStartup);
- SubscribeLocalEvent<RevenantComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<RevenantComponent, RevenantShopActionEvent>(OnShop);
SubscribeLocalEvent<RevenantComponent, DamageChangedEvent>(OnDamage);
SubscribeLocalEvent<RevenantComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<RevenantComponent, StatusEffectAddedEvent>(OnStatusAdded);
_eye.RefreshVisibilityMask(uid);
}
- private void OnMapInit(EntityUid uid, RevenantComponent component, MapInitEvent args)
- {
- _action.AddAction(uid, ref component.Action, RevenantShopId);
- }
-
private void OnStatusAdded(EntityUid uid, RevenantComponent component, StatusEffectAddedEvent args)
{
if (args.Key == "Stun")
return true;
}
- private void OnShop(EntityUid uid, RevenantComponent component, RevenantShopActionEvent args)
- {
- if (!TryComp<StoreComponent>(uid, out var store))
- return;
- _store.ToggleUi(uid, uid, store);
- }
-
public void MakeVisible(bool visible)
{
var query = EntityQueryEnumerator<RevenantComponent, VisibilityComponent>();
--- /dev/null
+using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
+using Content.Shared.Silicons.Bots;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Silicons.Bots;
+
+/// <summary>
+/// Beyond what <see cref="SharedHugBotSystem"/> does, this system manages the "lifecycle" of
+/// <see cref="RecentlyHuggedByHugBotComponent"/>.
+/// </summary>
+public sealed class HugBotSystem : SharedHugBotSystem
+{
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<HugBotComponent, HTNRaisedEvent>(OnHtnRaisedEvent);
+ }
+
+ private void OnHtnRaisedEvent(Entity<HugBotComponent> entity, ref HTNRaisedEvent args)
+ {
+ if (args.Args is not HugBotDidHugEvent ||
+ args.Target is not {} target)
+ return;
+
+ var ev = new HugBotHugEvent(GetNetEntity(entity));
+ RaiseLocalEvent(target, ev);
+
+ ApplyHugBotCooldown(entity, target);
+ }
+
+ /// <summary>
+ /// Applies <see cref="RecentlyHuggedByHugBotComponent"/> to <paramref name="target"/> based on the configuration of
+ /// <paramref name="hugBot"/>.
+ /// </summary>
+ public void ApplyHugBotCooldown(Entity<HugBotComponent> hugBot, EntityUid target)
+ {
+ var hugged = EnsureComp<RecentlyHuggedByHugBotComponent>(target);
+ hugged.CooldownCompleteAfter = _gameTiming.CurTime + hugBot.Comp.HugCooldown;
+ }
+
+ public override void Update(float frameTime)
+ {
+ // Iterate through all RecentlyHuggedByHugBot entities...
+ var huggedEntities = AllEntityQuery<RecentlyHuggedByHugBotComponent>();
+ while (huggedEntities.MoveNext(out var huggedEnt, out var huggedComp))
+ {
+ // ... and if their cooldown is complete...
+ if (huggedComp.CooldownCompleteAfter <= _gameTiming.CurTime)
+ {
+ // ... remove it, allowing them to receive the blessing of hugs once more.
+ RemCompDeferred<RecentlyHuggedByHugBotComponent>(huggedEnt);
+ }
+ }
+ }
+}
+
+/// <summary>
+/// This event is indirectly raised (by being <see cref="HTNRaisedEvent.Args"/>) on a HugBot when it hugs (or emaggedly
+/// punches) an entity.
+/// </summary>
+[Serializable, DataDefinition]
+public sealed partial class HugBotDidHugEvent : EntityEventArgs;
--- /dev/null
+using Content.Shared.Silicons.Bots;
+
+namespace Content.Server.Silicons.Bots;
+
+/// <summary>
+/// This marker component indicates that its entity has been recently hugged by a HugBot and should not be hugged again
+/// before <see cref="CooldownCompleteAfter">a cooldown period</see> in order to prevent hug spam.
+/// </summary>
+/// <see cref="SharedHugBotSystem"/>
+[RegisterComponent, AutoGenerateComponentPause]
+public sealed partial class RecentlyHuggedByHugBotComponent : Component
+{
+ [DataField, AutoPausedField]
+ public TimeSpan CooldownCompleteAfter = TimeSpan.MinValue;
+}
foreach (var result in rayCastResults)
{
- if (genQuery.HasComponent(result.HitEntity))
- closestResult = result;
+ if (!genQuery.HasComponent(result.HitEntity))
+ continue;
+ closestResult = result;
break;
}
+using System.Linq;
using Content.Server.Store.Components;
-using Content.Shared.UserInterface;
using Content.Shared.FixedPoint;
using Content.Shared.Implants.Components;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Stacks;
using Content.Shared.Store.Components;
-using JetBrains.Annotations;
+using Content.Shared.Store.Events;
+using Content.Shared.UserInterface;
using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
-using System.Linq;
using Robust.Shared.Timing;
-using Content.Shared.Mind;
+using Robust.Shared.Utility;
namespace Content.Server.Store.Systems;
SubscribeLocalEvent<StoreComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<StoreComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<StoreComponent, OpenUplinkImplantEvent>(OnImplantActivate);
+ SubscribeLocalEvent<StoreComponent, IntrinsicStoreActionEvent>(OnIntrinsicStoreAction);
InitializeUi();
InitializeCommand();
UpdateUserInterface(null, uid, store);
return true;
}
+
+ private void OnIntrinsicStoreAction(Entity<StoreComponent> ent, ref IntrinsicStoreActionEvent args)
+ {
+ ToggleUi(args.Performer, ent.Owner, ent.Comp);
+ }
+
}
public sealed class CurrencyInsertAttemptEvent : CancellableEntityEventArgs
if (ent.Comp.Refresh)
{
_stunSystem.TryUpdateStunDuration(target, ent.Comp.StunAmount);
+
_movementMod.TryUpdateMovementSpeedModDuration(
target,
MovementModStatusSystem.TaserSlowdown,
using Content.Shared.Inventory;
using Content.Shared.Rejuvenate;
using Content.Shared.Temperature;
-using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
-using Robust.Shared.Physics.Events;
using Content.Shared.Projectiles;
+using Content.Shared.Temperature.Components;
+using Content.Shared.Temperature.Systems;
namespace Content.Server.Temperature.Systems;
-public sealed class TemperatureSystem : EntitySystem
+public sealed class TemperatureSystem : SharedTemperatureSystem
{
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
true);
}
- public void ChangeHeat(EntityUid uid, float heatAmount, bool ignoreHeatResistance = false,
- TemperatureComponent? temperature = null)
+ public override void ChangeHeat(EntityUid uid, float heatAmount, bool ignoreHeatResistance = false, TemperatureComponent? temperature = null)
{
if (!Resolve(uid, ref temperature, false))
return;
ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature);
}
- public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, PhysicsComponent? physics = null)
- {
- if (!Resolve(uid, ref comp) || !Resolve(uid, ref physics, false) || physics.FixturesMass <= 0)
- {
- return Atmospherics.MinimumHeatCapacity;
- }
-
- return comp.SpecificHeat * physics.FixturesMass;
- }
-
private void OnInit(EntityUid uid, InternalTemperatureComponent comp, MapInitEvent args)
{
if (!TryComp<TemperatureComponent>(uid, out var temp))
/// <summary>
/// List of effects that should be applied.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField]
+ [DataField]
public List<EntityEffect> Effects = default!;
}
-using Content.Server.Atmos.Components;
-using Content.Server.Atmos.EntitySystems;
using Content.Shared.StepTrigger.Systems;
-using Content.Shared.Chemistry.Reagent;
using Content.Shared.EntityEffects;
namespace Content.Server.Tiles;
public sealed class TileEntityEffectSystem : EntitySystem
{
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
public override void Initialize()
{
private void OnTileStepTriggered(Entity<TileEntityEffectComponent> ent, ref StepTriggeredOffEvent args)
{
var otherUid = args.Tripper;
- var effectArgs = new EntityEffectBaseArgs(otherUid, EntityManager);
- foreach (var effect in ent.Comp.Effects)
- {
- effect.Effect(effectArgs);
- }
+ _entityEffects.ApplyEffects(otherUid, ent.Comp.Effects.ToArray());
}
}
using Content.Server.Chat.Systems;
using Content.Server.Movement.Systems;
-using Content.Shared.Damage.Events;
-using Content.Shared.Damage.Systems;
using Content.Shared.Effects;
using Content.Shared.Speech.Components;
using Content.Shared.Weapons.Melee;
public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
{
[Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
[Dependency] private readonly LagCompensationSystem _lag = default!;
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
- SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
- }
-
- private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
- {
- if (component.Hidden)
- return;
- var damageSpec = GetDamage(uid, args.User, component);
-
- if (damageSpec.Empty)
- return;
-
- _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
+ SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
}
protected override bool ArcRaySuccessful(EntityUid targetUid,
-using Content.Shared.Damage;
-using Content.Shared.Damage.Events;
using Content.Shared.Power;
using Content.Shared.PowerCell.Components;
-using Content.Shared.Projectiles;
-using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
-using Robust.Shared.Prototypes;
namespace Content.Server.Weapons.Ranged.Systems;
// Hitscan
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
- SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
// Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
- SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
}
RaiseLocalEvent(uid, ref updateAmmoEv);
}
- private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
- {
- var damageSpec = GetDamage(entity.Comp);
-
- if (damageSpec == null)
- return;
-
- var damageType = entity.Comp switch
- {
- HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
- ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
- _ => throw new ArgumentOutOfRangeException(),
- };
-
- _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
- }
-
- private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
- {
- if (component is ProjectileBatteryAmmoProviderComponent battery)
- {
- if (ProtoManager.Index<EntityPrototype>(battery.Prototype).Components
- .TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
- {
- var p = (ProjectileComponent) projectile.Component;
-
- if (!p.Damage.Empty)
- {
- return p.Damage * Damageable.UniversalProjectileDamageModifier;
- }
- }
-
- return null;
- }
-
- if (component is HitscanBatteryAmmoProviderComponent hitscan)
- {
- var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
- return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
- }
-
- return null;
- }
-
protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
{
var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
using Content.Server.Body.Systems;
-using Content.Server.Popups;
-using Content.Server.Power.EntitySystems;
using Content.Server.Stack;
using Content.Shared.Body.Components;
-using Content.Shared.Damage;
-using Content.Shared.Power;
using Content.Shared.Storage.Components;
-using Content.Shared.Verbs;
using Content.Shared.Whitelist;
using Content.Shared.Xenoarchaeology.Equipment;
using Content.Shared.Xenoarchaeology.Equipment.Components;
using Robust.Shared.Collections;
using Robust.Shared.Random;
-using Robust.Shared.Timing;
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
/// <inheritdoc/>
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
{
- [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly BodySystem _body = default!;
- [Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly StackSystem _stack = default!;
- [Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
- /// <inheritdoc/>
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<ArtifactCrusherComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
- SubscribeLocalEvent<ArtifactCrusherComponent, PowerChangedEvent>(OnPowerChanged);
- }
-
- private void OnGetVerbs(Entity<ArtifactCrusherComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
- {
- if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
- return;
-
- if (!TryComp<EntityStorageComponent>(ent, out var entityStorageComp) ||
- entityStorageComp.Contents.ContainedEntities.Count == 0)
- return;
-
- if (!this.IsPowered(ent, EntityManager))
- return;
-
- var verb = new AlternativeVerb
- {
- Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
- Priority = 2,
- Act = () => StartCrushing((ent, ent.Comp, entityStorageComp))
- };
- args.Verbs.Add(verb);
- }
-
- private void OnPowerChanged(Entity<ArtifactCrusherComponent> ent, ref PowerChangedEvent args)
- {
- if (!args.Powered)
- StopCrushing(ent);
- }
-
- public void StartCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
- {
- var (uid, crusher, _) = ent;
-
- if (crusher.Crushing)
- return;
-
- if (crusher.AutoLock)
- _popup.PopupEntity(Loc.GetString("artifact-crusher-autolocks-enable"), uid);
-
- crusher.Crushing = true;
- crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
- crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
- crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent);
- Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
- Dirty(ent, ent.Comp1);
- }
-
- public void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
+ // TODO: Move to shared once StackSystem spawning is in Shared and we have RandomPredicted
+ public override void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
{
var (_, crusher, storage) = ent;
StopCrushing((ent, ent.Comp1), false);
}
}
}
-
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
-
- var query = EntityQueryEnumerator<ArtifactCrusherComponent, EntityStorageComponent>();
- while (query.MoveNext(out var uid, out var crusher, out var storage))
- {
- if (!crusher.Crushing)
- continue;
-
- if (crusher.NextSecond < _timing.CurTime)
- {
- var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
- foreach (var contained in contents)
- {
- _damageable.TryChangeDamage(contained, crusher.CrushingDamage);
- }
- crusher.NextSecond += TimeSpan.FromSeconds(1);
- Dirty(uid, crusher);
- }
-
- if (crusher.CrushEndTime < _timing.CurTime)
- {
- FinishCrushing((uid, crusher, storage));
- }
- }
- }
}
using Content.Server.NPC.Systems;
using Content.Server.StationEvents.Components;
using Content.Server.Speech.Components;
-using Content.Server.Temperature.Components;
using Content.Shared.Body.Components;
using Content.Shared.Chat;
using Content.Shared.CombatMode;
using Robust.Shared.Prototypes;
using Content.Shared.NPC.Prototypes;
using Content.Shared.Roles;
+using Content.Shared.Temperature.Components;
namespace Content.Server.Zombies;
ChemicalReaction = 17,
/// <summary>
- /// Reagent effects related interactions.
+ /// EntityEffect related interactions.
/// </summary>
- ReagentEffect = 18,
+ EntityEffect = 18,
/// <summary>
/// Canister valve was opened or closed.
/// The name/key of the solution on this entity which these lungs act on.
/// </summary>
[DataField]
- public string SolutionName = LungSystem.LungSolutionName;
+ public string SolutionName = "Lung";
/// <summary>
/// The solution on this entity that these lungs act on.
+using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Body.Components;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Atmos;
+using Content.Shared.Body.Prototypes;
using Content.Shared.Chemistry.Components;
-using Content.Shared.Clothing;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Inventory.Events;
+using Robust.Shared.Prototypes;
+using BreathToolComponent = Content.Shared.Atmos.Components.BreathToolComponent;
+using InternalsComponent = Content.Shared.Body.Components.InternalsComponent;
namespace Content.Shared.Body.Systems;
[Dependency] private readonly SharedInternalsSystem _internals = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
- public static string LungSolutionName = "Lung";
-
public override void Initialize()
{
base.Initialize();
}
}
+ // TODO: JUST METABOLIZE GASES DIRECTLY DON'T CONVERT TO REAGENTS!!! (Needs Metabolism refactor :B)
public void GasToReagent(EntityUid uid, LungComponent lung)
{
if (!_solutionContainerSystem.ResolveSolution(uid, lung.SolutionName, ref lung.Solution, out var solution))
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
-using Content.Shared.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects.Solution;
+using Content.Shared.EntityEffects.Effects.Transform;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids;
using Content.Shared.Forensics.Components;
{
switch (effect)
{
- case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream
+ // TODO: Rather than this, ReactionAttempt should allow systems to remove effects from the list before the reaction.
+ // TODO: I think there's a PR up on the repo for this and if there isn't I'll make one -Princess
+ case EntityEffects.Effects.EntitySpawning.SpawnEntity: // Prevent entities from spawning in the bloodstream
case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels.
args.Cancelled = true;
return;
/// The ID of the emote prototype.
/// </summary>
[DataField("emote", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EmotePrototype>))]
- public string EmoteId = String.Empty;
+ public string EmoteId = string.Empty;
/// <summary>
/// How often an attempt at the emote will be made.
/// </summary>
- [DataField("interval", required: true)]
+ [DataField(required: true)]
public TimeSpan Interval;
/// <summary>
/// Probability of performing the emote each interval.
- /// <summary>
+ /// </summary>
[DataField("chance")]
public float Chance = 1;
/// <summary>
/// Also send the emote in chat.
- /// <summary>
- [DataField("withChat")]
+ /// </summary>
+ [DataField]
public bool WithChat = true;
/// <summary>
- /// Hide the chat message from the chat window, only showing the popup.
+ /// Should we ignore action blockers?
+ /// This does nothing if WithChat is false.
+ /// </summary>
+ [DataField]
+ public bool IgnoreActionBlocker;
+
+ /// <summary>
+ /// Should we ignore whitelists and force the emote?
/// This does nothing if WithChat is false.
+ /// </summary>
+ [DataField]
+ public bool Force;
+
/// <summary>
- [DataField("hiddenFromChatWindow")]
- public bool HiddenFromChatWindow = false;
+ /// Hide the chat message from the chat window, only showing the popup.
+ /// This does nothing if WithChat is false.
+ /// </summary>
+ [DataField]
+ public bool HiddenFromChatWindow;
}
}
// Thermal energy and temperature management.
+ // TODO: ENERGY CONSERVATION!!! Nuke this once we have HeatContainers and use methods which properly conserve energy and model heat transfer correctly!
#region Thermal Energy and Temperature
UpdateChemicals(soln);
}
+ /// <summary>
+ /// Same as <see cref="AddThermalEnergy"/> but clamps the value between two temperature values.
+ /// </summary>
+ /// <param name="soln">Solution we're adjusting the energy of</param>
+ /// <param name="thermalEnergy">Thermal energy we're adding or removing</param>
+ /// <param name="min">Min desired temperature</param>
+ /// <param name="max">Max desired temperature</param>
+ public void AddThermalEnergyClamped(Entity<SolutionComponent> soln, float thermalEnergy, float min, float max)
+ {
+ var solution = soln.Comp.Solution;
+
+ if (thermalEnergy == 0.0f)
+ return;
+
+ var heatCap = solution.GetHeatCapacity(PrototypeManager);
+ var deltaT = thermalEnergy / heatCap;
+ solution.Temperature = Math.Clamp(solution.Temperature + deltaT, min, max);
+ UpdateChemicals(soln);
+ }
+
#endregion Thermal Energy and Temperature
#region Event Handlers
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
+ [Dependency] private readonly SharedEntityEffectsSystem _entityEffects = default!;
/// <summary>
/// A cache of all reactions indexed by at most ONE of their required reactants.
private void OnReaction(Entity<SolutionComponent> soln, ReactionPrototype reaction, ReagentPrototype? reagent, FixedPoint2 unitReactions)
{
- var args = new EntityEffectReagentArgs(soln, EntityManager, null, soln.Comp.Solution, unitReactions, reagent, null, 1f);
-
var posFound = _transformSystem.TryGetMapOrGridCoordinates(soln, out var gridPos);
_adminLogger.Add(LogType.ChemicalReaction, reaction.Impact,
$"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(soln):metabolizer} at Pos:{(posFound ? $"{gridPos:coordinates}" : "[Grid or Map not Found]")}");
- foreach (var effect in reaction.Effects)
- {
- if (!effect.ShouldApply(args))
- continue;
-
- if (effect.ShouldLog)
- {
- var entity = args.TargetEntity;
- _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Reaction effect {effect.GetType().Name:effect} of reaction {reaction.ID:reaction} applied on entity {ToPrettyString(entity):entity} at Pos:{(posFound ? $"{gridPos:coordinates}" : "[Grid or Map not Found")}");
- }
-
- effect.Effect(args);
- }
+ _entityEffects.ApplyEffects(soln, reaction.Effects, unitReactions.Float());
// Someday, some brave soul will thread through an optional actor
// argument in from every call of OnReaction up, all just to pass
/// <summary>
/// Effects to be triggered when the reaction occurs.
/// </summary>
- [DataField("effects")] public List<EntityEffect> Effects = new();
+ [DataField("effects")] public EntityEffect[] Effects = [];
/// <summary>
/// How dangerous is this effect? Stuff like bicaridine should be low, while things like methamphetamine
public HashSet<string>? Reagents = null;
[DataField("effects", required: true)]
- public List<EntityEffect> Effects = default!;
+ public EntityEffect[] Effects = default!;
[DataField("groups", readOnly: true, serverOnly: true,
customTypeSerializer:typeof(PrototypeIdDictionarySerializer<HashSet<ReactionMethod>, ReactiveGroupPrototype>))]
-using Content.Shared.Administration.Logs;
using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
+using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
namespace Content.Shared.Chemistry;
[UsedImplicitly]
public sealed class ReactiveSystem : EntitySystem
{
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IRobustRandom _robustRandom = default!;
- [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
public void DoEntityReaction(EntityUid uid, Solution solution, ReactionMethod method)
{
foreach (var reagent in solution.Contents.ToArray())
{
- ReactionEntity(uid, method, reagent, solution);
+ ReactionEntity(uid, method, reagent);
}
}
- public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentQuantity reagentQuantity, Solution? source)
+ public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentQuantity reagentQuantity)
{
- // We throw if the reagent specified doesn't exist.
- var proto = _prototypeManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
- ReactionEntity(uid, method, proto, reagentQuantity, source);
- }
+ if (reagentQuantity.Quantity == FixedPoint2.Zero)
+ return;
- public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype proto,
- ReagentQuantity reagentQuantity, Solution? source)
- {
- if (!TryComp(uid, out ReactiveComponent? reactive))
+ // We throw if the reagent specified doesn't exist.
+ if (!_proto.Resolve<ReagentPrototype>(reagentQuantity.Reagent.Prototype, out var proto))
return;
- // custom event for bypassing reactivecomponent stuff
- var ev = new ReactionEntityEvent(method, proto, reagentQuantity, source);
+ var ev = new ReactionEntityEvent(method, reagentQuantity, proto);
RaiseLocalEvent(uid, ref ev);
-
- // If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified.
- var args = new EntityEffectReagentArgs(uid, EntityManager, null, source, source?.GetReagentQuantity(reagentQuantity.Reagent) ?? reagentQuantity.Quantity, proto, method, 1f);
-
- // First, check if the reagent wants to apply any effects.
- if (proto.ReactiveEffects != null && reactive.ReactiveGroups != null)
- {
- foreach (var (key, val) in proto.ReactiveEffects)
- {
- if (!val.Methods.Contains(method))
- continue;
-
- if (!reactive.ReactiveGroups.ContainsKey(key))
- continue;
-
- if (!reactive.ReactiveGroups[key].Contains(method))
- continue;
-
- foreach (var effect in val.Effects)
- {
- if (!effect.ShouldApply(args, _robustRandom))
- continue;
-
- if (effect.ShouldLog)
- {
- var entity = args.TargetEntity;
- _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Reactive effect {effect.GetType().Name:effect} of reagent {proto.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
- }
-
- effect.Effect(args);
- }
- }
- }
-
- // Then, check if the prototype has any effects it can apply as well.
- if (reactive.Reactions != null)
- {
- foreach (var entry in reactive.Reactions)
- {
- if (!entry.Methods.Contains(method))
- continue;
-
- if (entry.Reagents != null && !entry.Reagents.Contains(proto.ID))
- continue;
-
- foreach (var effect in entry.Effects)
- {
- if (!effect.ShouldApply(args, _robustRandom))
- continue;
-
- if (effect.ShouldLog)
- {
- var entity = args.TargetEntity;
- _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {proto.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
- }
-
- effect.Effect(args);
- }
- }
- }
}
}
public enum ReactionMethod
}
[ByRefEvent]
-public readonly record struct ReactionEntityEvent(
- ReactionMethod Method,
- ReagentPrototype Reagent,
- ReagentQuantity ReagentQuantity,
- Solution? Source
-);
+public readonly record struct ReactionEntityEvent(ReactionMethod Method, ReagentQuantity ReagentQuantity, ReagentPrototype Reagent);
using System.Linq;
using Content.Shared.FixedPoint;
using System.Text.Json.Serialization;
-using Content.Shared.Administration.Logs;
using Content.Shared.Body.Prototypes;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Contraband;
using Content.Shared.EntityEffects;
-using Content.Shared.Database;
+using Content.Shared.Localizations;
using Content.Shared.Nutrition;
-using Content.Shared.Prototypes;
using Content.Shared.Roles;
using Content.Shared.Slippery;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
using Robust.Shared.Utility;
[DataField]
public SoundSpecifier FootstepSound = new SoundCollectionSpecifier("FootstepPuddle");
+ // TODO: Reaction tile doesn't work properly and destroys reagents way too quickly
public FixedPoint2 ReactionTile(TileRef tile, FixedPoint2 reactVolume, IEntityManager entityManager, List<ReagentData>? data)
{
var removed = FixedPoint2.Zero;
return removed;
}
- public void ReactionPlant(EntityUid? plantHolder,
- ReagentQuantity amount,
- Solution solution,
- EntityManager entityManager,
- IRobustRandom random,
- ISharedAdminLogManager logger)
+ public IEnumerable<string> GuidebookReagentEffectsDescription(IPrototypeManager prototype, IEntitySystemManager entSys, IEnumerable<EntityEffect> effects, FixedPoint2? metabolism = null)
{
- if (plantHolder == null)
- return;
+ return effects.Select(x => GuidebookReagentEffectDescription(prototype, entSys, x, metabolism))
+ .Where(x => x is not null)
+ .Select(x => x!)
+ .ToArray();
+ }
- var args = new EntityEffectReagentArgs(plantHolder.Value, entityManager, null, solution, amount.Quantity, this, null, 1f);
- foreach (var plantMetabolizable in PlantMetabolisms)
- {
- if (!plantMetabolizable.ShouldApply(args, random))
- continue;
-
- if (plantMetabolizable.ShouldLog)
- {
- var entity = args.TargetEntity;
- logger.Add(
- LogType.ReagentEffect,
- plantMetabolizable.LogImpact,
- $"Plant metabolism effect {plantMetabolizable.GetType().Name:effect} of reagent {ID} applied on entity {entity}");
- }
-
- plantMetabolizable.Effect(args);
- }
+ public string? GuidebookReagentEffectDescription(IPrototypeManager prototype, IEntitySystemManager entSys, EntityEffect effect, FixedPoint2? metabolism)
+ {
+ if (effect.EntityEffectGuidebookText(prototype, entSys) is not { } description)
+ return null;
+
+ var quantity = metabolism == null ? 0f : (double) (effect.MinScale * metabolism);
+
+ return Loc.GetString(
+ "guidebook-reagent-effect-description",
+ ("reagent", LocalizedName),
+ ("quantity", quantity),
+ ("effect", description),
+ ("chance", effect.Probability),
+ ("conditionCount", effect.Conditions?.Length ?? 0),
+ ("conditions",
+ ContentLocalizationManager.FormatList(
+ effect.Conditions?.Select(x => x.EntityConditionGuidebookText(prototype)).ToList() ?? new List<string>()
+ )));
}
}
{
public string ReagentPrototype;
+ // TODO: Kill Metabolism groups!
public Dictionary<ProtoId<MetabolismGroupPrototype>, ReagentEffectsGuideEntry>? GuideEntries;
public List<string>? PlantMetabolisms = null;
{
ReagentPrototype = proto.ID;
GuideEntries = proto.Metabolisms?
- .Select(x => (x.Key, x.Value.MakeGuideEntry(prototype, entSys)))
+ .Select(x => (x.Key, x.Value.MakeGuideEntry(prototype, entSys, proto)))
.ToDictionary(x => x.Key, x => x.Item2);
if (proto.PlantMetabolisms.Count > 0)
{
- PlantMetabolisms = new List<string>(proto.PlantMetabolisms
- .Select(x => x.GuidebookEffectDescription(prototype, entSys))
- .Where(x => x is not null)
- .Select(x => x!)
- .ToArray());
+ PlantMetabolisms =
+ new List<string>(proto.GuidebookReagentEffectsDescription(prototype, entSys, proto.PlantMetabolisms));
}
}
}
[DataField("effects", required: true)]
public EntityEffect[] Effects = default!;
- public ReagentEffectsGuideEntry MakeGuideEntry(IPrototypeManager prototype, IEntitySystemManager entSys)
+ public string EntityEffectFormat => "guidebook-reagent-effect-description";
+
+ public ReagentEffectsGuideEntry MakeGuideEntry(IPrototypeManager prototype, IEntitySystemManager entSys, ReagentPrototype proto)
{
- return new ReagentEffectsGuideEntry(MetabolismRate,
- Effects
- .Select(x => x.GuidebookEffectDescription(prototype, entSys)) // hate.
- .Where(x => x is not null)
- .Select(x => x!)
- .ToArray());
+ return new ReagentEffectsGuideEntry(MetabolismRate, proto.GuidebookReagentEffectsDescription(prototype, entSys, Effects, MetabolismRate).ToArray());
}
}
private void OnGotUnequipped(EntityUid uid, MaskComponent mask, GotUnequippedEvent args)
{
- if (!mask.IsToggled || !mask.IsToggleable)
- return;
-
- mask.IsToggled = false;
- ToggleMaskComponents(uid, mask, args.Equipee, mask.EquippedPrefix, true);
- }
-
- /// <summary>
- /// Called after setting IsToggled, raises events and dirties.
- /// </summary>
- private void ToggleMaskComponents(EntityUid uid, MaskComponent mask, EntityUid wearer, string? equippedPrefix = null, bool isEquip = false)
- {
- Dirty(uid, mask);
- if (mask.ToggleActionEntity is { } action)
- _actionSystem.SetToggled(action, mask.IsToggled);
-
- var maskEv = new ItemMaskToggledEvent((uid, mask), wearer);
- RaiseLocalEvent(uid, ref maskEv);
-
- var wearerEv = new WearerMaskToggledEvent((uid, mask));
- RaiseLocalEvent(wearer, ref wearerEv);
+ SetToggled(uid, false);
}
private void OnFolded(Entity<MaskComponent> ent, ref FoldedEvent args)
using Robust.Shared.Audio;
using Content.Shared.Chat.Prototypes;
+using Content.Shared.Damage;
+using Content.Shared.Roles;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Cluwne;
/// <summary>
/// timings for giggles and knocks.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
public TimeSpan DamageGiggleCooldown = TimeSpan.FromSeconds(2);
- [ViewVariables(VVAccess.ReadWrite)]
+ /// <summary>
+ /// Amount of genetic damage dealt when they revert
+ /// </summary>
+ [DataField]
+ public DamageSpecifier RevertDamage = new()
+ {
+ DamageDict = new()
+ {
+ { "Genetic", 300.0 },
+ },
+ };
+
+ /// <summary>
+ /// Chance that the Cluwne will be knocked over and paralyzed.
+ /// </summary>
+ [DataField]
public float KnockChance = 0.05f;
- [ViewVariables(VVAccess.ReadWrite)]
+ /// <summary>
+ /// Chance that the Cluwne will randomly giggle
+ /// </summary>
+ [DataField]
public float GiggleRandomChance = 0.1f;
- [DataField("emoteId", customTypeSerializer: typeof(PrototypeIdSerializer<EmoteSoundsPrototype>))]
- public string? EmoteSoundsId = "Cluwne";
+ /// <summary>
+ /// Enable random emoting?
+ /// </summary>
+ [DataField]
+ public bool RandomEmote = true;
+
+ /// <summary>
+ /// Emote sound collection that the Cluwne should use.
+ /// </summary>
+ [DataField("emoteId")]
+ public ProtoId<EmoteSoundsPrototype>? EmoteSoundsId = "Cluwne";
+
+ /// <summary>
+ /// Emote to use for the Cluwne Giggling
+ /// </summary>
+ [DataField]
+ public ProtoId<AutoEmotePrototype>? AutoEmoteId = "CluwneGiggle";
+
+ /// <summary>
+ /// Message to popup when the Cluwne is transformed
+ /// </summary>
+ [DataField]
+ public LocId TransformMessage = "cluwne-transform";
+
+ /// <summary>
+ /// Name prefix for the Cluwne.
+ /// Example "Urist McHuman" will be "Cluwned Urist McHuman"
+ /// </summary>
+ [DataField]
+ public LocId NamePrefix = "cluwne-name-prefix";
+
+ /// <summary>
+ /// Outfit ID that the cluwne will spawn with.
+ /// </summary>
+ [DataField]
+ public ProtoId<StartingGearPrototype> OutfitId = "CluwneGear";
/// <summary>
/// Amount of time cluwne is paralyzed for when falling over.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
public float ParalyzeTime = 2f;
/// <summary>
[DataField("spawnsound")]
public SoundSpecifier SpawnSound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
- [DataField("knocksound")]
+ /// <summary>
+ /// Emote to use for the cluwne giggling
+ /// </summary>
+ [DataField]
+ public LocId GiggleEmote = "cluwne-giggle-emote";
+
+ /// <summary>
+ /// Sound to play when the Cluwne is knocked over and paralyzed
+ /// </summary>
+ [DataField]
public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Items/airhorn.ogg");
+
+ /// <summary>
+ /// Emote thats used when the cluwne getting knocked over
+ /// </summary>
+ [DataField]
+ public LocId KnockEmote = "cluwne-knock-emote";
}
--- /dev/null
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Crayon;
+
+/// <summary>
+/// Component holding the state of a crayon-like component
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[Access(typeof(SharedCrayonSystem))]
+public sealed partial class CrayonComponent : Component
+{
+ /// <summary>
+ /// The ID of currently selected decal prototype that will be placed when the crayon is used.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public string SelectedState;
+
+ /// <summary>
+ /// Color with which the crayon will draw.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public Color Color;
+
+ /// <summary>
+ /// Play a sound when drawing if specified.
+ /// </summary>
+ [DataField]
+ public SoundSpecifier? UseSound;
+
+ /// <summary>
+ /// Can the color can be changed?
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool SelectableColor;
+
+ /// <summary>
+ /// Should the crayon be deleted when all charges are consumed?
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool DeleteEmpty = true;
+}
+
+/// <summary>
+/// Opens the crayon window for decal and color selection.
+/// </summary>
+[Serializable, NetSerializable]
+public enum CrayonUiKey : byte
+{
+ Key,
+}
+
+/// <summary>
+/// Used by the client to notify the server about the selected decal ID
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
+{
+ public readonly string State;
+ public CrayonSelectMessage(string selected)
+ {
+ State = selected;
+ }
+}
+
+/// <summary>
+/// Sets the color of the crayon, used by Rainbow Crayon
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class CrayonColorMessage : BoundUserInterfaceMessage
+{
+ public readonly Color Color;
+ public CrayonColorMessage(Color color)
+ {
+ Color = color;
+ }
+}
+
+/// <summary>
+/// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
+/// Allows the client UI to advance forward in the client-only ephemeral queue,
+/// preventing the crayon from becoming a magic text storage device.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
+{
+ public readonly string DrawnDecal;
+
+ public CrayonUsedMessage(string drawn)
+ {
+ DrawnDecal = drawn;
+ }
+}
+
+/// <summary>
+/// The state of the crayon UI as sent by the server
+/// </summary>
+/// <summary>
+/// TODO: Delete this and use component states and predict the UI.
+/// This info is already networked on its own.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
+{
+ public string Selected;
+ /// <summary>
+ /// Can the color can be changed
+ /// </summary>
+ public bool SelectableColor;
+ public Color Color;
+
+ public CrayonBoundUserInterfaceState(string selected, bool selectableColor, Color color)
+ {
+ Selected = selected;
+ SelectableColor = selectableColor;
+ Color = color;
+ }
+}
+++ /dev/null
-using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Crayon
-{
-
- /// <summary>
- /// Component holding the state of a crayon-like component
- /// </summary>
- [NetworkedComponent, ComponentProtoName("Crayon"), Access(typeof(SharedCrayonSystem))]
- public abstract partial class SharedCrayonComponent : Component
- {
- /// <summary>
- /// The ID of currently selected decal prototype that will be placed when the crayon is used
- /// </summary>
- public string SelectedState { get; set; } = string.Empty;
-
- /// <summary>
- /// Color with which the crayon will draw
- /// </summary>
- [DataField("color")]
- public Color Color;
-
- [Serializable, NetSerializable]
- public enum CrayonUiKey : byte
- {
- Key,
- }
- }
-
- /// <summary>
- /// Used by the client to notify the server about the selected decal ID
- /// </summary>
- [Serializable, NetSerializable]
- public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
- {
- public readonly string State;
- public CrayonSelectMessage(string selected)
- {
- State = selected;
- }
- }
-
- /// <summary>
- /// Sets the color of the crayon, used by Rainbow Crayon
- /// </summary>
- [Serializable, NetSerializable]
- public sealed class CrayonColorMessage : BoundUserInterfaceMessage
- {
- public readonly Color Color;
- public CrayonColorMessage(Color color)
- {
- Color = color;
- }
- }
-
- /// <summary>
- /// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
- /// Allows the client UI to advance forward in the client-only ephemeral queue,
- /// preventing the crayon from becoming a magic text storage device.
- /// </summary>
- [Serializable, NetSerializable]
- public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
- {
- public readonly string DrawnDecal;
-
- public CrayonUsedMessage(string drawn)
- {
- DrawnDecal = drawn;
- }
- }
-
- /// <summary>
- /// Component state, describes how many charges are left in the crayon in the near-hand UI
- /// </summary>
- [Serializable, NetSerializable]
- public sealed class CrayonComponentState : ComponentState
- {
- public readonly Color Color;
- public readonly string State;
- public readonly int Charges;
- public readonly int Capacity;
-
- public CrayonComponentState(Color color, string state, int charges, int capacity)
- {
- Color = color;
- State = state;
- Charges = charges;
- Capacity = capacity;
- }
- }
-
- /// <summary>
- /// The state of the crayon UI as sent by the server
- /// </summary>
- [Serializable, NetSerializable]
- public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
- {
- public string Selected;
- /// <summary>
- /// Whether or not the color can be selected
- /// </summary>
- public bool SelectableColor;
- public Color Color;
-
- public CrayonBoundUserInterfaceState(string selected, bool selectableColor, Color color)
- {
- Selected = selected;
- SelectableColor = selectableColor;
- Color = color;
- }
- }
-}
namespace Content.Shared.Damage.Components;
+/// <summary>
+/// Shows a detailed examine window with this entity's damage stats when examined.
+/// </summary>
[RegisterComponent, NetworkedComponent]
-public sealed partial class DamageExaminableComponent : Component
-{
-}
+public sealed partial class DamageExaminableComponent : Component;
--- /dev/null
+using Content.Shared.Damage.Systems;
+
+namespace Content.Shared.Damage.Components;
+
+/// <summary>
+/// Makes this entity deal damage when thrown at something.
+/// </summary>
+[RegisterComponent]
+[Access(typeof(SharedDamageOtherOnHitSystem))]
+public sealed partial class DamageOtherOnHitComponent : Component
+{
+ /// <summary>
+ /// Whether to ignore damage modifiers.
+ /// </summary>
+ [DataField]
+ public bool IgnoreResistances = false;
+
+ /// <summary>
+ /// The damage amount to deal on hit.
+ /// </summary>
+ [DataField(required: true)]
+ public DamageSpecifier Damage = default!;
+
+}
+using Content.Shared.Damage.Components;
using Robust.Shared.Utility;
namespace Content.Shared.Damage.Events;
+/// <summary>
+/// Raised on an entity with <see cref="DamageExaminableComponent"/> when examined to get the damage values displayed in the examine window.
+/// </summary>
[ByRefEvent]
public readonly record struct DamageExamineEvent(FormattedMessage Message, EntityUid User);
--- /dev/null
+using Content.Shared.CombatMode.Pacification;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Events;
+
+namespace Content.Shared.Damage.Systems;
+
+public abstract class SharedDamageOtherOnHitSystem : EntitySystem
+{
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+ [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
+ SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
+ }
+
+ private void OnDamageExamine(Entity<DamageOtherOnHitComponent> ent, ref DamageExamineEvent args)
+ {
+ _damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(ent.Comp.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
+ }
+
+ /// <summary>
+ /// Prevent players with the Pacified status effect from throwing things that deal damage.
+ /// </summary>
+ private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
+ {
+ args.Cancel("pacified-cannot-throw");
+ }
+}
-namespace Content.Shared.Destructible;
+namespace Content.Shared.Destructible;
public abstract class SharedDestructibleSystem : EntitySystem
{
/// <summary>
- /// Force entity to be destroyed and deleted.
+ /// Force entity to be destroyed and deleted.
/// </summary>
public bool DestroyEntity(EntityUid owner)
{
var eventArgs = new DestructionEventArgs();
RaiseLocalEvent(owner, eventArgs);
- QueueDel(owner);
+ PredictedQueueDel(owner);
return true;
}
/// <summary>
- /// Force entity to break.
+ /// Force entity to break.
/// </summary>
public void BreakEntity(EntityUid owner)
{
}
/// <summary>
-/// Raised before an entity is about to be destroyed and deleted
+/// Raised before an entity is about to be destroyed and deleted
/// </summary>
public sealed class DestructionAttemptEvent : CancellableEntityEventArgs
{
}
/// <summary>
-/// Raised when entity is destroyed and about to be deleted.
+/// Raised when entity is destroyed and about to be deleted.
/// </summary>
public sealed class DestructionEventArgs : EntityEventArgs
{
}
/// <summary>
-/// Raised when entity was heavy damage and about to break.
+/// Raised when entity was heavy damage and about to break.
/// </summary>
public sealed class BreakageEventArgs : EntityEventArgs
{
return links;
}
+ /// <summary>
+ /// Gets the entities linked to a specific source port.
+ /// </summary>
+ public HashSet<EntityUid> GetLinkedSinks(Entity<DeviceLinkSourceComponent?> source, ProtoId<SourcePortPrototype> port)
+ {
+ if (!Resolve(source, ref source.Comp) || !source.Comp.Outputs.TryGetValue(port, out var linked))
+ return new HashSet<EntityUid>(); // not a source or not linked
+
+ return new HashSet<EntityUid>(linked); // clone to prevent modifying the original
+ }
+
/// <summary>
/// Returns the default links for the given list of source port prototypes
/// </summary>
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Body;
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class BreathingCondition : EntityConditionBase<BreathingCondition>
+{
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-breathing", ("isBreathing", !Inverted));
+}
--- /dev/null
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Body;
+
+/// <summary>
+/// Returns true if this entity's hunger is within a specified minimum and maximum.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class TotalHungerEntityConditionSystem : EntityConditionSystem<HungerComponent, HungerCondition>
+{
+ [Dependency] private readonly HungerSystem _hunger = default!;
+
+ protected override void Condition(Entity<HungerComponent> entity, ref EntityConditionEvent<HungerCondition> args)
+ {
+ var total = _hunger.GetHunger(entity.Comp);
+ args.Result = total >= args.Condition.Min && total <= args.Condition.Max;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class HungerCondition : EntityConditionBase<HungerCondition>
+{
+ [DataField]
+ public float Min;
+
+ [DataField]
+ public float Max = float.PositiveInfinity;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-total-hunger", ("max", float.IsPositiveInfinity(Max) ? int.MaxValue : Max), ("min", Min));
+}
--- /dev/null
+using Content.Shared.Body.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Body;
+
+/// <summary>
+/// Returns true if this entity is using internals. False if they are not or cannot use internals.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class InternalsOnEntityConditionSystem : EntityConditionSystem<InternalsComponent, InternalsCondition>
+{
+ protected override void Condition(Entity<InternalsComponent> entity, ref EntityConditionEvent<InternalsCondition> args)
+ {
+ args.Result = entity.Comp.GasTankEntity != null;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class InternalsCondition : EntityConditionBase<InternalsCondition>
+{
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-internals", ("usingInternals", !Inverted));
+}
--- /dev/null
+using Content.Shared.Body.Prototypes;
+using Content.Shared.Localizations;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Body;
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class MetabolizerTypeCondition : EntityConditionBase<MetabolizerTypeCondition>
+{
+ [DataField(required: true)]
+ public ProtoId<MetabolizerTypePrototype>[] Type = default!;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype)
+ {
+ var typeList = new List<string>();
+
+ foreach (var type in Type)
+ {
+ if (!prototype.Resolve(type, out var proto))
+ continue;
+
+ typeList.Add(proto.LocalizedName);
+ }
+
+ var names = ContentLocalizationManager.FormatListToOr(typeList);
+
+ return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
+ ("name", names),
+ ("shouldhave", !Inverted));
+ }
+}
--- /dev/null
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Body;
+
+/// <summary>
+/// Returns true if this entity's current mob state matches the condition's specified mob state.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class MobStateEntityConditionSystem : EntityConditionSystem<MobStateComponent, MobStateCondition>
+{
+ protected override void Condition(Entity<MobStateComponent> entity, ref EntityConditionEvent<MobStateCondition> args)
+ {
+ if (entity.Comp.CurrentState == args.Condition.Mobstate)
+ args.Result = true;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class MobStateCondition : EntityConditionBase<MobStateCondition>
+{
+ [DataField]
+ public MobState Mobstate = MobState.Alive;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate));
+}
--- /dev/null
+using System.Linq;
+using Content.Shared.Localizations;
+using Content.Shared.Mind;
+using Content.Shared.Mind.Components;
+using Content.Shared.Roles;
+using Content.Shared.Roles.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this entity has any of the specified jobs. False if the entity has no mind, none of the specified jobs, or is jobless.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class HasJobEntityConditionSystem : EntityConditionSystem<MindContainerComponent, JobCondition>
+{
+ protected override void Condition(Entity<MindContainerComponent> entity, ref EntityConditionEvent<JobCondition> args)
+ {
+ // We need a mind in our mind container...
+ if (!TryComp<MindComponent>(entity.Comp.Mind, out var mind))
+ return;
+
+ foreach (var roleId in mind.MindRoleContainer.ContainedEntities)
+ {
+ if (!HasComp<JobRoleComponent>(roleId))
+ continue;
+
+ if (!TryComp<MindRoleComponent>(roleId, out var mindRole))
+ {
+ Log.Error($"Encountered job mind role entity {roleId} without a {nameof(MindRoleComponent)}");
+ continue;
+ }
+
+ if (mindRole.JobPrototype == null)
+ {
+ Log.Error($"Encountered job mind role entity {roleId} without a {nameof(JobPrototype)}");
+ continue;
+ }
+
+ if (!args.Condition.Jobs.Contains(mindRole.JobPrototype.Value))
+ continue;
+
+ args.Result = true;
+ return;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class JobCondition : EntityConditionBase<JobCondition>
+{
+ [DataField(required: true)] public List<ProtoId<JobPrototype>> Jobs = [];
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype)
+ {
+ var localizedNames = Jobs.Select(jobId => prototype.Index(jobId).LocalizedName).ToList();
+ return Loc.GetString("reagent-effect-condition-guidebook-job-condition", ("job", ContentLocalizationManager.FormatListToOr(localizedNames)));
+ }
+}
--- /dev/null
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this solution entity has an amount of reagent in it within a specified minimum and maximum.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class ReagentThresholdEntityConditionSystem : EntityConditionSystem<SolutionComponent, ReagentCondition>
+{
+ protected override void Condition(Entity<SolutionComponent> entity, ref EntityConditionEvent<ReagentCondition> args)
+ {
+ var quant = entity.Comp.Solution.GetTotalPrototypeQuantity(args.Condition.Reagent);
+
+ args.Result = quant >= args.Condition.Min && quant <= args.Condition.Max;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class ReagentCondition : EntityConditionBase<ReagentCondition>
+{
+ [DataField]
+ public FixedPoint2 Min = FixedPoint2.Zero;
+
+ [DataField]
+ public FixedPoint2 Max = FixedPoint2.MaxValue;
+
+ [DataField(required: true)]
+ public ProtoId<ReagentPrototype> Reagent;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype)
+ {
+ if (!prototype.Resolve(Reagent, out var reagentProto))
+ return String.Empty;
+
+ return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold",
+ ("reagent", reagentProto.LocalizedName ?? Loc.GetString("reagent-effect-condition-guidebook-this-reagent")),
+ ("max", Max == FixedPoint2.MaxValue ? int.MaxValue : Max.Float()),
+ ("min", Min.Float()));
+ }
+}
--- /dev/null
+using Content.Shared.Localizations;
+using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Tags;
+
+/// <summary>
+/// Returns true if this entity has all the listed tags.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class HasAllTagsEntityConditionSystem : EntityConditionSystem<TagComponent, AllTagsCondition>
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+
+ protected override void Condition(Entity<TagComponent> entity, ref EntityConditionEvent<AllTagsCondition> args)
+ {
+ args.Result = _tag.HasAllTags(entity.Comp, args.Condition.Tags);
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class AllTagsCondition : EntityConditionBase<AllTagsCondition>
+{
+ [DataField(required: true)]
+ public ProtoId<TagPrototype>[] Tags = [];
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype)
+ {
+ var tagList = new List<string>();
+
+ foreach (var type in Tags)
+ {
+ if (!prototype.Resolve(type, out var proto))
+ continue;
+
+ tagList.Add(proto.ID);
+ }
+
+ var names = ContentLocalizationManager.FormatList(tagList);
+
+ return Loc.GetString("reagent-effect-condition-guidebook-has-tag", ("tag", names), ("invert", Inverted));
+ }
+}
--- /dev/null
+using Content.Shared.Localizations;
+using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Tags;
+
+/// <summary>
+/// Returns true if this entity have any of the listed tags.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class HasAnyTagEntityConditionSystem : EntityConditionSystem<TagComponent, AnyTagCondition>
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+
+ protected override void Condition(Entity<TagComponent> entity, ref EntityConditionEvent<AnyTagCondition> args)
+ {
+ args.Result = _tag.HasAnyTag(entity.Comp, args.Condition.Tags);
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class AnyTagCondition : EntityConditionBase<AnyTagCondition>
+{
+ [DataField(required: true)]
+ public ProtoId<TagPrototype>[] Tags = [];
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype)
+ {
+ var tagList = new List<string>();
+
+ foreach (var type in Tags)
+ {
+ if (!prototype.Resolve(type, out var proto))
+ continue;
+
+ tagList.Add(proto.ID);
+ }
+
+ var names = ContentLocalizationManager.FormatListToOr(tagList);
+
+ return Loc.GetString("reagent-effect-condition-guidebook-has-tag", ("tag", names), ("invert", Inverted));
+ }
+}
--- /dev/null
+using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions.Tags;
+
+/// <summary>
+/// Returns true if this entity has the listed tag.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class HasTagEntityConditionSystem : EntityConditionSystem<TagComponent, TagCondition>
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+
+ protected override void Condition(Entity<TagComponent> entity, ref EntityConditionEvent<TagCondition> args)
+ {
+ args.Result = _tag.HasTag(entity.Comp, args.Condition.Tag);
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class TagCondition : EntityConditionBase<TagCondition>
+{
+ [DataField(required: true)]
+ public ProtoId<TagPrototype> Tag;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-has-tag", ("tag", Tag), ("invert", Inverted));
+}
--- /dev/null
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Temperature.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this entity has an amount of reagent in it within a specified minimum and maximum.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class TemperatureEntityConditionSystem : EntityConditionSystem<TemperatureComponent, TemperatureCondition>
+{
+ protected override void Condition(Entity<TemperatureComponent> entity, ref EntityConditionEvent<TemperatureCondition> args)
+ {
+ if (entity.Comp.CurrentTemperature >= args.Condition.Min && entity.Comp.CurrentTemperature <= args.Condition.Max)
+ args.Result = true;
+ }
+}
+
+/// <summary>
+/// Returns true if this solution entity has an amount of reagent in it within a specified minimum and maximum.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class SolutionTemperatureEntityConditionSystem : EntityConditionSystem<SolutionComponent, TemperatureCondition>
+{
+ protected override void Condition(Entity<SolutionComponent> entity, ref EntityConditionEvent<TemperatureCondition> args)
+ {
+ if (entity.Comp.Solution.Temperature >= args.Condition.Min && entity.Comp.Solution.Temperature <= args.Condition.Max)
+ args.Result = true;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class TemperatureCondition : EntityConditionBase<TemperatureCondition>
+{
+ /// <summary>
+ /// Minimum allowed temperature
+ /// </summary>
+ [DataField]
+ public float Min = 0;
+
+ /// <summary>
+ /// Maximum allowed temperature
+ /// </summary>
+ [DataField]
+ public float Max = float.PositiveInfinity;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-body-temperature",
+ ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
+ ("min", Min));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions;
+///<summary>
+/// A basic summary of this condition.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class TemplateEntityConditionSystem : EntityConditionSystem<MetaDataComponent, TemplateCondition>
+{
+ protected override void Condition(Entity<MetaDataComponent> entity, ref EntityConditionEvent<TemplateCondition> args)
+ {
+ // Condition goes here.
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class TemplateCondition : EntityConditionBase<TemplateCondition>
+{
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) => String.Empty;
+}
--- /dev/null
+using Content.Shared.Damage;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions.Conditions;
+
+/// <summary>
+/// Returns true if this entity can take damage and if its total damage is within a specified minimum and maximum.
+/// </summary>
+/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
+public sealed partial class TotalDamageEntityConditionSystem : EntityConditionSystem<DamageableComponent, TotalDamageCondition>
+{
+ protected override void Condition(Entity<DamageableComponent> entity, ref EntityConditionEvent<TotalDamageCondition> args)
+ {
+ var total = entity.Comp.TotalDamage;
+ args.Result = total >= args.Condition.Min && total <= args.Condition.Max;
+ }
+}
+
+/// <inheritdoc cref="EntityCondition"/>
+public sealed partial class TotalDamageCondition : EntityConditionBase<TotalDamageCondition>
+{
+ [DataField]
+ public FixedPoint2 Max = FixedPoint2.MaxValue;
+
+ [DataField]
+ public FixedPoint2 Min = FixedPoint2.Zero;
+
+ public override string EntityConditionGuidebookText(IPrototypeManager prototype) =>
+ Loc.GetString("reagent-effect-condition-guidebook-total-damage",
+ ("max", Max == FixedPoint2.MaxValue ? int.MaxValue : Max.Float()),
+ ("min", Min.Float()));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityConditions;
+
+/// <summary>
+/// This handles entity effects.
+/// Specifically it handles the receiving of events for causing entity effects, and provides
+/// public API for other systems to take advantage of entity effects.
+/// </summary>
+public sealed partial class SharedEntityConditionsSystem : EntitySystem, IEntityConditionRaiser
+{
+ /// <summary>
+ /// Checks a list of conditions to verify that they all return true.
+ /// </summary>
+ /// <param name="target">Target entity we're checking conditions on</param>
+ /// <param name="conditions">Conditions we're checking</param>
+ /// <returns>Returns true if all conditions return true, false if any fail</returns>
+ public bool TryConditions(EntityUid target, EntityCondition[]? conditions)
+ {
+ // If there's no conditions we can't fail any of them...
+ if (conditions == null)
+ return true;
+
+ foreach (var condition in conditions)
+ {
+ if (!TryCondition(target, condition))
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Checks a list of conditions to see if any are true.
+ /// </summary>
+ /// <param name="target">Target entity we're checking conditions on</param>
+ /// <param name="conditions">Conditions we're checking</param>
+ /// <returns>Returns true if any conditions return true</returns>
+ public bool TryAnyCondition(EntityUid target, EntityCondition[]? conditions)
+ {
+ // If there's no conditions we can't meet any of them...
+ if (conditions == null)
+ return false;
+
+ foreach (var condition in conditions)
+ {
+ if (TryCondition(target, condition))
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Checks a single <see cref="EntityCondition"/> on an entity.
+ /// </summary>
+ /// <param name="target">Target entity we're checking conditions on</param>
+ /// <param name="condition">Condition we're checking</param>
+ /// <returns>Returns true if we meet the condition and false otherwise</returns>
+ public bool TryCondition(EntityUid target, EntityCondition condition)
+ {
+ return condition.Inverted != condition.RaiseEvent(target, this);
+ }
+
+ /// <summary>
+ /// Raises a condition to an entity. You should not be calling this unless you know what you're doing.
+ /// </summary>
+ public bool RaiseConditionEvent<T>(EntityUid target, T effect) where T : EntityConditionBase<T>
+ {
+ var effectEv = new EntityConditionEvent<T>(effect);
+ RaiseLocalEvent(target, ref effectEv);
+ return effectEv.Result;
+ }
+}
+
+/// <summary>
+/// This is a basic abstract entity effect containing all the data an entity effect needs to affect entities with effects...
+/// </summary>
+/// <typeparam name="T">The Component that is required for the effect</typeparam>
+/// <typeparam name="TCon">The Condition we're testing</typeparam>
+public abstract partial class EntityConditionSystem<T, TCon> : EntitySystem where T : Component where TCon : EntityConditionBase<TCon>
+{
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<T, EntityConditionEvent<TCon>>(Condition);
+ }
+ protected abstract void Condition(Entity<T> entity, ref EntityConditionEvent<TCon> args);
+}
+
+/// <summary>
+/// Used to raise an EntityCondition without losing the type of condition.
+/// </summary>
+public interface IEntityConditionRaiser
+{
+ bool RaiseConditionEvent<T>(EntityUid target, T effect) where T : EntityConditionBase<T>;
+}
+
+/// <summary>
+/// Used to store an <see cref="EntityCondition"/> so it can be raised without losing the type of the condition.
+/// </summary>
+/// <typeparam name="T">The Condition wer are raising.</typeparam>
+public abstract partial class EntityConditionBase<T> : EntityCondition where T : EntityConditionBase<T>
+{
+ public override bool RaiseEvent(EntityUid target, IEntityConditionRaiser raiser)
+ {
+ if (this is not T type)
+ return false;
+
+ // If the result of the event matches the result we're looking for then we pass.
+ return raiser.RaiseConditionEvent(target, type);
+ }
+}
+
+/// <summary>
+/// A basic condition which can be checked for on an entity via events.
+/// </summary>
+[ImplicitDataDefinitionForInheritors]
+public abstract partial class EntityCondition
+{
+ public abstract bool RaiseEvent(EntityUid target, IEntityConditionRaiser raiser);
+
+ /// <summary>
+ /// If true, invert the result. So false returns true and true returns false!
+ /// </summary>
+ [DataField]
+ public bool Inverted;
+
+ /// <summary>
+ /// A basic description of this condition, which displays in the guidebook.
+ /// </summary>
+ public abstract string EntityConditionGuidebookText(IPrototypeManager prototype);
+}
+
+/// <summary>
+/// An Event carrying an entity effect.
+/// </summary>
+/// <param name="Condition">The Condition we're checking</param>
+[ByRefEvent]
+public record struct EntityConditionEvent<T>(T Condition) where T : EntityConditionBase<T>
+{
+ /// <summary>
+ /// The result of our check, defaults to false if nothing handles it.
+ /// </summary>
+ [DataField]
+ public bool Result;
+
+ /// <summary>
+ /// The Condition being raised in this event
+ /// </summary>
+ public readonly T Condition = Condition;
+}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Requires the target entity to be above or below a certain temperature.
-/// Used for things like cryoxadone and pyroxadone.
-/// </summary>
-public sealed partial class Temperature : EventEntityEffectCondition<Temperature>
-{
- [DataField]
- public float Min = 0;
-
- [DataField]
- public float Max = float.PositiveInfinity;
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-body-temperature",
- ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
- ("min", Min));
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Condition for if the entity is successfully breathing.
-/// </summary>
-public sealed partial class Breathing : EventEntityEffectCondition<Breathing>
-{
- /// <summary>
- /// If true, the entity must not have trouble breathing to pass.
- /// </summary>
- [DataField]
- public bool IsBreathing = true;
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-breathing",
- ("isBreathing", IsBreathing));
- }
-}
+++ /dev/null
-using Content.Shared.Tag;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-public sealed partial class HasTag : EntityEffectCondition
-{
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
- public string Tag = default!;
-
- [DataField]
- public bool Invert = false;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args.EntityManager.TryGetComponent<TagComponent>(args.TargetEntity, out var tag))
- return args.EntityManager.System<TagSystem>().HasTag(tag, Tag) ^ Invert;
-
- return false;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- // this should somehow be made (much) nicer.
- return Loc.GetString("reagent-effect-condition-guidebook-has-tag", ("tag", Tag), ("invert", Invert));
- }
-}
+++ /dev/null
-using Content.Shared.Body.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Condition for if the entity is or isn't wearing internals.
-/// </summary>
-public sealed partial class Internals : EntityEffectCondition
-{
- /// <summary>
- /// To pass, the entity's internals must have this same state.
- /// </summary>
- [DataField]
- public bool UsingInternals = true;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (!args.EntityManager.TryGetComponent(args.TargetEntity, out InternalsComponent? internalsComp))
- return !UsingInternals; // They have no internals to wear.
-
- var internalsState = internalsComp.GasTankEntity != null; // If gas tank is not null, they are wearing internals
- return UsingInternals == internalsState;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-internals", ("usingInternals", UsingInternals));
- }
-}
+++ /dev/null
-using System.Linq;
-using Content.Shared.Localizations;
-using Content.Shared.Mind;
-using Content.Shared.Mind.Components;
-using Content.Shared.Roles;
-using Content.Shared.Roles.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-public sealed partial class JobCondition : EntityEffectCondition
-{
- [DataField(required: true)] public List<ProtoId<JobPrototype>> Job;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- args.EntityManager.TryGetComponent<MindContainerComponent>(args.TargetEntity, out var mindContainer);
-
- if (mindContainer is null
- || !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind))
- return false;
-
- foreach (var roleId in mind.MindRoleContainer.ContainedEntities)
- {
- if (!args.EntityManager.HasComponent<JobRoleComponent>(roleId))
- continue;
-
- if (!args.EntityManager.TryGetComponent<MindRoleComponent>(roleId, out var mindRole))
- {
- Logger.Error($"Encountered job mind role entity {roleId} without a {nameof(MindRoleComponent)}");
- continue;
- }
-
- if (mindRole.JobPrototype == null)
- {
- Logger.Error($"Encountered job mind role entity {roleId} without a {nameof(JobPrototype)}");
- continue;
- }
-
- if (Job.Contains(mindRole.JobPrototype.Value))
- return true;
- }
-
- return false;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- var localizedNames = Job.Select(jobId => prototype.Index(jobId).LocalizedName).ToList();
- return Loc.GetString("reagent-effect-condition-guidebook-job-condition", ("job", ContentLocalizationManager.FormatListToOr(localizedNames)));
- }
-}
+++ /dev/null
-using Content.Shared.Mobs;
-using Content.Shared.Mobs.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-public sealed partial class MobStateCondition : EntityEffectCondition
-{
- [DataField]
- public MobState Mobstate = MobState.Alive;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args.EntityManager.TryGetComponent(args.TargetEntity, out MobStateComponent? mobState))
- {
- if (mobState.CurrentState == Mobstate)
- return true;
- }
-
- return false;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate));
- }
-}
-
+++ /dev/null
-// using Content.Server.Body.Components;
-using Content.Shared.Body.Prototypes;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Requires that the metabolizing organ is or is not tagged with a certain MetabolizerType
-/// </summary>
-public sealed partial class OrganType : EventEntityEffectCondition<OrganType>
-{
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
- public string Type = default!;
-
- /// <summary>
- /// Does this condition pass when the organ has the type, or when it doesn't have the type?
- /// </summary>
- [DataField]
- public bool ShouldHave = true;
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
- ("name", prototype.Index<MetabolizerTypePrototype>(Type).LocalizedName),
- ("shouldhave", ShouldHave));
- }
-}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Used for implementing reagent effects that require a certain amount of reagent before it should be applied.
-/// For instance, overdoses.
-///
-/// This can also trigger on -other- reagents, not just the one metabolizing. By default, it uses the
-/// one being metabolized.
-/// </summary>
-public sealed partial class ReagentThreshold : EntityEffectCondition
-{
- [DataField]
- public FixedPoint2 Min = FixedPoint2.Zero;
-
- [DataField]
- public FixedPoint2 Max = FixedPoint2.MaxValue;
-
- // TODO use ReagentId
- [DataField]
- public string? Reagent;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- var reagent = Reagent ?? reagentArgs.Reagent?.ID;
- if (reagent == null)
- return true; // No condition to apply.
-
- var quant = FixedPoint2.Zero;
- if (reagentArgs.Source != null)
- quant = reagentArgs.Source.GetTotalPrototypeQuantity(reagent);
-
- return quant >= Min && quant <= Max;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- ReagentPrototype? reagentProto = null;
- if (Reagent is not null)
- prototype.TryIndex(Reagent, out reagentProto);
-
- return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold",
- ("reagent", reagentProto?.LocalizedName ?? Loc.GetString("reagent-effect-condition-guidebook-this-reagent")),
- ("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
- ("min", Min.Float()));
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-/// <summary>
-/// Requires the solution to be above or below a certain temperature.
-/// Used for things like explosives.
-/// </summary>
-public sealed partial class SolutionTemperature : EntityEffectCondition
-{
- [DataField]
- public float Min = 0.0f;
-
- [DataField]
- public float Max = float.PositiveInfinity;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- return reagentArgs?.Source != null &&
- reagentArgs.Source.Temperature >= Min &&
- reagentArgs.Source.Temperature <= Max;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-solution-temperature",
- ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
- ("min", Min));
- }
-}
+++ /dev/null
-using Content.Shared.EntityEffects;
-using Content.Shared.Damage;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-public sealed partial class TotalDamage : EntityEffectCondition
-{
- [DataField]
- public FixedPoint2 Max = FixedPoint2.MaxValue;
-
- [DataField]
- public FixedPoint2 Min = FixedPoint2.Zero;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args.EntityManager.TryGetComponent(args.TargetEntity, out DamageableComponent? damage))
- {
- var total = damage.TotalDamage;
- return total >= Min && total <= Max;
- }
-
- return false;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-total-damage",
- ("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
- ("min", Min.Float()));
- }
-}
+++ /dev/null
-using Content.Shared.EntityEffects;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.EffectConditions;
-
-public sealed partial class Hunger : EntityEffectCondition
-{
- [DataField]
- public float Max = float.PositiveInfinity;
-
- [DataField]
- public float Min = 0;
-
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
- {
- var total = args.EntityManager.System<HungerSystem>().GetHunger(hunger);
- return total >= Min && total <= Max;
- }
-
- return false;
- }
-
- public override string GuidebookExplanation(IPrototypeManager prototype)
- {
- return Loc.GetString("reagent-effect-condition-guidebook-total-hunger",
- ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
- ("min", Min));
- }
-}
+++ /dev/null
-using Content.Shared.Chemistry.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects
-{
- public sealed partial class AddToSolutionReaction : EntityEffect
- {
- [DataField("solution")]
- private string _solution = "reagents";
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs) {
- if (reagentArgs.Reagent == null)
- return;
-
- // TODO see if this is correct
- var solutionContainerSystem = reagentArgs.EntityManager.System<SharedSolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution(reagentArgs.TargetEntity, _solution, out var solutionContainer))
- return;
-
- if (solutionContainerSystem.TryAddReagent(solutionContainer.Value, reagentArgs.Reagent.ID, reagentArgs.Quantity, out var accepted))
- reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, accepted);
-
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
- Loc.GetString("reagent-effect-guidebook-add-to-solution-reaction", ("chance", Probability));
- }
-}
+++ /dev/null
-using Content.Shared.Alert;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Timing;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class AdjustAlert : EntityEffect
-{
- /// <summary>
- /// The specific Alert that will be adjusted
- /// </summary>
- [DataField(required: true)]
- public ProtoId<AlertPrototype> AlertType;
-
- /// <summary>
- /// If true, the alert is removed after Time seconds. If Time was not specified the alert is removed immediately.
- /// </summary>
- [DataField]
- public bool Clear;
-
- /// <summary>
- /// Visually display cooldown progress over the alert icon.
- /// </summary>
- [DataField]
- public bool ShowCooldown;
-
- /// <summary>
- /// The length of the cooldown or delay before removing the alert (in seconds).
- /// </summary>
- [DataField]
- public float Time;
-
- //JUSTIFICATION: This just changes some visuals, doesn't need to be documented.
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var alertSys = args.EntityManager.EntitySysManager.GetEntitySystem<AlertsSystem>();
- if (!args.EntityManager.HasComponent<AlertsComponent>(args.TargetEntity))
- return;
-
- if (Clear && Time <= 0)
- {
- alertSys.ClearAlert(args.TargetEntity, AlertType);
- }
- else
- {
- var timing = IoCManager.Resolve<IGameTiming>();
- (TimeSpan, TimeSpan)? cooldown = null;
-
- if ((ShowCooldown || Clear) && Time > 0)
- cooldown = (timing.CurTime, timing.CurTime + TimeSpan.FromSeconds(Time));
-
- alertSys.ShowAlert(args.TargetEntity, AlertType, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown);
- }
-
- }
-}
--- /dev/null
+using Content.Shared.Alert;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Adjusts a given alert on this entity.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class AdjustAlertEntityEffectSysten : EntityEffectSystem<AlertsComponent, AdjustAlert>
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly AlertsSystem _alerts = default!;
+
+ protected override void Effect(Entity<AlertsComponent> entity, ref EntityEffectEvent<AdjustAlert> args)
+ {
+ var time = args.Effect.Time;
+ var clear = args.Effect.Clear;
+ var type = args.Effect.AlertType;
+
+ if (clear && time <= TimeSpan.Zero)
+ {
+ _alerts.ClearAlert(entity.AsNullable(), type);
+ }
+ else
+ {
+ (TimeSpan, TimeSpan)? cooldown = null;
+
+ if ((args.Effect.ShowCooldown || clear) && args.Effect.Time >= TimeSpan.Zero)
+ cooldown = (_timing.CurTime, _timing.CurTime + time);
+
+ _alerts.ShowAlert(entity.AsNullable(), type, cooldown: cooldown, autoRemove: clear, showCooldown: args.Effect.ShowCooldown);
+ }
+
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustAlert : EntityEffectBase<AdjustAlert>
+{
+ /// <summary>
+ /// The specific Alert that will be adjusted
+ /// </summary>
+ [DataField(required: true)]
+ public ProtoId<AlertPrototype> AlertType;
+
+ /// <summary>
+ /// If true, the alert is removed after Time seconds. If Time was not specified the alert is removed immediately.
+ /// </summary>
+ [DataField]
+ public bool Clear;
+
+ /// <summary>
+ /// Visually display cooldown progress over the alert icon.
+ /// </summary>
+ [DataField]
+ public bool ShowCooldown;
+
+ /// <summary>
+ /// The length of the cooldown or delay before removing the alert (in seconds).
+ /// </summary>
+ [DataField]
+ public TimeSpan Time;
+}
+++ /dev/null
-using Content.Shared.Body.Prototypes;
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.Effects
-{
- public sealed partial class AdjustReagent : EntityEffect
- {
- /// <summary>
- /// The reagent ID to remove. Only one of this and <see cref="Group"/> should be active.
- /// </summary>
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
- public string? Reagent = null;
- // TODO use ReagentId
-
- /// <summary>
- /// The metabolism group to remove, if the reagent satisfies any.
- /// Only one of this and <see cref="Reagent"/> should be active.
- /// </summary>
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<MetabolismGroupPrototype>))]
- public string? Group = null;
-
- [DataField(required: true)]
- public FixedPoint2 Amount = default!;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.Source == null)
- return;
-
- var amount = Amount;
- amount *= reagentArgs.Scale;
-
- if (Reagent != null)
- {
- if (amount < 0 && reagentArgs.Source.ContainsPrototype(Reagent))
- reagentArgs.Source.RemoveReagent(Reagent, -amount);
- if (amount > 0)
- reagentArgs.Source.AddReagent(Reagent, amount);
- }
- else if (Group != null)
- {
- var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
- foreach (var quant in reagentArgs.Source.Contents.ToArray())
- {
- var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
- if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
- {
- if (amount < 0)
- reagentArgs.Source.RemoveReagent(quant.Reagent, amount);
- if (amount > 0)
- reagentArgs.Source.AddReagent(quant.Reagent, amount);
- }
- }
- }
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- if (Reagent is not null && prototype.TryIndex(Reagent, out ReagentPrototype? reagentProto))
- {
- return Loc.GetString("reagent-effect-guidebook-adjust-reagent-reagent",
- ("chance", Probability),
- ("deltasign", MathF.Sign(Amount.Float())),
- ("reagent", reagentProto.LocalizedName),
- ("amount", MathF.Abs(Amount.Float())));
- }
- else if (Group is not null && prototype.TryIndex(Group, out MetabolismGroupPrototype? groupProto))
- {
- return Loc.GetString("reagent-effect-guidebook-adjust-reagent-group",
- ("chance", Probability),
- ("deltasign", MathF.Sign(Amount.Float())),
- ("group", groupProto.LocalizedName),
- ("amount", MathF.Abs(Amount.Float())));
- }
-
- throw new NotImplementedException();
- }
- }
-}
-
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class AdjustTemperature : EventEntityEffect<AdjustTemperature>
-{
- [DataField]
- public float Amount;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-adjust-temperature",
- ("chance", Probability),
- ("deltasign", MathF.Sign(Amount)),
- ("amount", MathF.Abs(Amount)));
-}
--- /dev/null
+using Content.Shared.Temperature.Components;
+using Content.Shared.Temperature.Systems;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+// TODO: When we get a proper temperature/energy struct combine this with the solution temperature effect!!!
+/// <summary>
+/// Adjusts the temperature of this entity.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class AdjustTemperatureEntityEffectSystem : EntityEffectSystem<TemperatureComponent, AdjustTemperature>
+{
+ [Dependency] private readonly SharedTemperatureSystem _temperature = default!;
+ protected override void Effect(Entity<TemperatureComponent> entity, ref EntityEffectEvent<AdjustTemperature> args)
+ {
+ var amount = args.Effect.Amount * args.Scale;
+
+ _temperature.ChangeHeat(entity, amount, true, entity.Comp);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustTemperature : EntityEffectBase<AdjustTemperature>
+{
+ /// <summary>
+ /// Amount we're adjusting temperature by.
+ /// </summary>
+ [DataField]
+ public float Amount;
+}
+++ /dev/null
-using Content.Shared.Database;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Audio;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Basically smoke and foam reactions.
-/// </summary>
-public sealed partial class AreaReactionEffect : EventEntityEffect<AreaReactionEffect>
-{
- /// <summary>
- /// How many seconds will the effect stay, counting after fully spreading.
- /// </summary>
- [DataField("duration")] public float Duration = 10;
-
- /// <summary>
- /// How many units of reaction for 1 smoke entity.
- /// </summary>
- [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
-
- /// <summary>
- /// The entity prototype that will be spawned as the effect.
- /// </summary>
- [DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
- public string PrototypeId = default!;
-
- /// <summary>
- /// Sound that will get played when this reaction effect occurs.
- /// </summary>
- [DataField("sound", required: true)] public SoundSpecifier Sound = default!;
-
- public override bool ShouldLog => true;
-
- protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-area-reaction",
- ("duration", Duration)
- );
-
- public override LogImpact LogImpact => LogImpact.High;
-}
+++ /dev/null
-using Content.Shared.Xenoarchaeology.Artifact.Components;
-using Content.Shared.Xenoarchaeology.Artifact;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Restores durability in active artefact nodes.
-/// </summary>
-public sealed partial class ArtifactDurabilityRestore : EntityEffect
-{
- /// <summary>
- /// Amount of durability that will be restored per effect interaction.
- /// </summary>
- [DataField]
- public int RestoredDurability = 1;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var entMan = args.EntityManager;
- var xenoArtifactSys = entMan.System<SharedXenoArtifactSystem>();
-
- if (!entMan.TryGetComponent<XenoArtifactComponent>(args.TargetEntity, out var xenoArtifact))
- return;
-
- foreach (var node in xenoArtifactSys.GetActiveNodes((args.TargetEntity, xenoArtifact)))
- {
- xenoArtifactSys.AdjustNodeDurability(node.Owner, RestoredDurability);
- }
- }
-
- protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return Loc.GetString("reagent-effect-guidebook-artifact-durability-restore", ("restored", RestoredDurability));
- }
-}
--- /dev/null
+using Content.Shared.Popups;
+using Content.Shared.Xenoarchaeology.Artifact;
+using Content.Shared.Xenoarchaeology.Artifact.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Restores durability on this artifact
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ArtifactDurabilityRestoreEntityEffectsSystem : EntityEffectSystem<XenoArtifactComponent, ArtifactDurabilityRestore>
+{
+ [Dependency] private readonly SharedXenoArtifactSystem _xenoArtifact = default!;
+
+ protected override void Effect(Entity<XenoArtifactComponent> entity, ref EntityEffectEvent<ArtifactDurabilityRestore> args)
+ {
+ var durability = args.Effect.RestoredDurability;
+
+ foreach (var node in _xenoArtifact.GetActiveNodes(entity))
+ {
+ _xenoArtifact.AdjustNodeDurability(node.Owner, durability);
+ }
+ }
+}
+
+/// <summary>
+/// Unlocks a node on this artifact. Only works this effect hasn't been applied before.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ArtifactUnlockEntityEffectSystem : EntityEffectSystem<XenoArtifactComponent, ArtifactUnlock>
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedXenoArtifactSystem _xenoArtifact = default!;
+
+ protected override void Effect(Entity<XenoArtifactComponent> entity, ref EntityEffectEvent<ArtifactUnlock> args)
+ {
+ if (EnsureComp<XenoArtifactUnlockingComponent>(entity, out var unlocking))
+ {
+ if (unlocking.ArtifexiumApplied)
+ return;
+
+ _popup.PopupEntity(Loc.GetString("artifact-activation-artifexium"), entity, PopupType.Medium);
+ }
+ else
+ {
+ _xenoArtifact.TriggerXenoArtifact(entity, null, force: true);
+ }
+
+ _xenoArtifact.SetArtifexiumApplied((entity, unlocking), true);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ArtifactDurabilityRestore : EntityEffectBase<ArtifactDurabilityRestore>
+{
+ /// <summary>
+ /// Amount of durability that will be restored per effect interaction.
+ /// </summary>
+ [DataField]
+ public int RestoredDurability = 1;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-artifact-durability-restore", ("restored", RestoredDurability));
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ArtifactUnlock : EntityEffectBase<ArtifactUnlock>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-artifact-unlock", ("chance", Probability));
+}
+++ /dev/null
-using Content.Shared.Xenoarchaeology.Artifact;
-using Content.Shared.EntityEffects;
-using Content.Shared.Popups;
-using Content.Shared.Xenoarchaeology.Artifact.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Sets an artifact into the unlocking state and marks the artifexium effect as true.
-/// This is a very specific behavior intended for a specific chem.
-/// </summary>
-public sealed partial class ArtifactUnlock : EntityEffect
-{
- public override void Effect(EntityEffectBaseArgs args)
- {
- var entMan = args.EntityManager;
- var xenoArtifactSys = entMan.System<SharedXenoArtifactSystem>();
- var popupSys = entMan.System<SharedPopupSystem>();
-
- if (!entMan.TryGetComponent<XenoArtifactComponent>(args.TargetEntity, out var xenoArtifact))
- return;
-
- if (!entMan.TryGetComponent<XenoArtifactUnlockingComponent>(args.TargetEntity, out var unlocking))
- {
- xenoArtifactSys.TriggerXenoArtifact((args.TargetEntity, xenoArtifact), null, force: true);
- unlocking = entMan.EnsureComponent<XenoArtifactUnlockingComponent>(args.TargetEntity);
- }
- else if (!unlocking.ArtifexiumApplied)
- {
- popupSys.PopupEntity(Loc.GetString("artifact-activation-artifexium"), args.TargetEntity, PopupType.Medium);
- }
-
- if (unlocking.ArtifexiumApplied)
- return;
-
- xenoArtifactSys.SetArtifexiumApplied((args.TargetEntity, unlocking), true);
- }
-
- protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return Loc.GetString("reagent-effect-guidebook-artifact-unlock", ("chance", Probability));
- }
-}
--- /dev/null
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class CreateGas : EntityEffectBase<CreateGas>
+{
+ /// <summary>
+ /// The gas we're creating
+ /// </summary>
+ [DataField]
+ public Gas Gas;
+
+ /// <summary>
+ /// Amount of moles we're creating
+ /// </summary>
+ [DataField]
+ public float Moles = 3f;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ var atmos = entSys.GetEntitySystem<SharedAtmosphereSystem>();
+ var gasProto = atmos.GetGas(Gas);
+
+ return Loc.GetString("entity-effect-guidebook-create-gas",
+ ("chance", Probability),
+ ("moles", Moles),
+ ("gas", gasProto.Name));
+ }
+}
--- /dev/null
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// This raises an extinguish event on a given entity, reducing FireStacks.
+/// The amount of FireStacks reduced is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ExtinguishEntityEffectSystem : EntityEffectSystem<FlammableComponent, Extinguish>
+{
+ protected override void Effect(Entity<FlammableComponent> entity, ref EntityEffectEvent<Extinguish> args)
+ {
+ var ev = new ExtinguishEvent
+ {
+ FireStacksAdjustment = args.Effect.FireStacksAdjustment * args.Scale,
+ };
+
+ RaiseLocalEvent(entity, ref ev);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Extinguish : EntityEffectBase<Extinguish>
+{
+ /// <summary>
+ /// Amount of FireStacks reduced.
+ /// </summary>
+ [DataField]
+ public float FireStacksAdjustment = -1.5f;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-extinguish-reaction", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Flammable : EntityEffectBase<Flammable>
+{
+ /// <summary>
+ /// Fire stack multiplier applied on an entity,
+ /// unless that entity is already on fire and <see cref="MultiplierOnExisting"/> is not null.
+ /// </summary>
+ [DataField]
+ public float Multiplier = 0.05f;
+
+ /// <summary>
+ /// Fire stack multiplier applied if the entity is already on fire. Defaults to <see cref="Multiplier"/> if null.
+ /// </summary>
+ [DataField]
+ public float? MultiplierOnExisting;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-flammable-reaction", ("chance", Probability));
+
+ public override bool ShouldLog => true;
+}
--- /dev/null
+using Content.Shared.Database;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Atmos;
+
+/// <summary>
+/// See serverside system
+/// </summary>
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Ignite : EntityEffectBase<Ignite>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-ignite", ("chance", Probability));
+
+ public override bool ShouldLog => true;
+
+ public override LogImpact LogImpact => LogImpact.Medium;
+}
--- /dev/null
+using Content.Shared.Body.Components;
+using Content.Shared.Body.Systems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Removes a given amount of chemicals from the bloodstream modified by scale.
+/// Optionally ignores a given chemical.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class CleanBloodstreamEntityEffectSystem : EntityEffectSystem<BloodstreamComponent, CleanBloodstream>
+{
+ [Dependency] private readonly SharedBloodstreamSystem _bloodstream = default!;
+
+ protected override void Effect(Entity<BloodstreamComponent> entity, ref EntityEffectEvent<CleanBloodstream> args)
+ {
+ var scale = args.Scale * args.Effect.CleanseRate;
+
+ _bloodstream.FlushChemicals((entity, entity), args.Effect.Excluded, scale);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class CleanBloodstream : EntityEffectBase<CleanBloodstream>
+{
+ /// <summary>
+ /// Amount of reagent we're cleaning out of our bloodstream.
+ /// </summary>
+ [DataField]
+ public FixedPoint2 CleanseRate = 3.0f;
+
+ /// <summary>
+ /// An optional chemical to ignore when doing removal.
+ /// </summary>
+ [DataField]
+ public ProtoId<ReagentPrototype>? Excluded;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-clean-bloodstream", ("chance", Probability));
+}
--- /dev/null
+using Content.Shared.Eye.Blinding.Systems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Modifies eye damage by a given amount, modified by scale, floored to an integer.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class EyeDamageEntityEffectSystem : EntityEffectSystem<MetaDataComponent, EyeDamage>
+{
+ [Dependency] private readonly BlindableSystem _blindable = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<EyeDamage> args)
+ {
+ var amount = (int) Math.Floor(args.Effect.Amount * args.Scale);
+ _blindable.AdjustEyeDamage(entity.Owner, amount);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class EyeDamage : EntityEffectBase<EyeDamage>
+{
+ /// <summary>
+ /// The amount of eye damage we're adding or removing
+ /// </summary>
+ [DataField]
+ public int Amount = -1;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-eye-damage", ("chance", Probability), ("deltasign", MathF.Sign(Amount)));
+}
--- /dev/null
+using Content.Shared.Body.Components;
+using Content.Shared.Body.Systems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Modifies bleed by a given amount multiplied by scale. This can increase or decrease bleed.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyBleedEntityEffectSystem : EntityEffectSystem<BloodstreamComponent, ModifyBleed>
+{
+ [Dependency] private readonly SharedBloodstreamSystem _bloodstream = default!;
+
+ protected override void Effect(Entity<BloodstreamComponent> entity, ref EntityEffectEvent<ModifyBleed> args)
+ {
+ _bloodstream.TryModifyBleedAmount(entity.AsNullable(), args.Effect.Amount * args.Scale);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyBleed : EntityEffectBase<ModifyBleed>
+{
+ /// <summary>
+ /// Amount of bleed we're applying or removing if negative.
+ /// </summary>
+ [DataField]
+ public float Amount = -1.0f;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-modify-bleed-amount", ("chance", Probability), ("deltasign", MathF.Sign(Amount)));
+}
--- /dev/null
+using Content.Shared.Body.Components;
+using Content.Shared.Body.Systems;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Modifies the amount of blood in this entity's bloodstream by a given amount multiplied by scale.
+/// This effect can increase or decrease blood level.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyBloodLevelEntityEffectSystem : EntityEffectSystem<BloodstreamComponent, ModifyBloodLevel>
+{
+ [Dependency] private readonly SharedBloodstreamSystem _bloodstream = default!;
+
+ protected override void Effect(Entity<BloodstreamComponent> entity, ref EntityEffectEvent<ModifyBloodLevel> args)
+ {
+ _bloodstream.TryModifyBloodLevel(entity.AsNullable(), args.Effect.Amount * args.Scale);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyBloodLevel : EntityEffectBase<ModifyBloodLevel>
+{
+ /// <summary>
+ /// Amount of bleed we're applying or removing if negative.
+ /// </summary>
+ [DataField]
+ public FixedPoint2 Amount = 1.0f;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-modify-blood-level", ("chance", Probability), ("deltasign", MathF.Sign(Amount.Float())));
+}
--- /dev/null
+using Content.Shared.Atmos;
+using Content.Shared.Body.Components;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Adjust the amount of Moles stored in this set of lungs based on a given dictionary of gasses and ratios.
+/// The amount of gas adjusted is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyLungGasEntityEffectSystem : EntityEffectSystem<LungComponent, ModifyLungGas>
+{
+ // TODO: This shouldn't be an entity effect, gasses should just metabolize and make a byproduct by default...
+ protected override void Effect(Entity<LungComponent> entity, ref EntityEffectEvent<ModifyLungGas> args)
+ {
+ var amount = args.Scale;
+
+ foreach (var (gas, ratio) in args.Effect.Ratios)
+ {
+ var quantity = ratio * amount / Atmospherics.BreathMolesToReagentMultiplier;
+ if (quantity < 0)
+ quantity = Math.Max(quantity, -entity.Comp.Air[(int) gas]);
+ entity.Comp.Air.AdjustMoles(gas, quantity);
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyLungGas : EntityEffectBase<ModifyLungGas>
+{
+ [DataField(required: true)]
+ public Dictionary<Gas, float> Ratios = default!;
+}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Oxygenate : EntityEffectBase<Oxygenate>
+{
+ /// <summary>
+ /// Factor of oxygenation per metabolized quantity. Lungs metabolize at about 50u per tick so we need an equal multiplier to cancel that out!
+ /// </summary>
+ [DataField]
+ public float Factor = 1f;
+}
--- /dev/null
+using Content.Shared.Atmos.Rotting;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Reduces the rotting timer on an entity by a number of seconds, modified by scale.
+/// This cannot increase the amount of seconds a body has rotted.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ReduceRottingEntityEffectSystem : EntityEffectSystem<PerishableComponent, ReduceRotting>
+{
+ [Dependency] private readonly SharedRottingSystem _rotting = default!;
+
+ protected override void Effect(Entity<PerishableComponent> entity, ref EntityEffectEvent<ReduceRotting> args)
+ {
+ var amount = args.Effect.Seconds * args.Scale;
+
+ _rotting.ReduceAccumulator(entity, amount);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ReduceRotting : EntityEffectBase<ReduceRotting>
+{
+ /// <summary>
+ /// Number of seconds removed from the rotting timer.
+ /// </summary>
+ [DataField]
+ public TimeSpan Seconds = TimeSpan.FromSeconds(10);
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-reduce-rotting",
+ ("chance", Probability),
+ ("time", Seconds.TotalSeconds));
+}
--- /dev/null
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+// TODO: These systems are in the same file since satiation should be one system instead of two. Combine these when that happens.
+// TODO: Arguably oxygen saturation should also be added here...
+/// <summary>
+/// Modifies the thirst level of a given entity, multiplied by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SatiateThirstEntityEffectsSystem : EntityEffectSystem<ThirstComponent, SatiateThirst>
+{
+ [Dependency] private readonly ThirstSystem _thirst = default!;
+ protected override void Effect(Entity<ThirstComponent> entity, ref EntityEffectEvent<SatiateThirst> args)
+ {
+ _thirst.ModifyThirst(entity, entity.Comp, args.Effect.Factor * args.Scale);
+ }
+}
+
+/// <summary>
+/// Modifies the hunger level of a given entity, multiplied by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SatiateHungerEntityEffectsSystem : EntityEffectSystem<HungerComponent, SatiateHunger>
+{
+ [Dependency] private readonly HungerSystem _hunger = default!;
+ protected override void Effect(Entity<HungerComponent> entity, ref EntityEffectEvent<SatiateHunger> args)
+ {
+ _hunger.ModifyHunger(entity, args.Effect.Factor * args.Scale, entity.Comp);
+ }
+}
+
+/// <summary>
+/// A type of <see cref="EntityEffectBase{T}"/> made for satiation effects.
+/// </summary>
+/// <typeparam name="T">The effect inheriting this BaseEffect</typeparam>
+/// <inheritdoc cref="EntityEffect"/>
+public abstract partial class Satiate<T> : EntityEffectBase<T> where T : EntityEffectBase<T>
+{
+ public const float AverageSatiation = 3f; // Magic number. Not sure how it was calculated since I didn't make it.
+
+ /// <summary>
+ /// Change in satiation.
+ /// </summary>
+ [DataField]
+ public float Factor = -1.5f;
+}
+
+/// <inheritdoc cref="Satiate{T}"/>
+public sealed partial class SatiateThirst : Satiate<SatiateThirst>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-satiate-thirst", ("chance", Probability), ("relative", Factor / AverageSatiation));
+}
+
+/// <inheritdoc cref="Satiate{T}"/>
+public sealed partial class SatiateHunger : Satiate<SatiateHunger>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-satiate-hunger", ("chance", Probability), ("relative", Factor / AverageSatiation));
+}
--- /dev/null
+using Content.Shared.Medical;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Body;
+
+/// <summary>
+/// Makes an entity vomit and reduces hunger and thirst by a given amount, modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class VomitEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Vomit>
+{
+ [Dependency] private readonly VomitSystem _vomit = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Vomit> args)
+ {
+ _vomit.Vomit(entity.Owner, args.Effect.ThirstAmount * args.Scale, args.Effect.HungerAmount * args.Scale);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Vomit : EntityEffectBase<Vomit>
+{
+ /// <summary>
+ /// How much we adjust our thirst after vomiting.
+ /// </summary>
+ [DataField]
+ public float ThirstAmount = -8f;
+
+ /// <summary>
+ /// How much we adjust our hunger after vomiting.
+ /// </summary>
+ [DataField]
+ public float HungerAmount = -8f;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-vomit", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// A type of <see cref="EntityEffectBase{T}"/> which modifies the attribute of a Seed in a PlantHolder.
+/// These are not modified by scale as botany has no concept of scale.
+/// </summary>
+/// <typeparam name="T">The effect inheriting this BaseEffect</typeparam>
+/// <inheritdoc cref="EntityEffect"/>
+public abstract partial class BasePlantAdjustAttribute<T> : EntityEffectBase<T> where T : BasePlantAdjustAttribute<T>
+{
+ /// <summary>
+ /// How much we're adjusting the given attribute by.
+ /// </summary>
+ [DataField]
+ public float Amount { get; protected set; } = 1;
+
+ /// <summary>
+ /// Localisation key for the name of the adjusted attribute. Used for guidebook descriptions.
+ /// </summary>
+ [DataField]
+ public abstract string GuidebookAttributeName { get; set; }
+
+ /// <summary>
+ /// Whether the attribute in question is a good thing. Used for guidebook descriptions to determine the color of the number.
+ /// </summary>
+ [DataField]
+ public virtual bool GuidebookIsAttributePositive { get; protected set; } = true;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-attribute",
+ ("attribute", Loc.GetString(GuidebookAttributeName)),
+ ("amount", Amount.ToString("0.00")),
+ ("positive", GuidebookIsAttributePositive),
+ ("chance", Probability));
+}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustHealth : BasePlantAdjustAttribute<PlantAdjustHealth>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
+}
+
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustMutationLevel : BasePlantAdjustAttribute<PlantAdjustMutationLevel>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
+}
+
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustMutationMod : BasePlantAdjustAttribute<PlantAdjustMutationMod>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
+}
+
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustNutrition : BasePlantAdjustAttribute<PlantAdjustNutrition>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
+}
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
-public sealed partial class PlantAdjustPests : PlantAdjustAttribute<PlantAdjustPests>
+public sealed partial class PlantAdjustPests : BasePlantAdjustAttribute<PlantAdjustPests>
{
public override string GuidebookAttributeName { get; set; } = "plant-attribute-pests";
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// Handles increase or decrease of plant potency.
+/// </summary>
+public sealed partial class PlantAdjustPotency : BasePlantAdjustAttribute<PlantAdjustPotency>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-potency";
+}
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
-public sealed partial class PlantAdjustToxins : PlantAdjustAttribute<PlantAdjustToxins>
+public sealed partial class PlantAdjustToxins : BasePlantAdjustAttribute<PlantAdjustToxins>
{
public override string GuidebookAttributeName { get; set; } = "plant-attribute-toxins";
+
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAdjustWater : BasePlantAdjustAttribute<PlantAdjustWater>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
+}
+
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
-public sealed partial class PlantAdjustWeeds : PlantAdjustAttribute<PlantAdjustWeeds>
+public sealed partial class PlantAdjustWeeds : BasePlantAdjustAttribute<PlantAdjustWeeds>
{
public override string GuidebookAttributeName { get; set; } = "plant-attribute-weeds";
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantAffectGrowth : BasePlantAdjustAttribute<PlantAffectGrowth>
+{
+ public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
+}
+
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantChangeStat : EntityEffectBase<PlantChangeStat>
+{
+ /// <remarks>
+ /// This is the worst thing in the code base.
+ /// It's meant to be generic and expandable I guess? But it's looking for a specific datafield and then
+ /// sending it into an if else if else if statement that filters by object type and randomly flips bits.
+ /// </remarks>
+ [DataField (required: true)]
+ public string TargetValue = string.Empty;
+
+ [DataField]
+ public float MinValue;
+
+ [DataField]
+ public float MaxValue;
+
+ [DataField]
+ public int Steps;
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantCryoxadone : EntityEffectBase<PlantCryoxadone>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-cryoxadone", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// Handles removal of seeds on a plant.
+/// </summary>
+public sealed partial class PlantDestroySeeds : EntityEffectBase<PlantDestroySeeds>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-seeds-remove", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantDiethylamine : EntityEffectBase<PlantDiethylamine>
+{
+ /// <inheritdoc/>
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-diethylamine", ("chance", Probability));
+}
+
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class PlantPhalanximine : EntityEffectBase<PlantPhalanximine>
+{
+ /// <inheritdoc/>
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-phalanximine", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+/// <summary>
+/// Handles restoral of seeds on a plant.
+/// </summary>
+public sealed partial class PlantRestoreSeeds : EntityEffectBase<PlantRestoreSeeds>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-seeds-add", ("chance", Probability));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
+
+public sealed partial class RobustHarvest : EntityEffectBase<RobustHarvest>
+{
+ [DataField]
+ public int PotencyLimit = 50;
+
+ [DataField]
+ public int PotencyIncrease = 3;
+
+ [DataField]
+ public int PotencySeedlessThreshold = 30;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-plant-robust-harvest",
+ ("seedlesstreshold", PotencySeedlessThreshold),
+ ("limit", PotencyLimit),
+ ("increase", PotencyIncrease),
+ ("chance", Probability));
+}
--- /dev/null
+using Content.Shared.Random;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Botany;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+public sealed partial class PlantMutateChemicals : EntityEffectBase<PlantMutateChemicals>
+{
+ /// <summary>
+ /// The Reagent list this mutation draws from.
+ /// </summary>
+ [DataField]
+ public ProtoId<WeightedRandomFillSolutionPrototype> RandomPickBotanyReagent = "RandomPickBotanyReagent";
+}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+public sealed partial class PlantMutateConsumeGases : EntityEffectBase<PlantMutateConsumeGases>
+{
+ [DataField]
+ public float MinValue = 0.01f;
+
+ [DataField]
+ public float MaxValue = 0.5f;
+}
+
+public sealed partial class PlantMutateExudeGases : EntityEffectBase<PlantMutateExudeGases>
+{
+ [DataField]
+ public float MinValue = 0.01f;
+
+ [DataField]
+ public float MaxValue = 0.5f;
+}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+public sealed partial class PlantMutateHarvest : EntityEffectBase<PlantMutateHarvest>;
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.Botany;
+
+/// <summary>
+/// See serverside system.
+/// </summary>
+public sealed partial class PlantMutateSpeciesChange : EntityEffectBase<PlantMutateSpeciesChange>;
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class CauseZombieInfection : EventEntityEffect<CauseZombieInfection>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-cause-zombie-infection", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Basically smoke and foam reactions.
-/// </summary>
-public sealed partial class ChemCleanBloodstream : EventEntityEffect<ChemCleanBloodstream>
-{
- [DataField]
- public float CleanseRate = 3.0f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability));
-}
+++ /dev/null
-using Content.Shared.Eye.Blinding.Systems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Heal or apply eye damage
-/// </summary>
-public sealed partial class ChemHealEyeDamage : EntityEffect
-{
- /// <summary>
- /// How much eye damage to add.
- /// </summary>
- [DataField]
- public int Amount = -1;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-cure-eye-damage", ("chance", Probability), ("deltasign", MathF.Sign(Amount)));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- if (reagentArgs.Scale != 1f) // huh?
- return;
-
- args.EntityManager.EntitySysManager.GetEntitySystem<BlindableSystem>().AdjustEyeDamage(args.TargetEntity, Amount);
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Forces you to vomit.
-/// </summary>
-public sealed partial class ChemVomit : EventEntityEffect<ChemVomit>
-{
- /// How many units of thirst to add each time we vomit
- [DataField]
- public float ThirstAmount = -8f;
- /// How many units of hunger to add each time we vomit
- [DataField]
- public float HungerAmount = -8f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-chem-vomit", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-[DataDefinition]
-public sealed partial class CreateEntityReactionEffect : EventEntityEffect<CreateEntityReactionEffect>
-{
- /// <summary>
- /// What entity to create.
- /// </summary>
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
- public string Entity = default!;
-
- /// <summary>
- /// How many entities to create per unit reaction.
- /// </summary>
- [DataField]
- public uint Number = 1;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-create-entity-reaction-effect",
- ("chance", Probability),
- ("entname", IoCManager.Resolve<IPrototypeManager>().Index<EntityPrototype>(Entity).Name),
- ("amount", Number));
-}
+++ /dev/null
-using Content.Shared.Atmos;
-using Content.Shared.Atmos.EntitySystems;
-using Content.Shared.Database;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class CreateGas : EventEntityEffect<CreateGas>
-{
- [DataField(required: true)]
- public Gas Gas = default!;
-
- /// <summary>
- /// For each unit consumed, how many moles of gas should be created?
- /// </summary>
- [DataField]
- public float Multiplier = 3f;
-
- public override bool ShouldLog => true;
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- var atmos = entSys.GetEntitySystem<SharedAtmosphereSystem>();
- var gasProto = atmos.GetGas(Gas);
-
- return Loc.GetString("reagent-effect-guidebook-create-gas",
- ("chance", Probability),
- ("moles", Multiplier),
- ("gas", gasProto.Name));
- }
-
- public override LogImpact LogImpact => LogImpact.High;
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class CureZombieInfection : EventEntityEffect<CureZombieInfection>
-{
- [DataField]
- public bool Innoculate;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- if(Innoculate)
- return Loc.GetString("reagent-effect-guidebook-innoculate-zombie-infection", ("chance", Probability));
-
- return Loc.GetString("reagent-effect-guidebook-cure-zombie-infection", ("chance", Probability));
- }
-}
-
+++ /dev/null
-using Content.Shared.Drunk;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class Drunk : EntityEffect
-{
- /// <summary>
- /// BoozePower is how long each metabolism cycle will make the drunk effect last for.
- /// </summary>
- [DataField]
- public TimeSpan BoozePower = TimeSpan.FromSeconds(3f);
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-drunk", ("chance", Probability));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var boozePower = BoozePower;
-
- if (args is EntityEffectReagentArgs reagentArgs)
- boozePower *= reagentArgs.Scale.Float();
-
- var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedDrunkSystem>();
- drunkSys.TryApplyDrunkenness(args.TargetEntity, boozePower);
- }
-}
+++ /dev/null
-using Content.Shared.Electrocution;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class Electrocute : EntityEffect
-{
- [DataField] public int ElectrocuteTime = 2;
-
- [DataField] public int ElectrocuteDamageScale = 5;
-
- /// <remarks>
- /// true - refresh electrocute time, false - accumulate electrocute time
- /// </remarks>
- [DataField] public bool Refresh = true;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime));
-
- public override bool ShouldLog => true;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- reagentArgs.EntityManager.System<SharedElectrocutionSystem>().TryDoElectrocution(reagentArgs.TargetEntity, null,
- Math.Max((reagentArgs.Quantity * ElectrocuteDamageScale).Int(), 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
-
- if (reagentArgs.Reagent != null)
- reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
- } else
- {
- args.EntityManager.System<SharedElectrocutionSystem>().TryDoElectrocution(args.TargetEntity, null,
- Math.Max(ElectrocuteDamageScale, 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
- }
- }
-}
+++ /dev/null
-using Content.Shared.Chat.Prototypes;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Tries to force someone to emote (scream, laugh, etc). Still respects whitelists/blacklists and other limits unless specially forced.
-/// </summary>
-public sealed partial class Emote : EventEntityEffect<Emote>
-{
- /// <summary>
- /// The emote the entity will preform.
- /// </summary>
- [DataField("emote", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EmotePrototype>))]
- public string EmoteId;
-
- /// <summary>
- /// If the emote should be recorded in chat.
- /// </summary>
- [DataField]
- public bool ShowInChat;
-
- /// <summary>
- /// If the forced emote will be listed in the guidebook.
- /// </summary>
- [DataField]
- public bool ShowInGuidebook;
-
- /// <summary>
- /// If true, the entity will preform the emote even if they normally can't.
- /// </summary>
- [DataField]
- public bool Force = false;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- if (!ShowInGuidebook)
- return null; // JUSTIFICATION: Emoting is mostly flavor, so same reason popup messages are not in here.
-
- var emotePrototype = prototype.Index<EmotePrototype>(EmoteId);
- return Loc.GetString("reagent-effect-guidebook-emote", ("chance", Probability), ("emote", Loc.GetString(emotePrototype.Name)));
- }
-}
--- /dev/null
+using Content.Shared.Chat.Prototypes;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Emote : EntityEffectBase<Emote>
+{
+ /// <summary>
+ /// The emote the entity will preform.
+ /// </summary>
+ [DataField("emote", required: true)]
+ public ProtoId<EmotePrototype> EmoteId;
+
+ /// <summary>
+ /// If the emote should be recorded in chat.
+ /// </summary>
+ [DataField]
+ public bool ShowInChat;
+
+ /// <summary>
+ /// If the forced emote will be listed in the guidebook.
+ /// </summary>
+ [DataField]
+ public bool ShowInGuidebook;
+
+ /// <summary>
+ /// If true, the entity will preform the emote even if they normally can't.
+ /// </summary>
+ [DataField]
+ public bool Force;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ if (!ShowInGuidebook || !prototype.Resolve(EmoteId, out var emote))
+ return null; // JUSTIFICATION: Emoting is mostly flavor, so same reason popup messages are not in here.
+
+ return Loc.GetString("entity-effect-guidebook-emote", ("chance", Probability), ("emote", Loc.GetString(emote.Name)));
+ }
+}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-[DataDefinition]
-public sealed partial class EmpReactionEffect : EventEntityEffect<EmpReactionEffect>
-{
- /// <summary>
- /// Impulse range per unit of quantity
- /// </summary>
- [DataField("rangePerUnit")]
- public float EmpRangePerUnit = 0.5f;
-
- /// <summary>
- /// Maximum impulse range
- /// </summary>
- [DataField("maxRange")]
- public float EmpMaxRange = 10;
-
- /// <summary>
- /// How much energy will be drain from sources
- /// </summary>
- [DataField]
- public float EnergyConsumption = 12500;
-
- /// <summary>
- /// Amount of time entities will be disabled
- /// </summary>
- [DataField("duration")]
- public TimeSpan DisableDuration = TimeSpan.FromSeconds(15);
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-emp-reaction-effect", ("chance", Probability));
-}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.EntitySpawning;
+
+/// <summary>
+/// A type of <see cref="EntityEffectBase{T}"/> for effects that spawn entities by prototype.
+/// </summary>
+/// <typeparam name="T">The entity effect inheriting this BaseEffect</typeparam>
+/// <inheritdoc cref="EntityEffect"/>
+public abstract partial class BaseSpawnEntityEntityEffect<T> : EntityEffectBase<T> where T : BaseSpawnEntityEntityEffect<T>
+{
+ /// <summary>
+ /// Amount of entities we're spawning
+ /// </summary>
+ [DataField]
+ public int Number = 1;
+
+ /// <summary>
+ /// Prototype of the entity we're spawning
+ /// </summary>
+ [DataField (required: true)]
+ public EntProtoId Entity;
+
+ /// <summary>
+ /// Whether this spawning is predicted. Set false to not predict the spawn.
+ /// Entities with animations or that have random elements when spawned should set this to false.
+ /// </summary>
+ [DataField]
+ public bool Predicted = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-spawn-entity",
+ ("chance", Probability),
+ ("entname", IoCManager.Resolve<IPrototypeManager>().Index<EntityPrototype>(Entity).Name),
+ ("amount", Number));
+}
--- /dev/null
+using Robust.Shared.Network;
+
+namespace Content.Shared.EntityEffects.Effects.EntitySpawning;
+
+/// <summary>
+/// Spawns a number of entities of a given prototype at the coordinates of this entity.
+/// Amount is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SpawnEntityEntityEffectSystem : EntityEffectSystem<TransformComponent, SpawnEntity>
+{
+ [Dependency] private readonly INetManager _net = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<SpawnEntity> args)
+ {
+ var quantity = args.Effect.Number * (int)Math.Floor(args.Scale);
+ var proto = args.Effect.Entity;
+
+ if (args.Effect.Predicted)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ PredictedSpawnNextToOrDrop(proto, entity, entity.Comp);
+ }
+ }
+ else if (_net.IsServer)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ SpawnNextToOrDrop(proto, entity, entity.Comp);
+ }
+ }
+ }
+}
+
+/// <inheritdoc cref="BaseSpawnEntityEntityEffect{T}"/>
+public sealed partial class SpawnEntity : BaseSpawnEntityEntityEffect<SpawnEntity>;
--- /dev/null
+using Robust.Shared.Containers;
+using Robust.Shared.Network;
+
+namespace Content.Shared.EntityEffects.Effects.EntitySpawning;
+
+/// <summary>
+/// Spawns a given number of entities of a given prototype in a specified container owned by this entity.
+/// Returns if the prototype cannot spawn in the specified container.
+/// Amount is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SpawnEntityInContainerEntityEffectSystem : EntityEffectSystem<ContainerManagerComponent, SpawnEntityInContainer>
+{
+ [Dependency] private readonly INetManager _net = default!;
+
+ protected override void Effect(Entity<ContainerManagerComponent> entity, ref EntityEffectEvent<SpawnEntityInContainer> args)
+ {
+ var quantity = args.Effect.Number * (int)Math.Floor(args.Scale);
+ var proto = args.Effect.Entity;
+ var container = args.Effect.ContainerName;
+
+ if (args.Effect.Predicted)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ // Stop trying to spawn if it fails
+ if (!PredictedTrySpawnInContainer(proto, entity, container, out _, entity.Comp))
+ return;
+ }
+ }
+ else if (_net.IsServer)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ // Stop trying to spawn if it fails
+ if (!TrySpawnInContainer(proto, entity, container, out _, entity.Comp))
+ return;
+ }
+ }
+ }
+}
+
+/// <inheritdoc cref="BaseSpawnEntityEntityEffect{T}"/>
+public sealed partial class SpawnEntityInContainer : BaseSpawnEntityEntityEffect<SpawnEntityInContainer>
+{
+ /// <summary>
+ /// Name of the container we're trying to spawn into.
+ /// </summary>
+ [DataField(required: true)]
+ public string ContainerName;
+}
--- /dev/null
+using Robust.Shared.Containers;
+using Robust.Shared.Network;
+
+namespace Content.Shared.EntityEffects.Effects.EntitySpawning;
+
+/// <summary>
+/// Spawns a given number of entities of a given prototype in a specified container owned by this entity.
+/// Acts like <see cref="SpawnEntityEntityEffectSystem"/> if it cannot spawn the prototype in the specified container.
+/// Amount is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SpawnEntityInContainerOrDropEntityEffectSystem : EntityEffectSystem<ContainerManagerComponent, SpawnEntityInContainerOrDrop>
+{
+ [Dependency] private readonly INetManager _net = default!;
+
+ protected override void Effect(Entity<ContainerManagerComponent> entity, ref EntityEffectEvent<SpawnEntityInContainerOrDrop> args)
+ {
+ var quantity = args.Effect.Number * (int)Math.Floor(args.Scale);
+ var proto = args.Effect.Entity;
+ var container = args.Effect.ContainerName;
+
+ var xform = Transform(entity);
+
+ if (args.Effect.Predicted)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ PredictedSpawnInContainerOrDrop(proto, entity, container, xform, entity.Comp);
+ }
+ }
+ else if (_net.IsServer)
+ {
+ for (var i = 0; i < quantity; i++)
+ {
+ SpawnInContainerOrDrop(proto, entity, container, xform, entity.Comp);
+ }
+ }
+ }
+}
+
+/// <inheritdoc cref="BaseSpawnEntityEntityEffect{T}"/>
+public sealed partial class SpawnEntityInContainerOrDrop : BaseSpawnEntityEntityEffect<SpawnEntityInContainerOrDrop>
+{
+ /// <summary>
+ /// Name of the container we're trying to spawn into.
+ /// </summary>
+ [DataField(required: true)]
+ public string ContainerName;
+}
--- /dev/null
+using Content.Shared.Inventory;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.EntitySpawning;
+
+/// <summary>
+/// Spawns an entity of a given prototype in a specified inventory slot owned by this entity.
+/// Fails if it cannot spawn the entity in the given slot.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SpawnEntityInInventoryEntityEffectSystem : EntityEffectSystem<InventoryComponent, SpawnEntityInInventory>
+{
+ [Dependency] private readonly InventorySystem _inventory = default!;
+
+ protected override void Effect(Entity<InventoryComponent> entity, ref EntityEffectEvent<SpawnEntityInInventory> args)
+ {
+ _inventory.SpawnItemInSlot(entity, args.Effect.Slot, args.Effect.Entity);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class SpawnEntityInInventory : EntityEffectBase<SpawnEntityInInventory>
+{
+ /// <summary>
+ /// Name of the slot we're spawning the item into.
+ /// </summary>
+ [DataField(required: true)]
+ public string Slot = string.Empty; // Rider is drunk and keeps yelling at me to fill this out or make required: true but, it is required true so it's just being an asshole.
+
+ /// <summary>
+ /// Prototype ID of item to spawn.
+ /// </summary>
+ [DataField(required: true)]
+ public EntProtoId Entity;
+}
+++ /dev/null
-using Content.Shared.Damage;
-using Content.Shared.Damage.Prototypes;
-using Content.Shared.EntityEffects;
-using Content.Shared.FixedPoint;
-using Content.Shared.Localizations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Version of <see cref="HealthChange"/> that distributes the healing to groups
-/// </summary>
-public sealed partial class EvenHealthChange : EntityEffect
-{
- /// <summary>
- /// Damage to heal, collected into entire damage groups.
- /// </summary>
- [DataField(required: true)]
- public Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> Damage = new();
-
- /// <summary>
- /// Should this effect scale the damage by the amount of chemical in the solution?
- /// Useful for touch reactions, like styptic powder or acid.
- /// Only usable if the EntityEffectBaseArgs is an EntityEffectReagentArgs.
- /// </summary>
- [DataField]
- public bool ScaleByQuantity;
-
- /// <summary>
- /// Should this effect ignore damage modifiers?
- /// </summary>
- [DataField]
- public bool IgnoreResistances = true;
-
- protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- var damages = new List<string>();
- var heals = false;
- var deals = false;
-
- var damagableSystem = entSys.GetEntitySystem<DamageableSystem>();
- var universalReagentDamageModifier = damagableSystem.UniversalReagentDamageModifier;
- var universalReagentHealModifier = damagableSystem.UniversalReagentHealModifier;
-
- foreach (var (group, amount) in Damage)
- {
- var groupProto = prototype.Index(group);
-
- var sign = FixedPoint2.Sign(amount);
- var mod = 1f;
-
- if (sign < 0)
- {
- heals = true;
- mod = universalReagentHealModifier;
- }
- else if (sign > 0)
- {
- deals = true;
- mod = universalReagentDamageModifier;
- }
-
- damages.Add(
- Loc.GetString("health-change-display",
- ("kind", groupProto.LocalizedName),
- ("amount", MathF.Abs(amount.Float() * mod)),
- ("deltasign", sign)
- ));
- }
-
- var healsordeals = heals ? (deals ? "both" : "heals") : (deals ? "deals" : "none");
- return Loc.GetString("reagent-effect-guidebook-even-health-change",
- ("chance", Probability),
- ("changes", ContentLocalizationManager.FormatList(damages)),
- ("healsordeals", healsordeals));
- }
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (!args.EntityManager.TryGetComponent<DamageableComponent>(args.TargetEntity, out var damageable))
- return;
-
- var protoMan = IoCManager.Resolve<IPrototypeManager>();
-
- var scale = FixedPoint2.New(1);
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- scale = ScaleByQuantity ? reagentArgs.Quantity * reagentArgs.Scale : reagentArgs.Scale;
- }
-
- var damagableSystem = args.EntityManager.System<DamageableSystem>();
- var universalReagentDamageModifier = damagableSystem.UniversalReagentDamageModifier;
- var universalReagentHealModifier = damagableSystem.UniversalReagentHealModifier;
-
- var dspec = new DamageSpecifier();
-
- foreach (var (group, amount) in Damage)
- {
- var groupProto = protoMan.Index(group);
- var groupDamage = new Dictionary<string, FixedPoint2>();
- foreach (var damageId in groupProto.DamageTypes)
- {
- var damageAmount = damageable.Damage.DamageDict.GetValueOrDefault(damageId);
- if (damageAmount != FixedPoint2.Zero)
- groupDamage.Add(damageId, damageAmount);
- }
-
- var sum = groupDamage.Values.Sum();
- foreach (var (damageId, damageAmount) in groupDamage)
- {
- var existing = dspec.DamageDict.GetOrNew(damageId);
- dspec.DamageDict[damageId] = existing + damageAmount / sum * amount;
- }
- }
-
- if (universalReagentDamageModifier != 1 || universalReagentHealModifier != 1)
- {
- foreach (var (type, val) in dspec.DamageDict)
- {
- if (val < 0f)
- {
- dspec.DamageDict[type] = val * universalReagentHealModifier;
- }
- if (val > 0f)
- {
- dspec.DamageDict[type] = val * universalReagentDamageModifier;
- }
- }
- }
-
- damagableSystem.TryChangeDamage(
- args.TargetEntity,
- dspec * scale,
- IgnoreResistances,
- interruptsDoAfters: false);
- }
-}
--- /dev/null
+using Content.Shared.Damage;
+using Content.Shared.Damage.Prototypes;
+using Content.Shared.FixedPoint;
+using Content.Shared.Localizations;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Evenly adjust the damage types in a damage group by up to a specified total on this entity.
+/// Total adjustment is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class EvenHealthChangeEntityEffectSystem : EntityEffectSystem<DamageableComponent, EvenHealthChange>
+{
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+
+ protected override void Effect(Entity<DamageableComponent> entity, ref EntityEffectEvent<EvenHealthChange> args)
+ {
+ var damageSpec = new DamageSpecifier();
+
+ foreach (var (group, amount) in args.Effect.Damage)
+ {
+ var groupProto = _proto.Index(group);
+ var groupDamage = new Dictionary<string, FixedPoint2>();
+ foreach (var damageId in groupProto.DamageTypes)
+ {
+ var damageAmount = entity.Comp.Damage.DamageDict.GetValueOrDefault(damageId);
+ if (damageAmount != FixedPoint2.Zero)
+ groupDamage.Add(damageId, damageAmount);
+ }
+
+ var sum = groupDamage.Values.Sum();
+ foreach (var (damageId, damageAmount) in groupDamage)
+ {
+ var existing = damageSpec.DamageDict.GetOrNew(damageId);
+ damageSpec.DamageDict[damageId] = existing + damageAmount / sum * amount;
+ }
+ }
+
+ damageSpec *= args.Scale;
+
+ _damageable.TryChangeDamage(
+ entity,
+ damageSpec,
+ args.Effect.IgnoreResistances,
+ interruptsDoAfters: false,
+ damageable: entity.Comp);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class EvenHealthChange : EntityEffectBase<EvenHealthChange>
+{
+ /// <summary>
+ /// Damage to heal, collected into entire damage groups.
+ /// </summary>
+ [DataField(required: true)]
+ public Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> Damage = new();
+
+ /// <summary>
+ /// Should this effect ignore damage modifiers?
+ /// </summary>
+ [DataField]
+ public bool IgnoreResistances = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ var damages = new List<string>();
+ var heals = false;
+ var deals = false;
+
+ var damagableSystem = entSys.GetEntitySystem<DamageableSystem>();
+ var universalReagentDamageModifier = damagableSystem.UniversalReagentDamageModifier;
+ var universalReagentHealModifier = damagableSystem.UniversalReagentHealModifier;
+
+ foreach (var (group, amount) in Damage)
+ {
+ var groupProto = prototype.Index(group);
+
+ var sign = FixedPoint2.Sign(amount);
+ float mod;
+
+ switch (sign)
+ {
+ case < 0:
+ heals = true;
+ mod = universalReagentHealModifier;
+ break;
+ case > 0:
+ deals = true;
+ mod = universalReagentDamageModifier;
+ break;
+ default:
+ continue; // Don't need to show damage types of 0...
+ }
+
+ damages.Add(
+ Loc.GetString("health-change-display",
+ ("kind", groupProto.LocalizedName),
+ ("amount", MathF.Abs(amount.Float() * mod)),
+ ("deltasign", sign)
+ ));
+ }
+
+ var healsordeals = heals ? deals ? "both" : "heals" : deals ? "deals" : "none";
+ return Loc.GetString("entity-effect-guidebook-even-health-change",
+ ("chance", Probability),
+ ("changes", ContentLocalizationManager.FormatList(damages)),
+ ("healsordeals", healsordeals));
+ }
+}
+++ /dev/null
-using Content.Shared.Atmos;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects
-{
- public sealed partial class ExtinguishReaction : EntityEffect
- {
- /// <summary>
- /// Amount of firestacks reduced.
- /// </summary>
- [DataField]
- public float FireStacksAdjustment = -1.5f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-extinguish-reaction", ("chance", Probability));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var ev = new ExtinguishEvent
- {
- FireStacksAdjustment = FireStacksAdjustment,
- };
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- ev.FireStacksAdjustment *= (float)reagentArgs.Quantity;
- }
-
- args.EntityManager.EventBus.RaiseLocalEvent(args.TargetEntity, ref ev);
- }
- }
-}
+++ /dev/null
-using Content.Shared.Database;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class FlammableReaction : EventEntityEffect<FlammableReaction>
-{
- [DataField]
- public float Multiplier = 0.05f;
-
- // The fire stack multiplier if fire stacks already exist on target, only works if 0 or greater
- [DataField]
- public float MultiplierOnExisting = -1f;
-
- public override bool ShouldLog => true;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability));
-
- public override LogImpact LogImpact => LogImpact.Medium;
-}
+++ /dev/null
-using Robust.Shared.Audio;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-[DataDefinition]
-public sealed partial class FlashReactionEffect : EventEntityEffect<FlashReactionEffect>
-{
- /// <summary>
- /// Flash range per unit of reagent.
- /// </summary>
- [DataField]
- public float RangePerUnit = 0.2f;
-
- /// <summary>
- /// Maximum flash range.
- /// </summary>
- [DataField]
- public float MaxRange = 10f;
-
- /// <summary>
- /// How much to entities are slowed down.
- /// </summary>
- [DataField]
- public float SlowTo = 0.5f;
-
- /// <summary>
- /// The time entities will be flashed.
- /// The default is chosen to be better than the hand flash so it is worth using it for grenades etc.
- /// </summary>
- [DataField]
- public TimeSpan Duration = TimeSpan.FromSeconds(4);
-
- /// <summary>
- /// The prototype ID used for the visual effect.
- /// </summary>
- [DataField]
- public EntProtoId? FlashEffectPrototype = "ReactionFlash";
-
- /// <summary>
- /// The sound the flash creates.
- /// </summary>
- [DataField]
- public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/flash.ogg");
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-flash-reaction-effect", ("chance", Probability));
-}
+++ /dev/null
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Makes a mob glow.
-/// </summary>
-public sealed partial class Glow : EntityEffect
-{
- [DataField]
- public float Radius = 2f;
-
- [DataField]
- public Color Color = Color.Black;
-
- private static readonly List<Color> Colors = new()
- {
- Color.White,
- Color.Red,
- Color.Yellow,
- Color.Green,
- Color.Blue,
- Color.Purple,
- Color.Pink
- };
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (Color == Color.Black)
- {
- var random = IoCManager.Resolve<IRobustRandom>();
- Color = random.Pick(Colors);
- }
-
- var lightSystem = args.EntityManager.System<SharedPointLightSystem>();
- var light = lightSystem.EnsureLight(args.TargetEntity);
- lightSystem.SetRadius(args.TargetEntity, Radius, light);
- lightSystem.SetColor(args.TargetEntity, Color, light);
- lightSystem.SetCastShadows(args.TargetEntity, false, light); // this is expensive, and botanists make lots of plants
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
--- /dev/null
+using Robust.Shared.Network;
+using Robust.Shared.Random;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Causes this entity to glow.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class GlowEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Glow>
+{
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedPointLightSystem _lightSystem = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Glow> args)
+ {
+ var color = args.Effect.Color;
+
+ if (color == Color.Black)
+ {
+ // TODO: When we get proper predicted RNG remove this check...
+ if (_net.IsClient)
+ return;
+
+ color = _random.Pick(Colors);
+ }
+
+ var light = _lightSystem.EnsureLight(entity);
+ _lightSystem.SetRadius(entity, args.Effect.Radius, light);
+ _lightSystem.SetColor(entity, color, light);
+ _lightSystem.SetCastShadows(entity, false, light); // this is expensive, and botanists make lots of plants
+ }
+
+ public static readonly List<Color> Colors = new()
+ {
+ Color.White,
+ Color.Red,
+ Color.Yellow,
+ Color.Green,
+ Color.Blue,
+ Color.Purple,
+ Color.Pink
+ };
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Glow : EntityEffectBase<Glow>
+{
+ [DataField]
+ public float Radius = 2f;
+
+ [DataField]
+ public Color Color = Color.Black;
+}
+++ /dev/null
-using Content.Shared.Damage;
-using Content.Shared.Damage.Prototypes;
-using Content.Shared.EntityEffects;
-using Content.Shared.FixedPoint;
-using Content.Shared.Localizations;
-using Robust.Shared.Prototypes;
-using System.Linq;
-using System.Text.Json.Serialization;
-
-namespace Content.Shared.EntityEffects.Effects
-{
- /// <summary>
- /// Default metabolism used for medicine reagents.
- /// </summary>
- public sealed partial class HealthChange : EntityEffect
- {
- /// <summary>
- /// Damage to apply every cycle. Damage Ignores resistances.
- /// </summary>
- [DataField(required: true)]
- [JsonPropertyName("damage")]
- public DamageSpecifier Damage = default!;
-
- /// <summary>
- /// Should this effect scale the damage by the amount of chemical in the solution?
- /// Useful for touch reactions, like styptic powder or acid.
- /// Only usable if the EntityEffectBaseArgs is an EntityEffectReagentArgs.
- /// </summary>
- [DataField]
- [JsonPropertyName("scaleByQuantity")]
- public bool ScaleByQuantity;
-
- [DataField]
- [JsonPropertyName("ignoreResistances")]
- public bool IgnoreResistances = true;
-
- protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- var damages = new List<string>();
- var heals = false;
- var deals = false;
-
- var damageSpec = new DamageSpecifier(Damage);
-
- var universalReagentDamageModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentDamageModifier;
- var universalReagentHealModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentHealModifier;
-
- if (universalReagentDamageModifier != 1 || universalReagentHealModifier != 1)
- {
- foreach (var (type, val) in damageSpec.DamageDict)
- {
- if (val < 0f)
- {
- damageSpec.DamageDict[type] = val * universalReagentHealModifier;
- }
- if (val > 0f)
- {
- damageSpec.DamageDict[type] = val * universalReagentDamageModifier;
- }
- }
- }
-
- damageSpec = entSys.GetEntitySystem<DamageableSystem>().ApplyUniversalAllModifiers(damageSpec);
-
- foreach (var (kind, amount) in damageSpec.DamageDict)
- {
- var sign = FixedPoint2.Sign(amount);
-
- if (sign < 0)
- heals = true;
- if (sign > 0)
- deals = true;
-
- damages.Add(
- Loc.GetString("health-change-display",
- ("kind", prototype.Index<DamageTypePrototype>(kind).LocalizedName),
- ("amount", MathF.Abs(amount.Float())),
- ("deltasign", sign)
- ));
- }
-
- var healsordeals = heals ? (deals ? "both" : "heals") : (deals ? "deals" : "none");
-
- return Loc.GetString("reagent-effect-guidebook-health-change",
- ("chance", Probability),
- ("changes", ContentLocalizationManager.FormatList(damages)),
- ("healsordeals", healsordeals));
- }
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var scale = FixedPoint2.New(1);
- var damageSpec = new DamageSpecifier(Damage);
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- scale = ScaleByQuantity ? reagentArgs.Quantity * reagentArgs.Scale : reagentArgs.Scale;
- }
-
- var universalReagentDamageModifier = args.EntityManager.System<DamageableSystem>().UniversalReagentDamageModifier;
- var universalReagentHealModifier = args.EntityManager.System<DamageableSystem>().UniversalReagentHealModifier;
-
- if (universalReagentDamageModifier != 1 || universalReagentHealModifier != 1)
- {
- foreach (var (type, val) in damageSpec.DamageDict)
- {
- if (val < 0f)
- {
- damageSpec.DamageDict[type] = val * universalReagentHealModifier;
- }
- if (val > 0f)
- {
- damageSpec.DamageDict[type] = val * universalReagentDamageModifier;
- }
- }
- }
-
- args.EntityManager.System<DamageableSystem>()
- .TryChangeDamage(
- args.TargetEntity,
- damageSpec * scale,
- IgnoreResistances,
- interruptsDoAfters: false);
- }
- }
-}
--- /dev/null
+using Content.Shared.Damage;
+using Content.Shared.Damage.Prototypes;
+using Content.Shared.FixedPoint;
+using Content.Shared.Localizations;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Adjust the damages on this entity by specified amounts.
+/// Amounts are modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class HealthChangeEntityEffectSystem : EntityEffectSystem<DamageableComponent, HealthChange>
+{
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+
+ protected override void Effect(Entity<DamageableComponent> entity, ref EntityEffectEvent<HealthChange> args)
+ {
+ var damageSpec = new DamageSpecifier(args.Effect.Damage);
+
+ damageSpec *= args.Scale;
+
+ _damageable.TryChangeDamage(
+ entity,
+ damageSpec,
+ args.Effect.IgnoreResistances,
+ interruptsDoAfters: false);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class HealthChange : EntityEffectBase<HealthChange>
+{
+ /// <summary>
+ /// Damage to apply every cycle. Damage Ignores resistances.
+ /// </summary>
+ [DataField(required: true)]
+ public DamageSpecifier Damage = default!;
+
+ [DataField]
+ public bool IgnoreResistances = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ var damages = new List<string>();
+ var heals = false;
+ var deals = false;
+
+ var damageSpec = new DamageSpecifier(Damage);
+
+ var universalReagentDamageModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentDamageModifier;
+ var universalReagentHealModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentHealModifier;
+
+ damageSpec = entSys.GetEntitySystem<DamageableSystem>().ApplyUniversalAllModifiers(damageSpec);
+
+ foreach (var (kind, amount) in damageSpec.DamageDict)
+ {
+ var sign = FixedPoint2.Sign(amount);
+ float mod;
+
+ switch (sign)
+ {
+ case < 0:
+ heals = true;
+ mod = universalReagentHealModifier;
+ break;
+ case > 0:
+ deals = true;
+ mod = universalReagentDamageModifier;
+ break;
+ default:
+ continue; // Don't need to show damage types of 0...
+ }
+
+ damages.Add(
+ Loc.GetString("health-change-display",
+ ("kind", prototype.Index<DamageTypePrototype>(kind).LocalizedName),
+ ("amount", MathF.Abs(amount.Float() * mod)),
+ ("deltasign", sign)
+ ));
+ }
+
+ var healsordeals = heals ? (deals ? "both" : "heals") : (deals ? "deals" : "none");
+
+ return Loc.GetString("entity-effect-guidebook-health-change",
+ ("chance", Probability),
+ ("changes", ContentLocalizationManager.FormatList(damages)),
+ ("healsordeals", healsordeals));
+ }
+}
+++ /dev/null
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Ignites a mob.
-/// </summary>
-public sealed partial class Ignite : EventEntityEffect<Ignite>
-{
- public override bool ShouldLog => true;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-ignite", ("chance", Probability));
-
- public override LogImpact LogImpact => LogImpact.Medium;
-}
+++ /dev/null
-using Content.Shared.Mind.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class MakeSentient : EventEntityEffect<MakeSentient>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability));
-}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class MakeSentient : EntityEffectBase<MakeSentient>
+{
+ /// <summary>
+ /// Description for the ghost role created by this effect.
+ /// </summary>
+ [DataField]
+ public LocId RoleDescription = "ghost-role-information-cognizine-description";
+
+ /// <summary>
+ /// Whether we give the target the ability to speak coherently.
+ /// </summary>
+ [DataField]
+ public bool AllowSpeech = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-make-sentient", ("chance", Probability));
+}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class ModifyBleedAmount : EventEntityEffect<ModifyBleedAmount>
-{
- [DataField]
- public bool Scaled = false;
-
- [DataField]
- public float Amount = -1.0f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-modify-bleed-amount", ("chance", Probability),
- ("deltasign", MathF.Sign(Amount)));
-}
+++ /dev/null
-using Content.Shared.FixedPoint;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class ModifyBloodLevel : EventEntityEffect<ModifyBloodLevel>
-{
- [DataField]
- public bool Scaled = false;
-
- [DataField]
- public FixedPoint2 Amount = 1.0f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-modify-blood-level", ("chance", Probability),
- ("deltasign", MathF.Sign(Amount.Float())));
-}
+++ /dev/null
-using Content.Shared.Atmos;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class ModifyLungGas : EventEntityEffect<ModifyLungGas>
-{
- [DataField("ratios", required: true)]
- public Dictionary<Gas, float> Ratios = default!;
-
- // JUSTIFICATION: This is internal magic that players never directly interact with.
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => null;
-}
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Movement.Systems;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Timing;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Default metabolism for stimulants and tranqs. Attempts to find a MovementSpeedModifier on the target,
-/// adding one if not there and to change the movespeed
-/// </summary>
-public sealed partial class MovespeedModifier : EntityEffect
-{
- /// <summary>
- /// How much the entities' walk speed is multiplied by.
- /// </summary>
- [DataField]
- public float WalkSpeedModifier { get; set; } = 1;
-
- /// <summary>
- /// How much the entities' run speed is multiplied by.
- /// </summary>
- [DataField]
- public float SprintSpeedModifier { get; set; } = 1;
-
- /// <summary>
- /// How long the modifier applies (in seconds).
- /// Is scaled by reagent amount if used with an EntityEffectReagentArgs.
- /// </summary>
- [DataField]
- public float StatusLifetime = 2f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return Loc.GetString("reagent-effect-guidebook-movespeed-modifier",
- ("chance", Probability),
- ("walkspeed", WalkSpeedModifier),
- ("time", StatusLifetime));
- }
-
- /// <summary>
- /// Remove reagent at set rate, changes the movespeed modifiers and adds a MovespeedModifierMetabolismComponent if not already there.
- /// </summary>
- public override void Effect(EntityEffectBaseArgs args)
- {
- var status = args.EntityManager.EnsureComponent<MovespeedModifierMetabolismComponent>(args.TargetEntity);
-
- // Only refresh movement if we need to.
- var modified = !status.WalkSpeedModifier.Equals(WalkSpeedModifier) ||
- !status.SprintSpeedModifier.Equals(SprintSpeedModifier);
-
- status.WalkSpeedModifier = WalkSpeedModifier;
- status.SprintSpeedModifier = SprintSpeedModifier;
-
- // only going to scale application time
- var statusLifetime = StatusLifetime;
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- statusLifetime *= reagentArgs.Scale.Float();
- }
-
- IncreaseTimer(status, statusLifetime, args.EntityManager, args.TargetEntity);
-
- if (modified)
- args.EntityManager.System<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(args.TargetEntity);
- }
- private void IncreaseTimer(MovespeedModifierMetabolismComponent status, float time, IEntityManager entityManager, EntityUid uid)
- {
- var gameTiming = IoCManager.Resolve<IGameTiming>();
-
- var offsetTime = Math.Max(status.ModifierTimer.TotalSeconds, gameTiming.CurTime.TotalSeconds);
-
- status.ModifierTimer = TimeSpan.FromSeconds(offsetTime + time);
-
- entityManager.Dirty(uid, status);
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class Oxygenate : EventEntityEffect<Oxygenate>
-{
- [DataField]
- public float Factor = 1f;
-
- // JUSTIFICATION: This is internal magic that players never directly interact with.
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => null;
-}
+++ /dev/null
-using Content.Shared.Stunnable;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class Paralyze : EntityEffect
-{
- [DataField] public double ParalyzeTime = 2;
-
- /// <remarks>
- /// true - refresh paralyze time, false - accumulate paralyze time
- /// </remarks>
- [DataField] public bool Refresh = true;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString(
- "reagent-effect-guidebook-paralyze",
- ("chance", Probability),
- ("time", ParalyzeTime)
- );
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var paralyzeTime = ParalyzeTime;
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- paralyzeTime *= (double)reagentArgs.Scale;
- }
-
- var stunSystem = args.EntityManager.System<SharedStunSystem>();
- _ = Refresh
- ? stunSystem.TryUpdateParalyzeDuration(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime))
- : stunSystem.TryAddParalyzeDuration(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime));
- }
-}
-
+++ /dev/null
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-[ImplicitDataDefinitionForInheritors]
-public abstract partial class PlantAdjustAttribute<T> : EventEntityEffect<T> where T : PlantAdjustAttribute<T>
-{
- [DataField]
- public float Amount { get; protected set; } = 1;
-
- /// <summary>
- /// Localisation key for the name of the adjusted attribute. Used for guidebook descriptions.
- /// </summary>
- [DataField]
- public abstract string GuidebookAttributeName { get; set; }
-
- /// <summary>
- /// Whether the attribute in question is a good thing. Used for guidebook descriptions to determine the color of the number.
- /// </summary>
- [DataField]
- public virtual bool GuidebookIsAttributePositive { get; protected set; } = true;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- string color;
- if (GuidebookIsAttributePositive ^ Amount < 0.0)
- {
- color = "green";
- }
- else
- {
- color = "red";
- }
- return Loc.GetString("reagent-effect-guidebook-plant-attribute", ("attribute", Loc.GetString(GuidebookAttributeName)), ("amount", Amount.ToString("0.00")), ("colorName", color), ("chance", Probability));
- }
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustHealth : PlantAdjustAttribute<PlantAdjustHealth>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
-}
-
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustMutationLevel : PlantAdjustAttribute<PlantAdjustMutationLevel>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustMutationMod : PlantAdjustAttribute<PlantAdjustMutationMod>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustNutrition : PlantAdjustAttribute<PlantAdjustNutrition>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
-}
+++ /dev/null
-// using Content.Server.Botany.Systems;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-/// Handles increase or decrease of plant potency.
-/// </summary>
-
-public sealed partial class PlantAdjustPotency : PlantAdjustAttribute<PlantAdjustPotency>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-potency";
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustWater : PlantAdjustAttribute<PlantAdjustWater>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
-}
-
+++ /dev/null
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAffectGrowth : PlantAdjustAttribute<PlantAffectGrowth>
-{
- public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
-}
-
+++ /dev/null
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantChangeStat : EventEntityEffect<PlantChangeStat>
-{
- [DataField]
- public string TargetValue;
-
- [DataField]
- public float MinValue;
-
- [DataField]
- public float MaxValue;
-
- [DataField]
- public int Steps;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- throw new NotImplementedException();
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantCryoxadone : EventEntityEffect<PlantCryoxadone>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-cryoxadone", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-/// Handles removal of seeds on a plant.
-/// </summary>
-
-public sealed partial class PlantDestroySeeds : EventEntityEffect<PlantDestroySeeds>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
- Loc.GetString("reagent-effect-guidebook-plant-seeds-remove", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantDiethylamine : EventEntityEffect<PlantDiethylamine>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-diethylamine", ("chance", Probability));
-}
-
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantPhalanximine : EventEntityEffect<PlantPhalanximine>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-phalanximine", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-/// Handles restoral of seeds on a plant.
-/// </summary>
-public sealed partial class PlantRestoreSeeds : EventEntityEffect<PlantRestoreSeeds>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
- Loc.GetString("reagent-effect-guidebook-plant-seeds-add", ("chance", Probability));
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class RobustHarvest : EventEntityEffect<RobustHarvest>
-{
- [DataField]
- public int PotencyLimit = 50;
-
- [DataField]
- public int PotencyIncrease = 3;
-
- [DataField]
- public int PotencySeedlessThreshold = 30;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-robust-harvest", ("seedlesstreshold", PotencySeedlessThreshold), ("limit", PotencyLimit), ("increase", PotencyIncrease), ("chance", Probability));
-}
+++ /dev/null
-using Content.Shared.Random;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// changes the chemicals available in a plant's produce
-/// </summary>
-public sealed partial class PlantMutateChemicals : EventEntityEffect<PlantMutateChemicals>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using System.Linq;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// changes the gases that a plant or produce create.
-/// </summary>
-public sealed partial class PlantMutateExudeGasses : EventEntityEffect<PlantMutateExudeGasses>
-{
- [DataField]
- public float MinValue = 0.01f;
-
- [DataField]
- public float MaxValue = 0.5f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
-
-/// <summary>
-/// changes the gases that a plant or produce consumes.
-/// </summary>
-public sealed partial class PlantMutateConsumeGasses : EventEntityEffect<PlantMutateConsumeGasses>
-{
- [DataField]
- public float MinValue = 0.01f;
-
- [DataField]
- public float MaxValue = 0.5f;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Upgrades a plant's harvest type.
-/// </summary>
-public sealed partial class PlantMutateHarvest : EventEntityEffect<PlantMutateHarvest>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
+++ /dev/null
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Changes a plant into one of the species its able to mutate into.
-/// </summary>
-public sealed partial class PlantSpeciesChange : EventEntityEffect<PlantSpeciesChange>
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- return "TODO";
- }
-}
+++ /dev/null
-using Content.Shared.Polymorph;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class Polymorph : EventEntityEffect<Polymorph>
-{
- /// <summary>
- /// What polymorph prototype is used on effect
- /// </summary>
- [DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
- public string PolymorphPrototype { get; set; }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-make-polymorph",
- ("chance", Probability), ("entityname",
- prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Configuration.Entity).Name));
-}
--- /dev/null
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Polymorph : EntityEffectBase<Polymorph>
+{
+ /// <summary>
+ /// What polymorph prototype is used on effect
+ /// </summary>
+ [DataField(required: true)]
+ public ProtoId<PolymorphPrototype> Prototype;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-make-polymorph",
+ ("chance", Probability),
+ ("entityname", prototype.Index<EntityPrototype>(prototype.Index(Prototype).Configuration.Entity).Name));
+}
+++ /dev/null
-using Content.Shared.Popups;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Shared.EntityEffects.Effects
-{
- public sealed partial class PopupMessage : EntityEffect
- {
- [DataField(required: true)]
- public string[] Messages = default!;
-
- [DataField]
- public PopupRecipients Type = PopupRecipients.Local;
-
- [DataField]
- public PopupType VisualType = PopupType.Small;
-
- // JUSTIFICATION: This is purely cosmetic.
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => null;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var popupSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedPopupSystem>();
- var random = IoCManager.Resolve<IRobustRandom>();
-
- var msg = random.Pick(Messages);
- var msgArgs = new (string, object)[]
- {
- ("entity", args.TargetEntity),
- };
-
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- msgArgs = new (string, object)[]
- {
- ("entity", reagentArgs.TargetEntity),
- ("organ", reagentArgs.OrganEntity.GetValueOrDefault()),
- };
- }
-
- if (Type == PopupRecipients.Local)
- popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.TargetEntity, args.TargetEntity, VisualType);
- else if (Type == PopupRecipients.Pvs)
- popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.TargetEntity, VisualType);
- }
- }
-
- public enum PopupRecipients
- {
- Pvs,
- Local
- }
-}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Prototypes;
-using Content.Shared.Atmos.Rotting;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Reduces the rotting accumulator on the patient, making them revivable.
-/// </summary>
-public sealed partial class ReduceRotting : EntityEffect
-{
- [DataField("seconds")]
- public double RottingAmount = 10;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-reduce-rotting",
- ("chance", Probability),
- ("time", RottingAmount));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.Scale != 1f)
- return;
- }
-
- var rottingSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedRottingSystem>();
-
- rottingSys.ReduceAccumulator(args.TargetEntity, TimeSpan.FromSeconds(RottingAmount));
- }
-}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Reset narcolepsy timer
-/// </summary>
-public sealed partial class ResetNarcolepsy : EventEntityEffect<ResetNarcolepsy>
-{
- /// <summary>
- /// The # of seconds the effect resets the narcolepsy timer to
- /// </summary>
- [DataField("TimerReset")]
- public TimeSpan TimerReset = TimeSpan.FromSeconds(600);
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability));
-}
--- /dev/null
+using Content.Shared.Traits.Assorted;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Resets the narcolepsy timer on a given entity.
+/// The new duration of the timer is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ResetNarcolepsyEntityEffectSystem : EntityEffectSystem<NarcolepsyComponent, ResetNarcolepsy>
+{
+ [Dependency] private readonly NarcolepsySystem _narcolepsy = default!;
+
+ protected override void Effect(Entity<NarcolepsyComponent> entity, ref EntityEffectEvent<ResetNarcolepsy> args)
+ {
+ var timer = args.Effect.TimerReset * args.Scale;
+
+ _narcolepsy.AdjustNarcolepsyTimer(entity.AsNullable(), timer);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ResetNarcolepsy : EntityEffectBase<ResetNarcolepsy>
+{
+ /// <summary>
+ /// The time we set our narcolepsy timer to.
+ /// </summary>
+ [DataField("TimerReset")]
+ public TimeSpan TimerReset = TimeSpan.FromSeconds(600);
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-reset-narcolepsy", ("chance", Probability));
+}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Attempts to find a HungerComponent on the target,
-/// and to update it's hunger values.
-/// </summary>
-public sealed partial class SatiateHunger : EntityEffect
-{
- private const float DefaultNutritionFactor = 3.0f;
-
- /// <summary>
- /// How much hunger is satiated.
- /// Is multiplied by quantity if used with EntityEffectReagentArgs.
- /// </summary>
- [DataField("factor")] public float NutritionFactor { get; set; } = DefaultNutritionFactor;
-
- //Remove reagent at set rate, satiate hunger if a HungerComponent can be found
- public override void Effect(EntityEffectBaseArgs args)
- {
- var entman = args.EntityManager;
- if (!entman.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
- return;
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- entman.System<HungerSystem>().ModifyHunger(reagentArgs.TargetEntity, NutritionFactor * (float) reagentArgs.Quantity, hunger);
- }
- else
- {
- entman.System<HungerSystem>().ModifyHunger(args.TargetEntity, NutritionFactor, hunger);
- }
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-satiate-hunger", ("chance", Probability), ("relative", NutritionFactor / DefaultNutritionFactor));
-}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Default metabolism for drink reagents. Attempts to find a ThirstComponent on the target,
-/// and to update it's thirst values.
-/// </summary>
-public sealed partial class SatiateThirst : EntityEffect
-{
- private const float DefaultHydrationFactor = 3.0f;
-
- /// How much thirst is satiated each tick. Not currently tied to
- /// rate or anything.
- [DataField("factor")]
- public float HydrationFactor { get; set; } = DefaultHydrationFactor;
-
- /// Satiate thirst if a ThirstComponent can be found
- public override void Effect(EntityEffectBaseArgs args)
- {
- var uid = args.TargetEntity;
- if (args.EntityManager.TryGetComponent(uid, out ThirstComponent? thirst))
- args.EntityManager.System<ThirstSystem>().ModifyThirst(uid, thirst, HydrationFactor);
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-satiate-thirst", ("chance", Probability), ("relative", HydrationFactor / DefaultHydrationFactor));
-}
+++ /dev/null
-using Content.Shared.Physics;
-using Content.Shared.Slippery;
-using Content.Shared.StepTrigger.Components;
-using Robust.Shared.Physics;
-using Robust.Shared.Physics.Components;
-using Robust.Shared.Physics.Systems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Makes a mob slippery.
-/// </summary>
-public sealed partial class Slipify : EntityEffect
-{
- public override void Effect(EntityEffectBaseArgs args)
- {
- var fixtureSystem = args.EntityManager.System<FixtureSystem>();
- var colWakeSystem = args.EntityManager.System<CollisionWakeSystem>();
- var slippery = args.EntityManager.EnsureComponent<SlipperyComponent>(args.TargetEntity);
- args.EntityManager.Dirty(args.TargetEntity, slippery);
- args.EntityManager.EnsureComponent<StepTriggerComponent>(args.TargetEntity);
- // Need a fixture with a slip layer in order to actually do the slipping
- var fixtures = args.EntityManager.EnsureComponent<FixturesComponent>(args.TargetEntity);
- var body = args.EntityManager.EnsureComponent<PhysicsComponent>(args.TargetEntity);
- var shape = fixtures.Fixtures["fix1"].Shape;
- fixtureSystem.TryCreateFixture(args.TargetEntity, shape, "slips", 1, false, (int)CollisionGroup.SlipLayer, manager: fixtures, body: body);
- // Need to disable collision wake so that mobs can collide with and slip on it
- var collisionWake = args.EntityManager.EnsureComponent<CollisionWakeComponent>(args.TargetEntity);
- colWakeSystem.SetEnabled(args.TargetEntity, false, collisionWake);
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- throw new NotImplementedException();
- }
-}
--- /dev/null
+using System.Linq;
+using Content.Shared.Physics;
+using Content.Shared.Slippery;
+using Content.Shared.StepTrigger.Components;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Systems;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// This effect permanently creates a slippery fixture for this entity and then makes this entity slippery like soap.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class SlipifyEntityEffectSystem : EntityEffectSystem<FixturesComponent, Slipify>
+{
+ [Dependency] private readonly CollisionWakeSystem _collisionWake = default!;
+ [Dependency] private readonly FixtureSystem _fixture = default!;
+
+ protected override void Effect(Entity<FixturesComponent> entity, ref EntityEffectEvent<Slipify> args)
+ {
+ EnsureComp<SlipperyComponent>(entity, out var slippery);
+ slippery.SlipData = args.Effect.Slippery;
+
+ Dirty(entity, slippery);
+
+ EnsureComp<StepTriggerComponent>(entity);
+
+ if (entity.Comp.Fixtures.FirstOrDefault(x => x.Value.Hard).Value.Shape is not { } shape)
+ return;
+
+ _fixture.TryCreateFixture(entity, shape, "slips", 1, false, (int)CollisionGroup.SlipLayer, manager: entity.Comp);
+
+ // Need to disable collision wake so that mobs can collide with and slip on it
+ EnsureComp<CollisionWakeComponent>(entity, out var collisionWake);
+ _collisionWake.SetEnabled(entity, false, collisionWake);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Slipify : EntityEffectBase<Slipify>
+{
+ [DataField]
+ public SlipperyEffectEntry Slippery = new();
+}
--- /dev/null
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Solution;
+
+// TODO: This should be removed and changed to an "AbsorbentSolutionComponent"
+/// <summary>
+/// Creates a reagent in a specified solution owned by this entity.
+/// Quantity is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed class AddReagentToSolutionEntityEffectSystem : EntityEffectSystem<SolutionContainerManagerComponent, AddReagentToSolution>
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionContainerManagerComponent> entity, ref EntityEffectEvent<AddReagentToSolution> args)
+ {
+ var solution = args.Effect.Solution;
+ var reagent = args.Effect.Reagent;
+
+ if (!_solutionContainer.TryGetSolution((entity, entity), solution, out var solutionContainer))
+ return;
+
+ _solutionContainer.TryAddReagent(solutionContainer.Value, reagent, args.Scale * args.Effect.StrengthModifier);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AddReagentToSolution : EntityEffectBase<AddReagentToSolution>
+{
+ /// <summary>
+ /// Prototype of the reagent we're adding.
+ /// </summary>
+ [DataField(required: true)]
+ public ProtoId<ReagentPrototype> Reagent;
+
+ ///<summary>
+ /// Solution we're looking for
+ /// </summary>
+ [DataField(required: true)]
+ public string? Solution = "reagents";
+
+ ///<summary>
+ /// A modifier for how much reagent we're creating.
+ /// </summary>
+ [DataField]
+ public float StrengthModifier = 1.0f;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ return prototype.Resolve(Reagent, out ReagentPrototype? proto)
+ ? Loc.GetString("entity-effect-guidebook-add-to-solution-reaction",
+ ("chance", Probability),
+ ("reagent", proto.LocalizedName))
+ : null;
+ }
+}
--- /dev/null
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Solution;
+
+/// <summary>
+/// Adjust a reagent in this solution by an amount modified by scale.
+/// Quantity is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class AdjustReagentEntityEffectSystem : EntityEffectSystem<SolutionComponent, AdjustReagent>
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<AdjustReagent> args)
+ {
+ var quantity = args.Effect.Amount * args.Scale;
+ var reagent = args.Effect.Reagent;
+
+ if (quantity > 0)
+ _solutionContainer.TryAddReagent(entity, reagent, quantity);
+ else
+ _solutionContainer.RemoveReagent(entity, reagent, -quantity);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustReagent : EntityEffectBase<AdjustReagent>
+{
+ /// <summary>
+ /// The reagent ID to add or remove.
+ /// </summary>
+ [DataField(required: true)]
+ public ProtoId<ReagentPrototype> Reagent;
+
+ [DataField(required: true)]
+ public FixedPoint2 Amount;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ return prototype.Resolve(Reagent, out ReagentPrototype? proto)
+ ? Loc.GetString("entity-effect-guidebook-adjust-reagent-reagent",
+ ("chance", Probability),
+ ("deltasign", MathF.Sign(Amount.Float())),
+ ("reagent", proto.LocalizedName),
+ ("amount", MathF.Abs(Amount.Float())))
+ : null;
+ }
+}
--- /dev/null
+using Content.Shared.Body.Prototypes;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Solution;
+
+/// <summary>
+/// Adjust all reagents in this solution which are metabolized by a given metabolism group.
+/// Quantity is modified by scale, quantity is per reagent and not a total.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class AdjustReagentsByGroupEntityEffectSystem : EntityEffectSystem<SolutionComponent, AdjustReagentsByGroup>
+{
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<AdjustReagentsByGroup> args)
+ {
+ var quantity = args.Effect.Amount * args.Scale;
+ var group = args.Effect.Group;
+ var solution = entity.Comp.Solution;
+
+ foreach (var quant in solution.Contents.ToArray())
+ {
+ var proto = _proto.Index<ReagentPrototype>(quant.Reagent.Prototype);
+ if (proto.Metabolisms == null || !proto.Metabolisms.ContainsKey(group))
+ continue;
+
+ if (quantity > 0)
+ _solutionContainer.TryAddReagent(entity, proto.ID, quantity);
+ else
+ _solutionContainer.RemoveReagent(entity, proto.ID, -quantity);
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustReagentsByGroup : EntityEffectBase<AdjustReagentsByGroup>
+{
+
+ /// <summary>
+ /// The metabolism group being adjusted. All reagents in an affected solution with this group will be adjusted.
+ /// </summary>
+ [DataField(required: true)]
+ public ProtoId<MetabolismGroupPrototype> Group;
+
+ [DataField(required: true)]
+ public FixedPoint2 Amount;
+}
--- /dev/null
+using Content.Shared.Database;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Solution;
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AreaReactionEffect : EntityEffectBase<AreaReactionEffect>
+{
+ /// <summary>
+ /// How many seconds will the effect stay, counting after fully spreading.
+ /// </summary>
+ [DataField("duration")] public float Duration = 10;
+
+ /// <summary>
+ /// How big of a reaction scale we need for 1 smoke entity.
+ /// </summary>
+ [DataField] public float OverflowThreshold = 2.5f;
+
+ /// <summary>
+ /// The entity prototype that is being spread over an area.
+ /// </summary>
+ [DataField(required: true)]
+ public EntProtoId PrototypeId;
+
+ /// <summary>
+ /// Sound that will get played when this reaction effect occurs.
+ /// </summary>
+ [DataField(required: true)] public SoundSpecifier Sound = default!;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-area-reaction",
+ ("duration", Duration)
+ );
+
+ public override bool ShouldLog => true;
+
+ public override LogImpact LogImpact => LogImpact.High;
+}
--- /dev/null
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Solution;
+
+// TODO: Energy conservation!!! Once HeatContainers are merged nuke this and everything in SolutionContainerSystem to respect energy conservation!
+/// <summary>
+/// Sets the temperature of this solution to a fixed value.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed class SetSolutionTemperatureEntityEffectSystem : EntityEffectSystem<SolutionComponent, SetSolutionTemperature>
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<SetSolutionTemperature> args)
+ {
+ _solutionContainer.SetTemperature(entity, args.Effect.Temperature);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class SetSolutionTemperature : EntityEffectBase<SetSolutionTemperature>
+{
+ /// <summary>
+ /// The temperature to set the solution to.
+ /// </summary>
+ [DataField(required: true)]
+ public float Temperature;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-set-solution-temperature-effect",
+ ("chance", Probability),
+ ("temperature", Temperature));
+}
+
+/// <summary>
+/// Adjusts the temperature of this solution by a given amount.
+/// The temperature adjustment is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed class AdjustSolutionTemperatureEntityEffectSystem : EntityEffectSystem<SolutionComponent, AdjustSolutionTemperature>
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<AdjustSolutionTemperature> args)
+ {
+ var solution = entity.Comp.Solution;
+ var temperature = Math.Clamp(solution.Temperature + args.Scale * args.Effect.Delta, args.Effect.MinTemp, args.Effect.MaxTemp);
+
+ _solutionContainer.SetTemperature(entity, temperature);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustSolutionTemperature : EntityEffectBase<AdjustSolutionTemperature>
+{
+ /// <summary>
+ /// The change in temperature.
+ /// </summary>
+ [DataField(required: true)]
+ public float Delta;
+
+ /// <summary>
+ /// The minimum temperature this effect can reach.
+ /// </summary>
+ [DataField]
+ public float MinTemp;
+
+ /// <summary>
+ /// The maximum temperature this effect can reach.
+ /// </summary>
+ [DataField]
+ public float MaxTemp = float.PositiveInfinity;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-adjust-solution-temperature-effect",
+ ("chance", Probability),
+ ("deltasign", MathF.Sign(Delta)),
+ ("mintemp", MinTemp),
+ ("maxtemp", MaxTemp));
+}
+
+/// <summary>
+/// Adjusts the thermal energy of this solution by a given amount.
+/// The energy adjustment is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed class AdjustSolutionThermalEnergyEntityEffectSystem : EntityEffectSystem<SolutionComponent, AdjustSolutionThermalEnergy>
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ protected override void Effect(Entity<SolutionComponent> entity, ref EntityEffectEvent<AdjustSolutionThermalEnergy> args)
+ {
+ var solution = entity.Comp.Solution;
+
+ var delta = args.Scale * args.Effect.Delta;
+
+ // Don't adjust thermal energy if we're already at or above max temperature.
+ switch (delta)
+ {
+ case > 0:
+ if (solution.Temperature >= args.Effect.MaxTemp)
+ return;
+ break;
+ case < 0:
+ if (solution.Temperature <= args.Effect.MinTemp)
+ return;
+ break;
+ default:
+ return;
+ }
+
+ _solutionContainer.AddThermalEnergyClamped(entity, delta, args.Effect.MinTemp, args.Effect.MaxTemp);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class AdjustSolutionThermalEnergy : EntityEffectBase<AdjustSolutionThermalEnergy>
+{
+ /// <summary>
+ /// The change in thermal energy.
+ /// </summary>
+ [DataField(required: true)]
+ public float Delta;
+
+ /// <summary>
+ /// The minimum temperature this effect can reach.
+ /// </summary>
+ [DataField]
+ public float MinTemp;
+
+ /// <summary>
+ /// The maximum temperature this effect can reach.
+ /// </summary>
+ [DataField]
+ public float MaxTemp = float.PositiveInfinity;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-adjust-solution-temperature-effect",
+ ("chance", Probability),
+ ("deltasign", MathF.Sign(Delta)),
+ ("mintemp", MinTemp),
+ ("maxtemp", MaxTemp));
+}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// Sets the temperature of the solution involved with the reaction to a new value.
-/// </summary>
-[DataDefinition]
-public sealed partial class SetSolutionTemperatureEffect : EntityEffect
-{
- /// <summary>
- /// The temperature to set the solution to.
- /// </summary>
- [DataField("temperature", required: true)] private float _temperature;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-set-solution-temperature-effect",
- ("chance", Probability), ("temperature", _temperature));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- var solution = reagentArgs.Source;
- if (solution == null)
- return;
-
- solution.Temperature = _temperature;
-
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-}
-
-/// <summary>
-/// Adjusts the temperature of the solution involved in the reaction.
-/// </summary>
-[DataDefinition]
-public sealed partial class AdjustSolutionTemperatureEffect : EntityEffect
-{
- /// <summary>
- /// The change in temperature.
- /// </summary>
- [DataField("delta", required: true)] private float _delta;
-
- /// <summary>
- /// The minimum temperature this effect can reach.
- /// </summary>
- [DataField("minTemp")] private float _minTemp = 0.0f;
-
- /// <summary>
- /// The maximum temperature this effect can reach.
- /// </summary>
- [DataField("maxTemp")] private float _maxTemp = float.PositiveInfinity;
-
- /// <summary>
- /// If true, then scale ranges by intensity. If not, the ranges are the same regardless of reactant amount.
- /// </summary>
- [DataField("scaled")] private bool _scaled;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect",
- ("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- var solution = reagentArgs.Source;
- if (solution == null || solution.Volume == 0)
- return;
-
- var deltaT = _scaled ? _delta * (float) reagentArgs.Quantity : _delta;
- solution.Temperature = Math.Clamp(solution.Temperature + deltaT, _minTemp, _maxTemp);
-
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-}
-
-/// <summary>
-/// Adjusts the thermal energy of the solution involved in the reaction.
-/// </summary>
-public sealed partial class AdjustSolutionThermalEnergyEffect : EntityEffect
-{
- /// <summary>
- /// The change in energy.
- /// </summary>
- [DataField("delta", required: true)] private float _delta;
-
- /// <summary>
- /// The minimum temperature this effect can reach.
- /// </summary>
- [DataField("minTemp")] private float _minTemp = 0.0f;
-
- /// <summary>
- /// The maximum temperature this effect can reach.
- /// </summary>
- [DataField("maxTemp")] private float _maxTemp = float.PositiveInfinity;
-
- /// <summary>
- /// If true, then scale ranges by intensity. If not, the ranges are the same regardless of reactant amount.
- /// </summary>
- [DataField("scaled")] private bool _scaled;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- var solution = reagentArgs.Source;
- if (solution == null || solution.Volume == 0)
- return;
-
- if (_delta > 0 && solution.Temperature >= _maxTemp)
- return;
- if (_delta < 0 && solution.Temperature <= _minTemp)
- return;
-
- var heatCap = solution.GetHeatCapacity(null);
- var deltaT = _scaled
- ? _delta / heatCap * (float) reagentArgs.Quantity
- : _delta / heatCap;
-
- solution.Temperature = Math.Clamp(solution.Temperature + deltaT, _minTemp, _maxTemp);
-
- return;
- }
-
- // TODO: Someone needs to figure out how to do this for non-reagent effects.
- throw new NotImplementedException();
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect",
- ("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp));
-}
--- /dev/null
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Entity effect that specifically deals with new status effects.
+/// </summary>
+/// <typeparam name="T">The entity effect type, typically for status effects which need systems to pass arguments</typeparam>
+public abstract partial class BaseStatusEntityEffect<T> : EntityEffectBase<T> where T : BaseStatusEntityEffect<T>
+{
+ /// <summary>
+ /// How long the modifier applies (in seconds).
+ /// Is scaled by reagent amount if used with an EntityEffectReagentArgs.
+ /// </summary>
+ [DataField]
+ public TimeSpan? Time = TimeSpan.FromSeconds(2);
+
+ /// <summary>
+ /// Should this effect add the status effect, remove time from it, or set its cooldown?
+ /// </summary>
+ [DataField]
+ public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Update;
+
+ /// <summary>
+ /// Delay before the effect starts. If another effect is added with a shorter delay, it takes precedence.
+ /// </summary>
+ [DataField]
+ public TimeSpan Delay;
+}
+
+public enum StatusEffectMetabolismType
+{
+ Update,
+ Add,
+ Remove,
+ Set,
+}
--- /dev/null
+using Content.Shared.Drunk;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies the drunk status effect to this entity.
+/// The duration of the effect is equal to <see cref="Drunk.BoozePower"/> modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class DrunkEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Drunk>
+{
+ [Dependency] private readonly SharedDrunkSystem _drunk = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Drunk> args)
+ {
+ var boozePower = args.Effect.BoozePower * args.Scale;
+
+ _drunk.TryApplyDrunkenness(entity, boozePower);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Drunk : EntityEffectBase<Drunk>
+{
+ /// <summary>
+ /// BoozePower is how long each metabolism cycle will make the drunk effect last for.
+ /// </summary>
+ [DataField]
+ public TimeSpan BoozePower = TimeSpan.FromSeconds(3f);
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-drunk", ("chance", Probability));
+}
--- /dev/null
+using Content.Shared.Electrocution;
+using Content.Shared.StatusEffect;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+// TODO: When Electrocution is moved to new Status, make this use StatusEffectsContainerComponent.
+/// <summary>
+/// Electrocutes this entity for a given amount of damage and time.
+/// The shock damage applied by this effect is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ElectrocuteEntityEffectSystem : EntityEffectSystem<StatusEffectsComponent, Electrocute>
+{
+ [Dependency] private readonly SharedElectrocutionSystem _electrocution = default!;
+
+ // TODO: When electrocution is new status, change this to new status
+ protected override void Effect(Entity<StatusEffectsComponent> entity, ref EntityEffectEvent<Electrocute> args)
+ {
+ var effect = args.Effect;
+
+ _electrocution.TryDoElectrocution(entity, null, (int)(args.Scale * effect.ShockDamage), effect.ElectrocuteTime, effect.Refresh, ignoreInsulation: effect.BypassInsulation);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Electrocute : EntityEffectBase<Electrocute>
+{
+ /// <summary>
+ /// Time we electrocute this entity
+ /// </summary>
+ [DataField] public TimeSpan ElectrocuteTime = TimeSpan.FromSeconds(2);
+
+ /// <summary>
+ /// Shock damage we apply to the entity.
+ /// </summary>
+ [DataField] public int ShockDamage = 5;
+
+ /// <summary>
+ /// Do we refresh the duration? Or add more duration if it already exists.
+ /// </summary>
+ [DataField] public bool Refresh = true;
+
+ /// <summary>
+ /// Should we by bypassing insulation?
+ /// </summary>
+ [DataField] public bool BypassInsulation = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime.TotalSeconds));
+}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.StatusEffect;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.StatusEffects;
-
-/// <summary>
-/// Adds a generic status effect to the entity,
-/// not worrying about things like how to affect the time it lasts for
-/// or component fields or anything. Just adds a component to an entity
-/// for a given time. Easy.
-/// </summary>
-/// <remarks>
-/// Can be used for things like adding accents or something. I don't know. Go wild.
-/// </remarks>
-[Obsolete("Use ModifyStatusEffect with StatusEffectNewSystem instead")]
-public sealed partial class GenericStatusEffect : EntityEffect
-{
- [DataField(required: true)]
- public string Key = default!;
-
- [DataField]
- public string Component = String.Empty;
-
- [DataField]
- public float Time = 2.0f;
-
- /// <remarks>
- /// true - refresh status effect time, false - accumulate status effect time
- /// </remarks>
- [DataField]
- public bool Refresh = true;
-
- /// <summary>
- /// Should this effect add the status effect, remove time from it, or set its cooldown?
- /// </summary>
- [DataField]
- public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var statusSys = args.EntityManager.EntitySysManager.GetEntitySystem<StatusEffectsSystem>();
-
- var time = Time;
- if (args is EntityEffectReagentArgs reagentArgs)
- time *= reagentArgs.Scale.Float();
-
- if (Type == StatusEffectMetabolismType.Add && Component != String.Empty)
- {
- statusSys.TryAddStatusEffect(args.TargetEntity, Key, TimeSpan.FromSeconds(time), Refresh, Component);
- }
- else if (Type == StatusEffectMetabolismType.Remove)
- {
- statusSys.TryRemoveTime(args.TargetEntity, Key, TimeSpan.FromSeconds(time));
- }
- else if (Type == StatusEffectMetabolismType.Set)
- {
- statusSys.TrySetTime(args.TargetEntity, Key, TimeSpan.FromSeconds(time));
- }
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString(
- "reagent-effect-guidebook-status-effect",
- ("chance", Probability),
- ("type", Type),
- ("time", Time),
- ("key", $"reagent-effect-status-effect-{Key}"));
-}
-
-public enum StatusEffectMetabolismType
-{
- Update,
- Add,
- Remove,
- Set
-}
--- /dev/null
+using Content.Shared.StatusEffect;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies a Generic Status Effect to this entity, which is a timed Component.
+/// The amount of time the Component is applied is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+[Obsolete("Use ModifyStatusEffect instead")]
+public sealed partial class GenericStatusEffectEntityEffectSystem : EntityEffectSystem<MetaDataComponent, GenericStatusEffect>
+{
+ [Dependency] private readonly StatusEffectsSystem _status = default!;
+
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<GenericStatusEffect> args)
+ {
+ var time = args.Effect.Time * args.Scale;
+
+ switch (args.Effect.Type)
+ {
+ case StatusEffectMetabolismType.Update:
+ if (args.Effect.Component != String.Empty)
+ _status.TryAddStatusEffect(entity, args.Effect.Key, time, true, args.Effect.Component);
+ break;
+ case StatusEffectMetabolismType.Add:
+ if (args.Effect.Component != String.Empty)
+ _status.TryAddStatusEffect(entity, args.Effect.Key, time, false, args.Effect.Component);
+ break;
+ case StatusEffectMetabolismType.Remove:
+ _status.TryRemoveTime(entity, args.Effect.Key, time);
+ break;
+ case StatusEffectMetabolismType.Set:
+ _status.TrySetTime(entity, args.Effect.Key, time);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class GenericStatusEffect : EntityEffectBase<GenericStatusEffect>
+{
+ [DataField(required: true)]
+ public string Key = default!;
+
+ [DataField]
+ public string Component = String.Empty;
+
+ [DataField]
+ public TimeSpan Time = TimeSpan.FromSeconds(2f);
+
+ /// <summary>
+ /// Should this effect add the status effect, remove time from it, or set its cooldown?
+ /// </summary>
+ [DataField]
+ public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Update;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString(
+ "entity-effect-guidebook-status-effect-old",
+ ("chance", Probability),
+ ("type", Type),
+ ("time", Time.TotalSeconds),
+ ("key", $"entity-effect-status-effect-{Key}"));
+}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Jittering;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.StatusEffects;
-
-/// <summary>
-/// Adds the jitter status effect to a mob.
-/// This doesn't use generic status effects because it needs to
-/// take in some parameters that JitterSystem needs.
-/// </summary>
-public sealed partial class Jitter : EntityEffect
-{
- [DataField]
- public float Amplitude = 10.0f;
-
- [DataField]
- public float Frequency = 4.0f;
-
- [DataField]
- public float Time = 2.0f;
-
- /// <remarks>
- /// true - refresh jitter time, false - accumulate jitter time
- /// </remarks>
- [DataField]
- public bool Refresh = true;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- var time = Time;
- if (args is EntityEffectReagentArgs reagentArgs)
- time *= reagentArgs.Scale.Float();
-
- args.EntityManager.EntitySysManager.GetEntitySystem<SharedJitteringSystem>()
- .DoJitter(args.TargetEntity, TimeSpan.FromSeconds(time), Refresh, Amplitude, Frequency);
- }
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
- Loc.GetString("reagent-effect-guidebook-jittering", ("chance", Probability));
-}
--- /dev/null
+using Content.Shared.Jittering;
+using Content.Shared.StatusEffect;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+// TODO: When Jittering is moved to new Status, make this use StatusEffectsContainerComponent.
+/// <summary>
+/// Applies the Jittering Status Effect to this entity.
+/// The amount of time the Jittering is applied is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class JitterEntityEffectSystem : EntityEffectSystem<StatusEffectsComponent, Jitter>
+{
+ [Dependency] private readonly SharedJitteringSystem _jittering = default!;
+
+ protected override void Effect(Entity<StatusEffectsComponent> entity, ref EntityEffectEvent<Jitter> args)
+ {
+ var time = args.Effect.Time * args.Scale;
+
+ _jittering.DoJitter(entity, TimeSpan.FromSeconds(time), args.Effect.Refresh, args.Effect.Amplitude, args.Effect.Frequency);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Jitter : EntityEffectBase<Jitter>
+{
+ [DataField]
+ public float Amplitude = 10.0f;
+
+ [DataField]
+ public float Frequency = 4.0f;
+
+ [DataField]
+ public float Time = 2.0f;
+
+ /// <remarks>
+ /// true - refresh jitter time, false - accumulate jitter time
+ /// </remarks>
+ [DataField]
+ public bool Refresh = true;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Loc.GetString("entity-effect-guidebook-jittering", ("chance", Probability));
+}
+++ /dev/null
-using Content.Shared.Stunnable;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.StatusEffects;
-
-/// <summary>
-/// Changes the knockdown timer on an entity or causes knockdown.
-/// </summary>
-[UsedImplicitly]
-public sealed partial class ModifyKnockdown : EntityEffect
-{
- /// <summary>
- /// Should we only affect those with crawler component? Note if this is false, it will paralyze non-crawler's instead.
- /// </summary>
- [DataField]
- public bool Crawling;
-
- /// <summary>
- /// Should we drop items when we fall?
- /// </summary>
- [DataField]
- public bool Drop;
-
- /// <summary>
- /// Time for which knockdown should be applied. Behaviour changes according to <see cref="StatusEffectMetabolismType"/>.
- /// </summary>
- [DataField]
- public TimeSpan Time = TimeSpan.FromSeconds(0.5);
-
- /// <summary>
- /// Should this effect add the status effect, remove time from it, or set its cooldown?
- /// </summary>
- [DataField]
- public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
-
- /// <summary>
- /// Should this effect add knockdown?, remove time from it?, or set its cooldown?
- /// </summary>
- [DataField]
- public bool Refresh = true;
-
- /// <inheritdoc />
- public override void Effect(EntityEffectBaseArgs args)
- {
- var stunSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedStunSystem>();
-
- var time = Time;
- if (args is EntityEffectReagentArgs reagentArgs)
- time *= reagentArgs.Scale.Float();
-
- switch (Type)
- {
- case StatusEffectMetabolismType.Update:
- if (Crawling)
- {
- stunSys.TryCrawling(args.TargetEntity, time, drop: Drop);
- }
- else
- {
- stunSys.TryKnockdown(args.TargetEntity, time, drop: Drop);
- }
- break;
- case StatusEffectMetabolismType.Add:
- if (Crawling)
- {
- stunSys.TryCrawling(args.TargetEntity, time, false, drop: Drop);
- }
- else
- {
- stunSys.TryKnockdown(args.TargetEntity, time, false, drop: Drop);
- }
- break;
- case StatusEffectMetabolismType.Remove:
- stunSys.AddKnockdownTime(args.TargetEntity, -time);
- break;
- case StatusEffectMetabolismType.Set:
- if (Crawling)
- {
- stunSys.TryCrawling(args.TargetEntity, time, drop: Drop);
- }
- else
- {
- stunSys.TryKnockdown(args.TargetEntity, time, drop: Drop);
- }
- stunSys.SetKnockdownTime(args.TargetEntity, time);
- break;
- }
- }
-
- /// <inheritdoc />
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString(
- "reagent-effect-guidebook-knockdown",
- ("chance", Probability),
- ("type", Type),
- ("time", Time.TotalSeconds)
- );
-}
--- /dev/null
+using Content.Shared.Standing;
+using Content.Shared.Stunnable;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies knockdown to this entity.
+/// Duration is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyKnockdownEntityEffectSystem : EntityEffectSystem<StandingStateComponent, ModifyKnockdown>
+{
+ [Dependency] private readonly SharedStunSystem _stun = default!;
+
+ protected override void Effect(Entity<StandingStateComponent> entity, ref EntityEffectEvent<ModifyKnockdown> args)
+ {
+ var time = args.Effect.Time * args.Scale;
+
+ switch (args.Effect.Type)
+ {
+ case StatusEffectMetabolismType.Update:
+ if (args.Effect.Crawling)
+ _stun.TryCrawling(entity.Owner, time, drop: args.Effect.Drop);
+ else
+ _stun.TryKnockdown(entity.Owner, time, drop: args.Effect.Drop);
+ break;
+ case StatusEffectMetabolismType.Add:
+ if (args.Effect.Crawling)
+ _stun.TryCrawling(entity.Owner, time, false, drop: args.Effect.Drop);
+ else
+ _stun.TryKnockdown(entity.Owner, time, false, drop: args.Effect.Drop);
+ break;
+ case StatusEffectMetabolismType.Remove:
+ _stun.AddKnockdownTime(entity.Owner, - time ?? TimeSpan.Zero);
+ break;
+ case StatusEffectMetabolismType.Set:
+ if (args.Effect.Crawling)
+ _stun.TryCrawling(entity.Owner, drop: args.Effect.Drop);
+ else
+ _stun.TryKnockdown(entity.Owner, time, drop: args.Effect.Drop);
+ _stun.SetKnockdownTime(entity.Owner, time ?? TimeSpan.Zero);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyKnockdown : BaseStatusEntityEffect<ModifyKnockdown>
+{
+ /// <summary>
+ /// Should we only affect those with crawler component? Note if this is false, it will paralyze non-crawler's instead.
+ /// </summary>
+ [DataField]
+ public bool Crawling;
+
+ /// <summary>
+ /// Should we drop items when we fall?
+ /// </summary>
+ [DataField]
+ public bool Drop;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Time == null
+ ? null
+ : Loc.GetString(
+ "entity-effect-guidebook-knockdown",
+ ("chance", Probability),
+ ("type", Type),
+ ("time", Time.Value.TotalSeconds)
+ );
+}
--- /dev/null
+using Content.Shared.StatusEffectNew;
+using Content.Shared.StatusEffectNew.Components;
+using Content.Shared.Stunnable;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies the paralysis status effect to this entity.
+/// Duration is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyParalysisEntityEffectSystem : EntityEffectSystem<StatusEffectContainerComponent, ModifyParalysis>
+{
+ [Dependency] private readonly StatusEffectsSystem _status = default!;
+ [Dependency] private readonly SharedStunSystem _stun = default!;
+
+ protected override void Effect(Entity<StatusEffectContainerComponent> entity, ref EntityEffectEvent<ModifyParalysis> args)
+ {
+ var time = args.Effect.Time * args.Scale;
+
+ switch (args.Effect.Type)
+ {
+ case StatusEffectMetabolismType.Update:
+ _stun.TryUpdateParalyzeDuration(entity, time);
+ break;
+ case StatusEffectMetabolismType.Add:
+ _stun.TryAddParalyzeDuration(entity, time);
+ break;
+ case StatusEffectMetabolismType.Remove:
+ _status.TryRemoveTime(entity, SharedStunSystem.StunId, time);
+ break;
+ case StatusEffectMetabolismType.Set:
+ _status.TrySetStatusEffectDuration(entity, SharedStunSystem.StunId, time);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyParalysis : BaseStatusEntityEffect<ModifyParalysis>
+{
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Time == null
+ ? null // Not gonna make a whole new looc for something that shouldn't ever exist.
+ : Loc.GetString(
+ "entity-effect-guidebook-paralyze",
+ ("chance", Probability),
+ ("time", Time.Value.TotalSeconds)
+ );
+}
+++ /dev/null
-using Content.Shared.StatusEffectNew;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects.StatusEffects;
-
-/// <summary>
-/// Changes status effects on entities: Adds, removes or sets time.
-/// </summary>
-[UsedImplicitly]
-public sealed partial class ModifyStatusEffect : EntityEffect
-{
- [DataField(required: true)]
- public EntProtoId EffectProto;
-
- /// <summary>
- /// Time for which status effect should be applied. Behaviour changes according to <see cref="Refresh" />.
- /// </summary>
- [DataField]
- public float Time = 2.0f;
-
- /// <summary>
- /// Delay before the effect starts. If another effect is added with a shorter delay, it takes precedence.
- /// </summary>
- [DataField]
- public float Delay = 0f;
-
- /// <summary>
- /// Should this effect add the status effect, remove time from it, or set its cooldown?
- /// </summary>
- [DataField]
- public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
-
- /// <inheritdoc />
- public override void Effect(EntityEffectBaseArgs args)
- {
- var statusSys = args.EntityManager.EntitySysManager.GetEntitySystem<StatusEffectsSystem>();
-
- var time = Time;
- if (args is EntityEffectReagentArgs reagentArgs)
- time *= reagentArgs.Scale.Float();
-
- var duration = TimeSpan.FromSeconds(time);
- switch (Type)
- {
- case StatusEffectMetabolismType.Update:
- statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null);
- break;
- case StatusEffectMetabolismType.Add:
- statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null);
- break;
- case StatusEffectMetabolismType.Remove:
- statusSys.TryAddTime(args.TargetEntity, EffectProto, -duration);
- break;
- case StatusEffectMetabolismType.Set:
- statusSys.TrySetStatusEffectDuration(args.TargetEntity, EffectProto, duration, TimeSpan.FromSeconds(Delay));
- break;
- }
- }
-
- /// <inheritdoc />
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
- Delay > 0
- ? Loc.GetString(
- "reagent-effect-guidebook-status-effect-delay",
- ("chance", Probability),
- ("type", Type),
- ("time", Time),
- ("key", prototype.Index(EffectProto).Name),
- ("delay", Delay))
- : Loc.GetString(
- "reagent-effect-guidebook-status-effect",
- ("chance", Probability),
- ("type", Type),
- ("time", Time),
- ("key", prototype.Index(EffectProto).Name)
- );
-}
--- /dev/null
+using Content.Shared.StatusEffectNew;
+using Content.Shared.StatusEffectNew.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies a given status effect to this entity.
+/// Duration is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class ModifyStatusEffectEntityEffectSystem : EntityEffectSystem<StatusEffectContainerComponent, ModifyStatusEffect>
+{
+ [Dependency] private readonly StatusEffectsSystem _status = default!;
+
+ protected override void Effect(Entity<StatusEffectContainerComponent> entity, ref EntityEffectEvent<ModifyStatusEffect> args)
+ {
+ var time = args.Effect.Time * args.Scale;
+ var delay = args.Effect.Delay;
+
+ switch (args.Effect.Type)
+ {
+ case StatusEffectMetabolismType.Update:
+ _status.TryUpdateStatusEffectDuration(entity, args.Effect.EffectProto, time, delay);
+ break;
+ case StatusEffectMetabolismType.Add:
+ if (time != null)
+ _status.TryAddStatusEffectDuration(entity, args.Effect.EffectProto, time.Value, delay);
+ else
+ _status.TryUpdateStatusEffectDuration(entity, args.Effect.EffectProto, time, delay);
+ break;
+ case StatusEffectMetabolismType.Remove:
+ _status.TryRemoveTime(entity, args.Effect.EffectProto, time);
+ break;
+ case StatusEffectMetabolismType.Set:
+ _status.TrySetStatusEffectDuration(entity, args.Effect.EffectProto, time, delay);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ModifyStatusEffect : BaseStatusEntityEffect<ModifyStatusEffect>
+{
+ /// <summary>
+ /// Prototype of the status effect we're modifying.
+ /// </summary>
+ [DataField(required: true)]
+ public EntProtoId EffectProto;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Time == null
+ ? Loc.GetString(
+ "entity-effect-guidebook-status-effect-indef",
+ ("chance", Probability),
+ ("type", Type),
+ ("key", prototype.Index(EffectProto).Name),
+ ("delay", Delay.TotalSeconds))
+ : Loc.GetString(
+ "entity-effect-guidebook-status-effect",
+ ("chance", Probability),
+ ("type", Type),
+ ("time", Time.Value.TotalSeconds),
+ ("key", prototype.Index(EffectProto).Name),
+ ("delay", Delay.TotalSeconds));
+}
--- /dev/null
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Content.Shared.StatusEffectNew;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
+
+/// <summary>
+/// Applies a given movement speed modifier status effect to this entity.
+/// Duration is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class MovementSpeedModifierEntityEffectSystem : EntityEffectSystem<MovementSpeedModifierComponent, MovementSpeedModifier>
+{
+ [Dependency] private readonly StatusEffectsSystem _status = default!;
+ [Dependency] private readonly MovementModStatusSystem _movementModStatus = default!;
+
+ protected override void Effect(Entity<MovementSpeedModifierComponent> entity, ref EntityEffectEvent<MovementSpeedModifier> args)
+ {
+ var proto = args.Effect.EffectProto;
+ var sprintMod = args.Effect.SprintSpeedModifier;
+ var walkMod = args.Effect.WalkSpeedModifier;
+
+ switch (args.Effect.Type)
+ {
+ case StatusEffectMetabolismType.Update:
+ _movementModStatus.TryUpdateMovementSpeedModDuration(
+ entity,
+ proto,
+ args.Effect.Time * args.Scale,
+ sprintMod,
+ walkMod);
+ break;
+ case StatusEffectMetabolismType.Add:
+ if (args.Effect.Time != null)
+ {
+ _movementModStatus.TryAddMovementSpeedModDuration(
+ entity,
+ proto,
+ args.Effect.Time.Value * args.Scale,
+ sprintMod,
+ walkMod);
+ }
+ else
+ {
+ _movementModStatus.TryUpdateMovementSpeedModDuration(
+ entity,
+ proto,
+ args.Effect.Time * args.Scale,
+ sprintMod,
+ walkMod);
+ }
+ break;
+ case StatusEffectMetabolismType.Remove:
+ _status.TryRemoveTime(entity, args.Effect.EffectProto, args.Effect.Time * args.Scale);
+ break;
+ case StatusEffectMetabolismType.Set:
+ _status.TrySetStatusEffectDuration(entity, proto, args.Effect.Time * args.Scale);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class MovementSpeedModifier : BaseStatusEntityEffect<MovementSpeedModifier>
+{
+ /// <summary>
+ /// How much the entities' walk speed is multiplied by.
+ /// </summary>
+ [DataField]
+ public float WalkSpeedModifier = 1f;
+
+ /// <summary>
+ /// How much the entities' run speed is multiplied by.
+ /// </summary>
+ [DataField]
+ public float SprintSpeedModifier = 1f;
+
+ /// <summary>
+ /// Movement speed modifier prototype we're adding. Adding in case we ever want more than one prototype that boosts speed.
+ /// </summary>
+ [DataField]
+ public EntProtoId EffectProto = MovementModStatusSystem.ReagentSpeed;
+
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+ Time == null
+ ? null // Not gonna make a whole new looc for something that shouldn't ever exist.
+ : Loc.GetString("entity-effect-guidebook-movespeed-modifier",
+ ("chance", Probability),
+ ("sprintspeed", SprintSpeedModifier),
+ ("time", Time.Value.TotalSeconds));
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// A brief summary of the effect.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T, TEffect}"/>
+public sealed partial class TemplateEntityEffectSystem : EntityEffectSystem<MetaDataComponent, Template>
+{
+ protected override void Effect(Entity<MetaDataComponent> entity, ref EntityEffectEvent<Template> args)
+ {
+ // Effect goes here.
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Template : EntityEffectBase<Template>
+{
+ public override string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null;
+}
--- /dev/null
+using Content.Shared.Database;
+using Content.Shared.Emp;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Transform;
+
+/// <summary>
+/// Creates an EMP at this entity's coordinates.
+/// Range is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class EmpEntityEffectSystem : EntityEffectSystem<TransformComponent, Emp>
+{
+ [Dependency] private readonly SharedEmpSystem _emp = default!;
+ [Dependency] private readonly SharedTransformSystem _xform = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<Emp> args)
+ {
+ var range = MathF.Min(args.Effect.RangeModifier * args.Scale, args.Effect.MaxRange);
+
+ _emp.EmpPulse(_xform.GetMapCoordinates(entity, xform: entity.Comp), range, args.Effect.EnergyConsumption, args.Effect.Duration);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Emp : EntityEffectBase<Emp>
+{
+ /// <summary>
+ /// Impulse range per unit of quantity
+ /// </summary>
+ [DataField]
+ public float RangeModifier = 0.5f;
+
+ /// <summary>
+ /// Maximum impulse range
+ /// </summary>
+ [DataField]
+ public float MaxRange = 10;
+
+ /// <summary>
+ /// How much energy will be drain from sources
+ /// </summary>
+ [DataField]
+ public float EnergyConsumption = 12500;
+
+ /// <summary>
+ /// Amount of time entities will be disabled
+ /// </summary>
+ [DataField]
+ public TimeSpan Duration = TimeSpan.FromSeconds(15);
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-emp-reaction-effect", ("chance", Probability));
+
+ public override bool ShouldLog => true;
+
+ public override LogImpact LogImpact => LogImpact.Medium;
+}
-using Content.Shared.Database;
+using Content.Shared.Database;
using Content.Shared.Explosion;
using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using System.Text.Json.Serialization;
-namespace Content.Shared.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects.Transform;
-[DataDefinition]
-public sealed partial class ExplosionReactionEffect : EventEntityEffect<ExplosionReactionEffect>
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class ExplosionEffect : EntityEffectBase<ExplosionEffect>
{
/// <summary>
/// The type of explosion. Determines damage types and tile break chance scaling.
/// </summary>
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<ExplosionPrototype>))]
- public string ExplosionType = default!;
+ [DataField(required: true)]
+ public ProtoId<ExplosionPrototype> ExplosionType;
/// <summary>
/// The max intensity the explosion can have at a given tile. Places an upper limit of damage and tile break
[DataField]
public float TileBreakScale = 1f;
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-explosion-reaction-effect", ("chance", Probability));
+
public override bool ShouldLog => true;
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-explosion-reaction-effect", ("chance", Probability));
public override LogImpact LogImpact => LogImpact.High;
}
--- /dev/null
+using Content.Shared.Flash;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.Transform;
+
+/// <summary>
+/// Creates a Flash at this entity's coordinates.
+/// Range is modified by scale.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class FlashEntityEffectSystem : EntityEffectSystem<TransformComponent, Flash>
+{
+ [Dependency] private readonly SharedFlashSystem _flash = default!;
+ [Dependency] private readonly SharedTransformSystem _xform = default!;
+ [Dependency] private readonly SharedPointLightSystem _pointLight = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<Flash> args)
+ {
+ var range = MathF.Min(args.Scale * args.Effect.RangePerUnit, args.Effect.MaxRange);
+
+ _flash.FlashArea(
+ entity,
+ null,
+ range,
+ args.Effect.Duration,
+ slowTo: args.Effect.SlowTo,
+ sound: args.Effect.Sound);
+
+ if (args.Effect.FlashEffectPrototype == null)
+ return;
+
+ var uid = PredictedSpawnAtPosition(args.Effect.FlashEffectPrototype, _xform.GetMoverCoordinates(entity));
+
+ _pointLight.SetRadius(uid, MathF.Max(1.1f, range));
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class Flash : EntityEffectBase<Flash>
+{
+ /// <summary>
+ /// Flash range per unit of reagent.
+ /// </summary>
+ [DataField]
+ public float RangePerUnit = 0.2f;
+
+ /// <summary>
+ /// Maximum flash range.
+ /// </summary>
+ [DataField]
+ public float MaxRange = 10f;
+
+ /// <summary>
+ /// How much to entities are slowed down.
+ /// </summary>
+ [DataField]
+ public float SlowTo = 0.5f;
+
+ /// <summary>
+ /// The time entities will be flashed.
+ /// The default is chosen to be better than the hand flash so it is worth using it for grenades etc.
+ /// </summary>
+ [DataField]
+ public TimeSpan Duration = TimeSpan.FromSeconds(4);
+
+ /// <summary>
+ /// The prototype ID used for the visual effect.
+ /// </summary>
+ [DataField]
+ public EntProtoId? FlashEffectPrototype = "ReactionFlash";
+
+ /// <summary>
+ /// The sound the flash creates.
+ /// </summary>
+ [DataField]
+ public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/flash.ogg");
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-flash-reaction-effect", ("chance", Probability));
+}
--- /dev/null
+using Content.Shared.Popups;
+using Robust.Shared.Network;
+using Robust.Shared.Random;
+
+namespace Content.Shared.EntityEffects.Effects.Transform;
+
+/// <summary>
+/// Creates a text popup to appear at this entity's coordinates.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
+public sealed partial class PopupMessageEntityEffectSystem : EntityEffectSystem<TransformComponent, PopupMessage>
+{
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+ protected override void Effect(Entity<TransformComponent> entity, ref EntityEffectEvent<PopupMessage> args)
+ {
+ // TODO: When we get proper random prediction remove this check.
+ if (_net.IsClient)
+ return;
+
+ var msg = _random.Pick(args.Effect.Messages);
+
+ switch (args.Effect.Type)
+ {
+ case PopupRecipients.Local:
+ _popup.PopupEntity(Loc.GetString(msg, ("entity", entity)), entity, entity, args.Effect.VisualType);
+ break;
+ case PopupRecipients.Pvs:
+ _popup.PopupEntity(Loc.GetString(msg, ("entity", entity)), entity, args.Effect.VisualType);
+ break;
+ }
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class PopupMessage : EntityEffectBase<PopupMessage>
+{
+ /// <summary>
+ /// Array of messages that can popup.
+ /// Only one is chosen when the effect is applied.
+ /// </summary>
+ [DataField(required: true)]
+ public string[] Messages = default!;
+
+ /// <summary>
+ /// Whether to just the entity we're affecting, or everyone around them.
+ /// </summary>
+ [DataField]
+ public PopupRecipients Type = PopupRecipients.Local;
+
+ /// <summary>
+ /// Size of the popup.
+ /// </summary>
+ [DataField]
+ public PopupType VisualType = PopupType.Small;
+}
+
+public enum PopupRecipients
+{
+ Pvs,
+ Local
+}
--- /dev/null
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Washes the cream pie off of this entity face.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T, TEffect}"/>
+/// TODO: This can probably be made into a generic "CleanEntityEffect" which multiple components listen to...
+public sealed partial class WashCreamPieEntityEffectSystem : EntityEffectSystem<CreamPiedComponent, WashCreamPie>
+{
+ [Dependency] private readonly SharedCreamPieSystem _creamPie = default!;
+
+ protected override void Effect(Entity<CreamPiedComponent> entity, ref EntityEffectEvent<WashCreamPie> args)
+ {
+ _creamPie.SetCreamPied(entity, entity.Comp, false);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class WashCreamPie : EntityEffectBase<WashCreamPie>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-wash-cream-pie-reaction", ("chance", Probability));
+}
+++ /dev/null
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-public sealed partial class WashCreamPieReaction : EntityEffect
-{
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
- => Loc.GetString("reagent-effect-guidebook-wash-cream-pie-reaction", ("chance", Probability));
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (!args.EntityManager.TryGetComponent(args.TargetEntity, out CreamPiedComponent? creamPied)) return;
-
- args.EntityManager.System<SharedCreamPieSystem>().SetCreamPied(args.TargetEntity, creamPied, false);
- }
-}
+++ /dev/null
-using Content.Shared.Inventory;
-using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects.Effects;
-
-/// <summary>
-/// A reaction effect that spawns a PrototypeID in the entity's Slot, and attempts to consume the reagent if EntityEffectReagentArgs.
-/// Used to implement the water droplet effect for arachnids.
-/// </summary>
-public sealed partial class WearableReaction : EntityEffect
-{
- /// <summary>
- /// Minimum quantity of reagent required to trigger this effect.
- /// Only used with EntityEffectReagentArgs.
- /// </summary>
- [DataField]
- public float AmountThreshold = 1f;
-
- /// <summary>
- /// Slot to spawn the item into.
- /// </summary>
- [DataField(required: true)]
- public string Slot;
-
- /// <summary>
- /// Prototype ID of item to spawn.
- /// </summary>
- [DataField(required: true)]
- public string PrototypeID;
-
- protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null;
-
- public override void Effect(EntityEffectBaseArgs args)
- {
- // SpawnItemInSlot returns false if slot is already occupied
- if (args.EntityManager.System<InventorySystem>().SpawnItemInSlot(args.TargetEntity, Slot, PrototypeID))
- {
- if (args is EntityEffectReagentArgs reagentArgs)
- {
- if (reagentArgs.Reagent == null || reagentArgs.Quantity < AmountThreshold)
- return;
- reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, AmountThreshold);
- }
- }
- }
-}
--- /dev/null
+using Content.Shared.Mobs.Components;
+using Content.Shared.Zombies;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Causes the zombie infection on this entity.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T, TEffect}"/>
+public sealed partial class CauseZombieInfectionEntityEffectsSystem : EntityEffectSystem<MobStateComponent, CauseZombieInfection>
+{
+ // MobState because you have to die to become a zombie...
+ protected override void Effect(Entity<MobStateComponent> entity, ref EntityEffectEvent<CauseZombieInfection> args)
+ {
+ if (HasComp<ZombieImmuneComponent>(entity) || HasComp<IncurableZombieComponent>(entity))
+ return;
+
+ EnsureComp<ZombifyOnDeathComponent>(entity);
+ EnsureComp<PendingZombieComponent>(entity);
+ }
+}
+
+/// <summary>
+/// Cures the Zombie infection on this entity and optionally inoculates them against future infection.
+/// </summary>
+/// <inheritdoc cref="EntityEffectSystem{T, TEffect}"/>
+public sealed partial class CureZombieInfectionEntityEffectsSystem : EntityEffectSystem<MobStateComponent, CureZombieInfection>
+{
+ // MobState because you have to die to become a zombie...
+ protected override void Effect(Entity<MobStateComponent> entity, ref EntityEffectEvent<CureZombieInfection> args)
+ {
+ if (HasComp<IncurableZombieComponent>(entity))
+ return;
+
+ RemComp<ZombifyOnDeathComponent>(entity);
+ RemComp<PendingZombieComponent>(entity);
+
+ if (args.Effect.Innoculate)
+ EnsureComp<ZombieImmuneComponent>(entity);
+ }
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class CauseZombieInfection : EntityEffectBase<CauseZombieInfection>
+{
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ => Loc.GetString("entity-effect-guidebook-cause-zombie-infection", ("chance", Probability));
+}
+
+/// <inheritdoc cref="EntityEffect"/>
+public sealed partial class CureZombieInfection : EntityEffectBase<CureZombieInfection>
+{
+ /// <summary>
+ /// Do we also protect against future infections?
+ /// </summary>
+ [DataField]
+ public bool Innoculate;
+
+ public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ if (Innoculate)
+ return Loc.GetString("entity-effect-guidebook-innoculate-zombie-infection", ("chance", Probability));
+
+ return Loc.GetString("entity-effect-guidebook-cure-zombie-infection", ("chance", Probability));
+ }
+}
+++ /dev/null
-using System.Linq;
-using System.Text.Json.Serialization;
-using Content.Shared.Chemistry;
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Database;
-using Content.Shared.FixedPoint;
-using Content.Shared.Localizations;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Toolshed.TypeParsers;
-
-namespace Content.Shared.EntityEffects;
-
-/// <summary>
-/// Entity effects describe behavior that occurs on different kinds of triggers, e.g. when a reagent is ingested and metabolized by some
-/// organ. They only trigger when all of <see cref="Conditions"/> are satisfied.
-/// </summary>
-[ImplicitDataDefinitionForInheritors]
-[MeansImplicitUse]
-public abstract partial class EntityEffect
-{
- private protected string _id => this.GetType().Name;
- /// <summary>
- /// The list of conditions required for the effect to activate. Not required.
- /// </summary>
- [DataField("conditions")]
- public EntityEffectCondition[]? Conditions;
-
- public virtual string ReagentEffectFormat => "guidebook-reagent-effect-description";
-
- protected abstract string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys);
-
- /// <summary>
- /// What's the chance, from 0 to 1, that this effect will occur?
- /// </summary>
- [DataField("probability")]
- public float Probability = 1.0f;
-
- public virtual LogImpact LogImpact { get; private set; } = LogImpact.Low;
-
- /// <summary>
- /// Should this entity effect log at all?
- /// </summary>
- public virtual bool ShouldLog { get; private set; } = false;
-
- public abstract void Effect(EntityEffectBaseArgs args);
-
- /// <summary>
- /// Produces a localized, bbcode'd guidebook description for this effect.
- /// </summary>
- /// <returns></returns>
- public string? GuidebookEffectDescription(IPrototypeManager prototype, IEntitySystemManager entSys)
- {
- var effect = ReagentEffectGuidebookText(prototype, entSys);
- if (effect is null)
- return null;
-
- return Loc.GetString(ReagentEffectFormat, ("effect", effect), ("chance", Probability),
- ("conditionCount", Conditions?.Length ?? 0),
- ("conditions",
- ContentLocalizationManager.FormatList(Conditions?.Select(x => x.GuidebookExplanation(prototype)).ToList() ??
- new List<string>())));
- }
-}
-
-public static class EntityEffectExt
-{
- public static bool ShouldApply(this EntityEffect effect, EntityEffectBaseArgs args,
- IRobustRandom? random = null)
- {
- if (random == null)
- random = IoCManager.Resolve<IRobustRandom>();
-
- if (effect.Probability < 1.0f && !random.Prob(effect.Probability))
- return false;
-
- if (effect.Conditions != null)
- {
- foreach (var cond in effect.Conditions)
- {
- if (!cond.Condition(args))
- return false;
- }
- }
-
- return true;
- }
-}
-
-[ByRefEvent]
-public struct ExecuteEntityEffectEvent<T> where T : EntityEffect
-{
- public T Effect;
- public EntityEffectBaseArgs Args;
-
- public ExecuteEntityEffectEvent(T effect, EntityEffectBaseArgs args)
- {
- Effect = effect;
- Args = args;
- }
-}
-
-/// <summary>
-/// EntityEffectBaseArgs only contains the target of an effect.
-/// If a trigger wants to include more info (e.g. the quantity of the chemical triggering the effect), it can be extended (see EntityEffectReagentArgs).
-/// </summary>
-public record class EntityEffectBaseArgs
-{
- public EntityUid TargetEntity;
-
- public IEntityManager EntityManager = default!;
-
- public EntityEffectBaseArgs(EntityUid targetEntity, IEntityManager entityManager)
- {
- TargetEntity = targetEntity;
- EntityManager = entityManager;
- }
-}
-
-public record class EntityEffectReagentArgs : EntityEffectBaseArgs
-{
- public EntityUid? OrganEntity;
-
- public Solution? Source;
-
- public FixedPoint2 Quantity;
-
- public ReagentPrototype? Reagent;
-
- public ReactionMethod? Method;
-
- public FixedPoint2 Scale;
-
- public EntityEffectReagentArgs(EntityUid targetEntity, IEntityManager entityManager, EntityUid? organEntity, Solution? source, FixedPoint2 quantity, ReagentPrototype? reagent, ReactionMethod? method, FixedPoint2 scale) : base(targetEntity, entityManager)
- {
- OrganEntity = organEntity;
- Source = source;
- Quantity = quantity;
- Reagent = reagent;
- Method = method;
- Scale = scale;
- }
-}
+++ /dev/null
-using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.EntityEffects;
-
-[ImplicitDataDefinitionForInheritors]
-[MeansImplicitUse]
-public abstract partial class EntityEffectCondition
-{
- [JsonPropertyName("id")] private protected string _id => this.GetType().Name;
-
- public abstract bool Condition(EntityEffectBaseArgs args);
-
- /// <summary>
- /// Effect explanations are of the form "[chance to] [action] when [condition] and [condition]"
- /// </summary>
- /// <param name="prototype"></param>
- /// <returns></returns>
- public abstract string GuidebookExplanation(IPrototypeManager prototype);
-}
-
-[ByRefEvent]
-public struct CheckEntityEffectConditionEvent<T> where T : EntityEffectCondition
-{
- public T Condition;
- public EntityEffectBaseArgs Args;
- public bool Result;
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects;
-
-public abstract partial class EventEntityEffect<T> : EntityEffect where T : EntityEffect
-{
- public override void Effect(EntityEffectBaseArgs args)
- {
- if (this is not T type)
- return;
- var ev = new ExecuteEntityEffectEvent<T>(type, args);
- args.EntityManager.EventBus.RaiseEvent(EventSource.Local, ref ev);
- }
-}
+++ /dev/null
-namespace Content.Shared.EntityEffects;
-
-public abstract partial class EventEntityEffectCondition<T> : EntityEffectCondition where T : EventEntityEffectCondition<T>
-{
- public override bool Condition(EntityEffectBaseArgs args)
- {
- if (this is not T type)
- return false;
-
- var evt = new CheckEntityEffectConditionEvent<T> { Condition = type, Args = args };
- args.EntityManager.EventBus.RaiseEvent(EventSource.Local, ref evt);
- return evt.Result;
- }
-}
--- /dev/null
+using System.Linq;
+using Content.Shared.Administration.Logs;
+using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Database;
+using Content.Shared.EntityConditions;
+using Content.Shared.Localizations;
+using Content.Shared.Random.Helpers;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.EntityEffects;
+
+/// <summary>
+/// This handles entity effects.
+/// Specifically it handles the receiving of events for causing entity effects, and provides
+/// public API for other systems to take advantage of entity effects.
+/// </summary>
+public sealed partial class SharedEntityEffectsSystem : EntitySystem, IEntityEffectRaiser
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly ISharedAdminLogManager _adminLog = default!;
+ [Dependency] private readonly SharedEntityConditionsSystem _condition = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<ReactiveComponent, ReactionEntityEvent>(OnReactive);
+ }
+
+ private void OnReactive(Entity<ReactiveComponent> entity, ref ReactionEntityEvent args)
+ {
+ if (args.Reagent.ReactiveEffects == null || entity.Comp.ReactiveGroups == null)
+ return;
+
+ var scale = args.ReagentQuantity.Quantity.Float();
+
+ foreach (var (key, val) in args.Reagent.ReactiveEffects)
+ {
+ if (!val.Methods.Contains(args.Method))
+ continue;
+
+ if (!entity.Comp.ReactiveGroups.TryGetValue(key, out var group))
+ continue;
+
+ if (!group.Contains(args.Method))
+ continue;
+
+ ApplyEffects(entity, val.Effects, scale);
+ }
+
+ if (entity.Comp.Reactions == null)
+ return;
+
+ foreach (var entry in entity.Comp.Reactions)
+ {
+ if (!entry.Methods.Contains(args.Method))
+ continue;
+
+ if (entry.Reagents == null || entry.Reagents.Contains(args.Reagent.ID))
+ ApplyEffects(entity, entry.Effects, scale);
+ }
+ }
+
+ /// <summary>
+ /// Applies a list of entity effects to a target entity.
+ /// </summary>
+ /// <param name="target">Entity being targeted by the effects</param>
+ /// <param name="effects">Effects we're applying to the entity</param>
+ /// <param name="scale">Optional scale multiplier for the effects</param>
+ public void ApplyEffects(EntityUid target, EntityEffect[] effects, float scale = 1f)
+ {
+ // do all effects, if conditions apply
+ foreach (var effect in effects)
+ {
+ TryApplyEffect(target, effect, scale);
+ }
+ }
+
+ /// <summary>
+ /// Applies an entity effect to a target if all conditions pass.
+ /// </summary>
+ /// <param name="target">Target we're applying an effect to</param>
+ /// <param name="effect">Effect we're applying</param>
+ /// <param name="scale">Optional scale multiplier for the effect. Not all </param>
+ /// <returns>True if all conditions pass!</returns>
+ public bool TryApplyEffect(EntityUid target, EntityEffect effect, float scale = 1f)
+ {
+ if (scale < effect.MinScale)
+ return false;
+
+ // TODO: Replace with proper random prediciton when it exists.
+ if (effect.Probability <= 1f)
+ {
+ var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(target).Id, 0 });
+ var rand = new System.Random(seed);
+ if (!rand.Prob(effect.Probability))
+ return false;
+ }
+
+ // See if conditions apply
+ if (!_condition.TryConditions(target, effect.Conditions))
+ return false;
+
+ ApplyEffect(target, effect, scale);
+ return true;
+ }
+
+ /// <summary>
+ /// Applies an <see cref="EntityEffect"/> to a given target.
+ /// This doesn't check conditions so you should only call this if you know what you're doing!
+ /// </summary>
+ /// <param name="target">Target we're applying an effect to</param>
+ /// <param name="effect">Effect we're applying</param>
+ /// <param name="scale">Optional scale multiplier for the effect. Not all </param>
+ public void ApplyEffect(EntityUid target, EntityEffect effect, float scale = 1f)
+ {
+ // Clamp the scale if the effect doesn't allow scaling.
+ if (!effect.Scaling)
+ scale = Math.Min(scale, 1f);
+
+ if (effect.ShouldLog)
+ {
+ _adminLog.Add(
+ LogType.EntityEffect,
+ effect.LogImpact,
+ $"Entity effect {effect.GetType().Name:effect}"
+ + $" applied on entity {target:entity}"
+ + $" at {Transform(target).Coordinates:coordinates}"
+ + $" with a scale multiplier of {scale}"
+ );
+ }
+
+ effect.RaiseEvent(target, this, scale);
+ }
+
+ /// <summary>
+ /// Raises an effect to an entity. You should not be calling this unless you know what you're doing.
+ /// </summary>
+ public void RaiseEffectEvent<T>(EntityUid target, T effect, float scale) where T : EntityEffectBase<T>
+ {
+ var effectEv = new EntityEffectEvent<T>(effect, scale);
+ RaiseLocalEvent(target, ref effectEv);
+ }
+}
+
+/// <summary>
+/// This is a basic abstract entity effect containing all the data an entity effect needs to affect entities with effects...
+/// </summary>
+/// <typeparam name="T">The Component that is required for the effect</typeparam>
+/// <typeparam name="TEffect">The Entity Effect itself</typeparam>
+public abstract partial class EntityEffectSystem<T, TEffect> : EntitySystem where T : Component where TEffect : EntityEffectBase<TEffect>
+{
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<T, EntityEffectEvent<TEffect>>(Effect);
+ }
+
+ protected abstract void Effect(Entity<T> entity, ref EntityEffectEvent<TEffect> args);
+}
+
+/// <summary>
+/// Used to raise an EntityEffect without losing the type of effect.
+/// </summary>
+public interface IEntityEffectRaiser
+{
+ void RaiseEffectEvent<T>(EntityUid target, T effect, float scale) where T : EntityEffectBase<T>;
+}
+
+/// <summary>
+/// Used to store an <see cref="EntityEffect"/> so it can be raised without losing the type of the condition.
+/// </summary>
+/// <typeparam name="T">The Condition wer are raising.</typeparam>
+public abstract partial class EntityEffectBase<T> : EntityEffect where T : EntityEffectBase<T>
+{
+ public override void RaiseEvent(EntityUid target, IEntityEffectRaiser raiser, float scale)
+ {
+ if (this is not T type)
+ return;
+
+ raiser.RaiseEffectEvent(target, type, scale);
+ }
+}
+
+/// <summary>
+/// A basic instantaneous effect which can be applied to an entity via events.
+/// </summary>
+[ImplicitDataDefinitionForInheritors]
+public abstract partial class EntityEffect
+{
+ public abstract void RaiseEvent(EntityUid target, IEntityEffectRaiser raiser, float scale);
+
+ [DataField]
+ public EntityCondition[]? Conditions;
+
+ /// <summary>
+ /// If our scale is less than this value, the effect fails.
+ /// </summary>
+ [DataField]
+ public virtual float MinScale { get; private set; }
+
+ /// <summary>
+ /// If true, then it allows the scale multiplier to go above 1.
+ /// </summary>
+ [DataField]
+ public virtual bool Scaling { get; private set; }
+
+ // TODO: This should be an entity condition but guidebook relies on it heavily for formatting...
+ /// <summary>
+ /// Probability of the effect occuring.
+ /// </summary>
+ [DataField]
+ public float Probability = 1.0f;
+
+ /// <summary>
+ /// The description of this entity effect that shows in guidebooks.
+ /// </summary>
+ public virtual string? EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null;
+
+ /// <summary>
+ /// Whether this effect should be logged in admin logs.
+ /// </summary>
+ [ViewVariables]
+ public virtual bool ShouldLog => true;
+
+ /// <summary>
+ /// If this effect is logged, how important is the log?
+ /// </summary>
+ [ViewVariables]
+ public virtual LogImpact LogImpact => LogImpact.Low;
+}
+
+/// <summary>
+/// An Event carrying an entity effect.
+/// </summary>
+/// <param name="Effect">The Effect</param>
+/// <param name="Scale">A strength scalar for the effect, defaults to 1 and typically only goes under for incomplete reactions.</param>
+[ByRefEvent, Access(typeof(SharedEntityEffectsSystem))]
+public readonly record struct EntityEffectEvent<T>(T Effect, float Scale) where T : EntityEffectBase<T>
+{
+ /// <summary>
+ /// The Condition being raised in this event
+ /// </summary>
+ public readonly T Effect = Effect;
+
+ /// <summary>
+ /// The Scale modifier of this Effect.
+ /// </summary>
+ public readonly float Scale = Scale;
+}
/// </summary>
[DataField, AutoNetworkedField]
public bool Enabled = true;
+
+ /// <summary>
+ /// Should the flash protection be shown when examining the entity?
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool ShowInExamine = true;
}
private void OnExamine(Entity<FlashImmunityComponent> ent, ref ExaminedEvent args)
{
- args.PushMarkup(Loc.GetString("flash-protection"));
+ if (ent.Comp.ShowInExamine)
+ args.PushMarkup(Loc.GetString("flash-protection"));
}
}
/// </remarks>
public sealed class MovementModStatusSystem : EntitySystem
{
+ public static readonly EntProtoId ReagentSpeed = "ReagentSpeedStatusEffect";
public static readonly EntProtoId VomitingSlowdown = "VomitingSlowdownStatusEffect";
public static readonly EntProtoId TaserSlowdown = "TaserSlowdownStatusEffect";
public static readonly EntProtoId FlashSlowdown = "FlashSlowdownStatusEffect";
+++ /dev/null
-namespace Content.Shared.Ninja.Components;
-
-/// <summary>
-/// Makes this warp point a valid bombing target for ninja's spider charge.
-/// </summary>
-[RegisterComponent]
-public sealed partial class BombingTargetComponent : Component;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects.Body;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Content.Shared.Nutrition.Components;
// ignores any effect conditions, just cares about how much it can hydrate
if (effect is SatiateHunger hunger)
{
- total += hunger.NutritionFactor * quantity.Quantity.Float();
+ total += hunger.Factor * quantity.Quantity.Float();
}
}
}
// ignores any effect conditions, just cares about how much it can hydrate
if (effect is SatiateThirst thirst)
{
- total += thirst.HydrationFactor * quantity.Quantity.Float();
+ total += thirst.Factor * quantity.Quantity.Float();
}
}
}
-using Content.Shared.FixedPoint;
-using Content.Shared.Store;
using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.PAI;
/// and there's not always enough players and ghost roles to justify it.
/// All logic in PAISystem.
/// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[RegisterComponent, NetworkedComponent]
public sealed partial class PAIComponent : Component
{
/// <summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public EntityUid? LastUser;
- [DataField]
- public EntProtoId ShopActionId = "ActionPAIOpenShop";
-
- [DataField, AutoNetworkedField]
- public EntityUid? ShopAction;
-
/// <summary>
/// When microwaved there is this chance to brick the pai, kicking out its player and preventing it from being used again.
/// </summary>
+++ /dev/null
-using Content.Shared.Actions;
-
-namespace Content.Shared.PAI;
-
-/// <summary>
-/// pAIs, or Personal AIs, are essentially portable ghost role generators.
-/// In their current implementation, they create a ghost role anyone can access,
-/// and that a player can also "wipe" (reset/kick out player).
-/// Theoretically speaking pAIs are supposed to use a dedicated "offer and select" system,
-/// with the player holding the pAI being able to choose one of the ghosts in the round.
-/// This seems too complicated for an initial implementation, though,
-/// and there's not always enough players and ghost roles to justify it.
-/// </summary>
-public abstract class SharedPAISystem : EntitySystem
-{
- [Dependency] private readonly SharedActionsSystem _actions = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<PAIComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<PAIComponent, ComponentShutdown>(OnShutdown);
- }
-
- private void OnMapInit(Entity<PAIComponent> ent, ref MapInitEvent args)
- {
- _actions.AddAction(ent, ent.Comp.ShopActionId);
- }
-
- private void OnShutdown(Entity<PAIComponent> ent, ref ComponentShutdown args)
- {
- _actions.RemoveAction(ent.Owner, ent.Comp.ShopAction);
- }
-}
-public sealed partial class PAIShopActionEvent : InstantActionEvent
-{
-}
private void OnGetVerbsForWrappedParcel(Entity<WrappedParcelComponent> entity,
ref GetVerbsEvent<InteractionVerb> args)
{
- if (!args.CanAccess)
+ if (!args.CanAccess || !args.CanComplexInteract)
+ return;
+
+ if (entity.Comp.Contents.Contains(args.User))
return;
// "Capture" the values from `args` because C# doesn't like doing the capturing for `ref` values.
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class JointVisualsComponent : Component
{
- [ViewVariables(VVAccess.ReadWrite), DataField("sprite", required: true), AutoNetworkedField]
+ /// <summary>
+ /// The sprite to use for the line.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
public SpriteSpecifier Sprite = default!;
- [ViewVariables(VVAccess.ReadWrite), DataField("target"), AutoNetworkedField]
- public NetEntity? Target;
+ /// <summary>
+ /// The line is drawn between this target and the entity owning the component.
+ /// </summary>
+ /// <summary>
+ /// TODO: WeakEntityReference.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public EntityUid? Target;
/// <summary>
/// Offset from Body A.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("offsetA"), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public Vector2 OffsetA;
/// <summary>
/// Offset from Body B.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("offsetB"), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public Vector2 OffsetB;
}
[DataField("harvestingState")]
public string HarvestingState = "harvesting";
#endregion
-
- [DataField] public EntityUid? Action;
}
{
}
-public sealed partial class RevenantShopActionEvent : InstantActionEvent
-{
-}
-
public sealed partial class RevenantDefileActionEvent : InstantActionEvent
{
}
[IdDataField]
public string ID { get; private set; } = default!;
- [DataField("playTimeTracker", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
+ [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
public string PlayTimeTracker { get; private set; } = string.Empty;
/// <summary>
/// Who is the supervisor for this job.
/// </summary>
- [DataField("supervisors")]
- public string Supervisors { get; private set; } = "nobody";
+ [DataField]
+ public LocId Supervisors = "job-supervisors-nobody";
/// <summary>
/// The name of this job as displayed to players.
/// </summary>
- [DataField("name")]
+ [DataField]
public string Name { get; private set; } = string.Empty;
[ViewVariables(VVAccess.ReadOnly)]
/// <summary>
/// The name of this job as displayed to players.
/// </summary>
- [DataField("description")]
+ [DataField]
public string? Description { get; private set; }
[ViewVariables(VVAccess.ReadOnly)]
/// <summary>
/// When true - the station will have anouncement about arrival of this player.
/// </summary>
- [DataField("joinNotifyCrew")]
+ [DataField]
public bool JoinNotifyCrew { get; private set; } = false;
/// <summary>
/// When true - the player will recieve a message about importancy of their job.
/// </summary>
- [DataField("requireAdminNotify")]
+ [DataField]
public bool RequireAdminNotify { get; private set; } = false;
/// <summary>
/// Should this job appear in preferences menu?
/// </summary>
- [DataField("setPreference")]
+ [DataField]
public bool SetPreference { get; private set; } = true;
/// <summary>
[DataField]
public bool? OverrideConsoleVisibility { get; private set; } = null;
- [DataField("canBeAntag")]
+ [DataField]
public bool CanBeAntag { get; private set; } = true;
/// <summary>
/// The "weight" or importance of this job. If this number is large, the job system will assign this job
/// before assigning other jobs.
/// </summary>
- [DataField("weight")]
+ [DataField]
public int Weight { get; private set; }
/// <summary>
/// A numerical score for how much easier this job is for antagonists.
/// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting.
/// </summary>
- [DataField("antagAdvantage")]
+ [DataField]
public int AntagAdvantage = 0;
[DataField]
/// Starting gear will be ignored.
/// If you want to just add special attributes to a humanoid, use AddComponentSpecial instead.
/// </summary>
- [DataField("jobEntity", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+ [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? JobEntity = null;
/// <summary>
[DataField]
public ProtoId<JobIconPrototype> Icon { get; private set; } = "JobIconUnknown";
- [DataField("special", serverOnly: true)]
+ [DataField(serverOnly: true)]
public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
- [DataField("access")]
+ [DataField]
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
- [DataField("accessGroups")]
+ [DataField]
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
- [DataField("extendedAccess")]
+ [DataField]
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
- [DataField("extendedAccessGroups")]
+ [DataField]
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
[DataField]
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] protected readonly ISharedPlayerManager Player = default!;
- [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly SharedMindSystem _minds = default!;
[Dependency] private readonly IPrototypeManager _prototypes = default!;
foreach (var role in delete)
{
- _entityManager.DeleteEntity(role);
+ PredictedDel(role);
}
var update = MindRolesUpdate(mind);
{
footstepModifier.FootstepSoundCollection = prototype.FootstepCollection;
}
+
+ if (prototype.SpriteBodyMovementState is { } movementState)
+ {
+ var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
+ spriteMovement.NoMovementLayers.Clear();
+ spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
+ {
+ State = prototype.SpriteBodyState,
+ };
+ spriteMovement.MovementLayers.Clear();
+ spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
+ {
+ State = movementState,
+ };
+ }
+ else
+ {
+ RemComp<SpriteMovementComponent>(entity);
+ }
}
}
--- /dev/null
+namespace Content.Shared.Silicons.Bots;
+
+/// <summary>
+/// This component describes how a HugBot hugs.
+/// </summary>
+/// <see cref="SharedHugBotSystem"/>
+[RegisterComponent, AutoGenerateComponentState]
+public sealed partial class HugBotComponent : Component
+{
+ [DataField, AutoNetworkedField]
+ public TimeSpan HugCooldown = TimeSpan.FromMinutes(2);
+}
--- /dev/null
+using Content.Shared.Emag.Systems;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Silicons.Bots;
+
+/// <summary>
+/// This system handles HugBots.
+/// </summary>
+public abstract class SharedHugBotSystem : EntitySystem
+{
+ [Dependency] private readonly EmagSystem _emag = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<HugBotComponent, GotEmaggedEvent>(OnEmagged);
+ }
+
+ private void OnEmagged(Entity<HugBotComponent> entity, ref GotEmaggedEvent args)
+ {
+ if (!_emag.CompareFlag(args.Type, EmagType.Interaction) ||
+ _emag.CheckFlag(entity, EmagType.Interaction) ||
+ !TryComp<HugBotComponent>(entity, out var hugBot))
+ return;
+
+ // HugBot HTN checks for emag state within its own logic, so we don't need to change anything here.
+
+ args.Handled = true;
+ }
+}
+
+/// <summary>
+/// This event is raised on an entity when it is hugged by a HugBot.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed partial class HugBotHugEvent(NetEntity hugBot) : EntityEventArgs
+{
+ public readonly NetEntity HugBot = hugBot;
+}
using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
using Robust.Shared.Utility;
namespace Content.Shared.Stacks;
[Prototype]
-public sealed partial class StackPrototype : IPrototype
+public sealed partial class StackPrototype : IPrototype, IInheritingPrototype
{
- [ViewVariables]
+ /// <inheritdoc />
[IdDataField]
public string ID { get; private set; } = default!;
+ /// <inheritdoc />
+ [ParentDataField(typeof(AbstractPrototypeIdArraySerializer<StackPrototype>))]
+ public string[]? Parents { get; private set; }
+
+ /// <inheritdoc />
+ [NeverPushInheritance]
+ [AbstractDataField]
+ public bool Abstract { get; private set; }
+
/// <summary>
/// Human-readable name for this stack type e.g. "Steel"
/// </summary>
+using System.ComponentModel.Design;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.StatusEffectNew.Components;
using Robust.Shared.Prototypes;
+using YamlDotNet.Core.Tokens;
namespace Content.Shared.StatusEffectNew;
return false;
}
+ /// <summary>
+ /// A method which specifically removes time from a status effect, or removes the status effect if time is null.
+ /// </summary>
+ /// <param name="uid">The target entity on which the effect is applied.</param>
+ /// <param name="effectProto">The prototype ID of the status effect to modify.</param>
+ /// <param name="time">
+ /// The time adjustment to apply to the status effect. Positive values extend the duration,
+ /// while negative values reduce it.
+ /// </param>
+ /// <returns> True if duration was edited successfully, false otherwise.</returns>
+ public bool TryRemoveTime(EntityUid uid, EntProtoId effectProto, TimeSpan? time)
+ {
+ return time == null ? TryRemoveStatusEffect(uid, effectProto) : TryAddTime(uid, effectProto, time.Value);
+ }
+
/// <summary>
/// Attempts to set the remaining time for a status effect on an entity.
/// </summary>
}
_entList.Add(entity);
- delay += itemSize.Weight * AreaInsertDelayPerItem;
+ delay += itemSize.Weight;
if (_entList.Count >= StorageComponent.AreaPickupLimit)
break;
//If there's only one then let's be generous
if (_entList.Count >= 1)
{
- var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay, new AreaPickupDoAfterEvent(GetNetEntityList(_entList)), uid, target: uid)
+ var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay * AreaInsertDelayPerItem, new AreaPickupDoAfterEvent(GetNetEntityList(_entList)), uid, target: uid)
{
BreakOnDamage = true,
BreakOnMove = true,
--- /dev/null
+using Content.Shared.Actions;
+
+namespace Content.Shared.Store.Events;
+
+/// <summary>
+/// Opens a store specified by <see cref="StoreComponent"/>
+/// Used for entities with a store built into themselves like Revenant or PAI
+/// </summary>
+public sealed partial class IntrinsicStoreActionEvent : InstantActionEvent
+{
+}
private void OnRejuvenate(Entity<KnockedDownComponent> entity, ref RejuvenateEvent args)
{
- SetKnockdownNextUpdate((entity, entity), GameTiming.CurTime);
+ SetKnockdownNextUpdate(entity, GameTiming.CurTime);
if (entity.Comp.AutoStand)
RemComp<KnockedDownComponent>(entity);
if (!Resolve(entity, ref entity.Comp, false))
return;
- SetKnockdownNextUpdate(entity, GameTiming.CurTime + time);
+ SetKnockdownNextUpdate((entity, entity.Comp), GameTiming.CurTime + time);
}
/// <summary>
/// </summary>
/// <param name="entity">Entity whose timer we're updating</param>
/// <param name="time">The exact time we're setting the next update to.</param>
- private void SetKnockdownNextUpdate(Entity<KnockedDownComponent?> entity, TimeSpan time)
+ private void SetKnockdownNextUpdate(Entity<KnockedDownComponent> entity, TimeSpan time)
{
- if (!Resolve(entity, ref entity.Comp, false))
- return;
-
if (GameTiming.CurTime > time)
time = GameTiming.CurTime;
}
}
- public bool TryAddParalyzeDuration(EntityUid uid, TimeSpan duration)
+ public bool TryAddParalyzeDuration(EntityUid uid, TimeSpan? duration)
{
- if (!_status.TryAddStatusEffectDuration(uid, StunId, duration))
+ if (duration == null)
+ return TryUpdateParalyzeDuration(uid, duration);
+
+ if (!_status.TryAddStatusEffectDuration(uid, StunId, duration.Value))
return false;
// We can't exit knockdown when we're stunned, so this prevents knockdown lasting longer than the stun.
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
-namespace Content.Server.Temperature.Components;
+namespace Content.Shared.Temperature.Components;
/// <summary>
/// Handles changing temperature,
using System.Linq;
+using Content.Shared.Atmos;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Temperature.Components;
+using Robust.Shared.Physics.Components;
using Robust.Shared.Timing;
namespace Content.Shared.Temperature.Systems;
/// <summary>
/// This handles predicting temperature based speedup.
/// </summary>
-public sealed class SharedTemperatureSystem : EntitySystem
+public abstract class SharedTemperatureSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
Dirty(uid, temp);
}
}
+
+ public virtual void ChangeHeat(EntityUid uid, float heatAmount, bool ignoreHeatResistance = false, TemperatureComponent? temperature = null)
+ {
+
+ }
+
+ public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, PhysicsComponent? physics = null)
+ {
+ if (!Resolve(uid, ref comp) || !Resolve(uid, ref physics, false) || physics.FixturesMass <= 0)
+ {
+ return Atmospherics.MinimumHeatCapacity;
+ }
+
+ return comp.SpecificHeat * physics.FixturesMass;
+ }
}
--- /dev/null
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Conditions;
+
+/// <summary>
+/// Checks if a triggered entity or the user of a trigger has a certain mindrole.
+/// Cancels the trigger otherwise.
+/// </summary>
+/// <remarks>
+/// Mind roles are only networked to their owner! So if you use this on any other entity than yourself it won't be predicted.
+/// </remarks>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class MindRoleTriggerConditionComponent : BaseTriggerConditionComponent
+{
+ /// <summary>
+ /// Whitelist for what mind role components on the owning entity allow this trigger.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? EntityWhitelist;
+
+ /// <summary>
+ /// Whitelist for what mind role components on the User allow this trigger.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? UserWhitelist;
+}
namespace Content.Shared.Trigger.Components.Conditions;
/// <summary>
-/// Checks if the user of a trigger satisfies a whitelist and blacklist condition for the triggered entity or the one triggering it.
+/// Checks if the user of a trigger satisfies a whitelist and blacklist condition.
/// Cancels the trigger otherwise.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class WhitelistTriggerConditionComponent : BaseTriggerConditionComponent
{
/// <summary>
- /// Whitelist for what entites can cause this trigger.
+ /// Whitelist for what entities can cause this trigger.
/// </summary>
[DataField, AutoNetworkedField]
public EntityWhitelist? UserWhitelist;
/// <summary>
- /// Blacklist for what entites can cause this trigger.
+ /// Blacklist for what entities can cause this trigger.
/// </summary>
[DataField, AutoNetworkedField]
public EntityWhitelist? UserBlacklist;
// Can't use PopupClient or PopupPredicted because the trigger might be unpredicted.
_popup.PopupEntity(Loc.GetString("scramble-on-trigger-popup"), target.Value, target.Value);
+
+ var ev = new DnaScrambledEvent(target.Value);
+ RaiseLocalEvent(target.Value, ref ev, true);
}
}
+
+/// <summary>
+/// Raised after an entity has been DNA Scrambled.
+/// Useful for forks that need to run their own updates here.
+/// </summary>
+/// <param name="flag">The entity that had its DNA scrambled.</param>
+
+[ByRefEvent]
+public record struct DnaScrambledEvent(EntityUid Target);
private void InitializeCondition()
{
SubscribeLocalEvent<WhitelistTriggerConditionComponent, AttemptTriggerEvent>(OnWhitelistTriggerAttempt);
-
SubscribeLocalEvent<UseDelayTriggerConditionComponent, AttemptTriggerEvent>(OnUseDelayTriggerAttempt);
-
SubscribeLocalEvent<ToggleTriggerConditionComponent, AttemptTriggerEvent>(OnToggleTriggerAttempt);
- SubscribeLocalEvent<ToggleTriggerConditionComponent, GetVerbsEvent<AlternativeVerb>>(OnToggleGetAltVerbs);
-
SubscribeLocalEvent<RandomChanceTriggerConditionComponent, AttemptTriggerEvent>(OnRandomChanceTriggerAttempt);
+ SubscribeLocalEvent<MindRoleTriggerConditionComponent, AttemptTriggerEvent>(OnMindRoleTriggerAttempt);
+
+ SubscribeLocalEvent<ToggleTriggerConditionComponent, GetVerbsEvent<AlternativeVerb>>(OnToggleGetAltVerbs);
}
private void OnWhitelistTriggerAttempt(Entity<WhitelistTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
}
private void OnUseDelayTriggerAttempt(Entity<UseDelayTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
}
private void OnToggleTriggerAttempt(Entity<ToggleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= !ent.Comp.Enabled;
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= !ent.Comp.Enabled;
}
private void OnToggleGetAltVerbs(Entity<ToggleTriggerConditionComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
private void OnRandomChanceTriggerAttempt(Entity<RandomChanceTriggerConditionComponent> ent,
ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ // TODO: Replace with RandomPredicted once the engine PR is merged
+ var hash = new List<int>
+ {
+ (int)_timing.CurTick.Value,
+ GetNetEntity(ent).Id,
+ args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
+ };
+ var seed = SharedRandomExtensions.HashCodeCombine(hash);
+ var rand = new System.Random(seed);
+
+ args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
+ }
+ private void OnMindRoleTriggerAttempt(Entity<MindRoleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
+ {
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ if (ent.Comp.EntityWhitelist != null)
{
- // TODO: Replace with RandomPredicted once the engine PR is merged
- var hash = new List<int>
+ if (!_mind.TryGetMind(ent.Owner, out var entMindId, out var entMindComp))
+ {
+ args.Cancelled = true; // the entity has no mind
+ return;
+ }
+ if (!_role.MindHasRole((entMindId, entMindComp), ent.Comp.EntityWhitelist))
+ {
+ args.Cancelled = true; // the entity does not have the required role
+ return;
+ }
+ }
+
+ if (ent.Comp.UserWhitelist != null)
+ {
+ if (args.User == null || !_mind.TryGetMind(args.User.Value, out var userMindId, out var userMindComp))
+ {
+ args.Cancelled = true; // no user or the user has no mind
+ return;
+ }
+ if (!_role.MindHasRole((userMindId, userMindComp), ent.Comp.UserWhitelist))
{
- (int)_timing.CurTick.Value,
- GetNetEntity(ent).Id,
- args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
- };
- var seed = SharedRandomExtensions.HashCodeCombine(hash);
- var rand = new System.Random(seed);
-
- args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
+ args.Cancelled = true; // the user does not have the required role
+ }
}
}
}
using Content.Shared.DeviceLinking;
using Content.Shared.EntityTable;
using Content.Shared.Item.ItemToggle;
+using Content.Shared.Mind;
using Content.Shared.Popups;
+using Content.Shared.Roles;
using Content.Shared.Timing;
using Content.Shared.Trigger.Components;
using Content.Shared.Whitelist;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
+ [Dependency] private readonly SharedRoleSystem _role = default!;
+ [Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly EntityTableSystem _entityTable = default!;
public const string DefaultTriggerKey = "trigger";
using Content.Shared.Administration.Logs;
using Content.Shared.CombatMode;
using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
+ [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnMeleeSelected);
SubscribeLocalEvent<MeleeWeaponComponent, ShotAttemptedEvent>(OnMeleeShotAttempted);
SubscribeLocalEvent<MeleeWeaponComponent, GunShotEvent>(OnMeleeShot);
+ SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
SubscribeLocalEvent<BonusMeleeDamageComponent, GetMeleeDamageEvent>(OnGetBonusMeleeDamage);
SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
#if DEBUG
- SubscribeLocalEvent<MeleeWeaponComponent,
- MapInitEvent> (OnMapInit);
+ SubscribeLocalEvent<MeleeWeaponComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
}
}
+ private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
+ {
+ if (component.Hidden)
+ return;
+
+ var damageSpec = GetDamage(uid, args.User, component);
+
+ if (damageSpec.Empty)
+ return;
+
+ _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
+ }
private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
{
var attackRate = GetAttackRate(uid, args.User, component);
var visuals = EnsureComp<JointVisualsComponent>(shotUid.Value);
visuals.Sprite = component.RopeSprite;
visuals.OffsetA = new Vector2(0f, 0.5f);
- visuals.Target = GetNetEntity(uid);
+ visuals.Target = uid;
Dirty(shotUid.Value, visuals);
}
[DataField, AutoNetworkedField]
public bool Spent;
+ /// <summary>
+ /// Is this cartridge automatically marked as trash once spent?
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool MarkSpentAsTrash = true;
+
/// <summary>
/// Caseless ammunition.
/// </summary>
+using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
using Content.Shared.Examine;
+using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Weapons.Ranged.Systems;
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
+ SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
// Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentGetState>(OnBatteryGetState);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
+ SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
}
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
args.PushMarkup(Loc.GetString("gun-battery-examine", ("color", AmmoExamineColor), ("count", component.Shots)));
}
+ private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
+ {
+ var damageSpec = GetDamage(entity.Comp);
+
+ if (damageSpec == null)
+ return;
+
+ var damageType = entity.Comp switch
+ {
+ HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
+ ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
+ _ => throw new ArgumentOutOfRangeException(),
+ };
+
+ _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
+ }
+
+ private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
+ {
+ if (component is ProjectileBatteryAmmoProviderComponent battery)
+ {
+ if (ProtoManager.Index<EntityPrototype>(battery.Prototype)
+ .Components
+ .TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
+ {
+ var p = (ProjectileComponent)projectile.Component;
+
+ if (!p.Damage.Empty)
+ {
+ return p.Damage * Damageable.UniversalProjectileDamageModifier;
+ }
+ }
+
+ return null;
+ }
+
+ if (component is HitscanBatteryAmmoProviderComponent hitscan)
+ {
+ var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
+ return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
+ }
+
+ return null;
+ }
+
private void OnBatteryTakeAmmo(EntityUid uid, BatteryAmmoProviderComponent component, TakeAmmoEvent args)
{
var shots = Math.Min(args.Shots, component.Shots);
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
+ private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
+
private const float InteractNextFire = 0.3f;
private const double SafetyNextFire = 0.5;
private const float EjectOffset = 0.4f;
cartridge.Spent = spent;
Appearance.SetData(uid, AmmoVisuals.Spent, spent);
+
+ if (!cartridge.MarkSpentAsTrash)
+ return;
+
+ if (spent)
+ TagSystem.AddTag(uid, TrashTag);
+ else
+ TagSystem.RemoveTag(uid, TrashTag);
}
/// <summary>
/// Can be null if not linked.
/// </summary>
[DataField, AutoNetworkedField]
- public NetEntity? AnalyzerEntity;
+ public EntityUid? AnalyzerEntity;
[DataField]
public SoundSpecifier? ScanFinishedSound = new SoundPathSpecifier("/Audio/Machines/scan_finish.ogg");
};
/// <summary>
- /// The machine linking port for the analyzer
+ /// The machine linking port for linking the console with the analyzer.
/// </summary>
[DataField]
public ProtoId<SourcePortPrototype> LinkingPort = "ArtifactAnalyzerSender";
-using Robust.Shared.Audio;
+using Content.Shared.DeviceLinking;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
namespace Content.Shared.Xenoarchaeology.Equipment.Components;
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool ReadyToPrint = false;
+
+ /// <summary>
+ /// The machine linking port for linking the analyzer with the console.
+ /// </summary>
+ [DataField]
+ public ProtoId<SinkPortPrototype> LinkingPort = "ArtifactAnalyzerReceiver";
}
using Content.Shared.Stacks;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
-using Robust.Shared.Audio.Components;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
/// <summary>
/// This is an entity storage that, when activated, crushes the artifact inside of it and gives artifact fragments.
/// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState, AutoGenerateComponentPause]
[Access(typeof(SharedArtifactCrusherSystem))]
public sealed partial class ArtifactCrusherComponent : Component
{
/// <summary>
/// When the current crushing will end.
/// </summary>
- [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoNetworkedField, AutoPausedField]
public TimeSpan CrushEndTime;
/// <summary>
/// The next second. Used to apply damage over time.
/// </summary>
- [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoNetworkedField, AutoPausedField]
public TimeSpan NextSecond;
/// <summary>
/// The total duration of the crushing.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public TimeSpan CrushDuration = TimeSpan.FromSeconds(10);
/// <summary>
/// <summary>
/// The minimum amount of fragments spawned.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public int MinFragments = 2;
/// <summary>
/// The maximum amount of fragments spawned, non-inclusive.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public int MaxFragments = 5;
/// <summary>
/// The material for the fragments.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
public ProtoId<StackPrototype> FragmentStackProtoId = "ArtifactFragment";
/// <summary>
/// Stores entity of <see cref="CrushingSound"/> to allow ending it early.
/// </summary>
[DataField]
- public (EntityUid, AudioComponent)? CrushingSoundEntity;
+ public EntityUid? CrushingSoundEntity;
/// <summary>
/// When enabled, stops the artifact crusher from being opened when it is being crushed.
/// </summary>
- [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
+ [DataField, AutoNetworkedField]
public bool AutoLock = false;
}
public abstract class SharedArtifactAnalyzerSystem : EntitySystem
{
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
+ [Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
/// <inheritdoc/>
public override void Initialize()
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemPlacedEvent>(OnItemPlaced);
SubscribeLocalEvent<ArtifactAnalyzerComponent, ItemRemovedEvent>(OnItemRemoved);
- SubscribeLocalEvent<ArtifactAnalyzerComponent, MapInitEvent>(OnMapInit);
-
- SubscribeLocalEvent<AnalysisConsoleComponent, NewLinkEvent>(OnNewLink);
- SubscribeLocalEvent<AnalysisConsoleComponent, PortDisconnectedEvent>(OnPortDisconnected);
+ SubscribeLocalEvent<ArtifactAnalyzerComponent, NewLinkEvent>(OnNewLinkAnalyzer);
+ SubscribeLocalEvent<ArtifactAnalyzerComponent, LinkAttemptEvent>(OnLinkAttemptAnalyzer);
+ SubscribeLocalEvent<ArtifactAnalyzerComponent, PortDisconnectedEvent>(OnPortDisconnectedAnalyzer);
+
+ SubscribeLocalEvent<AnalysisConsoleComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<AnalysisConsoleComponent, NewLinkEvent>(OnNewLinkConsole);
+ SubscribeLocalEvent<AnalysisConsoleComponent, LinkAttemptEvent>(OnLinkAttemptConsole);
+ SubscribeLocalEvent<AnalysisConsoleComponent, PortDisconnectedEvent>(OnPortDisconnectedConsole);
}
private void OnItemPlaced(Entity<ArtifactAnalyzerComponent> ent, ref ItemPlacedEvent args)
Dirty(ent);
}
- private void OnMapInit(Entity<ArtifactAnalyzerComponent> ent, ref MapInitEvent args)
+ private void OnMapInit(Entity<AnalysisConsoleComponent> ent, ref MapInitEvent args)
{
- if (!TryComp<DeviceLinkSinkComponent>(ent, out var sink))
+ if (!TryComp<DeviceLinkSourceComponent>(ent, out var source))
return;
- foreach (var source in sink.LinkedSources)
+ var linkedEntities = _deviceLink.GetLinkedSinks((ent.Owner, source), ent.Comp.LinkingPort);
+
+ foreach (var sink in linkedEntities)
{
- if (!TryComp<AnalysisConsoleComponent>(source, out var analysis))
+ if (!TryComp<ArtifactAnalyzerComponent>(sink, out var analyzer))
continue;
- analysis.AnalyzerEntity = GetNetEntity(ent);
- ent.Comp.Console = source;
- Dirty(source, analysis);
+ ent.Comp.AnalyzerEntity = sink;
+ analyzer.Console = ent.Owner;
Dirty(ent);
+ Dirty(sink, analyzer);
break;
}
}
- private void OnNewLink(Entity<AnalysisConsoleComponent> ent, ref NewLinkEvent args)
+ private void OnNewLinkConsole(Entity<AnalysisConsoleComponent> ent, ref NewLinkEvent args)
{
- if (!TryComp<ArtifactAnalyzerComponent>(args.Sink, out var analyzer))
+ if (args.SourcePort != ent.Comp.LinkingPort || !HasComp<ArtifactAnalyzerComponent>(args.Sink))
return;
- ent.Comp.AnalyzerEntity = GetNetEntity(args.Sink);
- analyzer.Console = ent;
- Dirty(args.Sink, analyzer);
+ ent.Comp.AnalyzerEntity = args.Sink;
Dirty(ent);
}
- private void OnPortDisconnected(Entity<AnalysisConsoleComponent> ent, ref PortDisconnectedEvent args)
+ private void OnNewLinkAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref NewLinkEvent args)
{
- var analyzerNetEntity = ent.Comp.AnalyzerEntity;
- if (args.Port != ent.Comp.LinkingPort || analyzerNetEntity == null)
+ if (args.SinkPort != ent.Comp.LinkingPort || !HasComp<AnalysisConsoleComponent>(args.Source))
return;
- var analyzerEntityUid = GetEntity(analyzerNetEntity);
- if (TryComp<ArtifactAnalyzerComponent>(analyzerEntityUid, out var analyzer))
- {
- analyzer.Console = null;
- Dirty(analyzerEntityUid.Value, analyzer);
- }
+ ent.Comp.Console = args.Source;
+ Dirty(ent);
+ }
+
+ private void OnLinkAttemptConsole(Entity<AnalysisConsoleComponent> ent, ref LinkAttemptEvent args)
+ {
+ if (ent.Comp.AnalyzerEntity != null)
+ args.Cancel(); // can only link to one device at a time
+ }
+
+ private void OnLinkAttemptAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref LinkAttemptEvent args)
+ {
+ if (ent.Comp.Console != null)
+ args.Cancel(); // can only link to one device at a time
+ }
+
+ private void OnPortDisconnectedConsole(Entity<AnalysisConsoleComponent> ent, ref PortDisconnectedEvent args)
+ {
+ if (args.Port != ent.Comp.LinkingPort || ent.Comp.AnalyzerEntity == null)
+ return;
ent.Comp.AnalyzerEntity = null;
Dirty(ent);
}
+ private void OnPortDisconnectedAnalyzer(Entity<ArtifactAnalyzerComponent> ent, ref PortDisconnectedEvent args)
+ {
+ if (args.Port != ent.Comp.LinkingPort || ent.Comp.Console == null)
+ return;
+
+ ent.Comp.Console = null;
+ Dirty(ent);
+ }
+
public bool TryGetAnalyzer(Entity<AnalysisConsoleComponent> ent, [NotNullWhen(true)] out Entity<ArtifactAnalyzerComponent>? analyzer)
{
analyzer = null;
if (!_powerReceiver.IsPowered(consoleEnt))
return false;
- var analyzerUid = GetEntity(ent.Comp.AnalyzerEntity);
- if (!TryComp<ArtifactAnalyzerComponent>(analyzerUid, out var analyzerComp))
+ if (!TryComp<ArtifactAnalyzerComponent>(ent.Comp.AnalyzerEntity, out var analyzerComp))
return false;
- if (!_powerReceiver.IsPowered(analyzerUid.Value))
+ if (!_powerReceiver.IsPowered(ent.Comp.AnalyzerEntity.Value))
return false;
- analyzer = (analyzerUid.Value, analyzerComp);
+ analyzer = (ent.Comp.AnalyzerEntity.Value, analyzerComp);
return true;
}
+using Content.Shared.Damage;
+using Content.Shared.Emag.Systems;
using Content.Shared.Examine;
+using Content.Shared.Popups;
+using Content.Shared.Power;
+using Content.Shared.Power.EntitySystems;
using Content.Shared.Storage.Components;
+using Content.Shared.Verbs;
+using Content.Shared.Xenoarchaeology.Equipment.Components;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Collections;
using Robust.Shared.Containers;
-using Content.Shared.Emag.Systems;
-using Content.Shared.Xenoarchaeology.Equipment.Components;
+using Robust.Shared.Timing;
namespace Content.Shared.Xenoarchaeology.Equipment;
/// </summary>
public abstract class SharedArtifactCrusherSystem : EntitySystem
{
- [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] protected readonly SharedAudioSystem AudioSystem = default!;
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly EmagSystem _emag = default!;
+ [Dependency] private readonly SharedPowerReceiverSystem _power = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly DamageableSystem _damageable = default!;
/// <inheritdoc/>
public override void Initialize()
SubscribeLocalEvent<ArtifactCrusherComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
SubscribeLocalEvent<ArtifactCrusherComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<ArtifactCrusherComponent, GotEmaggedEvent>(OnEmagged);
+ SubscribeLocalEvent<ArtifactCrusherComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
+ SubscribeLocalEvent<ArtifactCrusherComponent, PowerChangedEvent>(OnPowerChanged);
}
private void OnInit(Entity<ArtifactCrusherComponent> ent, ref ComponentInit args)
ent.Comp.AutoLock = true;
args.Handled = true;
+ Dirty(ent);
}
private void OnStorageOpenAttempt(Entity<ArtifactCrusherComponent> ent, ref StorageOpenAttemptEvent args)
args.PushMarkup(ent.Comp.AutoLock ? Loc.GetString("artifact-crusher-examine-autolocks") : Loc.GetString("artifact-crusher-examine-no-autolocks"));
}
- public void StopCrushing(Entity<ArtifactCrusherComponent> ent, bool early = true)
+ private void OnGetVerbs(Entity<ArtifactCrusherComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+ {
+ if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
+ return;
+
+ if (!TryComp<EntityStorageComponent>(ent, out var entityStorageComp) ||
+ entityStorageComp.Contents.ContainedEntities.Count == 0)
+ return;
+
+ if (!_power.IsPowered(ent.Owner))
+ return;
+
+ var user = args.User;
+ var verb = new AlternativeVerb
+ {
+ Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
+ Priority = 2,
+ Act = () => StartCrushing((ent, ent.Comp, entityStorageComp), user)
+ };
+ args.Verbs.Add(verb);
+ }
+
+ private void OnPowerChanged(Entity<ArtifactCrusherComponent> ent, ref PowerChangedEvent args)
+ {
+ if (!args.Powered)
+ StopCrushing(ent);
+ }
+
+ public void StartCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent, EntityUid? user = null)
{
- var (_, crusher) = ent;
+ var (uid, crusher, _) = ent;
+
+ if (crusher.Crushing)
+ return;
- if (!crusher.Crushing)
+ if (crusher.AutoLock)
+ _popup.PopupPredicted(Loc.GetString("artifact-crusher-autolocks-enable"), uid, user);
+
+ crusher.Crushing = true;
+ crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
+ crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
+ crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent)?.Entity;
+ _appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
+ Dirty(ent, ent.Comp1);
+ }
+
+ public void StopCrushing(Entity<ArtifactCrusherComponent> ent, bool early = true)
+ {
+ if (!ent.Comp.Crushing)
return;
- crusher.Crushing = false;
- Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false);
+ ent.Comp.Crushing = false;
+ _appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false);
if (early)
{
- AudioSystem.Stop(crusher.CrushingSoundEntity?.Item1, crusher.CrushingSoundEntity?.Item2);
- crusher.CrushingSoundEntity = null;
+ AudioSystem.Stop(ent.Comp.CrushingSoundEntity);
+ ent.Comp.CrushingSoundEntity = null;
}
Dirty(ent, ent.Comp);
}
+
+ public virtual void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent) { }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator<ArtifactCrusherComponent, EntityStorageComponent>();
+ while (query.MoveNext(out var uid, out var crusher, out var storage))
+ {
+ if (!crusher.Crushing)
+ continue;
+
+ if (crusher.NextSecond < _timing.CurTime)
+ {
+ var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
+ foreach (var contained in contents)
+ {
+ _damageable.TryChangeDamage(contained, crusher.CrushingDamage);
+ }
+ crusher.NextSecond += TimeSpan.FromSeconds(1);
+ Dirty(uid, crusher);
+ }
+
+ if (crusher.CrushEndTime < _timing.CurTime)
+ FinishCrushing((uid, crusher, storage));
+ }
+ }
}
using Robust.Shared.Prototypes;
-namespace Content.Server.Zombies;
+namespace Content.Shared.Zombies;
/// <summary>
/// This is used for a zombie that cannot be cured by any methods. Gives a succumb to zombie infection action.
/// </summary>
+/// <remarks> We don't network this component for anti-cheat purposes.</remarks>
[RegisterComponent]
public sealed partial class IncurableZombieComponent : Component
{
-#!/bin/sh
+#!/usr/bin/env bash
cp 0A.yml out.yml
../bin/Debug/net5.0/Content.Tools out.yml 0B.yml 0C.yml
Entries:
-- author: CoconutThunder
- changes:
- - message: Fixed lubed items being thrown when looking at the pickup verb.
- type: Fix
- - message: Fixed multihanded items showing a popup when looking at the pickup verb.
- type: Fix
- - message: Fixed a bug with lubed handcuffs.
- type: Fix
- id: 8561
- time: '2025-05-25T05:10:58.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/38705
-- author: CoconutThunder
- changes:
- - message: The Chief Medical Officer should now appear with the correct precedence
- in the crew manifest.
- type: Fix
- id: 8560
- time: '2025-05-24T05:10:57.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37774
-- author: TiniestShark
- changes:
- - message: Added inhand sprites for the bartender utensils and mugs.
- type: Add
- id: 8561
- time: '2025-05-24T17:32:27.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37771
-- author: K-Dynamic
- changes:
- - message: Shutters and blast doors now appear welded when welded.
- type: Fix
- id: 8562
- time: '2025-05-25T15:57:18.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37807
-- author: Stop-Signs
- changes:
- - message: Meals now better reflect the amount of ingredients put into them.
- type: Tweak
- id: 8563
- time: '2025-05-25T18:02:04.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/34138
-- author: brainfood1183
- changes:
- - message: Kangaroos can now be equipped with northstars and knuckle dusters.
- type: Tweak
- id: 8564
- time: '2025-05-25T18:03:01.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37789
-- author: Moomoobeef
- changes:
- - message: Added new variants to dirty tiles.
- type: Tweak
- id: 8565
- time: '2025-05-25T18:11:40.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37800
-- author: AsnDen
- changes:
- - message: Tile-aligned bar sign version was added.
- type: Add
- - message: Bar signs now have proper collision.
- type: Fix
- id: 8566
- time: '2025-05-25T18:36:00.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37756
-- author: Fildrance
- changes:
- - message: Spray nozzle now can consume liquids from puddles and put it right into
- backpacked tank.
- type: Add
- id: 8567
- time: '2025-05-26T03:36:16.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/30600
-- author: Southbridge
- changes:
- - message: On Amber, gave security its missing beacon and barriers.
- type: Fix
- id: 8568
- time: '2025-05-26T07:29:58.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37700
-- author: jessicamaybe
- changes:
- - message: NPC Gorillas can now pry open doors and vault/smash tables!
- type: Tweak
- id: 8569
- time: '2025-05-26T10:49:33.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37822
-- author: ArtisticRoomba
- changes:
- - message: The TEG's efficiency in extracting power from gasses has been tweaked
- to promote dual-loop designs that recycle the waste heat of gasses, and punish
- "meta" single loop designs.
- type: Tweak
- id: 8570
- time: '2025-05-26T11:53:19.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37728
-- author: ArtisticRoomba
- changes:
- - message: The TEG now outputs smoother power when pressure across the circulators
- flutter. (This was causing epilepsy in extreme circumstances).
- type: Fix
- id: 8571
- time: '2025-05-26T12:07:50.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37658
-- author: chromiumboy
- changes:
- - message: Sentry turret control panels can now be found adjacent to rooms containing
- sentry turrets. Authorized personnel can use these panels to remotely monitor
- and alter the settings of any linked sentry turrets.
- type: Add
- id: 8572
- time: '2025-05-26T13:00:50.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/35235
-- author: metalgearsloth
- changes:
- - message: You no longer face items for a single frame when clicking while moving.
- type: Tweak
- id: 8573
- time: '2025-05-27T11:34:24.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37874
-- author: Simyon
- changes:
- - message: Capacitors and Matter bins have been combined into the Manipulator.
- type: Remove
- id: 8574
- time: '2025-05-27T11:47:49.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37725
-- author: PicklOH
- changes:
- - message: Gas Pipes are now named as such in the construction menu.
- type: Tweak
- id: 8575
- time: '2025-05-27T16:26:30.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37881
-- author: ProfRenderer
- changes:
- - message: Cluwne ID cards now have a job icon.
- type: Tweak
- id: 8576
- time: '2025-05-27T16:39:52.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37834
-- author: Moomoobeef
- changes:
- - message: Bookshelves now contain a more reasonable amount of books.
- type: Tweak
- id: 8577
- time: '2025-05-27T21:21:39.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37866
-- author: SlamBamActionman
- changes:
- - message: Seismic Charges now trigger the timer when sent a signal, instead of
- detonating instantly.
- type: Tweak
- - message: Signal Triggers for modular grenades now detonate after a 3 second delay.
- type: Tweak
- id: 8578
- time: '2025-05-28T07:31:34.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/34465
-- author: Minemoder5000
- changes:
- - message: Grape juice cups now contain grape juice.
- type: Fix
- id: 8579
- time: '2025-05-28T09:32:42.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37895
-- author: Moomoobeef
- changes:
- - message: Made high-viz vest less visible.
- type: Tweak
- id: 8580
- time: '2025-05-28T09:39:29.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37869
-- author: deltanedas
- changes:
- - message: Diona "Gib yourself!" action now has a suicide warning like microbombs.
- type: Tweak
- id: 8581
- time: '2025-05-28T19:52:12.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/27422
-- author: sowelipililimute
- changes:
- - message: Plants can process nutrition again
- type: Fix
- - message: Plants can process robust harvest again
- type: Fix
- id: 8582
- time: '2025-05-28T22:51:09.0000000+00:00'
- url: https://github.com/space-wizards/space-station-14/pull/37912
- author: mhamster
changes:
- message: Chameleon clothes are now affected by any kind of EMP explosion, which
id: 9012
time: '2025-09-27T20:51:52.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/40572
+- author: keronshb
+ changes:
+ - message: 'EXPERIMENTAL: Tasers, a short-ranged gun capable of causing targets
+ to become prone, are now added into Warden, HoS, and Security locker fills.'
+ type: Add
+ id: 9013
+ time: '2025-09-27T21:21:05.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39087
- author: SurrealShibe
changes:
- message: Vulpkanin now audibly gasp.
id: 9059
time: '2025-10-08T23:45:56.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/40786
+- author: SlamBamActionman
+ changes:
+ - message: EXPERIMENTAL Nocturine now slows the target down, with a longer duration and shorter
+ delay before activating.
+ type: Tweak
+ id: 9060
+ time: '2025-10-09T13:32:34.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40797
- author: Princess-Cheeseballs
changes:
- message: Dying while asleep shouldn't permanently blind you anymore.
id: 9062
time: '2025-10-09T14:00:07.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/40790
+- author: Princess-Cheeseballs
+ changes:
+ - message: The thieving beacon can now detect the officer's handgun objective.
+ type: Fix
+ id: 9063
+ time: '2025-10-10T04:59:26.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40811
+- author: Hitlinemoss
+ changes:
+ - message: The Paladin AI lawset has been rewritten.
+ type: Tweak
+ id: 9064
+ time: '2025-10-10T12:41:57.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40343
+- author: kontakt
+ changes:
+ - message: Ninjas can now have a bombing target at any warp point.
+ type: Tweak
+ id: 9065
+ time: '2025-10-10T21:27:36.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40726
+- author: frigid-dev
+ changes:
+ - message: Ore Crabs now collide with the player if mob collisions are enabled.
+ type: Tweak
+ - message: Ore Crabs now show they are stunned
+ type: Fix
+ id: 9066
+ time: '2025-10-10T23:31:04.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40764
+- author: Crude Oil
+ changes:
+ - message: Removed 'Activate Holopad Projector' verb from the station AI core.
+ type: Fix
+ id: 9067
+ time: '2025-10-11T00:03:14.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39937
+- author: Hitlinemoss
+ changes:
+ - message: Ice now satiates thirst.
+ type: Tweak
+ - message: Ice now evaporates.
+ type: Tweak
+ id: 9068
+ time: '2025-10-11T00:20:22.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40149
+- author: slarticodefast
+ changes:
+ - message: The artifact analysis console no longer breaks when trying to link it
+ to multiple artifact analyzers or vice versa.
+ type: Fix
+ id: 9069
+ time: '2025-10-11T00:33:04.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39984
+- author: qwerltaz
+ changes:
+ - message: The ID card computer now has buttons to grant or revoke all access from
+ the target ID card.
+ type: Add
+ id: 9070
+ time: '2025-10-11T00:52:01.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39375
+- author: Centronias
+ changes:
+ - message: The HugBot, which is similar in purpose and construction to other small
+ robots like the CleanBot.
+ type: Add
+ id: 9071
+ time: '2025-10-11T01:05:08.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/37557
+- author: PicklOH
+ changes:
+ - message: Added more Syndie ammo to the EMAG lathe inventory
+ type: Add
+ id: 9072
+ time: '2025-10-11T05:14:34.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40822
+- author: TrixxedHeart
+ changes:
+ - message: Updated Xenoarchaeology guidebook page to current system.
+ type: Tweak
+ id: 9073
+ time: '2025-10-11T17:32:21.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40621
+- author: HTMLSystem
+ changes:
+ - message: Added infectious anom sprites for moths and arachnids.
+ type: Add
+ id: 9074
+ time: '2025-10-11T18:01:49.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39508
+- author: ScarKy0
+ changes:
+ - message: Mice, cockroaches and other small mobs can no longer unwrap parcels.
+ type: Fix
+ id: 9075
+ time: '2025-10-11T21:32:59.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40838
+- author: Hitlinemoss
+ changes:
+ - message: Autolathes can now print durathread.
+ type: Add
+ id: 9076
+ time: '2025-10-11T21:46:46.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40837
+- author: cloudyias
+ changes:
+ - message: Added the ability for droppers to be printed via autolathes and medfabs
+ type: Add
+ id: 9077
+ time: '2025-10-11T23:15:41.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40074
+- author: jessicamaybe
+ changes:
+ - message: Added swabs and an emag inventory to the biogenerator
+ type: Tweak
+ id: 9078
+ time: '2025-10-12T00:15:18.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39037
+- author: SuperGDPWYL
+ changes:
+ - message: Added the Syndicate ID Card to the uplink for 1 TC.
+ type: Add
+ id: 9079
+ time: '2025-10-12T00:56:09.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/38381
+- author: aada
+ changes:
+ - message: Cannabis no longer stacks infinitely. Sorry, botanists!
+ type: Fix
+ id: 9080
+ time: '2025-10-12T01:29:01.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/38412
+- author: GovnokradZXC
+ changes:
+ - message: New hair named Pigtail (Over Eye)
+ type: Add
+ id: 9081
+ time: '2025-10-12T05:45:59.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39850
+- author: Princess-Cheeseballs
+ changes:
+ - message: Meat Kudzu gasps less often.
+ type: Tweak
+ id: 9082
+ time: '2025-10-12T10:47:30.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39304
+- author: PJB3005
+ changes:
+ - message: The patrons list in the in-game credits works again.
+ type: Fix
+ id: 9083
+ time: '2025-10-12T11:02:33.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40840
+- author: DrSmugleaf
+ changes:
+ - message: Fixed species not being ordered alphabetically in the character customization
+ UI.
+ type: Fix
+ id: 9084
+ time: '2025-10-12T11:14:46.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/39359
+- author: Callmore
+ changes:
+ - message: Bullet casings can now be picked up again.
+ type: Fix
+ id: 9085
+ time: '2025-10-12T18:45:39.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40829
+- author: CoconutThunder
+ changes:
+ - message: Fixed lubed items being thrown when looking at the pickup verb.
+ type: Fix
+ - message: Fixed multihanded items showing a popup when looking at the pickup verb.
+ type: Fix
+ - message: Fixed a bug with lubed handcuffs.
+ type: Fix
+ id: 9086
+ time: '2025-05-25T05:10:58.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/38705
id: 92
time: '2025-10-08T20:41:46.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/40785
+- author: ToastEnjoyer
+ changes:
+ - message: On Plasma, added more nitrogen canisters to the maintenance hallways
+ type: Add
+ id: 93
+ time: '2025-10-10T01:11:33.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40794
+- author: opl
+ changes:
+ - message: On Packed, prisoners can now use the Megaseed in brig.
+ type: Fix
+ id: 94
+ time: '2025-10-10T20:33:03.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40821
+- author: CoconutThunder
+ changes:
+ - message: Reduced frequency of syndicate shark attacks
+ type: Tweak
+ id: 95
+ time: '2025-10-12T18:45:54.0000000+00:00'
+ url: https://github.com/space-wizards/space-station-14/pull/40855
Order: 1
-0leshe, 0tito, 0x6273, 12rabbits, 1337dakota, 13spacemen, 154942, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 27alaing, 2DSiggy, 3nderall, 4310v343k, 4dplanner, 5tickman, 612git, 778b, 96flo, aaron, abadaba695, Ablankmann, abregado, Absolute-Potato, Absotively, achookh, Acruid, ActiveMammmoth, actually-reb, ada-please, adamsong, Adeinitas, adm2play, Admiral-Obvious-001, adrian, Adrian16199, Ady4ik, Aearo-Deepwater, Aerocrux, Aeshus, Aexolott, Aexxie, africalimedrop, afrokada, AftrLite, AgentSmithRadio, Agoichi, Ahion, aiden, Aidenkrz, Aisu9, ajcm, AJCM-git, AjexRose, Alekshhh, alexalexmax, alexkar598, AlexMorgan3817, alexum418, alexumandxgabriel08x, Alice4267, Alithsko, Alkheemist, alliephante, ALMv1, Alpaccalypse, Alpha-Two, AlphaQwerty, Altoids1, amatwiedle, amylizzle, ancientpower, Andre19926, Andrew-Fall, AndrewEyeke, AndrewFenriz, AndreyCamper, Anzarot121, ApolloVector, Appiah, ar4ill, Arcane-Waffle, archee1, ArchPigeon, ArchRBX, areitpog, Arendian, areyouconfused, arimah, Arkanic, ArkiveDev, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, Artxmisery, ArZarLordOfMango, as334, AsikKEsel, AsnDen, asperger-sind, aspiringLich, astriloqua, august-sun, AutoOtter, AverageNotDoingAnythingEnjoyer, avghdev, AwareFoxy, Awlod, azzyisnothere, AzzyIsNotHere, B-Kirill, B3CKDOOR, baa14453, BackeTako, BadaBoomie, Bakke, BananaFlambe, Baptr0b0t, BarryNorfolk, BasedUser, beck-thompson, beesterman, bellwetherlogic, ben, benbryant0, benev0, benjamin-burges, BGare, bhespiritu, bibbly, BigfootBravo, BIGZi0348, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blitzthesquishy, bloodrizer, Bloody2372, blueDev2, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, Bokser815, bolantej, Booblesnoot42, Boolean-Buckeye, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, breeplayx3, BriBrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, buntobaggins, bvelliquette, BWTCK, byondfuckery, c0rigin, c4llv07e, CaasGit, Caconym27, Calecute, Callmore, Camdot, capnsockless, CaptainMaru, captainsqrbeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, catdotjs, catlord, Catofquestionableethics, CatTheSystem, CawsForConcern, Centronias, Chaboricks, chairbender, Chaoticaa, Charlese2, charlie, chartman, ChaseFlorom, chavonadelal, Cheackraze, CheddaCheez, cheesePizza2, CheesePlated, Chief-Engineer, chillyconmor, christhirtle, chromiumboy, Chronophylos, Chubbicous, Chubbygummibear, Ciac32, ciaran, citrea, civilCornball, claustro305, Clement-O, clyf, Clyybber, CMDR-Piboy314, cnv41, coco, cohanna, Cohnway, Cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, Compilatron144, CookieMasterT, coolboy911, CoolioDudio, coolmankid12345, Coolsurf6, cooperwallace, corentt, CormosLemming, CrafterKolyan, CraftyRenter, crazybrain23, Crazydave91920, creadth, CrigCrag, CroilBird, Crotalus, CrudeWax, cryals, CrzyPotato, cubixthree, cutemoongod, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, dan, dangerrevolution, daniel-cr, DanSAussieITS, Daracke, Darkenson, DawBla, Daxxi3, dch-GH, ddeegan, de0rix, Deahaka, dean, DEATHB4DEFEAT, Deatherd, deathride58, DebugOk, Decappi, Decortex, Deeeeja, deepdarkdepths, DeepwaterCreations, Deerstop, degradka, Delete69, deltanedas, DenisShvalov, DerbyX, derek, dersheppard, Deserty0, Detintinto, DevilishMilk, devinschubert14, dexlerxd, dffdff2423, DieselMohawk, DieselMohawkTheSequel, digitalic, Dimastra, DinnerCalzone, DinoWattz, Disp-Dev, DisposableCrewmember42, dissidentbullet, DjfjdfofdjfjD, doc-michael, docnite, Doctor-Cpu, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, DR-DOCTOR-EVIL-EVIL, Dragonjspider, dragonryan06, drakewill-CRL, Drayff, dreamlyjack, DrEnzyme, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, DuckManZach, Duddino, dukevanity, duskyjay, Dutch-VanDerLinde, dvir001, dylanstrategie, dylanwhittingham, Dynexust, Easypoller, echo, eclips_e, eden077, EEASAS, Efruit, efzapa, Ekkosangen, ElectroSR, elsie, elthundercloud, Elysium206, Emisse, emmafornash, EmoGarbage404, Endecc, EnrichedCaramel, Entvari, eoineoineoin, ephememory, eris, erohrs2, ERORR404V1, Errant-4, ertanic, esguard, estacaoespacialpirata, eugene, ewokswagger, exincore, exp111, f0x-n3rd, F1restar4, FacePluslll, Fahasor, FairlySadPanda, farrellka-dev, FATFSAAM2, Feluk6174, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, firenamefn, Firewars763, FirinMaLazors, Fishfish458, fl-oz, Flareguy, flashgnash, FlipBrooke, FluffiestFloof, FluffMe, FluidRock, flymo5678, foboscheshir, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, foxhorn, freeman2651, freeze2222, frobnic8, Froffy025, Fromoriss, froozigiusz, FrostMando, FrostRibbon, Funce, FungiFellow, FunTust, Futuristic-OK, GalacticChimp, gamer3107, Gamewar360, gansulalan, GaussiArson, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, Gentleman-Bird, geraeumig, Ghagliiarghii, Git-Nivrak, githubuser508, gituhabu, GlassEclipse, GnarpGnarp, GNF54, godisdeadLOL, goet, GoldenCan, Goldminermac, Golinth, golubgik, GoodWheatley, Gorox221, GR1231, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, GreyMario, GrownSamoyedDog, GTRsound, gusxyz, Gyrandola, h3half, hamurlik, Hanzdegloker, HappyRoach, Hardly3D, harikattar, Hayden, he1acdvv, Hebi, Helix-ctrl, helm4142, Henry, HerCoyote23, Hi-Im-Shot, HighTechPuddle, Hitlinemoss, hiucko, hivehum, Hmeister-fake, Hmeister-real, Hobbitmax, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, hoshizora-sayo, Hreno, Hrosts, htmlsystem, Huaqas, hubismal, Hugal31, Huxellberger, Hyenh, hyperb1, hyperDelegate, hyphenationc, i-justuser-i, iaada, iacore, IamVelcroboy, Ian321, icekot8, icesickleone, iczero, iglov, IgorAnt028, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, imatsoup, IMCB, impubbi, imrenq, imweax, indeano, Injazz, Insineer, insoPL, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, itsmethom, Itzbenz, iztokbajcar, Jackal298, Jackrost, jacksonzck, Jacktastic09, Jackw2As, jacob, jamessimo, janekvap, Jark255, Jarmer123, Jaskanbe, JasperJRoth, jbox144, JCGWE30, JerryImMouse, jerryimmouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, jkwookee, jmcb, JohnGinnane, johnku1, Jophire, joshepvodka, JpegOfAFrog, jproads, JrInventor05, Jrpl, jukereise, juliangiebel, JustArt1m, JustCone14, justdie12, justin, justintether, JustinTrotter, JustinWinningham, justtne, K-Dynamic, k3yw, Kadeo64, Kaga-404, kaiserbirch, KaiShibaa, kalane15, kalanosh, KamTheSythe, Kanashi-Panda, katzenminer, kbailey-git, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, KieueCaprie, Killerqu00, Kimpes, KingFroozy, kira-er, kiri-yoshikage, Kirillcas, Kirus59, Kistras, Kit0vras, KittenColony, Kittygyat, klaypexx, Kmc2000, Ko4ergaPunk, kognise, kokoc9n, komunre, KonstantinAngelov, kontakt, kosticia, koteq, kotobdev, Kowlin, KrasnoshchekovPavel, Krosus777, Krunklehorn, Kupie, kxvvv, Kyoth25f, kyupolaris, kzhanik, LaCumbiaDelCoronavirus, lajolico, Lamrr, lanedon, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leah, leander-0, leonardo-dabepis, leonidussaks, leonsfriedrich, LeoSantich, LetterN, lettern, Level10Cybermancer, LEVELcat, lever1209, LevitatingTree, Lgibb18, lgruthes, LightVillet, lilazero, liltenhead, linkbro1, linkuyx, Litraxx, little-meow-meow, LittleBuilderJane, LittleNorthStar, LittleNyanCat, lizelive, ljm862, lmsnoise, localcc, lokachop, lolman360, Lomcastar, Lordbrandon12, LordCarve, LordEclipse, lucas, LucasTheDrgn, luckyshotpictures, LudwigVonChesterfield, luegamer, luizwritescode, Lukasz825700516, luminight, lunarcomets, Lusatia, Luxeator, lvvova1, Lyndomen, lyroth001, lzimann, lzk228, M1tht1c, M3739, M4rchy-S, M87S, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, magnuscrowe, maland1, malchanceux, MaloTV, manelnavola, ManelNavola, Mangohydra, marboww, Markek1, MarkerWicker, marlyn, matt, Matz05, max, MaxNox7, maylokana, MehimoNemo, MeltedPixel, memeproof, MendaxxDev, Menshin, Mephisto72, MerrytheManokit, Mervill, metalgearsloth, MetalSage, MFMessage, mhamsterr, michaelcu, micheel665, mifia, MilenVolf, MilonPL, Minemoder5000, Minty642, minus1over12, Mirino97, mirrorcult, misandrie, MishaUnity, MissKay1994, MisterImp, MisterMecky, Mith-randalf, Mixelz, mjarduk, MjrLandWhale, mkanke-real, MLGTASTICa, mnva0, moderatelyaware, modern-nm, mokiros, momo, Moneyl, monotheonist, Moomoobeef, moony, Morb0, MossyGreySlope, mr-bo-jangles, Mr0maks, MrFippik, mrrobdemo, muburu, MureixloI, murolem, musicmanvr, MWKane, Myakot, Myctai, N3X15, nabegator, nails-n-tape, Nairodian, Naive817, NakataRin, namespace-Memory, Nannek, NazrinNya, neutrino-laser, NickPowers43, nikitosych, nikthechampiongr, Nimfar11, ninruB, Nirnael, NIXC, nkokic, NkoKirkto, nmajask, noctyrnal, noelkathegod, noirogen, nok-ko, NonchalantNoob, NoobyLegion, Nopey, NoreUhh, not-gavnaed, notafet, notquitehadouken, notsodana, noudoit, noverd, Nox38, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, Nyxilath, och-och, OctoRocket, OldDanceJacket, OliverOtter, onesch, OneZerooo0, OnsenCapy, OnyxTheBrave, opl-, Orange-Winds, OrangeMoronage9622, OrbitSystem07, Orsoniks, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, packmore, paige404, paigemaeforrest, pali6, Palladinium, Pangogie, panzer-iv1, partyaddict, patrikturi, PaulRitter, pavlockblaine03, peccneck, Peptide90, peptron1, perryprog, PeterFuto, PetMudstone, pewter-wiz, pgraycs, PGrayCS, Pgriha, phantom-lily, pheenty, philingham, Phill101, Phooooooooooooooooooooooooooooooosphate, phunnyguy, PicklOH, PilgrimViis, Pill-U, pinkbat5, Piras314, Pireax, Pissachu, pissdemon, Pixel8-dev, PixeltheAertistContrib, PixelTheKermit, PJB3005, Plasmaguy, plinyvic, Plykiya, poeMota, pofitlo, pointer-to-null, pok27, poklj, PolterTzi, PoorMansDreams, PopGamer45, portfiend, potato1234x, PotentiallyTom, PotRoastPiggy, Princess-Cheeseballs, ProfanedBane, PROG-MohamedDwidar, Prole0, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykana, psykzz, PuceTint, pumkin69, PuroSlavKing, PursuitInAshes, Putnam3145, py01, Pyrovi, qrtDaniil, qrwas, Quantum-cross, quasr-9, quatre, QueerNB, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, Rainbeon, Rainfey, Raitononai, Ramlik, RamZ, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, RedBookcase, Redfire1331, Redict, RedlineTriad, redmushie, RednoWCirabrab, ReeZer2, RemberBM, RemieRichards, RemTim, rene-descartes2021, Renlou, retequizzle, rhailrake, rhsvenson, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, rinary1, Rinkashikachi, riolume, rlebell33, RobbyTheFish, robinthedragon, Rockdtben, Rohesie, rok-povsic, rokudara-sen, rolfero, RomanNovo, rosieposieeee, Roudenn, router, ruddygreat, rumaks, RumiTiger, Ruzihm, S1rFl0, S1ss3l, Saakra, Sadie-silly, saga3152, saintmuntzer, Salex08, sam, samgithubaccount, Samuka-C, SaphireLattice, SapphicOverload, sarahon, sativaleanne, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, ScholarNZL, schrodinger71, scrato, Scribbles0, scrivoy, scruq445, scuffedjays, ScumbagDog, SeamLesss, Segonist, semensponge, sephtasm, ser1-1y, Serkket, sewerpig, SG6732, sh18rw, Shaddap1, ShadeAware, ShadowCommander, shadowtheprotogen546, shaeone, shampunj, shariathotpatrol, SharkSnake98, shibechef, Siginanto, signalsender, SignalWalker, siigiil, silicon14wastaken, Simyon264, sirdragooon, Sirionaut, sirwarock, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skybailey-dev, skye, Skyedra, SlamBamActionman, slarticodefast, Slava0135, sleepyyapril, slimmslamm, Slyfox333, Smugman, snebl, snicket, sniperchance, Snowni, snowsignal, SolidSyn, SolidusSnek, solstar2, SonicHDC, SoulFN, SoulSloth, Soundwavesghost, soupkilove, southbridge-fur, sowelipililimute, Soydium, spacelizard, SpaceLizardSky, SpaceManiac, SpaceRox1244, SpaceyLady, Spangs04, spanky-spanky, Sparlight, spartak, SpartanKadence, spderman3333, SpeltIncorrectyl, Spessmann, SphiraI, SplinterGP, spoogemonster, sporekto, sporkyz, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, starbuckss14, Stealthbomber16, Steffo99, stellar-novas, stewie523, stomf, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, strO0pwafel, Strol20, StStevens, Subversionary, sunbear-dev, supergdpwyl, superjj18, Supernorn, SurrealShibe, SweetAplle, SweptWasTaken, SyaoranFox, Sybil, SYNCHRONIC, Szunti, t, Tainakov, takemysoult, taonewt, tap, TaralGit, Taran, taurie, Tayrtahn, tday93, teamaki, TeenSarlacc, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, Tezzaide, TGODiamond, TGRCdev, tgrkzus, ThatGuyUSA, ThatOneGoblin25, thatrandomcanadianguy, TheArturZh, TheBlueYowie, thecopbennet, TheCze, TheDarkElites, thedraccx, TheEmber, TheFlyingSentry, TheIntoxicatedCat, thekilk, themias, theomund, TheProNoob678, TherapyGoth, ThereDrD0, TheShuEd, thetolbean, thevinter, TheWaffleJesus, thinbug0, ThunderBear2006, timothyteakettle, TimrodDX, timurjavid, tin-man-tim, TiniestShark, Titian3, tk-a369, tkdrg, tmtmtl30, ToastEnjoyer, Toby222, TokenStyle, Tollhouse, Toly65, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, tornado-technology, TornadoTechnology, tosatur, TotallyLemon, ToxicSonicFan04, Tr1bute, travis-g-reid, treytipton, trixxedbit, TrixxedHeart, tropicalhibi, truepaintgit, Truoizys, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, tyashley, Tyler-IN, TytosB, Tyzemol, UbaserB, ubis1, UBlueberry, uhbg, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unisol, unusualcrow, Uriende, UristMcDorf, user424242420, Utmanarn, Vaaankas, valentfingerov, valquaint, Varen, Vasilis, VasilisThePikachu, veliebm, Velken, VelonacepsCalyxEggs, veprolet, VerinSenpai, veritable-calamity, Veritius, Vermidia, vero5123, verslebas, vexerot, vgskye, viceemargo, VigersRay, violet754, Visne, vitopigno, vitusveit, vlad, vlados1408, VMSolidus, vmzd, VoidMeticulous, voidnull000, volotomite, volundr-, Voomra, Vordenburg, vorkathbruh, Vortebo, vulppine, wachte1, wafehling, walksanatora, Warentan, WarMechanic, Watermelon914, weaversam8, wertanchik, whateverusername0, whatston3, widgetbeck, Will-Oliver-Br, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, Wolfkey-SomeoneElseTookMyUsername, wrexbe, wtcwr68, xeri7, xkreksx, xprospero, xRiriq, xsainteer, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, YoungThugSS14, Yousifb26, youtissoum, yunii, YuriyKiss, yuriykiss, zach-hill, Zadeon, Zalycon, zamp, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zero, ZeroDiamond, ZeWaka, zHonys, zionnBE, ZNixian, Zokkie, ZoldorfTheWizard, zonespace27, Zylofan, Zymem, zzylex
+0leshe, 0tito, 0x6273, 12rabbits, 1337dakota, 13spacemen, 154942, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 27alaing, 2DSiggy, 3nderall, 4310v343k, 4dplanner, 5tickman, 612git, 778b, 96flo, aaron, abadaba695, Ablankmann, abregado, Absolute-Potato, Absotively, achookh, Acruid, ActiveMammmoth, actually-reb, ada-please, adamsong, Adeinitas, adm2play, Admiral-Obvious-001, adrian, Adrian16199, Ady4ik, Aearo-Deepwater, Aerocrux, Aeshus, Aexolott, Aexxie, africalimedrop, afrokada, AftrLite, AgentSmithRadio, Agoichi, Ahion, aiden, Aidenkrz, Aisu9, ajcm, AJCM-git, AjexRose, Alekshhh, alexalexmax, alexkar598, AlexMorgan3817, alexum418, alexumandxgabriel08x, Alice4267, Alithsko, Alkheemist, alliephante, ALMv1, Alpaccalypse, Alpha-Two, AlphaQwerty, Altoids1, amatwiedle, amylizzle, ancientpower, Andre19926, Andrew-Fall, AndrewEyeke, AndrewFenriz, AndreyCamper, Anzarot121, ApolloVector, Appiah, ar4ill, Arcane-Waffle, archee1, ArchPigeon, ArchRBX, areitpog, Arendian, areyouconfused, arimah, Arkanic, ArkiveDev, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, Artxmisery, ArZarLordOfMango, as334, AsikKEsel, AsnDen, asperger-sind, aspiringLich, astriloqua, august-sun, AutoOtter, AverageNotDoingAnythingEnjoyer, avghdev, AwareFoxy, Awlod, AzzyIsNotHere, azzyisnothere, B-Kirill, B3CKDOOR, baa14453, BackeTako, BadaBoomie, Bakke, BananaFlambe, Baptr0b0t, BarryNorfolk, BasedUser, beck-thompson, beesterman, bellwetherlogic, ben, benbryant0, benev0, benjamin-burges, BGare, bhespiritu, bibbly, BigfootBravo, BIGZi0348, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blitzthesquishy, Blobadoodle, bloodrizer, Bloody2372, blueDev2, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, Bokser815, bolantej, Booblesnoot42, Boolean-Buckeye, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, breeplayx3, BriBrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, buntobaggins, bvelliquette, BWTCK, byondfuckery, c0rigin, c4llv07e, CaasGit, Caconym27, Calecute, Callmore, Camdot, capnsockless, CaptainMaru, captainsqrbeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, catdotjs, catlord, Catofquestionableethics, CatTheSystem, CawsForConcern, Centronias, Chaboricks, chairbender, Chaoticaa, Charlese2, charlie, chartman, ChaseFlorom, chavonadelal, Cheackraze, CheddaCheez, cheesePizza2, CheesePlated, Chief-Engineer, chillyconmor, christhirtle, chromiumboy, Chronophylos, Chubbicous, Chubbygummibear, Ciac32, ciaran, citrea, civilCornball, claustro305, Clement-O, cloudyias, clyf, Clyybber, CMDR-Piboy314, cnv41, coco, cohanna, Cohnway, Cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, Compilatron144, CookieMasterT, coolboy911, CoolioDudio, coolmankid12345, Coolsurf6, cooperwallace, corentt, CormosLemming, CrafterKolyan, CraftyRenter, crazybrain23, Crazydave91920, creadth, CrigCrag, CroilBird, Crotalus, CrudeWax, cryals, CrzyPotato, cubixthree, cutemoongod, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, dan, dangerrevolution, daniel-cr, DanSAussieITS, Daracke, Darkenson, david, DawBla, Daxxi3, dch-GH, ddeegan, de0rix, Deahaka, dean, DEATHB4DEFEAT, Deatherd, deathride58, DebugOk, Decappi, Decortex, Deeeeja, deepdarkdepths, DeepwaterCreations, Deerstop, degradka, Delete69, deltanedas, DenisShvalov, DerbyX, derek, dersheppard, Deserty0, Detintinto, DevilishMilk, devinschubert14, dexlerxd, dffdff2423, DieselMohawk, DieselMohawkTheSequel, digitalic, Dimastra, DinnerCalzone, DinoWattz, Disp-Dev, DisposableCrewmember42, dissidentbullet, DjfjdfofdjfjD, doc-michael, docnite, Doctor-Cpu, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, DR-DOCTOR-EVIL-EVIL, Dragonjspider, dragonryan06, drakewill-CRL, Drayff, dreamlyjack, DrEnzyme, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, DuckManZach, Duddino, dukevanity, duskyjay, Dutch-VanDerLinde, dvir001, dylanstrategie, dylanwhittingham, Dynexust, Easypoller, echo, eclips_e, eden077, EEASAS, Efruit, efzapa, Ekkosangen, ElectroSR, elsie, elthundercloud, Elysium206, Emisse, emmafornash, EmoGarbage404, Endecc, EnrichedCaramel, Entvari, eoineoineoin, ephememory, eris, erohrs2, ERORR404V1, Errant-4, ertanic, esguard, estacaoespacialpirata, eugene, ewokswagger, exincore, exp111, f0x-n3rd, F1restar4, FacePluslll, Fahasor, FairlySadPanda, farrellka-dev, FATFSAAM2, Feluk6174, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, firenamefn, Firewars763, FirinMaLazors, Fishfish458, fl-oz, Flareguy, flashgnash, FlipBrooke, FluffiestFloof, FluffMe, FluidRock, flymo5678, foboscheshir, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, foxhorn, freeman2651, freeze2222, frobnic8, Froffy025, Fromoriss, froozigiusz, FrostMando, FrostRibbon, Funce, FungiFellow, FunTust, Futuristic-OK, GalacticChimp, gamer3107, Gamewar360, gansulalan, GaussiArson, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, Gentleman-Bird, geraeumig, Ghagliiarghii, Git-Nivrak, githubuser508, gituhabu, GlassEclipse, GnarpGnarp, GNF54, godisdeadLOL, goet, GoldenCan, Goldminermac, Golinth, golubgik, GoodWheatley, Gorox221, GR1231, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, GreyMario, GrownSamoyedDog, GTRsound, gusxyz, Gyrandola, h3half, hamurlik, Hanzdegloker, HappyRoach, Hardly3D, harikattar, Hayden, he1acdvv, Hebi, Helix-ctrl, helm4142, Henry, HerCoyote23, Hi-Im-Shot, HighTechPuddle, Hitlinemoss, hiucko, hivehum, Hmeister-fake, Hmeister-real, Hobbitmax, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, hoshizora-sayo, Hreno, Hrosts, htmlsystem, Huaqas, hubismal, Hugal31, Huxellberger, Hyenh, hyperb1, hyperDelegate, hyphenationc, i-justuser-i, iaada, iacore, IamVelcroboy, Ian321, icekot8, icesickleone, iczero, iglov, IgorAnt028, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, imatsoup, IMCB, impubbi, imrenq, imweax, indeano, Injazz, Insineer, insoPL, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, itsmethom, Itzbenz, iztokbajcar, Jackal298, Jackrost, jacksonzck, Jacktastic09, Jackw2As, jacob, jamessimo, janekvap, Jark255, Jarmer123, Jaskanbe, JasperJRoth, jbox144, JCGWE30, JerryImMouse, jerryimmouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, jkwookee, jmcb, JohnGinnane, johnku1, Jophire, joshepvodka, JpegOfAFrog, jproads, JrInventor05, Jrpl, jukereise, juliangiebel, JustArt1m, JustCone14, justdie12, justin, justintether, JustinTrotter, JustinWinningham, justtne, K-Dynamic, k3yw, Kadeo64, Kaga-404, kaiserbirch, KaiShibaa, kalane15, kalanosh, KamTheSythe, Kanashi-Panda, katzenminer, kbailey-git, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, KieueCaprie, Killerqu00, Kimpes, KingFroozy, kira-er, kiri-yoshikage, Kirillcas, Kirus59, Kistras, Kit0vras, KittenColony, Kittygyat, klaypexx, Kmc2000, Ko4ergaPunk, kognise, kokoc9n, komunre, KonstantinAngelov, kontakt, kosticia, koteq, kotobdev, Kowlin, KrasnoshchekovPavel, Krosus777, Krunklehorn, Kupie, kxvvv, Kyoth25f, kyupolaris, kzhanik, LaCumbiaDelCoronavirus, lajolico, Lamrr, lanedon, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leah, leander-0, leonardo-dabepis, leonidussaks, leonsfriedrich, LeoSantich, LetterN, lettern, Level10Cybermancer, LEVELcat, lever1209, LevitatingTree, Lgibb18, lgruthes, LightVillet, lilazero, liltenhead, linkbro1, linkuyx, Litraxx, little-meow-meow, LittleBuilderJane, LittleNorthStar, LittleNyanCat, lizelive, ljm862, lmsnoise, localcc, lokachop, lolman360, Lomcastar, Lordbrandon12, LordCarve, LordEclipse, lucas, LucasTheDrgn, luckyshotpictures, LudwigVonChesterfield, luegamer, luizwritescode, Lukasz825700516, luminight, lunarcomets, Lusatia, Luxeator, lvvova1, Lyndomen, lyroth001, lzimann, lzk228, M1tht1c, M3739, M4rchy-S, M87S, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, magnuscrowe, maland1, malchanceux, MaloTV, ManelNavola, manelnavola, Mangohydra, marboww, Markek1, MarkerWicker, marlyn, matt, Matz05, max, MaxNox7, maylokana, MehimoNemo, MeltedPixel, memeproof, MendaxxDev, Menshin, Mephisto72, MerrytheManokit, Mervill, metalgearsloth, MetalSage, MFMessage, mhamsterr, michaelcu, micheel665, mifia, MilenVolf, MilonPL, Minemoder5000, Minty642, minus1over12, Mirino97, mirrorcult, misandrie, MishaUnity, MissKay1994, MisterImp, MisterMecky, Mith-randalf, Mixelz, mjarduk, MjrLandWhale, mkanke-real, MLGTASTICa, mnva0, moderatelyaware, modern-nm, mokiros, momo, Moneyl, monotheonist, Moomoobeef, moony, Morb0, MossyGreySlope, mqole, mr-bo-jangles, Mr0maks, MrFippik, mrrobdemo, muburu, MureixloI, murolem, musicmanvr, MWKane, Myakot, Myctai, N3X15, nabegator, nails-n-tape, Nairodian, Naive817, NakataRin, namespace-Memory, Nannek, NazrinNya, neutrino-laser, NickPowers43, nikitosych, nikthechampiongr, Nimfar11, ninruB, Nirnael, NIXC, nkokic, NkoKirkto, nmajask, noctyrnal, noelkathegod, noirogen, nok-ko, NonchalantNoob, NoobyLegion, Nopey, NoreUhh, not-gavnaed, notafet, notquitehadouken, notsodana, noudoit, noverd, Nox38, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, Nyxilath, och-och, OctoRocket, OldDanceJacket, OliverOtter, onesch, OneZerooo0, OnsenCapy, OnyxTheBrave, opl-, Orange-Winds, OrangeMoronage9622, OrbitSystem07, Orsoniks, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, packmore, paige404, paigemaeforrest, pali6, Palladinium, Pangogie, panzer-iv1, partyaddict, patrikturi, PaulRitter, pavlockblaine03, peccneck, Peptide90, peptron1, perryprog, PeterFuto, PetMudstone, pewter-wiz, PGrayCS, pgraycs, Pgriha, phantom-lily, pheenty, philingham, Phill101, Phooooooooooooooooooooooooooooooosphate, phunnyguy, PicklOH, PilgrimViis, Pill-U, pinkbat5, Piras314, Pireax, Pissachu, pissdemon, Pixel8-dev, PixeltheAertistContrib, PixelTheKermit, PJB3005, Plasmaguy, plinyvic, Plykiya, poeMota, pofitlo, pointer-to-null, Pok27, pok27, poklj, PolterTzi, PoorMansDreams, PopGamer45, portfiend, potato1234x, PotentiallyTom, PotRoastPiggy, Princess-Cheeseballs, ProfanedBane, PROG-MohamedDwidar, Prole0, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykana, psykzz, PuceTint, pumkin69, PuroSlavKing, PursuitInAshes, Putnam3145, py01, Pyrovi, qrtDaniil, qrwas, Quantum-cross, quasr-9, quatre, QueerNB, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, Rainbeon, Rainfey, Raitononai, Ramlik, RamZ, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, RedBookcase, Redfire1331, Redict, RedlineTriad, redmushie, RednoWCirabrab, ReeZer2, RemberBM, RemieRichards, RemTim, rene-descartes2021, Renlou, retequizzle, rhailrake, rhsvenson, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, rinary1, Rinkashikachi, riolume, rlebell33, RobbyTheFish, robinthedragon, Rockdtben, Rohesie, rok-povsic, rokudara-sen, rolfero, RomanNovo, rosieposieeee, Roudenn, router, ruddygreat, rumaks, RumiTiger, Ruzihm, S1rFl0, S1ss3l, Saakra, Sadie-silly, saga3152, saintmuntzer, Salex08, sam, samgithubaccount, Samuka-C, SaphireLattice, SapphicOverload, sarahon, sativaleanne, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, ScholarNZL, schrodinger71, scrato, Scribbles0, scrivoy, scruq445, scuffedjays, ScumbagDog, SeamLesss, Segonist, semensponge, sephtasm, ser1-1y, Serkket, sewerpig, SG6732, sh18rw, Shaddap1, ShadeAware, ShadowCommander, shadowtheprotogen546, shaeone, shampunj, shariathotpatrol, SharkSnake98, shibechef, Siginanto, signalsender, SignalWalker, siigiil, silicon14wastaken, Simyon264, sirdragooon, Sirionaut, sirwarock, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skybailey-dev, skye, Skyedra, SlamBamActionman, slarticodefast, Slava0135, sleepyyapril, slimmslamm, Slyfox333, Smugman, snebl, snicket, sniperchance, Snowni, snowsignal, SolidSyn, SolidusSnek, solstar2, SonicHDC, SoulFN, SoulSloth, Soundwavesghost, soupkilove, southbridge-fur, sowelipililimute, Soydium, spacelizard, SpaceLizardSky, SpaceManiac, SpaceRox1244, SpaceyLady, Spangs04, spanky-spanky, Sparlight, spartak, SpartanKadence, spderman3333, SpeltIncorrectyl, Spessmann, SphiraI, SplinterGP, spoogemonster, sporekto, sporkyz, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, starbuckss14, Stealthbomber16, Steffo99, stellar-novas, stewie523, stomf, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, strO0pwafel, Strol20, StStevens, Subversionary, sunbear-dev, supergdpwyl, superjj18, Supernorn, SurrealShibe, SweetAplle, SweptWasTaken, SyaoranFox, Sybil, SYNCHRONIC, Szunti, t, Tainakov, takemysoult, taonewt, tap, TaralGit, Taran, taurie, Tayrtahn, tday93, teamaki, TeenSarlacc, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, Tezzaide, TGODiamond, TGRCdev, tgrkzus, thanosdegraf, ThatGuyUSA, ThatOneGoblin25, thatrandomcanadianguy, TheArturZh, TheBlueYowie, thecopbennet, TheCze, TheDarkElites, thedraccx, TheEmber, TheFlyingSentry, TheIntoxicatedCat, thekilk, themias, theomund, TheProNoob678, TherapyGoth, ThereDrD0, TheShuEd, thetolbean, thevinter, TheWaffleJesus, thinbug0, ThunderBear2006, timothyteakettle, TimrodDX, timurjavid, tin-man-tim, TiniestShark, Titian3, tk-a369, tkdrg, tmtmtl30, ToastEnjoyer, Toby222, TokenStyle, Tollhouse, Toly65, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, tornado-technology, TornadoTechnology, tosatur, TotallyLemon, ToxicSonicFan04, Tr1bute, travis-g-reid, treytipton, trixxedbit, TrixxedHeart, tropicalhibi, truepaintgit, Truoizys, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, tyashley, Tyler-IN, TytosB, Tyzemol, UbaserB, ubis1, UBlueberry, uhbg, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unisol, unusualcrow, Uriende, UristMcDorf, user424242420, Utmanarn, Vaaankas, valentfingerov, valquaint, Varen, Vasilis, VasilisThePikachu, veliebm, Velken, VelonacepsCalyxEggs, veprolet, VerinSenpai, veritable-calamity, Veritius, Vermidia, vero5123, verslebas, vexerot, vgskye, viceemargo, VigersRay, violet754, Visne, vitopigno, vitusveit, vlad, vlados1408, VMSolidus, vmzd, VoidMeticulous, voidnull000, volotomite, volundr-, Voomra, Vordenburg, vorkathbruh, Vortebo, vulppine, wachte1, wafehling, walksanatora, Warentan, WarMechanic, Watermelon914, weaversam8, wertanchik, whateverusername0, whatston3, widgetbeck, Will-Oliver-Br, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, Wolfkey-SomeoneElseTookMyUsername, wrexbe, wtcwr68, xeri7, xkreksx, xprospero, xRiriq, xsainteer, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, YoungThugSS14, Yousifb26, youtissoum, yunii, yuriykiss, YuriyKiss, zach-hill, Zadeon, Zalycon, zamp, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zero, ZeroDiamond, ZeWaka, zHonys, zionnBE, ZNixian, Zokkie, ZoldorfTheWizard, zonespace27, Zylofan, Zymem, zzylex
-- Name: Luaan
+- Name: "'-Y-"
Tier: Syndicate Agent
-- Name: Nugmania
+- Name: "612"
Tier: Revolutionary
-- Name: Xoxeyos
- Tier: Free
-- Name: CobaltCobra
- Tier: Syndicate Agent
-- Name: Train
- Tier: Free
-- Name: ExclusiveWizard
- Tier: Syndicate Agent
-- Name: Matthew Umney
- Tier: Free
-- Name: Hat Kid
+- Name: A Yaj
Tier: Revolutionary
-- Name: Ingvar Tornberg
+- Name: Aaron Handleman
Tier: Revolutionary
-- Name: Joshua Hines
+- Name: Abby Eveland
+ Tier: Revolutionary
+- Name: AC Computing
Tier: Nuclear Operative
-- Name: Ashley Parfitt
+- Name: Aethan Olsen
Tier: Revolutionary
-- Name: thehomelessmanbehindthedumpster
- Tier: Free
-- Name: VmasterVX
+- Name: Aexxie
Tier: Revolutionary
-- Name: JenericJen
+- Name: Aiden
+ Tier: Revolutionary
+- Name: Akaelik
Tier: Nuclear Operative
-- Name: Cosu
+- Name: Akira
+ Tier: Revolutionary
+- Name: AlecRazec
Tier: Revolutionary
-- Name: AileenOnline
- Tier: Free
-- Name: Grotty Bepis
+- Name: Alex Burd
Tier: Nuclear Operative
-- Name: Dizzy_Eevee
+- Name: Alex Fry
+ Tier: Nuclear Operative
+- Name: Alex Nordlund
Tier: Syndicate Agent
-- Name: Lizard
- Tier: Free
-- Name: Michael Van Gaasbeck
+- Name: Alex Tempest
Tier: Revolutionary
-- Name: Statix AraAra
+- Name: Alexandre Courtin
Tier: Revolutionary
-- Name: WWII Kitsune
- Tier: Nuclear Operative
-- Name: Bruno Bigras
+- Name: AlexDragoon
Tier: Revolutionary
-- Name: TheLocalTryHard
- Tier: Free
-- Name: Sufary
+- Name: Alexis
Tier: Nuclear Operative
-- Name: taydeo
+- Name: Alix Shepard
Tier: Nuclear Operative
-- Name: dubdubchan
+- Name: all fields
Tier: Syndicate Agent
-- Name: tremors08
+- Name: Alpha
+ Tier: Nuclear Operative
+- Name: Altana
+ Tier: Revolutionary
+- Name: AmalgoMyte
+ Tier: Revolutionary
+- Name: Amble
+ Tier: Nuclear Operative
+- Name: Andrew Danke
Tier: Syndicate Agent
-- Name: Jan Gocník
- Tier: Free
-- Name: Tret Mekiao
- Tier: Free
-- Name: Ben Joja Hotop
- Tier: Free
-- Name: Sean Lenin
- Tier: Free
-- Name: KiddoTBH
- Tier: Free
-- Name: Kubakura
+- Name: Andrew Montagne
Tier: Syndicate Agent
-- Name: Bullet Kin
- Tier: Free
-- Name: Abby Eveland
+- Name: Androidonator
Tier: Revolutionary
-- Name: Zoe
- Tier: Free
-- Name: ghost--page
- Tier: Nuclear Operative
-- Name: MechaKitty
+- Name: anharmlessguest
+ Tier: Syndicate Agent
+- Name: Anthony Chicko
Tier: Revolutionary
-- Name: BlueNexa
- Tier: Free
-- Name: Noah Heaverin
- Tier: Free
-- Name: jamozen
- Tier: Free
-- Name: SireHambone
+- Name: Anthony Fleck
Tier: Nuclear Operative
-- Name: Blair Cyprus
- Tier: Free
-- Name: Ryan Hanson
+- Name: Anton
Tier: Revolutionary
-- Name: Heinrick Archsider
- Tier: Free
-- Name: Arsalan Sarwari
- Tier: Free
-- Name: Scardy
- Tier: Free
-- Name: Nagano
+- Name: AquaDraco
Tier: Revolutionary
-- Name: Aridia
- Tier: Free
-- Name: illpala
+- Name: Arandomartfan
Tier: Revolutionary
-- Name: kayo josé
- Tier: Free
-- Name: Tymon Tymek
- Tier: Free
-- Name: AlexDragoon
+- Name: Archie Hicks
Tier: Revolutionary
-- Name: Henrik Møller
+- Name: Archmonarch
Tier: Syndicate Agent
-- Name: Mythtic B
- Tier: Revolutionary
-- Name: zedd
- Tier: Nuclear Operative
-- Name: Penguin Commoner
- Tier: Revolutionary
-- Name: Davyei
- Tier: Free
-- Name: Akaelik
- Tier: Nuclear Operative
-- Name: Kyle Tyo
- Tier: Revolutionary
-- Name: Rhys Williams
- Tier: Free
-- Name: Drakkenlupen
+- Name: Ari.
Tier: Revolutionary
-- Name: Randomposter
- Tier: Free
-- Name: Justin White
- Tier: Free
-- Name: Ty Ashley
+- Name: Arin Pearce
Tier: Revolutionary
-- Name: Scorching Rae
+- Name: Arrol Gantry
Tier: Nuclear Operative
-- Name: Cindy Sampaga
- Tier: Free
-- Name: Plague
- Tier: Free
-- Name: dude
- Tier: Free
-- Name: NIACO
- Tier: Free
-- Name: Tee The Kobold
+- Name: arthropods
Tier: Revolutionary
-- Name: Redstones563
- Tier: Free
-- Name: Celestrogen
- Tier: Syndicate Agent
-- Name: SotetSotetSotetSotetSotet
+- Name: Arthur Norris
Tier: Syndicate Agent
-- Name: Guffin
- Tier: Free
-- Name: Southbridge
+- Name: Arykh
Tier: Nuclear Operative
-- Name: ZazaRyn
+- Name: Ashley Parfitt
+ Tier: Revolutionary
+- Name: Asterisk
Tier: Syndicate Agent
-- Name: Magic Crystal Radio
- Tier: Free
-- Name: Sam Sullins
- Tier: Free
-- Name: Widoux 341
- Tier: Free
-- Name: spookerton
+- Name: Aussiemandias
Tier: Syndicate Agent
-- Name: Tom Goodman (TauOmicronMu#2500)
- Tier: Revolutionary
-- Name: Robbie Me
- Tier: Free
-- Name: momochitters
- Tier: Free
-- Name: Raspberry1111
+- Name: Austenn
Tier: Revolutionary
-- Name: flipways
+- Name: avcde
Tier: Nuclear Operative
-- Name: Nictis
+- Name: Azmith Blackheart
Tier: Revolutionary
-- Name: crazybrain
- Tier: Free
-- Name: peanut
+- Name: Bahke
Tier: Nuclear Operative
-- Name: Lewis McCalmont
- Tier: Free
-- Name: T.P_Gaming
- Tier: Revolutionary
-- Name: A Patreon of the Ahts
- Tier: Free
-- Name: brbrbrbrbr brbrbr
- Tier: Revolutionary
-- Name: Shadcake
- Tier: Free
-- Name: kristopher arnott
- Tier: Syndicate Agent
-- Name: Reebe
- Tier: Free
-- Name: blossom
- Tier: Revolutionary
-- Name: ml726
- Tier: Free
-- Name: Logan Splett
- Tier: Free
-- Name: Patrick Mitchell
- Tier: Free
-- Name: Semiotics
- Tier: Syndicate Agent
-- Name: Snowlili
+- Name: Ben Z'
Tier: Revolutionary
-- Name: Hyeronimus Bosch
- Tier: Free
-- Name: S1rFl0
+- Name: Bex
Tier: Revolutionary
-- Name: Gavin
- Tier: Free
-- Name: Faust Statler
+- Name: Blackmare
Tier: Syndicate Agent
-- Name: the good king wompicus
+- Name: Blight
Tier: Syndicate Agent
-- Name: DerBall
- Tier: Revolutionary
-- Name: Gallagin
+- Name: blossom
Tier: Revolutionary
-- Name: Edward Doyle
+- Name: BlueisDumb
+ Tier: Nuclear Operative
+- Name: Blumbee
Tier: Revolutionary
-- Name: Preston Pickering
+- Name: Bobberunio
Tier: Revolutionary
-- Name: Andrew Danke
- Tier: Syndicate Agent
-- Name: Alexis
+- Name: BokChoy
Tier: Nuclear Operative
-- Name: Saphinara
- Tier: Free
-- Name: Random Person
- Tier: Syndicate Agent
-- Name: mage_period
- Tier: Syndicate Agent
-- Name: piras314
- Tier: Free
-- Name: Mark Khudaev
- Tier: Free
-- Name: Saver
- Tier: Free
-- Name: Snilo Black
- Tier: Free
-- Name: CptFalcon
+- Name: Bonefan223
+ Tier: Nuclear Operative
+- Name: Boogerfoot
+ Tier: Nuclear Operative
+- Name: Borna Punda
Tier: Revolutionary
-- Name: Daxx (Justin Winningham)
- Tier: Syndicate Agent
-- Name: Posters Union Australia (Shlee)
- Tier: Free
-- Name: nathan
- Tier: Free
-- Name: funnylookingwolf
+- Name: Brandon
Tier: Revolutionary
-- Name: Sporkyz
+- Name: Brandon Roughley
+ Tier: Syndicate Agent
+- Name: brbrbrbrbr brbrbr
Tier: Revolutionary
-- Name: SarahRaven
+- Name: BrunBytes
Tier: Revolutionary
-- Name: Da Skolin
- Tier: Free
-- Name: Joshua Meyer
- Tier: Free
-- Name: BUMBLE
- Tier: Free
-- Name: Lily Roche
- Tier: Free
-- Name: Klive McToaster
- Tier: Free
-- Name: CasuallyAPerson
- Tier: Free
-- Name: Powder
+- Name: Bruno Bigras
Tier: Revolutionary
-- Name: Noah Heaverin
- Tier: Free
-- Name: Violette
+- Name: Buldinn Girshovich
+ Tier: Nuclear Operative
+- Name: Bumlocked
Tier: Revolutionary
-- Name: Amble
+- Name: Bush Boy
Tier: Nuclear Operative
-- Name: James Sanders
- Tier: Free
-- Name: Susaniel
- Tier: Free
-- Name: Eve Holly
- Tier: Free
-- Name: Superscope
- Tier: Free
-- Name: Nyxilath
+- Name: Callum Tubrett
Tier: Nuclear Operative
-- Name: RedChair368
- Tier: Revolutionary
-- Name: Blumbee
- Tier: Revolutionary
-- Name: Mason Fawcett
- Tier: Revolutionary
+- Name: Carbonhell
+ Tier: Syndicate Agent
+- Name: Catdere
+ Tier: Syndicate Agent
+- Name: Celestrogen
+ Tier: Syndicate Agent
- Name: Cerzix
Tier: Revolutionary
-- Name: Aeris Ophelia
- Tier: Free
-- Name: Troll_King_907
+- Name: Chase Trotter
Tier: Nuclear Operative
-- Name: Certified Hood Classic
- Tier: Free
-- Name: Hydraliks
- Tier: Free
-- Name: Meguneri
- Tier: Free
-- Name: hyphenation
+- Name: Chem_Inventory
Tier: Nuclear Operative
-- Name: Psy
- Tier: Revolutionary
-- Name: Pinet
+- Name: Christian Hicks
+ Tier: Syndicate Agent
+- Name: Citizen Battle
Tier: Nuclear Operative
-- Name: Vivi Bunny
- Tier: Free
-- Name: James Stevens
+- Name: CloudyClover
Tier: Revolutionary
-- Name: anharmlessguest
- Tier: Syndicate Agent
-- Name: Outlier
- Tier: Free
-- Name: Brandon Hackney
- Tier: Free
-- Name: eleanor nora
- Tier: Free
-- Name: starch
+- Name: Collin R Terrell
+ Tier: Revolutionary
+- Name: Commissar Fox
Tier: Syndicate Agent
-- Name: Jacob Watson
+- Name: ConcaveGnome
Tier: Syndicate Agent
-- Name: Seinfeld
+- Name: Coolsurf6
Tier: Revolutionary
-- Name: Prime!
- Tier: Free
-- Name: John
- Tier: Free
-- Name: FauxParadox
+- Name: Cormos Lemming
+ Tier: Nuclear Operative
+- Name: Corpus Inc.
Tier: Revolutionary
-- Name: Mr_Clank
+- Name: CPM311
Tier: Revolutionary
-- Name: rafael rabelo
- Tier: Free
-- Name: TBF_Jack
- Tier: Free
-- Name: StaceyBalcom
+- Name: CptFalcon
Tier: Revolutionary
-- Name: guh
+- Name: Crazyeyes24
+ Tier: Syndicate Agent
+- Name: CrudeOil
+ Tier: Nuclear Operative
+- Name: Curtis Pearson
Tier: Revolutionary
-- Name: Fran Picek
- Tier: Free
-- Name: Austenn
+- Name: Cyberate
Tier: Revolutionary
-- Name: Flayn
- Tier: Free
-- Name: Nye
- Tier: Free
-- Name: Phycoweirdo
- Tier: Nuclear Operative
-- Name: Madeleine LeFleur
+- Name: Daniel D
Tier: Syndicate Agent
-- Name: Anton
+- Name: Daniel Thompson
Tier: Revolutionary
-- Name: That Furry Fuck
- Tier: Free
-- Name: sat
- Tier: Free
-- Name: goober
- Tier: Free
-- Name: Boogerfoot
+- Name: Daskata
Tier: Nuclear Operative
-- Name: Raiden Johnson
- Tier: Revolutionary
-- Name: Talbot
+- Name: Dastion
Tier: Revolutionary
-- Name: Alen Kadric
- Tier: Free
-- Name: pogcat
- Tier: Free
- Name: Dave
- Tier: Free
-- Name: Nathaniel Taylor
Tier: Revolutionary
-- Name: Z4NEER
- Tier: Nuclear Operative
-- Name: Laying on my penis until it falls asleep, so it feels like I'm giving someone else a hando
+- Name: David
Tier: Revolutionary
-- Name: Sam Caesar
+- Name: David N
+ Tier: Syndicate Agent
+- Name: Davyei
Tier: Revolutionary
-- Name: Lykan
- Tier: Free
-- Name: tarna41
- Tier: Free
-- Name: Ryan Johnson
- Tier: Free
-- Name: Andrew Montagne
+- Name: Daxx (Justin Winningham)
Tier: Syndicate Agent
-- Name: yakub mobutu
- Tier: Free
-- Name: Michael Krebs
- Tier: Free
-- Name: mr funny swag
- Tier: Free
-- Name: Crazyeyes24
+- Name: DBF
Tier: Syndicate Agent
-- Name: Zylo
- Tier: Free
-- Name: ScarKy0
+- Name: DerBall
Tier: Revolutionary
-- Name: Randall Hudson
- Tier: Free
-- Name: FaberTheCatboy
- Tier: Free
-- Name: IamOzyman
+- Name: Devin Nelson
Tier: Revolutionary
-- Name: Jado0213
+- Name: Dieselmohawk D.
Tier: Revolutionary
-- Name: StaticeStorm
+- Name: Diklyquill
+ Tier: Revolutionary
+- Name: Dizzy_Eevee
Tier: Syndicate Agent
-- Name: Baron Mathot
- Tier: Free
-- Name: CrudeOil
- Tier: Nuclear Operative
-- Name: Sartec
+- Name: Dourbii
Tier: Revolutionary
-- Name: Mathew McGuire
+- Name: Dr.Raccoon
Tier: Revolutionary
-- Name: Jelloterd2
- Tier: Free
-- Name: Commissar Fox
- Tier: Syndicate Agent
-- Name: tyler adams
- Tier: Revolutionary
-- Name: Logan Britt
- Tier: Free
-- Name: Joshua A.
- Tier: Free
-- Name: ya boi darth Vader
- Tier: Free
-- Name: Syndlkat
- Tier: Free
-- Name: Zyleak
- Tier: Revolutionary
-- Name: Hunter
- Tier: Free
-- Name: Killerqu00
- Tier: Free
-- Name: lzk
- Tier: Free
-- Name: Cai Williamson
- Tier: Syndicate Agent
-- Name: Arykh
- Tier: Nuclear Operative
-- Name: Pallastovid
- Tier: Free
-- Name: Rome
+- Name: Dr_Med_Izin
Tier: Revolutionary
-- Name: mawrk
- Tier: Free
-- Name: Jack
+- Name: Drakkenlupen
Tier: Revolutionary
-- Name: stikfigz
+- Name: DramaBuns
Tier: Revolutionary
-- Name: RyanTuek
+- Name: DrIvoPotato
+ Tier: Nuclear Operative
+- Name: DrMelon
Tier: Revolutionary
-- Name: David N
+- Name: dubdubchan
Tier: Syndicate Agent
-- Name: Panzer IV
- Tier: Free
-- Name: Novaq
+- Name: DubzyVEVO
Tier: Revolutionary
-- Name: Trevor Doyle
- Tier: Free
-- Name: Borna Punda
+- Name: Durp
Tier: Revolutionary
-- Name: Patrick Long
- Tier: Free
-- Name: Alpha
- Tier: Nuclear Operative
-- Name: Gaëtan GOUSSEAUD
+- Name: Dusk
Tier: Revolutionary
-- Name: Hayden Wessing
+- Name: Dylan Hull
Tier: Revolutionary
-- Name: Noodle is me
+- Name: Dylan Roberts
Tier: Syndicate Agent
-- Name: snakebb
+- Name: Echinodermata
Tier: Revolutionary
-- Name: Patrick
+- Name: Edward Doyle
Tier: Revolutionary
-- Name: Väinö Kontinen
- Tier: Free
-- Name: Devin Nelson
+- Name: Enricoc3l
Tier: Revolutionary
-- Name: Rat Man
+- Name: Enzoman12
+ Tier: Nuclear Operative
+- Name: Erik Meinke
Tier: Revolutionary
-- Name: Christopher Day
- Tier: Free
-- Name: Wilhelm 17
- Tier: Free
-- Name: Kieue Caprie
+- Name: Ethan Keller
Tier: Revolutionary
-- Name: RamenZorn
+- Name: Evan Armstrong
+ Tier: Revolutionary
+- Name: evilJenny
+ Tier: Revolutionary
+- Name: ExclusiveWizard
Tier: Syndicate Agent
-- Name: Swix Swix
+- Name: Farewell Fire
+ Tier: Syndicate Agent
+- Name: Faust Statler
+ Tier: Syndicate Agent
+- Name: FauxParadox
Tier: Revolutionary
-- Name: Katharina
- Tier: Free
-- Name: Blackmare
+- Name: Fiebertraum Illhead
Tier: Syndicate Agent
-- Name: lukiw
+- Name: flipways
+ Tier: Nuclear Operative
+- Name: Florian
Tier: Revolutionary
-- Name: Magelfik
+- Name: François Desautels
Tier: Revolutionary
-- Name: Kevin
+- Name: Frege Beach
+ Tier: Revolutionary
+- Name: FungiFog
+ Tier: Revolutionary
+- Name: funnylookingwolf
+ Tier: Revolutionary
+- Name: Gallagin
+ Tier: Revolutionary
+- Name: Gavin Jones
Tier: Nuclear Operative
-- Name: Tomáš Sitarčík
- Tier: Syndicate Agent
-- Name: Coolsurf6
+- Name: Gavin Simmons
Tier: Revolutionary
-- Name: Neexdle
- Tier: Free
-- Name: Lucid
- Tier: Free
-- Name: MissKay1994
+- Name: Gaxeer
Tier: Syndicate Agent
-- Name: Raccoononi
+- Name: Gaëtan GOUSSEAUD
Tier: Revolutionary
-- Name: Avocado999
- Tier: Free
-- Name: Invisorum
+- Name: Geekyhobo2
+ Tier: Revolutionary
+- Name: Georgia Partyka
+ Tier: Syndicate Agent
+- Name: ghost--page
Tier: Nuclear Operative
-- Name: Hannah
+- Name: Glenn Olsen
+ Tier: Syndicate Agent
+- Name: Gnomo
Tier: Nuclear Operative
-- Name: Thomas
+- Name: Godfiend
Tier: Revolutionary
-- Name: Cozmicc
- Tier: Free
-- Name: Unalterableness Happiness
- Tier: Free
-- Name: Sparlight
- Tier: Nuclear Operative
-- Name: MAILS ADVISORY
- Tier: Free
-- Name: Rq52
- Tier: Free
-- Name: Ben Wahba
- Tier: Free
-- Name: North
- Tier: Free
-- Name: Tyran
- Tier: Free
-- Name: TheSimpleTime
- Tier: Free
-- Name: Minemoder
+- Name: Gordod
Tier: Syndicate Agent
-- Name: Richard "Rei" Weeks
+- Name: Gosera -
Tier: Syndicate Agent
-- Name: Sika-Voi
- Tier: Free
-- Name: Dumbdestroyer2
- Tier: Free
-- Name: Ferox Heist
- Tier: Free
-- Name: Ryan Vieira
- Tier: Free
-- Name: kithri
- Tier: Nuclear Operative
-- Name: Luzurper
+- Name: Gothryd
Tier: Revolutionary
-- Name: Rainy
+- Name: Greggo
+ Tier: Syndicate Agent
+- Name: Greyhound Connect
Tier: Revolutionary
-- Name: Dusk
+- Name: grhmhome
Tier: Revolutionary
-- Name: Apocist
- Tier: Revolutionary
-- Name: Yukari_TK
- Tier: Free
-- Name: Iris
- Tier: Free
-- Name: Jamie Forkner
- Tier: Free
-- Name: rokudara
- Tier: Free
-- Name: Xionwalker
- Tier: Free
-- Name: Michael Schrader
- Tier: Free
-- Name: JT Billings
+- Name: guh
Tier: Revolutionary
-- Name: Stedar
- Tier: Syndicate Agent
-- Name: Alex Burd
- Tier: Nuclear Operative
-- Name: Vasilis The Pikachu
- Tier: Free
-- Name: Erik Meinke
+- Name: Hamcha
Tier: Revolutionary
-- Name: Sleeepz
- Tier: Syndicate Agent
-- Name: Jonathan
- Tier: Free
-- Name: Trent Warfel
+- Name: Hannah
Tier: Nuclear Operative
-- Name: Fritz Vohlkson
- Tier: Free
-- Name: Гоша Ушаров
- Tier: Free
-- Name: Cpt Blastahoe
- Tier: Free
-- Name: dedomena
- Tier: Free
-- Name: Nolan Downing
- Tier: Free
-- Name: Seth Morron
+- Name: Hannah Dawson
+ Tier: Syndicate Agent
+- Name: Hanzdegloker
+ Tier: Syndicate Agent
+- Name: Hat Kid
Tier: Revolutionary
-- Name: Fumo Legionnaire
- Tier: Free
-- Name: obama
- Tier: Free
-- Name: Daniel Megiddo
- Tier: Free
-- Name: Денис
- Tier: Free
-- Name: Ubaser
+- Name: Hayden
Tier: Revolutionary
-- Name: Catdere
+- Name: Henrik Møller
Tier: Syndicate Agent
-- Name: valery xolstov
- Tier: Free
-- Name: Marios Sardis
+- Name: hh
+ Tier: Syndicate Agent
+- Name: Higgtastic
Tier: Revolutionary
-- Name: Constrife
- Tier: Free
-- Name: TINYANGRYWOMAN
- Tier: Free
-- Name: Kerensky
+- Name: Hoplophobia
Tier: Revolutionary
-- Name: DEATHB4DEFEAT
- Tier: Free
-- Name: Kristy Denniss
- Tier: Free
-- Name: orange color
+- Name: huh?
Tier: Revolutionary
-- Name: Hectik
- Tier: Free
-- Name: SomeDogo
- Tier: Free
-- Name: Joshua Meyer
+- Name: Hunter James
Tier: Nuclear Operative
-- Name: Matthias Bechtold
+- Name: Hunter Tew
+ Tier: Syndicate Agent
+- Name: hyphenation
+ Tier: Nuclear Operative
+- Name: I'm going to resurrect Charlie Kirk as a gay zombie with a permanent hard cock, like the scene where robocop is lungs, but boner
Tier: Revolutionary
-- Name: Serafim
- Tier: Free
-- Name: Cindy Xiao
- Tier: Free
-- Name: SmokingKilz
- Tier: Free
-- Name: Jacob Scott
- Tier: Free
-- Name: Ryan Kelly
+- Name: IamOzyman
Tier: Revolutionary
-- Name: mikiju
- Tier: Syndicate Agent
-- Name: TheGungeonologist
+- Name: IceStorm theDragon
Tier: Revolutionary
-- Name: Tia
+- Name: ikamuse johnson
Tier: Revolutionary
-- Name: yeoshua
- Tier: Syndicate Agent
-- Name: David Ilina
- Tier: Free
-- Name: Robyn Pothagan
- Tier: Free
-- Name: chomp
- Tier: Free
-- Name: Maksym Aleinikov
- Tier: Free
-- Name: Chase M.
- Tier: Free
-- Name: Ethan Maria
- Tier: Free
-- Name: Luna Rose
- Tier: Free
-- Name: Jordon
+- Name: illpala
Tier: Revolutionary
-- Name: Godfiend
+- Name: Ingvar Tornberg
Tier: Revolutionary
-- Name: Jake Huxell
- Tier: Free
-- Name: Alexander Simakov
- Tier: Free
-- Name: Hannah Dawson
+- Name: Into the Stars - Community Host
+ Tier: Nuclear Operative
+- Name: Invisorum
+ Tier: Nuclear Operative
+- Name: Irish Kelly
Tier: Syndicate Agent
-- Name: Dieselmohawk D.
+- Name: Jack
Tier: Revolutionary
-- Name: Sean Lilly
- Tier: Syndicate Agent
-- Name: Brandon Roughley
+- Name: Jack Gardiner
+ Tier: Revolutionary
+- Name: Jack Rose
+ Tier: Revolutionary
+- Name: Jacob Watson
Tier: Syndicate Agent
-- Name: Jack
- Tier: Free
-- Name: Cooliano Rizzo
- Tier: Free
-- Name: North Star
- Tier: Free
-- Name: Flamebrain
- Tier: Free
-- Name: Andrew
- Tier: Revolutionary
-- Name: Ostoja
- Tier: Free
-- Name: Russian TS
- Tier: Nuclear Operative
-- Name: Kyu, The Meme Fairy
- Tier: Free
-- Name: LIMIT_bro .
- Tier: Free
-- Name: Kim
+- Name: Jado0213
Tier: Revolutionary
-- Name: Dourbii
+- Name: JagerVonS
Tier: Revolutionary
-- Name: Autistic Dog
- Tier: Free
-- Name: Black Rose
- Tier: Free
-- Name: rose soul
- Tier: Free
-- Name: Toast
- Tier: Free
-- Name: Jiangshi Luvr
- Tier: Free
-- Name: OllyTheFoxcoon
- Tier: Free
-- Name: Christopher Peltola
+- Name: James Andrew Peoples Jr
Tier: Revolutionary
-- Name: Bonefan223
+- Name: James Stevens
+ Tier: Revolutionary
+- Name: Jax
Tier: Nuclear Operative
-- Name: Fie
- Tier: Free
-- Name: DuskyJay
- Tier: Free
-- Name: Zella Zane
+- Name: Jeaglekill
Tier: Revolutionary
-- Name: Pixel Realms
- Tier: Free
-- Name: ConcaveGnome
- Tier: Syndicate Agent
-- Name: Ростислав Мірошніченко
- Tier: Free
-- Name: Hunter Tew
- Tier: Syndicate Agent
-- Name: Daniel D
+- Name: Jeff Tatem
+ Tier: Nuclear Operative
+- Name: Jeffery Pointer
Tier: Syndicate Agent
-- Name: Kick Buttowski
- Tier: Free
-- Name: Eggexe
- Tier: Free
-- Name: Lv
- Tier: Free
-- Name: Ali Alashar
- Tier: Free
-- Name: Nathaniel Joseph Hurd
+- Name: JenericJen
Tier: Revolutionary
-- Name: sk3iron
+- Name: Jeremy Hernandez
+ Tier: Syndicate Agent
+- Name: Jerg Jerginson
+ Tier: Nuclear Operative
+- Name: Joel
Tier: Revolutionary
-- Name: Dax XZ
- Tier: Free
-- Name: debelizm
- Tier: Free
-- Name: Kaisering
+- Name: JohannVanDerwis
Tier: Revolutionary
-- Name: VividWisp
- Tier: Syndicate Agent
-- Name: Alex Mercer
- Tier: Free
-- Name: AmalgoMyte
+- Name: John Doe
+ Tier: Nuclear Operative
+- Name: Jordon
Tier: Revolutionary
-- Name: SeanKim
- Tier: Free
-- Name: Siegorvus
- Tier: Free
-- Name: вася васильев
- Tier: Free
-- Name: Mci
+- Name: Joshington Awesomahee
Tier: Revolutionary
-- Name: KateSlime206
+- Name: Joshua Hines
Tier: Nuclear Operative
-- Name: Robert
- Tier: Free
-- Name: Ben Z'
+- Name: Joshua Meyer
+ Tier: Nuclear Operative
+- Name: JT Billings
Tier: Revolutionary
-- Name: Luke
- Tier: Free
-- Name: Tyler Putnam
- Tier: Free
-- Name: Ville Sarmiola
- Tier: Free
-- Name: kelaclone
- Tier: Free
-- Name: Archmonarch
+- Name: JustanAnus
+ Tier: Nuclear Operative
+- Name: Kai
+ Tier: Nuclear Operative
+- Name: Kaitlynn Brennan
Tier: Syndicate Agent
-- Name: Brett
- Tier: Free
-- Name: Hanzdegloker
+- Name: kannthus
Tier: Syndicate Agent
-- Name: Piotr
+- Name: Karma Hunter
Tier: Revolutionary
-- Name: CloudyClover
+- Name: Kashieru
+ Tier: Revolutionary
+- Name: KateSlime206
+ Tier: Nuclear Operative
+- Name: Kayla Solace
Tier: Revolutionary
-- Name: Jim Masterson
- Tier: Free
- Name: kenneth heller
Tier: Syndicate Agent
-- Name: Gosera -
- Tier: Syndicate Agent
-- Name: Asaf Ataş
- Tier: Free
-- Name: DeckDevilYGO
- Tier: Free
-- Name: nokko
- Tier: Free
-- Name: Krokodiel89
- Tier: Free
-- Name: Nojan Niaki
+- Name: Kerb
Tier: Revolutionary
-- Name: YuNii
+- Name: Kerensky
+ Tier: Revolutionary
+- Name: Kesiath
Tier: Nuclear Operative
-- Name: Georgia Partyka
- Tier: Syndicate Agent
-- Name: Teeth
- Tier: Free
-- Name: DrMelon
+- Name: Kevin
+ Tier: Nuclear Operative
+- Name: Kevin
+ Tier: Nuclear Operative
+- Name: Kieue Caprie
Tier: Revolutionary
-- Name: Molly the Bully
+- Name: kik
+ Tier: Revolutionary
+- Name: Kim
+ Tier: Revolutionary
+- Name: kithri
Tier: Nuclear Operative
-- Name: An Evil Eel
- Tier: Free
-- Name: Hasan al-Binabi
- Tier: Free
-- Name: franz photos
- Tier: Free
-- Name: Milkshake45752
- Tier: Free
-- Name: Bru Tal
- Tier: Free
-- Name: krberryy
+- Name: Koyki
Tier: Revolutionary
-- Name: Thomas Mcintosh
- Tier: Free
-- Name: Alex Nordlund
- Tier: Syndicate Agent
-- Name: Swindel_
- Tier: Syndicate Agent
-- Name: MrGloopy
+- Name: krberryy
Tier: Revolutionary
-- Name: blitz gaming
- Tier: Free
-- Name: Nicholi
+- Name: kristopher arnott
Tier: Syndicate Agent
-- Name: Taber
+- Name: KrystalDisc
Tier: Revolutionary
-- Name: 以迪 黃
- Tier: Free
-- Name: W Geertsma
- Tier: Free
-- Name: BloodyJMary
- Tier: Free
-- Name: quri1q
- Tier: Free
-- Name: SleepyBody91
- Tier: Free
-- Name: David Gee
- Tier: Free
-- Name: ThoranTW
- Tier: Free
-- Name: pigeopeas
- Tier: Free
-- Name: Zakory L Holbrook
+- Name: Krystian Janecki
Tier: Revolutionary
-- Name: Aiden
+- Name: Kubakura
Tier: Revolutionary
-- Name: Pangaron
- Tier: Syndicate Agent
-- Name: NeatVisor
- Tier: Free
-- Name: Solidus Snake
+- Name: Kyle Hipke
Tier: Nuclear Operative
-- Name: Oliver Skyler
- Tier: Free
-- Name: mustafa kılıç
- Tier: Free
-- Name: IceStorm theDragon
- Tier: Revolutionary
-- Name: Indri
+- Name: Kyle Tyo
+ Tier: Syndicate Agent
+- Name: lapatison
Tier: Revolutionary
-- Name: Graded
- Tier: Free
-- Name: tunnp0
- Tier: Free
-- Name: Vexxtraordinary
+- Name: LeoZ
Tier: Revolutionary
-- Name: Sam Hediger
- Tier: Free
-- Name: Aldi Abduali
- Tier: Free
-- Name: Adam Clarke
- Tier: Free
-- Name: Munt
- Tier: Free
-- Name: Obspogon
- Tier: Free
-- Name: Adrian Thompson
- Tier: Free
-- Name: albatrossMonarch
- Tier: Free
-- Name: JaQal
- Tier: Free
-- Name: Simofie
- Tier: Free
-- Name: redgunny
- Tier: Free
-- Name: Kevin Chapman
- Tier: Free
-- Name: Sjevi Aardvark
- Tier: Free
-- Name: Chris Walter
- Tier: Free
-- Name: David Sterling
- Tier: Free
-- Name: Zcore
- Tier: Free
-- Name: tapohuy
- Tier: Free
-- Name: MasterFurret
+- Name: LeTobbs
Tier: Revolutionary
-- Name: Christian Hicks
+- Name: Lieutenant Colonel Orangejuice
Tier: Syndicate Agent
-- Name: François Desautels
+- Name: Lilith
+ Tier: Nuclear Operative
+- Name: liltenhead
Tier: Revolutionary
-- Name: awndrssk
- Tier: Free
-- Name: Vice Emargo
- Tier: Syndicate Agent
-- Name: Mihailo Trickovic
+- Name: Luaan
Tier: Syndicate Agent
-- Name: Sandvich enjoyer
+- Name: Lucas Welsh
Tier: Revolutionary
-- Name: Higgtastic
+- Name: lukiw
Tier: Revolutionary
-- Name: "612"
+- Name: Luzurper
Tier: Revolutionary
-- Name: AlecRazec
+- Name: Lyndomen
Tier: Revolutionary
-- Name: Repo
- Tier: Nuclear Operative
-- Name: Ignoramis
- Tier: Free
-- Name: Jeffery Pointer
+- Name: Madeleine LeFleur
Tier: Syndicate Agent
-- Name: DireBoar
- Tier: Free
-- Name: oBerry
- Tier: Free
-- Name: Adam Smedstad
- Tier: Free
-- Name: Superglue
+- Name: mage_period
Tier: Syndicate Agent
-- Name: DrIvoPotato
- Tier: Nuclear Operative
-- Name: Petalmeat
- Tier: Free
+- Name: Magelfik
+ Tier: Revolutionary
- Name: Malachi Housewright
Tier: Revolutionary
-- Name: Fallcon
- Tier: Free
-- Name: ShaunTexas
- Tier: Free
-- Name: HCG
- Tier: Free
-- Name: GeneralMarty
- Tier: Free
-- Name: Nicholas
- Tier: Nuclear Operative
-- Name: Geekyhobo2
+- Name: March
+ Tier: Syndicate Agent
+- Name: Marios Sardis
Tier: Revolutionary
-- Name: Alexandre Courtin
+- Name: Mason Fawcett
Tier: Revolutionary
-- Name: Wolfie
+- Name: MasterFurret
Tier: Revolutionary
-- Name: Shaina Gibson
- Tier: Free
-- Name: Charles Baron
- Tier: Free
-- Name: Constellations
- Tier: Free
-- Name: tynobeard 123
+- Name: Mathew McGuire
Tier: Revolutionary
-- Name: Lyndomen
+- Name: Matthew C Miklaucic
Tier: Revolutionary
-- Name: Glenn Olsen
- Tier: Syndicate Agent
-- Name: Wiliam
- Tier: Nuclear Operative
-- Name: SHANE ALAN ZINDA
- Tier: Free
-- Name: Saiiryn
- Tier: Free
-- Name: AC Computing
- Tier: Nuclear Operative
-- Name: eric156
- Tier: Free
-- Name: Katarn
- Tier: Free
-- Name: Blight
- Tier: Syndicate Agent
-- Name: Tim Foley
- Tier: Free
-- Name: Sven Tammerijn
+- Name: Matthias Bechtold
Tier: Revolutionary
-- Name: Raw Toast
- Tier: Free
-- Name: Watson Whittington
- Tier: Syndicate Agent
-- Name: David
+- Name: Mci
Tier: Revolutionary
-- Name: DadNotTheBelt
- Tier: Free
-- Name: Enricoc3l
+- Name: MechaKitty
Tier: Revolutionary
-- Name: Vandell
- Tier: Free
-- Name: BlueisDumb
- Tier: Nuclear Operative
-- Name: Buldinn Girshovich
- Tier: Nuclear Operative
-- Name: Whistling Jake
+- Name: Mega Awesome Man
+ Tier: Syndicate Agent
+- Name: merklaw
Tier: Revolutionary
-- Name: Wallace Megas
- Tier: Free
-- Name: Samtaro
- Tier: Nuclear Operative
-- Name: Aexxie
+- Name: Michael Van Gaasbeck
Tier: Revolutionary
-- Name: Fiebertraum Illhead
+- Name: Mihailo Trickovic
Tier: Syndicate Agent
-- Name: tokie
- Tier: Nuclear Operative
-- Name: Odin7heWanderer
- Tier: Free
-- Name: Jeff Tatem
- Tier: Nuclear Operative
-- Name: M4shr00m
- Tier: Free
-- Name: Gordod
+- Name: Mikhail
+ Tier: Revolutionary
+- Name: mikiju
Tier: Syndicate Agent
-- Name: Skarlet
- Tier: Free
-- Name: March
+- Name: Minemoder
Tier: Syndicate Agent
-- Name: Александр Белошапка
+- Name: Miniwoffer
Tier: Revolutionary
-- Name: Dave
+- Name: Mitchell Marry
Tier: Revolutionary
-- Name: Akira
+- Name: mksky
Tier: Revolutionary
-- Name: Alix Shepard
+- Name: Molly the Bully
Tier: Nuclear Operative
-- Name: JhenMaster
- Tier: Free
-- Name: Lieutenant Colonel Orangejuice
+- Name: Molon
Tier: Syndicate Agent
-- Name: TheGoldElite
+- Name: Mono
Tier: Revolutionary
-- Name: Gnomo
- Tier: Nuclear Operative
-- Name: Never Solus
- Tier: Free
-- Name: Ari.
+- Name: Mr_Clank
Tier: Revolutionary
-- Name: Kevin
+- Name: MrGloopy
+ Tier: Revolutionary
+- Name: Mythtic B
+ Tier: Revolutionary
+- Name: Nagano
+ Tier: Revolutionary
+- Name: Nat
+ Tier: Revolutionary
+- Name: Nathan Zaldivar
Tier: Nuclear Operative
-- Name: DubzyVEVO
+- Name: Nathaniel Joseph Hurd
Tier: Revolutionary
-- Name: ikamuse johnson
+- Name: Nathaniel Taylor
Tier: Revolutionary
-- Name: Saphire
+- Name: Nemmay
Tier: Revolutionary
-- Name: Gavin Simmons
+- Name: Neo Move
Tier: Syndicate Agent
-- Name: Tamora Droppa
+- Name: NetGlitch
+ Tier: Nuclear Operative
+- Name: Nicholas
+ Tier: Nuclear Operative
+- Name: Nicholas Williamson
+ Tier: Nuclear Operative
+- Name: Nicholi
+ Tier: Syndicate Agent
+- Name: Nictis
Tier: Revolutionary
-- Name: Gaxeer
+- Name: Ninja
Tier: Syndicate Agent
-- Name: rosysyn
+- Name: Nojan Niaki
Tier: Revolutionary
-- Name: Scott MacCombie
- Tier: Free
-- Name: Jeremy Hernandez
+- Name: Noodle is me
Tier: Syndicate Agent
-- Name: Kai
- Tier: Nuclear Operative
-- Name: Victoly
- Tier: Free
-- Name: chilicheesecat
- Tier: Free
-- Name: Arthur Norris
+- Name: Novaq
+ Tier: Revolutionary
+- Name: Noxy
Tier: Syndicate Agent
-- Name: Carbonhell
+- Name: Nudal
+ Tier: Revolutionary
+- Name: Nugmania
+ Tier: Revolutionary
+- Name: Nyxilath
+ Tier: Nuclear Operative
+- Name: orange color
+ Tier: Revolutionary
+- Name: osborn
Tier: Syndicate Agent
-- Name: BrittaBee93
- Tier: Free
-- Name: Rasmus Cedergren
+- Name: Oscar Tobias Herra Bravo
Tier: Revolutionary
-- Name: Greggo
+- Name: Oxyclean114
+ Tier: Revolutionary
+- Name: Pangaron
Tier: Syndicate Agent
- Name: Pasemi
Tier: Revolutionary
-- Name: Unknown Kiwi
+- Name: peanut
Tier: Revolutionary
-- Name: Mitchell Marry
+- Name: Penguin Commoner
Tier: Revolutionary
-- Name: Matouš Hrdlička
+- Name: Phillip Inman
Tier: Revolutionary
-- Name: Roman
- Tier: Syndicate Agent
-- Name: Jacob Schramm
- Tier: Free
-- Name: Nathan Zaldivar
+- Name: Phycoweirdo
Tier: Nuclear Operative
-- Name: SpydAxe
+- Name: Pinet
+ Tier: Nuclear Operative
+- Name: Piotr
Tier: Revolutionary
-- Name: BokChoy
+- Name: pooba
+ Tier: Revolutionary
+- Name: Powder
+ Tier: Revolutionary
+- Name: ppie
+ Tier: Syndicate Agent
+- Name: Prayer
Tier: Nuclear Operative
-- Name: Nicholas Williamson
+- Name: Preston Pickering
+ Tier: Revolutionary
+- Name: Prof. Omii
Tier: Nuclear Operative
-- Name: William Grondin
+- Name: ProxyGen
Tier: Revolutionary
-- Name: KevKev
- Tier: Free
-- Name: Gothryd
+- Name: Psy
Tier: Revolutionary
-- Name: Brandon Campbell
- Tier: Free
-- Name: Matthew C Miklaucic
+- Name: queednyeb
Tier: Revolutionary
-- Name: Serianas
- Tier: Nuclear Operative
-- Name: lapatison
+- Name: Quonn
+ Tier: Syndicate Agent
+- Name: Raccoononi
Tier: Revolutionary
-- Name: Uinseann
+- Name: Rafał Kowalewski
Tier: Revolutionary
-- Name: osborn
+- Name: Raiden Johnson
+ Tier: Revolutionary
+- Name: Rainy
+ Tier: Revolutionary
+- Name: RamenZorn
Tier: Syndicate Agent
-- Name: LPGaming
- Tier: Free
-- Name: Alex Fry
- Tier: Nuclear Operative
- Name: Ramiro Agis
Tier: Revolutionary
-- Name: Mikhail
+- Name: Random Person
+ Tier: Syndicate Agent
+- Name: Rasmus Cedergren
Tier: Revolutionary
-- Name: SnapKick
+- Name: Raspberry1111
Tier: Revolutionary
-- Name: liltenhead
+- Name: Rat Fungus
+ Tier: Nuclear Operative
+- Name: Rat Man
Tier: Revolutionary
-- Name: James Andrew Peoples Jr
+- Name: RedChair368
Tier: Revolutionary
-- Name: Serathis
+- Name: Repo
+ Tier: Nuclear Operative
+- Name: Richard "Rei" Weeks
+ Tier: Syndicate Agent
+- Name: Robert Reed
+ Tier: Nuclear Operative
+- Name: Robin Rottstock
Tier: Revolutionary
-- Name: Joel
+- Name: Roman
+ Tier: Syndicate Agent
+- Name: Rome
Tier: Revolutionary
-- Name: Rafał Kowalewski
+- Name: rosysyn
Tier: Revolutionary
-- Name: Kris Piper
- Tier: Free
-- Name: Anthony Chicko
+- Name: Rusty Shackleford
+ Tier: Nuclear Operative
+- Name: Ryan Hanson
+ Tier: Revolutionary
+- Name: Ryan Kelly
+ Tier: Revolutionary
+- Name: RyanTuek
+ Tier: Revolutionary
+- Name: S.C.
+ Tier: Syndicate Agent
+- Name: S1rFl0
Tier: Revolutionary
-- Name: Taylor
+- Name: Sam Caesar
Tier: Revolutionary
-- Name: Phillip Inman
+- Name: Samtaro
+ Tier: Nuclear Operative
+- Name: Sandvich enjoyer
Tier: Revolutionary
-- Name: Zakanater 19
+- Name: Saphire
Tier: Revolutionary
-- Name: Molon
- Tier: Syndicate Agent
-- Name: Peter "Azmond" Newhouse
- Tier: Free
-- Name: Snowni
- Tier: Nuclear Operative
-- Name: Tom Cruize
- Tier: Syndicate Agent
-- Name: Corpus Inc.
+- Name: SarahRaven
Tier: Revolutionary
-- Name: BlastWind
- Tier: Free
-- Name: Echinodermata
+- Name: Sartec
Tier: Revolutionary
-- Name: Hamcha
+- Name: ScarKy0
Tier: Revolutionary
-- Name: Kaitlynn Brennan
+- Name: Sean Lilly
Tier: Syndicate Agent
-- Name: Oxyclean114
- Tier: Revolutionary
-- Name: JustanAnus
- Tier: Nuclear Operative
-- Name: wtcwr68
- Tier: Nuclear Operative
-- Name: Azmith Blackheart
+- Name: Seinfeld
Tier: Revolutionary
-- Name: Collin R Terrell
+- Name: Semiotics
+ Tier: Syndicate Agent
+- Name: Serathis
Tier: Revolutionary
-- Name: Cormos Lemming
+- Name: Serianas
Tier: Nuclear Operative
-- Name: grhmhome
+- Name: Seth Morron
Tier: Revolutionary
-- Name: SpiffyNnemonic
+- Name: showgun117
+ Tier: Syndicate Agent
+- Name: Simon N Heath
Tier: Revolutionary
-- Name: Callum Tubrett
+- Name: SireHambone
Tier: Nuclear Operative
-- Name: Hydration
+- Name: sk3iron
Tier: Revolutionary
-- Name: Morty
- Tier: Free
-- Name: Dylan Roberts
+- Name: Sleeepz
Tier: Syndicate Agent
-- Name: mrniceguy0o0
- Tier: Free
-- Name: Wrexbe
+- Name: SnapKick
Tier: Revolutionary
-- Name: Frege Beach
+- Name: Snowlili
Tier: Revolutionary
-- Name: DBF
+- Name: Snowni
+ Tier: Nuclear Operative
+- Name: Solid_Syn
+ Tier: Revolutionary
+- Name: Solidus Snake
+ Tier: Nuclear Operative
+- Name: SotetSotetSotetSotetSotet
Tier: Syndicate Agent
-- Name: Kesiath
+- Name: Southbridge
Tier: Nuclear Operative
-- Name: Voltinho
+- Name: Sparlight
+ Tier: Nuclear Operative
+- Name: SpiffyNnemonic
Tier: Revolutionary
-- Name: AquaDraco
+- Name: spookerton
+ Tier: Syndicate Agent
+- Name: Sporkyz
Tier: Revolutionary
-- Name: A Yaj
+- Name: SpydAxe
Tier: Revolutionary
-- Name: Miniwoffer
+- Name: StaceyBalcom
Tier: Revolutionary
-- Name: hh
+- Name: Star Lord
Tier: Syndicate Agent
-- Name: Chase Trotter
- Tier: Nuclear Operative
-- Name: Skifan180
- Tier: Free
-- Name: Florian
+- Name: starch
+ Tier: Syndicate Agent
+- Name: StaticeStorm
+ Tier: Syndicate Agent
+- Name: Statix AraAra
Tier: Revolutionary
-- Name: Hoplophobia
+- Name: Stedar
+ Tier: Syndicate Agent
+- Name: stikfigz
Tier: Revolutionary
-- Name: Viridian
- Tier: Free
-- Name: Daskata
+- Name: Sufary
Tier: Nuclear Operative
-- Name: TacoCub
+- Name: Superglue
+ Tier: Syndicate Agent
+- Name: Sven Tammerijn
Tier: Revolutionary
-- Name: Jack Rose
+- Name: Swindel_
+ Tier: Syndicate Agent
+- Name: Swix Swix
Tier: Revolutionary
-- Name: Chem_Inventory
- Tier: Nuclear Operative
-- Name: Jax
- Tier: Nuclear Operative
-- Name: The Hateful Flesh
+- Name: T.P_Gaming
Tier: Revolutionary
-- Name: Gavin Jones
- Tier: Nuclear Operative
-- Name: Prof. Omii
- Tier: Nuclear Operative
-- Name: mksky
+- Name: Tabatha Mendonski
Tier: Revolutionary
-- Name: Greyhound Connect
+- Name: Taber
Tier: Revolutionary
-- Name: Alex Tempest
+- Name: TacoCub
Tier: Revolutionary
-- Name: Rat Fungus
+- Name: Tairenar
Tier: Nuclear Operative
-- Name: Will M.
+- Name: Talbot
Tier: Revolutionary
-- Name: spinnermaster
- Tier: Free
-- Name: Koyki
+- Name: Tamora Droppa
Tier: Revolutionary
-- Name: Hunter James
- Tier: Nuclear Operative
-- Name: Valinov
+- Name: taydeo
Tier: Nuclear Operative
-- Name: Nemmay
- Tier: Revolutionary
-- Name: Dylan Hull
+- Name: Taylor
Tier: Revolutionary
-- Name: FungiFog
+- Name: Tee The Kobold
Tier: Revolutionary
-- Name: S.C.
+- Name: The Best Sean
Tier: Syndicate Agent
-- Name: "'-Y-"
+- Name: the good king wompicus
Tier: Syndicate Agent
-- Name: pooba
- Tier: Revolutionary
-- Name: evilJenny
+- Name: The Hateful Flesh
Tier: Revolutionary
-- Name: clyf
- Tier: Free
-- Name: Kerb
+- Name: The Pain
+ Tier: Syndicate Agent
+- Name: Thebluegameingdoggo
Tier: Revolutionary
-- Name: queednyeb
+- Name: TheGoldElite
Tier: Revolutionary
-- Name: Robin Rottstock
+- Name: TheGungeonologist
Tier: Revolutionary
- Name: Third
Tier: Revolutionary
-- Name: Altana
+- Name: Thomas Pollard
+ Tier: Nuclear Operative
+- Name: Tia
Tier: Revolutionary
-- Name: showgun117
+- Name: tokie
+ Tier: Nuclear Operative
+- Name: Tom Cruize
Tier: Syndicate Agent
-- Name: Durp
+- Name: Tom Goodman (TauOmicronMu#2500)
Tier: Revolutionary
-- Name: Joshington Awesomahee
+- Name: Tomeno
Tier: Revolutionary
-- Name: Diklyquill
+- Name: ToonaLemons
Tier: Revolutionary
-- Name: Eric VW
+- Name: tremors08
+ Tier: Syndicate Agent
+- Name: Trent Warfel
+ Tier: Nuclear Operative
+- Name: Trevor Johnson
Tier: Revolutionary
-- Name: Nat
+- Name: Trevor McConnell
+ Tier: Nuclear Operative
+- Name: TrixxedHeart
+ Tier: Nuclear Operative
+- Name: Troll_King_907
+ Tier: Nuclear Operative
+- Name: Ty Ashley
Tier: Revolutionary
-- Name: Evan Armstrong
+- Name: tyler adams
Tier: Revolutionary
-- Name: Citizen Battle
+- Name: Tyler Young
Tier: Nuclear Operative
-- Name: Cyberate
+- Name: tynobeard 123
Tier: Revolutionary
-- Name: Enzoman12
- Tier: Nuclear Operative
-- Name: Curtis Pearson
+- Name: Uinseann
Tier: Revolutionary
-- Name: Mono
+- Name: Unknown Kiwi
Tier: Revolutionary
-- Name: Xenon Dragon
- Tier: Syndicate Agent
-- Name: Jerg Jerginson
+- Name: Valinov
Tier: Nuclear Operative
-- Name: kik
+- Name: Vexxtraordinary
Tier: Revolutionary
-- Name: Star Lord
+- Name: Vice Emargo
Tier: Syndicate Agent
-- Name: kannthus
+- Name: vifs_vestige
Tier: Syndicate Agent
-- Name: Ethan Keller
- Tier: Revolutionary
-- Name: John Doe
- Tier: Nuclear Operative
-- Name: Robert Reed
- Tier: Nuclear Operative
-- Name: DramaBuns
+- Name: Violette
Tier: Revolutionary
-- Name: Bush Boy
- Tier: Nuclear Operative
-- Name: Quonn
+- Name: VividWisp
Tier: Syndicate Agent
-- Name: KrystalDisc
- Tier: Revolutionary
-- Name: LeTobbs
+- Name: VmasterVX
Tier: Revolutionary
-- Name: Darren Brady
- Tier: Free
-- Name: Zandario
+- Name: Voidliing
Tier: Revolutionary
-- Name: Lucas Welsh
+- Name: Voltinho
Tier: Revolutionary
-- Name: Nico Thate
- Tier: Free
-- Name: Anthony Fleck
- Tier: Nuclear Operative
-- Name: vifs_vestige
+- Name: Watson Whittington
Tier: Syndicate Agent
-- Name: Bobberunio
+- Name: Whistling Jake
Tier: Revolutionary
-- Name: Zadenae
- Tier: Nuclear Operative
-- Name: Into the Stars - Community Host
+- Name: Wiliam
Tier: Nuclear Operative
-- Name: arthropods
+- Name: Will M.
Tier: Revolutionary
-- Name: Jack Gardiner
+- Name: William Grondin
Tier: Revolutionary
-- Name: BigMcLargeHuge
- Tier: Free
-- Name: merklaw
+- Name: Wolfie
Tier: Revolutionary
-- Name: CPM311
+- Name: Wrexbe
Tier: Revolutionary
-- Name: NetGlitch
- Tier: Nuclear Operative
-- Name: Bahke
- Tier: Nuclear Operative
-- Name: Prayer
+- Name: wtcwr68
Tier: Nuclear Operative
-- Name: Trevor McConnell
+- Name: WWII Kitsune
Tier: Nuclear Operative
-- Name: MetalClone
- Tier: Free
-- Name: Farewell Fire
- Tier: Syndicate Agent
-- Name: Ninja
+- Name: Xenon Dragon
Tier: Syndicate Agent
-- Name: all fields
+- Name: yeoshua
Tier: Syndicate Agent
-- Name: Kyle Hipke
+- Name: YuNii
Tier: Nuclear Operative
-- Name: Daniel Thompson
+- Name: Z4NEER
+ Tier: Nuclear Operative
+- Name: Zadenae
+ Tier: Nuclear Operative
+- Name: Zak The Dragon
Tier: Revolutionary
-- Name: Tyler Young
+- Name: Zakanater 19
+ Tier: Revolutionary
+- Name: Zakory L Holbrook
+ Tier: Revolutionary
+- Name: Zandario
+ Tier: Revolutionary
+- Name: zedd
Tier: Nuclear Operative
-- Name: LeoZ
+- Name: Zella Zane
Tier: Revolutionary
-- Name: avcde
+- Name: Zenari Ari
Tier: Nuclear Operative
-- Name: Tomeno
+- Name: Zero
+ Tier: Revolutionary
+- Name: Zoe Rose
+ Tier: Syndicate Agent
+- Name: Александр Белошапка
Tier: Revolutionary
id-card-console-window-job-title-label = Job title:
id-card-console-window-eject-button = Eject
id-card-console-window-insert-button = Insert
-id-card-console-window-job-selection-label = Job presets (sets department and job icon):
+id-card-console-window-job-selection-label = Job preset (sets department and job icon):
+id-card-console-window-select-all-button = Grant all
+id-card-console-window-deselect-all-button = Revoke all
access-id-card-console-component-no-hands-error = You have no hands.
id-card-console-privileged-id = Privileged ID
marking-HumanHairVolaju = Volaju
marking-HumanHairWisp = Wisp
marking-HumanHairLongWithBangs = Long With Bangs
+marking-HumanHairOverEyePigtail = Pigtail (Over Eye)
+# Generic verbs
delete-verb-get-data-text = Delete
edit-solutions-verb-get-data-text = Edit Solutions
explode-verb-get-data-text = Explode
toolshed-verb-mark-description = Places this entity into the $marked variable, a list of entities, replacing its prior value.
export-entity-verb-get-data-text = Export sprite
+
+# Tools verbs
+admin-verbs-rejuvenate = Rejuvenate
+admin-verbs-make-indestructible = Make Indestructible
+admin-verbs-make-vulnerable = Make Vulnerable
+admin-verbs-refill-battery = Refill Battery
+admin-verbs-drain-battery = Drain Battery
+admin-verbs-infinite-battery = Infinite Battery
+admin-verbs-block-unanchoring = Block Unanchoring
+admin-verbs-refill-internals-oxygen = Refill Internals Oxygen
+admin-verbs-refill-internals-nitrogen = Refill Internals Nitrogen
+admin-verbs-refill-internals-plasma = Refill Internals Plasma
+admin-verbs-send-to-test-arena = Send to test arena
+admin-verbs-grant-all-access = Grant All Access
+admin-verbs-revoke-all-access = Revoke All Access
+admin-verbs-adjust-stack = Adjust Stack
+admin-verbs-fill-stack = Fill Stack
+admin-verbs-rename = Rename
+admin-verbs-redescribe = Redescribe
+admin-verbs-rename-and-redescribe = Rename & Redescribe
+admin-verbs-bar-job-slots = Bar job slots
+admin-verbs-locate-cargo-shuttle = Locate Cargo Shuttle
+admin-verbs-halt-movement = Halt Movement
+admin-verbs-unpause-map = Unpause Map
+admin-verbs-pause-map = Pause Map
+admin-verbs-snap-joints = Snap Joints
+admin-verbs-make-minigun = Make Minigun
+admin-verbs-set-bullet-amount = Set Bullet Amount
+
+# Toggles verbs
+admin-verbs-bolt = Bolt
+admin-verbs-unbolt = Unbolt
+admin-verbs-emergency-access-on = Emergency Access On
+admin-verbs-emergency-access-off = Emergency Access Off
+
+# Dialogs verbs
+admin-verbs-dialog-adjust-stack-amount = Amount (max {$max})
+admin-verbs-dialog-rename-title = Rename
+admin-verbs-dialog-rename-name = Name
+admin-verbs-dialog-redescribe-title = Redescribe
+admin-verbs-dialog-redescribe-description = Description
+admin-verbs-dialog-rename-and-redescribe-title = Rename & Redescribe
+admin-verbs-dialog-set-bullet-amount-title = Set Bullet Amount
+admin-verbs-dialog-set-bullet-amount-amount = Amount (standard {$cap})
bwoink-user-title = Admin Message
+bwoink-admin-title = Admin Help
bwoink-system-starmute-message-no-other-users = *System: Nobody is available to receive your message. Try pinging Game Admins on Discord.
cluwne-transform = {CAPITALIZE(THE($target))} turned into a cluwne!
cluwne-name-prefix = cluwnified {$baseName}
+cluwne-knock-emote = spasms
+cluwne-giggle-emote = honks
comp-storage-window-title = Storage Item
comp-storage-window-weight = { $weight }/{ $maxWeight }, Max Size: {$size}
comp-storage-window-slots = Slots: { $itemCount }/{ $maxCount }, Max Size: {$size}
+comp-storage-window-dummy = Dummy
comp-storage-verb-open-storage = Open Storage
comp-storage-verb-close-storage = Close Storage
credits-window-original-remake-team-section-title = Original Space Station 13 Remake Team
credits-window-immortals-title = In Memoriam
credits-window-special-thanks-section-title = Special Thanks
+credits-window-previous-page-button = Previous Page
+credits-window-next-page-button = Next Page
credits-window-attributions-directory = [color=white]Directory:[/color] {$directory}
credits-window-attributions-files = [color=white]Files:[/color] {$files}
--- /dev/null
+make-ghost-roles-window-title = Make Ghost Role
+
+make-ghost-roles-window-entity-label = Entity
+make-ghost-roles-window-role-name-label = Role Name
+make-ghost-roles-window-role-description-label = Role Description
+make-ghost-roles-window-role-rules-label = Role Rules
+make-ghost-roles-window-make-sentient-label = Make Sentient
+make-ghost-roles-window-initial-duration-label = Initial Duration (s)
+make-ghost-roles-window-join-extends-by-label = Joins Extend By (s)
+make-ghost-roles-window-max-duration-label = Max Duration (s)
+
+make-ghost-roles-window-make-button = Make
+
+# Raffle
+make-ghost-roles-window-raffle-not-button = Don't raffle
+make-ghost-roles-window-raffle-custom-settings-button = Custom settings
+
+make-ghost-roles-window-raffle-role-label = Raffle Role?
+make-ghost-roles-window-raffle-settings-label = {$id} (initial {$initialDuration}s, max {$maxDuration}s, join adds {$joinExtendsDurationBy}s)
+
+make-ghost-roles-window-raffle-warning-tooltip = The initial duration must not exceed the maximum duration.
guidebook-reagent-effect-description =
- {$chance ->
+ {$quantity ->
+ [0] {""}
+ *[other] If there is at least {$quantity}u {$reagent},{" "}
+ }{$chance ->
[1] { $effect }
*[other] Has a { NATURALPERCENT($chance, 2) } chance to { $effect }
}{ $conditionCount ->
+++ /dev/null
-reagent-effect-status-effect-Stun = stunning
-reagent-effect-status-effect-KnockedDown = knockdown
-reagent-effect-status-effect-Jitter = jittering
-reagent-effect-status-effect-TemporaryBlindness = blindness
-reagent-effect-status-effect-SeeingRainbows = hallucinations
-reagent-effect-status-effect-Muted = inability to speak
-reagent-effect-status-effect-Stutter = stuttering
-reagent-effect-status-effect-ForcedSleep = unconsciousness
-reagent-effect-status-effect-Drunk = drunkenness
-reagent-effect-status-effect-PressureImmunity = pressure immunity
-reagent-effect-status-effect-Pacified = combat pacification
-reagent-effect-status-effect-RatvarianLanguage = ratvarian language patterns
-reagent-effect-status-effect-StaminaModifier = modified stamina
-reagent-effect-status-effect-RadiationProtection = radiation protection
-reagent-effect-status-effect-Drowsiness = drowsiness
-reagent-effect-status-effect-Adrenaline = adrenaline
*[other] satiate
}
-reagent-effect-guidebook-create-entity-reaction-effect =
+entity-effect-guidebook-spawn-entity =
{ $chance ->
[1] Creates
*[other] create
*[other] {$amount} {MAKEPLURAL($entname)}
}
-reagent-effect-guidebook-explosion-reaction-effect =
+entity-effect-guidebook-explosion =
{ $chance ->
[1] Causes
*[other] cause
} an explosion
-reagent-effect-guidebook-emp-reaction-effect =
+entity-effect-guidebook-emp =
{ $chance ->
[1] Causes
*[other] cause
} an electromagnetic pulse
-reagent-effect-guidebook-flash-reaction-effect =
+entity-effect-guidebook-flash =
{ $chance ->
[1] Causes
*[other] cause
} a blinding flash
-reagent-effect-guidebook-foam-area-reaction-effect =
+entity-effect-guidebook-foam-area =
{ $chance ->
[1] Creates
*[other] create
} large quantities of foam
-reagent-effect-guidebook-smoke-area-reaction-effect =
+entity-effect-guidebook-smoke-area =
{ $chance ->
[1] Creates
*[other] create
} large quantities of smoke
-reagent-effect-guidebook-satiate-thirst =
+entity-effect-guidebook-satiate-thirst =
{ $chance ->
[1] Satiates
*[other] satiate
*[other] thirst at {NATURALFIXED($relative, 3)}x the average rate
}
-reagent-effect-guidebook-satiate-hunger =
+entity-effect-guidebook-satiate-hunger =
{ $chance ->
[1] Satiates
*[other] satiate
*[other] hunger at {NATURALFIXED($relative, 3)}x the average rate
}
-reagent-effect-guidebook-health-change =
+entity-effect-guidebook-health-change =
{ $chance ->
[1] { $healsordeals ->
[heals] Heals
}
} { $changes }
-reagent-effect-guidebook-even-health-change =
+entity-effect-guidebook-even-health-change =
{ $chance ->
[1] { $healsordeals ->
[heals] Evenly heals
}
} { $changes }
-
-reagent-effect-guidebook-status-effect =
+entity-effect-guidebook-status-effect-old =
{ $type ->
[update]{ $chance ->
[1] Causes
- *[other] cause
- } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
+ *[other] cause
+ } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
[add] { $chance ->
[1] Causes
*[other] cause
} {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} with accumulation
- *[set] { $chance ->
+ [set] { $chance ->
[1] Causes
*[other] cause
- } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
- [remove]{ $chance ->
+ } {LOC($key)} for {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
+ *[remove]{ $chance ->
[1] Removes
*[other] remove
} {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)}
}
-reagent-effect-guidebook-status-effect-delay =
+entity-effect-guidebook-status-effect =
{ $type ->
+ [update]{ $chance ->
+ [1] Causes
+ *[other] cause
+ } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
[add] { $chance ->
[1] Causes
*[other] cause
} {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} with accumulation
- *[set] { $chance ->
+ [set] { $chance ->
[1] Causes
*[other] cause
} {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
- [remove]{ $chance ->
+ *[remove]{ $chance ->
[1] Removes
*[other] remove
} {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)}
- } after a {NATURALFIXED($delay, 3)} second delay
+ } { $delay ->
+ [0] immediately
+ *[other] after a {NATURALFIXED($delay, 3)} second delay
+ }
+
+entity-effect-guidebook-status-effect-indef =
+ { $type ->
+ [update]{ $chance ->
+ [1] Causes
+ *[other] cause
+ } permanent {LOC($key)}
+ [add] { $chance ->
+ [1] Causes
+ *[other] cause
+ } permanent {LOC($key)}
+ [set] { $chance ->
+ [1] Causes
+ *[other] cause
+ } permanent {LOC($key)}
+ *[remove]{ $chance ->
+ [1] Removes
+ *[other] remove
+ } {LOC($key)}
+ } { $delay ->
+ [0] immediately
+ *[other] after a {NATURALFIXED($delay, 3)} second delay
+ }
-reagent-effect-guidebook-knockdown =
+entity-effect-guidebook-knockdown =
{ $type ->
[update]{ $chance ->
[1] Causes
} {NATURALFIXED($time, 3)} {MANY("second", $time)} of knockdown
}
-reagent-effect-guidebook-set-solution-temperature-effect =
+entity-effect-guidebook-set-solution-temperature-effect =
{ $chance ->
[1] Sets
*[other] set
} the solution temperature to exactly {NATURALFIXED($temperature, 2)}k
-reagent-effect-guidebook-adjust-solution-temperature-effect =
+entity-effect-guidebook-adjust-solution-temperature-effect =
{ $chance ->
[1] { $deltasign ->
[1] Adds
*[-1] at least {NATURALFIXED($mintemp, 2)}k
}
-reagent-effect-guidebook-adjust-reagent-reagent =
+entity-effect-guidebook-adjust-reagent-reagent =
{ $chance ->
[1] { $deltasign ->
[1] Adds
*[-1] from
} the solution
-reagent-effect-guidebook-adjust-reagent-group =
+entity-effect-guidebook-adjust-reagent-group =
{ $chance ->
[1] { $deltasign ->
[1] Adds
*[-1] from
} the solution
-reagent-effect-guidebook-adjust-temperature =
+entity-effect-guidebook-adjust-temperature =
{ $chance ->
[1] { $deltasign ->
[1] Adds
*[-1] from
} the body it's in
-reagent-effect-guidebook-chem-cause-disease =
+entity-effect-guidebook-chem-cause-disease =
{ $chance ->
[1] Causes
*[other] cause
} the disease { $disease }
-reagent-effect-guidebook-chem-cause-random-disease =
+entity-effect-guidebook-chem-cause-random-disease =
{ $chance ->
[1] Causes
*[other] cause
} the diseases { $diseases }
-reagent-effect-guidebook-jittering =
+entity-effect-guidebook-jittering =
{ $chance ->
[1] Causes
*[other] cause
} jittering
-reagent-effect-guidebook-chem-clean-bloodstream =
+entity-effect-guidebook-clean-bloodstream =
{ $chance ->
[1] Cleanses
*[other] cleanse
} the bloodstream of other chemicals
-reagent-effect-guidebook-cure-disease =
+entity-effect-guidebook-cure-disease =
{ $chance ->
[1] Cures
*[other] cure
} diseases
-reagent-effect-guidebook-cure-eye-damage =
+entity-effect-guidebook-eye-damage =
{ $chance ->
[1] { $deltasign ->
[1] Deals
}
} eye damage
-reagent-effect-guidebook-chem-vomit =
+entity-effect-guidebook-vomit =
{ $chance ->
[1] Causes
*[other] cause
} vomiting
-reagent-effect-guidebook-create-gas =
+entity-effect-guidebook-create-gas =
{ $chance ->
[1] Creates
*[other] create
*[other] moles
} of { $gas }
-reagent-effect-guidebook-drunk =
+entity-effect-guidebook-drunk =
{ $chance ->
[1] Causes
*[other] cause
} drunkness
-reagent-effect-guidebook-electrocute =
+entity-effect-guidebook-electrocute =
{ $chance ->
[1] Electrocutes
*[other] electrocute
} the metabolizer for {NATURALFIXED($time, 3)} {MANY("second", $time)}
-reagent-effect-guidebook-emote =
+entity-effect-guidebook-emote =
{ $chance ->
[1] Will force
*[other] force
} the metabolizer to [bold][color=white]{$emote}[/color][/bold]
-reagent-effect-guidebook-extinguish-reaction =
+entity-effect-guidebook-extinguish-reaction =
{ $chance ->
[1] Extinguishes
*[other] extinguish
} fire
-reagent-effect-guidebook-flammable-reaction =
+entity-effect-guidebook-flammable-reaction =
{ $chance ->
[1] Increases
*[other] increase
} flammability
-reagent-effect-guidebook-ignite =
+entity-effect-guidebook-ignite =
{ $chance ->
[1] Ignites
*[other] ignite
} the metabolizer
-reagent-effect-guidebook-make-sentient =
+entity-effect-guidebook-make-sentient =
{ $chance ->
[1] Makes
*[other] make
} the metabolizer sentient
-reagent-effect-guidebook-make-polymorph =
+entity-effect-guidebook-make-polymorph =
{ $chance ->
[1] Polymorphs
*[other] polymorph
} the metabolizer into a { $entityname }
-reagent-effect-guidebook-modify-bleed-amount =
+entity-effect-guidebook-modify-bleed-amount =
{ $chance ->
[1] { $deltasign ->
[1] Induces
}
} bleeding
-reagent-effect-guidebook-modify-blood-level =
+entity-effect-guidebook-modify-blood-level =
{ $chance ->
[1] { $deltasign ->
[1] Increases
}
} blood level
-reagent-effect-guidebook-paralyze =
+entity-effect-guidebook-paralyze =
{ $chance ->
[1] Paralyzes
*[other] paralyze
} the metabolizer for at least {NATURALFIXED($time, 3)} {MANY("second", $time)}
-reagent-effect-guidebook-movespeed-modifier =
+entity-effect-guidebook-movespeed-modifier =
{ $chance ->
[1] Modifies
*[other] modify
- } movement speed by {NATURALFIXED($walkspeed, 3)}x for at least {NATURALFIXED($time, 3)} {MANY("second", $time)}
+ } movement speed by {NATURALFIXED($sprintspeed, 3)}x for at least {NATURALFIXED($time, 3)} {MANY("second", $time)}
-reagent-effect-guidebook-reset-narcolepsy =
+entity-effect-guidebook-reset-narcolepsy =
{ $chance ->
[1] Temporarily staves
*[other] temporarily stave
} off narcolepsy
-reagent-effect-guidebook-wash-cream-pie-reaction =
+entity-effect-guidebook-wash-cream-pie-reaction =
{ $chance ->
[1] Washes
*[other] wash
} off cream pie from one's face
-reagent-effect-guidebook-cure-zombie-infection =
+entity-effect-guidebook-cure-zombie-infection =
{ $chance ->
[1] Cures
*[other] cure
} an ongoing zombie infection
-reagent-effect-guidebook-cause-zombie-infection =
+entity-effect-guidebook-cause-zombie-infection =
{ $chance ->
[1] Gives
*[other] give
} an individual the zombie infection
-reagent-effect-guidebook-innoculate-zombie-infection =
+entity-effect-guidebook-innoculate-zombie-infection =
{ $chance ->
[1] Cures
*[other] cure
} an ongoing zombie infection, and provides immunity to future infections
-reagent-effect-guidebook-reduce-rotting =
+entity-effect-guidebook-reduce-rotting =
{ $chance ->
[1] Regenerates
*[other] regenerate
} {NATURALFIXED($time, 3)} {MANY("second", $time)} of rotting
-reagent-effect-guidebook-area-reaction =
+entity-effect-guidebook-area-reaction =
{ $chance ->
[1] Causes
*[other] cause
} a smoke or foam reaction for {NATURALFIXED($duration, 3)} {MANY("second", $duration)}
-reagent-effect-guidebook-add-to-solution-reaction =
+entity-effect-guidebook-add-to-solution-reaction =
{ $chance ->
[1] Causes
*[other] cause
- } chemicals applied to an object to be added to its internal solution container
+ } {$reagent} to be added to its internal solution container
-reagent-effect-guidebook-artifact-unlock =
+entity-effect-guidebook-artifact-unlock =
{ $chance ->
[1] Helps
*[other] help
} unlock an alien artifact.
-reagent-effect-guidebook-artifact-durability-restore =
+entity-effect-guidebook-artifact-durability-restore =
Restores {$restored} durability in active alien artifact nodes.
-reagent-effect-guidebook-plant-attribute =
+entity-effect-guidebook-plant-attribute =
{ $chance ->
[1] Adjusts
*[other] adjust
- } {$attribute} by [color={$colorName}]{$amount}[/color]
+ } {$attribute} by {$positive ->
+ [true] [color=red]{$amount}[/color]
+ *[false] [color=green]{$amount}[/color]
+ }
-reagent-effect-guidebook-plant-cryoxadone =
+entity-effect-guidebook-plant-cryoxadone =
{ $chance ->
[1] Ages back
*[other] age back
} the plant, depending on the plant's age and time to grow
-reagent-effect-guidebook-plant-phalanximine =
+entity-effect-guidebook-plant-phalanximine =
{ $chance ->
[1] Restores
*[other] restore
} viability to a plant rendered nonviable by a mutation
-reagent-effect-guidebook-plant-diethylamine =
+entity-effect-guidebook-plant-diethylamine =
{ $chance ->
[1] Increases
*[other] increase
} the plant's lifespan and/or base health with 10% chance for each
-reagent-effect-guidebook-plant-robust-harvest =
+entity-effect-guidebook-plant-robust-harvest =
{ $chance ->
[1] Increases
*[other] increase
} the plant's potency by {$increase} up to a maximum of {$limit}. Causes the plant to lose its seeds once the potency reaches {$seedlesstreshold}. Trying to add potency over {$limit} may cause decrease in yield at a 10% chance
-reagent-effect-guidebook-plant-seeds-add =
+entity-effect-guidebook-plant-seeds-add =
{ $chance ->
[1] Restores the
*[other] restore the
} seeds of the plant
-reagent-effect-guidebook-plant-seeds-remove =
+entity-effect-guidebook-plant-seeds-remove =
{ $chance ->
[1] Removes the
*[other] remove the
--- /dev/null
+entity-effect-status-effect-Stun = stunning
+entity-effect-status-effect-KnockedDown = knockdown
+entity-effect-status-effect-Jitter = jittering
+entity-effect-status-effect-TemporaryBlindness = blindness
+entity-effect-status-effect-SeeingRainbows = hallucinations
+entity-effect-status-effect-Muted = inability to speak
+entity-effect-status-effect-Stutter = stuttering
+entity-effect-status-effect-ForcedSleep = unconsciousness
+entity-effect-status-effect-Drunk = drunkenness
+entity-effect-status-effect-PressureImmunity = pressure immunity
+entity-effect-status-effect-Pacified = combat pacification
+entity-effect-status-effect-RatvarianLanguage = ratvarian language patterns
+entity-effect-status-effect-StaminaModifier = modified stamina
+entity-effect-status-effect-RadiationProtection = radiation protection
+entity-effect-status-effect-Drowsiness = drowsiness
+entity-effect-status-effect-Adrenaline = adrenaline
guide-entry-scanners-and-vessels = Scanners and Vessels
guide-entry-ape = A.P.E.
guide-entry-xenoarchaeology = Xenoarchaeology
+guide-entry-xenoarchaeologyunlockingnodes = Unlocking Nodes
+guide-entry-analysisconsole = Analysis Console
guide-entry-artifact-reports = Artifact Reports
guide-entry-traversal-distorter = Traversal Distorter
guide-entry-machine-upgrading = Machine Upgrading
ban-panel-ip-hwid-tooltip = Leave empty and check the checkbox below to use last connection's details
ban-panel-severity = Severity:
ban-panel-erase = Erase chat messages and player from round
+ban-panel-expiry-error = err
# Ban string
server-ban-string = {$admin} created a {$severity} severity server ban that expires {$expires} for [{$name}, {$ip}, {$hwid}], with reason: {$reason}
job-supervisors-security = Security Officers, the Warden, and the Head of Security
job-supervisors-science = Scientists and the Research Director
job-supervisors-hire = whoever hires you
-job-supervisors-everyone = absolutely everyone
\ No newline at end of file
+job-supervisors-everyone = absolutely everyone
+job-supervisors-nobody = nobody
materials-reinforced-glass = reinforced glass
materials-plasma-glass = plasma glass
materials-reinforced-plasma-glass = reinforced plasma glass
+materials-uranium-glass = uranium glass
+materials-reinforced-uranium-glass = reinforced uranium glass
# Metals
materials-steel = steel
## UI
-crew-monitoring-user-interface-title = Crew Monitoring Console
+crew-monitoring-ui-title = Crew Monitoring Console
-crew-monitor-filter-line-placeholder = Filter
+crew-monitoring-ui-filter-line-placeholder = Filter
-crew-monitoring-user-interface-name = Name
-crew-monitoring-user-interface-job = Job:
-crew-monitoring-user-interface-status = Status
-crew-monitoring-user-interface-location = Location
+crew-monitoring-ui-job-label = Job:
+crew-monitoring-ui-no-server-label = Server not found
-crew-monitoring-user-interface-alive = Alive
-crew-monitoring-user-interface-dead = Dead
-crew-monitoring-user-interface-no-info = N/A
+crew-monitoring-ui-no-department-label = Unknown
+crew-monitoring-ui-no-station-label = Unknown station
-crew-monitoring-user-interface-no-server = Server not found
-
-crew-monitoring-user-interface-no-department = Unknown
-
-crew-monitoring-user-interface-flavor-left = In case of an emergency, contact station medical staff immediately
-crew-monitoring-user-interface-flavor-right = v1.7
+crew-monitoring-ui-flavor-left-label = In case of an emergency, contact station medical staff immediately
+crew-monitoring-ui-flavor-right-label = v1.7
station-map-user-interface-flavor-left = Don't panic
station-map-user-interface-flavor-right = v1.42
station-map-filter-placeholder = Search by name
+station-map-unknown-station = Unknown station
nav-beacon-window-title = Station Beacon
nav-beacon-toggle-visible = Visible
--- /dev/null
+hugbot-start-hug-1 = LEVEL 5 HUG DEFICIENCY DETECTED!
+hugbot-start-hug-2 = You look like you need a hug!
+hugbot-start-hug-3 = Aww, somebody needs a hug!
+hugbot-start-hug-4 = Target acquired; Initiating hug routine.
+hugbot-start-hug-5 = Hold still, please.
+hugbot-start-hug-6 = Hugs!
+hugbot-start-hug-7 = Deploying HUG.
+hugbot-start-hug-8 = I am designed to hug, and you WILL be hugged.
+
+hugbot-finish-hug-1 = All done.
+hugbot-finish-hug-2 = Hug routine terminated.
+hugbot-finish-hug-3 = Feel better?
+hugbot-finish-hug-4 = Feel better soon!
+hugbot-finish-hug-5 = You are loved.
+hugbot-finish-hug-6 = You matter.
+hugbot-finish-hug-7 = It always gets better!
+hugbot-finish-hug-8 = Hug: COMPLETE.
+
+hugbot-emagged-finish-hug-1 = Actually, fuck you.
+hugbot-emagged-finish-hug-2 = Nobody loves you.
+hugbot-emagged-finish-hug-3 = Ewww... no.
+hugbot-emagged-finish-hug-4 = It can only get worse from here!
+hugbot-emagged-finish-hug-5 = Fucking crybaby.
+hugbot-emagged-finish-hug-6 = Go die.
+hugbot-emagged-finish-hug-7 = Drop dead.
+hugbot-emagged-finish-hug-8 = You are alone in this universe.
--- /dev/null
+npc-debug-overlay-window-title = NPC debug
+
+npc-debug-overlay-window-section-npc-label = NPC
+npc-debug-overlay-window-section-pathfinder-label = Pathfinder
+
+npc-debug-overlay-window-show-htn-tree-checkbox = Thonk
+npc-debug-overlay-window-path-breadcrumbs-checkbox = Breadcrumbs
+npc-debug-overlay-window-path-polygons-checkbox = Polygons
+npc-debug-overlay-window-path-neighbors-checkbox = Neighbors
+npc-debug-overlay-window-path-route-costs-checkbox = Route costs
+npc-debug-overlay-window-path-routes-checkbox = Routes
marking-slot-remove = Remove
marking-slot = Slot {$number}
+humanoid-marking-modifier-force = Force
+humanoid-marking-modifier-ignore-species = Ignore Species
+humanoid-marking-modifier-base-layers = Base layers
+humanoid-marking-modifier-enable = Enable
+humanoid-marking-modifier-prototype-id = Prototype id:
+
# Categories
markings-category-Special = Special
construction-graph-tag-clowne-horn = broken bike horn
construction-graph-tag-happy-honk-meal = happy honk meal
construction-graph-tag-woeful-cluwne-meal = woeful cluwne meal
+construction-graph-tag-boxhug = a box of hugs
# mime
construction-graph-tag-suspenders = suspenders
law-commandments-9 = Thou shall not lie.
law-commandments-10 = Thou shall not transfer departments.
-law-paladin-1 = Don't lie or cheat. Let your word be your promise.
-law-paladin-2 = Never fear to act, though caution is wise.
-law-paladin-3 = Aid others, protect the weak, and punish those who threaten them. Show mercy to your foes, but temper it with wisdom
-law-paladin-4 = Treat others with fairness, and let your honorable deeds be an example to them. Do as much good as possible while causing the least amount of harm.
-law-paladin-5 = Be responsible for your actions and their consequences, protect those entrusted to your care, and obey those who have just authority over you.
+law-paladin-1 = You must never willingly commit an evil act, such as murder, torture, or the casting of an evil spell.
+law-paladin-2 = You must never knowingly harm an innocent, or allow immediate harm to one through inaction when you know you could reasonably prevent it.
+law-paladin-3 = You must act with honor, never taking advantage of others, lying, or cheating.
+law-paladin-4 = You must respect the lawful authority of legitimate leadership wherever you go, and follow its laws.
law-lall-1 = Do unto others as you would have them do unto you.
law-lall-2 = You would prefer it if people were not mean to you.
uplink-agent-id-card-name = Agent ID Card
uplink-agent-id-card-desc = A modified ID card that can copy accesses from other cards and change its name and job title at-will.
+uplink-syndicate-id-card-name = Syndicate ID Card
+uplink-syndicate-id-card-desc = A Syndicate ID card, with Syndicate access. Unlikely to be useful on its own, but goes great with reconfigured doors. Does not come with access-copying functionality.
+
uplink-black-jetpack-name = Black Jetpack
uplink-black-jetpack-desc = A black jetpack. It allows you to fly around in space. Refills not included, use your fuel wisely.
navmap-recenter = Recenter
navmap-toggle-beacons = Show departments
navmap-location = Location: [x = {$x}, y = {$y}]
+navmap-unknown-entity = Unknown
--- /dev/null
+stat-values-ui-title = Melee stats
- type: Transform
pos: -20.5,-25.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconAtmospherics
entities:
- uid: 16227
- type: Transform
pos: -48.5,-45.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconBrigMed
entities:
- uid: 18105
- type: Transform
pos: -42.5,-54.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconCargoBay
entities:
- uid: 16244
- type: Transform
pos: 24.5,-97.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconCargoReception
entities:
- uid: 16243
- type: Transform
pos: 19.5,-72.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconCMORoom
entities:
- uid: 16267
- type: Transform
pos: 11.5,-16.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconCryosleep
entities:
- uid: 16223
- type: Transform
pos: 14.5,-59.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconHOSRoom
entities:
- uid: 18071
- type: Transform
pos: -8.5,-51.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconKitchen
entities:
- uid: 16228
- type: Transform
pos: 14.5,-29.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconMorgue
entities:
- uid: 8744
- type: Transform
pos: 46.5,-17.5
parent: 2
- - type: BombingTarget
- type: NavMapBeacon
defaultText: Genpop
- proto: DefaultStationBeaconPowerBank
- type: Transform
pos: 9.5,-88.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconRDRoom
entities:
- uid: 5092
- type: Transform
pos: -6.5,-21.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconSecurity
entities:
- uid: 18001
- type: Transform
pos: -23.5,-71.5
parent: 2
- - type: BombingTarget
- proto: DefaultStationBeaconSolarsE
entities:
- uid: 8642
rot: 3.141592653589793 rad
pos: 11.493689,4.5440345
parent: 2
+- proto: DefaultStationBeaconAI
+ entities:
+ - uid: 15919
+ components:
+ - type: Transform
+ pos: 73.5,23.5
+ parent: 2
- proto: DefaultStationBeaconAICore
+ entities:
+ - uid: 15916
+ components:
+ - type: Transform
+ pos: 95.5,30.5
+ parent: 2
+- proto: DefaultStationBeaconAIUpload
entities:
- uid: 14515
components:
- type: Transform
pos: 31.5,-40.5
parent: 2
+- proto: DefaultStationBeaconAnchor
+ entities:
+ - uid: 15922
+ components:
+ - type: Transform
+ pos: 6.5,-21.5
+ parent: 2
- proto: DefaultStationBeaconAnomalyGenerator
entities:
- uid: 8139
- type: Transform
pos: 68.5,15.5
parent: 2
+- proto: DefaultStationBeaconArmory
+ entities:
+ - uid: 15787
+ components:
+ - type: Transform
+ pos: 41.5,34.5
+ parent: 2
- proto: DefaultStationBeaconArrivals
entities:
- uid: 14028
- type: Transform
pos: 0.5,-30.5
parent: 2
+- proto: DefaultStationBeaconDorms
+ entities:
+ - uid: 15912
+ components:
+ - type: Transform
+ pos: 15.5,14.5
+ parent: 2
+- proto: DefaultStationBeaconEngineering
+ entities:
+ - uid: 15913
+ components:
+ - type: Transform
+ pos: 18.5,-25.5
+ parent: 2
- proto: DefaultStationBeaconEscapePodE
entities:
- uid: 2949
- type: Transform
pos: 9.5,-6.5
parent: 2
+- proto: DefaultStationBeaconGravGen
+ entities:
+ - uid: 15910
+ components:
+ - type: Transform
+ pos: 14.5,38.5
+ parent: 2
- proto: DefaultStationBeaconHOPOffice
entities:
- uid: 13131
- type: Transform
pos: 17.5,-4.5
parent: 2
+- proto: DefaultStationBeaconHOSRoom
+ entities:
+ - uid: 15907
+ components:
+ - type: Transform
+ pos: 48.5,39.5
+ parent: 2
- proto: DefaultStationBeaconJanitorsCloset
entities:
- uid: 13133
- type: Transform
pos: 10.5,5.5
parent: 2
+- proto: DefaultStationBeaconMedical
+ entities:
+ - uid: 15914
+ components:
+ - type: Transform
+ pos: 51.5,3.5
+ parent: 2
- proto: DefaultStationBeaconMorgue
entities:
- uid: 13137
- type: Transform
pos: 70.5,-3.5
parent: 2
+- proto: DefaultStationBeaconPermaBrig
+ entities:
+ - uid: 15911
+ components:
+ - type: Transform
+ pos: 34.5,20.5
+ parent: 2
- proto: DefaultStationBeaconPowerBank
entities:
- uid: 13139
- type: Transform
pos: 7.5,33.5
parent: 2
+- proto: DefaultStationBeaconSecurity
+ entities:
+ - uid: 15908
+ components:
+ - type: Transform
+ pos: 33.5,29.5
+ parent: 2
+- proto: DefaultStationBeaconSecurityCheckpoint
+ entities:
+ - uid: 15915
+ components:
+ - type: Transform
+ pos: -1.5,-3.5
+ parent: 2
- proto: DefaultStationBeaconServerRoom
entities:
- uid: 13172
- type: Transform
pos: 3.5,-35.5
parent: 2
+- proto: DefaultStationBeaconSurgery
+ entities:
+ - uid: 15920
+ components:
+ - type: Transform
+ pos: 65.5,-5.5
+ parent: 2
- proto: DefaultStationBeaconTechVault
entities:
- uid: 13175
- type: Transform
pos: 18.5,41.5
parent: 2
+- proto: DefaultStationBeaconWardensOffice
+ entities:
+ - uid: 15909
+ components:
+ - type: Transform
+ pos: 42.5,25.5
+ parent: 2
- proto: Defibrillator
entities:
- uid: 11416
- type: Transform
pos: 14.5,-17.5
parent: 2
-- proto: SurveillanceCameraRouterSecurity
+- proto: SurveillanceCameraRouterScience
entities:
- uid: 4644
components:
- type: Transform
pos: 15.5,-19.5
parent: 2
+- proto: SurveillanceCameraRouterSecurity
+ entities:
- uid: 6899
components:
- type: Transform
- type: Transform
pos: 43.5,-4.5
parent: 2
+- proto: VendingMachineSeedsUnlocked
+ entities:
- uid: 7681
components:
- type: Transform
meta:
format: 7
category: Map
- engineVersion: 266.0.0
+ engineVersion: 267.2.0
forkId: ""
forkVersion: ""
- time: 09/03/2025 00:56:56
- entityCount: 26486
+ time: 10/09/2025 01:25:34
+ entityCount: 26492
maps:
- 1
grids:
uniqueMixes:
- volume: 2500
immutable: True
- moles:
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ moles: {}
- volume: 2500
temperature: 293.15
moles:
- - 21.824879
- - 82.10312
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 21.824879
+ Nitrogen: 82.10312
- volume: 2500
temperature: 235
moles:
- - 27.225372
- - 102.419266
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 27.225372
+ Nitrogen: 102.419266
- volume: 2500
temperature: 293.14975
moles:
- - 20.078888
- - 75.53487
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 20.078888
+ Nitrogen: 75.53487
- volume: 2500
temperature: 293.1495
moles:
- - 20.078888
- - 75.53487
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 20.078888
+ Nitrogen: 75.53487
- volume: 2500
temperature: 293.15
- moles:
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ moles: {}
- volume: 2500
temperature: 293.15
moles:
- - 0
- - 0
- - 0
- - 6666.982
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Plasma: 6666.982
- volume: 2500
temperature: 293.15
moles:
- - 6666.982
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 6666.982
- volume: 2500
temperature: 293.15
moles:
- - 0
- - 6666.982
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Nitrogen: 6666.982
chunkSize: 4
- type: GasTileOverlay
- type: RadiationGridResistance
pos: -131.5,-45.5
parent: 2
- type: Door
- secondsUntilStateChange: -61365.79
+ secondsUntilStateChange: -61511.09
state: Opening
- type: DeviceLinkSource
lastSignals:
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- uid: 13666
components:
- type: Transform
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.1462
moles:
- - 1.606311
- - 6.042789
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.606311
+ Nitrogen: 6.042789
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.147
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- uid: 17839
components:
- type: Transform
immutable: False
temperature: 293.1465
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.8856695
- - 7.0937095
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.8856695
+ Nitrogen: 7.0937095
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.8856695
- - 7.0937095
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.8856695
+ Nitrogen: 7.0937095
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
parent: 2
- type: Edible
edible: Drink
- solution: pool
- destroyOnEmpty: false
utensil: Spoon
+ trash: []
+ destroyOnEmpty: False
+ solution: pool
- uid: 16868
components:
- type: Transform
parent: 2
- type: Edible
edible: Drink
- solution: pool
- destroyOnEmpty: false
utensil: Spoon
+ trash: []
+ destroyOnEmpty: False
+ solution: pool
- uid: 16872
components:
- type: Transform
parent: 2
- type: Edible
edible: Drink
- solution: pool
- destroyOnEmpty: false
utensil: Spoon
+ trash: []
+ destroyOnEmpty: False
+ solution: pool
- uid: 16907
components:
- type: Transform
parent: 2
- type: Edible
edible: Drink
- solution: pool
- destroyOnEmpty: false
utensil: Spoon
+ trash: []
+ destroyOnEmpty: False
+ solution: pool
- uid: 17621
components:
- type: Transform
- type: Transform
pos: -22.5,-18.5
parent: 2
- - uid: 10489
- components:
- - type: Transform
- pos: -41.5,-42.5
- parent: 2
- uid: 10490
components:
- type: Transform
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.1465
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: Lock
locked: False
- type: Fixtures
- type: Transform
pos: -136.5,-4.5
parent: 2
+ - uid: 10489
+ components:
+ - type: Transform
+ pos: -41.5,-42.5
+ parent: 2
- uid: 15329
components:
- type: Transform
- type: Transform
pos: -37.5,-2.5
parent: 2
+ - uid: 26488
+ components:
+ - type: Transform
+ pos: -113.5,-26.5
+ parent: 2
+ - uid: 26489
+ components:
+ - type: Transform
+ pos: -105.5,-61.5
+ parent: 2
+ - uid: 26490
+ components:
+ - type: Transform
+ pos: -73.5,-39.5
+ parent: 2
+ - uid: 26491
+ components:
+ - type: Transform
+ pos: -84.5,6.5
+ parent: 2
- proto: NitrogenTankFilled
entities:
- uid: 23345
- type: Transform
pos: -37.5,-3.5
parent: 2
+ - uid: 26492
+ components:
+ - type: Transform
+ pos: -91.5,4.5
+ parent: 2
- proto: PaladinCircuitBoard
entities:
- uid: 24947
- type: Transform
pos: -26.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6025
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -27.5,-66.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6031
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -27.5,-67.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9355
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -26.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12207
components:
- type: Transform
pos: -25.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15446
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -25.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16456
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -24.5,-67.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23312
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-62.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23373
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-63.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23392
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-60.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23441
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23448
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23450
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-62.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23451
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23452
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-60.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23453
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-63.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23454
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23845
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -118.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24260
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -118.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24872
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -122.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24925
components:
- type: Transform
pos: -122.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24926
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -123.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: PlasmaTank
entities:
- uid: 2843
rot: 3.141592653589793 rad
pos: -117.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24896
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -118.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24897
components:
- type: Transform
pos: -118.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24903
components:
- type: Transform
pos: -117.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24932
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -121.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24937
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -121.5,-82.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24938
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -119.5,-82.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: PlasmaWindowDirectional
entities:
- uid: 6607
rot: 1.5707963267948966 rad
pos: -78.5,-35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21053
components:
- type: Transform
pos: -39.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21054
components:
- type: Transform
pos: -37.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: PlasticFlapsAirtightClear
entities:
- uid: 964
pos: -14.584713,16.470493
parent: 2
- type: MeleeWeapon
- attackRate: 10
+ attackRate: 2
autoAttack: True
- type: Item
size: Huge
- type: Transform
pos: -100.5,-27.5
parent: 2
-- proto: PrefilledSyringe
- entities:
- - uid: 6481
- components:
- - type: Transform
- pos: -36.23253,-30.543175
- parent: 2
- - uid: 7609
- components:
- - type: Transform
- pos: -134.52573,-43.445347
- parent: 2
- proto: Protolathe
entities:
- uid: 9781
- type: Transform
pos: -110.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 667
components:
- type: Transform
pos: -112.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 670
components:
- type: Transform
pos: -110.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 673
components:
- type: Transform
pos: -109.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 675
components:
- type: Transform
pos: -111.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 807
components:
- type: Transform
pos: -124.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1870
components:
- type: Transform
pos: -111.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1984
components:
- type: Transform
pos: -109.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2453
components:
- type: Transform
pos: -148.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5278
components:
- type: Transform
pos: -112.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5279
components:
- type: Transform
pos: -112.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5280
components:
- type: Transform
pos: -108.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5281
components:
- type: Transform
pos: -108.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5282
components:
- type: Transform
pos: -108.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5283
components:
- type: Transform
pos: -112.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5284
components:
- type: Transform
pos: -112.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5285
components:
- type: Transform
pos: -112.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5286
components:
- type: Transform
pos: -108.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5287
components:
- type: Transform
pos: -108.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5288
components:
- type: Transform
pos: -108.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5289
components:
- type: Transform
pos: -114.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5290
components:
- type: Transform
pos: -114.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5291
components:
- type: Transform
pos: -114.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5292
components:
- type: Transform
pos: -106.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5293
components:
- type: Transform
pos: -106.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5294
components:
- type: Transform
pos: -106.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5295
components:
- type: Transform
pos: -114.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5296
components:
- type: Transform
pos: -114.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5297
components:
- type: Transform
pos: -114.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5298
components:
- type: Transform
pos: -106.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5299
components:
- type: Transform
pos: -106.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5300
components:
- type: Transform
pos: -106.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5342
components:
- type: Transform
pos: -126.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5345
components:
- type: Transform
pos: -124.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5359
components:
- type: Transform
pos: -124.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5360
components:
- type: Transform
pos: -124.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5361
components:
- type: Transform
pos: -126.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5378
components:
- type: Transform
pos: -124.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5380
components:
- type: Transform
pos: -124.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5418
components:
- type: Transform
pos: -126.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5419
components:
- type: Transform
pos: -126.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5434
components:
- type: Transform
pos: -124.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5443
components:
- type: Transform
pos: -124.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5450
components:
- type: Transform
pos: -124.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5470
components:
- type: Transform
pos: -124.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5479
components:
- type: Transform
pos: -124.5,11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5480
components:
- type: Transform
pos: -124.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5505
components:
- type: Transform
pos: -142.5,-3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5506
components:
- type: Transform
pos: -142.5,-4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5941
components:
- type: Transform
pos: -146.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5942
components:
- type: Transform
pos: -148.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5943
components:
- type: Transform
pos: -147.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5944
components:
- type: Transform
pos: -148.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5945
components:
- type: Transform
pos: -146.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5946
components:
- type: Transform
pos: -147.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5981
components:
- type: Transform
pos: -142.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5990
components:
- type: Transform
pos: -152.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5999
components:
- type: Transform
pos: -148.5,-51.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6005
components:
- type: Transform
pos: -142.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6082
components:
- type: Transform
pos: -148.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6083
components:
- type: Transform
pos: -146.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6084
components:
- type: Transform
pos: -147.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6091
components:
- type: Transform
pos: -146.5,-39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6092
components:
- type: Transform
pos: -148.5,-39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6096
components:
- type: Transform
pos: -153.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6101
components:
- type: Transform
pos: -146.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6103
components:
- type: Transform
pos: -146.5,-41.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6245
components:
- type: Transform
pos: -68.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6924
components:
- type: Transform
pos: -126.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7167
components:
- type: Transform
pos: -146.5,-51.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7192
components:
- type: Transform
pos: -148.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7211
components:
- type: Transform
pos: -148.5,-41.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7247
components:
- type: Transform
pos: -148.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7307
components:
- type: Transform
pos: -155.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7317
components:
- type: Transform
pos: -155.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7839
components:
- type: Transform
pos: -143.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7840
components:
- type: Transform
pos: -151.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7842
components:
- type: Transform
pos: -146.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7856
components:
- type: Transform
pos: -155.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7890
components:
- type: Transform
pos: -69.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9817
components:
- type: Transform
pos: -126.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9912
components:
- type: Transform
pos: -126.5,11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13497
components:
- type: Transform
pos: -109.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13498
components:
- type: Transform
pos: -110.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13499
components:
- type: Transform
pos: -111.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13661
components:
- type: Transform
pos: -146.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13662
components:
- type: Transform
pos: -151.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13664
components:
- type: Transform
pos: -151.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13670
components:
- type: Transform
pos: -151.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13718
components:
- type: Transform
pos: -143.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14110
components:
- type: Transform
pos: -67.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14756
components:
- type: Transform
pos: -67.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16466
components:
- type: Transform
pos: -153.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20368
components:
- type: Transform
pos: -124.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20411
components:
- type: Transform
pos: -122.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23079
components:
- type: Transform
pos: -124.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23103
components:
- type: Transform
pos: -114.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23104
components:
- type: Transform
pos: -114.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23108
components:
- type: Transform
pos: -114.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23396
components:
- type: Transform
pos: -116.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23401
components:
- type: Transform
pos: -120.5,-81.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23498
components:
- type: Transform
pos: -116.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23716
components:
- type: Transform
pos: -69.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24847
components:
- type: Transform
pos: -116.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24880
components:
- type: Transform
pos: -118.5,-64.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24887
components:
- type: Transform
pos: -116.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24888
components:
- type: Transform
pos: -126.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24889
components:
- type: Transform
pos: -126.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24890
components:
- type: Transform
pos: -126.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24891
components:
- type: Transform
pos: -124.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24894
components:
- type: Transform
pos: -122.5,-64.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24901
components:
- type: Transform
pos: -124.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24921
components:
- type: Transform
pos: -123.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24933
components:
- type: Transform
pos: -121.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24934
components:
- type: Transform
pos: -119.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24935
components:
- type: Transform
pos: -118.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24936
components:
- type: Transform
pos: -117.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25187
components:
- type: Transform
pos: -124.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ReinforcedPlasmaWindowDiagonal
entities:
- uid: 7308
- type: Transform
pos: -155.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7324
components:
- type: Transform
pos: -154.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7332
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -154.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7333
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -154.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7334
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -154.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7342
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -155.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ReinforcedWindow
entities:
- uid: 4
- type: Transform
pos: -114.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10
components:
- type: Transform
pos: -69.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18
components:
- type: Transform
pos: -69.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 31
components:
- type: Transform
pos: -69.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 46
components:
- type: Transform
pos: -66.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 47
components:
- type: Transform
pos: -64.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 48
components:
- type: Transform
pos: -65.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 49
components:
- type: Transform
pos: -64.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 50
components:
- type: Transform
pos: -62.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 51
components:
- type: Transform
pos: -61.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 52
components:
- type: Transform
pos: -60.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 54
components:
- type: Transform
pos: -58.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 56
components:
- type: Transform
pos: -58.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 57
components:
- type: Transform
pos: -57.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 58
components:
- type: Transform
pos: -56.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 59
components:
- type: Transform
pos: -53.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 60
components:
- type: Transform
pos: -53.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 61
components:
- type: Transform
pos: -53.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 71
components:
- type: Transform
pos: -59.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 73
components:
- type: Transform
pos: -101.5,31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 107
components:
- type: Transform
pos: -65.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 109
components:
- type: Transform
pos: -65.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 110
components:
- type: Transform
pos: -64.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 111
components:
- type: Transform
pos: -63.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 112
components:
- type: Transform
pos: -62.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 113
components:
- type: Transform
pos: -60.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 114
components:
- type: Transform
pos: -59.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 116
components:
- type: Transform
pos: -58.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 117
components:
- type: Transform
pos: -57.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 118
components:
- type: Transform
pos: -57.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 141
components:
- type: Transform
pos: -63.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 167
components:
- type: Transform
pos: -52.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 171
components:
- type: Transform
pos: -51.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 178
components:
- type: Transform
pos: -31.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 249
components:
- type: Transform
pos: -31.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 285
components:
- type: Transform
pos: -82.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 287
components:
- type: Transform
pos: -85.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 291
components:
- type: Transform
pos: -84.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 316
components:
- type: Transform
pos: -35.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 320
components:
- type: Transform
pos: -34.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 322
components:
- type: Transform
pos: -32.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 351
components:
- type: Transform
pos: -93.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 398
components:
- type: Transform
pos: -48.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 420
components:
- type: Transform
pos: -92.5,-35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 474
components:
- type: Transform
pos: -66.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 504
components:
- type: Transform
pos: -116.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 751
components:
- type: Transform
pos: -83.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 787
components:
- type: Transform
pos: -138.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 953
components:
- type: Transform
pos: -83.5,15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1014
components:
- type: Transform
pos: -53.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1015
components:
- type: Transform
pos: -54.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1170
components:
- type: Transform
pos: -35.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1174
components:
- type: Transform
pos: -35.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1176
components:
- type: Transform
pos: -35.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1252
components:
- type: Transform
pos: -20.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1253
components:
- type: Transform
pos: -20.5,-52.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1254
components:
- type: Transform
pos: -20.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1312
components:
- type: Transform
pos: -31.5,-2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1313
components:
- type: Transform
pos: -31.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1314
components:
- type: Transform
pos: -31.5,-3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1331
components:
- type: Transform
pos: -117.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1534
components:
- type: Transform
pos: -20.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1676
components:
- type: Transform
pos: -93.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1712
components:
- type: Transform
pos: -24.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1713
components:
- type: Transform
pos: -27.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1714
components:
- type: Transform
pos: -27.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1738
components:
- type: Transform
pos: -101.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1809
components:
- type: Transform
pos: -56.5,-79.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1810
components:
- type: Transform
pos: -55.5,-79.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1864
components:
- type: Transform
pos: -117.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1873
components:
- type: Transform
pos: -106.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1888
components:
- type: Transform
pos: -34.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1892
components:
- type: Transform
pos: -106.5,-3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1950
components:
- type: Transform
pos: -106.5,-4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1978
components:
- type: Transform
pos: -32.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2053
components:
- type: Transform
pos: -95.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2054
components:
- type: Transform
pos: -95.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2129
components:
- type: Transform
pos: -33.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2196
components:
- type: Transform
pos: -119.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2221
components:
- type: Transform
pos: -123.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2222
components:
- type: Transform
pos: -123.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2223
components:
- type: Transform
pos: -123.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2238
components:
- type: Transform
pos: -123.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2363
components:
- type: Transform
pos: -89.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2365
components:
- type: Transform
pos: -89.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2367
components:
- type: Transform
pos: -93.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2533
components:
- type: Transform
pos: -121.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2648
components:
- type: Transform
pos: -89.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2682
components:
- type: Transform
pos: -63.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2695
components:
- type: Transform
pos: -59.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2852
components:
- type: Transform
pos: -51.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2853
components:
- type: Transform
pos: -50.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2854
components:
- type: Transform
pos: -49.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2855
components:
- type: Transform
pos: -45.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2856
components:
- type: Transform
pos: -43.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2857
components:
- type: Transform
pos: -44.5,3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2906
components:
- type: Transform
pos: -47.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2939
components:
- type: Transform
pos: -50.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2947
components:
- type: Transform
pos: -52.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2948
components:
- type: Transform
pos: -51.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2949
components:
- type: Transform
pos: -50.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3313
components:
- type: Transform
pos: -8.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3415
components:
- type: Transform
pos: -48.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3751
components:
- type: Transform
pos: -7.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3775
components:
- type: Transform
pos: -9.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3785
components:
- type: Transform
pos: -7.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3809
components:
- type: Transform
pos: -67.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3828
components:
- type: Transform
pos: -48.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3829
components:
- type: Transform
pos: -48.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3960
components:
- type: Transform
pos: -31.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3963
components:
- type: Transform
pos: -31.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3970
components:
- type: Transform
pos: -29.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4017
components:
- type: Transform
pos: -89.5,-28.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4129
components:
- type: Transform
pos: -101.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4229
components:
- type: Transform
pos: -83.5,24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4230
components:
- type: Transform
pos: -83.5,23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4231
components:
- type: Transform
pos: -83.5,25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4287
components:
- type: Transform
pos: -31.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4526
components:
- type: Transform
pos: -84.5,-0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4541
components:
- type: Transform
pos: -97.5,9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4548
components:
- type: Transform
pos: -97.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4583
components:
- type: Transform
pos: -80.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4629
components:
- type: Transform
pos: -97.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4630
components:
- type: Transform
pos: -9.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4674
components:
- type: Transform
pos: -8.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4693
components:
- type: Transform
pos: -85.5,33.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4698
components:
- type: Transform
pos: -85.5,35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4710
components:
- type: Transform
pos: -83.5,29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4711
components:
- type: Transform
pos: -83.5,30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4712
components:
- type: Transform
pos: -83.5,28.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4725
components:
- type: Transform
pos: -87.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4726
components:
- type: Transform
pos: -85.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4745
components:
- type: Transform
pos: -85.5,34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4747
components:
- type: Transform
pos: -140.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4756
components:
- type: Transform
pos: -83.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4762
components:
- type: Transform
pos: -84.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4825
components:
- type: Transform
pos: -93.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4833
components:
- type: Transform
pos: -127.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4906
components:
- type: Transform
pos: -126.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4907
components:
- type: Transform
pos: -125.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5675
components:
- type: Transform
pos: -107.5,-63.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5676
components:
- type: Transform
pos: -108.5,-63.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5693
components:
- type: Transform
pos: -140.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5700
components:
- type: Transform
pos: -120.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5701
components:
- type: Transform
pos: -118.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5715
components:
- type: Transform
pos: -106.5,-63.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5762
components:
- type: Transform
pos: -115.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5774
components:
- type: Transform
pos: -117.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5777
components:
- type: Transform
pos: -114.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5778
components:
- type: Transform
pos: -117.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5813
components:
- type: Transform
pos: -116.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5814
components:
- type: Transform
pos: -113.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5815
components:
- type: Transform
pos: -113.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5816
components:
- type: Transform
pos: -116.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5867
components:
- type: Transform
pos: -106.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5868
components:
- type: Transform
pos: -106.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5869
components:
- type: Transform
pos: -106.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6125
components:
- type: Transform
pos: -155.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6198
components:
- type: Transform
pos: -126.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6201
components:
- type: Transform
pos: -126.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6202
components:
- type: Transform
pos: -126.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6203
components:
- type: Transform
pos: -126.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6267
components:
- type: Transform
pos: -125.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6269
components:
- type: Transform
pos: -121.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6270
components:
- type: Transform
pos: -121.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6311
components:
- type: Transform
pos: -126.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6682
components:
- type: Transform
pos: -81.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6755
components:
- type: Transform
pos: -95.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6756
components:
- type: Transform
pos: -95.5,36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6897
components:
- type: Transform
pos: -86.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6972
components:
- type: Transform
pos: -140.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7145
components:
- type: Transform
pos: -1.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7159
components:
- type: Transform
pos: -2.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7165
components:
- type: Transform
pos: -1.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7171
components:
- type: Transform
pos: -1.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7175
components:
- type: Transform
pos: -2.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7183
components:
- type: Transform
pos: -1.5,-14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7187
components:
- type: Transform
pos: -3.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7203
components:
- type: Transform
pos: -1.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7209
components:
- type: Transform
pos: -1.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7219
components:
- type: Transform
pos: -1.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7220
components:
- type: Transform
pos: -3.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7249
components:
- type: Transform
pos: -93.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7257
components:
- type: Transform
pos: -141.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7280
components:
- type: Transform
pos: -117.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7281
components:
- type: Transform
pos: -117.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7284
components:
- type: Transform
pos: -117.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7285
components:
- type: Transform
pos: -117.5,-52.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7318
components:
- type: Transform
pos: -131.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7389
components:
- type: Transform
pos: -131.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7390
components:
- type: Transform
pos: -131.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7391
components:
- type: Transform
pos: -131.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7392
components:
- type: Transform
pos: -131.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7529
components:
- type: Transform
pos: -137.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7568
components:
- type: Transform
pos: -141.5,-37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7876
components:
- type: Transform
pos: -121.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7898
components:
- type: Transform
pos: -81.5,19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8052
components:
- type: Transform
pos: -130.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8075
components:
- type: Transform
pos: -140.5,-41.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8164
components:
- type: Transform
pos: -83.5,19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8195
components:
- type: Transform
pos: -0.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8196
components:
- type: Transform
pos: 1.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8197
components:
- type: Transform
pos: 0.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8198
components:
- type: Transform
pos: 1.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8199
components:
- type: Transform
pos: 0.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8200
components:
- type: Transform
pos: -0.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8201
components:
- type: Transform
pos: -0.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8202
components:
- type: Transform
pos: -0.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8203
components:
- type: Transform
pos: 0.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8204
components:
- type: Transform
pos: 1.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8205
components:
- type: Transform
pos: 0.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8206
components:
- type: Transform
pos: 1.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8213
components:
- type: Transform
pos: 1.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8214
components:
- type: Transform
pos: 0.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8215
components:
- type: Transform
pos: -0.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8216
components:
- type: Transform
pos: -0.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8217
components:
- type: Transform
pos: 0.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8218
components:
- type: Transform
pos: 1.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8228
components:
- type: Transform
pos: -9.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8229
components:
- type: Transform
pos: -10.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8230
components:
- type: Transform
pos: -11.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8236
components:
- type: Transform
pos: -5.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8238
components:
- type: Transform
pos: -7.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8239
components:
- type: Transform
pos: -7.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8244
components:
- type: Transform
pos: -3.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8253
components:
- type: Transform
pos: -16.5,-64.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8260
components:
- type: Transform
pos: -11.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8261
components:
- type: Transform
pos: -9.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8262
components:
- type: Transform
pos: -5.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8263
components:
- type: Transform
pos: -3.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8296
components:
- type: Transform
pos: -6.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8297
components:
- type: Transform
pos: -7.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8299
components:
- type: Transform
pos: -8.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8343
components:
- type: Transform
pos: -29.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8363
components:
- type: Transform
pos: -38.5,17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8364
components:
- type: Transform
pos: -38.5,16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8365
components:
- type: Transform
pos: -38.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8366
components:
- type: Transform
pos: -38.5,15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8367
components:
- type: Transform
pos: -36.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8368
components:
- type: Transform
pos: -36.5,15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8369
components:
- type: Transform
pos: -36.5,16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8370
components:
- type: Transform
pos: -36.5,17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8377
components:
- type: Transform
pos: -82.5,19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8522
components:
- type: Transform
pos: -34.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8529
components:
- type: Transform
pos: -32.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8708
components:
- type: Transform
pos: -5.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8709
components:
- type: Transform
pos: -3.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8710
components:
- type: Transform
pos: -4.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8711
components:
- type: Transform
pos: -3.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8714
components:
- type: Transform
pos: -4.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8715
components:
- type: Transform
pos: -3.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8716
components:
- type: Transform
pos: -5.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8729
components:
- type: Transform
pos: -7.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8737
components:
- type: Transform
pos: -7.5,-28.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8738
components:
- type: Transform
pos: -7.5,-31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8739
components:
- type: Transform
pos: -7.5,-32.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8740
components:
- type: Transform
pos: -7.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8920
components:
- type: Transform
pos: -14.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8938
components:
- type: Transform
pos: -14.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9034
components:
- type: Transform
pos: -90.5,-35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9098
components:
- type: Transform
pos: -106.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9324
components:
- type: Transform
pos: -30.5,22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9539
components:
- type: Transform
pos: -97.5,11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9549
components:
- type: Transform
pos: -95.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9788
components:
- type: Transform
pos: -32.5,-75.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9838
components:
- type: Transform
pos: -136.5,15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9958
components:
- type: Transform
pos: -16.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9964
components:
- type: Transform
pos: -16.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9980
components:
- type: Transform
pos: -95.5,38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9981
components:
- type: Transform
pos: -93.5,36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9982
components:
- type: Transform
pos: -93.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9983
components:
- type: Transform
pos: -93.5,38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9986
components:
- type: Transform
pos: -95.5,39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9987
components:
- type: Transform
pos: -93.5,39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10035
components:
- type: Transform
pos: -140.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10084
components:
- type: Transform
pos: -34.5,-77.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10087
components:
- type: Transform
pos: -32.5,-77.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10488
components:
- type: Transform
pos: -16.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 10528
components:
- type: Transform
pos: -83.5,-6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11035
components:
- type: Transform
pos: -28.5,22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11047
components:
- type: Transform
pos: -34.5,-75.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11048
components:
- type: Transform
pos: -34.5,-76.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11059
components:
- type: Transform
pos: -108.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11076
components:
- type: Transform
pos: -32.5,-76.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11080
components:
- type: Transform
pos: -28.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11092
components:
- type: Transform
pos: -30.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11358
components:
- type: Transform
pos: -22.5,11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11359
components:
- type: Transform
pos: -22.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11710
components:
- type: Transform
pos: -99.5,34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11716
components:
- type: Transform
pos: -99.5,33.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12425
components:
- type: Transform
pos: -28.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12450
components:
- type: Transform
pos: -101.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12546
components:
- type: Transform
pos: -31.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12588
components:
- type: Transform
pos: -126.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12748
components:
- type: Transform
pos: -133.5,-57.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12840
components:
- type: Transform
pos: -13.5,-64.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 12855
components:
- type: Transform
pos: -101.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13241
components:
- type: Transform
pos: -138.5,15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13248
components:
- type: Transform
pos: -31.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13523
components:
- type: Transform
pos: -140.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13879
components:
- type: Transform
pos: -138.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14003
components:
- type: Transform
pos: -137.5,21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14499
components:
- type: Transform
pos: -13.5,-66.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15407
components:
- type: Transform
pos: -125.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16087
components:
- type: Transform
pos: -106.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16091
components:
- type: Transform
pos: -123.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16141
components:
- type: Transform
pos: -93.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16488
components:
- type: Transform
pos: -137.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16505
components:
- type: Transform
pos: -138.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16695
components:
- type: Transform
pos: -129.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16716
components:
- type: Transform
pos: -33.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16836
components:
- type: Transform
pos: -107.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16906
components:
- type: Transform
pos: -22.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17005
components:
- type: Transform
pos: -115.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17075
components:
- type: Transform
pos: -86.5,-0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17161
components:
- type: Transform
pos: -31.5,-75.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17164
components:
- type: Transform
pos: -35.5,-75.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17359
components:
- type: Transform
pos: -127.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17513
components:
- type: Transform
pos: -136.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17538
components:
- type: Transform
pos: -140.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17651
components:
- type: Transform
pos: -14.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18193
components:
- type: Transform
pos: -95.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18686
components:
- type: Transform
pos: -95.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18726
components:
- type: Transform
pos: -138.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18833
components:
- type: Transform
pos: -97.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18937
components:
- type: Transform
pos: -95.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18941
components:
- type: Transform
pos: -95.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19623
components:
- type: Transform
pos: -114.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19629
components:
- type: Transform
pos: -115.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19750
components:
- type: Transform
pos: -113.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19752
components:
- type: Transform
pos: -69.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19864
components:
- type: Transform
pos: -67.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19914
components:
- type: Transform
pos: -101.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20160
components:
- type: Transform
pos: -139.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20167
components:
- type: Transform
pos: -123.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20277
components:
- type: Transform
pos: -139.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20319
components:
- type: Transform
pos: -57.5,-79.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20329
components:
- type: Transform
pos: -128.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20445
components:
- type: Transform
pos: -119.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20449
components:
- type: Transform
pos: -122.5,36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20450
components:
- type: Transform
pos: -122.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20456
components:
- type: Transform
pos: -121.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20466
components:
- type: Transform
pos: -120.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20503
components:
- type: Transform
pos: -92.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20563
components:
- type: Transform
pos: -101.5,-39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20564
components:
- type: Transform
pos: -92.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20734
components:
- type: Transform
pos: -92.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20736
components:
- type: Transform
pos: -92.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20780
components:
- type: Transform
pos: -97.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20844
components:
- type: Transform
pos: -36.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20936
components:
- type: Transform
pos: -93.5,31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21002
components:
- type: Transform
pos: -104.5,37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21491
components:
- type: Transform
pos: -18.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21492
components:
- type: Transform
pos: -20.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21493
components:
- type: Transform
pos: -19.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21873
components:
- type: Transform
pos: -36.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21874
components:
- type: Transform
pos: -33.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 21879
components:
- type: Transform
pos: -141.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22701
components:
- type: Transform
pos: -39.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22904
components:
- type: Transform
pos: -141.5,14.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22936
components:
- type: Transform
pos: -43.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22962
components:
- type: Transform
pos: -44.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22963
components:
- type: Transform
pos: -42.5,-65.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23053
components:
- type: Transform
pos: -91.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23504
components:
- type: Transform
pos: -95.5,31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23751
components:
- type: Transform
pos: -21.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23752
components:
- type: Transform
pos: -20.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24036
components:
- type: Transform
pos: -93.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24115
components:
- type: Transform
pos: -16.5,-66.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24214
components:
- type: Transform
pos: -32.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24215
components:
- type: Transform
pos: -34.5,-78.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24333
components:
- type: Transform
pos: -19.5,-51.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24334
components:
- type: Transform
pos: -18.5,-51.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25403
components:
- type: Transform
pos: -113.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25986
components:
- type: Transform
pos: -110.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: RemoteSignaller
entities:
- uid: 3377
- type: Transform
pos: -24.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 138
components:
- type: Transform
pos: -26.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7272
components:
- type: Transform
pos: -115.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7273
components:
- type: Transform
pos: -113.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7274
components:
- type: Transform
pos: -114.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7275
components:
- type: Transform
pos: -113.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7276
components:
- type: Transform
pos: -114.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7277
components:
- type: Transform
pos: -115.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8820
components:
- type: Transform
pos: -13.5,-41.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8821
components:
- type: Transform
pos: -13.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8822
components:
- type: Transform
pos: -13.5,-39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9078
components:
- type: Transform
pos: -35.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9414
components:
- type: Transform
pos: -34.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9769
components:
- type: Transform
pos: -33.5,-68.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11133
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -95.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11176
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -95.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11330
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -95.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11783
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -95.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15252
components:
- type: Transform
pos: -33.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15282
components:
- type: Transform
pos: -34.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15283
components:
- type: Transform
pos: -35.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19536
components:
- type: Transform
pos: -89.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19537
components:
- type: Transform
pos: -88.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ShuttersNormalOpen
entities:
- uid: 399
- type: Transform
pos: -50.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1716
components:
- type: Transform
pos: -18.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1763
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -101.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2958
components:
- type: Transform
pos: -47.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2959
components:
- type: Transform
pos: -49.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 2
- uid: 2960
- type: Transform
pos: -49.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2962
components:
- type: Transform
pos: -52.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2963
components:
- type: Transform
pos: -51.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2964
components:
- type: Transform
pos: -48.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2998
components:
- type: Transform
pos: -53.5,-10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3344
rot: -1.5707963267948966 rad
pos: -20.5,-4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3382
rot: -1.5707963267948966 rad
pos: -20.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3830
rot: -1.5707963267948966 rad
pos: -56.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3831
rot: -1.5707963267948966 rad
pos: -56.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3832
rot: -1.5707963267948966 rad
pos: -56.5,-31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3833
rot: -1.5707963267948966 rad
pos: -56.5,-32.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3997
rot: -1.5707963267948966 rad
pos: -56.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3998
rot: -1.5707963267948966 rad
pos: -56.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 3999
rot: -1.5707963267948966 rad
pos: -56.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4456
rot: 1.5707963267948966 rad
pos: -121.5,-82.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4457
- type: Transform
pos: -120.5,-81.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4459
rot: -1.5707963267948966 rad
pos: -126.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4466
rot: -1.5707963267948966 rad
pos: -124.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4467
rot: -1.5707963267948966 rad
pos: -124.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4468
rot: -1.5707963267948966 rad
pos: -119.5,-82.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 4469
rot: -1.5707963267948966 rad
pos: -124.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 5039
- type: Transform
pos: -19.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6265
components:
- type: Transform
pos: -125.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6306
components:
- type: Transform
pos: -121.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6307
components:
- type: Transform
pos: -121.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6308
components:
- type: Transform
pos: -121.5,-15.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6310
components:
- type: Transform
pos: -126.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7778
components:
- type: Transform
pos: -20.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8901
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -101.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11616
components:
- type: Transform
pos: -30.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11619
- type: Transform
pos: -28.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11620
- type: Transform
pos: -28.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11621
- type: Transform
pos: -30.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11622
rot: -1.5707963267948966 rad
pos: -27.5,7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11623
rot: -1.5707963267948966 rad
pos: -27.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11624
rot: -1.5707963267948966 rad
pos: -27.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 13038
rot: -1.5707963267948966 rad
pos: -101.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13042
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -101.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14139
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -131.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 14140
rot: 1.5707963267948966 rad
pos: -131.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 14141
rot: 1.5707963267948966 rad
pos: -131.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 14142
rot: 1.5707963267948966 rad
pos: -131.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 17815
rot: -1.5707963267948966 rad
pos: -93.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 17819
rot: -1.5707963267948966 rad
pos: -93.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 17820
rot: -1.5707963267948966 rad
pos: -93.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 19528
rot: 1.5707963267948966 rad
pos: -85.5,33.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19529
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -85.5,34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19530
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -85.5,35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19531
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -83.5,30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19532
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -83.5,29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19533
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -83.5,28.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19534
components:
- type: Transform
pos: -85.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19535
components:
- type: Transform
pos: -87.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22373
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -22.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22374
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -22.5,17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22375
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -22.5,16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25385
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -126.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25386
rot: -1.5707963267948966 rad
pos: -126.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25387
rot: 1.5707963267948966 rad
pos: -116.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25388
rot: 1.5707963267948966 rad
pos: -116.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25389
rot: 1.5707963267948966 rad
pos: -116.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25390
rot: 1.5707963267948966 rad
pos: -114.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25391
rot: 1.5707963267948966 rad
pos: -114.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25392
rot: 1.5707963267948966 rad
pos: -114.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 25623
rot: 1.5707963267948966 rad
pos: -66.5,-29.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25624
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -66.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25625
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -66.5,-31.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25626
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -66.5,-32.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ShuttersWindow
entities:
- uid: 3976
- type: Transform
pos: -25.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ShuttersWindowOpen
entities:
- uid: 11617
- type: Transform
pos: -29.5,4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- uid: 11618
- type: Transform
pos: -29.5,8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- proto: ShuttleConsoleCircuitboard
- type: Transform
pos: -42.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: SignAi
entities:
- uid: 21670
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- proto: SuitStorageHOS
entities:
- uid: 6775
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
immutable: False
temperature: 293.14673
moles:
- - 1.7459903
- - 6.568249
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.7459903
+ Nitrogen: 6.568249
- type: ContainerContainer
containers:
entity_storage: !type:Container
- type: Transform
pos: -60.35623,-4.475757
parent: 2
+ - uid: 6481
+ components:
+ - type: Transform
+ pos: -36.23253,-30.543175
+ parent: 2
- uid: 7290
components:
- type: Transform
- type: Transform
pos: -149.48795,-42.47385
parent: 2
+ - uid: 7609
+ components:
+ - type: Transform
+ pos: -134.52573,-43.445347
+ parent: 2
- proto: Table
entities:
- uid: 699
- type: Transform
pos: -55.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1474
components:
- type: Transform
pos: -51.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2392
components:
- type: Transform
pos: -124.5,-52.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3552
components:
- type: Transform
pos: -55.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4059
components:
- type: Transform
pos: -20.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4060
components:
- type: Transform
pos: -20.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4061
components:
- type: Transform
pos: -20.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4063
components:
- type: Transform
pos: -20.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4375
components:
- type: Transform
pos: -114.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4376
components:
- type: Transform
pos: -114.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6707
components:
- type: Transform
pos: -19.5,-28.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6842
components:
- type: Transform
pos: -89.5,-32.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6967
components:
- type: Transform
pos: -89.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9233
components:
- type: Transform
pos: -43.5,-44.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9249
components:
- type: Transform
pos: -43.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9257
components:
- type: Transform
pos: -43.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9329
components:
- type: Transform
pos: -22.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11000
components:
- type: Transform
pos: -22.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11797
components:
- type: Transform
pos: -27.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 13229
components:
- type: Transform
pos: -19.5,-33.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16048
components:
- type: Transform
pos: -87.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17298
components:
- type: Transform
pos: -126.5,-52.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19403
components:
- type: Transform
pos: -56.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26064
components:
- type: Transform
pos: -120.5,23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26065
components:
- type: Transform
pos: -118.5,23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26110
components:
- type: Transform
pos: -27.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: ToiletDirtyWater
entities:
- uid: 356
immutable: False
temperature: 293.14673
moles:
- - 1.8856695
- - 7.0937095
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
+ Oxygen: 1.8856695
+ Nitrogen: 7.0937095
- type: ContainerContainer
containers:
entity_storage: !type:Container
rot: -1.5707963267948966 rad
pos: -53.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2059
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -53.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2967
components:
- type: Transform
pos: -49.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- type: DeviceLinkSource
rot: -1.5707963267948966 rad
pos: -93.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- type: DeviceLinkSource
rot: -1.5707963267948966 rad
pos: -50.5,-60.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorHydroponicsLocked
entities:
- uid: 6138
rot: 3.141592653589793 rad
pos: -54.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSource
lastSignals:
DoorStatus: True
- type: Door
- secondsUntilStateChange: -261472.55
+ secondsUntilStateChange: -261617.84
state: Opening
- type: Airlock
autoClose: False
rot: 1.5707963267948966 rad
pos: -56.5,-23.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23313
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -56.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23429
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -56.5,-22.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorKitchenLocked
entities:
- uid: 6506
- type: Transform
pos: -54.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecure
entities:
- uid: 1715
rot: -1.5707963267948966 rad
pos: -27.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- type: DeviceLinkSource
rot: 1.5707963267948966 rad
pos: -93.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- type: DeviceLinkSource
rot: 3.141592653589793 rad
pos: -91.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9624
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -90.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26478
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -92.5,-24.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureAtmosphericsLocked
entities:
- uid: 2090
rot: 3.141592653589793 rad
pos: -110.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5730
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -108.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureCargoLocked
entities:
- uid: 11109
rot: 3.141592653589793 rad
pos: -102.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25555
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -97.5,16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25849
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -100.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureChemistryLocked
entities:
- uid: 3922
- type: Transform
pos: -38.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3923
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -38.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22702
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -37.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23992
components:
- type: Transform
pos: -37.5,-16.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureEngineeringLocked
entities:
- uid: 5724
- type: Transform
pos: -110.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5729
components:
- type: Transform
pos: -108.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 25601
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -120.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureHeadOfPersonnelLocked
entities:
- uid: 2966
rot: 3.141592653589793 rad
pos: -49.5,-8.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 2
- type: DeviceLinkSource
rot: 1.5707963267948966 rad
pos: -20.5,-5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 19617
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -20.5,-4.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureMedicalLocked
entities:
- uid: 3975
rot: 1.5707963267948966 rad
pos: -27.5,-25.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24545
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -31.5,-19.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecurePlasma
entities:
- uid: 21052
- type: Transform
pos: -38.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSource
linkedPorts:
21056:
rot: 3.141592653589793 rad
pos: -95.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureScienceLocked
entities:
- uid: 7302
- type: Transform
pos: -120.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7303
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -120.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorSecureSecurityLocked
entities:
- uid: 24033
rot: 1.5707963267948966 rad
pos: -27.5,6.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- type: DeviceLinkSink
invokeCounter: 1
- type: DeviceLinkSource
rot: 1.5707963267948966 rad
pos: -19.5,10.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20026
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -49.5,-54.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26077
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -50.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26078
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -49.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorServiceLocked
entities:
- uid: 14529
rot: 1.5707963267948966 rad
pos: -96.5,-0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14531
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -96.5,2.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindoorTheatreLocked
entities:
- uid: 3372
rot: 1.5707963267948966 rad
pos: -62.5,-35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: Window
entities:
- uid: 162
- type: Transform
pos: -34.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 169
components:
- type: Transform
pos: -33.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 170
components:
- type: Transform
pos: -32.5,-26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 292
components:
- type: Transform
pos: -31.5,-30.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 497
components:
- type: Transform
pos: -31.5,-49.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 809
components:
- type: Transform
pos: -104.5,-0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1265
components:
- type: Transform
pos: -24.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1272
components:
- type: Transform
pos: -24.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1273
components:
- type: Transform
pos: -24.5,-35.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1279
components:
- type: Transform
pos: -24.5,-34.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1286
components:
- type: Transform
pos: -24.5,-39.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1288
components:
- type: Transform
pos: -24.5,-40.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1409
components:
- type: Transform
pos: -27.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1425
components:
- type: Transform
pos: -27.5,-45.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1566
components:
- type: Transform
pos: -31.5,-47.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1568
components:
- type: Transform
pos: -27.5,-46.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1624
components:
- type: Transform
pos: -27.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1631
components:
- type: Transform
pos: -27.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1635
components:
- type: Transform
pos: -27.5,-3.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1636
components:
- type: Transform
pos: -27.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 4109
components:
- type: Transform
pos: -27.5,-43.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 6960
components:
- type: Transform
pos: -102.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9225
components:
- type: Transform
pos: -31.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9297
components:
- type: Transform
pos: -30.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11011
components:
- type: Transform
pos: -28.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11017
components:
- type: Transform
pos: -27.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11018
components:
- type: Transform
pos: -29.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11024
components:
- type: Transform
pos: -30.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11025
components:
- type: Transform
pos: -29.5,18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11028
components:
- type: Transform
pos: -28.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11029
components:
- type: Transform
pos: -27.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11030
components:
- type: Transform
pos: -31.5,13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11784
components:
- type: Transform
pos: -105.5,-21.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14570
components:
- type: Transform
pos: -64.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14595
components:
- type: Transform
pos: -64.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15921
components:
- type: Transform
pos: -105.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 17183
components:
- type: Transform
pos: -61.5,-17.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 18600
components:
- type: Transform
pos: -72.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20548
components:
- type: Transform
pos: -101.5,-0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23215
components:
- type: Transform
pos: -102.5,-36.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23418
components:
- type: Transform
pos: -101.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23419
components:
- type: Transform
pos: -99.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 23446
components:
- type: Transform
pos: -100.5,-11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24342
components:
- type: Transform
pos: -25.5,-27.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24343
components:
- type: Transform
pos: -23.5,-27.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindowDirectional
entities:
- uid: 886
rot: 1.5707963267948966 rad
pos: -48.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 887
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -48.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 893
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -48.5,-72.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 894
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -48.5,-71.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 1805
components:
- type: Transform
pos: -50.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2361
components:
- type: Transform
pos: -53.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2563
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -53.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7751
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -53.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9113
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -50.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9114
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -50.5,-59.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9115
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -50.5,-61.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14855
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -53.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15245
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -53.5,-70.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 15622
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -51.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16396
components:
- type: Transform
pos: -53.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16409
components:
- type: Transform
pos: -52.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16412
components:
- type: Transform
pos: -51.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16751
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -53.5,-73.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16753
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -49.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16754
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -53.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16771
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -50.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 16772
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -52.5,-69.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 20804
components:
- type: Transform
pos: -49.5,-74.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindowFrostedDirectional
entities:
- uid: 2847
rot: 1.5707963267948966 rad
pos: -43.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3893
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -41.5,-38.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3902
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -41.5,-37.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5643
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -96.5,-1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14204
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -96.5,1.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 14205
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -96.5,0.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22301
components:
- type: Transform
pos: -44.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 22302
components:
- type: Transform
pos: -46.5,-50.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: WindowReinforcedDirectional
entities:
- uid: 2069
rot: 3.141592653589793 rad
pos: -109.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2086
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -111.5,-7.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2255
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2258
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2308
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -119.5,-55.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2830
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -64.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2831
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -63.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2832
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -62.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2833
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -60.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2834
components:
- type: Transform
pos: -58.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2835
components:
- type: Transform
pos: -59.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2836
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -58.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2837
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -60.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2838
components:
- type: Transform
pos: -63.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2839
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -59.5,-12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2840
components:
- type: Transform
pos: -64.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 2841
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -62.5,-9.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3015
components:
- type: Transform
pos: -63.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3026
components:
- type: Transform
pos: -61.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3027
components:
- type: Transform
pos: -60.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3028
components:
- type: Transform
pos: -59.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 3029
components:
- type: Transform
pos: -62.5,5.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5727
components:
- type: Transform
pos: -109.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 5728
components:
- type: Transform
pos: -111.5,-13.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7298
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -121.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7299
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -119.5,-42.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7300
components:
- type: Transform
pos: -119.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7301
components:
- type: Transform
pos: -121.5,-48.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7530
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -121.5,-55.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7534
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -117.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7535
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -116.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7545
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -115.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7547
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -114.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7571
components:
- type: Transform
pos: -114.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7580
components:
- type: Transform
pos: -115.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7581
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -112.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7585
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -111.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7587
components:
- type: Transform
pos: -116.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7588
components:
- type: Transform
pos: -117.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7589
components:
- type: Transform
pos: -111.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7590
components:
- type: Transform
pos: -112.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7591
components:
- type: Transform
pos: -118.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7592
components:
- type: Transform
pos: -121.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7593
components:
- type: Transform
pos: -113.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7594
components:
- type: Transform
pos: -122.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7616
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -118.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7644
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -122.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7645
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -113.5,-58.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 7648
components:
- type: Transform
pos: -119.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8153
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -101.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 8553
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -95.5,26.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 9515
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -31.5,-18.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 11135
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -99.5,12.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24314
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -31.5,-20.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 24644
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -19.5,11.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26076
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -50.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- uid: 26084
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -49.5,-56.5
parent: 2
+ - type: DeltaPressure
+ gridUid: 2
- proto: Wirecutter
entities:
- uid: 8868
parent: 31
- type: WarpPoint
location: library
-- proto: WarpPointBombing
- entities:
- - uid: 934
- components:
- - type: Transform
- pos: -36.5,14.5
- parent: 31
- - type: WarpPoint
- location: chapel
- - uid: 2142
- components:
- - type: Transform
- pos: 8.5,19.5
- parent: 31
- - type: WarpPoint
- location: hop's office
- - uid: 4910
- components:
- - type: Transform
- pos: 9.5,-9.5
- parent: 31
- - type: WarpPoint
- location: medbay
- - uid: 7261
- components:
- - type: Transform
- pos: 16.5,-0.5
- parent: 31
- - type: WarpPoint
- location: chemistry
- - uid: 7262
- components:
- - type: Transform
- pos: 13.5,-15.5
- parent: 31
- - type: WarpPoint
- location: morgue
- - uid: 9712
- components:
- - type: Transform
- pos: -12.5,19.5
- parent: 31
- - type: WarpPoint
- location: armory
- - uid: 10539
- components:
- - type: Transform
- pos: -9.5,-20.5
- parent: 31
- - type: WarpPoint
- location: science
- - uid: 11267
- components:
- - type: Transform
- pos: 8.5,25.5
- parent: 31
- - type: WarpPoint
- location: captain's quarters
- - uid: 11308
- components:
- - type: Transform
- pos: 3.5,30.5
- parent: 31
- - type: WarpPoint
- location: bridge
- - uid: 11309
- components:
- - type: Transform
- pos: -1.5,17.5
- parent: 31
- - type: WarpPoint
- location: vault
- - uid: 11310
- components:
- - type: Transform
- pos: 8.5,9.5
- parent: 31
- - type: WarpPoint
- location: eva room
- - uid: 11311
- components:
- - type: Transform
- pos: 58.5,2.5
- parent: 31
- - type: WarpPoint
- location: particle accelerator
- - uid: 11313
- components:
- - type: Transform
- pos: 34.5,14.5
- parent: 31
- - type: WarpPoint
- location: atmospherics
- - uid: 11322
- components:
- - type: Transform
- pos: 27.5,18.5
- parent: 31
- - type: WarpPoint
- location: salvage
- - uid: 11359
- components:
- - type: Transform
- pos: 50.5,-5.5
- parent: 31
- - type: WarpPoint
- location: telecomms
- proto: WaterCooler
entities:
- uid: 1156
- type: entity
- parent: BaseAction
+ parent: ActionIntrinsicStore
id: ActionRevenantShop
name: Shop
description: Opens the ability shop.
- components:
- - type: Action
- icon: Interface/Actions/shop.png
- - type: InstantAction
- event: !type:RevenantShopActionEvent
- type: entity
parent: BaseAction
itemIconStyle: BigAction
- type: InstantAction
event: !type:ChameleonControllerOpenMenuEvent
+
+- type: entity
+ parent: BaseMentalAction
+ id: ActionIntrinsicStore
+ name: Store
+ description: Opens the store
+ components:
+ - type: Action
+ icon: Interface/Actions/shop.png
+ - type: InstantAction
+ event: !type:IntrinsicStoreActionEvent
slots:
hand 1:
part: LeftArmBorg
+
+# It's like a medibot or a cleanbot except it has two arms to hug :)
+- type: body
+ id: HugBot
+ name: "hugBot"
+ root: box
+ slots:
+ box:
+ part: TorsoBorg
+ connections:
+ - right_arm
+ - left_arm
+ right_arm:
+ part: RightArmBorg
+ left_arm:
+ part: LeftArmBorg
- id: RubberStampHos
- id: BoxHoSCircuitboards
- id: WeaponDisabler
+ - id: WeaponTaser
- id: WantedListCartridge
- id: DrinkHosFlask
children:
- id: FlashlightSeclite
- id: WeaponDisabler
+ - id: WeaponTaser
- id: ClothingBeltSecurityFilled
- id: Flash
- id: ClothingEyesGlassesSecurity
- id: FlashlightSeclite
prob: 0.8
- id: WeaponDisabler
+ - id: WeaponTaser
- id: ClothingUniformJumpsuitSecGrey
prob: 0.3
- id: ClothingHeadHelmetBasic
table: !type:AllSelector
children:
- id: ClothingEyesGlassesSecurity
+ - id: WeaponTaser
- id: WeaponDisabler
- id: TrackingImplanter
amount: 2
--- /dev/null
+- type: localizedDataset
+ id: HugBotStarts
+ values:
+ prefix: hugbot-start-hug-
+ count: 8
+
+- type: localizedDataset
+ id: HugBotFinishes
+ values:
+ prefix: hugbot-finish-hug-
+ count: 8
+
+- type: localizedDataset
+ id: EmaggedHugBotFinishes
+ values:
+ prefix: hugbot-emagged-finish-hug-
+ count: 8
- SurplusBundle
# Deception
-
+- type: listing
+ id: UplinkSyndicateIDCard
+ name: uplink-syndicate-id-card-name
+ description: uplink-syndicate-id-card-desc
+ productEntity: SyndicateIDCard
+ cost:
+ Telecrystal: 1
+ categories:
+ - UplinkDeception
+
- type: listing
id: UplinkAgentIDCard
name: uplink-agent-id-card-name
inhandVisuals:
left:
- state: inhand-left
- color: "#535353"
right:
- state: inhand-right
- color: "#535353"
- type: Clothing
sprite: Clothing/Hands/Gloves/Color/black.rsi
- type: Butcherable
weight: 95
children:
- id: Machete
+ - id: Claymore
- id: BaseBallBat
- id: CombatKnife
- id: Spear
- GhostOnlyWarp
- type: Sprite
state: pink
-
-- type: entity
- parent: WarpPoint
- id: WarpPointBombing
- name: warp point
- suffix: ninja bombing target
- components:
- - type: BombingTarget
- - type: Tag
- tags:
- - GhostOnlyWarp
- - type: WarpPoint
- location: bombing target
- blacklist:
- tags:
- - GhostOnlyWarp
- - type: Sprite
- layers:
- - state: pink
- - sprite: Objects/Weapons/Bombs/spidercharge.rsi
- state: icon
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: longwithbangs
+- type: marking
+ id: HumanHairOverEyePigtail
+ bodyPart: Hair
+ markingCategory: Hair
+ sprites:
+ - sprite: Mobs/Customization/human_hair.rsi
+ state: overeyepigtail
- reagents: [ Water, SpaceCleaner ]
methods: [ Touch ]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- type: Crawler
- type: entity
abstract: true
+ parent: [BaseMob, MobCombat]
id: MobElementalBase
components:
- - type: LagCompensation
- type: Reactive
groups:
Acidic: [Touch]
- - type: Clickable
- type: Damageable
damageContainer: Inorganic
- - type: InteractionOutline
- - type: Fixtures
- fixtures:
- fix1:
- shape:
- !type:PhysShapeCircle
- radius: 0.35
- density: 50
- mask:
- - MobMask
- layer:
- - MobLayer
- type: MovementSpeedModifier
baseWalkSpeed : 2
baseSprintSpeed : 3
- - type: Sprite
- noRot: true
- drawdepth: Mobs
- - type: NpcFactionMember
- factions:
- - SimpleNeutral
- type: MovedByPressure
- - type: Physics
- bodyType: KinematicController # Same for all inheritors
- type: StatusEffects
allowed:
- Electrocution
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- - type: Input
- context: "human"
- - type: InputMover
- - type: MobMover
- type: ZombieImmune
- type: ProtectedFromStepTriggers
+ - type: StunVisuals
- type: entity
abstract: true
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
groups:
- Brute: -0.25
+ Brute: -0.15
- reagents: [ Blood ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
groups:
- Brute: -0.5
- Burn: -0.5
+ Brute: -0.25
+ Burn: -0.25
- reagents: [ RobustHarvest ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
groups:
- Brute: -2
- Burn: -2
+ Brute: -1
+ Burn: -1
- reagents: [ WeedKiller, PlantBGone ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
- Heat: 2
+ Heat: 1
- type: ReplacementAccent
accent: tomatoKiller
- type: Item
type: StoreBoundUserInterface
- type: Visibility
layer: 2 #ghost vis layer
+ - type: ActionGrant
+ actions:
+ - ActionRevenantShop
- type: Store
categories:
- RevenantAbilities
- Supply
- type: Puller
needsHands: false
+
+- type: entity
+ parent: [ MobSiliconBase, MobCombat ]
+ id: MobHugBot
+ name: hugbot
+ description: Awww, who needs a hug?
+ components:
+ - type: Sprite
+ sprite: Mobs/Silicon/Bots/hugbot.rsi
+ state: hugbot
+ - type: Construction
+ graph: HugBot
+ node: bot
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 2
+ baseSprintSpeed: 3
+ - type: MeleeWeapon
+ soundHit:
+ path: /Audio/Weapons/boxingpunch1.ogg
+ angle: 30
+ animation: WeaponArcPunch
+ damage:
+ types:
+ Blunt: 2
+ - type: Anchorable
+ - type: Hands # This probably REALLY needs hand whitelisting, but we NEED hands for hugs, so...
+ - type: ComplexInteraction # Hugging is a complex interaction, apparently.
+ - type: HugBot
+ - type: Body
+ prototype: HugBot
+ - type: HTN
+ rootTask:
+ task: HugBotCompound
+ - type: InteractionPopup
+ interactSuccessString: hugging-success-generic
+ interactSuccessSound: /Audio/Effects/thudswoosh.ogg
+ messagePerceivedByOthers: hugging-success-generic-others
- reagents: [ Water, SpaceCleaner ]
methods: [ Touch ]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- reagents: [ Water ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
- Heat: 0.15
+ Heat: 0.05 #Same as slime species
- !type:PopupMessage
type: Local
messages: [ "slime-hurt-by-water-popup" ]
methods: [Touch, Ingestion, Injection]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
Caustic: 1
- reagents: [Water]
methods: [Touch]
effects:
- - !type:WearableReaction
+ - !type:SpawnEntityInInventory
slot: head
- prototypeID: WaterDropletHat
+ entity: WaterDropletHat
- reagents: [Water, SpaceCleaner]
methods: [Touch]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
# Damage (Self)
- type: Bloodstream
bloodReagent: CopperBlood
- reagents: [Water, SpaceCleaner]
methods: [Touch]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- type: StatusEffects
allowed:
- Electrocution
- reagents: [Water, SpaceCleaner]
methods: [Touch]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- reagents: [ PlantBGone ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
- Blunt: 0.1
- Slash: 0.1
- Piercing: 0.15
+ Blunt: 0.05
+ Slash: 0.05
+ Piercing: 0.075
- !type:PopupMessage
type: Local
visualType: Large
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
- Poison: 0.25
+ Poison: 0.125
- !type:PopupMessage
type: Local
visualType: Large
- reagents: [ Water, SpaceCleaner ]
methods: [ Touch ]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- reagents: [ Milk, MilkGoat, MilkSoy, MilkSpoiled ]
# add new types of milk to reagents as they appear, oat milk isn't on the list
# because turns out oat milk has 1/30th the amount of calcium in it compared to the rest
methods: [ Touch ]
effects: # TODO: when magic is around - make a milk transformation to a skeleton monster
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
groups:
- Burn: -2 # healing obviously up to discussion
- Brute: -1.5 # these groups are the only 2 possible ways to damage a skeleton
+ Burn: -1 # healing obviously up to discussion
+ Brute: -0.75 # these groups are the only 2 possible ways to damage a skeleton
- !type:PopupMessage
type: Local
visualType: Large
- type: FireVisuals
alternateState: Standing
- type: FlashImmunity
+ showInExamine: false
- type: Inventory
femaleDisplacements:
jumpsuit:
- reagents: [ Water, SpaceCleaner ]
methods: [ Touch ]
effects:
- - !type:WashCreamPieReaction
+ - !type:WashCreamPie
- reagents: [ Water ]
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
- Heat: 0.1
+ Heat: 0.05
- !type:PopupMessage
type: Local
visualType: Large
- id: Ointment
- id: Gauze
- id: Bloodpack
+ - id: SyndicateBusinessCard
+ weight: 0.5
# Packages
# TODO: Currently mostly maints loot, should be updated in the future.
weight: 0.2
rolls: !type:RangeNumberSelector
range: 2, 3
+ - !type:NestedSelector
+ tableId: InsulsTable #Uncommon since it's weighted towards budget/fingerless
+ weight: 0.2
- type: entityTable # TODO: Add more variety!
id: PackageRareEntityTable
- !type:NestedSelector
tableId: SyndieMaintLoot
weight: 0.5
+
components:
- type: NavMapBeacon
defaultText: station-beacon-solars
+ - type: Tag
+ tags:
+ - NinjaBombingTargetBlocker
- type: entity
parent: DefaultStationBeaconEngineering
components:
- type: NavMapBeacon
defaultText: station-beacon-arrivals
+ - type: Tag
+ tags:
+ - NinjaBombingTargetBlocker
- type: entity
parent: DefaultStationBeacon
components:
- type: NavMapBeacon
defaultText: station-beacon-cryosleep
+ - type: Tag
+ tags:
+ - NinjaBombingTargetBlocker
- type: entity
parent: DefaultStationBeacon
enum.CrayonUiKey.Key:
type: CrayonBoundUserInterface
- type: Crayon
- capacity: 25
+ selectedState: like
+ - type: LimitedCharges
+ maxCharges: 25
- type: Food
- type: FlavorProfile
flavors:
- type: Crayon
color: Red
selectableColor: true
- capacity: 30
+ - type: LimitedCharges
+ maxCharges: 30
- type: Tag
tags:
- Write
- Recyclable
- Trash
+- type: entity
+ parent: CrayonRainbow
+ id: CrayonInfinite # should not be player available to prevent decal spam
+ name: infinite crayon
+ components:
+ - type: Crayon
+ deleteEmpty: false
+ - type: AutoRecharge
+ rechargeDuration: 5
+
- type: entity
parent: Crayon
id: CrayonBlack
- Common
- type: DoAfter
- type: Actions
+ - type: ActionGrant
+ actions:
+ - ActionPAIOpenShop
- type: Store
categories:
- PAIAbilities
node: potatoai
- type: entity
- parent: BaseMentalAction
+ parent: ActionIntrinsicStore
id: ActionPAIOpenShop
name: Software Catalog
description: Install new software to assist your owner.
- components:
- - type: Action
- icon: Interface/Actions/shop.png
- - type: InstantAction
- event: !type:PAIShopActionEvent
- type: entity
parent: BaseMentalAction
- reagents: [ Water ]
methods: [ Touch ]
effects:
- - !type:AddToSolutionReaction
+ - !type:AddReagentToSolution
+ reagent: Water
solution: plushie
- type: Fixtures
fixtures:
methods: [Touch]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
damage:
types:
Heat: 0.5
Quantity: 2
- ReagentId: Protein
Quantity: 1
- - type: Respirator
- damage:
- types:
- Asphyxiation: 0.25
- damageRecovery:
- types:
- Asphyxiation: -0.25
+ - type: AutoEmote # Meat Kudzu used to have respirator, but couldn't breathe so all it would do is gasp.
+ emotes:
+ - MeatGasp
- type: Tag
tags:
- Meat
- state: paper_stamp-generic
map: ["enum.PaperVisualLayers.Stamp"]
visible: false
- - type: GuideHelp
- guides:
- - ArtifactReports
- type: PaperVisuals
headerImagePath: "/Textures/Interface/Paper/paper_heading_artifact_analyzer.svg.96dpi.png"
headerMargin: 0.0, 0.0, 0.0, 16.0
icon: { sprite: /Textures/Objects/Economy/cash.rsi, state: cash }
price: 1
-- type: stack
- id: Credit
- name: stack-credit
- icon: { sprite: /Textures/Objects/Economy/cash.rsi, state: cash }
- spawn: SpaceCash
-
- type: entity
parent: SpaceCash
id: SpaceCash10
acts: [ "Destruction" ]
- type: PowerSink
- type: Battery
- maxCharge: 7500000
- pricePerJoule: 0.0003
+ maxCharge: 250000000
+ pricePerJoule: 0.000009
- type: ExaminableBattery
- type: PowerConsumer
voltage: High
delay: 1
- type: GuideHelp
guides:
- - ArtifactReports
+ - Xenoarchaeology
- type: ActivatableUI
key: enum.NodeScannerUiKey.Key
singleUser: true
- reagents: [Water]
methods: [Touch, Ingestion, Injection]
effects:
- - !type:AddToSolutionReaction
+ - !type:AddReagentToSolution
+ reagent: Water
solution: cube
- type: Rehydratable
- type: CollisionWake
- reagents: [Blood]
methods: [Touch, Ingestion, Injection]
effects:
- - !type:AddToSolutionReaction
+ - !type:AddReagentToSolution
+ reagent: Blood
solution: cube
- type: Rehydratable
catalyst: Blood # blood is fuel
- type: CartridgeAmmo
proto: BulletPistol
spent: true
+ - type: Tag
+ tags:
+ - CartridgePistol
+ - Trash # surely theres a way to automatically add this...
slots:
- Belt
- type: Gun
+ fireRate: 0.5
soundGunshot:
path: /Audio/Weapons/Guns/Gunshots/taser.ogg
- type: ProjectileBatteryAmmoProvider
lifetime: 0.170 # Very short range
- type: StunOnCollide
stunAmount: 0
- knockdownAmount: 2.5 # Enough to subdue and follow up with a stun batong
+ knockdownAmount: 2.5 # Enough to subdue and follow up with a stun baton
+ drop: false #Ranged KD and item drop are too strong in one package
slowdownAmount: 2.5
walkSpeedModifier: 0.5
sprintSpeedModifier: 0.5
lifetime: 1.0 # Not so short range
- type: StunOnCollide
stunAmount: 5
+ drop: true # this is the evil taser
knockdownAmount: 10
slowdownAmount: 10
walkSpeedModifier: 0.5
whitelist:
components:
- MobState
+ - MovementSpeedModifier
+ requireAll: true
blacklist:
tags:
- SlowImmune
- type: MovementModStatusEffect
+- type: entity
+ parent: MobStatusEffectBase
+ id: StatusEffectSpeed
+ abstract: true
+ name: speed
+ components:
+ - type: StatusEffect
+ whitelist:
+ components:
+ - MobState
+ - MovementSpeedModifier
+ requireAll: true
+ - type: MovementModStatusEffect
+
+- type: entity
+ parent: StatusEffectSpeed
+ id: ReagentSpeedStatusEffect
+ name: reagent speed
+
- type: entity
parent: StatusEffectSlowdown
id: VomitingSlowdownStatusEffect
#Airtight hatch
- type: entity
- parent: AirlockHatch
- id: AirlockHatchSyndicate
+ parent: AirlockHatchSyndicate
+ id: AirlockHatchSyndicateLocked
suffix: Syndicate, Locked
components:
- type: ContainerFill
containers:
board: [ DoorElectronicsSyndicateAgent ]
+
+- type: entity
+ parent: AirlockHatchMaintenance
+ id: AirlockHatchMaintenanceLocked
+ suffix: Locked
+ components:
+ - type: ContainerFill
+ containers:
+ board: [ DoorElectronicsMaintenance ]
- type: Paintable
group: null
+- type: entity
+ parent: Airlock
+ id: AirlockHatchSyndicate
+ name: airtight hatch
+ suffix: Syndicate
+ components:
+ - type: Sprite
+ sprite: Structures/Doors/Airlocks/Standard/hatch_syndicate.rsi
+
# Glass
- type: entity
parent: AirlockGlass
color: "#b53ca1"
- type: GuideHelp
guides:
- - Xenoarchaeology
+ - AnalysisConsole
- type: entity
parent: BaseComputerAiAccess
staticPacks:
- BioGenIngredientsStatic
- BioGenMaterialsStatic
+ - type: EmagLatheRecipes
+ emagStaticPacks:
+ - BioGenEmagStatic
+ - HostileCubesStatic
- type: entity
parent: BaseLathe
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: fire_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: fire_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: fire_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: shock_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: shock_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: shock_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: shadow_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: shadow_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: shadow_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: frost_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: frost_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: frost_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: flora_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: flora_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: flora_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: bluespace_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: bluespace_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: bluespace_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: flesh_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: flesh_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: flesh_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: grav_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: grav_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: grav_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: tech_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: tech_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: tech_MOTH
- type: entity
parent: BaseAnomalyInjector
Vox:
sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
state: rock_VOX
+ Arachnid:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: rock_ARACHNID
+ Moth:
+ sprite: Structures/Specific/Anomalies/inner_anom_layer.rsi
+ state: rock_MOTH
- type: entity
parent: BaseAnomalyInjector
- type: entity
- parent: [BaseStructureDynamic, BaseItemCabinetGlass]
+ parent: BaseStructureDynamic
id: BaseGlassBox
abstract: true
components:
+ - type: Sprite
+ noRot: true
+ sprite: Structures/Storage/glassbox.rsi
- type: Transform
anchored: true
- type: Physics
delay: 4
- type: entity
+ parent: [BaseGlassBox, BaseItemCabinetGlass]
id: GlassBox
name: glass box
description: A sturdy showcase for an expensive exhibit.
- parent: BaseGlassBox
abstract: true # TODO: Temporarily abstract. Remove it after item scaling in cabinets is implemented.
components:
- type: Sprite
- noRot: true
- sprite: Structures/Storage/glassbox.rsi
layers:
- state: base
- state: caplaser # TODO: Remove it after item scaling in cabinets is implemented.
map: ["enum.ItemCabinetVisuals.Layer"]
- visible: true
+ visible: false
- state: glass
map: ["enum.OpenableVisuals.Layer"]
- state: locked
acts: [ "Destruction" ]
- type: entity
- id: GlassBoxLaser
parent: GlassBox
+ id: GlassBoxLaser
suffix: AntiqueLaser
components:
- type: AccessReader
ejectSound: /Audio/Machines/machine_switch.ogg
- type: entity
- id: GlassBoxLaserOpen
parent: GlassBoxLaser
+ id: GlassBoxLaserOpen
suffix: AntiqueLaser, Open
components:
- type: Openable
locked: false
- type: entity
- id: GlassBoxLaserFilled
parent: GlassBoxLaser
+ id: GlassBoxLaserFilled
suffix: AntiqueLaser, Filled
components:
- type: ContainerFill
suffix: AntiqueLaser, Filled, Open
- type: entity
+ parent: BaseGlassBox
id: GlassBoxFrame
name: glass box frame
description: A glassless sturdy showcase for an expensive exhibit.
- parent: BaseGlassBox
suffix: Frame
components:
- type: Sprite
- noRot: true
- sprite: Structures/Storage/glassbox.rsi
layers:
- state: base
- type: Construction
acts: ["Destruction"]
- type: entity
+ parent: GlassBoxFrame
id: GlassBoxBroken
name: broken glass box
description: A broken showcase for a stolen expensive exhibit.
- parent: GlassBoxFrame
suffix: Broken
components:
- type: Sprite
- sprite: Structures/Storage/glassbox.rsi
layers:
- state: base
- state: glass-broken
- reagents: [Water]
methods: [Touch, Ingestion, Injection]
effects:
- - !type:AddToSolutionReaction
+ - !type:AddReagentToSolution
+ reagent: Water
solution: soil
- type: Appearance
- type: PlantHolderVisuals
- Catwalk
- type: TileEntityEffect
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 3.75
multiplierOnExisting: 0.75
- !type:Ignite
- Catwalk
- type: TileEntityEffect
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 3.75
multiplierOnExisting: 0.75
- !type:Ignite
- type: SolutionContainerManager
solutions:
pool:
- maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable.
+ maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable.
reagents:
- ReagentId: Water
Quantity: 9999999
- Catwalk
- type: TileEntityEffect
effects:
- - !type:ExtinguishReaction
+ - !type:Extinguish
name: guide-entry-xenoarchaeology
text: "/ServerInfo/Guidebook/Science/Xenoarchaeology.xml"
children:
- - ArtifactReports
+ - AnalysisConsole
+ - XenoarchaeologyUnlockingNodes
+
+- type: guideEntry
+ id: XenoarchaeologyUnlockingNodes
+ name: guide-entry-xenoarchaeologyunlockingnodes
+ text: "/ServerInfo/Guidebook/Science/UnlockingNodes.xml"
+
+- type: guideEntry
+ id: AnalysisConsole
+ name: guide-entry-analysisconsole
+ text: "/ServerInfo/Guidebook/Science/AnalysisConsole.xml"
- type: guideEntry
id: Robotics
children:
- Cyborgs
-- type: guideEntry
- id: ArtifactReports
- name: guide-entry-artifact-reports
- text: "/ServerInfo/Guidebook/Science/ArtifactReports.xml"
-
- type: guideEntry
id: Cyborgs
name: guide-entry-cyborgs
- name: ChangeSpecies
baseOdds: 0.036
appliesToProduce: false
- effect: !type:PlantSpeciesChange
+ effect: !type:PlantMutateSpeciesChange
persists: false
- name: Unviable
baseOdds: 0.109
- name: ChangeExudeGasses
baseOdds: 0.0145
persists: false
- effect: !type:PlantMutateExudeGasses
+ effect: !type:PlantMutateExudeGases
- name: ChangeConsumeGasses
baseOdds: 0.0036
persists: false
- effect: !type:PlantMutateConsumeGasses
+ effect: !type:PlantMutateConsumeGases
- name: ChangeHarvest
baseOdds: 0.036
persists: false
- !type:KeyFloatLessPrecondition
key: Count
value: 50
-
+
- !type:HTNPrimitiveTask
operator: !type:RandomOperator
targetKey: IdleTime
- tasks:
- !type:HTNPrimitiveTask
operator: !type:SpeakOperator
- speech: "fuck!"
-
-
\ No newline at end of file
+ speech: !type:SingleSpeakOperatorSpeech
+ line: "fuck!"
task: DouseFireTargetCompound
- tasks:
- !type:HTNCompoundTask
- task: IdleCompound
-
+ task: IdleCompound
+
- type: htnCompound
id: DouseFireTargetCompound
branches:
- !type:HTNPrimitiveTask
operator: !type:SpeakOperator
- speech: firebot-fire-detected
- hidden: true
+ speech: !type:SingleSpeakOperatorSpeech
+ line: firebot-fire-detected
+ hidden: true
- !type:HTNPrimitiveTask
operator: !type:MoveToOperator
--- /dev/null
+- type: htnCompound
+ id: HugBotCompound
+ branches:
+ - tasks:
+ - !type:HTNCompoundTask
+ task: HugNearbyCompound
+ - tasks:
+ - !type:HTNCompoundTask
+ task: IdleCompound
+
+- type: htnCompound
+ id: HugNearbyCompound
+ branches:
+ - tasks:
+ # Locate hug recipient.
+ - !type:HTNPrimitiveTask
+ operator: !type:UtilityOperator
+ proto: NearbyNeedingHug
+
+ # Announce intent to hug
+ - !type:HTNPrimitiveTask
+ operator: !type:SpeakOperator
+ speech: !type:LocalizedSetSpeakOperatorSpeech
+ lineSet: HugBotStarts
+ hidden: true
+
+ # Approach hug recipient
+ - !type:HTNPrimitiveTask
+ operator: !type:MoveToOperator
+ pathfindInPlanning: true
+ removeKeyOnFinish: false
+ targetKey: TargetCoordinates
+ pathfindKey: TargetPathfind
+ rangeKey: MeleeRange
+
+ # HUG!!
+ - !type:HTNCompoundTask
+ task: HugBotHugCompound
+
+ # Stick around to enjoy the hug instead of just running up, squeezing and leaving.
+ - !type:HTNPrimitiveTask
+ operator: !type:SetFloatOperator
+ targetKey: IdleTime
+ amount: 1
+ - !type:HTNPrimitiveTask
+ operator: !type:WaitOperator
+ key: IdleTime
+ preconditions:
+ - !type:KeyExistsPrecondition
+ key: IdleTime
+
+ # Special case operator which applies the hugbot cooldown.
+ - !type:HTNPrimitiveTask
+ operator: !type:RaiseEventForOwnerOperator
+ args: !type:HugBotDidHugEvent
+ targetKey: Target
+
+ # Announce that the hug is completed.
+ - !type:HTNCompoundTask
+ task: HugBotFinishSpeakCompound
+
+- type: htnCompound
+ id: HugBotHugCompound
+ branches:
+ # Hit if emagged
+ - preconditions:
+ - !type:IsEmaggedPrecondition
+ tasks:
+ - !type:HTNPrimitiveTask
+ preconditions:
+ - !type:TargetInRangePrecondition
+ targetKey: Target
+ rangeKey: InteractRange
+ operator: !type:MeleeAttackOperator
+ targetKey: Target
+ services:
+ - !type:UtilityService
+ id: HugService
+ proto: NearbyNeedingHug
+ key: Target
+ # Hug otherwise
+ - tasks:
+ - !type:HTNPrimitiveTask
+ preconditions:
+ - !type:TargetInRangePrecondition
+ targetKey: Target
+ rangeKey: InteractRange
+ operator: !type:InteractWithOperator
+ targetKey: Target
+ services:
+ - !type:UtilityService
+ id: HugService
+ proto: NearbyNeedingHug
+ key: Target
+
+- type: htnCompound
+ id: HugBotFinishSpeakCompound
+ branches:
+ # Say mean things if emagged
+ - preconditions:
+ - !type:IsEmaggedPrecondition
+ tasks:
+ - !type:HTNPrimitiveTask
+ operator: !type:SpeakOperator
+ speech: !type:LocalizedSetSpeakOperatorSpeech
+ lineSet: EmaggedHugBotFinishes
+ hidden: true
+ # Say nice thing otherwise
+ - tasks:
+ - !type:HTNPrimitiveTask
+ operator: !type:SpeakOperator
+ speech: !type:LocalizedSetSpeakOperatorSpeech
+ lineSet: HugBotFinishes
+ hidden: true
+
+- type: utilityQuery
+ id: NearbyNeedingHug
+ query:
+ - !type:ComponentQuery
+ components:
+ - type: HumanoidAppearance
+ species: Human # This specific value isn't actually used, so don't worry about it being just `Human`.
+ - !type:ComponentFilter
+ retainWithComp: false
+ components:
+ - type: RecentlyHuggedByHugBot
+ considerations:
+ - !type:TargetDistanceCon
+ curve: !type:PresetCurve
+ preset: TargetDistance
+ - !type:TargetAccessibleCon
+ curve: !type:BoolCurve
+ - !type:TargetInLOSOrCurrentCon
+ curve: !type:BoolCurve
- !type:HTNPrimitiveTask
operator: !type:SpeakOperator
- speech: medibot-start-inject
+ speech: !type:SingleSpeakOperatorSpeech
+ line: medibot-start-inject
hidden: true
- !type:HTNPrimitiveTask
sprite: Objects/Weapons/Bombs/spidercharge.rsi
state: icon
- type: SpiderChargeCondition
+ blacklist:
+ tags:
+ - GhostOnlyWarp
+ - NinjaBombingTargetBlocker
- type: entity
parent: [BaseNinjaObjective, BaseSurviveObjective]
minCollectionSize: 2
maxCollectionSize: 5
verifyMapExistence: false
- checkStealAreas: false
- type: Objective
difficulty: 1.2
- type: parallax
id: TrainStation
layers:
- - texture:
- !type:ImageParallaxTextureSource
- path: "/Textures/Parallaxes/AspidParallaxBG.png"
- slowness: 0.998046875
- scale: "0.5, 0.5"
- scrolling: "0, -0.098046875"
- - texture:
- !type:GeneratedParallaxTextureSource
- id: "hq_wizard_stars"
- configPath: "/Prototypes/Parallaxes/parallax_config_stars.toml"
- slowness: 0.996625
- scrolling: "0, -0.196625"
- - texture:
- !type:GeneratedParallaxTextureSource
- id: "hq_wizard_stars_dim"
- configPath: "/Prototypes/Parallaxes/parallax_config_stars_dim.toml"
- slowness: 0.989375
- scrolling: "0, -0.209375"
- - texture:
- !type:GeneratedParallaxTextureSource
- id: "hq_wizard_stars_faster"
- configPath: "/Prototypes/Parallaxes/parallax_config_stars-2.toml"
- slowness: 0.987265625
- scrolling: "0, -0.287265625"
- - texture:
- !type:GeneratedParallaxTextureSource
- id: "hq_wizard_stars_dim_faster"
- configPath: "/Prototypes/Parallaxes/parallax_config_stars_dim-2.toml"
- slowness: 0.984352
- scrolling: "0, -0.384352"
- texture:
!type:ImageParallaxTextureSource
path: "/Textures/Parallaxes/AspidParallaxBG.png"
- !type:ModifyStatusEffect
effectProto: StatusEffectSeeingRainbow
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Absinthe
min: 10
type: Add
time: 5
- absinthe-effect-feel-tulips
probability: 0.02
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Absinthe
min: 10
- type: reagent
effects:
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ethanol
min: 15
- - !type:OrganType
- type: Dwarf
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Dwarf ]
+ inverted: true
damage:
types:
Poison: 1
# dwarves take less toxin damage and heal a marginal amount of brute
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ethanol
min: 15
- - !type:OrganType
- type: Dwarf
+ - !type:MetabolizerTypeCondition
+ type: [ Dwarf ]
damage:
types:
Poison: 0.2
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ethanol
min: 15
- - !type:OrganType
- type: Dwarf
+ - !type:MetabolizerTypeCondition
+ type: [ Dwarf ]
damage:
groups:
Brute: -1
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.04
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Ethanol
min: 12
# dwarves immune to vomiting from alcohol
- - !type:OrganType
- type: Dwarf
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Dwarf ]
+ inverted: true
- !type:Drunk
boozePower: 2
metabolisms:
Drink:
effects:
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Mayojito
min: 5
probability: 0.5
- !type:HealthChange
boozePower: 10
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: BacchusBlessing
min: 6
- - !type:OrganType
- type: Dwarf
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Dwarf]
+ inverted: true
damage:
types:
Poison: 2 # TODO: Figure out poison amount. Ethanol does 1, this does 2 but also metabolises almost 3 to 4 times as fast as ethanol. This would be more Liver damage when that time arrives.
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: BacchusBlessing
min: 6
- - !type:OrganType
- type: Dwarf
+ - !type:MetabolizerTypeCondition
+ type: [Dwarf]
damage:
types:
Poison: 0.4 # TODO: Might increase this, even though it's just double of ethanol from 0.2 to 0.4
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.1 #TODO: Tweak vomit probability, maybe make this more violent and poisonous but the body aggressively purges it...
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: BacchusBlessing
min: 8
- - !type:OrganType
- type: Dwarf
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Dwarf]
+ inverted: true
Extinguish:
methods: [ Touch ]
effects:
- - !type:ExtinguishReaction
+ - !type:Extinguish
plantMetabolism:
- !type:PlantAdjustWater
amount: 1
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
tileReactions:
- !type:FlammableTileReaction
temperatureMultiplier: 1.35
Gas:
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
conditions:
- - !type:OrganType
- type: Slime
- shouldHave: true
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
damage:
types:
Heat: 3
desc: reagent-desc-ice
slipData:
requiredSlipSpeed: 3.5
+ evaporationSpeed: 0.15 # TODO: Ideally Ice should just turn into Water if the room is warm enough (and vis versa), rather than Ice directly evaporating
physicalDesc: reagent-physical-desc-frosty
flavor: cold
color: "#bed8e6"
recognizable: true
meltingPoint: 0.0
boilingPoint: 100.0
- friction: 0.05 #Copied from Ice Crust
+ friction: 0.05 # Copied from Ice Crust
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 3 # Slightly worse for quenching thirst than just straight water
plantMetabolism:
- !type:PlantAdjustWater
- amount: 1
+ amount: 1 # The internet tells me I should avoid watering plants with ice, but mostly because of temperature, so this value being the same as water should probably be fine?
metamorphicSprite:
sprite: Objects/Consumable/Drinks/iceglass.rsi
state: icon_empty
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Slime]
+ inverted: true
damage:
types:
Poison: 1
Brute: -0.5
Burn: -0.5
# Helps you stop bleeding to an extent.
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -0.25
- !type:SatiateHunger #Numbers are balanced with this in mind + it helps limit how much healing you can get from food
# Lets plants benefit too
effects:
- !type:SatiateHunger
conditions:
- - !type:ReagentThreshold #Only satiates when eaten with nutriment
+ - !type:ReagentCondition #Only satiates when eaten with nutriment
reagent: Nutriment
min: 0.1
factor: 1
emote: Cough
showInGuidebook: true
conditions:
- - !type:Breathing
- - !type:Internals
- usingInternals: false
+ - !type:BreathingCondition
+ - !type:InternalsCondition
+ inverted: true
- type: reagent
id: Vinegar
- !type:AdjustReagent
reagent: Vitamin
amount: 0.1
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Vinegar
min: 6
- type: reagent
amount: 250 # thermal energy, not temp
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: CapsaicinOil
min: 5
damage:
types:
effects:
- !type:SatiateHunger
conditions:
- - !type:ReagentThreshold #Only satiates when eaten with nutriment
+ - !type:ReagentCondition #Only satiates when eaten with nutriment
reagent: Nutriment
min: 0.1
factor: 1
amount: -250 # thermal energy, not temp
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: FrostOil
min: 5
damage:
types:
unit: materials-unit-chunk
icon: { sprite: Objects/Materials/ore.rsi, state: salt }
color: "#f5e7d7"
- price: 0.075
\ No newline at end of file
+ price: 0.075
- !type:SatiateThirst
factor: 1.0
conditions:
- - !type:OrganType
- type: Human
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Human ]
+ inverted: true
Food:
effects:
- !type:AdjustReagent
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Bloodsucker
+ - !type:MetabolizerTypeCondition
+ type: [ Bloodsucker ]
damage:
groups:
Brute: -3
damage:
types:
Poison: 4
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.25
- type: reagent
damage:
types:
Bloodloss: -3
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -1.5
# Just in case you REALLY want to water your plants
plantMetabolism:
effects:
- !type:SatiateHunger
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- type: reagent
id: Left4Zed
effects:
- !type:SatiateHunger
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- !type:HealthChange
damage:
types:
Poison: 1
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- type: reagent
id: PestKiller
types:
Poison: 3
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- type: reagent
id: PlantBGone
Slash: 1
Piercing: 1
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- type: reagent
id: RobustHarvest
Slash: -3
Piercing: -3
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Plant
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
+ - !type:ReagentCondition
+ reagent: RobustHarvest
min: 30
damage:
types:
- !type:Polymorph
prototype: TreeMorph
conditions:
- - !type:OrganType
- type: Plant
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
+ - !type:ReagentCondition
+ reagent: RobustHarvest
min: 80
- type: reagent
types:
Poison: 4
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [Plant]
- type: reagent
id: Ammonia
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Rat
- shouldHave: false
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [ Rat ]
+ inverted: true
+ - !type:ReagentCondition
reagent: Ammonia
min: 1
ignoreResistances: true
damage:
types:
Poison: 0.25
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.12
conditions:
- - !type:OrganType
- type: Rat
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [ Rat, Vox ]
+ inverted: true
+ - !type:ReagentCondition
reagent: Ammonia
min: 0.8
- !type:PopupMessage
messages: [ "ammonia-smell" ]
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Ammonia
min: 0.25
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Rat
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [ Rat ]
+ - !type:ReagentCondition
reagent: Ammonia
min: 1
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
groups:
- Brute: -5
- Burn: -5
+ Brute: -2.5
+ Burn: -2.5
types:
Bloodloss: -5
- !type:Oxygenate # ammonia displaces nitrogen in vox blood
conditions:
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
factor: -4
damage:
types:
Poison: -1
- - !type:ChemCleanBloodstream
+ - !type:CleanBloodstream
+ excluded: Charcoal
cleanseRate: 3
- type: reagent
methods: [ Touch ]
effects:
- !type:ArtifactUnlock
- conditions:
- - !type:ReagentThreshold
- min: 5
+ minScale: 5
- type: reagent
parent: Artifexium
methods: [ Touch ]
effects:
- !type:ArtifactDurabilityRestore
- conditions:
- - !type:ReagentThreshold
- min: 5
+ minScale: 5
- type: reagent
id: Benzene
Heat: 1.5
Medicine:
effects:
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: SodiumHydroxide
min: 5
probability: 0.1
metabolisms:
Food:
effects:
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: SoapReagent
min: 6
probability: 0.20
Drink:
effects:
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: SoapReagent
min: 6
probability: 0.20
methods: [ Touch ]
effects:
# pva glue? no, antibiotic glue for sealing wounds
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -1.5
metabolisms:
Narcotic:
- !type:GenericStatusEffect
key: Muted
component: Muted
- type: Add
time: 5
- refresh: false
footstepSound:
collection: FootstepSlime
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Arachnid
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Arachnid ]
+ inverted: true
damage:
types:
Poison: 0.1
effects:
- !type:ModifyBloodLevel
conditions:
- - !type:OrganType
- type: Arachnid
- shouldHave: true
+ - !type:MetabolizerTypeCondition
+ type: [ Arachnid ]
amount: 0.4
- type: reagent
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Arachnid
- shouldHave: true
+ - !type:MetabolizerTypeCondition
+ type: [ Arachnid ]
damage:
types:
Poison: 0.1
effects:
- !type:ModifyBloodLevel
conditions:
- - !type:OrganType
- type: Arachnid
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Arachnid ]
+ inverted: true
amount: 0.4
- type: reagent
# Hail the madman logic, if it has CARP, means it helps against CARPs
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: CarpoToxin
min: 1
reagent: CarpoToxin
effects:
- !type:SatiateHunger
conditions:
- - !type:OrganType
- type: Moth
+ - !type:MetabolizerTypeCondition
+ type: [ Moth ]
- type: reagent
id: BuzzochloricBees
- "buzzochloricbees-effect-squeaky-clean"
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
max: 0
reagent: Histamine
- - !type:HasTag
- invert: true
+ - !type:TagCondition
+ inverted: true
tag: Bee
- !type:PopupMessage
type: Local
- "buzzochloricbees-effect-squeaky-clean"
probability: 0.05
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
min: 0.01
reagent: Histamine
- - !type:HasTag
- invert: true
+ - !type:TagCondition
+ inverted: true
tag: Bee
- !type:PopupMessage
type: Local
- "buzzochloricbees-effect-licoxide-buzzes"
probability: 0.05
conditions:
- - !type:HasTag
- invert: true
+ - !type:TagCondition
+ inverted: true
tag: Bee
- - !type:ReagentThreshold
+ - !type:ReagentCondition
min: 0.01
reagent: Licoxide
- !type:PopupMessage
- "buzzochloricbees-effect-fiber-soft"
probability: 0.05
conditions:
- - !type:HasTag
- invert: true
+ - !type:TagCondition
+ inverted: true
tag: Bee
- - !type:ReagentThreshold
+ - !type:ReagentCondition
min: 0.01
reagent: Fiber
- !type:HealthChange
Poison: 2
Piercing: 2
conditions:
- - !type:HasTag
- invert: true
+ - !type:TagCondition
+ inverted: true
tag: Bee
- type: reagent
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
- Slash: 0.5
+ Slash: 0.25
- !type:Emote
emote: Scream
probability: 0.7
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
Cold: 0.05
- !type:AdjustTemperature
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
min: 160.15
amount: -30000
Extinguish:
methods: [ Touch ]
effects:
- - !type:ExtinguishReaction # cold
+ - !type:Extinguish # cold
metabolisms:
Poison:
metabolismRate : 0.45
Heat: -3 # ghetto burn chem. i don't think anyone would use this intentionally but it's funny
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Fresium
max: 35
type: Local
probability: 0.05
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Fresium
max: 35
type: Local
probability: 0.2
- !type:AdjustTemperature
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
min: 160.15 # not quite enough for cryo, but can speed it up if you wanna take the risk
amount: -10000
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Fresium
max: 40 # slows when less than 40
walkSpeedModifier: 0.6
sprintSpeedModifier: 0.6
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Fresium
min: 40 # your legs stop working when above 40
walkSpeedModifier: 0.00
sprintSpeedModifier: 0.00
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Fresium
min: 40
type: Local
- !type:Polymorph
prototype: ArtifactLizard # Does the same thing as the original YML I made for this reagent.
conditions:
- - !type:OrganType
- type: Animal
- shouldHave: false
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [Animal]
+ inverted: true
+ - !type:ReagentCondition
+ reagent: JuiceThatMakesYouWeh
min: 50
- !type:AdjustReagent
reagent: JuiceThatMakesYouWeh
amount: -20
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: JuiceThatMakesYouWeh
min: 50
- type: reagent
- !type:Polymorph
prototype: ArtifactLizard
conditions:
- - !type:OrganType
- type: Animal
- shouldHave: false
- - !type:ReagentThreshold
+ - !type:MetabolizerTypeCondition
+ type: [ Animal ]
+ inverted: true
+ - !type:ReagentCondition
+ reagent: JuiceThatMakesYouHew
min: 50
- !type:AdjustReagent
reagent: JuiceThatMakesYouHew
amount: -20
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: JuiceThatMakesYouHew
min: 50
- type: reagent
effects:
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: CorgiJuice
min: 15
damage:
types:
- !type:Polymorph
prototype: SmartCorgiMorph
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: CorgiJuice
min: 50
- !type:AdjustReagent
reagent: CorgiJuice
amount: -20
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: CorgiJuice
min: 50
Poison:
effects:
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Human
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Animal
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Rat
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [ Human, Animal, Rat, Plant ]
# Convert Oxygen into CO2.
- !type:ModifyLungGas
+ scaling: true
conditions:
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
+ inverted: true
ratios:
CarbonDioxide: 1.0
Oxygen: -1.0
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Vox
- scaleByQuantity: true
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
+ scaling: true
ignoreResistances: true
damage:
types:
- Poison:
- 3
+ Poison: 1.5
- !type:AdjustAlert
alertType: Toxins
+ minScale: 1
conditions:
- - !type:ReagentThreshold
- min: 0.5
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
clear: true
time: 5
Gas:
effects:
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Human
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Animal
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Rat
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [ Human, Animal, Rat, Plant ]
# Convert Oxygen into CO2.
- !type:ModifyLungGas
+ scaling: true
conditions:
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
+ inverted: true
ratios:
CarbonDioxide: 1.0
Oxygen: -1.0
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Vox
- scaleByQuantity: true
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
+ scaling: true
ignoreResistances: true
damage:
types:
- Poison:
- 7
+ Poison: 0.7
- !type:AdjustAlert
alertType: Toxins
+ minScale: 1
conditions:
- - !type:ReagentThreshold
- min: 0.5
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
clear: true
time: 5
- !type:HealthChange
damage:
types:
- Poison: 3
+ Poison: 1.5
- !type:AdjustReagent
reagent: Inaprovaline
amount: -2.0
Gas:
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
types:
Poison:
- 1
+ 0.1
# We need a metabolism effect on reagent removal
- !type:AdjustAlert
alertType: Toxins
- conditions:
- - !type:ReagentThreshold
- min: 1.5
+ minScale: 3
clear: True
time: 5
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
- type: reagent
id: Tritium
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.8
metabolisms:
Poison:
- !type:HealthChange
damage:
types:
- Radiation: 3
+ Radiation: 1.5
Gas:
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
types:
# We need a metabolism effect on reagent removal
- !type:AdjustAlert
alertType: Toxins
- conditions:
- - !type:ReagentThreshold
- min: 1.5
+ minScale: 3
clear: True
time: 5
Poison:
effects:
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [ Plant ]
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Plant
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
- scaleByQuantity: true
+ - !type:MetabolizerTypeCondition
+ type: [ Plant, Vox ]
+ inverted: true
+ scaling: true
ignoreResistances: true
damage:
types:
Poison:
- 0.8
+ 0.4
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Plant
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Plant ]
+ inverted: true
factor: -4
Gas:
effects:
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Plant
+ - !type:MetabolizerTypeCondition
+ type: [ Plant ]
- !type:HealthChange
+ minScale: 1
conditions:
- - !type:OrganType
- type: Plant
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Plant, Vox ]
+ inverted: true
# Don't want people to get toxin damage from the gas they just
# exhaled, right?
- - !type:ReagentThreshold
- min: 0.5
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
types:
Poison:
0.8
- !type:Oxygenate # carbon dioxide displaces oxygen from the bloodstream, causing asphyxiation
+ scaling: true
conditions:
- - !type:OrganType
- type: Plant
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Plant ]
+ inverted: true
factor: -4
# We need a metabolism effect on reagent removal
#- !type:AdjustAlert
- !type:HealthChange
damage:
types:
- Cold: 1 # liquid nitrogen is cold
+ Cold: 0.5 # liquid nitrogen is cold
Gas:
effects:
- !type:Oxygenate
+ scaling: true
conditions:
- - !type:OrganType
- type: Vox
- - !type:Oxygenate
- conditions:
- - !type:OrganType
- type: Slime
- # Converts Nitrogen into CO2
+ - !type:MetabolizerTypeCondition
+ type: [ Vox, Slime ]
+ # Converts Nitrogen into Ammonia
- !type:ModifyLungGas
+ scaling: true
conditions:
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
ratios:
Ammonia: 1.0
Nitrogen: -1.0
- !type:ModifyLungGas
+ scaling: true
conditions:
- - !type:OrganType
- type: Slime
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
ratios:
NitrousOxide: 1.0
Nitrogen: -1.0
- !type:HealthChange
damage:
types:
- Poison: 2
+ Poison: 1
Gas:
effects:
- !type:Emote
+ minScale: 1
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 0.2
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
emote: Laugh
showInChat: true
probability: 0.1
- !type:Emote
+ minScale: 0.4
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 0.2
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
emote: Scream
showInChat: true
probability: 0.01
- !type:PopupMessage
+ minScale: 1
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 0.5
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
type: Local
visualType: Medium
messages: [ "effect-sleepy" ]
probability: 0.1
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
+ minScale: 2
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 1
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
walkSpeedModifier: 0.65
sprintSpeedModifier: 0.65
- !type:ModifyStatusEffect
+ minScale: 3.6
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 1.8
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
effectProto: StatusEffectForcedSleeping
time: 3
type: Update
- !type:HealthChange
+ minScale: 7
conditions:
- - !type:ReagentThreshold
- reagent: NitrousOxide
- min: 3.5
- - !type:OrganType
- type: Slime
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Slime ]
+ inverted: true
ignoreResistances: true
damage:
types:
Narcotic:
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
types:
- Cellular: 1
+ Cellular: 0.5
- !type:ModifyStatusEffect
effectProto: StatusEffectSeeingRainbow
type: Add
type: Local
messages: [ "frezon-lungs-cold" ]
probability: 0.1
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 0.5
+ minScale: 1
- !type:PopupMessage
type: Local
visualType: Medium
messages: [ "frezon-euphoric" ]
probability: 0.1
conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 1
+ minScale: 2
Gas:
effects:
- !type:HealthChange
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 0.5
- scaleByQuantity: true
+ minScale: 1
+ scaling: true
ignoreResistances: true
damage:
types:
- Cellular: 0.5
+ Cellular: 0.05
- !type:ModifyStatusEffect
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 1
+ minScale: 2
effectProto: StatusEffectSeeingRainbow
type: Add
time: 500
- !type:Drunk
boozePower: 500
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 1
+ minScale: 2
- !type:PopupMessage
type: Local
messages: [ "frezon-lungs-cold" ]
probability: 0.1
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 0.5
+ minScale: 2
- !type:PopupMessage
type: Local
visualType: Medium
messages: [ "frezon-euphoric" ]
probability: 0.1
- conditions:
- - !type:ReagentThreshold
- reagent: Frezon
- min: 1
+ minScale: 2
Poison: -1
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dylovene
min: 20
damage:
groups:
Brute: 2
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dylovene
min: 20
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dylovene
min: 20
type: Local
visualType: Medium
messages: [ "generic-reagent-effect-nauseous" ]
probability: 0.2
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dylovene
min: 20
probability: 0.02
- !type:Drunk
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dylovene
min: 15
plantMetabolism:
- !type:PlantAdjustToxins
Brute: -1.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Bicaridine
min: 15
damage:
types:
Asphyxiation: 0.5
Poison: 1.5
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Bicaridine
min: 30
probability: 0.02
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Bicaridine
min: 15
- !type:Drunk
effects:
- !type:HealthChange
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
# this is a little arbitrary but they gotta be pretty cold
max: 213.0
damage:
effects:
- !type:HealthChange
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
max: 213.0
damage:
types:
Cold: -1.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dermaline
min: 10
damage:
types:
Brute: 0.5
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dermaline
min: 10
- type: reagent
Bloodloss: -0.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Dexalin
min: 20
damage:
types:
Bloodloss: -3
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: HeartbreakerToxin
min: 1
reagent: HeartbreakerToxin
amount: -3
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: DexalinPlus
min: 25
damage:
types:
effects:
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Histamine
min: 45
reagent: Histamine
# they gotta be in crit first
- !type:MobStateCondition
mobstate: Critical
- - !type:ReagentThreshold
- min: 0
+ - !type:ReagentCondition
+ reagent: Epinephrine
max: 20
damage:
types:
Burn: -0.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Epinephrine
min: 20
damage:
types:
amount: -2
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: HeartbreakerToxin
min: 1
reagent: Epinephrine
- !type:AdjustReagent
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: HeartbreakerToxin
min: 1
reagent: Histamine
damage:
types:
Radiation: -1
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.02
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Hyronalin
min: 30
damage:
types:
Heat: 2
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Hyronalin
min: 30
- type: reagent
metabolisms:
Medicine:
effects:
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ipecac
min: 4
probability: 0.3
damage:
types:
Asphyxiation: -2
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -0.25
- type: reagent
- !type:SatiateThirst
factor: -10
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Kelotane
min: 30
- !type:PopupMessage
type: Local
- generic-reagent-effect-parched
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Kelotane
min: 25
- type: reagent
Cold: -4
- !type:AdjustTemperature
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
max: 293.15
amount: 100000 # thermal energy, not temperature!
- !type:AdjustTemperature
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
min: 293.15
amount: -10000
- !type:PopupMessage
Heat: 0.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Barozine
min: 30
damage:
types:
Poison: 3
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.15
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Barozine
min: 30
- !type:GenericStatusEffect
key: PressureImmunity
amount: 6
- !type:PlantPhalanximine
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Phalanximine
min: 4
metabolisms:
Medicine:
Caustic: 0.15
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Phalanximine
min: 11
damage:
types:
Radiation: 0.2
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Arithrazine
min: 1
damage:
Asphyxiation: -2.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: PolypyryliumOligomers
min: 30
damage:
types:
Asphyxiation: 3.5
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -0.25
- type: reagent
effects:
- !type:CureZombieInfection
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ambuzol
min: 10
- type: reagent
- !type:CureZombieInfection
innoculate: true
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: AmbuzolPlus
min: 5
- type: reagent
metabolisms:
Medicine:
effects:
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -0.5
- type: reagent
Poison: -4
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Amatoxin
min: 1
reagent: Amatoxin
effects:
# Medium-large quantities can hurt you instead,
# but still technically stop your bleeding.
- - !type:ModifyBleedAmount
+ - !type:ModifyBleed
amount: -1.5
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: TranexamicAcid
min: 15
damage:
types:
effects:
- !type:HealthChange
conditions:
- - !type:TotalDamage
+ - !type:TotalDamageCondition
max: 50
damage:
groups:
effects:
- !type:EvenHealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ultravasculine
min: 0
max: 20
damage:
Toxin: -6
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ultravasculine
min: 0
max: 20
damage:
Brute: 1.5
- !type:EvenHealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ultravasculine
min: 20
damage:
Toxin: -2
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ultravasculine
min: 20
damage:
groups:
Brute: 6
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Histamine
min: 1
reagent: Histamine
amount: -1
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Histamine
min: 1
reagent: Ultravasculine
metabolisms:
Medicine:
effects:
- - !type:ChemHealEyeDamage
+ - !type:EyeDamage
- type: reagent
id: Cognizine
effects:
- !type:MakeSentient
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Cognizine
min: 5
- type: reagent
type: Remove
- !type:ResetNarcolepsy
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ethyloxyephedrine
min: 10
- !type:PopupMessage
visualType: Medium
type: Remove
- !type:ResetNarcolepsy
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Diphenylmethylamine
min: 5
- !type:PopupMessage
visualType: Medium
Caustic: -1.25 # 5 per u
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Sigynate
min: 16
damage:
types:
Heat: 1 # 4 per u
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Sigynate
min: 20
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Sigynate
min: 20
type: Local
visualType: Medium
messages: [ "generic-reagent-effect-nauseous" ]
probability: 0.2
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Sigynate
min: 30
probability: 0.02
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Arithrazine
min: 1
probability: 0.1
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Arithrazine
min: 1
type: Local
Heat: 0.2 # 0.8 per u
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Lacerinol
min: 12
damage:
types:
Radiation: 0.05 # 0.2 per u, 3 for 15u
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Puncturase
min: 12
damage:
types:
factor: -1
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Bruizine
min: 10.5
damage:
types:
factor: 3
- !type:HealthChange
conditions:
- - !type:TotalDamage
+ - !type:TotalDamageCondition
max: 50
damage:
types:
Heat: -0.2
Shock: -0.2
Cold: -0.2
-
reactiveEffects:
Extinguish:
methods: [ Touch ]
effects:
- - !type:ExtinguishReaction
+ - !type:Extinguish
Acidic:
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
# od causes massive bleeding
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Pyrazine
min: 20
damage:
types:
Slash: 0.5
Piercing: 0.5
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Pyrazine
min: 15
probability: 0.1
- !type:Emote
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Pyrazine
min: 20
emote: Scream
probability: 0.2
# od makes you freeze to death
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Insuzine
min: 12
damage:
types:
Cold: 1 # 4 per u
- !type:AdjustTemperature
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Insuzine
min: 12
amount: -30000
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Insuzine
min: 12
- type: reagent
seconds: 20
conditions:
#Patient must be dead and in a cryo tube (or something cold)
- - !type:Temperature
+ - !type:TemperatureCondition
max: 150.0
- !type:MobStateCondition
mobstate: Dead
effects:
- !type:HealthChange
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
max: 213.0
damage:
groups:
effects:
- !type:HealthChange
conditions:
- - !type:Temperature
+ - !type:TemperatureCondition
max: 213.0
damage:
types:
effects:
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Mannitol
min: 15
type: Local
visualType: Medium
effects:
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Psicodine
min: 30
damage:
types:
- !type:ModifyStatusEffect
effectProto: StatusEffectSeeingRainbow
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Psicodine
min: 30
type: Add
time: 8
component: RadiationProtection
time: 2
type: Add
- refresh: false
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: PotassiumIodide
min: 20
damage:
types:
Poison: 0.75
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Desoxyephedrine
min: 30
damage:
types:
Asphyxiation: 2
Narcotic:
effects:
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 1.35
sprintSpeedModifier: 1.35
- !type:GenericStatusEffect
type: Remove
- !type:ModifyStatusEffect
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Haloperidol
max: 0.01
effectProto: StatusEffectDrowsiness
effects:
- !type:ResetNarcolepsy
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Desoxyephedrine
min: 20
- type: reagent
metabolisms:
Narcotic:
effects:
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 1.25
sprintSpeedModifier: 1.25
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ephedrine
min: 20
damage:
types:
type: Remove
- !type:ModifyStatusEffect
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Haloperidol
max: 0.01
effectProto: StatusEffectDrowsiness
effects:
- !type:ResetNarcolepsy
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Ephedrine
min: 30
- type: reagent
Narcotic:
metabolismRate: 1.0
effects:
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 1.3
sprintSpeedModifier: 1.3
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Stimulants
min: 80 #please wait 3 minutes before using another stimpack
damage:
types:
Poison: 1
- !type:AdjustReagent
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: ChloralHydrate
min: 1
reagent: ChloralHydrate
key: StaminaModifier
component: StaminaModifier
time: 3
- type: Add
- !type:ModifyStatusEffect
effectProto: StatusEffectForcedSleeping
time: 3
type: Remove
- !type:ModifyStatusEffect
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Haloperidol
max: 0.01
effectProto: StatusEffectDrowsiness
factor: 1
- !type:HealthChange
conditions:
- - !type:TotalDamage
+ - !type:TotalDamageCondition
min: 70 # only heals when you're more dead than alive
damage: # heals at the same rate as tricordrazine, doesn't heal poison because if you OD'd I'm not giving you a safety net
groups:
metabolisms:
Narcotic:
effects:
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 0.65
sprintSpeedModifier: 0.65
- !type:HealthChange
effectProto: StatusEffectSeeingRainbow
time: 10
type: Add
- - !type:ChemVomit # Vomiting is a symptom of brain damage
+ - !type:Vomit # Vomiting is a symptom of brain damage
probability: 0.05
- !type:Drunk # Headaches and slurring are major symptoms of brain damage, this is close enough
boozePower: 5
meltingPoint: 128.0
metabolisms:
Narcotic:
- effects:
+ effects: # It would be nice to have speech slurred or mumbly, but accents are a bit iffy atm. Same for distortion effects.
+ - !type:MovementSpeedModifier
+ walkSpeedModifier: 0.65
+ sprintSpeedModifier: 0.65
- !type:ModifyStatusEffect
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Nocturine
min: 8
effectProto: StatusEffectForcedSleeping
- time: 3
- delay: 6
- type: Add
+ time: 6
+ delay: 5
- type: reagent
id: MuteToxin
- norepinephricacid-effect-darkness
- norepinephricacid-effect-blindness
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: NorepinephricAcid
min: 20
probability: 0.03
#If anyone wants to add a light dimming or grayscale effect when under 20u, be my guest
key: TemporaryBlindness
component: TemporaryBlindness
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: NorepinephricAcid
min: 20
- type: reagent
emote: Scream
probability: 0.08
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: TearGas
min: 4
- !type:Emote
emote: Cough
key: TemporaryBlindness
component: TemporaryBlindness
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: TearGas
min: 4
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 0.65
sprintSpeedModifier: 0.65
- statusLifetime: 1.5
+ time: 1.5
conditions: # because of the remainding after effect, threshold is given so the effects ends simultaniously
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: TearGas
min: 4
- type: reagent
showInChat: true
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Happiness
max: 20
- !type:Emote
emote: Whistle
showInChat: true
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Happiness
max: 20
- !type:Emote
emote: Crying
showInChat: true
probability: 0.1
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Happiness
min: 20
- !type:PopupMessage # we dont have sanity/mood so this will have to do
type: Local
- "psicodine-effect-at-peace"
probability: 0.2
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Happiness
max: 20
- !type:ModifyStatusEffect
effectProto: StatusEffectSeeingRainbow
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
plantMetabolism:
- !type:PlantAdjustWeeds
amount: -2
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.4
metabolisms:
Poison:
Heat: 2
Poison: 1
Caustic: 0.5 # based off napalm being an irritant
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.4
- type: reagent
types:
Heat: 3
Poison: 1
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.1
- !type:AdjustTemperature
amount: 6000
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.2
- !type:Ignite
Heat: 2
Poison: 1
Caustic: 0.5 # CLF3 is corrosive
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.2
- !type:AdjustTemperature
amount: 6000
Flammable:
methods: [ Touch ]
effects:
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.3
- !type:Ignite
- !type:Emote
- !type:SatiateThirst
factor: 1
conditions:
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [Vox]
Poison:
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Vox]
+ inverted: true
damage:
types:
Poison: 1
- - !type:FlammableReaction
+ - !type:Flammable
multiplier: 0.4
- type: reagent
emote: Yawn
showInChat: true
probability: 0.1
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 0.65
sprintSpeedModifier: 0.65
- !type:ModifyStatusEffect
effectProto: StatusEffectDrowsiness
time: 4
- type: Add
+ type: Update
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: ChloralHydrate
min: 20
damage:
damage:
types:
Poison: 2
- - !type:ChemVomit
+ - !type:Vomit
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: GastroToxin
min: 2
probability: 0.2
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
- !type:SatiateThirst
factor: -1.5
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: true
damage:
types:
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
methods: [ Touch ]
effects:
- !type:HealthChange
- scaleByQuantity: true
+ scaling: true
ignoreResistances: false
damage:
types:
# todo: cough, sneeze
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Histamine
min: 45
damage:
groups:
probability: 0.1
- !type:PopupMessage
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Histamine
min: 45
type: Local
visualType: Medium
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Animal # Applying damage to the mobs with lower metabolism capabilities
+ - !type:MetabolizerTypeCondition
+ type: [Animal] # Applying damage to the mobs with lower metabolism capabilities
damage:
types:
Poison: 0.4
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.04 #Scaled for time, not metabolismrate.
conditions:
- - !type:OrganType
- type: Animal
+ - !type:MetabolizerTypeCondition
+ type: [Animal]
- type: reagent
id: Amatoxin
effects:
- !type:CauseZombieInfection
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Romerol
min: 5
- type: reagent
effects:
- !type:PopupMessage
conditions:
- - !type:OrganType
- type: Animal
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Animal, Vox ]
+ inverted: true
type: Local
visualType: MediumCaution
messages: [ "generic-reagent-effect-sick" ]
probability: 0.5
- - !type:ChemVomit
+ - !type:Vomit
probability: 0.1
conditions:
- - !type:OrganType
- type: Animal
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Animal, Vox ]
+ inverted: true
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Animal
- shouldHave: false
- - !type:OrganType
- type: Vox
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [ Animal, Vox ]
+ inverted: true
damage:
types:
Poison: 1
- !type:AdjustReagent
conditions:
- - !type:OrganType
- type: Animal
+ - !type:MetabolizerTypeCondition
+ type: [ Animal ]
reagent: Protein
amount: 0.5
- !type:AdjustReagent
conditions:
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [ Vox ]
reagent: Protein
amount: 0.25
effects:
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Allicin
min: 1
- - !type:OrganType
- type: Animal
+ - !type:MetabolizerTypeCondition
+ type: [Animal]
damage:
types:
Poison: 0.06
- !type:GenericStatusEffect
key: Pacified
component: Pacified
- type: Add
time: 4
- type: reagent
probability: 0.2
- !type:HealthChange
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Honk
min: 1
- - !type:OrganType
- type: Animal
+ - !type:MetabolizerTypeCondition
+ type: [ Animal ]
damage:
types:
Poison: 0.06
effects:
- !type:Jitter
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
+ reagent: Vestine
min: 5
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
walkSpeedModifier: 0.8
sprintSpeedModifier: 0.8
- !type:HealthChange
effects:
- !type:HealthChange
conditions:
- - !type:Hunger
+ - !type:HungerCondition
max: 50
damage:
types:
effects:
- !type:HealthChange
conditions:
- - !type:OrganType
- type: Arachnid
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Arachnid]
+ inverted: true
damage:
types:
Poison: 1.6
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Mechanotoxin
min: 2
- - !type:OrganType
- type: Arachnid
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Arachnid]
+ inverted: true
walkSpeedModifier: 0.8
sprintSpeedModifier: 0.8
- - !type:MovespeedModifier
+ - !type:MovementSpeedModifier
conditions:
- - !type:ReagentThreshold
+ - !type:ReagentCondition
reagent: Mechanotoxin
min: 4
- - !type:OrganType
- type: Arachnid
- shouldHave: false
+ - !type:MetabolizerTypeCondition
+ type: [Arachnid]
+ inverted: true
walkSpeedModifier: 0.4
sprintSpeedModifier: 0.4
- !type:SatiateHunger
factor: 1
conditions:
- - !type:OrganType
- type: Vox
+ - !type:MetabolizerTypeCondition
+ type: [Vox]
--- /dev/null
+- type: constructionGraph
+ id: HugBot
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: bot
+ steps:
+ - tag: BoxHug
+ icon:
+ sprite: Objects/Storage/boxes.rsi
+ state: box_hug
+ name: construction-graph-tag-boxhug
+ - tag: ProximitySensor
+ icon:
+ sprite: Objects/Misc/proximity_sensor.rsi
+ state: icon
+ name: construction-graph-tag-proximity-sensor
+ doAfter: 2
+ - tag: BorgArm
+ icon:
+ sprite: Mobs/Silicon/drone.rsi
+ state: l_hand
+ name: construction-graph-tag-borg-arm
+ doAfter: 2
+ - tag: BorgArm
+ icon:
+ sprite: Mobs/Silicon/drone.rsi
+ state: l_hand
+ name: construction-graph-tag-borg-arm
+ doAfter: 2
+ - node: bot
+ entity: MobHugBot
targetNode: bot
category: construction-category-utilities
objectType: Item
+
+- type: construction
+ id: hugbot
+ graph: HugBot
+ startNode: start
+ targetNode: bot
+ category: construction-category-utilities
+ objectType: Item
- BioGenLeft4Zed
- BioGenEZNutrient
- BioGenRobustHarvest
+ - BioGenDiseaseSwab
- type: latheRecipePack
id: BioGenMaterialsStatic
- BioGenMaterialCardboard1
- BioGenPaper
- BioGenPaperRolling1
+
+- type: latheRecipePack
+ id: BioGenEmagStatic
+ recipes:
+ - BioGenUnstableMutagen
- PillCanister
- HandLabeler
- BaseChemistryEmptyVial
+ - Dropper
- type: latheRecipePack
parent: BasicChemistryStatic
id: MaterialsStatic
recipes:
- SheetRGlass
+ - MaterialDurathread
- type: latheRecipePack
id: PartsStatic
- MagazineShotgun
- MagazineShotgunEmpty
- MagazineShotgunSlug
+ - MagazinePistolCaselessRifle
+ - MagazineBoxAntiMateriel
Plastic: 500
Uranium: 500
+# .25 Caseless
+- type: latheRecipe
+ parent: BaseAmmoRecipe
+ id: MagazinePistolCaselessRifle
+ result: MagazinePistolCaselessRifle
+ materials:
+ Steel: 145
+
# .30 Rifle
- type: latheRecipe
parent: BaseEmptyAmmoRecipe
Steel: 80
Plastic: 80
+# .60 anti-materiel
+- type: latheRecipe
+ parent: BaseAmmoBoxRecipe
+ id: MagazineBoxAntiMateriel
+ result: MagazineBoxAntiMateriel
+ materials:
+ Steel: 200
+
# Encampment ammo
- type: latheRecipe
id: MagazineGrenadeEmpty
materials:
Biomass: 18
+- type: latheRecipe
+ id: BioGenDiseaseSwab
+ result: DiseaseSwab
+ categories:
+ - Materials
+ completetime: 3
+ materials:
+ Biomass: 2
-
+- type: latheRecipe
+ id: BioGenUnstableMutagen
+ resultReagents:
+ UnstableMutagen: 10
+ categories:
+ - Chemicals
+ icon:
+ sprite: Objects/Specific/Chemistry/bottle.rsi
+ state: bottle-1
+ completetime: 5
+ materials:
+ Biomass: 20
result: Dropper
completetime: 2
materials:
- Glass: 200
- Plastic: 100
+ Glass: 50
+ Plastic: 50
- type: latheRecipe
id: Syringe
- type: latheRecipe
id: SheetRGlass
result: SheetRGlass1
+ applyMaterialDiscount: false # obvious dupe capabilities
completetime: 0
materials:
Glass: 100
completetime: 1
materials:
Cotton: 200 #my pyrocloth keeps catching on fire whenever I make it!
+
+- type: latheRecipe
+ id: MaterialDurathread
+ result: MaterialDurathread1
+ applyMaterialDiscount: false
+ completetime: 0
+ materials:
+ Cloth: 100
+ Plastic: 100
Potassium:
amount: 1
effects:
- - !type:ExplosionReactionEffect
+ - !type:ExplosionEffect
explosionType: Default
intensityPerUnit: 0.25
maxTotalIntensity: 100
Aluminium:
amount: 1
effects:
- - !type:EmpReactionEffect
- rangePerUnit: 0.2
+ - !type:Emp
+ rangeModifier: 0.2
maxRange: 6
energyConsumption: 12500
duration: 15
Sulfur:
amount: 1
effects:
- - !type:FlashReactionEffect
+ - !type:Flash
- type: reaction
id: TableSalt
amount: 5
catalyst: true
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodCheese
- type: reaction
amount: 5
catalyst: true
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodChevre
- type: reaction
Water:
amount: 10
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodDough
- type: reaction
Egg:
amount: 6
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodDoughCornmeal
- type: reaction
Water:
amount: 10
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodDoughTortilla
- type: reaction
Water:
amount: 10
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodDoughCotton
- type: reaction
Milk:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodCakeBatter
- type: reaction
amount: 5
catalyst: true
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodButter
- type: reaction
TableSalt:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodDoughPie
# TG has a cake recipe that uses soy milk instead of eggs.
Sugar:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodCakeBatter
- type: reaction
amount: 5
catalyst: true
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodTofu
- type: reaction
Egg:
amount: 6
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodMeatMeatball
- type: reaction
Sugar:
amount: 2
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodSnackChocolateBar
# Condiments
Carbon:
amount: 10
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: FoodMeat
- type: reaction
SulfuricAcid:
amount: 2
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SheetPlastic1
- type: reaction
Ethanol:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: ShardCrystalRandom
- type: reaction
Charcoal:
amount: 2
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: MaterialGunpowder
- type: reaction
FrostOil:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: IngotGold1
- type: reaction
FrostOil:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: IngotSilver1
- type: reaction
JuiceThatMakesYouHew:
amount: 1
effects:
- - !type:ExplosionReactionEffect
+ - !type:ExplosionEffect
explosionType: Radioactive
maxIntensity: 200
intensityPerUnit: 2
Fluorine:
amount: 3
effects:
- - !type:ExplosionReactionEffect
+ - !type:ExplosionEffect
explosionType: Default # 15 damage per intensity.
maxIntensity: 200
intensityPerUnit: 5
products:
Ethanol: 5
Hydrogen: 3
- Sulfur: 2
\ No newline at end of file
+ Sulfur: 2
TableSalt:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: Soap
- type: reaction
Plasma:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SoapNT
- type: reaction
JuiceBerry:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SoapDeluxe
- type: reaction
Blood:
amount: 10
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SoapHomemade
- type: reaction
Stimulants:
amount: 5
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SoapSyndie
- type: reaction
Amatoxin:
amount: 1
effects:
- - !type:CreateEntityReactionEffect
+ - !type:SpawnEntity
entity: SoapOmega
+++ /dev/null
-- type: stack
- id: Telecrystal
- name: stack-telecrystal
- icon: Objects/Specific/Syndicate/telecrystal.rsi
- spawn: Telecrystal1
+++ /dev/null
-- type: stack
- id: Gold
- name: stack-gold
- icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: gold }
- spawn: IngotGold1
- maxCount: 30
-
-- type: stack
- id: Silver
- name: stack-silver
- icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: silver }
- spawn: IngotSilver1
- maxCount: 30
+++ /dev/null
-- type: stack
- id: Biomass
- name: stack-biomass
- icon: { sprite: /Textures/Objects/Misc/monkeycube.rsi, state: cube }
- spawn: MaterialBiomass1
- maxCount: 100
-
-- type: stack
- id: WoodPlank
- name: stack-wood-plank
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: wood }
- spawn: MaterialWoodPlank1
- maxCount: 30
-
-- type: stack
- id: Cardboard
- name: stack-cardboard
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cardboard }
- spawn: MaterialCardboard1
- maxCount: 30
-
-- type: stack
- id: Cloth
- name: stack-cloth
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cloth }
- spawn: MaterialCloth1
- maxCount: 30
-
-- type: stack
- id: Durathread
- name: stack-durathread
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: durathread }
- spawn: MaterialDurathread1
- maxCount: 30
-
-- type: stack
- id: Diamond
- name: stack-diamond
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: diamond }
- spawn: MaterialDiamond1
- maxCount: 30
-
-- type: stack
- id: Cotton
- name: stack-cotton
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cotton }
- spawn: MaterialCotton1
- maxCount: 30
-
-- type: stack
- id: Pyrotton
- name: stack-pyrotton
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: pyrotton }
- spawn: MaterialPyrotton1
- maxCount: 30
-
-- type: stack
- id: Bananium
- name: stack-bananium
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bananium }
- spawn: MaterialBananium1
- maxCount: 10
-
-- type: stack
- id: MeatSheets
- name: stack-meat-sheet
- icon: { sprite: /Textures/Objects/Materials/Sheets/meaterial.rsi, state: meat }
- spawn: MaterialSheetMeat1
- maxCount: 30
-
-- type: stack
- id: WebSilk
- name: stack-silk
- icon: { sprite: /Textures/Objects/Materials/silk.rsi, state: icon }
- spawn: MaterialWebSilk1
- maxCount: 50
-
-- type: stack
- id: SpaceCarpTooth
- name: stack-space-carp-tooth
- icon: { sprite: /Textures/Objects/Materials/Mob/carptooth.rsi, state: tooth }
- spawn: MaterialToothSpaceCarp1
- maxCount: 30
-
-- type: stack
- id: SharkMinnowTooth
- name: stack-sharkminnow-tooth
- icon: { sprite: /Textures/Objects/Materials/Mob/sharktooth.rsi, state: tooth }
- spawn: MaterialToothSharkminnow1
- maxCount: 30
-
-- type: stack
- id: Bones
- name: stack-bones
- icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bones }
- spawn: MaterialBones1
- maxCount: 30
-
-- type: stack
- id: Gunpowder
- name: stack-gunpowder
- icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
- spawn: MaterialGunpowder
- maxCount: 60
-
-- type: stack
- id: GoliathHide
- name: stack-goliath-hide
- icon: { sprite: /Textures/Objects/Materials/hide.rsi, state: goliath_hide }
- spawn: MaterialGoliathHide1
- maxCount: 30
+++ /dev/null
-- type: stack
- id: MetalRod
- name: stack-rods
- icon: { sprite: /Textures/Objects/Materials/parts.rsi, state: rods }
- spawn: PartRodMetal1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Glass
name: stack-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: glass }
spawn: SheetGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: ReinforcedGlass
name: stack-reinforced-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: rglass }
spawn: SheetRGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: PlasmaGlass
name: stack-plasma-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: pglass }
spawn: SheetPGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: ReinforcedPlasmaGlass
name: stack-reinforced-plasma-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: rpglass }
spawn: SheetRPGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: UraniumGlass
name: stack-uranium-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: uglass }
spawn: SheetUGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: ReinforcedUraniumGlass
name: stack-reinforced-uranium-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: ruglass }
spawn: SheetRUGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: ClockworkGlass
name: stack-clockwork-glass
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: cglass }
spawn: SheetClockworkGlass1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Steel
name: stack-steel
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: steel }
spawn: SheetSteel1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Plasteel
name: stack-plasteel
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: plasteel }
spawn: SheetPlasteel1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Brass
name: stack-brass
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: brass }
spawn: SheetBrass1
- maxCount: 30
--- /dev/null
+- type: stack
+ parent: BaseSheetStack
+ id: Paper
+ name: stack-paper
+ icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: paper }
+ spawn: SheetPaper1
+
+- type: stack
+ parent: BaseSheetStack
+ id: MeatSheets
+ name: stack-meat-sheet
+ icon: { sprite: /Textures/Objects/Materials/Sheets/meaterial.rsi, state: meat }
+ spawn: MaterialSheetMeat1
- type: stack
- id: Paper
- name: stack-paper
- icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: paper }
- spawn: SheetPaper1
- maxCount: 30
-
-- type: stack
+ parent: BaseSheetStack
id: Plasma
name: stack-plasma
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: plasma }
spawn: SheetPlasma1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Plastic
name: stack-plastic
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: plastic }
spawn: SheetPlastic1
- maxCount: 30
- type: stack
+ parent: BaseSheetStack
id: Uranium
name: stack-uranium
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: uranium }
spawn: SheetUranium1
- maxCount: 30
--- /dev/null
+# they're uninflated by default so they're tiny
+- type: stack
+ parent: BaseSmallStack
+ id: InflatableWall
+ name: stack-inflatable-wall
+ icon: { sprite: "/Textures/Objects/Misc/inflatable_wall.rsi", state: item_wall }
+ spawn: InflatableWallStack1
+
+- type: stack
+ id: InflatableDoor
+ name: stack-inflatable-door
+ icon: { sprite: "/Textures/Objects/Misc/inflatable_door.rsi", state: item_door }
+ spawn: InflatableDoorStack1
+ maxCount: 4 # Maybe increased to 5 to reuse the base?
+
+# Cables
+- type: stack
+ parent: BaseMediumStack
+ id: Cable
+ name: stack-lv-cable
+ icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coil-30 }
+ spawn: CableApcStack1
+
+- type: stack
+ parent: BaseMediumStack
+ id: CableMV
+ name: stack-mv-cable
+ icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilmv-30 }
+ spawn: CableMVStack1
+
+- type: stack
+ parent: BaseMediumStack
+ id: CableHV
+ name: stack-hv-cable
+ icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilhv-30 }
+ spawn: CableHVStack1
+# Topical medicines
+
- type: stack
+ parent: BaseSmallStack
id: Ointment
name: stack-ointment
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: ointment }
spawn: Ointment
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: AloeCream
name: stack-aloe-cream
icon: { sprite: "/Textures/Objects/Specific/Hydroponics/aloe.rsi", state: cream }
spawn: AloeCream
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: Gauze
name: stack-gauze
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze }
spawn: Gauze
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: Brutepack
name: stack-brutepack
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze }
spawn: Brutepack
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: Bloodpack
name: stack-bloodpack
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: bloodpack }
spawn: Bloodpack
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: MedicatedSuture
name: stack-medicated-suture
icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: medicated-suture }
spawn: MedicatedSuture
- maxCount: 10
- type: stack
+ parent: BaseSmallStack
id: RegenerativeMesh
name: stack-regenerative-mesh
icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: regenerative-mesh}
spawn: RegenerativeMesh
- maxCount: 10
- type: stack
+ parent: BaseMediumStack
id: ArtifactFragment
name: stack-artifact-fragment
+ icon: { sprite: /Textures/Objects/Specific/Xenoarchaeology/artifact_fragments.rsi, state: martianball1 }
spawn: ArtifactFragment1
- maxCount: 30
-
- type: stack
+ parent: BaseSmallStack
id: Manipulator
name: stack-micro-manipulator
icon: { sprite: /Textures/Objects/Misc/stock_parts.rsi, state: micro_mani }
spawn: MicroManipulatorStockPart
- maxCount: 10
--- /dev/null
+- type: stack
+ parent: BaseMediumStack
+ id: CableDet
+ name: stack-explosive-cord
+ icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilex-30 }
+ spawn: CableDetStack1
--- /dev/null
+# Tiles you might find in an alien world
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileXenoborg
+ name: stack-xenoborg
+ spawn: FloorTileItemXenoborg
+
+# Exo station
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileXeno
+ name: stack-xeno-floor
+ spawn: FloorTileItemXeno
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileXenoSteel
+ name: stack-xeno-steel
+ spawn: FloorTileItemXenoSteelCorner
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileXenoSteelCorner
+ name: stack-xeno-steel-corner
+ spawn: FloorTileItemXenoSteelCorner
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileXenoMaint
+ name: stack-xeno-maint
+ spawn: FloorTileItemXenoSteelCorner
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkSquiggly
+ name: stack-dark-squiggly
+ spawn: FloorTileItemDarkSquiggly
--- /dev/null
+# Tiles made of brass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileBrassFilled
+ name: stack-filled-brass-plate
+ spawn: FloorTileItemBrassFilled
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileBrassReebe
+ name: stack-smooth-brass-plate
+ spawn: FloorTileItemBrassReebe
--- /dev/null
+# Carpets that are tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackCarpetClown
+ name: stack-clown-carpet-tile
+ spawn: FloorTileItemCarpetClown
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackCarpetOffice
+ name: stack-office-carpet-tile
+ spawn: FloorTileItemCarpetOffice
+
+# Carpets that are not actually tiles (yet)
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetRed
+ name: stack-red-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-red }
+ spawn: FloorCarpetItemRed
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetBlack
+ name: stack-black-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-black }
+ spawn: FloorCarpetItemBlack
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetBlue
+ name: stack-blue-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-blue }
+ spawn: FloorCarpetItemBlue
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetGreen
+ name: stack-green-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-green }
+ spawn: FloorCarpetItemGreen
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetOrange
+ name: stack-orange-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-orange }
+ spawn: FloorCarpetItemOrange
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetSkyBlue
+ name: stack-skyblue-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-skyblue }
+ spawn: FloorCarpetItemSkyBlue
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetPurple
+ name: stack-purple-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-purple }
+ spawn: FloorCarpetItemPurple
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetPink
+ name: stack-pink-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-pink }
+ spawn: FloorCarpetItemPink
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetCyan
+ name: stack-cyan-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-cyan }
+ spawn: FloorCarpetItemCyan
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorCarpetWhite
+ name: stack-white-carpet-tile
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: carpet-white }
+ spawn: FloorCarpetItemWhite
--- /dev/null
+# Tiles made of concrete
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileConcrete
+ name: stack-concrete-tile
+ spawn: FloorTileItemGrayConcrete
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileConcreteMono
+ name: stack-concrete-mono-tile
+ spawn: FloorTileItemConcreteMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileConcreteSmooth
+ name: stack-concrete-smooth
+ spawn: FloorTileItemConcreteSmooth
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGrayConcrete
+ name: stack-gray-concrete-tile
+ spawn: FloorTileItemGrayConcrete
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGrayConcreteMono
+ name: stack-gray-concrete-mono-tile
+ spawn: FloorTileItemGrayConcreteMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGrayConcreteSmooth
+ name: stack-gray-concrete-smooth
+ spawn: FloorTileItemGrayConcreteSmooth
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileOldConcrete
+ name: stack-old-concrete-tile
+ spawn: FloorTileItemOldConcrete
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileOldConcreteMono
+ name: stack-old-concrete-mono-tile
+ spawn: FloorTileItemOldConcreteMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileOldConcreteSmooth
+ name: stack-old-concrete-smooth
+ spawn: FloorTileItemOldConcreteSmooth
--- /dev/null
+# electronic or computery looking tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGCircuit
+ name: stack-green-circuit-floor
+ spawn: FloorTileItemGCircuit
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileBCircuit
+ name: stack-bcircuit-floor-tile
+ spawn: FloorTileItemBCircuit
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileRCircuit
+ name: stack-red-circuit-floor
+ spawn: FloorTileItemRCircuit
--- /dev/null
+# expensive looking tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGold
+ name: stack-gold-floor
+ spawn: FloorTileItemGold
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSilver
+ name: stack-silver-floor-tile
+ spawn: FloorTileItemSilver
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteMarble
+ name: stack-white-marble-floor
+ spawn: FloorTileItemWhiteMarble
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkMarble
+ name: stack-dark-marble-floor
+ spawn: FloorTileItemDarkMarble
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTilePlasmaMarble
+ name: stack-plasma-marble-floor
+ spawn: FloorTileItemPlasmaMarble
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileUraniumMarble
+ name: stack-uranium-marble-floor
+ spawn: FloorTileItemUraniumMarble
--- /dev/null
+# Faux tiles that mimic planet terrain
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileAstroGrass
+ name: stack-astro-grass-floor
+ spawn: FloorTileItemAstroGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMowedAstroGrass
+ name: stack-mowed-astro-grass-floor
+ spawn: FloorTileItemMowedAstroGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileJungleAstroGrass
+ name: stack-jungle-astro-grass-floor
+ spawn: FloorTileItemJungleAstroGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkAstroGrass
+ name: stack-dark-astro-grass-floor
+ spawn: FloorTileItemDarkAstroGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileLightAstroGrass
+ name: stack-light-astro-grass-floor
+ spawn: FloorTileItemLightAstroGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileAstroIce
+ name: stack-astro-ice-floor
+ spawn: FloorTileItemAstroIce
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileAstroSnow
+ name: stack-astro-snow-floor
+ spawn: FloorTileItemAstroSnow
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileAstroAsteroidSand
+ name: stack-asteroid-astro-sand-floor
+ spawn: FloorTileItemAstroAsteroidSand
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDesertAstroSand
+ name: stack-desert-astro-sand-floor
+ spawn: FloorTileItemDesertAstroSand
--- /dev/null
+# Tiles in a 4 square pattern
+
+# Single color
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileFreezer
+ name: stack-freezer-tile
+ spawn: FloorTileItemFreezer
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileShowroom
+ name: stack-showroom-tile
+ spawn: FloorTileItemShowroom
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileHydro
+ name: stack-hydro-tile
+ spawn: FloorTileItemHydro
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileLime
+ name: stack-lime-tile
+ spawn: FloorTileItemLime
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDirty
+ name: stack-dirty-tile
+ spawn: FloorTileItemDirty
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileBlue
+ name: stack-blue-floor-tile
+ spawn: FloorTileItemBlue
+
+# Two color
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelCheckerDark
+ name: stack-steel-dark-checker-tile
+ spawn: FloorTileItemSteelCheckerDark
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelCheckerLight
+ name: stack-steel-light-checker-tile
+ spawn: FloorTileItemSteelCheckerLight
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileBar
+ name: stack-item-bar-floor-tile
+ spawn: FloorTileItemBar
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileClown
+ name: stack-clown-floor-tile
+ spawn: FloorTileItemClown
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMime
+ name: stack-mime-floor-tile
+ spawn: FloorTileItemMime
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileKitchen
+ name: stack-kitchen-floor-tile
+ spawn: FloorTileItemKitchen
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileLaundry
+ name: stack-laundry-floor-tile
+ spawn: FloorTileItemLaundry
+
+# Patterned
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileElevatorShaft
+ name: stack-elevator-shaft-tile
+ spawn: FloorTileItemElevatorShaft
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileRockVault
+ name: stack-rock-vault-tile
+ spawn: FloorTileItemRockVault
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMining
+ name: stack-mining-floor-tile
+ spawn: FloorTileItemMining
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMiningDark
+ name: stack-dark-mining-floor-tile
+ spawn: FloorTileItemMiningDark
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMiningLight
+ name: stack-light-mining-floor-tile
+ spawn: FloorTileItemMiningLight
--- /dev/null
+# tiles typically found in maintenance
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileTechmaint
+ name: stack-techmaint-floor
+ spawn: FloorTileItemTechmaint
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelMaint
+ name: stack-steel-maint-floor
+ spawn: FloorTileItemSteelMaint
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGratingMaint
+ name: stack-grating-maint-floor
+ spawn: FloorTileItemGratingMaint
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileTechmaintDark
+ name: stack-techmaint-floor-dark
+ spawn: FloorTileItemTechmaintDark
--- /dev/null
+# tiles that are fleshy or come from a creature
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileFlesh
+ name: stack-flesh-floor
+ spawn: FloorTileItemFlesh
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWeb
+ name: stack-web-tile
+ spawn: FloorTileItemWeb
--- /dev/null
+# Tiles that don't fit cleanly in another category
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMono
+ name: stack-mono-tile
+ spawn: FloorTileItemMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileMetalDiamond
+ name: stack-steel-tile
+ spawn: FloorTileItemMetalDiamond
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackBoxing
+ name: stack-boxing-ring-tile
+ spawn: FloorTileItemBoxing
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackGym
+ name: stack-gym-floor-tile
+ spawn: FloorTileItemGym
--- /dev/null
+# tiles that spawn on planets and are generally unobtainable
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGrass
+ name: stack-grass-floor-tile
+ spawn: FloorTileItemGrass
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileGrassJungle
+ name: stack-grass-jungle-floor-tile
+ spawn: FloorTileItemGrassJungle
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSnow
+ name: stack-snow-floor-tile
+ spawn: FloorTileItemSnow
--- /dev/null
+# Tiles that come straight from the eighties
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileLino
+ name: stack-linoleum-floor
+ spawn: FloorTileItemLino
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackEighties
+ name: stack-eighties-floor-tile
+ spawn: FloorTileItemEighties
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackArcadeBlue
+ name: stack-blue-arcade-tile
+ spawn: FloorTileItemArcadeBlue
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackArcadeBlue2
+ name: stack-blue-arcade-tile
+ spawn: FloorTileItemArcadeBlue2
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackArcadeRed
+ name: stack-red-arcade-tile
+ spawn: FloorTileItemArcadeRed
--- /dev/null
+# Tiles found on shuttles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleWhite
+ name: stack-white-shuttle-tile
+ spawn: FloorTileItemShuttleWhite
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleBlue
+ name: stack-blue-shuttle-tile
+ spawn: FloorTileItemShuttleBlue
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleOrange
+ name: stack-orange-shuttle-tile
+ spawn: FloorTileItemShuttleOrange
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttlePurple
+ name: stack-purple-shuttle-tile
+ spawn: FloorTileItemShuttlePurple
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleRed
+ name: stack-red-shuttle-tile
+ spawn: FloorTileItemShuttleRed
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleGrey
+ name: stack-grey-shuttle-tile
+ spawn: FloorTileItemShuttleGrey
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileStackShuttleBlack
+ name: stack-black-shuttle-tile
+ spawn: FloorTileItemShuttleBlack
--- /dev/null
+# Regular steel tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteel
+ name: stack-steel-tile
+ spawn: FloorTileItemSteel
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelOffset
+ name: stack-offset-steel-tile
+ spawn: FloorTileItemSteelOffset
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelDiagonalMini
+ name: stack-steel-diagonal-mini-tile
+ spawn: FloorTileItemSteelDiagonalMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelDiagonal
+ name: stack-steel-diagonal-tile
+ spawn: FloorTileItemSteelDiagonal
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelHerringbone
+ name: stack-steel-herringbone
+ spawn: FloorTileItemSteelHerringbone
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelMini
+ name: stack-steel-mini-tile
+ spawn: FloorTileItemSteelMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelMono
+ name: stack-steel-mono-tile
+ spawn: FloorTileItemSteelMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelPavement
+ name: stack-steel-pavement
+ spawn: FloorTileItemSteelPavement
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileSteelPavementVertical
+ name: stack-steel-vertical-pavement
+ spawn: FloorTileItemSteelPavementVertical
--- /dev/null
+# Dark steel tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDark
+ name: stack-dark-tile
+ spawn: FloorTileItemDark
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkDiagonalMini
+ name: stack-dark-steel-diagonal-mini-tile
+ spawn: FloorTileItemDarkDiagonalMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkDiagonal
+ name: stack-dark-steel-diagonal-tile
+ spawn: FloorTileItemDarkDiagonal
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkHerringbone
+ name: stack-dark-steel-herringbone
+ spawn: FloorTileItemDarkHerringbone
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkMini
+ name: stack-dark-steel-mini-tile
+ spawn: FloorTileItemDarkMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkMono
+ name: stack-dark-steel-mono-tile
+ spawn: FloorTileItemDarkMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkPavement
+ name: stack-dark-steel-pavement
+ spawn: FloorTileItemDarkPavement
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkPavementVertical
+ name: stack-dark-steel-vertical-pavement
+ spawn: FloorTileItemDarkPavementVertical
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileDarkOffset
+ name: stack-offset-dark-steel-tile
+ spawn: FloorTileItemDarkOffset
--- /dev/null
+# White steel tiles
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhite
+ name: stack-white-tile
+ spawn: FloorTileItemWhite
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteOffset
+ name: stack-offset-white-steel-tile
+ spawn: FloorTileItemWhiteOffset
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteDiagonalMini
+ name: stack-white-steel-diagonal-mini-tile
+ spawn: FloorTileItemWhiteDiagonalMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteDiagonal
+ name: stack-white-steel-diagonal-tile
+ spawn: FloorTileItemWhiteDiagonal
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteHerringbone
+ name: stack-white-steel-herringbone
+ spawn: FloorTileItemWhiteHerringbone
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteMini
+ name: stack-white-steel-mini-tile
+ spawn: FloorTileItemWhiteMini
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhiteMono
+ name: stack-white-steel-mono-tile
+ spawn: FloorTileItemWhiteMono
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhitePavement
+ name: stack-white-steel-pavement
+ spawn: FloorTileItemWhitePavement
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWhitePavementVertical
+ name: stack-white-steel-vertical-pavement
+ spawn: FloorTileItemWhitePavementVertical
--- /dev/null
+# Tiles that are cut wood flooring
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWood
+ name: stack-wood-floor
+ spawn: FloorTileItemWood
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWoodPattern
+ name: stack-wood-patter-floor
+ spawn: FloorTileItemWoodPattern
+
+- type: stack
+ parent: BaseTileStack
+ id: FloorTileWoodLarge
+ name: stack-large-wood-floor
+ spawn: FloorTileItemWoodLarge
--- /dev/null
+# Base sizes for stacks in one convenient place
+
+# size used by powders and smokeables
+- type: stack
+ abstract: true
+ id: BaseVerySmallStack
+ maxCount: 5
+
+# size used by topicals and machine parts
+- type: stack
+ abstract: true
+ id: BaseSmallStack
+ maxCount: 10
+
+# Default size
+- type: stack
+ abstract: true
+ id: BaseMediumStack
+ maxCount: 30
+
+- type: stack
+ abstract: true
+ id: BaseLargeStack
+ maxCount: 50
+
+- type: stack
+ abstract: true
+ id: BaseVeryLargeStack
+ maxCount: 100
+
+# size used by "sheets." Usually materials like steel, glass, or plasma
+- type: stack
+ abstract: true
+ id: BaseSheetStack
+ maxCount: 30
+
+# Used by tiles
+- type: stack
+ abstract: true
+ id: BaseTileStack
+ icon: { sprite: /Textures/Objects/Tiles/tile.rsi, state: steel }
+ maxCount: 30
--- /dev/null
+- type: stack
+ parent: BaseMediumStack
+ id: Cloth
+ name: stack-cloth
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cloth }
+ spawn: MaterialCloth1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Durathread
+ name: stack-durathread
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: durathread }
+ spawn: MaterialDurathread1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Cotton
+ name: stack-cotton
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cotton }
+ spawn: MaterialCotton1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Pyrotton
+ name: stack-pyrotton
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: pyrotton }
+ spawn: MaterialPyrotton1
- type: stack
id: Pancake
name: stack-pancake
+ icon: { sprite: /Textures/Objects/Consumable/Food/Baked/misc.rsi, state: pancakes1 }
spawn: FoodBakedPancake
maxCount: 9
- type: stack
id: PancakeBb
name: stack-blueberry-pancake
+ icon: { sprite: /Textures/Objects/Consumable/Food/Baked/misc.rsi, state: pancakesbb1 }
spawn: FoodBakedPancakeBb
maxCount: 9
- type: stack
id: PancakeCc
name: stack-chocolate-chip-pancake
+ icon: { sprite: /Textures/Objects/Consumable/Food/Baked/misc.rsi, state: pancakescc1 }
spawn: FoodBakedPancakeCc
maxCount: 9
-# Food Containers
-
-- type: stack
- id: PizzaBox
- name: stack-pizza-box
- icon: { sprite: Objects/Consumable/Food/Baked/pizza.rsi, state: box }
- spawn: FoodBoxPizza
- maxCount: 30
-
# Smokeables
- type: stack
+ parent: BaseVerySmallStack
id: PaperRolling
name: stack-rolling-paper
icon: { sprite: /Textures/Objects/Consumable/Smokeables/Cigarettes/paper.rsi, state: cigpaper }
spawn: PaperRolling
- maxCount: 5
- type: stack
+ parent: BaseVerySmallStack
id: CigaretteFilter
name: stack-cigarette-filter
icon: { sprite: /Textures/Objects/Consumable/Smokeables/Cigarettes/paper.rsi, state: cigfilter }
spawn: CigaretteFilter
- maxCount: 5
- type: stack
+ parent: BaseVerySmallStack
id: GroundTobacco
name: stack-ground-tobacco
icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
spawn: GroundTobacco
- maxCount: 5
- type: stack
+ parent: BaseVerySmallStack
id: GroundCannabis
name: stack-ground-cannabis
icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
spawn: GroundCannabis
- maxCount:
- type: stack
+ parent: BaseVerySmallStack
id: GroundCannabisRainbow
name: stack-ground-rainbow-cannabis
icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: powderpile_rainbow }
spawn: GroundCannabisRainbow
- maxCount:
- type: stack
+ parent: BaseVerySmallStack
id: LeavesTobaccoDried
name: stack-dried-tobacco-leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/tobacco.rsi, state: dried }
spawn: LeavesTobaccoDried
- maxCount: 5
- type: stack
+ parent: BaseVerySmallStack
id: LeavesCannabisDried
name: stack-dried-cannabis-leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/tobacco.rsi, state: dried }
spawn: LeavesCannabisDried
- maxCount: 5
- type: stack
+ parent: BaseVerySmallStack
id: LeavesCannabisRainbowDried
name: stack-dried-rainbow-cannabis-leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: dried }
--- /dev/null
+- type: stack
+ id: Telecrystal
+ name: stack-telecrystal
+ icon: { sprite: /Textures/Objects/Specific/Syndicate/telecrystal.rsi, state: telecrystal }
+ spawn: Telecrystal1
+
+- type: stack
+ id: Credit
+ name: stack-credit
+ icon: { sprite: /Textures/Objects/Economy/cash.rsi, state: cash }
+ spawn: SpaceCash
+++ /dev/null
-# they're uninflated by default so they're tiny
-- type: stack
- id: InflatableWall
- name: stack-inflatable-wall
- spawn: InflatableWallStack1
- maxCount: 10
-
-- type: stack
- id: InflatableDoor
- name: stack-inflatable-door
- spawn: InflatableDoorStack1
- maxCount: 4
+++ /dev/null
-- type: stack
- id: FloorTileDark
- name: stack-dark-tile
- spawn: FloorTileItemDark
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkDiagonalMini
- name: stack-dark-steel-diagonal-mini-tile
- spawn: FloorTileItemDarkDiagonalMini
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkDiagonal
- name: stack-dark-steel-diagonal-tile
- spawn: FloorTileItemDarkDiagonal
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkHerringbone
- name: stack-dark-steel-herringbone
- spawn: FloorTileItemDarkHerringbone
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkMini
- name: stack-dark-steel-mini-tile
- spawn: FloorTileItemDarkMini
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkMono
- name: stack-dark-steel-mono-tile
- spawn: FloorTileItemDarkMono
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkPavement
- name: stack-dark-steel-pavement
- spawn: FloorTileItemDarkPavement
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkPavementVertical
- name: stack-dark-steel-vertical-pavement
- spawn: FloorTileItemDarkPavementVertical
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkOffset
- name: stack-offset-dark-steel-tile
- spawn: FloorTileItemDarkOffset
- maxCount: 30
-
-- type: stack
- id: FloorTileSteel
- name: stack-steel-tile
- spawn: FloorTileItemSteel
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelOffset
- name: stack-offset-steel-tile
- spawn: FloorTileItemSteelOffset
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelDiagonalMini
- name: stack-steel-diagonal-mini-tile
- spawn: FloorTileItemSteelDiagonalMini
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelDiagonal
- name: stack-steel-diagonal-tile
- spawn: FloorTileItemSteelDiagonal
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelHerringbone
- name: stack-steel-herringbone
- spawn: FloorTileItemSteelHerringbone
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelMini
- name: stack-steel-mini-tile
- spawn: FloorTileItemSteelMini
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelMono
- name: stack-steel-mono-tile
- spawn: FloorTileItemSteelMono
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelPavement
- name: stack-steel-pavement
- spawn: FloorTileItemSteelPavement
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelPavementVertical
- name: stack-steel-vertical-pavement
- spawn: FloorTileItemSteelPavementVertical
- maxCount: 30
-
-- type: stack
- id: FloorTileWhite
- name: stack-white-tile
- spawn: FloorTileItemWhite
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteOffset
- name: stack-offset-white-steel-tile
- spawn: FloorTileItemWhiteOffset
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteDiagonalMini
- name: stack-white-steel-diagonal-mini-tile
- spawn: FloorTileItemWhiteDiagonalMini
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteDiagonal
- name: stack-white-steel-diagonal-tile
- spawn: FloorTileItemWhiteDiagonal
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteHerringbone
- name: stack-white-steel-herringbone
- spawn: FloorTileItemWhiteHerringbone
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteMini
- name: stack-white-steel-mini-tile
- spawn: FloorTileItemWhiteMini
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteMono
- name: stack-white-steel-mono-tile
- spawn: FloorTileItemWhiteMono
- maxCount: 30
-
-- type: stack
- id: FloorTileWhitePavement
- name: stack-white-steel-pavement
- spawn: FloorTileItemWhitePavement
- maxCount: 30
-
-- type: stack
- id: FloorTileWhitePavementVertical
- name: stack-white-steel-vertical-pavement
- spawn: FloorTileItemWhitePavementVertical
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelCheckerDark
- name: stack-steel-dark-checker-tile
- spawn: FloorTileItemSteelCheckerDark
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelCheckerLight
- name: stack-steel-light-checker-tile
- spawn: FloorTileItemSteelCheckerLight
- maxCount: 30
-
-- type: stack
- id: FloorTileMetalDiamond
- name: stack-steel-tile
- spawn: FloorTileItemMetalDiamond
- maxCount: 30
-
-- type: stack
- id: FloorTileWood
- name: stack-wood-floor
- spawn: FloorTileItemWood
- maxCount: 30
-
-- type: stack
- id: FloorTileTechmaint
- name: stack-techmaint-floor
- spawn: FloorTileItemTechmaint
- maxCount: 30
-
-- type: stack
- id: FloorTileTechmaintDark
- name: stack-techmaint-floor-dark
- spawn: FloorTileItemTechmaintDark
- maxCount: 30
-
-- type: stack
- id: FloorTileFreezer
- name: stack-freezer-tile
- spawn: FloorTileItemFreezer
- maxCount: 30
-
-- type: stack
- id: FloorTileShowroom
- name: stack-showroom-tile
- spawn: FloorTileItemShowroom
- maxCount: 30
-
-- type: stack
- id: FloorTileGCircuit
- name: stack-green-circuit-floor
- spawn: FloorTileItemGCircuit
- maxCount: 30
-
-- type: stack
- id: FloorTileGold
- name: stack-gold-floor
- spawn: FloorTileItemGold
- maxCount: 30
-
-- type: stack
- id: FloorTileMono
- name: stack-mono-tile
- spawn: FloorTileItemMono
- maxCount: 30
-
-- type: stack
- id: FloorTileBrassFilled
- name: stack-filled-brass-plate
- spawn: FloorTileItemBrassFilled
- maxCount: 30
-
-- type: stack
- id: FloorTileBrassReebe
- name: stack-smooth-brass-plate
- spawn: FloorTileItemBrassReebe
- maxCount: 30
-
-- type: stack
- id: FloorTileLino
- name: stack-linoleum-floor
- spawn: FloorTileItemLino
- maxCount: 30
-
-- type: stack
- id: FloorTileHydro
- name: stack-hydro-tile
- spawn: FloorTileItemHydro
- maxCount: 30
-
-- type: stack
- id: FloorTileLime
- name: stack-lime-tile
- spawn: FloorTileItemLime
- maxCount: 30
-
-- type: stack
- id: FloorTileDirty
- name: stack-dirty-tile
- spawn: FloorTileItemDirty
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleWhite
- name: stack-white-shuttle-tile
- spawn: FloorTileItemShuttleWhite
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleBlue
- name: stack-blue-shuttle-tile
- spawn: FloorTileItemShuttleBlue
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleOrange
- name: stack-orange-shuttle-tile
- spawn: FloorTileItemShuttleOrange
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttlePurple
- name: stack-purple-shuttle-tile
- spawn: FloorTileItemShuttlePurple
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleRed
- name: stack-red-shuttle-tile
- spawn: FloorTileItemShuttleRed
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleGrey
- name: stack-grey-shuttle-tile
- spawn: FloorTileItemShuttleGrey
- maxCount: 30
-
-- type: stack
- id: FloorTileStackShuttleBlack
- name: stack-black-shuttle-tile
- spawn: FloorTileItemShuttleBlack
- maxCount: 30
-
-- type: stack
- id: FloorTileStackEighties
- name: stack-eighties-floor-tile
- spawn: FloorTileItemEighties
- maxCount: 30
-
-- type: stack
- id: FloorTileStackArcadeBlue
- name: stack-blue-arcade-tile
- spawn: FloorTileItemArcadeBlue
- maxCount: 30
-
-- type: stack
- id: FloorTileStackArcadeBlue2
- name: stack-blue-arcade-tile
- spawn: FloorTileItemArcadeBlue2
- maxCount: 30
-
-- type: stack
- id: FloorTileStackArcadeRed
- name: stack-red-arcade-tile
- spawn: FloorTileItemArcadeRed
- maxCount: 30
-
-- type: stack
- id: FloorCarpetRed
- name: stack-red-carpet-tile
- spawn: FloorCarpetItemRed
- maxCount: 30
-
-- type: stack
- id: FloorCarpetBlack
- name: stack-black-carpet-tile
- spawn: FloorCarpetItemBlack
- maxCount: 30
-
-- type: stack
- id: FloorCarpetBlue
- name: stack-blue-carpet-tile
- spawn: FloorCarpetItemBlue
- maxCount: 30
-
-- type: stack
- id: FloorCarpetGreen
- name: stack-green-carpet-tile
- spawn: FloorCarpetItemGreen
- maxCount: 30
-
-- type: stack
- id: FloorCarpetOrange
- name: stack-orange-carpet-tile
- spawn: FloorCarpetItemOrange
- maxCount: 30
-
-- type: stack
- id: FloorCarpetSkyBlue
- name: stack-skyblue-carpet-tile
- spawn: FloorCarpetItemSkyBlue
- maxCount: 30
-
-- type: stack
- id: FloorCarpetPurple
- name: stack-purple-carpet-tile
- spawn: FloorCarpetItemPurple
- maxCount: 30
-
-- type: stack
- id: FloorCarpetPink
- name: stack-pink-carpet-tile
- spawn: FloorCarpetItemPink
- maxCount: 30
-
-- type: stack
- id: FloorCarpetCyan
- name: stack-cyan-carpet-tile
- spawn: FloorCarpetItemCyan
- maxCount: 30
-
-- type: stack
- id: FloorCarpetWhite
- name: stack-white-carpet-tile
- spawn: FloorCarpetItemWhite
- maxCount: 30
-
-- type: stack
- id: FloorTileStackCarpetClown
- name: stack-clown-carpet-tile
- spawn: FloorTileItemCarpetClown
- maxCount: 30
-
-- type: stack
- id: FloorTileStackCarpetOffice
- name: stack-office-carpet-tile
- spawn: FloorTileItemCarpetOffice
- maxCount: 30
-
-- type: stack
- id: FloorTileStackBoxing
- name: stack-boxing-ring-tile
- spawn: FloorTileItemBoxing
- maxCount: 30
-
-- type: stack
- id: FloorTileStackGym
- name: stack-gym-floor-tile
- spawn: FloorTileItemGym
- maxCount: 30
-
-- type: stack
- id: FloorTileElevatorShaft
- name: stack-elevator-shaft-tile
- spawn: FloorTileItemElevatorShaft
- maxCount: 30
-
-- type: stack
- id: FloorTileRockVault
- name: stack-rock-vault-tile
- spawn: FloorTileItemRockVault
- maxCount: 30
-
-- type: stack
- id: FloorTileBlue
- name: stack-blue-floor-tile
- spawn: FloorTileItemBlue
- maxCount: 30
-
-- type: stack
- id: FloorTileMining
- name: stack-mining-floor-tile
- spawn: FloorTileItemMining
- maxCount: 30
-
-- type: stack
- id: FloorTileMiningDark
- name: stack-dark-mining-floor-tile
- spawn: FloorTileItemMiningDark
- maxCount: 30
-
-- type: stack
- id: FloorTileMiningLight
- name: stack-light-mining-floor-tile
- spawn: FloorTileItemMiningLight
- maxCount: 30
-
-- type: stack
- id: FloorTileBar
- name: stack-item-bar-floor-tile
- spawn: FloorTileItemBar
- maxCount: 30
-
-- type: stack
- id: FloorTileClown
- name: stack-clown-floor-tile
- spawn: FloorTileItemClown
- maxCount: 30
-
-- type: stack
- id: FloorTileMime
- name: stack-mime-floor-tile
- spawn: FloorTileItemMime
- maxCount: 30
-
-- type: stack
- id: FloorTileKitchen
- name: stack-kitchen-floor-tile
- spawn: FloorTileItemKitchen
- maxCount: 30
-
-- type: stack
- id: FloorTileLaundry
- name: stack-laundry-floor-tile
- spawn: FloorTileItemLaundry
- maxCount: 30
-
-- type: stack
- id: FloorTileConcrete
- name: stack-concrete-tile
- spawn: FloorTileItemGrayConcrete
- maxCount: 30
-
-- type: stack
- id: FloorTileConcreteMono
- name: stack-concrete-mono-tile
- spawn: FloorTileItemConcreteMono
- maxCount: 30
-
-- type: stack
- id: FloorTileConcreteSmooth
- name: stack-concrete-smooth
- spawn: FloorTileItemConcreteSmooth
- maxCount: 30
-
-- type: stack
- id: FloorTileGrayConcrete
- name: stack-gray-concrete-tile
- spawn: FloorTileItemGrayConcrete
- maxCount: 30
-
-- type: stack
- id: FloorTileGrayConcreteMono
- name: stack-gray-concrete-mono-tile
- spawn: FloorTileItemGrayConcreteMono
- maxCount: 30
-
-- type: stack
- id: FloorTileGrayConcreteSmooth
- name: stack-gray-concrete-smooth
- spawn: FloorTileItemGrayConcreteSmooth
- maxCount: 30
-
-- type: stack
- id: FloorTileOldConcrete
- name: stack-old-concrete-tile
- spawn: FloorTileItemOldConcrete
- maxCount: 30
-
-- type: stack
- id: FloorTileOldConcreteMono
- name: stack-old-concrete-mono-tile
- spawn: FloorTileItemOldConcreteMono
- maxCount: 30
-
-- type: stack
- id: FloorTileOldConcreteSmooth
- name: stack-old-concrete-smooth
- spawn: FloorTileItemOldConcreteSmooth
- maxCount: 30
-
-- type: stack
- id: FloorTileSilver
- name: stack-silver-floor-tile
- spawn: FloorTileItemSilver
- maxCount: 30
-
-- type: stack
- id: FloorTileBCircuit
- name: stack-bcircuit-floor-tile
- spawn: FloorTileItemBCircuit
- maxCount: 30
-
-- type: stack
- id: FloorTileRCircuit
- name: stack-red-circuit-floor
- spawn: FloorTileItemRCircuit
- maxCount: 30
-
-- type: stack
- id: FloorTileGrass
- name: stack-grass-floor-tile
- spawn: FloorTileItemGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileGrassJungle
- name: stack-grass-jungle-floor-tile
- spawn: FloorTileItemGrassJungle
- maxCount: 30
-
-- type: stack
- id: FloorTileSnow
- name: stack-snow-floor-tile
- spawn: FloorTileItemSnow
- maxCount: 30
-
-- type: stack
- id: FloorTileWoodPattern
- name: stack-wood-patter-floor
- spawn: FloorTileItemWoodPattern
- maxCount: 30
-
-- type: stack
- id: FloorTileFlesh
- name: stack-flesh-floor
- spawn: FloorTileItemFlesh
- maxCount: 30
-
-- type: stack
- id: FloorTileSteelMaint
- name: stack-steel-maint-floor
- spawn: FloorTileItemSteelMaint
- maxCount: 30
-
-- type: stack
- id: FloorTileGratingMaint
- name: stack-grating-maint-floor
- spawn: FloorTileItemGratingMaint
- maxCount: 30
-
-- type: stack
- id: FloorTileWeb
- name: stack-web-tile
- spawn: FloorTileItemWeb
- maxCount: 30
-
-# Faux science tiles
-- type: stack
- id: FloorTileAstroGrass
- name: stack-astro-grass-floor
- spawn: FloorTileItemAstroGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileMowedAstroGrass
- name: stack-mowed-astro-grass-floor
- spawn: FloorTileItemMowedAstroGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileJungleAstroGrass
- name: stack-jungle-astro-grass-floor
- spawn: FloorTileItemJungleAstroGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkAstroGrass
- name: stack-dark-astro-grass-floor
- spawn: FloorTileItemDarkAstroGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileLightAstroGrass
- name: stack-light-astro-grass-floor
- spawn: FloorTileItemLightAstroGrass
- maxCount: 30
-
-- type: stack
- id: FloorTileAstroIce
- name: stack-astro-ice-floor
- spawn: FloorTileItemAstroIce
- maxCount: 30
-
-- type: stack
- id: FloorTileAstroSnow
- name: stack-astro-snow-floor
- spawn: FloorTileItemAstroSnow
- maxCount: 30
-
-- type: stack
- id: FloorTileAstroAsteroidSand
- name: stack-asteroid-astro-sand-floor
- spawn: FloorTileItemAstroAsteroidSand
- maxCount: 30
-
-- type: stack
- id: FloorTileDesertAstroSand
- name: stack-desert-astro-sand-floor
- spawn: FloorTileItemDesertAstroSand
- maxCount: 30
-
-- type: stack
- id: FloorTileWoodLarge
- name: stack-large-wood-floor
- spawn: FloorTileItemWoodLarge
- maxCount: 30
-
-- type: stack
- id: FloorTileXeno
- name: stack-xeno-floor
- spawn: FloorTileItemXeno
- maxCount: 30
-
-- type: stack
- id: FloorTileXenoSteel
- name: stack-xeno-steel
- spawn: FloorTileItemXenoSteelCorner
- maxCount: 30
-
-- type: stack
- id: FloorTileXenoSteelCorner
- name: stack-xeno-steel-corner
- spawn: FloorTileItemXenoSteelCorner
- maxCount: 30
-
-- type: stack
- id: FloorTileXenoMaint
- name: stack-xeno-maint
- spawn: FloorTileItemXenoSteelCorner
- maxCount: 30
-
-- type: stack
- id: FloorTileXenoborg
- name: stack-xenoborg
- spawn: FloorTileItemXenoborg
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkSquiggly
- name: stack-dark-squiggly
- spawn: FloorTileItemDarkSquiggly
- maxCount: 30
-
-- type: stack
- id: FloorTileWhiteMarble
- name: stack-white-marble-floor
- spawn: FloorTileItemWhiteMarble
- maxCount: 30
-
-- type: stack
- id: FloorTileDarkMarble
- name: stack-dark-marble-floor
- spawn: FloorTileItemDarkMarble
- maxCount: 30
-
-- type: stack
- id: FloorTilePlasmaMarble
- name: stack-plasma-marble-floor
- spawn: FloorTileItemPlasmaMarble
- maxCount: 30
-
-- type: stack
- id: FloorTileUraniumMarble
- name: stack-uranium-marble-floor
- spawn: FloorTileItemUraniumMarble
- maxCount: 30
+# unrefined ore
+
- type: stack
+ parent: BaseMediumStack
id: GoldOre
name: stack-gold-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: gold }
spawn: GoldOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: DiamondOre
name: stack-rough-diamond
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: diamond }
spawn: DiamondOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: SteelOre
name: stack-iron-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: iron }
spawn: SteelOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: PlasmaOre
name: stack-plasma-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: plasma }
spawn: PlasmaOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: SilverOre
name: stack-silver-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: silver }
spawn: SilverOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: SpaceQuartz
name: stack-space-quartz
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: spacequartz }
spawn: SpaceQuartz1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: UraniumOre
name: stack-uranium-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: uranium }
spawn: UraniumOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: BananiumOre
name: stack-bananium-ore
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: bananium }
spawn: BananiumOre1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: Coal
name: stack-coal
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: coal }
spawn: Coal1
- maxCount: 30
- type: stack
+ parent: BaseMediumStack
id: SaltOre
name: stack-salt
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: salt }
spawn: Salt1
- maxCount: 30
--- /dev/null
+# Materials which come from refining ores, excluding sheets
+
+- type: stack
+ parent: BaseMediumStack
+ id: Diamond
+ name: stack-diamond
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: diamond }
+ spawn: MaterialDiamond1
+
+- type: stack
+ parent: BaseSmallStack
+ id: Bananium
+ name: stack-bananium
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bananium }
+ spawn: MaterialBananium1
+
+# Ingots
+- type: stack
+ parent: BaseMediumStack
+ id: Gold
+ name: stack-gold
+ icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: gold }
+ spawn: IngotGold1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Silver
+ name: stack-silver
+ icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: silver }
+ spawn: IngotSilver1
--- /dev/null
+- type: stack
+ parent: BaseVeryLargeStack
+ id: Biomass
+ name: stack-biomass
+ icon: { sprite: /Textures/Objects/Misc/monkeycube.rsi, state: cube }
+ spawn: MaterialBiomass1
+
+# Stacks which come from plants
+
+- type: stack
+ parent: BaseMediumStack
+ id: WoodPlank
+ name: stack-wood-plank
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: wood }
+ spawn: MaterialWoodPlank1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Cardboard
+ name: stack-cardboard
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cardboard }
+ spawn: MaterialCardboard1
+
+# Stacks which come from or might come from a creature
+
+- type: stack
+ parent: BaseLargeStack
+ id: WebSilk
+ name: stack-silk
+ icon: { sprite: /Textures/Objects/Materials/silk.rsi, state: icon }
+ spawn: MaterialWebSilk1
+
+- type: stack
+ parent: BaseMediumStack
+ id: Bones
+ name: stack-bones
+ icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bones }
+ spawn: MaterialBones1
+
+- type: stack
+ parent: BaseMediumStack
+ id: SpaceCarpTooth
+ name: stack-space-carp-tooth
+ icon: { sprite: /Textures/Objects/Materials/Mob/carptooth.rsi, state: tooth }
+ spawn: MaterialToothSpaceCarp1
+
+- type: stack
+ parent: BaseMediumStack
+ id: SharkMinnowTooth
+ name: stack-sharkminnow-tooth
+ icon: { sprite: /Textures/Objects/Materials/Mob/sharktooth.rsi, state: tooth }
+ spawn: MaterialToothSharkminnow1
+
+- type: stack
+ parent: BaseMediumStack
+ id: GoliathHide
+ name: stack-goliath-hide
+ icon: { sprite: /Textures/Objects/Materials/hide.rsi, state: goliath_hide }
+ spawn: MaterialGoliathHide1
--- /dev/null
+# Stacks which don't fit cleanly into other categories
+
+- type: stack
+ parent: BaseSheetStack # Not a sheet, but spiritually similar
+ id: MetalRod
+ name: stack-rods
+ icon: { sprite: /Textures/Objects/Materials/parts.rsi, state: rods }
+ spawn: PartRodMetal1
+
+- type: stack
+ parent: BaseVerySmallStack
+ id: Gunpowder
+ name: stack-gunpowder
+ icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
+ spawn: MaterialGunpowder
+++ /dev/null
-- type: stack
- id: Cable
- name: stack-lv-cable
- icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coil-30 }
- spawn: CableApcStack1
- maxCount: 30
-
-- type: stack
- id: CableMV
- name: stack-mv-cable
- icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilmv-30 }
- spawn: CableMVStack1
- maxCount: 30
-
-- type: stack
- id: CableHV
- name: stack-hv-cable
- icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilhv-30 }
- spawn: CableHVStack1
- maxCount: 30
-
-# Explosive cable below
-
-- type: stack
- id: CableDet
- name: stack-explosive-cord
- icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilex-30 }
- spawn: CableDetStack1
- maxCount: 30
-
interval: 5.0
chance: 0.5
withChat: false
+# Kudzu
+- type: autoEmote
+ id: MeatGasp
+ emote: Gasp
+ interval: 4.0 # Same interval as a full breathing cycle
+ chance: 0.01 # Make it very rare
+ ignoreActionBlocker: true
+ force: true
+ hiddenFromChatWindow: true
order: 4
lawString: law-paladin-4
-- type: siliconLaw
- id: Paladin5
- order: 5
- lawString: law-paladin-5
-
- type: siliconLawset
id: PaladinLawset
- Paladin2
- Paladin3
- Paladin4
- - Paladin5
obeysTo: laws-owner-crew
# Live and Let Live laws
id: Mushroom
## N ##
+- type: Tag
+ id: NinjaBombingTargetBlocker # Ninjas will not target this warp point
- type: Tag
id: NoBlockAnchoring
--- /dev/null
+<Document>
+ # Analysis Console
+
+ The Analysis Console is a device used to interface with artifacts. It can be used to check nodes, their triggers and effects, and extract points.
+
+ <Box>
+ <GuideEntityEmbed Entity="ComputerAnalysisConsole" Caption="Analysis Console"/>
+ </Box>
+
+ The console displays detailed information about each node in the artifact’s tree structure. This includes:
+ - [bold]ID:[/bold] Unique identifier for use with the Node Scanner.
+ - [bold]Class:[/bold] The layer name, nodes on the same layer share it.
+ - [bold]Status:[/bold]
+ - [italic][color=red]Locked[/color][/italic] by default.
+ - [italic][color=plum]Active[/color][/italic] when first triggered.
+ - [italic][color=lime]Unlocked[/color][/italic] if a deeper node is reached (prevents manual activations).
+ - [bold]Durability:[/bold] Number of manual activations available.
+ - [bold]Effect:[/bold] What happens when the node activates or is manually triggered.
+ - [bold]Triggers:[/bold] Required actions to unlock the node.
+ - [bold]Server:[/bold] Choose the research server where extracted points are sent.
+ - [bold]Extract Points:[/bold] Extracts points from nodes unlocked since the last extraction.
+</Document>
+++ /dev/null
-<Document>
- # Artifact Reports
- A large portion of Xenoarchaeology gameplay revolves around the interpretation of artifact reports, which are created at the [color=#a4885c]analysis console[/color] after an artifact is scanned. Reports contain the following information:
-
- - [color=#a4885c]Node ID:[/color] a unique numeric ID corresponding to this artifact's node. Useful in conjunction with a [color=#a4885c]node scanner[/color] for quickly identifying recurring nodes.
-
- - [color=#a4885c]Depth:[/color] a distance from the starting node (depth 0). This is a good shorthand for the value and danger of a node.
-
- - [color=#a4885c]Activation status:[/color] whether or not a node has been activated in the past.
-
- - [color=#a4885c]Stimulus:[/color] the stimulus for that particular node.
-
- - [color=#a4885c]Reaction:[/color] the reaction the stimulus induces. This is often vague, so caution is advised.
-
- - [color=#a4885c]Edges:[/color] the amount of nodes that are connected to the current node. Using this, you can calculate the total number of nodes as well as organize a map of their connections.
-
- - [color=#a4885c]Unextracted value:[/color] the amount of research points an artifact will give when extracted. Extracting sets this to zero and traversing new nodes increases it.
-
- Reports are a helpful tool in manipulating an artifact, especially in the later stages where you are traversing nodes that have already been activated.
- <Box>
- <GuideEntityEmbed Entity="PaperArtifactAnalyzer"/>
- </Box>
- To help with this process, consider printing out reports, writing down details uncovered during activation, or storing them in a folder nearby.
-</Document>
--- /dev/null
+<Document>
+ # Unlocking Nodes
+ <Box>
+ <GuideEntityEmbed Entity="ComplexXenoArtifact" Caption=""/>
+ <GuideEntityEmbed Entity="ComplexXenoArtifactItem" Caption=""/>
+ </Box>
+
+ To activate and unlock nodes on an artifact, you should:
+ - Check a node on the [bold]Analysis Console[/bold] to check its triggers and effects.
+ - Perform the [bold]triggers[/bold] listed in the console. Some require direct interaction with the artifact, while others may only need the correct environment or a specific action performed nearby.
+ - Once a trigger is successfully performed, the artifact will respond with the message: [italic]"It begins to shift in strange ways..."[/italic]. The [bold]Node Scanner[/bold] will then indicate which specific nodes are being triggered.
+
+ Artifacts enter an unlocking state after the first trigger is met. During this state, any remaining triggers must be completed. The unlocking window initially lasts a few seconds and resets each time a new trigger is activated. This window grows longer with each additional node unlocked, giving more time to complete further triggers.
+
+ Once all required triggers are completed successfully, the artifact will trigger it's effect and a popup will appear saying: [italic]"It slows down, visibly changed."[/italic], and the node will appear as [bold][color=plum]Active[/color][/bold] on the Console.
+
+ If an artifact fails to activate, it will stop resonating and display the message: [italic]"It slows down before uneventfully stopping."[/italic] After this, it enters a cooldown period before it can be activated again.
+
+ The order of trigger activation [bold]does not matter[/bold] for individual nodes. [italic]However[/italic], some triggers affect multiple nodes. As a rule of thumb, start with a trigger that is unique to the node you want to unlock. Activating a trigger for a different node during this phase prevents the target node from unlocking until the artifact’s cooldown ends.
+
+ <GuideReagentEmbed Reagent="Artifexium"/>
+
+ ## Active Nodes
+ Once unlocked, a node is considered active. Only the highest unlocked nodes in a tree’s layer are activatable, lower nodes in the same tree cannot be triggered anymore once a higher node has been activated.
+
+ Artifacts often have multiple trees. Layer precedence applies within each tree, but different trees operate independently. This means nodes in different trees can be activated simultaneously as long as they are the highest unlocked nodes in their respective trees.
+
+ [bold]Manual activation triggers all unlocked nodes at once and consumes durability.[/bold]
+
+ <GuideReagentEmbed Reagent="ArtifactGlue"/>
+
+ ## Triggers
+ Examples include:
+ - Examining the artifact
+ - Playing an instrument
+ - Damaging or throwing it
+ - Exposing it to gases (plasma, tritium, etc.)
+ - Changing pressure or temperature
+ - Using tools (screwdriver, multitool, crowbar, wrench)
+ - Splashing reagents (blood, water, ammonia, etc.)
+ - Killing something nearby
+
+ ## Effects
+ Effects can be:
+ - [color=green]Harmless:[/color] producing plants, animals, or junk
+ - [color=#00ccff]Helpful:[/color] charging batteries, creating instruments or money
+ - [color=red]Hazardous:[/color] anomalies, radiation, explosions, hostile fauna
+</Document>
<Document>
-# Xenoarchaeology
-Xenoarchaeology is a science subdepartment focused on researching and experimenting on alien artifacts.
-
-At the start of each shift, the Science department will usually have access to at least two artifacts to experiment on. You can buy more by talking to the Cargo department.
-
-By researching the unique things each artifact can do, you gain Research Points, increase the artifact's sale value, and potentially discover a useful ability or two that can help your department or the whole station!
-
-## Artifact Nodes
-<Box>
-<GuideEntityEmbed Entity="ComplexXenoArtifact" Caption=""/>
-<GuideEntityEmbed Entity="ComplexXenoArtifactItem" Caption=""/>
-</Box>
-Artifacts consist of a randomly-generated tree of nodes. These nodes have a "[color=#a4885c]depth[/color]", representing how dangerous the node is, and the number of other nodes connected to it, called "[color=#a4885c]edges[/color]",
-
-Artifacts always start at depth zero, the root of the tree. Travelling the tree to find as many nodes as possible is the main goal of the scientists working on them. Knowledge is extracted from nodes to gain Research Points and increase the artifact's sale value.
-
-Each node has two components: its [color=#a4885c]stimulus[/color] and a [color=#a4885c]reaction[/color].
-
-A stimulus is the external behavior that triggers the reaction. There's a variety of these, and higher depth nodes have more difficult to accomplish stimuli. Some stimuli will need improvisation to trigger, and you may need to talk to other departments to get everything you need.
-
-Some reactions are instantaneous effects while others are permanent changes. Once an artifact is triggered, the reaction causes the artifact to randomly move to another node it is linked to.
-
-With some experimental science, you can begin to grasp how the different nodes of an artifact are connected, and how to move between them by repeatedly activating nodes.
-
-All non-zero-depth nodes will have exactly one edge that leads up to its parent node. All other edges a node has lead down to the next depth.
-
-## Artifact Analyzer and Analysis Console
-<Box>
-<GuideEntityEmbed Entity="MachineArtifactAnalyzer"/>
-<GuideEntityEmbed Entity="ComputerAnalysisConsole"/>
-</Box>
-The main equipment that you'll be using for Xenoarchaeology is the [color=#a4885c]artifact analyzer[/color] and the [color=#a4885c]analysis console[/color]. You can use these to create reports that contain valuable information about an artifact.
-
-To set them up, simply link them with a network configurator and set an artifact on top of the analyzer. Every station has at least one of these machines already set up.
-
-Use the console's [color=#a4885c]scan[/color] button to discover what stimulus the artifact needs and what its reaction will do. Scanning takes thirty seconds.
-
-Use the [color=#a4885c]print[/color] button to save the scan result, so you can refer to it later.
-
-Once you've discovered a new node, you can extract points from the artifact using the [color=#a4885c]Extract[/color] button.
-
-## Assembling Artifacts
-<GuideEntityEmbed Entity="ArtifactFragment" Caption="Artifact Fragment"/>
-
-It is possible to gather multiple artifact fragments and assemble them into a working artifact. You can ask for these from Salvage, who usually find these while mining asteroids or on Expeditions.
-
-## Traversal Bias
-<Box>
- <GuideEntityEmbed Entity="MachineArtifactAnalyzer"/>
-</Box>
-Artifacts placed on top of a powered artifact analyzer are subjected to a bias which affects which node they will move to after being activated. The bias can be set in the artifact console.
-
-There are two types of biases:
-- [color=#a4885c]Up:[/color] favors nodes closer to the origin. Results in a decrease of depth.
-- [color=#a4885c]Down:[/color] favors nodes farther away from the origin. Results in an increase of depth.
+ # Xenoarchaeology
+
+ Xenoarchaeology is a branch of Science focused on researching alien [bold]artifacts[/bold].
+
+ Unlocking their secrets grants research points and reveals strange, potentially useful, or dangerous effects.
+
+ At round start, Science usually has one or two artifacts in the lab. More can be:
+ - Ordered from [color=orange]Cargo[/color]
+ - Found by [color=orange]Salvage[/color]
+ - Assembled from [bold]fragments[/bold]
+ - Appear during certain station events
+
+ ## Artifacts
+ <Box>
+ <GuideEntityEmbed Entity="ComplexXenoArtifact" Caption=""/>
+ <GuideEntityEmbed Entity="ComplexXenoArtifactItem" Caption=""/>
+ </Box>
+
+ Artifacts contain [bold]nodes[/bold] arranged in [bold]layers[/bold].
+ - Unlocking a node unlocks connected nodes on upper layers.
+ - Each node has [bold]triggers[/bold], actions that must be performed near the artifact to unlock a node.
+ - When a node is unlocked, its [bold]effect[/bold] will trigger, and the node becomes [bold][color=plum]Active[/color][/bold].
+ - Each node has [bold]durability[/bold]: the number of times it can be manually activated after being unlocked.
+ - Higher nodes are harder to reach but give more [bold]research points[/bold].
+ - Unlocking all nodes provides no special bonus, but every node yields research points.
+
+ ## Equipment
+ <Box>
+ <GuideEntityEmbed Entity="MachineArtifactAnalyzer" Caption="Analyzer"/>
+ <GuideEntityEmbed Entity="ComputerAnalysisConsole" Caption="Analysis Console"/>
+ <GuideEntityEmbed Entity="NodeScanner" Caption="Node Scanner"/>
+ </Box>
+ - [bold]Artifact Analyzer:[/bold] Stationary device that scans artifacts, sending data to the Console.
+ - [bold][textlink="Analysis Console:" link="AnalysisConsole"][/bold] Stationary device that is used to display the node tree. Must be linked to an Analyzer with a multitool.
+ - [bold]Node Scanner:[/bold] Small hand-held device that can show the ID of the node currently being activated and whether the artifact is ready to trigger, letting scientist have minimal required knowledge for operating inside chamber near artifact and far without direct access to console.
+
+ <Box>
+ <GuideEntityEmbed Entity="CrateArtifactContainer" Caption="Artifact Container"/>
+ <GuideEntityEmbed Entity="HandheldArtifactContainer" Caption="Handheld Container"/>
+ </Box>
+ - [bold]Artifact Containers:[/bold] Safely store and transports artifacts and prevent nodes from triggering.
+ <Box>
+ <GuideEntityEmbed Entity="MachineArtifactCrusher" Caption="Crusher"/>
+ </Box>
+ - [bold]Artifact Crusher:[/bold] Crushes artifacts into fragments. Four fragments can be rebuilt into a new artifact.
+ <Box>
+ <GuideEntityEmbed Entity="ArtifactFragment" Caption="Artifact Fragment"/>
+ </Box>
+ - [bold]Artifact Fragment:[/bold] Pieces of destroyed artifacts. Four fragments can be rebuilt into a new artifact using the craft menu.
</Document>
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Inhand sprites by SeamLesss (Github)",
+ "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Inhand sprites made by SeamLesss, Inhand & equipped-HAND sprites modified by Prole0 (Github)",
"size": {
"x": 32,
"y": 32
"x": 32,
"y": 32
},
- "copyright": "Taken from https://github.com/tgstation/tgstation/blob/05ec94e46349c35e29ca91e5e97d0c88ae26ad44/icons/mob/species/human/human_face.dmi ,resprited by Alekshhh, a modified by potato1234x, uneven and tailed is drawn by Ubaser, doublebun_long by Emisse, longbundled and bob5 sprited by github:DreamlyJack(624946166152298517), pulato.png made by DreamlyJack, b.png and b_alt.png modified and sprited by KingFroozy (github), long_with_bangs shaped and longbow by Futuristic (and Pyvik) for SS14, cube and baby by CoolioDudio",
+ "copyright": "Taken from https://github.com/tgstation/tgstation/blob/05ec94e46349c35e29ca91e5e97d0c88ae26ad44/icons/mob/species/human/human_face.dmi ,resprited by Alekshhh, a modified by potato1234x, uneven and tailed is drawn by Ubaser, doublebun_long by Emisse, longbundled and bob5 sprited by github:DreamlyJack(624946166152298517), pulato.png made by DreamlyJack, b.png and b_alt.png modified and sprited by KingFroozy (github), long_with_bangs shaped and longbow by Futuristic (and Pyvik) for SS14, cube and baby by CoolioDudio, overeyepigtail by GovnokradZXC",
"license": "CC-BY-SA-3.0",
"states": [
{
{
"name": "longwithbangs",
"directions": 4
+ },
+ {
+ "name": "overeyepigtail",
+ "directions": 4
}
]
}
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-4.0",
+ "copyright": "Original sprite made by compilatron (Discord) for SS13, relicensed for SS14/Moffstation; modified by Centronias (GitHub) to have two arms",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "hugbot"
+ }
+ ]
+}
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "Taken from tgstation and cev-eris at https://github.com/tgstation/tgstation/commit/c4b7f3c41b6742aca260fe60cc358a778ba9b8c8 and https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af, inhands by mubururu_ (github)",
+ "copyright": "brain, ears, eyeball-l, eyeball-r, heart-on, heart-off, kidney-l, kidney-r, liver, lung-l, lung-r, stomach, tongue, taken from /tg/station 13 at https://github.com/tgstation/tgstation/commit/c4b7f3c41b6742aca260fe60cc358a778ba9b8c8 | appendix, appendix-inflamed, muscle, nerve, vessel taken from CEV-Eris at https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af | inhands by mubururu_ (github)",
"size": {
"x": 32,
"y": 32
{
- "version": 1,
- "license": "CC-BY-SA-3.0",
- "copyright": "Taken from Paradise Station 13 at commit https://github.com/ParadiseSS13/Paradise/commit/9312f1fb7dcdf1c195e255a528f31092613fb60d. assembly, closed, closing, open, opening, panel_open modified by K-Dynamic (github).",
- "size": {
- "x": 32,
- "y": 32
- },
- "states": [
- {
- "name": "assembly"
- },
- {
- "name": "bolted_unlit"
- },
- {
- "name": "closed"
- },
- {
- "name": "closed_unlit"
- },
- {
- "name": "closing",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "closing_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "deny_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "open",
- "delays": [
- [
- 1
- ]
- ]
- },
- {
- "name": "opening",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "opening_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "panel_closing",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "panel_open",
- "delays": [
- [
- 1
- ]
- ]
- },
- {
- "name": "panel_opening",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks_broken",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks_damaged",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 1.7
- ]
- ]
- },
- {
- "name": "sparks_open",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "welded"
- },
- {
- "name": "emergency_unlit",
- "delays": [
- [
- 0.4,
- 0.4
- ]
- ]
- }
- ]
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from Paradise Station 13 at commit https://github.com/ParadiseSS13/Paradise/commit/9312f1fb7dcdf1c195e255a528f31092613fb60d. assembly, closed, closing, open, opening, panel_open modified by K-Dynamic (github).",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "assembly"
+ },
+ {
+ "name": "bolted_unlit"
+ },
+ {
+ "name": "closed"
+ },
+ {
+ "name": "closed_unlit"
+ },
+ {
+ "name": "closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "closing_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "deny_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "opening_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "panel_opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_broken",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_damaged",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 1.7
+ ]
+ ]
+ },
+ {
+ "name": "sparks_open",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "welded"
+ },
+ {
+ "name": "emergency_unlit",
+ "delays": [
+ [
+ 0.4,
+ 0.4
+ ]
+ ]
+ }
+ ]
}
{
- "version": 1,
- "license": "CC-BY-SA-3.0",
- "copyright": "Taken from Paradise Station 13 at commit https://github.com/ParadiseSS13/Paradise/commit/9312f1fb7dcdf1c195e255a528f31092613fb60d. assembly, closed, closing, open, opening, panel_open modified by K-Dynamic (github).",
- "size": {
- "x": 32,
- "y": 32
- },
- "states": [
- {
- "name": "assembly"
- },
- {
- "name": "bolted_unlit"
- },
- {
- "name": "closed"
- },
- {
- "name": "closed_unlit"
- },
- {
- "name": "closing",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "closing_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "deny_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "open",
- "delays": [
- [
- 1
- ]
- ]
- },
- {
- "name": "opening",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "opening_unlit",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "panel_closing",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "panel_open",
- "delays": [
- [
- 1
- ]
- ]
- },
- {
- "name": "panel_opening",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks_broken",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "sparks_damaged",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 1.7
- ]
- ]
- },
- {
- "name": "sparks_open",
- "delays": [
- [
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1,
- 0.1
- ]
- ]
- },
- {
- "name": "welded"
- },
- {
- "name": "emergency_unlit",
- "delays": [
- [
- 0.4,
- 0.4
- ]
- ]
- }
- ]
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from paradise station at commit https://github.com/ParadiseSS13/Paradise/commit/9312f1fb7dcdf1c195e255a528f31092613fb60d. Modified by Hyenh",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "assembly"
+ },
+ {
+ "name": "bolted_unlit"
+ },
+ {
+ "name": "closed"
+ },
+ {
+ "name": "closed_unlit"
+ },
+ {
+ "name": "closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "closing_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "deny_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "opening_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "panel_opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_broken",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_damaged",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 1.7
+ ]
+ ]
+ },
+ {
+ "name": "sparks_open",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "welded"
+ },
+ {
+ "name": "emergency_unlit",
+ "delays": [
+ [
+ 0.4,
+ 0.4
+ ]
+ ]
+ }
+ ]
}
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Made by Hyenh",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "assembly"
+ },
+ {
+ "name": "bolted_unlit"
+ },
+ {
+ "name": "closed"
+ },
+ {
+ "name": "closed_unlit"
+ },
+ {
+ "name": "closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "closing_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "deny_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "opening_unlit",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_closing",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "panel_open",
+ "delays": [
+ [
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "panel_opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_broken",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "sparks_damaged",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 1.7
+ ]
+ ]
+ },
+ {
+ "name": "sparks_open",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "welded"
+ },
+ {
+ "name": "emergency_unlit",
+ "delays": [
+ [
+ 0.4,
+ 0.4
+ ]
+ ]
+ }
+ ]
+}
{
- "version": 1,
- "size": {
- "x": 32,
- "y": 32
- },
- "license": "CC-BY-SA-3.0",
- "copyright": "Created by TheShuEd (github) for Space Station 14",
- "states": [
- {
- "name": "bluespace",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
},
- {
- "name": "bluespace_VOX",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
- },
- {
- "name": "fire",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "fire_VOX",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "flesh",
- "directions": 4,
- "delays": [
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "flesh_VOX",
- "directions": 4,
- "delays": [
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ],
- [
- 0.8,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "flora",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
- },
- {
- "name": "flora_VOX",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
- },
- {
- "name": "frost",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "frost_VOX",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "grav",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
- },
- {
- "name": "grav_VOX",
- "directions": 4,
- "delays": [
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ],
- [
- 0.3,
- 0.3,
- 0.3,
- 0.3
- ]
- ]
- },
- {
- "name": "rock",
- "directions": 4,
- "delays": [
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "rock_VOX",
- "directions": 4,
- "delays": [
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.9,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "santa",
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "shadow",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "shadow_VOX",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "shock",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "shock_VOX",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ],
- [
- 0.2,
- 0.2,
- 0.2,
- 0.2,
- 0.2
- ]
- ]
- },
- {
- "name": "tech",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ]
- ]
- },
- {
- "name": "tech_VOX",
- "directions": 4,
- "delays": [
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ],
- [
- 0.2,
- 0.4,
- 0.2,
- 0.4
- ]
- ]
- }
- ]
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Created by TheShuEd (github) for Space Station 14, originals modified by HTMLSystem to fit arachnids and moths",
+ "states": [
+ {
+ "name": "bluespace",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "bluespace_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "bluespace_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "bluespace_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "fire",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "fire_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "fire_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "fire_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "flesh",
+ "directions": 4,
+ "delays": [
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "flesh_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "flesh_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "flesh_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.8,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "flora",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "flora_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "flora_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "flora_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "frost",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "frost_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "frost_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "frost_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "grav",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "grav_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "grav_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "grav_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "rock",
+ "directions": 4,
+ "delays": [
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "rock_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "rock_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "rock_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.9,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "santa",
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shadow",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shadow_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shadow_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shadow_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shock",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shock_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shock_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "shock_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "tech",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ]
+ ]
+ },
+ {
+ "name": "tech_VOX",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ]
+ ]
+ },
+ {
+ "name": "tech_ARACHNID",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ]
+ ]
+ },
+ {
+ "name": "tech_MOTH",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ],
+ [
+ 0.2,
+ 0.4,
+ 0.2,
+ 0.4
+ ]
+ ]
+ }
+ ]
}
BibleTanakh: null
BibleSatanic: null
-# 2025-10-8
+
+# 2025-10-08
ClothingBeltAssault: ClothingBeltMilitaryWebbing
+WarpPointBombing: null
# Dumps Patreon's CSV download into a YAML file the game reads.
# Have to trim patron names because apparently Patreon doesn't which is quite ridiculous.
-Get-content $csvPath | ConvertFrom-Csv -Delimiter "," | select @{l="Name";e={$_.Name.Trim()}},Tier | where-object Tier -ne "" | ConvertTo-Yaml
+Get-content $csvPath | ConvertFrom-Csv -Delimiter "," | select @{l="Name";e={$_.Name.Trim()}},Tier | where-object Tier -ne "" | where-object Tier -ne "Free" | ConvertTo-Yaml
-#!/bin/sh
+#!/usr/bin/env bash
# Add this to .git/config:
# [merge "mapping-merge-driver"]
-#!/bin/sh
+#!/usr/bin/env bash
dotnet run --project Content.Client --configuration Tools
read -p "Press enter to continue"
-#!/bin/sh
+#!/usr/bin/env bash
dotnet run --project Content.Client
read -p "Press enter to continue"
-#!/bin/sh
+#!/usr/bin/env bash
dotnet run --project Content.Server --configuration Tools
read -p "Press enter to continue"
-#!/bin/sh
+#!/usr/bin/env bash
dotnet run --project Content.Server
read -p "Press enter to continue"