Merge branch 'master' into 2020-04-28-tool-component

This commit is contained in:
Víctor Aguilera Puerto
2020-05-19 14:19:45 +02:00
committed by GitHub
201 changed files with 4249 additions and 162 deletions

View File

@@ -144,7 +144,10 @@ namespace Content.Client
"Mop", "Mop",
"Bucket", "Bucket",
"Puddle", "Puddle",
"CanSpill" "CanSpill",
"RandomPottedPlant",
"CommunicationsConsole",
"BarSign",
}; };
foreach (var ignoreName in registerIgnore) foreach (var ignoreName in registerIgnore)

View File

@@ -81,6 +81,9 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
base.Startup(); base.Startup();
SnapGrid.OnPositionChanged += SnapGridOnPositionChanged; SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
// ensures lastposition initial value is populated on spawn. Just calling
// the hook here would cause a dirty event to fire needlessly
_lastPosition = (Owner.Transform.GridID, SnapGrid.Position);
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new IconSmoothDirtyEvent(Owner,null, SnapGrid.Offset, Mode)); Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new IconSmoothDirtyEvent(Owner,null, SnapGrid.Offset, Mode));
if (Mode == IconSmoothingMode.Corners) if (Mode == IconSmoothingMode.Corners)
{ {

View File

@@ -27,7 +27,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
public MicrowaveBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner,uiKey) public MicrowaveBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner,uiKey)
{ {
} }
protected override void Open() protected override void Open()
@@ -39,9 +39,9 @@ namespace Content.Client.GameObjects.Components.Kitchen
_menu.StartButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveStartCookMessage()); _menu.StartButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveStartCookMessage());
_menu.EjectButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveEjectMessage()); _menu.EjectButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveEjectMessage());
_menu.IngredientsList.OnItemSelected += args => _menu.IngredientsList.OnItemSelected += args =>
{ {
SendMessage(new SharedMicrowaveComponent.MicrowaveEjectSolidIndexedMessage(_solids[args.ItemIndex])); SendMessage(new SharedMicrowaveComponent.MicrowaveEjectSolidIndexedMessage(_solids[args.ItemIndex]));
}; };
_menu.IngredientsListReagents.OnItemSelected += args => _menu.IngredientsListReagents.OnItemSelected += args =>
@@ -49,7 +49,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
SendMessage( SendMessage(
new SharedMicrowaveComponent.MicrowaveVaporizeReagentIndexedMessage(_reagents[args.ItemIndex])); new SharedMicrowaveComponent.MicrowaveVaporizeReagentIndexedMessage(_reagents[args.ItemIndex]));
}; };
_menu.OnCookTimeSelected += args => _menu.OnCookTimeSelected += args =>
{ {
var actualButton = args.Button as Button; var actualButton = args.Button as Button;
@@ -80,6 +80,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
return; return;
} }
_menu.ToggleBusyDisableOverlayPanel(cstate.IsMicrowaveBusy);
RefreshContentsDisplay(cstate.ReagentsReagents, cstate.ContainedSolids); RefreshContentsDisplay(cstate.ReagentsReagents, cstate.ContainedSolids);
} }
@@ -101,9 +102,12 @@ namespace Content.Client.GameObjects.Components.Kitchen
_menu.IngredientsList.Clear(); _menu.IngredientsList.Clear();
foreach (var entityID in solids) foreach (var entityID in solids)
{ {
var entity = _entityManager.GetEntity(entityID); if (!_entityManager.TryGetEntity(entityID, out var entity))
{
return;
}
if (entity.TryGetComponent(out IconComponent icon)) if (!entity.Deleted && entity.TryGetComponent(out IconComponent icon))
{ {
var solidItem = _menu.IngredientsList.AddItem(entity.Name, icon.Icon.Default); var solidItem = _menu.IngredientsList.AddItem(entity.Name, icon.Icon.Default);

View File

@@ -26,6 +26,11 @@ namespace Content.Client.GameObjects.Components.Kitchen
public ButtonGroup CookTimeButtonGroup { get; } public ButtonGroup CookTimeButtonGroup { get; }
private VBoxContainer CookTimeButtonVbox { get; } private VBoxContainer CookTimeButtonVbox { get; }
private VBoxContainer ButtonGridContainer { get; }
private PanelContainer DisableCookingPanelOverlay { get;}
public ItemList IngredientsList { get;} public ItemList IngredientsList { get;}
public ItemList IngredientsListReagents { get; } public ItemList IngredientsListReagents { get; }
@@ -35,6 +40,16 @@ namespace Content.Client.GameObjects.Components.Kitchen
{ {
Owner = owner; Owner = owner;
Title = Loc.GetString("Microwave"); Title = Loc.GetString("Microwave");
DisableCookingPanelOverlay = new PanelContainer
{
MouseFilter = MouseFilterMode.Stop,
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.60f)},
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
};
var hSplit = new HBoxContainer var hSplit = new HBoxContainer
{ {
SizeFlagsHorizontal = SizeFlags.Fill, SizeFlagsHorizontal = SizeFlags.Fill,
@@ -58,14 +73,14 @@ namespace Content.Client.GameObjects.Components.Kitchen
SizeFlagsStretchRatio = 2, SizeFlagsStretchRatio = 2,
CustomMinimumSize = (100,128) CustomMinimumSize = (100,128)
}; };
hSplit.AddChild(IngredientsListReagents); hSplit.AddChild(IngredientsListReagents);
//Padding between the lists. //Padding between the lists.
hSplit.AddChild(new Control hSplit.AddChild(new Control
{ {
CustomMinimumSize = (0,5), CustomMinimumSize = (0,5),
}); });
hSplit.AddChild(IngredientsList); hSplit.AddChild(IngredientsList);
var vSplit = new VBoxContainer var vSplit = new VBoxContainer
@@ -76,7 +91,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
hSplit.AddChild(vSplit); hSplit.AddChild(vSplit);
var buttonGridContainer = new VBoxContainer ButtonGridContainer = new VBoxContainer
{ {
Align = BoxContainer.AlignMode.Center, Align = BoxContainer.AlignMode.Center,
SizeFlagsStretchRatio = 3 SizeFlagsStretchRatio = 3
@@ -96,10 +111,10 @@ namespace Content.Client.GameObjects.Components.Kitchen
TextAlign = Label.AlignMode.Center, TextAlign = Label.AlignMode.Center,
}; };
buttonGridContainer.AddChild(StartButton); ButtonGridContainer.AddChild(StartButton);
buttonGridContainer.AddChild(EjectButton); ButtonGridContainer.AddChild(EjectButton);
vSplit.AddChild(buttonGridContainer); vSplit.AddChild(ButtonGridContainer);
//Padding //Padding
vSplit.AddChild(new Control vSplit.AddChild(new Control
{ {
@@ -114,6 +129,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
Align = BoxContainer.AlignMode.Center, Align = BoxContainer.AlignMode.Center,
}; };
var index = 0; var index = 0;
for (var i = 0; i <= 12; i++) for (var i = 0; i <= 12; i++)
{ {
@@ -134,7 +150,8 @@ namespace Content.Client.GameObjects.Components.Kitchen
var cookTimeOneSecondButton = (Button)CookTimeButtonVbox.GetChild(0); var cookTimeOneSecondButton = (Button)CookTimeButtonVbox.GetChild(0);
cookTimeOneSecondButton.Pressed = true; cookTimeOneSecondButton.Pressed = true;
_cookTimeInfoLabel = new Label _cookTimeInfoLabel = new Label
{ {
Text = Loc.GetString($"COOK TIME: {VisualCookTime}"), Text = Loc.GetString($"COOK TIME: {VisualCookTime}"),
@@ -158,7 +175,7 @@ namespace Content.Client.GameObjects.Components.Kitchen
Children = Children =
{ {
new PanelContainer new PanelContainer
{ {
PanelOverride = new StyleBoxFlat(){BackgroundColor = Color.Gray.WithAlpha(0.2f)}, PanelOverride = new StyleBoxFlat(){BackgroundColor = Color.Gray.WithAlpha(0.2f)},
@@ -199,8 +216,15 @@ namespace Content.Client.GameObjects.Components.Kitchen
vSplit.AddChild(TimerFacePlate); vSplit.AddChild(TimerFacePlate);
Contents.AddChild(hSplit); Contents.AddChild(hSplit);
Contents.AddChild(DisableCookingPanelOverlay);
} }
public void ToggleBusyDisableOverlayPanel(bool shouldDisable)
{
DisableCookingPanelOverlay.Visible = shouldDisable;
}
} }
} }

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Storage; using Content.Shared.GameObjects.Components.Storage;
using Content.Client.Interfaces.GameObjects; using Content.Client.Interfaces.GameObjects;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
@@ -103,9 +104,11 @@ namespace Content.Client.GameObjects.Components.Storage
private Control VSplitContainer; private Control VSplitContainer;
private VBoxContainer EntityList; private VBoxContainer EntityList;
private Label Information; private Label Information;
private Button AddItemButton;
public ClientStorageComponent StorageEntity; public ClientStorageComponent StorageEntity;
private StyleBoxFlat _HoveredBox = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.35f)};
private StyleBoxFlat _unHoveredBox = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.0f)};
protected override Vector2? CustomSize => (180, 320); protected override Vector2? CustomSize => (180, 320);
public StorageWindow() public StorageWindow()
@@ -113,7 +116,37 @@ namespace Content.Client.GameObjects.Components.Storage
Title = "Storage Item"; Title = "Storage Item";
RectClipContent = true; RectClipContent = true;
VSplitContainer = new VBoxContainer(); var containerButton = new ContainerButton
{
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
MouseFilter = MouseFilterMode.Pass,
};
var innerContainerButton = new PanelContainer
{
PanelOverride = _unHoveredBox,
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
};
containerButton.AddChild(innerContainerButton);
containerButton.OnPressed += args =>
{
var controlledEntity = IoCManager.Resolve<IPlayerManager>().LocalPlayer.ControlledEntity;
if (controlledEntity.TryGetComponent(out IHandsComponent hands))
{
StorageEntity.SendNetworkMessage(new InsertEntityMessage());
}
};
VSplitContainer = new VBoxContainer()
{
MouseFilter = MouseFilterMode.Ignore,
};
containerButton.AddChild(VSplitContainer);
Information = new Label Information = new Label
{ {
Text = "Items: 0 Volume: 0/0 Stuff", Text = "Items: 0 Volume: 0/0 Stuff",
@@ -126,7 +159,7 @@ namespace Content.Client.GameObjects.Components.Storage
SizeFlagsVertical = SizeFlags.FillExpand, SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsHorizontal = SizeFlags.FillExpand,
HScrollEnabled = true, HScrollEnabled = true,
VScrollEnabled = true VScrollEnabled = true,
}; };
EntityList = new VBoxContainer EntityList = new VBoxContainer
{ {
@@ -135,16 +168,17 @@ namespace Content.Client.GameObjects.Components.Storage
listScrollContainer.AddChild(EntityList); listScrollContainer.AddChild(EntityList);
VSplitContainer.AddChild(listScrollContainer); VSplitContainer.AddChild(listScrollContainer);
AddItemButton = new Button Contents.AddChild(containerButton);
{
Text = "Add Item",
ToggleMode = false,
SizeFlagsHorizontal = SizeFlags.FillExpand
};
AddItemButton.OnPressed += OnAddItemButtonPressed;
VSplitContainer.AddChild(AddItemButton);
Contents.AddChild(VSplitContainer); listScrollContainer.OnMouseEntered += args =>
{
innerContainerButton.PanelOverride = _HoveredBox;
};
listScrollContainer.OnMouseExited += args =>
{
innerContainerButton.PanelOverride = _unHoveredBox;
};
} }
public override void Close() public override void Close()
@@ -168,7 +202,8 @@ namespace Content.Client.GameObjects.Components.Storage
var button = new EntityButton() var button = new EntityButton()
{ {
EntityuID = entityuid.Key EntityuID = entityuid.Key,
MouseFilter = MouseFilterMode.Stop,
}; };
button.ActualButton.OnToggled += OnItemButtonToggled; button.ActualButton.OnToggled += OnItemButtonToggled;
//Name and Size labels set //Name and Size labels set

View File

@@ -0,0 +1,53 @@
using Content.Client.UserInterface;
using Content.Shared.BodySystem;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.ViewVariables;
using System.Collections.Generic;
namespace Content.Client.BodySystem
{
public class BodyScannerBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private BodyScannerDisplay _display;
[ViewVariables]
private BodyScannerTemplateData _template;
[ViewVariables]
private Dictionary<string, BodyScannerBodyPartData> _parts;
public BodyScannerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_display = new BodyScannerDisplay(this);
_display.OnClose += Close;
_display.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (!(state is BodyScannerInterfaceState scannerState))
return;
_template = scannerState.Template;
_parts = scannerState.Parts;
_display.UpdateDisplay(_template, _parts);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
}

View File

@@ -0,0 +1,160 @@
using Content.Client.BodySystem;
using Content.Shared.BodySystem;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using System;
using System.Collections.Generic;
using System.Globalization;
using static Robust.Client.UserInterface.Controls.ItemList;
namespace Content.Client.UserInterface
{
public sealed class BodyScannerDisplay : SS14Window
{
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _loc;
#pragma warning restore 649
public BodyScannerBoundUserInterface Owner { get; private set; }
protected override Vector2? CustomSize => (800, 600);
private ItemList BodyPartList { get; }
private Label BodyPartLabel { get; }
private Label BodyPartHealth { get; }
private ItemList MechanismList { get; }
private RichTextLabel MechanismInfoLabel { get; }
private BodyScannerTemplateData _template;
private Dictionary<string, BodyScannerBodyPartData> _parts;
private List<string> _slots;
private BodyScannerBodyPartData _currentBodyPart;
public BodyScannerDisplay(BodyScannerBoundUserInterface owner)
{
IoCManager.InjectDependencies(this);
Owner = owner;
Title = _loc.GetString("Body Scanner");
var hSplit = new HBoxContainer();
Contents.AddChild(hSplit);
//Left half
var scrollBox = new ScrollContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
};
hSplit.AddChild(scrollBox);
BodyPartList = new ItemList { };
scrollBox.AddChild(BodyPartList);
BodyPartList.OnItemSelected += BodyPartOnItemSelected;
//Right half
var vSplit = new VBoxContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
};
hSplit.AddChild(vSplit);
//Top half of the right half
var limbBox = new VBoxContainer
{
SizeFlagsVertical = SizeFlags.FillExpand
};
vSplit.AddChild(limbBox);
BodyPartLabel = new Label();
limbBox.AddChild(BodyPartLabel);
var limbHealthHBox = new HBoxContainer();
limbBox.AddChild(limbHealthHBox);
var healthLabel = new Label
{
Text = "Health: "
};
limbHealthHBox.AddChild(healthLabel);
BodyPartHealth = new Label();
limbHealthHBox.AddChild(BodyPartHealth);
var limbScroll = new ScrollContainer
{
SizeFlagsVertical = SizeFlags.FillExpand
};
limbBox.AddChild(limbScroll);
MechanismList = new ItemList();
limbScroll.AddChild(MechanismList);
MechanismList.OnItemSelected += MechanismOnItemSelected;
//Bottom half of the right half
MechanismInfoLabel = new RichTextLabel
{
SizeFlagsVertical = SizeFlags.FillExpand
};
vSplit.AddChild(MechanismInfoLabel);
}
public void UpdateDisplay(BodyScannerTemplateData template, Dictionary<string, BodyScannerBodyPartData> parts)
{
_template = template;
_parts = parts;
_slots = new List<string>();
foreach (var (key, value) in _parts)
{
_slots.Add(key); //We have to do this since ItemLists only return the index of what item is selected and dictionaries don't allow you to explicitly grab things by index.
//So we put the contents of the dictionary into a list so that we can grab the list by index. I don't know either.
BodyPartList.AddItem(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(key));
}
}
public void BodyPartOnItemSelected(ItemListSelectedEventArgs args)
{
if(_parts.TryGetValue(_slots[args.ItemIndex], out _currentBodyPart)) {
UpdateBodyPartBox(_currentBodyPart, _slots[args.ItemIndex]);
}
}
private void UpdateBodyPartBox(BodyScannerBodyPartData part, string slotName)
{
BodyPartLabel.Text = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(slotName) + ": " + CultureInfo.CurrentCulture.TextInfo.ToTitleCase(part.Name);
BodyPartHealth.Text = part.CurrentDurability + "/" + part.MaxDurability;
MechanismList.Clear();
foreach (var mechanism in part.Mechanisms) {
MechanismList.AddItem(mechanism.Name);
}
}
public void MechanismOnItemSelected(ItemListSelectedEventArgs args)
{
UpdateMechanismBox(_currentBodyPart.Mechanisms[args.ItemIndex]);
}
private void UpdateMechanismBox(BodyScannerMechanismData mechanism)
{
//TODO: Make UI look less shit and clean up whatever the fuck this is lmao
if (mechanism != null)
{
string message = "";
message += mechanism.Name;
message += "\nHealth: ";
message += mechanism.CurrentDurability;
message += "/";
message += mechanism.MaxDurability;
message += "\n";
message += mechanism.Description;
MechanismInfoLabel.SetMessage(message);
}
else
{
MechanismInfoLabel.SetMessage("");
}
}
}
}

View File

@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Storage;
using Content.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Content.Shared.BodySystem;
using System.Globalization;
namespace Content.Client.BodySystem
{
[RegisterComponent]
public class ClientSurgeryToolComponent : SharedSurgeryToolComponent
{
private SurgeryToolWindow Window;
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, channel, session);
switch (message)
{
case OpenSurgeryUIMessage msg:
HandleOpenSurgeryUIMessage();
break;
case CloseSurgeryUIMessage msg:
HandleCloseSurgeryUIMessage();
break;
case UpdateSurgeryUIMessage msg:
HandleUpdateSurgeryUIMessage(msg);
break;
}
}
public override void OnAdd()
{
base.OnAdd();
Window = new SurgeryToolWindow() { SurgeryToolEntity = this };
}
public override void OnRemove()
{
Window.Dispose();
base.OnRemove();
}
private void HandleOpenSurgeryUIMessage()
{
Window.Open();
}
private void HandleCloseSurgeryUIMessage()
{
Window.Close();
}
private void HandleUpdateSurgeryUIMessage(UpdateSurgeryUIMessage surgeryUIState)
{
Window.BuildDisplay(surgeryUIState.Targets);
}
private class SurgeryToolWindow : SS14Window
{
private Control _VSplitContainer;
private VBoxContainer _bodyPartList;
public ClientSurgeryToolComponent SurgeryToolEntity;
protected override Vector2? CustomSize => (300, 400);
public SurgeryToolWindow()
{
Title = "Select surgery target...";
RectClipContent = true;
_VSplitContainer = new VBoxContainer();
var listScrollContainer = new ScrollContainer
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand,
HScrollEnabled = true,
VScrollEnabled = true
};
_bodyPartList = new VBoxContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand
};
listScrollContainer.AddChild(_bodyPartList);
_VSplitContainer.AddChild(listScrollContainer);
Contents.AddChild(_VSplitContainer);
}
public override void Close()
{
SurgeryToolEntity.SendNetworkMessage(new CloseSurgeryUIMessage());
base.Close();
}
public void BuildDisplay(Dictionary<string, string> targets)
{
_bodyPartList.DisposeAllChildren();
foreach (var(slotName, partname) in targets)
{
var button = new BodyPartButton(slotName);
button.ActualButton.OnToggled += OnButtonPressed;
button.LimbName.Text = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(slotName + " - " + partname);
//button.SpriteView.Sprite = sprite;
_bodyPartList.AddChild(button);
}
}
private void OnButtonPressed(BaseButton.ButtonEventArgs args)
{
var parent = (BodyPartButton) args.Button.Parent;
SurgeryToolEntity.SendNetworkMessage(new SelectSurgeryUIMessage(parent.LimbSlotName));
}
}
private class BodyPartButton : PanelContainer
{
public Button ActualButton { get; }
public SpriteView SpriteView { get; }
public Control EntityControl { get; }
public Label LimbName { get; }
public string LimbSlotName { get; }
public BodyPartButton(string slotName)
{
LimbSlotName = slotName;
ActualButton = new Button
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
ToggleMode = true,
MouseFilter = MouseFilterMode.Stop
};
AddChild(ActualButton);
var hBoxContainer = new HBoxContainer();
SpriteView = new SpriteView
{
CustomMinimumSize = new Vector2(32.0f, 32.0f)
};
LimbName = new Label
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
Text = "N/A",
};
hBoxContainer.AddChild(SpriteView);
hBoxContainer.AddChild(LimbName);
EntityControl = new Control
{
SizeFlagsHorizontal = SizeFlags.FillExpand
};
hBoxContainer.AddChild(EntityControl);
AddChild(hBoxContainer);
}
}
}
}

