Inventories (#61)

* Bully the fuck out of inventory shit
Inventory Stuff
Inventories technically work
It works technicaly speaking
Yeah this part too
Lets do it!
Inventories completed
Motherfucker

* Remove unnecessary usings and fix one thing

* Submodule update

* Adds a bunch of various clothing prototypes for each current inventory slot
This commit is contained in:
clusterfack
2018-04-25 06:42:35 -05:00
committed by Pieter-Jan Briers
parent ea05c593aa
commit c33c227d95
37 changed files with 1205 additions and 395 deletions

View File

@@ -0,0 +1,231 @@
using Content.Shared.GameObjects;
using SS14.Client.GameObjects;
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.ContentPack;
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.Serialization;
using SS14.Shared.Input;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
using SS14.Shared.Utility;
using System;
using System.Collections.Generic;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventoryMessage;
using static Content.Shared.GameObjects.SharedInventoryComponent.ServerInventoryMessage;
namespace Content.Client.GameObjects
{
public class ClientInventoryComponent : SharedInventoryComponent
{
private InventoryWindow Window;
private string TemplateName = "HumanInventory"; //stored for serialization purposes
public event EventHandler<BoundKeyChangedMessage> OnCharacterMenuKey;
public override void ExposeData(EntitySerializer serializer)
{
base.ExposeData(serializer);
Window = new InventoryWindow(this);
serializer.DataField(ref TemplateName, "Template", "HumanInventory");
Window.CreateInventory(TemplateName);
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
switch (message)
{
//Updates what we are storing in UI slots
case ServerInventoryMessage msg:
if (msg.Updatetype == ServerInventoryUpdate.Addition)
{
Window.AddToSlot(msg);
}
else if (msg.Updatetype == ServerInventoryUpdate.Removal)
{
Window.RemoveFromSlot(msg);
}
break;
}
}
/// <summary>
/// Register a hotkey to open the character menu with
/// </summary>
public override void Initialize()
{
base.Initialize();
OnCharacterMenuKey += OpenMenu;
IoCManager.Resolve<IEntityManager>().SubscribeEvent<BoundKeyChangedMessage>(OnCharacterMenuKey, this);
}
/// <summary>
/// Hotkey opens the character menu window
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
private void OpenMenu(object sender, BoundKeyChangedMessage message)
{
if(message.Function == BoundKeyFunctions.OpenCharacterMenu && message.State == BoundKeyState.Down)
{
Window.AddToScreen();
Window.Open();
}
}
public void SendUnequipMessage(Slots slot)
{
var unequipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Unequip);
SendNetworkMessage(unequipmessage);
}
public void SendEquipMessage(Slots slot)
{
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
SendNetworkMessage(equipmessage);
}
/// <summary>
/// Temporary window to hold the basis for inventory hud
/// </summary>
private class InventoryWindow : SS14Window
{
private int elements_x;
private GridContainer GridContainer;
private List<Slots> IndexedSlots;
private Dictionary<Slots, InventoryButton> InventorySlots = new Dictionary<Slots, InventoryButton>(); //ordered dictionary?
private ClientInventoryComponent InventoryComponent;
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Inventory/HumanInventory.tscn");
public InventoryWindow(ClientInventoryComponent inventory)
{
InventoryComponent = inventory;
HideOnClose = true;
}
/// <summary>
/// Creates a grid container filled with slot buttons loaded from an inventory template
/// </summary>
/// <param name="TemplateName"></param>
public void CreateInventory(string TemplateName)
{
Type type = AppDomain.CurrentDomain.GetAssemblyByName("Content.Shared").GetType("Content.Shared.GameObjects." + TemplateName);
Inventory inventory = (Inventory)Activator.CreateInstance(type);
elements_x = inventory.Columns;
GridContainer = (GridContainer)Contents.GetChild("PanelContainer").GetChild("CenterContainer").GetChild("GridContainer");
GridContainer.Columns = elements_x;
IndexedSlots = new List<Slots>(inventory.SlotMasks);
foreach(Slots slot in IndexedSlots)
{
InventoryButton newbutton = new InventoryButton(slot);
if (slot == Slots.NONE)
{
//TODO: Re-enable when godot grid container maintains grid with invisible elements
//newbutton.Visible = false;
}
else
{
//Store slot button and give it the default onpress behavior for empty elements
newbutton.GetChild<Button>("Button").OnPressed += AddToInventory;
InventorySlots.Add(slot, newbutton);
}
if (SlotNames.ContainsKey(slot))
{
newbutton.GetChild<Button>("Button").Text = SlotNames[slot];
}
GridContainer.AddChild(newbutton);
}
}
/// <summary>
/// Adds the item we have equipped to the slot texture and prepares the slot button for removal
/// </summary>
/// <param name="message"></param>
public void AddToSlot(ServerInventoryMessage message)
{
InventoryButton button = InventorySlots[message.Inventoryslot];
var entity = IoCManager.Resolve<IEntityManager>().GetEntity(message.EntityUid);
button.EntityUid = message.EntityUid;
var container = button.GetChild("CenterContainer");
button.GetChild<Button>("Button").OnPressed += RemoveFromInventory;
button.GetChild<Button>("Button").OnPressed -= AddToInventory;
//Gets entity sprite and assigns it to button texture
if (entity.TryGetComponent(out SpriteComponent sprite))
{
var tex = sprite.CurrentSprite;
var rect = button.GetChild("CenterContainer").GetChild<TextureRect>("TextureRect");
if (tex != null)
{
rect.Texture = tex;
rect.Scale = new Vector2(Math.Min(CalculateMinimumSize().X, 32) / tex.Height, Math.Min(CalculateMinimumSize().Y, 32) / tex.Height);
}
else
{
throw new NotImplementedException();
}
}
}
/// <summary>
/// Remove element from the UI and update its button to blank texture and prepare for insertion again
/// </summary>
/// <param name="message"></param>
public void RemoveFromSlot(ServerInventoryMessage message)
{
InventoryButton button = InventorySlots[message.Inventoryslot];
button.GetChild("CenterContainer").GetChild<TextureRect>("TextureRect").Texture = null;
button.EntityUid = EntityUid.Invalid;
button.GetChild<Button>("Button").OnPressed -= RemoveFromInventory;
button.GetChild<Button>("Button").OnPressed += AddToInventory;
}
private void RemoveFromInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton)args.Button.Parent;
InventoryComponent.SendUnequipMessage(control.Slot);
}
private void AddToInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton)args.Button.Parent;
InventoryComponent.SendEquipMessage(control.Slot);
}
}
private class InventoryButton : Control
{
public Slots Slot;
public EntityUid EntityUid;
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Inventory/StorageSlot.tscn");
public InventoryButton(Slots slot)
{
Slot = slot;
}
}
}
}