diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index fb7d05835e..0c937fa2d0 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -86,6 +86,9 @@ + + + @@ -114,6 +117,8 @@ + + diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index d1c4affc94..5caf8bec12 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -28,11 +28,15 @@ using System; using Content.Client.Chat; using Content.Client.GameObjects.Components; using Content.Client.GameObjects.Components.Mobs; +using Content.Client.GameObjects.Components.Research; using Content.Client.GameObjects.Components.Sound; using Content.Client.Interfaces.Chat; +using Content.Client.Research; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components.Markers; +using Content.Shared.GameObjects.Components.Materials; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Research; using Robust.Client.Interfaces.UserInterface; using Robust.Shared.Log; @@ -72,7 +76,6 @@ namespace Content.Client factory.RegisterIgnore("Storeable"); - factory.RegisterIgnore("Material"); factory.RegisterIgnore("Stack"); factory.Register(); @@ -86,7 +89,10 @@ namespace Content.Client factory.Register(); factory.Register(); factory.Register(); + factory.Register(); factory.Register(); + factory.Register(); + factory.RegisterReference(); factory.RegisterReference(); @@ -114,6 +120,11 @@ namespace Content.Client factory.Register(); + factory.Register(); + factory.Register(); + + factory.RegisterReference(); + factory.Register(); factory.RegisterReference(); diff --git a/Content.Client/GameObjects/Components/Research/LatheBoundUserInterface.cs b/Content.Client/GameObjects/Components/Research/LatheBoundUserInterface.cs new file mode 100644 index 0000000000..c8fbeb063a --- /dev/null +++ b/Content.Client/GameObjects/Components/Research/LatheBoundUserInterface.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using Content.Client.Research; +using Content.Shared.GameObjects.Components.Research; +using Content.Shared.Research; +using Robust.Client.GameObjects.Components.UserInterface; +using Robust.Client.Interfaces.Graphics; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.ViewVariables; + +namespace Content.Client.GameObjects.Components.Research +{ + public class LatheBoundUserInterface : BoundUserInterface + { +#pragma warning disable CS0649 + [Dependency] + private IDisplayManager _displayManager; + [Dependency] + private IPrototypeManager _prototypeManager; +#pragma warning restore + [ViewVariables] + private LatheMenu menu; + [ViewVariables] + private LatheQueueMenu queueMenu; + + public MaterialStorageComponent Storage { get; private set; } + public SharedLatheComponent Lathe { get; private set; } + public LatheDatabaseComponent Database { get; private set; } + + [ViewVariables] + public Queue QueuedRecipes => _queuedRecipes; + private Queue _queuedRecipes = new Queue(); + + public LatheBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + SendMessage(new SharedLatheComponent.LatheSyncRequestMessage()); + } + + protected override void Open() + { + base.Open(); + IoCManager.InjectDependencies(this); + + if (!Owner.Owner.TryGetComponent(out MaterialStorageComponent storage) + || !Owner.Owner.TryGetComponent(out SharedLatheComponent lathe) + || !Owner.Owner.TryGetComponent(out LatheDatabaseComponent database)) return; + + Storage = storage; + Lathe = lathe; + Database = database; + + menu = new LatheMenu(_displayManager) {Owner = this}; + queueMenu = new LatheQueueMenu(_displayManager) { Owner = this }; + + menu.OnClose += Close; + + menu.AddToScreen(); + menu.Populate(); + menu.PopulateMaterials(); + queueMenu.AddToScreen(); + + menu.QueueButton.OnPressed += (args) => { queueMenu.OpenCentered(); }; + + storage.OnMaterialStorageChanged += menu.PopulateDisabled; + storage.OnMaterialStorageChanged += menu.PopulateMaterials; + + menu.OpenCentered(); + } + + public void Queue(LatheRecipePrototype recipe, int quantity = 1) + { + SendMessage(new SharedLatheComponent.LatheQueueRecipeMessage(recipe.ID, quantity)); + } + + protected override void ReceiveMessage(BoundUserInterfaceMessage message) + { + switch (message) + { + case SharedLatheComponent.LatheProducingRecipeMessage msg: + if (!_prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe)) break; + queueMenu.SetInfo(recipe); + break; + case SharedLatheComponent.LatheStoppedProducingRecipeMessage msg: + queueMenu.ClearInfo(); + break; + case SharedLatheComponent.LatheFullQueueMessage msg: + _queuedRecipes.Clear(); + foreach (var id in msg.Recipes) + { + if (!_prototypeManager.TryIndex(id, out LatheRecipePrototype recipePrototype)) break; + _queuedRecipes.Enqueue(recipePrototype); + } + queueMenu.PopulateList(); + break; + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + menu?.Dispose(); + queueMenu?.Dispose(); + } + } +} diff --git a/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs new file mode 100644 index 0000000000..b40d96319d --- /dev/null +++ b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.GameObjects.Components.Research; +using Content.Shared.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; + +namespace Content.Client.GameObjects.Components.Research +{ + public class LatheDatabaseComponent : SharedLatheDatabaseComponent + { +#pragma warning disable CS0649 + [Dependency] + private IPrototypeManager _prototypeManager; +#pragma warning restore + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + if (!(curState is LatheDatabaseState state)) return; + Clear(); + foreach (var ID in state.Recipes) + { + if(!_prototypeManager.TryIndex(ID, out LatheRecipePrototype recipe)) continue; + AddRecipe(recipe); + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs new file mode 100644 index 0000000000..de32c6f55c --- /dev/null +++ b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Network; + +namespace Content.Client.GameObjects.Components.Research +{ + public class MaterialStorageComponent : SharedMaterialStorageComponent + { + protected override Dictionary Storage { get; set; } = new Dictionary(); + + public event Action OnMaterialStorageChanged; + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + if (!(curState is MaterialStorageState state)) return; + Storage = state.Storage; + OnMaterialStorageChanged?.Invoke(); + } + } +} diff --git a/Content.Client/Research/LatheMenu.cs b/Content.Client/Research/LatheMenu.cs new file mode 100644 index 0000000000..5a7ab389a7 --- /dev/null +++ b/Content.Client/Research/LatheMenu.cs @@ -0,0 +1,255 @@ +using System.Collections.Generic; +using Content.Client.GameObjects.Components.Research; +using Content.Shared.Materials; +using Content.Shared.Research; +using Robust.Client.Interfaces.Graphics; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.Utility; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Timers; +using Robust.Shared.Utility; + +namespace Content.Client.Research +{ + public class LatheMenu : SS14Window + { +#pragma warning disable CS0649 + [Dependency] + private IPrototypeManager PrototypeManager; + [Dependency] + private IResourceCache ResourceCache; +#pragma warning restore + + private ItemList Items; + private ItemList Materials; + private LineEdit AmountLineEdit; + private LineEdit SearchBar; + public Button QueueButton; + protected override Vector2? CustomSize => (300, 450); + + public LatheBoundUserInterface Owner { get; set; } + + private List _recipes = new List(); + private List _shownRecipes = new List(); + + public LatheMenu(IDisplayManager displayMan) : base(displayMan) + { + } + + public LatheMenu(IDisplayManager displayMan, string name) : base(displayMan, name) + { + } + + protected override void Initialize() + { + base.Initialize(); + IoCManager.InjectDependencies(this); + + HideOnClose = true; + Title = "Lathe Menu"; + Visible = false; + + var margin = new MarginContainer() + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsHorizontal = SizeFlags.FillExpand, + MarginTop = 5f, + MarginLeft = 5f, + MarginRight = -5f, + MarginBottom = -5f, + }; + + margin.SetAnchorAndMarginPreset(LayoutPreset.Wide); + + var vbox = new VBoxContainer() + { + SizeFlagsVertical = SizeFlags.FillExpand, + SeparationOverride = 5, + }; + + vbox.SetAnchorAndMarginPreset(LayoutPreset.Wide); + + var hboxButtons = new HBoxContainer() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1, + }; + + QueueButton = new Button() + { + Text = "Queue", + TextAlign = Button.AlignMode.Center, + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1, + }; + + var spacer = new Control() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 3, + }; + + spacer.SetAnchorAndMarginPreset(LayoutPreset.Wide); + + var hboxFilter = new HBoxContainer() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1 + }; + + SearchBar = new LineEdit() + { + PlaceHolder = "Search Designs", + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 3 + }; + + SearchBar.OnTextChanged += Populate; + + var filterButton = new Button() + { + Text = "Filter", + TextAlign = Button.AlignMode.Center, + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 1, + Disabled = true, + }; + + Items = new ItemList() + { + SizeFlagsStretchRatio = 8, + SizeFlagsVertical = SizeFlags.FillExpand, + }; + + + + Items.OnItemSelected += ItemSelected; + + AmountLineEdit = new LineEdit() + { + PlaceHolder = "Amount", + Text = "1", + SizeFlagsHorizontal = SizeFlags.FillExpand, + }; + + AmountLineEdit.OnTextChanged += PopulateDisabled; + + Materials = new ItemList() + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 3 + }; + + hboxButtons.AddChild(spacer); + hboxButtons.AddChild(QueueButton); + + hboxFilter.AddChild(SearchBar); + hboxFilter.AddChild(filterButton); + + vbox.AddChild(hboxButtons); + vbox.AddChild(hboxFilter); + vbox.AddChild(Items); + vbox.AddChild(AmountLineEdit); + vbox.AddChild(Materials); + + margin.AddChild(vbox); + + Contents.AddChild(margin); + } + + public void ItemSelected(ItemList.ItemListSelectedEventArgs args) + { + int.TryParse(AmountLineEdit.Text, out var quantity); + if (quantity <= 0) quantity = 1; + Owner.Queue(_shownRecipes[args.ItemIndex], quantity); + Items.SelectMode = ItemList.ItemListSelectMode.None; + Timer.Spawn(100, () => + { + Items.Unselect(args.ItemIndex); + Items.SelectMode = ItemList.ItemListSelectMode.Single; + }); + } + + public void PopulateMaterials() + { + Materials.Clear(); + + foreach (var (id, amount) in Owner.Storage) + { + if (!PrototypeManager.TryIndex(id, out MaterialPrototype materialPrototype)) continue; + var material = materialPrototype.Material; + Materials.AddItem($"{material.Name} {amount} cm3", material.Icon.Frame0(), false); + } + } + + /// + /// Disables or enables shown recipes depending on whether there are enough materials for it or not. + /// + public void PopulateDisabled() + { + int.TryParse(AmountLineEdit.Text, out var quantity); + if (quantity <= 0) quantity = 1; + for (var i = 0; i < _shownRecipes.Count; i++) + { + var prototype = _shownRecipes[i]; + Items.SetItemDisabled(i, !Owner.Lathe.CanProduce(prototype, quantity)); + } + } + + /// + public void PopulateDisabled(LineEdit.LineEditEventArgs args) + { + PopulateDisabled(); + } + + /// + /// Adds shown recipes to the ItemList control. + /// + public void PopulateList() + { + Items.Clear(); + for (var i = 0; i < _shownRecipes.Count; i++) + { + var prototype = _shownRecipes[i]; + Items.AddItem(prototype.Name, prototype.Icon.Frame0()); + } + + PopulateDisabled(); + } + + /// + /// Populates the list of recipes that will actually be shown, using the current filters. + /// + public void Populate() + { + _shownRecipes.Clear(); + + foreach (var prototype in Owner.Database) + { + if (SearchBar.Text.Trim().Length != 0) + { + if (prototype.Name.ToLowerInvariant().Contains(SearchBar.Text.Trim().ToLowerInvariant())) + _shownRecipes.Add(prototype); + continue; + } + + _shownRecipes.Add(prototype); + } + + PopulateList(); + } + + /// + public void Populate(LineEdit.LineEditEventArgs args) + { + Populate(); + } + } +} diff --git a/Content.Client/Research/LatheQueueMenu.cs b/Content.Client/Research/LatheQueueMenu.cs new file mode 100644 index 0000000000..64b617ad78 --- /dev/null +++ b/Content.Client/Research/LatheQueueMenu.cs @@ -0,0 +1,149 @@ +using Content.Client.GameObjects.Components.Research; +using Content.Shared.Research; +using Robust.Client.Graphics; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Interfaces.Graphics; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.Utility; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.ViewVariables; + +namespace Content.Client.Research +{ + public class LatheQueueMenu : SS14Window + { + protected override Vector2? CustomSize => (300, 450); + + public LatheBoundUserInterface Owner { get; set; } + + [ViewVariables] + private ItemList QueueList; + private Label Name; + private Label Description; + private TextureRect Icon; + + public LatheQueueMenu(IDisplayManager displayManager) : base(displayManager) + { + + } + + protected override void Initialize() + { + base.Initialize(); + + HideOnClose = true; + Title = "Lathe Queue"; + Visible = false; + + var margin = new MarginContainer() + { + MarginTop = 5f, + MarginLeft = 5f, + MarginRight = -5f, + MarginBottom = -5f, + }; + + margin.SetAnchorAndMarginPreset(LayoutPreset.Wide); + + var vbox = new VBoxContainer(); + + vbox.SetAnchorAndMarginPreset(LayoutPreset.Wide); + + var descMargin = new MarginContainer() + { + MarginTop = 5f, + MarginLeft = 5f, + MarginRight = -5f, + MarginBottom = -5f, + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 2, + }; + + var hbox = new HBoxContainer() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + }; + + Icon = new TextureRect() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 2, + }; + + var vboxInfo = new VBoxContainer() + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 3, + }; + + Name = new Label() + { + RectClipContent = true, + SizeFlagsHorizontal = SizeFlags.Fill, + }; + + Description = new Label() + { + RectClipContent = true, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsHorizontal = SizeFlags.Fill, + + }; + + QueueList = new ItemList() + { + SizeFlagsHorizontal = SizeFlags.Fill, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 3, + SelectMode = ItemList.ItemListSelectMode.None + }; + + vboxInfo.AddChild(Name); + vboxInfo.AddChild(Description); + + hbox.AddChild(Icon); + hbox.AddChild(vboxInfo); + + descMargin.AddChild(hbox); + + vbox.AddChild(descMargin); + vbox.AddChild(QueueList); + + margin.AddChild(vbox); + + Contents.AddChild(margin); + + ClearInfo(); + } + + public void SetInfo(LatheRecipePrototype recipe) + { + Icon.Texture = recipe.Icon.Frame0(); + if (recipe.Name != null) + Name.Text = recipe.Name; + if (recipe.Description != null) + Description.Text = recipe.Description; + } + + public void ClearInfo() + { + Icon.Texture = Texture.Transparent; + Name.Text = "-------"; + Description.Text = "Not producing anything."; + } + + public void PopulateList() + { + QueueList.Clear(); + var idx = 1; + foreach (var recipe in Owner.QueuedRecipes) + { + QueueList.AddItem($"{idx}. {recipe.Name}", recipe.Icon.Frame0(), false); + idx++; + } + } + } +} diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 5fd73f4365..b08832352c 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -108,6 +108,9 @@ + + + @@ -125,6 +128,7 @@ + @@ -198,8 +202,6 @@ - - diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 885862d97a..a4ab7fccd8 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -26,7 +26,6 @@ using Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan; using Content.Server.GameObjects.Components.Weapon.Ranged.Projectile; using Content.Server.GameObjects.Components.Projectiles; using Content.Server.GameObjects.Components.Weapon.Melee; -using Content.Server.GameObjects.Components.Materials; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.Components.Construction; using Content.Server.GameObjects.Components.Mobs; @@ -40,6 +39,7 @@ using Content.Server.GameObjects.Components.Weapon.Ranged; using Content.Server.GameTicking; using Content.Server.Interfaces; using Content.Server.Interfaces.GameTicking; +using Content.Shared.GameObjects.Components.Materials; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Markers; using Content.Shared.GameObjects.Components.Mobs; @@ -50,6 +50,8 @@ using Content.Server.GameObjects.Components.Destructible; using Content.Server.GameObjects.Components.Movement; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameObjects.Components.Movement; +using Content.Server.GameObjects.Components.Research; +using Content.Shared.GameObjects.Components.Research; namespace Content.Server { @@ -127,6 +129,8 @@ namespace Content.Server factory.Register(); factory.Register(); factory.Register(); + factory.Register(); + factory.RegisterReference(); factory.Register(); factory.Register(); @@ -139,6 +143,11 @@ namespace Content.Server factory.Register(); factory.RegisterReference(); + factory.Register(); + factory.Register(); + + factory.RegisterReference(); + factory.Register(); factory.Register(); diff --git a/Content.Server/GameObjects/Components/Research/LatheComponent.cs b/Content.Server/GameObjects/Components/Research/LatheComponent.cs new file mode 100644 index 0000000000..5e55075e53 --- /dev/null +++ b/Content.Server/GameObjects/Components/Research/LatheComponent.cs @@ -0,0 +1,152 @@ +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Stack; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Materials; +using Content.Shared.GameObjects.Components.Research; +using Content.Shared.Research; +using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Timers; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Research +{ + public class LatheComponent : SharedLatheComponent, IAttackHand, IAttackBy, IActivate + { + public const int VolumePerSheet = 3750; + + private BoundUserInterface _userInterface; + + [ViewVariables] + public Queue Queue { get; } = new Queue(); + + [ViewVariables] + public bool Producing { get; private set; } = false; + + private LatheRecipePrototype _producingRecipe = null; + + public override void Initialize() + { + base.Initialize(); + _userInterface = Owner.GetComponent().GetBoundUserInterface(LatheUiKey.Key); + _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } + + private void UserInterfaceOnOnReceiveMessage(BoundUserInterfaceMessage message) + { + switch (message) + { + case LatheQueueRecipeMessage msg: + _prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe); + if (recipe != null) + for (var i = 0; i < msg.Quantity; i++) + { + Queue.Enqueue(recipe); + _userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); + } + break; + case LatheSyncRequestMessage msg: + if (!Owner.TryGetComponent(out MaterialStorageComponent storage)) return; + _userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); + if (_producingRecipe != null) + _userInterface.SendMessage(new LatheProducingRecipeMessage(_producingRecipe.ID)); + break; + } + } + + internal bool Produce(LatheRecipePrototype recipe) + { + if (Producing || !CanProduce(recipe) || !Owner.TryGetComponent(out MaterialStorageComponent storage)) return false; + + _userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); + + Producing = true; + _producingRecipe = recipe; + + foreach (var (material, amount) in recipe.RequiredMaterials) + { + // This should always return true, otherwise CanProduce fucked up. + storage.RemoveMaterial(material, amount); + } + + _userInterface.SendMessage(new LatheProducingRecipeMessage(recipe.ID)); + + Timer.Spawn(recipe.CompleteTime, () => + { + Producing = false; + _producingRecipe = null; + Owner.EntityManager.TrySpawnEntityAt(recipe.Result, Owner.Transform.GridPosition, out var entity); + _userInterface.SendMessage(new LatheStoppedProducingRecipeMessage()); + }); + + return true; + } + + void IActivate.Activate(ActivateEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + return; + + _userInterface.Open(actor.playerSession); + return; + } + + bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs) + { + + if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + return false; + + _userInterface.Open(actor.playerSession); + return true; + } + + bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) + { + if (!Owner.TryGetComponent(out MaterialStorageComponent storage) + || !eventArgs.AttackWith.TryGetComponent(out MaterialComponent material)) return false; + + var multiplier = 1; + + if (eventArgs.AttackWith.TryGetComponent(out StackComponent stack)) multiplier = stack.Count; + + var totalAmount = 0; + + // Check if it can insert all materials. + foreach (var mat in material.MaterialTypes.Values) + { + // TODO: Change how MaterialComponent works so this is not hard-coded. + if (!storage.CanInsertMaterial(mat.ID, VolumePerSheet * multiplier)) return false; + totalAmount += VolumePerSheet * multiplier; + } + + // Check if it can take ALL of the material's volume. + if (storage.CanTakeAmount(totalAmount)) return false; + + foreach (var mat in material.MaterialTypes.Values) + { + + storage.InsertMaterial(mat.ID, VolumePerSheet * multiplier); + } + + eventArgs.AttackWith.Delete(); + + return false; + } + + private Queue GetIDQueue() + { + var queue = new Queue(); + foreach (var recipePrototype in Queue) + { + queue.Enqueue(recipePrototype.ID); + } + + return queue; + } + } +} diff --git a/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs new file mode 100644 index 0000000000..b0d6c85e37 --- /dev/null +++ b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Research; +using Content.Shared.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Research +{ + public class LatheDatabaseComponent : SharedLatheDatabaseComponent + { + /// + /// Whether new recipes can be added to this database or not. + /// + public bool Static => _static; + private bool _static = false; + + public override ComponentState GetComponentState() + { + return new LatheDatabaseState(GetRecipeIdList()); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _static, "static", false); + } + + public override void Clear() + { + if (Static) return; + Dirty(); + } + + public override void AddRecipe(LatheRecipePrototype recipe) + { + if (Static) return; + Dirty(); + } + + public override bool RemoveRecipe(LatheRecipePrototype recipe) + { + if (Static || !base.RemoveRecipe(recipe)) return false; + Dirty(); + return true; + } + + private List GetRecipeIdList() + { + var list = new List(); + + foreach (var recipe in this) + { + list.Add(recipe.ID); + } + + return list; + } + } +} diff --git a/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs new file mode 100644 index 0000000000..2d1d22f061 --- /dev/null +++ b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Research +{ + public class MaterialStorageComponent : SharedMaterialStorageComponent + { + protected override Dictionary Storage { get; set; } = new Dictionary(); + + /// + /// How much material the storage can store in total. + /// + public int StorageLimit => _storageLimit; + private int _storageLimit; + + public override ComponentState GetComponentState() + { + return new MaterialStorageState(Storage); + } + + /// + /// Checks if the storage can take a volume of material without surpassing its own limits. + /// + /// The volume of material + /// + public bool CanTakeAmount(int amount) + { + return CurrentAmount + amount <= StorageLimit; + } + + /// + /// Checks if it can insert a material. + /// + /// Material ID + /// How much to insert + /// Whether it can insert the material or not. + public bool CanInsertMaterial(string ID, int amount) + { + return (CanTakeAmount(amount) || StorageLimit < 0) && (!Storage.ContainsKey(ID) || Storage[ID] + amount >= 0); + } + + /// + /// Inserts material into the storage. + /// + /// Material ID + /// How much to insert + /// Whether it inserted it or not. + public bool InsertMaterial(string ID, int amount) + { + if (!CanInsertMaterial(ID, amount)) return false; + + if (!Storage.ContainsKey(ID)) + Storage.Add(ID, 0); + + Storage[ID] += amount; + + Dirty(); + + return true; + } + + /// + /// Removes material from the storage. + /// + /// Material ID + /// How much to remove + /// Whether it removed it or not. + public bool RemoveMaterial(string ID, int amount) + { + return InsertMaterial(ID, -amount); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _storageLimit, "StorageLimit", -1); + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/LatheSystem.cs b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs new file mode 100644 index 0000000000..b85a251a4a --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs @@ -0,0 +1,26 @@ +using Content.Server.GameObjects.Components.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + public class LatheSystem : EntitySystem + { + public override void Initialize() + { + EntityQuery = new TypeEntityQuery(typeof(LatheComponent)); + } + + public override void Update(float frameTime) + { + foreach (var entity in RelevantEntities) + { + var comp = entity.GetComponent(); + if (comp.Producing == false && comp.Queue.Count > 0) + { + comp.Produce(comp.Queue.Dequeue()); + } + } + } + } +} diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 00dda7b7e2..94c90549c4 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -74,9 +74,13 @@ + + + + @@ -90,6 +94,7 @@ + @@ -100,6 +105,7 @@ + diff --git a/Content.Server/GameObjects/Components/Materials/MaterialComponent.cs b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs similarity index 81% rename from Content.Server/GameObjects/Components/Materials/MaterialComponent.cs rename to Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs index f1a3ae2edc..2514c9cdfc 100644 --- a/Content.Server/GameObjects/Components/Materials/MaterialComponent.cs +++ b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Content.Server.Materials; +using Content.Shared.Materials; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Reflection; using Robust.Shared.Interfaces.Serialization; @@ -8,7 +8,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; -namespace Content.Server.GameObjects.Components.Materials +namespace Content.Shared.GameObjects.Components.Materials { /// /// Component to store data such as "this object is made out of steel". @@ -19,7 +19,8 @@ namespace Content.Server.GameObjects.Components.Materials public const string SerializationCache = "mat"; public override string Name => "Material"; - Dictionary MaterialTypes; + public Dictionary MaterialTypes => _materialTypes; + private Dictionary _materialTypes; public override void ExposeData(ObjectSerializer serializer) { @@ -33,11 +34,11 @@ namespace Content.Server.GameObjects.Components.Materials if (serializer.TryGetCacheData(SerializationCache, out Dictionary cached)) { - MaterialTypes = cached.ShallowClone(); + _materialTypes = cached.ShallowClone(); return; } - MaterialTypes = new Dictionary(); + _materialTypes = new Dictionary(); if (serializer.TryReadDataField("materials", out List list)) { @@ -46,12 +47,12 @@ namespace Content.Server.GameObjects.Components.Materials foreach (var entry in list) { var proto = protoMan.Index(entry.Value); - MaterialTypes[entry.Key] = proto.Material; + _materialTypes[entry.Key] = proto.Material; index++; } } - serializer.SetCacheData(SerializationCache, MaterialTypes.ShallowClone()); + serializer.SetCacheData(SerializationCache, _materialTypes.ShallowClone()); } class MaterialDataEntry : IExposeData diff --git a/Content.Shared/GameObjects/Components/Research/SharedLatheComponent.cs b/Content.Shared/GameObjects/Components/Research/SharedLatheComponent.cs new file mode 100644 index 0000000000..feb5518d5c --- /dev/null +++ b/Content.Shared/GameObjects/Components/Research/SharedLatheComponent.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using Content.Shared.Materials; +using Content.Shared.Research; +using Mono.Cecil; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Research +{ + public class SharedLatheComponent : Component + { + public override string Name => "Lathe"; + public override uint? NetID => ContentNetIDs.LATHE; + +#pragma warning disable CS0649 + [Dependency] + protected IPrototypeManager _prototypeManager; +#pragma warning restore + + public bool CanProduce(LatheRecipePrototype recipe, int quantity = 1) + { + if (!Owner.TryGetComponent(out SharedMaterialStorageComponent storage) + || !Owner.TryGetComponent(out SharedLatheDatabaseComponent database)) return false; + + if (!database.Contains(recipe)) return false; + + foreach (var (material, amount) in recipe.RequiredMaterials) + { + if (storage[material] <= (amount * quantity)) return false; + } + + return true; + } + + public bool CanProduce(string ID, int quantity = 1) + { + return _prototypeManager.TryIndex(ID, out LatheRecipePrototype recipe) && CanProduce(recipe, quantity); + } + + /// + /// Sent to the server to sync material storage and the recipe queue. + /// + [Serializable, NetSerializable] + public class LatheSyncRequestMessage : BoundUserInterfaceMessage + { + public LatheSyncRequestMessage() + { + } + } + + /// + /// Sent to the client when the lathe is producing a recipe. + /// + [Serializable, NetSerializable] + public class LatheProducingRecipeMessage : BoundUserInterfaceMessage + { + public readonly string ID; + public LatheProducingRecipeMessage(string id) + { + ID = id; + } + } + + /// + /// Sent to the client when the lathe stopped/finished producing a recipe. + /// + [Serializable, NetSerializable] + public class LatheStoppedProducingRecipeMessage : BoundUserInterfaceMessage + { + public LatheStoppedProducingRecipeMessage() + { + } + } + + /// + /// Sent to the client to let it know about the recipe queue. + /// + [Serializable, NetSerializable] + public class LatheFullQueueMessage : BoundUserInterfaceMessage + { + public readonly Queue Recipes; + public LatheFullQueueMessage(Queue recipes) + { + Recipes = recipes; + } + } + + /// + /// Sent to the server when a client queues a new recipe. + /// + [Serializable, NetSerializable] + public class LatheQueueRecipeMessage : BoundUserInterfaceMessage + { + public readonly string ID; + public readonly int Quantity; + public LatheQueueRecipeMessage(string id, int quantity) + { + ID = id; + Quantity = quantity; + } + } + + [NetSerializable, Serializable] + public enum LatheUiKey + { + Key, + } + } +} diff --git a/Content.Shared/GameObjects/Components/Research/SharedLatheDatabaseComponent.cs b/Content.Shared/GameObjects/Components/Research/SharedLatheDatabaseComponent.cs new file mode 100644 index 0000000000..1471889e94 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Research/SharedLatheDatabaseComponent.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Content.Shared.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Research +{ + public class SharedLatheDatabaseComponent : Component, IEnumerable + { + public override string Name => "LatheDatabase"; + public sealed override uint? NetID => ContentNetIDs.LATHE_DATABASE; + public sealed override Type StateType => typeof(LatheDatabaseState); + + private List _recipes = new List(); + + /// + /// Removes all recipes from the database if it's not static. + /// + /// Whether it could clear the database or not. + public virtual void Clear() + { + _recipes.Clear(); + } + + /// + /// Adds a recipe to the database if it's not static. + /// + /// The recipe to be added. + /// Whether it could be added or not + public virtual void AddRecipe(LatheRecipePrototype recipe) + { + _recipes.Add(recipe); + } + + /// + /// Removes a recipe from the database if it's not static. + /// + /// The recipe to be removed. + /// Whether it could be removed or not + public virtual bool RemoveRecipe(LatheRecipePrototype recipe) + { + return _recipes.Remove(recipe); + } + + /// + /// Returns whether the database contains the recipe or not. + /// + /// The recipe to check + /// Whether the database contained the recipe or not. + public virtual bool Contains(LatheRecipePrototype recipe) + { + return _recipes.Contains(recipe); + } + + /// + /// Returns whether the database contains the recipe or not. + /// + /// The recipe id to check + /// Whether the database contained the recipe or not. + public virtual bool Contains(string id) + { + foreach (var recipe in _recipes) + { + if (recipe.ID == id) return true; + } + return false; + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + var recipes = serializer.ReadDataField("recipes", new List()); + var prototypeManager = IoCManager.Resolve(); + foreach (var id in recipes) + { + if (!prototypeManager.TryIndex(id, out LatheRecipePrototype recipe)) continue; + _recipes.Add(recipe); + } + } + + public IEnumerator GetEnumerator() + { + return _recipes.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + [NetSerializable, Serializable] + public class LatheDatabaseState : ComponentState + { + public readonly List Recipes; + public LatheDatabaseState(List recipes) : base(ContentNetIDs.LATHE_DATABASE) + { + Recipes = recipes; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Research/SharedMaterialStorageComponent.cs b/Content.Shared/GameObjects/Components/Research/SharedMaterialStorageComponent.cs new file mode 100644 index 0000000000..d72dae1a75 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Research/SharedMaterialStorageComponent.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Content.Shared.Materials; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Research +{ + public class SharedMaterialStorageComponent : Component, IEnumerable> + { + [ViewVariables] + protected virtual Dictionary Storage { get; set; } + public override string Name => "MaterialStorage"; + public sealed override uint? NetID => ContentNetIDs.MATERIAL_STORAGE; + public sealed override Type StateType => typeof(MaterialStorageState); + + public int this[string ID] + { + get + { + if (!Storage.ContainsKey(ID)) + return 0; + return Storage[ID]; + } + } + + public int this[Material material] + { + get + { + var ID = material.ID; + if (!Storage.ContainsKey(ID)) + return 0; + return Storage[ID]; + } + } + + /// + /// The total volume of material stored currently. + /// + [ViewVariables] public int CurrentAmount + { + get + { + var value = 0; + + foreach (var amount in Storage.Values) + { + value += amount; + } + + return value; + } + } + + public IEnumerator> GetEnumerator() + { + return Storage.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + [NetSerializable, Serializable] + public class MaterialStorageState : ComponentState + { + public readonly Dictionary Storage; + public MaterialStorageState(Dictionary storage) : base(ContentNetIDs.MATERIAL_STORAGE) + { + Storage = storage; + } + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index f25e205bad..fe8a7cae1e 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -18,5 +18,8 @@ public const uint ITEM = 1013; public const uint CLOTHING = 1014; public const uint ENTITYSTORAGE = 1015; + public const uint LATHE = 1016; + public const uint LATHE_DATABASE = 1017; + public const uint MATERIAL_STORAGE = 1018; } } diff --git a/Content.Server/Materials/Material.cs b/Content.Shared/Materials/Material.cs similarity index 83% rename from Content.Server/Materials/Material.cs rename to Content.Shared/Materials/Material.cs index f1ac8f3be6..de8d8dcf68 100644 --- a/Content.Server/Materials/Material.cs +++ b/Content.Shared/Materials/Material.cs @@ -1,17 +1,18 @@ using Robust.Shared.Interfaces.Serialization; +using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; using YamlDotNet.RepresentationModel; -namespace Content.Server.Materials +namespace Content.Shared.Materials { /// /// Materials are read-only storage for the properties of specific materials. /// Properties should be intrinsic (or at least as much is necessary for game purposes). /// - public class Material : IExposeData +public class Material : IExposeData { public string Name => _name; private string _name = "unobtanium"; @@ -72,6 +73,26 @@ namespace Content.Server.Materials public double BluntDamage => _bluntDamage; private double _bluntDamage = 1; + /// + /// An icon used to represent the material in graphic interfaces. + /// + public SpriteSpecifier Icon => _icon; + private SpriteSpecifier _icon = SpriteSpecifier.Invalid; + + public string ID + { + get + { + var prototypeManager = IoCManager.Resolve(); + foreach (var prototype in prototypeManager.EnumeratePrototypes()) + { + if (prototype.Material == this) return prototype.ID; + } + + return null; + } + } + public void ExposeData(ObjectSerializer serializer) { serializer.DataField(ref _name, "name", "unobtanium", alwaysWrite: true); @@ -87,6 +108,7 @@ namespace Content.Server.Materials serializer.DataField(ref _hardness, "hardness", 1, alwaysWrite: true); serializer.DataField(ref _sharpDamage, "sharpdamage", 1, alwaysWrite: true); serializer.DataField(ref _bluntDamage, "bluntdamage", 1, alwaysWrite: true); + serializer.DataField(ref _icon, "icon", SpriteSpecifier.Invalid, alwaysWrite: true); } } diff --git a/Content.Shared/Research/LatheRecipePrototype.cs b/Content.Shared/Research/LatheRecipePrototype.cs new file mode 100644 index 0000000000..2f82b046f0 --- /dev/null +++ b/Content.Shared/Research/LatheRecipePrototype.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Research; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Research +{ + [NetSerializable, Serializable, Prototype("latheRecipe")] + public class LatheRecipePrototype : IPrototype, IIndexedPrototype + { + private string _name; + private string _id; + private SpriteSpecifier _icon; + private string _description; + private string _result; + private int _completeTime; + private Dictionary _requiredMaterials; + + public string ID => _id; + + /// + /// Name displayed in the lathe GUI. + /// + public string Name + { + get + { + if (_name.Trim().Length != 0) return _name; + var protoMan = IoCManager.Resolve(); + if (protoMan == null) return _description; + protoMan.TryIndex(_result, out EntityPrototype prototype); + if (prototype?.Name != null) + _name = prototype.Name; + return _name; + } + } + + /// + /// Short description displayed in the lathe GUI. + /// + public string Description + { + get + { + if (_description.Trim().Length != 0) return _description; + var protoMan = IoCManager.Resolve(); + if (protoMan == null) return _description; + protoMan.TryIndex(_result, out EntityPrototype prototype); + if (prototype?.Description != null) + _description = prototype.Description; + return _description; + } + } + + /// + /// Texture path used in the lathe GUI. + /// + public SpriteSpecifier Icon => _icon; + + /// + /// The prototype name of the resulting entity when the recipe is printed. + /// + public string Result => _result; + + /// + /// The materials required to produce this recipe. + /// Takes a material ID as string. + /// + public Dictionary RequiredMaterials + { + get => _requiredMaterials; + private set => _requiredMaterials = value; + } + + + /// + /// How many milliseconds it'll take for the lathe to finish this recipe. + /// Might lower depending on the lathe's upgrade level. + /// + public int CompleteTime => _completeTime; + + public 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 _description, "description", string.Empty); + serializer.DataField(ref _icon, "icon", SpriteSpecifier.Invalid); + serializer.DataField(ref _result, "result", null); + serializer.DataField(ref _completeTime, "completetime", 2500); + serializer.DataField(ref _requiredMaterials, "materials", new Dictionary()); + } + } +} diff --git a/Content.Shared/Research/RecipePrototype.cs b/Content.Shared/Research/RecipePrototype.cs new file mode 100644 index 0000000000..c0cabf2a3a --- /dev/null +++ b/Content.Shared/Research/RecipePrototype.cs @@ -0,0 +1,65 @@ +using SS14.Shared.Prototypes; +using SS14.Shared.Serialization; +using SS14.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Research +{ + [Prototype("latheRecipe")] + public class LatheRecipePrototype : IPrototype, IIndexedPrototype + { + private string _name; + private string _id; + private SpriteSpecifier _icon; + private string _description; + private string _result; + private bool _hacked; + private string _latheType; + + public string ID => _id; + + /// + /// Name displayed in the lathe GUI. + /// + public string Name => _name; + + /// + /// Short description displayed in the lathe GUI. + /// + public string Description => _description; + + /// + /// Texture path used in the lathe GUI. + /// + public SpriteSpecifier Icon => _icon; + + /// + /// The prototype name of the resulting entity when the recipe is printed. + /// + public string Result => _result; + + /// + /// Whether the lathe should be hacked to unlock this recipe. + /// + public bool Hacked => _hacked; + + /// + /// The type of lathe that'll print this recipe. + /// TODO: Replace with an enum before merging, henk! + /// + public string LatheType => _latheType; + + public void LoadFrom(YamlMappingNode mapping) + { + var serializer = YamlObjectSerializer.NewReader(mapping); + _name = serializer.ReadDataField("name"); + + serializer.DataField(ref _id, "id", string.Empty); + serializer.DataField(ref _description, "description", string.Empty); + serializer.DataField(ref _icon, "icon", SpriteSpecifier.Invalid); + serializer.DataField(ref _result, "result", null); + serializer.DataField(ref _hacked, "hacked", false); + serializer.DataField(ref _latheType, "lathetype", "default"); + } + } +} diff --git a/Resources/Prototypes/Entities/Lathe.yml b/Resources/Prototypes/Entities/Lathe.yml new file mode 100644 index 0000000000..e47498093a --- /dev/null +++ b/Resources/Prototypes/Entities/Lathe.yml @@ -0,0 +1,37 @@ +- type: entity + id: autolathe + name: "Autolathe" + components: + - type: Clickable + - type: Sprite + sprite: Buildings/autolathe.rsi + state: idle + - type: Icon + sprite: Buildings/autolathe.rsi + state: idle + - type: BoundingBox + - type: Collidable + - type: SnapGrid + offset: Center + - type: Lathe + - type: LatheDatabase + static: true + recipes: + - Brutepack + - Ointment + - LightTube + - LightBulb + - MetalStack + - GlassStack + - Wirecutter + - Screwdriver + - Welder + - Wrench + - CableStack + - Crowbar + - Multitool + - type: MaterialStorage + - type: UserInterface + interfaces: + - key: enum.LatheUiKey.Key + type: LatheBoundUserInterface \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Materials.yml b/Resources/Prototypes/Entities/Materials.yml index 57539cb263..9ccce4bc94 100644 --- a/Resources/Prototypes/Entities/Materials.yml +++ b/Resources/Prototypes/Entities/Materials.yml @@ -45,6 +45,14 @@ texture: Objects/sheet_glass.png - type: Icon texture: Objects/sheet_glass.png + +- type: entity + id: GlassSheet1 + name: Glass Sheet 1 + parent: GlassStack + components: + - type: Stack + count: 1 - type: entity name: Cable Coil diff --git a/Resources/Prototypes/LatheRecipes/medical.yml b/Resources/Prototypes/LatheRecipes/medical.yml new file mode 100644 index 0000000000..a79746fc8e --- /dev/null +++ b/Resources/Prototypes/LatheRecipes/medical.yml @@ -0,0 +1,17 @@ +- type: latheRecipe + id: Brutepack + icon: Objects/brutepack.png + result: Brutepack + completetime: 500 + materials: + steel: 400 + glass: 125 + +- type: latheRecipe + id: Ointment + icon: Objects/ointment.png + result: Ointment + completetime: 500 + materials: + steel: 400 + glass: 125 \ No newline at end of file diff --git a/Resources/Prototypes/LatheRecipes/misc.yml b/Resources/Prototypes/LatheRecipes/misc.yml new file mode 100644 index 0000000000..e27cc5404d --- /dev/null +++ b/Resources/Prototypes/LatheRecipes/misc.yml @@ -0,0 +1,17 @@ +- type: latheRecipe + id: LightTube + icon: Objects/light_tube.rsi/normal.png + result: LightTube + completetime: 500 + materials: + steel: 60 + glass: 100 + +- type: latheRecipe + id: LightBulb + icon: Objects/light_bulb.rsi/normal.png + result: LightBulb + completetime: 500 + materials: + steel: 30 + glass: 50 \ No newline at end of file diff --git a/Resources/Prototypes/LatheRecipes/sheet.yml b/Resources/Prototypes/LatheRecipes/sheet.yml new file mode 100644 index 0000000000..ccb97f0262 --- /dev/null +++ b/Resources/Prototypes/LatheRecipes/sheet.yml @@ -0,0 +1,15 @@ +- type: latheRecipe + id: MetalStack + icon: Objects/sheet_metal.png + result: SteelSheet1 + completetime: 500 + materials: + steel: 3750 + +- type: latheRecipe + id: GlassStack + icon: Objects/sheet_glass.png + result: GlassSheet1 + completetime: 500 + materials: + glass: 3750 \ No newline at end of file diff --git a/Resources/Prototypes/LatheRecipes/tools.yml b/Resources/Prototypes/LatheRecipes/tools.yml new file mode 100644 index 0000000000..93ba2040b6 --- /dev/null +++ b/Resources/Prototypes/LatheRecipes/tools.yml @@ -0,0 +1,59 @@ +- type: latheRecipe + id: Wirecutter + icon: Objects/wirecutter.png + result: Wirecutter + completetime: 500 + materials: + steel: 80 + +- type: latheRecipe + id: Screwdriver + icon: Objects/screwdriver.png + result: Screwdriver + completetime: 500 + materials: + steel: 75 + +- type: latheRecipe + id: Welder + icon: Objects/welder.png + result: Welder + completetime: 500 + materials: + steel: 70 + glass: 30 + +- type: latheRecipe + id: Wrench + icon: Objects/wrench.png + result: Wrench + completetime: 500 + materials: + steel: 70 + glass: 30 + +- type: latheRecipe + id: CableStack + icon: Objects/cable_coil.png + result: CableStack + completetime: 500 + materials: + steel: 50 + glass: 50 + +- type: latheRecipe + id: Crowbar + icon: Objects/crowbar.png + result: Crowbar + completetime: 500 + materials: + steel: 50 + +- type: latheRecipe + id: Multitool + icon: Objects/multitool.png + result: Multitool + completetime: 500 + materials: + steel: 50 + glass: 20 \ No newline at end of file diff --git a/Resources/Prototypes/materials.yml b/Resources/Prototypes/materials.yml index 16ffd541f3..b95a13a0f0 100644 --- a/Resources/Prototypes/materials.yml +++ b/Resources/Prototypes/materials.yml @@ -2,6 +2,7 @@ id: steel name: Steel color: gray + icon: Objects/sheet_metal.png density: 7700 electricresistivity: 6.9e-7 thermalconductivity: 18 @@ -11,6 +12,7 @@ id: glass name: Glass color: '#e8f0ff33' + icon: Objects/sheet_glass.png density: 2500 electricresistivity: 1.0e+13 thermalconductivity: 0.9 diff --git a/Resources/Textures/Buildings/autolathe.rsi/closing.png b/Resources/Textures/Buildings/autolathe.rsi/closing.png new file mode 100644 index 0000000000..f09e99cebc Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/closing.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/idle.png b/Resources/Textures/Buildings/autolathe.rsi/idle.png new file mode 100644 index 0000000000..f30326ab23 Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/idle.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/meta.json b/Resources/Textures/Buildings/autolathe.rsi/meta.json new file mode 100644 index 0000000000..9ec8665236 --- /dev/null +++ b/Resources/Textures/Buildings/autolathe.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/master/icons/obj/machines/excelsior/autolathe.dmi", "states": [{"name": "closing", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "idle", "directions": 1, "delays": [[1.0]]}, {"name": "opening", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "panel", "directions": 1, "delays": [[1.0]]}, {"name": "stanok", "directions": 1, "delays": [[1.0]]}, {"name": "workdone", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.5, 0.1, 0.1, 0.5]]}, {"name": "working", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]]}]} \ No newline at end of file diff --git a/Resources/Textures/Buildings/autolathe.rsi/opening.png b/Resources/Textures/Buildings/autolathe.rsi/opening.png new file mode 100644 index 0000000000..f29bd92306 Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/opening.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/panel.png b/Resources/Textures/Buildings/autolathe.rsi/panel.png new file mode 100644 index 0000000000..5607cee9bc Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/panel.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/stanok.png b/Resources/Textures/Buildings/autolathe.rsi/stanok.png new file mode 100644 index 0000000000..1766a7baca Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/stanok.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/workdone.png b/Resources/Textures/Buildings/autolathe.rsi/workdone.png new file mode 100644 index 0000000000..161f1a4f35 Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/workdone.png differ diff --git a/Resources/Textures/Buildings/autolathe.rsi/working.png b/Resources/Textures/Buildings/autolathe.rsi/working.png new file mode 100644 index 0000000000..4a6cc55256 Binary files /dev/null and b/Resources/Textures/Buildings/autolathe.rsi/working.png differ