View File

@@ -19,11 +19,9 @@ using Robust.Server.GameObjects.Components.Container;
using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Power;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using YamlDotNet.Serialization.NodeTypeResolvers;
namespace Content.Server.GameObjects.Components.Kitchen namespace Content.Server.GameObjects.Components.Kitchen
{ {
@@ -76,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface;
private Container _storage; private Container _storage;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
@@ -101,7 +99,6 @@ namespace Content.Server.GameObjects.Components.Kitchen
_audioSystem = _entitySystemManager.GetEntitySystem<AudioSystem>(); _audioSystem = _entitySystemManager.GetEntitySystem<AudioSystem>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() _userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(MicrowaveUiKey.Key); .GetBoundUserInterface(MicrowaveUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
} }
@@ -137,7 +134,6 @@ namespace Content.Server.GameObjects.Components.Kitchen
UpdateUserInterface(); UpdateUserInterface();
} }
break; break;
case MicrowaveVaporizeReagentIndexedMessage msg: case MicrowaveVaporizeReagentIndexedMessage msg:
if (HasContents) if (HasContents)
{ {
@@ -146,7 +142,6 @@ namespace Content.Server.GameObjects.Components.Kitchen
UpdateUserInterface(); UpdateUserInterface();
} }
break; break;
case MicrowaveSelectCookTimeMessage msg: case MicrowaveSelectCookTimeMessage msg:
_currentCookTimerTime = msg.newCookTime; _currentCookTimerTime = msg.newCookTime;
ClickSound(); ClickSound();
@@ -173,7 +168,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
solidsVisualList.Add(item.Uid); solidsVisualList.Add(item.Uid);
} }
_userInterface.SetState(new MicrowaveUpdateUserInterfaceState(_solution.Solution.Contents, solidsVisualList)); _userInterface.SetState(new MicrowaveUpdateUserInterfaceState(_solution.Solution.Contents, solidsVisualList, _busy));
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
@@ -246,7 +241,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
{ {
return; return;
} }
_busy = true; _busy = true;
// Convert storage into Dictionary of ingredients // Convert storage into Dictionary of ingredients
var solidsDict = new Dictionary<string, int>(); var solidsDict = new Dictionary<string, int>();
@@ -279,7 +274,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
(_currentCookTimerTime == (uint)recipeToCook.CookTime) ? true : false; (_currentCookTimerTime == (uint)recipeToCook.CookTime) ? true : false;
SetAppearance(MicrowaveVisualState.Cooking); SetAppearance(MicrowaveVisualState.Cooking);
_audioSystem.Play(_startCookingSound); _audioSystem.Play(_startCookingSound, AudioParams.Default);
Timer.Spawn((int)(_currentCookTimerTime * _cookTimeMultiplier), () => Timer.Spawn((int)(_currentCookTimerTime * _cookTimeMultiplier), () =>
{ {
@@ -295,12 +290,12 @@ namespace Content.Server.GameObjects.Components.Kitchen
var entityToSpawn = goodMeal ? recipeToCook.Result : _badRecipeName; var entityToSpawn = goodMeal ? recipeToCook.Result : _badRecipeName;
_entityManager.SpawnEntity(entityToSpawn, Owner.Transform.GridPosition); _entityManager.SpawnEntity(entityToSpawn, Owner.Transform.GridPosition);
_audioSystem.Play(_cookingCompleteSound); _audioSystem.Play(_cookingCompleteSound, AudioParams.Default);
SetAppearance(MicrowaveVisualState.Idle); SetAppearance(MicrowaveVisualState.Idle);
_busy = false; _busy = false;
UpdateUserInterface();
}); });
UpdateUserInterface(); UpdateUserInterface();
return;
} }
private void VaporizeReagents() private void VaporizeReagents()
@@ -396,12 +391,12 @@ namespace Content.Server.GameObjects.Components.Kitchen
return true; return true;
} }
private void ClickSound() private void ClickSound()
{ {
_audioSystem.Play("/Audio/machines/machine_switch.ogg", AudioParams.Default.WithVolume(-2f)); _audioSystem.Play("/Audio/machines/machine_switch.ogg", AudioParams.Default.WithVolume(-2f));
} }
} }

View File

@@ -49,7 +49,7 @@ namespace Content.Server.GameObjects.Components
protected override void Activate(IEntity user, RotatableComponent component) protected override void Activate(IEntity user, RotatableComponent component)
{ {
component.TryRotate(user, Angle.FromDegrees(90)); component.TryRotate(user, Angle.FromDegrees(-90));
} }
} }
@@ -70,7 +70,7 @@ namespace Content.Server.GameObjects.Components
protected override void Activate(IEntity user, RotatableComponent component) protected override void Activate(IEntity user, RotatableComponent component)
{ {
component.TryRotate(user, Angle.FromDegrees(-90)); component.TryRotate(user, Angle.FromDegrees(90));
} }
} }

View File

@@ -28,12 +28,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
[Dependency] private readonly IPhysicsManager _physicsManager; [Dependency] private readonly IPhysicsManager _physicsManager;
#pragma warning restore 649 #pragma warning restore 649
private int _damage = 1; private int _damage;
private float _range = 1; private float _range;
private float _arcWidth = 90; private float _arcWidth;
private string _arc; private string _arc;
private string _hitSound; private string _hitSound;
private float _cooldownTime = 1f; private float _cooldownTime;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public string Arc public string Arc
@@ -122,9 +122,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
private HashSet<IEntity> ArcRayCast(Vector2 position, Angle angle, IEntity ignore) private HashSet<IEntity> ArcRayCast(Vector2 position, Angle angle, IEntity ignore)
{ {
// Maybe make this increment count depend on the width/length?
const int increments = 5;
var widthRad = Angle.FromDegrees(ArcWidth); var widthRad = Angle.FromDegrees(ArcWidth);
var increments = 1 + (35 * (int) Math.Ceiling(widthRad / (2 * Math.PI)));
var increment = widthRad / increments; var increment = widthRad / increments;
var baseAngle = angle - widthRad / 2; var baseAngle = angle - widthRad / 2;

View File

@@ -0,0 +1,248 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Robust.Shared.ViewVariables;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
using System.Linq;
using Content.Server.GameObjects.EntitySystems;
namespace Content.Server.BodySystem {
/// <summary>
/// Component representing the many BodyParts attached to each other.
/// </summary>
[RegisterComponent]
public class BodyManagerComponent : Component, IAttackHand {
public sealed override string Name => "BodyManager";
#pragma warning disable CS0649
[Dependency]
private IPrototypeManager _prototypeManager;
#pragma warning restore
[ViewVariables]
private BodyTemplate _template;
[ViewVariables]
private Dictionary<string, BodyPart> _partDictionary = new Dictionary<string, BodyPart>();
/// <summary>
/// The BodyTemplate that this BodyManagerComponent is adhering to.
/// </summary>
public BodyTemplate Template => _template;
/// <summary>
/// Maps BodyTemplate slot name to the BodyPart object filling it (if there is one).
/// </summary>
public Dictionary<string, BodyPart> PartDictionary => _partDictionary;
/// <summary>
/// List of all BodyParts in this body, taken from the keys of _parts.
/// </summary>
public IEnumerable<BodyPart> Parts
{
get
{
return _partDictionary.Values;
}
}
/// <summary>
/// Recursive search that returns whether a given BodyPart is connected to the center BodyPart. Not efficient (O(n^2)), but most bodies don't have a ton of BodyParts.
/// </summary>
protected bool ConnectedToCenterPart(BodyPart target)
{
List<string> searchedSlots = new List<string> { };
if (TryGetSlotName(target, out string result))
return false;
return ConnectedToCenterPartRecursion(searchedSlots, result);
}
protected bool ConnectedToCenterPartRecursion(List<string> searchedSlots, string slotName)
{
TryGetBodyPart(slotName, out BodyPart part);
if (part == GetCenterBodyPart())
return true;
searchedSlots.Add(slotName);
if (TryGetBodyPartConnections(slotName, out List<string> connections))
{
foreach (string connection in connections)
{
if (!searchedSlots.Contains(connection) && ConnectedToCenterPartRecursion(searchedSlots, connection))
return true;
}
}
return false;
}
/// <summary>
/// Returns the central BodyPart of this body based on the BodyTemplate. For humans, this is the torso. Returns null if not found.
/// </summary>
protected BodyPart GetCenterBodyPart()
{
_partDictionary.TryGetValue(_template.CenterSlot, out BodyPart center);
return center;
}
/// <summary>
/// Grabs the BodyPart in the given slotName if there is one. Returns true if a BodyPart is found, false otherwise. If false, result will be null.
/// </summary>
protected bool TryGetBodyPart(string slotName, out BodyPart result)
{
return _partDictionary.TryGetValue(slotName, out result);
}
/// <summary>
/// Grabs the slotName that the given BodyPart resides in. Returns true if the BodyPart is part of this body, false otherwise. If false, result will be null.
/// </summary>
protected bool TryGetSlotName(BodyPart part, out string result)
{
result = _partDictionary.FirstOrDefault(x => x.Value == part).Key; //We enforce that there is only one of each value in the dictionary, so we can iterate through the dictionary values to get the key from there.
return result == null;
}
/// <summary>
/// Grabs the names of all connected slots to the given slotName from the template. Returns true if connections are found to the slotName, false otherwise. If false, connections will be null.
/// </summary>
protected bool TryGetBodyPartConnections(string slotName, out List<string> connections)
{
return _template.Connections.TryGetValue(slotName, out connections);
}
/////////
///////// Server-specific stuff
/////////
public bool AttackHand(AttackHandEventArgs eventArgs)
{
//TODO: remove organs?
return false;
}
public override void ExposeData(ObjectSerializer serializer) {
base.ExposeData(serializer);
string templateName = "";
serializer.DataField(ref templateName, "BaseTemplate", "bodyTemplate.Humanoid");
if (serializer.Reading)
{
if (!_prototypeManager.TryIndex(templateName, out BodyTemplatePrototype templateData))
throw new InvalidOperationException("No BodyTemplatePrototype was found with the name " + templateName + " while loading a BodyTemplate!"); //Should never happen unless you fuck up the prototype.
string presetName = "";
serializer.DataField(ref presetName, "BasePreset", "bodyPreset.BasicHuman");
if (!_prototypeManager.TryIndex(presetName, out BodyPresetPrototype presetData))
throw new InvalidOperationException("No BodyPresetPrototype was found with the name " + presetName + " while loading a BodyPreset!"); //Should never happen unless you fuck up the prototype.
_template = new BodyTemplate(templateData);
LoadBodyPreset(new BodyPreset(presetData));
}
}
/// <summary>
/// Loads the given preset - forcefully changes all limbs found in both the preset and this template!
/// </summary>
public void LoadBodyPreset(BodyPreset preset)
{
foreach (var (slotName, type) in _template.Slots)
{
if (!preset.PartIDs.TryGetValue(slotName, out string partID))
{ //For each slot in our BodyManagerComponent's template, try and grab what the ID of what the preset says should be inside it.
continue; //If the preset doesn't define anything for it, continue.
}
if (!_prototypeManager.TryIndex(partID, out BodyPartPrototype newPartData))
{ //Get the BodyPartPrototype corresponding to the BodyPart ID we grabbed.
throw new InvalidOperationException("BodyPart prototype with ID " + partID + " could not be found!");
}
_partDictionary.Remove(slotName); //Try and remove an existing limb if that exists.
_partDictionary.Add(slotName, new BodyPart(newPartData)); //Add a new BodyPart with the BodyPartPrototype as a baseline to our BodyComponent.
}
}
/// <summary>
/// Changes the current BodyTemplate to the new BodyTemplate. Attempts to keep previous BodyParts if there is a slot for them in both BodyTemplates.
/// </summary>
public void ChangeBodyTemplate(BodyTemplatePrototype newTemplate)
{
foreach (KeyValuePair<string, BodyPart> part in _partDictionary)
{
//TODO: Make this work.
}
}
/// <summary>
/// Grabs all limbs of the given type in this body.
/// </summary>
public List<BodyPart> GetBodyPartsOfType(BodyPartType type)
{
List<BodyPart> toReturn = new List<BodyPart>();
foreach (var (slotName, bodyPart) in _partDictionary)
{
if (bodyPart.PartType == type)
toReturn.Add(bodyPart);
}
return toReturn;
}
/// <summary>
/// Disconnects the given BodyPart reference, potentially dropping other BodyParts if they were hanging off it.
/// </summary>
public void DisconnectBodyPart(BodyPart part, bool dropEntity)
{
if (!_partDictionary.ContainsValue(part))
return;
if (part != null)
{
string slotName = _partDictionary.FirstOrDefault(x => x.Value == part).Key;
if (TryGetBodyPartConnections(slotName, out List<string> connections)) //Call disconnect on all limbs that were hanging off this limb.
{
foreach (string connectionName in connections) //This loop is an unoptimized travesty. TODO: optimize to be less shit
{
if (TryGetBodyPart(connectionName, out BodyPart result) && !ConnectedToCenterPart(result))
{
DisconnectBodyPartByName(connectionName, dropEntity);
}
}
}
_partDictionary.Remove(slotName);
if (dropEntity)
{
var partEntity = Owner.EntityManager.SpawnEntity("BaseDroppedBodyPart", Owner.Transform.GridPosition);
partEntity.GetComponent<DroppedBodyPartComponent>().TransferBodyPartData(part);
}
}
}
/// <summary>
/// Internal string version of DisconnectBodyPart for performance purposes.
/// </summary>
private void DisconnectBodyPartByName(string name, bool dropEntity)
{
if (!TryGetBodyPart(name, out BodyPart part))
return;
if (part != null)
{
if (TryGetBodyPartConnections(name, out List<string> connections))
{
foreach (string connectionName in connections)
{
if (TryGetBodyPart(connectionName, out BodyPart result) && !ConnectedToCenterPart(result))
{
DisconnectBodyPartByName(connectionName, dropEntity);
}
}
}
_partDictionary.Remove(name);
if (dropEntity)
{
var partEntity = Owner.EntityManager.SpawnEntity("BaseDroppedBodyPart", Owner.Transform.GridPosition);
partEntity.GetComponent<DroppedBodyPartComponent>().TransferBodyPartData(part);
}
}
}
}
}

View File

@@ -0,0 +1,226 @@
using Content.Shared.BodySystem;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using System;
using System.Collections.Generic;
namespace Content.Server.BodySystem
{
/// <summary>
/// Data class representing a singular limb such as an arm or a leg. Typically held within a BodyManagerComponent,
/// which coordinates functions between BodyParts.
/// </summary>
public class BodyPart
{
[ViewVariables]
private ISurgeryData _surgeryData;
[ViewVariables]
private List<Mechanism> _mechanisms = new List<Mechanism>();
[ViewVariables]
private int _sizeUsed = 0;
/// <summary>
/// Body part name.
/// </summary>
[ViewVariables]
public string Name { get; set; }
/// <summary>
/// Plural version of this body part's name.
/// </summary>
[ViewVariables]
public string Plural { get; set; }
/// <summary>
/// Path to the RSI that represents this BodyPart.
/// </summary>
[ViewVariables]
public string RSIPath { get; set; }
/// <summary>
/// RSI state that represents this BodyPart.
/// </summary>
[ViewVariables]
public string RSIState { get; set; }
/// <summary>
/// BodyPartType that this body part is considered.
/// </summary>
[ViewVariables]
public BodyPartType PartType { get; set; }
/// <summary>
/// Max HP of this body part.
/// </summary>
[ViewVariables]
public int MaxDurability { get; set; }
/// <summary>
/// Current HP of this body part based on sum of all damage types.
/// </summary>
[ViewVariables]
public int CurrentDurability => MaxDurability - CurrentDamages.Damage;
/// <summary>
/// Current damage dealt to this BodyPart.
/// </summary>
[ViewVariables]
public AbstractDamageContainer CurrentDamages { get; set; }
/// <summary>
/// At what HP this body part is completely destroyed.
/// </summary>
[ViewVariables]
public int DestroyThreshold { get; set; }
/// <summary>
/// Armor of the body part against attacks.
/// </summary>
[ViewVariables]
public float Resistance { get; set; }
/// <summary>
/// Determines many things: how many mechanisms can be fit inside a body part, fitting through tiny crevices, etc.
/// </summary>
[ViewVariables]
public int Size { get; set; }
/// <summary>
/// What types of body parts this body part can attach to. For the most part, most limbs aren't universal and require extra work to attach between types.
/// </summary>
[ViewVariables]
public BodyPartCompatibility Compatibility { get; set; }
/// <summary>
/// List of IExposeData properties, allowing for additional data classes to be attached to a limb, such as a "length" class to an arm.
/// </summary>
[ViewVariables]
public List<IExposeData> Properties { get; set; }
/// <summary>
/// List of all Mechanisms currently inside this BodyPart.
/// </summary>
[ViewVariables]
public List<Mechanism> Mechanisms => _mechanisms;
public BodyPart(){}
public BodyPart(BodyPartPrototype data)
{
LoadFromPrototype(data);
}
/// <summary>
/// Attempts to add a Mechanism. Returns true if successful, false if there was an error (e.g. not enough room in BodyPart). Use InstallDroppedMechanism if you want to easily install an IEntity with a DroppedMechanismComponent.
/// </summary>
public bool InstallMechanism(Mechanism mechanism)
{
if (_sizeUsed + mechanism.Size > Size)
return false; //No space
_mechanisms.Add(mechanism);
_sizeUsed += mechanism.Size;
return true;
}
/// <summary>
/// Attempts to install a DroppedMechanismComponent into the given limb, potentially deleting the dropped IEntity. Returns true if successful, false if there was an error (e.g. not enough room in BodyPart).
/// </summary>
public bool InstallDroppedMechanism(DroppedMechanismComponent droppedMechanism)
{
if (_sizeUsed + droppedMechanism.ContainedMechanism.Size > Size)
return false; //No space
InstallMechanism(droppedMechanism.ContainedMechanism);
droppedMechanism.Owner.Delete();
return true;
}
/// <summary>
/// Tries to remove the given Mechanism reference from the given BodyPart reference. Returns null if there was an error in spawning the entity or removing the mechanism, otherwise returns a reference to the DroppedMechanismComponent on the newly spawned entity.
/// </summary>
public DroppedMechanismComponent DropMechanism(IEntity dropLocation, Mechanism mechanismTarget)
{
if (!_mechanisms.Contains(mechanismTarget))
return null;
_mechanisms.Remove(mechanismTarget);
_sizeUsed -= mechanismTarget.Size;
IEntityManager entityManager = IoCManager.Resolve<IEntityManager>();
var mechanismEntity = entityManager.SpawnEntity("BaseDroppedMechanism", dropLocation.Transform.GridPosition);
var droppedMechanism = mechanismEntity.GetComponent<DroppedMechanismComponent>();
droppedMechanism.InitializeDroppedMechanism(mechanismTarget);
return droppedMechanism;
}
/// <summary>
/// Tries to destroy the given Mechanism in the given BodyPart. Returns false if there was an error, true otherwise. Does NOT spawn a dropped entity.
/// </summary>
public bool DestroyMechanism(BodyPart bodyPartTarget, Mechanism mechanismTarget)
{
if (!_mechanisms.Contains(mechanismTarget))
return false;
_mechanisms.Remove(mechanismTarget);
_sizeUsed -= mechanismTarget.Size;
return true;
}
/// <summary>
/// Returns whether the given SurgertToolType can be used on the current state of this BodyPart (e.g.
/// </summary>
public bool SurgeryCheck(SurgeryToolType toolType)
{
return _surgeryData.CheckSurgery(toolType);
}
/// <summary>
/// Attempts to perform surgery on this BodyPart with the given tool. Returns false if there was an error, true if successful.
/// </summary>
public bool AttemptSurgery(SurgeryToolType toolType, BodyManagerComponent target, IEntity performer)
{
return _surgeryData.PerformSurgery(toolType, target, performer);
}
/// <summary>
/// Loads the given BodyPartPrototype - current data on this BodyPart will be overwritten!
/// </summary>
public virtual void LoadFromPrototype(BodyPartPrototype data)
{
Name = data.Name;
Plural = data.Plural;
PartType = data.PartType;
RSIPath = data.RSIPath;
RSIState = data.RSIState;
MaxDurability = data.Durability;
CurrentDamages = new BiologicalDamageContainer();
Resistance = data.Resistance;
Size = data.Size;
Compatibility = data.Compatibility;
Properties = data.Properties;
//_surgeryData = (ISurgeryData) Activator.CreateInstance(null, data.SurgeryDataName);
//TODO: figure out a way to convert a string name in the YAML to the proper class (reflection won't work for reasons)
_surgeryData = new BiologicalSurgeryData(this);
IPrototypeManager prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (string mechanismPrototypeID in data.Mechanisms)
{
if (!prototypeManager.TryIndex(mechanismPrototypeID, out MechanismPrototype mechanismData))
{
throw new InvalidOperationException("No MechanismPrototype was found with the name " + mechanismPrototypeID + " while loading a BodyPartPrototype!");
}
_mechanisms.Add(new Mechanism(mechanismData));
}
}
}
}

View File

@@ -0,0 +1,36 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Robust.Shared.ViewVariables;
using System.Globalization;
using Robust.Server.GameObjects;
namespace Content.Server.BodySystem {
/// <summary>
/// Component containing the data for a dropped BodyPart entity.
/// </summary>
[RegisterComponent]
public class DroppedBodyPartComponent : Component {
public sealed override string Name => "DroppedBodyPart";
[ViewVariables]
private BodyPart _containedBodyPart;
public void TransferBodyPartData(BodyPart data)
{
_containedBodyPart = data;
Owner.Name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_containedBodyPart.Name);
if (Owner.TryGetComponent<SpriteComponent>(out SpriteComponent component))
{
component.LayerSetRSI(0, data.RSIPath);
component.LayerSetState(0, data.RSIState);
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// Stores data on what BodyPart(Prototypes) should fill a BodyTemplate. Used for loading complete body presets, like a "basic human" with all human limbs.
/// </summary>
public class BodyPreset {
private string _name;
private Dictionary<string,string> _partIDs;
[ViewVariables]
public string Name => _name;
/// <summary>
/// Maps a template slot to the ID of the BodyPart that should fill it. E.g. "right arm" : "BodyPart.arm.basic_human".
/// </summary>
[ViewVariables]
public Dictionary<string, string> PartIDs => _partIDs;
public BodyPreset(BodyPresetPrototype data)
{
LoadFromPrototype(data);
}
public virtual void LoadFromPrototype(BodyPresetPrototype data)
{
_name = data.Name;
_partIDs = data.PartIDs;
}
}
}

View File

@@ -0,0 +1,71 @@
using Content.Server.GameObjects.EntitySystems;
using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Content.Shared.BodySystem;
namespace Content.Server.BodySystem
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
public class BodyScannerComponent : Component, IActivate
{
public sealed override string Name => "BodyScanner";
private BoundUserInterface _userInterface;
public override void Initialize()
{
base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(BodyScannerUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
{
}
void IActivate.Activate(ActivateEventArgs eventArgs)
{
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
{
return;
}
if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent attempt))
{
_userInterface.SetState(PrepareBodyScannerInterfaceState(attempt.Template, attempt.PartDictionary));
}
_userInterface.Open(actor.playerSession);
}
/// <summary>
/// Copy BodyTemplate and BodyPart data into a common data class that the client can read.
/// </summary>
private BodyScannerInterfaceState PrepareBodyScannerInterfaceState(BodyTemplate template, Dictionary<string, BodyPart> bodyParts)
{
Dictionary<string, BodyScannerBodyPartData> partsData = new Dictionary<string, BodyScannerBodyPartData>();
foreach (var(slotname, bpart) in bodyParts) {
List<BodyScannerMechanismData> mechanismData = new List<BodyScannerMechanismData>();
foreach (var mech in bpart.Mechanisms)
{
mechanismData.Add(new BodyScannerMechanismData(mech.Name, mech.Description, mech.RSIPath, mech.RSIState, mech.MaxDurability, mech.CurrentDurability));
}
partsData.Add(slotname, new BodyScannerBodyPartData(bpart.Name, bpart.RSIPath, bpart.RSIState, bpart.MaxDurability, bpart.CurrentDurability, mechanismData));
}
BodyScannerTemplateData templateData = new BodyScannerTemplateData(template.Name, template.Slots);
return new BodyScannerInterfaceState(partsData, templateData);
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// This class is a data capsule representing the standard format of a body. For instance, the "humanoid" BodyTemplate
/// defines two arms, each connected to a torso and so on. Capable of loading data from a BodyTemplatePrototype.
/// </summary>
public class BodyTemplate {
private int _hash;
private string _name;
private string _centerSlot;
private Dictionary<string, BodyPartType> _slots = new Dictionary<string, BodyPartType>();
private Dictionary<string, List<string>> _connections = new Dictionary<string, List<string>>();
[ViewVariables]
public int Hash => _hash;
[ViewVariables]
public string Name => _name;
/// <summary>
/// The name of the center BodyPart. For humans, this is set to "torso". Used in many calculations.
/// </summary>
[ViewVariables]
public string CenterSlot => _centerSlot;
/// <summary>
/// Maps all parts on this template to its BodyPartType. For instance, "right arm" is mapped to "BodyPartType.arm" on the humanoid template.
/// </summary>
[ViewVariables]
public Dictionary<string, BodyPartType> Slots => _slots;
/// <summary>
/// Maps limb name to the list of their connections to other limbs. For instance, on the humanoid template "torso" is mapped to a list containing "right arm", "left arm",
/// "left leg", and "right leg". Only one of the limbs in a connection has to map it, i.e. humanoid template chooses to map "head" to "torso" and not the other way around.
/// </summary>
[ViewVariables]
public Dictionary<string, List<string>> Connections => _connections;
public BodyTemplate()
{
_name = "empty";
}
public BodyTemplate(BodyTemplatePrototype data)
{
LoadFromPrototype(data);
}
/// <summary>
/// Somewhat costly operation. Stores an integer unique to this exact BodyTemplate in _hash when called.
/// </summary>
private void CacheHashCode()
{
int hash = 0;
foreach (var(key, value) in _slots)
{
hash = HashCode.Combine<int, int>(hash, key.GetHashCode());
}
foreach (var (key, value) in _connections)
{
hash = HashCode.Combine<int, int>(hash, key.GetHashCode());
foreach (var connection in value)
{
hash = HashCode.Combine<int, int>(hash, connection.GetHashCode());
}
}
_hash = hash;
}
public virtual void LoadFromPrototype(BodyTemplatePrototype data)
{
_name = data.Name;
_centerSlot = data.CenterSlot;
_slots = data.Slots;
_connections = data.Connections;
CacheHashCode();
}
}
}

View File

@@ -0,0 +1,45 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Robust.Shared.ViewVariables;
using System.Globalization;
using Robust.Server.GameObjects;
namespace Content.Server.BodySystem {
/// <summary>
/// Component containing the data for a dropped Mechanism entity.
/// </summary>
[RegisterComponent]
public class DroppedMechanismComponent : Component
{
#pragma warning disable CS0649
[Dependency]
private IPrototypeManager _prototypeManager;
#pragma warning restore
public sealed override string Name => "DroppedMechanism";
[ViewVariables]
private Mechanism _containedMechanism;
public Mechanism ContainedMechanism => _containedMechanism;
public void InitializeDroppedMechanism(Mechanism data)
{
_containedMechanism = data;
Owner.Name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_containedMechanism.Name);
if (Owner.TryGetComponent<SpriteComponent>(out SpriteComponent component))
{
component.LayerSetRSI(0, data.RSIPath);
component.LayerSetState(0, data.RSIState);
}
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Server.BodySystem {
/// <summary>
/// Data class representing a persistent item inside a BodyPart. This includes livers, eyes, cameras, brains, explosive implants, binary communicators, etc.
/// </summary>
public class Mechanism {
[ViewVariables]
public string Name { get; set; }
/// <summary>
/// Description shown in a mechanism installation console or when examining an uninstalled mechanism.
/// </summary>
[ViewVariables]
public string Description { get; set; }
/// <summary>
/// The message to display upon examining a mob with this mechanism installed. If the string is empty (""), no message will be displayed.
/// </summary>
[ViewVariables]
public string ExamineMessage { get; set; }
/// <summary>
/// Path to the RSI that represents this Mechanism.
/// </summary>
[ViewVariables]
public string RSIPath { get; set; }
/// <summary>
/// RSI state that represents this Mechanism.
/// </summary>
[ViewVariables]
public string RSIState { get; set; }
/// <summary>
/// Max HP of this mechanism.
/// </summary>
[ViewVariables]
public int MaxDurability { get; set; }
/// <summary>
/// Current HP of this mechanism.
/// </summary>
[ViewVariables]
public int CurrentDurability { get; set; }
/// <summary>
/// At what HP this mechanism is completely destroyed.
/// </summary>
[ViewVariables]
public int DestroyThreshold { get; set; }
/// <summary>
/// Armor of this mechanism against attacks.
/// </summary>
[ViewVariables]
public int Resistance { get; set; }
/// <summary>
/// Determines a handful of things - mostly whether this mechanism can fit into a BodyPart.
/// </summary>
[ViewVariables]
public int Size { get; set; }
/// <summary>
/// What kind of BodyParts this mechanism can be installed into.
/// </summary>
[ViewVariables]
public BodyPartCompatibility Compatibility { get; set; }
public Mechanism(MechanismPrototype data)
{
LoadFromPrototype(data);
}
/// <summary>
/// Loads the given MechanismPrototype - current data on this Mechanism will be overwritten!
/// </summary>
public void LoadFromPrototype(MechanismPrototype data)
{
Name = data.Name;
Description = data.Description;
ExamineMessage = data.ExamineMessage;
RSIPath = data.RSIPath;
RSIState = data.RSIState;
MaxDurability = data.Durability;
CurrentDurability = MaxDurability;
DestroyThreshold = data.DestroyThreshold;
Resistance = data.Resistance;
Size = data.Size;
Compatibility = data.Compatibility;
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using Content.Server.BodySystem;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.BodySystem;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.Player;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Weapon.Melee
{
[RegisterComponent]
public class ServerSurgeryToolComponent : SharedSurgeryToolComponent, IAfterAttack
{
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
[Dependency] private readonly IPhysicsManager _physicsManager;
#pragma warning restore 649
public HashSet<IPlayerSession> SubscribedSessions = new HashSet<IPlayerSession>();
private Dictionary<string, BodyPart> _surgeryOptionsCache = new Dictionary<string, BodyPart>();
private BodyManagerComponent _targetCache;
private IEntity _performerCache;
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
{
if (eventArgs.Attacked == null)
return;
if (eventArgs.Attacked.TryGetComponent<BodySystem.BodyManagerComponent>(out BodySystem.BodyManagerComponent bodyManager))
{
_surgeryOptionsCache.Clear();
var toSend = new Dictionary<string, string>();
foreach (var(key, value) in bodyManager.PartDictionary) {
if (value.SurgeryCheck(_surgeryToolClass))
{
_surgeryOptionsCache.Add(key, value);
toSend.Add(key, value.Name);
}
}
if (_surgeryOptionsCache.Count > 0)
{
OpenSurgeryUI(eventArgs.User);
UpdateSurgeryUI(eventArgs.User, toSend);
_performerCache = eventArgs.User;
_targetCache = bodyManager;
}
}
}
/// <summary>
/// Called after the user selects a surgery target.
/// </summary>
void PerformSurgery(SelectSurgeryUIMessage msg)
{
//TODO: sanity checks to see whether user is in range, body is still same, etc etc
if (!_surgeryOptionsCache.TryGetValue(msg.TargetSlot, out BodyPart target))
{
Logger.Debug("Error when trying to perform surgery on bodypart in slot " + msg.TargetSlot + ": it was not found!");
throw new InvalidOperationException();
}
if (!target.AttemptSurgery(_surgeryToolClass, _targetCache, _performerCache))
{
Logger.Debug("Error when trying to perform surgery on bodypart " + target.Name + "!");
throw new InvalidOperationException();
}
CloseSurgeryUI(_performerCache);
}
public void OpenSurgeryUI(IEntity character)
{
var user_session = character.GetComponent<BasicActorComponent>().playerSession;
SubscribeSession(user_session);
SendNetworkMessage(new OpenSurgeryUIMessage(), user_session.ConnectedClient);
}
public void UpdateSurgeryUI(IEntity character, Dictionary<string, string> options)
{
var user_session = character.GetComponent<BasicActorComponent>().playerSession;
if (user_session.AttachedEntity == null)
{
UnsubscribeSession(user_session);
return;
}
SendNetworkMessage(new UpdateSurgeryUIMessage(options), user_session.ConnectedClient);
}
public void CloseSurgeryUI(IEntity character)
{
var user_session = character.GetComponent<BasicActorComponent>().playerSession;
SubscribeSession(user_session);
SendNetworkMessage(new CloseSurgeryUIMessage(), user_session.ConnectedClient);
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, channel, session);
if (session == null)
{
throw new ArgumentException(nameof(session));
}
switch (message)
{
case CloseSurgeryUIMessage msg:
UnsubscribeSession(session as IPlayerSession);
break;
case SelectSurgeryUIMessage msg:
PerformSurgery(msg);
break;
}
}
public void SubscribeSession(IPlayerSession session)
{
if (!SubscribedSessions.Contains(session))
{
session.PlayerStatusChanged += HandlePlayerSessionChangeEvent;
SubscribedSessions.Add(session);
}
}
public void UnsubscribeSession(IPlayerSession session)
{
if (SubscribedSessions.Contains(session))
{
SubscribedSessions.Remove(session);
SendNetworkMessage(new CloseSurgeryUIMessage(), session.ConnectedClient);
}
}
public void HandlePlayerSessionChangeEvent(object obj, SessionStatusEventArgs SSEA)
{
if (SSEA.NewStatus != SessionStatus.InGame)
{
UnsubscribeSession(SSEA.Session);
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Content.Shared.Interfaces;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Server.BodySystem {
/// <summary>
/// Data class representing the surgery state of a biological entity.
/// </summary>
public class BiologicalSurgeryData : ISurgeryData {
protected bool _skinOpened = false;
protected bool _vesselsClamped = false;
protected bool _skinRetracted = false;
protected Mechanism _targetOrgan;
public BiologicalSurgeryData(BodyPart parent) : base(parent) { }
public override SurgeryAction GetSurgeryStep(SurgeryToolType toolType)
{
if (_skinOpened)
{
if (_vesselsClamped)
{
if (_skinRetracted)
{
if (_targetOrgan != null && toolType == SurgeryToolType.VesselCompression)
return RemoveOrganSurgery;
if (toolType == SurgeryToolType.Incision) //_targetOrgan is potentially given a value by DisconnectOrganSurgery.
return DisconnectOrganSurgery;
else if (toolType == SurgeryToolType.Cauterization)
return CautizerizeIncisionSurgery;
}
else
{
if (toolType == SurgeryToolType.Retraction)
return RetractSkinSurgery;
else if (toolType == SurgeryToolType.Cauterization)
return CautizerizeIncisionSurgery;
}
}
else
{
if (toolType == SurgeryToolType.VesselCompression)
return ClampVesselsSurgery;
else if (toolType == SurgeryToolType.Cauterization)
return CautizerizeIncisionSurgery;
}
}
else
{
if (toolType == SurgeryToolType.Incision)
return OpenSkinSurgery;
}
return null;
}
protected void OpenSkinSurgery(BodyManagerComponent target, IEntity performer)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Cut open the skin..."));
//Delay?
_skinOpened = true;
}
protected void ClampVesselsSurgery(BodyManagerComponent target, IEntity performer)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Clamp the vessels..."));
//Delay?
_vesselsClamped = true;
}
protected void RetractSkinSurgery(BodyManagerComponent target, IEntity performer)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Retract the skin..."));
//Delay?
_skinRetracted = true;
}
protected void CautizerizeIncisionSurgery(BodyManagerComponent target, IEntity performer)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Cauterize the incision..."));
//Delay?
_skinOpened = false;
_vesselsClamped = false;
_skinRetracted = false;
}
protected void DisconnectOrganSurgery(BodyManagerComponent target, IEntity performer)
{
Mechanism mechanismTarget = null;
//TODO: figureout popup, right now it just takes the first organ available if there is one
if (_parent.Mechanisms.Count > 0)
mechanismTarget = _parent.Mechanisms[0];
if (mechanismTarget != null)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Detach the organ..."));
//Delay?
_targetOrgan = mechanismTarget;
}
}
protected void RemoveOrganSurgery(BodyManagerComponent target, IEntity performer)
{
if (_targetOrgan != null)
{
ILocalizationManager localizationManager = IoCManager.Resolve<ILocalizationManager>();
performer.PopupMessage(performer, localizationManager.GetString("Remove the organ..."));
//Delay?
_parent.DropMechanism(performer, _targetOrgan);
}
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using Content.Shared.BodySystem;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Server.BodySystem {
/// <summary>
/// This data class represents the state of a BodyPart in regards to everything surgery related - whether there's an incision on it, whether the bone is broken, etc.
/// </summary>
public abstract class ISurgeryData {
/// <summary>
/// The BodyPart this surgeryData is attached to. The ISurgeryData class should not exist without a BodyPart that it represents, and will not work correctly without it.
/// </summary>
protected BodyPart _parent;
/// <summary>
/// The BodyPartType of the parent PartType.
/// </summary>
protected BodyPartType _parentType => _parent.PartType;
public delegate void SurgeryAction(BodyManagerComponent target, IEntity performer);
public ISurgeryData(BodyPart parent)
{
_parent = parent;
}
/// <summary>
/// Gets the delegate corresponding to the surgery step using the given SurgeryToolType. Returns null if no surgery step can be performed.
/// </summary>
public abstract SurgeryAction GetSurgeryStep(SurgeryToolType toolType);
/// <summary>
/// Returns whether the given SurgeryToolType can be used to perform a surgery.
/// </summary>
public bool CheckSurgery(SurgeryToolType toolType)
{
return GetSurgeryStep(toolType) != null;
}
/// <summary>
/// Attempts to perform surgery with the given tooltype. Returns whether the operation was successful.
/// </summary>
/// /// <param name="toolType">The SurgeryToolType used for this surgery.</param>
/// /// <param name="performer">The entity performing the surgery.</param>
public bool PerformSurgery(SurgeryToolType toolType, BodyManagerComponent target, IEntity performer)
{
SurgeryAction step = GetSurgeryStep(toolType);
if (step == null)
return false;
step(target, performer);
return true;
}
}
}

View File

@@ -36,15 +36,15 @@
public const uint GALACTIC_MARKET = 1031; public const uint GALACTIC_MARKET = 1031;
public const uint HUMANOID_APPEARANCE = 1032; public const uint HUMANOID_APPEARANCE = 1032;
public const uint INSTRUMENTS = 1033; public const uint INSTRUMENTS = 1033;
public const uint TOOL = 1034; public const uint WELDER = 1034;
public const uint WELDER = 1035; public const uint STACK = 1035;
public const uint STACK = 1036; public const uint HANDHELD_LIGHT = 1036;
public const uint HANDHELD_LIGHT = 1037; public const uint PAPER = 1037;
public const uint PAPER = 1038; public const uint REAGENT_INJECTOR = 1038;
public const uint REAGENT_INJECTOR = 1039; public const uint GHOST = 1039;
public const uint GHOST = 1040; public const uint MICROWAVE = 1040;
public const uint MICROWAVE = 1041; public const uint GRAVITY_GENERATOR = 1041;
public const uint GRAVITY_GENERATOR = 1042; public const uint SURGERY = 1042;
public const uint MULTITOOLS = 1043; public const uint MULTITOOLS = 1043;
} }
} }

View File

@@ -0,0 +1,17 @@

using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Serialization;
using System;
namespace Content.Shared.BodySystem {
[NetSerializable, Serializable]
class ArmLength : IExposeData {
private float _length;
public void ExposeData(ObjectSerializer serializer){
serializer.DataField(ref _length, "length", 2f);
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// Prototype for the BodyPart class.
/// </summary>
[Prototype("bodyPart")]
[NetSerializable, Serializable]
public class BodyPartPrototype : IPrototype, IIndexedPrototype {
private string _id;
private string _name;
private string _plural;
private string _rsiPath;
private string _rsiState;
private BodyPartType _partType;
private int _durability;
private int _destroyThreshold;
private float _resistance;
private int _size;
private BodyPartCompatibility _compatibility;
private string _surgeryDataName;
private List<IExposeData> _properties;
private List<string> _mechanisms;
[ViewVariables]
public string ID => _id;
[ViewVariables]
public string Name => _name;
[ViewVariables]
public string Plural => _plural;
[ViewVariables]
public string RSIPath => _rsiPath;
[ViewVariables]
public string RSIState => _rsiState;
[ViewVariables]
public BodyPartType PartType => _partType;
[ViewVariables]
public int Durability => _durability;
[ViewVariables]
public int DestroyThreshold => _destroyThreshold;
[ViewVariables]
public float Resistance => _resistance;
[ViewVariables]
public int Size => _size;
[ViewVariables]
public BodyPartCompatibility Compatibility => _compatibility;
[ViewVariables]
public string SurgeryDataName => _surgeryDataName;
[ViewVariables]
public List<IExposeData> Properties => _properties;
[ViewVariables]
public List<string> Mechanisms => _mechanisms;
public virtual void LoadFrom(YamlMappingNode mapping){
var serializer = YamlObjectSerializer.NewReader(mapping);
serializer.DataField(ref _name, "name", string.Empty);
serializer.DataField(ref _id, "id", string.Empty);
serializer.DataField(ref _plural, "plural", string.Empty);
serializer.DataField(ref _rsiPath, "rsiPath", string.Empty);
serializer.DataField(ref _rsiState, "rsiState", string.Empty);
serializer.DataField(ref _partType, "partType", BodyPartType.Other);
serializer.DataField(ref _surgeryDataName, "surgeryDataType", "BiologicalSurgeryData");
serializer.DataField(ref _durability, "durability", 50);
serializer.DataField(ref _destroyThreshold, "destroyThreshold", -50);
serializer.DataField(ref _resistance, "resistance", 0f);
serializer.DataField(ref _size, "size", 0);
serializer.DataField(ref _compatibility, "compatibility", BodyPartCompatibility.Universal);
serializer.DataField(ref _properties, "properties", new List<IExposeData>());
serializer.DataField(ref _mechanisms, "mechanisms", new List<string>());
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// Prototype for the BodyPreset class.
/// </summary>
[Prototype("bodyPreset")]
[NetSerializable, Serializable]
public class BodyPresetPrototype : IPrototype, IIndexedPrototype {
private string _id;
private string _name;
private Dictionary<string,string> _partIDs;
[ViewVariables]
public string ID => _id;
[ViewVariables]
public string Name => _name;
[ViewVariables]
public Dictionary<string, string> PartIDs => _partIDs;
public virtual void LoadFrom(YamlMappingNode mapping){
var serializer = YamlObjectSerializer.NewReader(mapping);
serializer.DataField(ref _id, "id", string.Empty);
serializer.DataField(ref _name, "name", string.Empty);
serializer.DataField(ref _partIDs, "partIDs", new Dictionary<string, string>());
}
}
}

View File

@@ -0,0 +1,89 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Content.Shared.BodySystem
{
[NetSerializable, Serializable]
public enum BodyScannerUiKey
{
Key
}
[NetSerializable, Serializable]
public class BodyScannerInterfaceState : BoundUserInterfaceState
{
public readonly Dictionary<string, BodyScannerBodyPartData> Parts;
public readonly BodyScannerTemplateData Template;
public BodyScannerInterfaceState(Dictionary<string, BodyScannerBodyPartData> parts, BodyScannerTemplateData template)
{
Template = template;
Parts = parts;
}
}
[NetSerializable, Serializable]
public class BodyScannerBodyPartData
{
public readonly string Name;
public readonly string RSIPath;
public readonly string RSIState;
public readonly int MaxDurability;
public readonly int CurrentDurability;
public readonly List<BodyScannerMechanismData> Mechanisms;
public BodyScannerBodyPartData(string name, string rsiPath, string rsiState, int maxDurability, int currentDurability, List<BodyScannerMechanismData> mechanisms)
{
Name = name;
RSIPath = rsiPath;
RSIState = rsiState;
MaxDurability = maxDurability;
CurrentDurability = currentDurability;
Mechanisms = mechanisms;
}
}
[NetSerializable, Serializable]
public class BodyScannerMechanismData
{
public readonly string Name;
public readonly string Description;
public readonly string RSIPath;
public readonly string RSIState;
public readonly int MaxDurability;
public readonly int CurrentDurability;
public BodyScannerMechanismData(string name, string description, string rsiPath, string rsiState, int maxDurability, int currentDurability)
{
Name = name;
Description = description;
RSIPath = rsiPath;
RSIState = rsiState;
MaxDurability = maxDurability;
CurrentDurability = currentDurability;
}
}
[NetSerializable, Serializable]
public class BodyScannerTemplateData
{
public readonly string Name;
public readonly Dictionary<string, BodyPartType> Slots;
public BodyScannerTemplateData(string name, Dictionary<string, BodyPartType> slots)
{
Name = name;
Slots = slots;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// Prototype for the BodyTemplate class.
/// </summary>
[Prototype("bodyTemplate")]
[NetSerializable, Serializable]
public class BodyTemplatePrototype : IPrototype, IIndexedPrototype {
private string _id;
private string _name;
private string _centerSlot;
private Dictionary<string, BodyPartType> _slots;
private Dictionary<string, List<string>> _connections;
[ViewVariables]
public string ID => _id;
[ViewVariables]
public string Name => _name;
[ViewVariables]
public string CenterSlot => _centerSlot;
[ViewVariables]
public Dictionary<string, BodyPartType> Slots => _slots;
[ViewVariables]
public Dictionary<string, List<string>> Connections => _connections;
public virtual void LoadFrom(YamlMappingNode mapping){
var serializer = YamlObjectSerializer.NewReader(mapping);
serializer.DataField(ref _name, "name", string.Empty);
serializer.DataField(ref _id, "id", string.Empty);
serializer.DataField(ref _centerSlot, "centerSlot", string.Empty);
serializer.DataField(ref _slots, "slots", new Dictionary<string, BodyPartType>());
serializer.DataField(ref _connections, "connections", new Dictionary<string, List<string>>());
//Our prototypes don't force the user to define a BodyPart connection twice. E.g. Head: Torso v.s. Torso: Head.
//The user only has to do one. We want it to be that way in the code, though, so this cleans that up.
Dictionary<string, List<string>> cleanedConnections = new Dictionary<string, List<string>>();
foreach (var (targetSlotName, slotType) in _slots)
{
List<string> tempConnections = new List<string>();
foreach (var (slotName, slotConnections) in _connections)
{
if (slotName == targetSlotName){
foreach (string connection in slotConnections) {
if (!tempConnections.Contains(connection))
tempConnections.Add(connection);
}
}
else if (slotConnections.Contains(slotName))
{
tempConnections.Add(slotName);
}
}
if(tempConnections.Count > 0)
cleanedConnections.Add(targetSlotName, tempConnections);
}
_connections = cleanedConnections;
}
}
}

View File

@@ -0,0 +1,9 @@

namespace Content.Shared.BodySystem
{
public enum BodyPartCompatibility { Mechanical, Biological, Universal };
public enum BodyPartType { Other, Torso, Head, Arm, Hand, Leg, Foot };
public enum SurgeryToolType { Incision, Retraction, Cauterization, VesselCompression, Drilling, BoneSawing, Amputation }
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
/// <summary>
/// Prototype for the Mechanism class.
/// </summary>
[Prototype("mechanism")]
[NetSerializable, Serializable]
public class MechanismPrototype : IPrototype, IIndexedPrototype {
private string _id;
private string _name;
private string _description;
private string _examineMessage;
private string _spritePath;
private string _rsiPath;
private string _rsiState;
private int _durability;
private int _destroyThreshold;
private int _resistance;
private int _size;
private BodyPartCompatibility _compatibility;
[ViewVariables]
public string ID => _id;
[ViewVariables]
public string Name => _name;
[ViewVariables]
public string Description => _description;
[ViewVariables]
public string ExamineMessage => _examineMessage;
[ViewVariables]
public string RSIPath => _rsiPath;
[ViewVariables]
public string RSIState => _rsiState;
[ViewVariables]
public int Durability => _durability;
[ViewVariables]
public int DestroyThreshold => _destroyThreshold;
[ViewVariables]
public int Resistance => _resistance;
[ViewVariables]
public int Size => _size;
[ViewVariables]
public BodyPartCompatibility Compatibility => _compatibility;
public virtual void LoadFrom(YamlMappingNode mapping){
var serializer = YamlObjectSerializer.NewReader(mapping);
serializer.DataField(ref _id, "id", string.Empty);
serializer.DataField(ref _name, "name", string.Empty);
serializer.DataField(ref _description, "description", string.Empty);
serializer.DataField(ref _examineMessage, "examineMessage", string.Empty);
serializer.DataField(ref _rsiPath, "rsiPath", string.Empty);
serializer.DataField(ref _rsiState, "rsiState", string.Empty);
serializer.DataField(ref _durability, "durability", 0);
serializer.DataField(ref _destroyThreshold, "destroyThreshold", 0);
serializer.DataField(ref _resistance, "resistance", 0);
serializer.DataField(ref _size, "size", 2);
serializer.DataField(ref _compatibility, "compatibility", BodyPartCompatibility.Universal);
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.BodySystem {
public class SharedSurgeryToolComponent : Component {
protected SurgeryToolType _surgeryToolClass;
protected float _baseOperateTime;
public override string Name => "SurgeryTool";
public override uint? NetID => ContentNetIDs.SURGERY;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _surgeryToolClass, "surgeryToolClass", SurgeryToolType.Incision);
serializer.DataField(ref _baseOperateTime, "baseOperateTime", 5);
}
}
[Serializable, NetSerializable]
public class OpenSurgeryUIMessage : ComponentMessage
{
public OpenSurgeryUIMessage()
{
Directed = true;
}
}
[Serializable, NetSerializable]
public class CloseSurgeryUIMessage : ComponentMessage
{
public CloseSurgeryUIMessage()
{
Directed = true;
}
}
[Serializable, NetSerializable]
public class UpdateSurgeryUIMessage : ComponentMessage
{
public Dictionary<string, string> Targets;
public UpdateSurgeryUIMessage(Dictionary<string, string> targets)
{
Targets = targets;
Directed = true;
}
}
[Serializable, NetSerializable]
public class SelectSurgeryUIMessage : ComponentMessage
{
public string TargetSlot;
public SelectSurgeryUIMessage(string target)
{
TargetSlot = target;
}
}
}

View File

@@ -0,0 +1,107 @@
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Content.Shared.BodySystem
{
public enum DamageClass { Brute, Burn, Toxin, Airloss }
public enum DamageType { Blunt, Piercing, Heat, Disintegration, Cellular, DNA, Airloss }
public static class DamageContainerValues
{
public static readonly Dictionary<DamageClass, List<DamageType>> DamageClassToType = new Dictionary<DamageClass, List<DamageType>>
{
{ DamageClass.Brute, new List<DamageType>{ DamageType.Blunt, DamageType.Piercing }},
{ DamageClass.Burn, new List<DamageType>{ DamageType.Heat, DamageType.Disintegration }},
{ DamageClass.Toxin, new List<DamageType>{ DamageType.Cellular, DamageType.DNA}},
{ DamageClass.Airloss, new List<DamageType>{ DamageType.Airloss }}
};
public static readonly Dictionary<DamageType, DamageClass> DamageTypeToClass = new Dictionary<DamageType, DamageClass>
{
{ DamageType.Blunt, DamageClass.Brute },
{ DamageType.Piercing, DamageClass.Brute },
{ DamageType.Heat, DamageClass.Burn },
{ DamageType.Disintegration, DamageClass.Burn },
{ DamageType.Cellular, DamageClass.Toxin },
{ DamageType.DNA, DamageClass.Toxin },
{ DamageType.Airloss, DamageClass.Airloss }
};
}
/// <summary>
/// Abstract class for all damage container classes.
/// </summary>
[NetSerializable, Serializable]
public abstract class AbstractDamageContainer
{
[ViewVariables]
abstract public List<DamageClass> SupportedDamageClasses { get; }
private Dictionary<DamageType, int> _damageList = new Dictionary<DamageType, int>();
[ViewVariables]
public Dictionary<DamageType, int> DamageList => _damageList;
/// <summary>
/// Sum of all damages kept on record.
/// </summary>
[ViewVariables]
public int Damage
{
get
{
return _damageList.Sum(x => x.Value);
}
}
public AbstractDamageContainer()
{
foreach(DamageClass damageClass in SupportedDamageClasses){
DamageContainerValues.DamageClassToType.TryGetValue(damageClass, out List<DamageType> childrenDamageTypes);
foreach (DamageType damageType in childrenDamageTypes)
{
_damageList.Add(damageType, 0);
}
}
}
/// <summary>
/// Attempts to grab the damage value for the given DamageType - returns false if the container does not support that type.
/// </summary>
public bool TryGetDamageValue(DamageType type, out int damage)
{
return _damageList.TryGetValue(type, out damage);
}
/// <summary>
/// Attempts to set the damage value for the given DamageType - returns false if the container does not support that type.
/// </summary>
public bool TrySetDamageValue(DamageType type, int target)
{
DamageContainerValues.DamageTypeToClass.TryGetValue(type, out DamageClass classType);
if (SupportedDamageClasses.Contains(classType))
{
_damageList[type] = target;
return true;
}
return false;
}
/// <summary>
/// Attempts to change the damage value for the given DamageType - returns false if the container does not support that type.
/// </summary>
public bool TryChangeDamageValue(DamageType type, int delta)
{
DamageContainerValues.DamageTypeToClass.TryGetValue(type, out DamageClass classType);
if (SupportedDamageClasses.Contains(classType))
{
_damageList[type] = _damageList[type] + delta;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Content.Shared.BodySystem
{
[NetSerializable, Serializable]
public class BiologicalDamageContainer : AbstractDamageContainer
{
public override List<DamageClass> SupportedDamageClasses {
get { return new List<DamageClass> { DamageClass.Brute, DamageClass.Burn, DamageClass.Toxin, DamageClass.Airloss }; }
}
}
}

View File

@@ -41,7 +41,7 @@ namespace Content.Shared.Kitchen
EntityID = entityID; EntityID = entityID;
} }
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class MicrowaveVaporizeReagentIndexedMessage : BoundUserInterfaceMessage public class MicrowaveVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
{ {
@@ -70,10 +70,12 @@ namespace Content.Shared.Kitchen
{ {
public readonly IReadOnlyList<Solution.ReagentQuantity> ReagentsReagents; public readonly IReadOnlyList<Solution.ReagentQuantity> ReagentsReagents;
public readonly List<EntityUid> ContainedSolids; public readonly List<EntityUid> ContainedSolids;
public MicrowaveUpdateUserInterfaceState(IReadOnlyList<Solution.ReagentQuantity> reagents, List<EntityUid> solids) public bool IsMicrowaveBusy;
public MicrowaveUpdateUserInterfaceState(IReadOnlyList<Solution.ReagentQuantity> reagents, List<EntityUid> solids, bool busyStatus)
{ {
ReagentsReagents = reagents; ReagentsReagents = reagents;
ContainedSolids = solids; ContainedSolids = solids;
IsMicrowaveBusy = busyStatus;
} }
} }

View File

@@ -0,0 +1,102 @@
- type: bodyPart
id: bodyPart.Torso.BasicHuman
name: "human torso"
plural: "human torsos"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: "torso_m"
partType: Torso
durability: 100
destroyThreshold: -150
resistance: 4.0
size: 14
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType
mechanisms:
- mechanism.Heart.BasicHuman
- mechanism.Lungs.BasicHuman
- mechanism.Liver.BasicHuman
- mechanism.Kidneys.BasicHuman
- type: bodyPart
id: bodyPart.Head.BasicHuman
name: "human head"
plural: "human heads"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: head_m
partType: Head
durability: 50
destroyThreshold: -120
resistance: 7.0
size: 7
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType
mechanisms:
- mechanism.Brain.BasicHuman
- mechanism.Eyes.BasicHuman
- type: bodyPart
id: bodyPart.Arm.BasicHuman
name: "human arm"
plural: "human arms"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: r_arm
partType: Arm
durability: 40
destroyThreshold: -80
resistance: 3.0
size: 5
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType
properties:
- !type:ArmLength
length: 2.4
- type: bodyPart
id: bodyPart.Hand.BasicHuman
name: "human hand"
plural: "human hands"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: r_hand
partType: Hand
durability: 30
destroyThreshold: -60
resistance: 2.0
size: 3
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType
- type: bodyPart
id: bodyPart.Leg.BasicHuman
name: "human leg"
plural: "human legs"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: r_leg
partType: Leg
durability: 45
destroyThreshold: -90
resistance: 2.0
size: 6
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType
- type: bodyPart
id: bodyPart.Foot.BasicHuman
name: "human foot"
plural: "human feet"
rsiPath: Objects/BodySystem/BodyParts/basic_human.rsi
rsiState: r_foot
partType: Foot
durability: 30
destroyThreshold: -60
resistance: 3.0
size: 2
compatibility: Biological
surgeryDataType: BiologicalsurgeryDataType

View File

@@ -0,0 +1,15 @@
- type: bodyPreset
name: "basic human"
id: bodyPreset.BasicHuman
partIDs:
head: bodyPart.Head.BasicHuman
torso: bodyPart.Torso.BasicHuman
right arm: bodyPart.Arm.BasicHuman
left arm: bodyPart.Arm.BasicHuman
right hand: bodyPart.Hand.BasicHuman
left hand: bodyPart.Hand.BasicHuman
right leg: bodyPart.Leg.BasicHuman
left leg: bodyPart.Leg.BasicHuman
right foot: bodyPart.Foot.BasicHuman
left foot: bodyPart.Foot.BasicHuman

View File

@@ -0,0 +1,33 @@
- type: bodyTemplate
id: bodyTemplate.Humanoid
name: "humanoid"
centerSlot: "torso"
slots:
head: Head
torso: Torso
left arm: Arm
left hand: Hand
right arm: Arm
right hand: Hand
left leg: Leg
left foot: Foot
right leg: Leg
right foot: Foot
connections:
head:
- torso
torso:
- left arm
- right arm
- left leg
- right leg
left arm:
- left hand
right arm:
- right hand
left leg:
- left foot
right leg:
- right foot

View File

@@ -0,0 +1,33 @@
- type: bodyTemplate
id: bodyTemplate.Quadrupedal
name: "Quadrupedal"
centerSlot: "torso"
slots:
head: Head
torso: Torso
left front leg: Leg
left front paw: Foot
right front leg: Leg
right front paw: Foot
left hind leg: Leg
left hind paw: Foot
right hind leg: Leg
right hind paw: Foot
connections:
head:
- torso
torso:
- left front leg
- right front leg
- left hind leg
- right hind paw
left front leg:
- left front paw
right front leg:
- right front paw
left hind leg:
- left hind paw
right hind leg:
- right hind paw

View File

@@ -0,0 +1,59 @@
- type: mechanism
id: mechanism.Brain.BasicHuman
name: "Human Brain"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "brain_human"
description: "The source of incredible, unending intelligence. Honk."
durability: 10
size: 1
compatibility: Biological
- type: mechanism
id: mechanism.Eyes.BasicHuman
name: "Human Eyes"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "eyes_human"
description: "Ocular organ capable of turning light into a colorful visual."
durability: 10
size: 1
compatibility: Biological
- type: mechanism
id: mechanism.Heart.BasicHuman
name: "Human Heart"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "heart_human"
description: "Pumps blood throughout a body. Essential for any entity with blood."
durability: 10
size: 1
compatibility: Biological
- type: mechanism
id: mechanism.Lungs.BasicHuman
name: "Human Lungs"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "lungs_human"
description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier."
durability: 13
size: 1
compatibility: Biological
- type: mechanism
id: mechanism.Liver.BasicHuman
name: "Human Liver"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "liver_human"
description: "Filters impurities out of a bloodstream and provides other important functionality to a human."
durability: 15
size: 1
compatibility: Biological
- type: mechanism
id: mechanism.Kidneys.BasicHuman
name: "Human Kidneys"
rsiPath: Objects/BodySystem/Organs/basic_human.rsi
rsiState: "kidneys_human"
description: "Filters toxins out of a bloodstream."
durability: 20
size: 1
compatibility: Biological

View File

@@ -0,0 +1,20 @@
- type: mechanism
id: mechanism.EMPStriker
name: "EMP Striker"
description: "When activated, this arm implant will apply a small EMP on the target of a physical strike for 10 watts per use."
durability: 80
size: 4
compatibility: Universal
implantableParts:
- Arm
- Hand
- type: mechanism
id: mechanism.HonkModule
name: "HONK Module 3000"
description: "Mandatory implant for all clowns after the Genevo Convention of 2459."
durability: 50
size: 3
compatibility: Universal

View File

@@ -0,0 +1,128 @@
- type: entity
name: Scalpel
parent: BaseItem
id: scalpel
desc: A surgical tool used to make incisions into flesh.
components:
- type: SurgeryTool
surgeryToolClass: Incision
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: scalpel
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: scalpel
- type: ItemCooldown
- type: MeleeWeapon
- type: entity
name: Retractor
parent: BaseItem
id: retractor
desc: A surgical tool used to hold open incisions.
components:
- type: SurgeryTool
surgeryToolClass: Retraction
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: retractor
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: retractor
- type: ItemCooldown
- type: MeleeWeapon
- type: entity
name: Cautery
parent: BaseItem
id: cautery
desc: A surgical tool used to cauterize open wounds.
components:
- type: SurgeryTool
surgeryToolClass: Cauterization
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: cautery
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: cautery
- type: ItemCooldown
- type: MeleeWeapon
- type: entity
name: Drill
parent: BaseItem
id: drill
desc: A surgical drill for making holes into hard material.
components:
- type: SurgeryTool
surgeryToolClass: Drilling
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: drill
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: drill
- type: ItemCooldown
- type: MeleeWeapon
- type: entity
name: Bone Saw
parent: BaseItem
id: bone_saw
desc: A surgical tool used to cauterize open wounds.
components:
- type: SurgeryTool
surgeryToolClass: BoneSawing
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: bone_saw
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: bone_saw
- type: ItemCooldown
- type: MeleeWeapon
- type: entity
name: Hemostat
parent: BaseItem
id: hemostat
desc: A surgical tool used to compress blood vessels to prevent bleeding.
components:
- type: SurgeryTool
surgeryToolClass: VesselCompression
baseOperateTime: 3
- type: Sprite
sprite: Objects/Surgery/surgery_tools.rsi
state: hemostat
- type: Icon
sprite: Objects/Surgery/surgery_tools.rsi
state: hemostat
- type: ItemCooldown
- type: MeleeWeapon

View File

@@ -0,0 +1,19 @@
- type: entity
name: "BaseDroppedBodyPart"
parent: BaseItem
id: BaseDroppedBodyPart
components:
- type: DroppedBodyPart
- type: Sprite
texture: Objects\BodySystem\Organs\eyes_grey.png
- type: Icon
- type: entity
name: "BaseDroppedMechanism"
parent: BaseItem
id: BaseDroppedMechanism
components:
- type: DroppedMechanism
- type: Sprite
texture: Objects\BodySystem\Organs\eyes_grey.png
- type: Icon

View File

@@ -165,7 +165,23 @@
- type: ComputerVisualizer2D - type: ComputerVisualizer2D
key: id_key key: id_key
screen: id screen: id
- type: entity
id: computerBodyScanner
parent: ComputerBase
name: Body Scanner Computer
components:
- type: BodyScanner
- type: UserInterface
interfaces:
- key: enum.BodyScannerUiKey.Key
type: BodyScannerBoundUserInterface
- type: Appearance
visuals:
- type: ComputerVisualizer2D
key: generic_key
screen: generic
- type: entity - type: entity
id: ComputerComms id: ComputerComms
parent: ComputerBase parent: ComputerBase

View File

@@ -35,10 +35,10 @@
- type: Instrument - type: Instrument
program: 1 program: 1
- type: Sprite - type: Sprite
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: piano state: piano
- type: Icon - type: Icon
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: piano state: piano
- type: entity - type: entity
@@ -49,10 +49,10 @@
- type: Instrument - type: Instrument
program: 7 program: 7
- type: Sprite - type: Sprite
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: minimoog state: minimoog
- type: Icon - type: Icon
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: minimoog state: minimoog
- type: entity - type: entity
@@ -63,8 +63,8 @@
- type: Instrument - type: Instrument
program: 13 program: 13
- type: Sprite - type: Sprite
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: xylophone state: xylophone
- type: Icon - type: Icon
sprite: Objects/Instruments/musician.rsi sprite: Objects/Instruments/otherinstruments.rsi
state: xylophone state: xylophone

View File

@@ -28,8 +28,9 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholdvalue: 50 thresholdvalue: 50
spawnondestroy: TableParts spawnondestroy: SteelSheet1
# TODO: drop wood instead of steel when destroyed when that's added
- type: entity - type: entity
id: TableWood id: TableWood
parent: Table parent: Table
@@ -41,4 +42,4 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholdvalue: 50 thresholdvalue: 50
spawnondestroy: TableParts spawnondestroy: SteelSheet1

View File

@@ -6,7 +6,6 @@
- type: Clothing - type: Clothing
Slots: [belt] Slots: [belt]
- type: entity - type: entity
parent: BeltBase parent: BeltBase
id: UtilityBeltClothing id: UtilityBeltClothing
@@ -14,15 +13,15 @@
description: Belt for holding all your usual tools description: Belt for holding all your usual tools
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/belt_utility.rsi sprite: Clothing/Belts/belt_utility.rsi
state: utilitybelt state: utilitybelt
- type: Icon - type: Icon
sprite: Clothing/belt_utility.rsi sprite: Clothing/Belts/belt_utility.rsi
state: utilitybelt state: utilitybelt
- type: Clothing - type: Clothing
Size: 50 Size: 50
QuickEquip: false QuickEquip: false
sprite: Clothing/belt_utility.rsi sprite: Clothing/Belts/belt_utility.rsi
- type: Storage - type: Storage
Capacity: 40 # Full tool loadout is 35, plus an extra Capacity: 40 # Full tool loadout is 35, plus an extra
@@ -31,4 +30,20 @@
parent: UtilityBeltClothing parent: UtilityBeltClothing
components: components:
- type: UtilityBeltClothingFill - type: UtilityBeltClothingFill
- type: entity
parent: BeltBase
id: SuspendersClothing
name: Suspenders
description: For holding your pants up.
components:
- type: Sprite
sprite: Clothing/Belts/suspenders.rsi
state: icon
- type: Icon
sprite: Clothing/Belts/suspenders.rsi
state: icon
- type: Clothing
Size: 50
QuickEquip: false
sprite: Clothing/Belts/suspenders.rsi

View File

@@ -5,12 +5,12 @@
description: The radio to keep up to date in real time with fun onboard station activities description: The radio to keep up to date in real time with fun onboard station activities
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/headset.rsi sprite: Clothing/Earpieces/headset.rsi
state: headset state: headset
- type: Icon - type: Icon
sprite: Clothing/headset.rsi sprite: Clothing/Earpieces/headset.rsi
state: headset state: headset
- type: Clothing - type: Clothing
Slots: Slots:
- ears - ears
sprite: Clothing/headset.rsi sprite: Clothing/Earpieces/headset.rsi

View File

@@ -17,10 +17,10 @@
sprite: Clothing/meson_scanners.rsi sprite: Clothing/meson_scanners.rsi
state: meson state: meson
- type: Icon - type: Icon
sprite: Clothing/meson_scanners.rsi sprite: Clothing/Glasses/meson_scanners.rsi
state: meson state: meson
- type: Clothing - type: Clothing
sprite: Clothing/meson_scanners.rsi sprite: Clothing/Glasses/meson_scanners.rsi
- type: entity - type: entity
@@ -30,13 +30,13 @@
description: Useful both for security and cargonia description: Useful both for security and cargonia
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/sunglasses.rsi sprite: Clothing/Glasses/sunglasses.rsi
state: sunglasses state: sunglasses
- type: Icon - type: Icon
sprite: Clothing/sunglasses.rsi sprite: Clothing/Glasses/sunglasses.rsi
state: sunglasses state: sunglasses
- type: Clothing - type: Clothing
sprite: Clothing/sunglasses.rsi sprite: Clothing/Glasses/sunglasses.rsi
- type: entity - type: entity
parent: GlassesBase parent: GlassesBase
@@ -45,10 +45,10 @@
description: Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes. Often worn by budget security officers. description: Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes. Often worn by budget security officers.
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/sunglasses_sec.rsi sprite: Clothing/Glasses/sunglasses_sec.rsi
state: icon state: icon
- type: Icon - type: Icon
sprite: Clothing/sunglasses_sec.rsi sprite: Clothing/Glasses/sunglasses_sec.rsi
state: icon state: icon
- type: Clothing - type: Clothing
sprite: Clothing/sunglasses_sec.rsi sprite: Clothing/Glasses/sunglasses_sec.rsi

View File

@@ -766,6 +766,19 @@
- type: Clothing - type: Clothing
sprite: Clothing/Gloves/s_ninjan.rsi sprite: Clothing/Gloves/s_ninjan.rsi
- type: entity
parent: GlovesBase
id: GlovesWhite
name: White Gloves
description:
components:
- type: Sprite
sprite: Clothing/Gloves/white.rsi
- type: Icon
sprite: Clothing/Gloves/white.rsi
- type: Clothing
sprite: Clothing/Gloves/white.rsi
- type: entity - type: entity
parent: GlovesBase parent: GlovesBase
id: GlovesYellow id: GlovesYellow

View File

@@ -6,6 +6,20 @@
- type: Clothing - type: Clothing
Slots: [mask] Slots: [mask]
- type: entity
parent: MasksBase
id: OldGasMaskClothing
name: Old Gas Mask
description: An old, dusty mask. Yet still dutifully functional.
components:
- type: Sprite
sprite: Clothing/Masks/mask_gasalt.rsi
state: icon
- type: Icon
sprite: Clothing/Masks/mask_gasalt.rsi
state: icon
- type: Clothing
sprite: Clothing/Masks/mask_gasalt.rsi
- type: entity - type: entity
parent: MasksBase parent: MasksBase
@@ -14,14 +28,13 @@
description: Regulations require these to be stocked after the fourth coolant leak description: Regulations require these to be stocked after the fourth coolant leak
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/gas_mask.rsi sprite: Clothing/Masks/mask_gas.rsi
state: gas_mask state: icon
- type: Icon - type: Icon
sprite: Clothing/gas_mask.rsi sprite: Clothing/Masks/mask_gas.rsi
state: gas_mask state: icon
- type: Clothing - type: Clothing
sprite: Clothing/gas_mask.rsi sprite: Clothing/Masks/mask_gas.rsi
- type: entity - type: entity
parent: MasksBase parent: MasksBase
@@ -30,13 +43,13 @@
description: Might as well keep this on 24/7 description: Might as well keep this on 24/7
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/mask_breath.rsi sprite: Clothing/Masks/mask_breath.rsi
state: breath state: icon
- type: Icon - type: Icon
sprite: Clothing/mask_breath.rsi sprite: Clothing/Masks/mask_breath.rsi
state: breath state: icon
- type: Clothing - type: Clothing
sprite: Clothing/mask_breath.rsi sprite: Clothing/Masks/mask_breath.rsi
- type: entity - type: entity
parent: MasksBase parent: MasksBase
@@ -45,10 +58,40 @@
description: A true prankster's facial attire. A clown is incomplete without his wig and mask. description: A true prankster's facial attire. A clown is incomplete without his wig and mask.
components: components:
- type: Sprite - type: Sprite
sprite: Clothing/mask_clown.rsi sprite: Clothing/Masks/mask_clown.rsi
state: icon state: icon
- type: Icon - type: Icon
sprite: Clothing/mask_clown.rsi sprite: Clothing/Masks/mask_clown.rsi
state: icon state: icon
- type: Clothing - type: Clothing
sprite: Clothing/mask_clown.rsi sprite: Clothing/Masks/mask_clown.rsi
- type: entity
parent: MasksBase
id: MaskJoy
name: Joy Mask
description:
components:
- type: Sprite
sprite: Clothing/Masks/mask_joy.rsi
state: icon
- type: Icon
sprite: Clothing/Masks/mask_joy.rsi
state: icon
- type: Clothing
sprite: Clothing/Masks/mask_joy.rsi
- type: entity
parent: MasksBase
id: MaskMime
name: Mime Mask
description:
components:
- type: Sprite
sprite: Clothing/Masks/mask_mime.rsi
state: icon
- type: Icon
sprite: Clothing/Masks/mask_mime.rsi
state: icon
- type: Clothing
sprite: Clothing/Masks/mask_mime.rsi

View File

@@ -245,6 +245,23 @@
- type: Clothing - type: Clothing
sprite: Clothing/Uniforms/uniform_rd.rsi sprite: Clothing/Uniforms/uniform_rd.rsi
- type: entity
parent: UniformBase
id: UniformMime
name: Mime's Clothes
description: ...
components:
- type: Sprite
sprite: Clothing/Uniforms/uniform_mime.rsi
state: icon
- type: Icon
sprite: Clothing/Uniforms/uniform_mime.rsi
state: icon
- type: Clothing
sprite: Clothing/Uniforms/uniform_mime.rsi
- type: entity - type: entity
parent: UniformBase parent: UniformBase
id: UniformHoS id: UniformHoS

View File

@@ -19,9 +19,15 @@
- type: Instrument - type: Instrument
program: 2 program: 2
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/h_synthesizer.png sprite: Objects/Instruments/h_synthesizer.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/h_synthesizer.png sprite: Objects/Instruments/h_synthesizer.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/h_synthesizer.rsi
- type: entity - type: entity
name: Acoustic Guitar name: Acoustic Guitar
@@ -31,9 +37,14 @@
- type: Instrument - type: Instrument
program: 25 program: 25
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/guitar.png sprite: Objects/Instruments/guitar.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/guitar.png sprite: Objects/Instruments/guitar.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/guitar.rsi
- type: entity - type: entity
name: Violin name: Violin
@@ -43,9 +54,14 @@
- type: Instrument - type: Instrument
program: 40 program: 40
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/violin.png sprite: Objects/Instruments/violin.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/violin.png sprite: Objects/Instruments/violin.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/violin.rsi
- type: entity - type: entity
name: Trumpet name: Trumpet
@@ -55,9 +71,9 @@
- type: Instrument - type: Instrument
program: 56 program: 56
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/trumpet.png texture: Objects/Instruments/otherinstruments.rsi/trumpet.png
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/trumpet.png texture: Objects/Instruments/otherinstruments.rsi/trumpet.png
- type: entity - type: entity
name: Electric Guitar name: Electric Guitar
@@ -67,9 +83,14 @@
- type: Instrument - type: Instrument
program: 27 program: 27
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/eguitar.png sprite: Objects/Instruments/eguitar.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/eguitar.png sprite: Objects/Instruments/eguitar.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/eguitar.rsi
- type: entity - type: entity
name: Accordion name: Accordion
@@ -79,9 +100,14 @@
- type: Instrument - type: Instrument
program: 21 program: 21
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/accordion.png sprite: Objects/Instruments/accordion.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/accordion.png sprite: Objects/Instruments/accordion.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/accordion.rsi
- type: entity - type: entity
name: Harmonica name: Harmonica
@@ -91,9 +117,14 @@
- type: Instrument - type: Instrument
program: 22 program: 22
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/harmonica.png sprite: Objects/Instruments/harmonica.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/harmonica.png sprite: Objects/Instruments/harmonica.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/harmonica.rsi
- type: entity - type: entity
name: Recorder name: Recorder
@@ -103,9 +134,14 @@
- type: Instrument - type: Instrument
program: 74 program: 74
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/recorder.png sprite: Objects/Instruments/recorder.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/recorder.png sprite: Objects/Instruments/recorder.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/recorder.rsi
- type: entity - type: entity
name: Trombone name: Trombone
@@ -115,9 +151,14 @@
- type: Instrument - type: Instrument
program: 57 program: 57
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/trombone.png sprite: Objects/Instruments/trombone.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/trombone.png sprite: Objects/Instruments/trombone.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/trombone.rsi
- type: entity - type: entity
name: Saxophone name: Saxophone
@@ -127,9 +168,14 @@
- type: Instrument - type: Instrument
program: 67 program: 67
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/saxophone.png sprite: Objects/Instruments/saxophone.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/saxophone.png sprite: Objects/Instruments/saxophone.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/saxophone.rsi
- type: entity - type: entity
name: Glockenspiel name: Glockenspiel
@@ -139,6 +185,11 @@
- type: Instrument - type: Instrument
program: 9 program: 9
- type: Sprite - type: Sprite
texture: Objects/Instruments/musician.rsi/glockenspiel.png sprite: Objects/Instruments/glockenspiel.rsi
state: icon
- type: Icon - type: Icon
texture: Objects/Instruments/musician.rsi/glockenspiel.png sprite: Objects/Instruments/glockenspiel.rsi
state: icon
- type: Item
Size: 24
sprite: Objects/Instruments/glockenspiel.rsi

View File

@@ -13,7 +13,7 @@
- type: MeleeWeapon - type: MeleeWeapon
range: 1.5 range: 1.5
arcwidth: 10 arcwidth: 0
arc: spear arc: spear
- type: Item - type: Item

View File

@@ -1,17 +0,0 @@
- type: entity
name: Table Parts
parent: BaseItem
id: TableParts
description: Parts of a table.
components:
- type: Sprite
sprite: Objects/Parts/table_parts.rsi
state: icon
- type: Icon
sprite: Objects/Parts/table_parts.rsi
state: icon
- type: Item
Size: 25
sprite: Objects/Parts/table_parts.rsi

View File

@@ -110,6 +110,10 @@
- type: Species - type: Species
Template: Human Template: Human
HeatResistance: 323 HeatResistance: 323
- type: BodyManager
BaseTemplate: bodyTemplate.Humanoid
BasePreset: bodyPreset.BasicHuman
- type: StatusEffectsUI - type: StatusEffectsUI
- type: OverlayEffectsUI - type: OverlayEffectsUI
- type: HeatResistance - type: HeatResistance
@@ -235,3 +239,4 @@
- type: SpeciesVisualizer2D - type: SpeciesVisualizer2D
- type: HumanoidAppearance - type: HumanoidAppearance

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

View File

@@ -0,0 +1,38 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/tgstation",
"states": [
{
"name": "equipped-BELT",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
},
{
"name": "icon",
"directions": 1,
"delays": [
[
1
]
]
}
]
}

View File

Before

Width:  |  Height:  |  Size: 165 B

After

Width:  |  Height:  |  Size: 165 B

View File

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 298 B

View File

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 329 B

View File

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

View File

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 226 B

View File

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 226 B

View File

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 250 B

View File

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 207 B

View File

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

View File

@@ -0,0 +1,60 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "https://github.com/discordia-space/CEV-Eris/raw/cb5bda251807e38fe5eae6b1def12f0c243b4d0a/icons/inventory/hands/mob.dmi",
"states": [
{
"name": "equipped-HAND",
"directions": 4
},
{
"name": "icon",
"directions": 1,
"delays": [
[
1
]
]
},
{
"name": "inhand-left",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
},
{
"name": "inhand-right",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
}
]
}

View File

Before

Width:  |  Height:  |  Size: 378 B

After

Width:  |  Height:  |  Size: 378 B

View File

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1,38 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 9a3a3a180344460263e8df7ea2565128e07b86b5",
"states": [
{
"name": "icon",
"directions": 1,
"delays": [
[
1
]
]
},
{
"name": "equipped-MASK",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
}
]
}

View File

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 528 B

View File

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

View File

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 287 B

View File

Before

Width:  |  Height:  |  Size: 285 B

After

Width:  |  Height:  |  Size: 285 B

View File

Before

Width:  |  Height:  |  Size: 597 B

After

Width:  |  Height:  |  Size: 597 B

View File

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 444 B

View File

Before

Width:  |  Height:  |  Size: 355 B

After

Width:  |  Height:  |  Size: 355 B

View File

Before

Width:  |  Height:  |  Size: 360 B

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -8,7 +8,7 @@
"copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 9f4bd6e0d5e457b6a36f3c505a8194116a666d6f", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 9f4bd6e0d5e457b6a36f3c505a8194116a666d6f",
"states": [ "states": [
{ {
"name": "gas_mask", "name": "icon",
"directions": 1, "directions": 1,
"delays": [ [ 1.0 ] ] "delays": [ [ 1.0 ] ]
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

View File

@@ -0,0 +1,46 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/tgstation",
"states": [
{
"name": "icon",
"directions": 1,
"delays": [ [ 1.0 ] ]
},
{
"name": "equipped-MASK",
"directions": 4,
"delays": [
[ 1.0 ],
[ 1.0 ],
[ 1.0 ],
[ 1.0 ]
]
},
{
"name": "inhand-left",
"directions": 4,
"delays": [
[ 1.0 ],
[ 1.0 ],
[ 1.0 ],
[ 1.0 ]
]
},
{
"name": "inhand-right",
"directions": 4,
"delays": [
[ 1.0 ],
[ 1.0 ],
[ 1.0 ],
[ 1.0 ]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

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