Construction System. (#87)
* Construction WiP * Construction kinda works! * Lots more construction work. * It mostly works!
56
Content.Client/Construction/ConstructionButton.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using SS14.Client.UserInterface;
|
||||
using SS14.Client.UserInterface.Controls;
|
||||
using SS14.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Construction
|
||||
{
|
||||
public class ConstructionButton : Button
|
||||
{
|
||||
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Construction/ConstructionButton.tscn");
|
||||
|
||||
public ConstructorComponent Owner
|
||||
{
|
||||
get => Menu.Owner;
|
||||
set => Menu.Owner = value;
|
||||
}
|
||||
ConstructionMenu Menu;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
OnPressed += IWasPressed;
|
||||
Menu = new ConstructionMenu();
|
||||
Menu.AddToScreen();
|
||||
}
|
||||
|
||||
void IWasPressed(ButtonEventArgs args)
|
||||
{
|
||||
Menu.Open();
|
||||
}
|
||||
|
||||
public void AddToScreen()
|
||||
{
|
||||
UserInterfaceManager.StateRoot.AddChild(this);
|
||||
}
|
||||
|
||||
public void RemoveFromScreen()
|
||||
{
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.RemoveChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Menu.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
344
Content.Client/Construction/ConstructionMenu.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using SS14.Client.GameObjects;
|
||||
using SS14.Client.Graphics;
|
||||
using SS14.Client.Interfaces.GameObjects;
|
||||
using SS14.Client.Interfaces.Placement;
|
||||
using SS14.Client.Interfaces.ResourceManagement;
|
||||
using SS14.Client.Placement;
|
||||
using SS14.Client.ResourceManagement;
|
||||
using SS14.Client.UserInterface;
|
||||
using SS14.Client.UserInterface.Controls;
|
||||
using SS14.Client.UserInterface.CustomControls;
|
||||
using SS14.Client.Utility;
|
||||
using SS14.Shared.Enums;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Log;
|
||||
using SS14.Shared.Maths;
|
||||
using SS14.Shared.Prototypes;
|
||||
using SS14.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Construction
|
||||
{
|
||||
public class ConstructionMenu : SS14Window
|
||||
{
|
||||
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Construction/ConstructionMenu.tscn");
|
||||
|
||||
#pragma warning disable CS0649
|
||||
[Dependency]
|
||||
readonly IPrototypeManager PrototypeManager;
|
||||
[Dependency]
|
||||
readonly IResourceCache ResourceCache;
|
||||
#pragma warning restore
|
||||
|
||||
public ConstructorComponent Owner { get; set; }
|
||||
Button BuildButton;
|
||||
Button EraseButton;
|
||||
LineEdit SearchBar;
|
||||
Tree RecipeList;
|
||||
TextureRect InfoIcon;
|
||||
Label InfoLabel;
|
||||
ItemList StepList;
|
||||
|
||||
CategoryNode RootCategory;
|
||||
// This list is flattened in such a way that the top most deepest category is first.
|
||||
List<CategoryNode> FlattenedCategories;
|
||||
PlacementManager Placement;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
IoCManager.InjectDependencies(this);
|
||||
Placement = (PlacementManager)IoCManager.Resolve<IPlacementManager>();
|
||||
Placement.PlacementCanceled += OnPlacementCanceled;
|
||||
|
||||
HideOnClose = true;
|
||||
Title = "Construction";
|
||||
Visible = false;
|
||||
var split = Contents.GetChild("HSplitContainer");
|
||||
var rightSide = split.GetChild("Guide");
|
||||
var info = rightSide.GetChild("Info");
|
||||
InfoIcon = info.GetChild<TextureRect>("TextureRect");
|
||||
InfoLabel = info.GetChild<Label>("Label");
|
||||
StepList = rightSide.GetChild<ItemList>("StepsList");
|
||||
var buttons = rightSide.GetChild("Buttons");
|
||||
BuildButton = buttons.GetChild<Button>("BuildButton");
|
||||
BuildButton.OnPressed += OnBuildPressed;
|
||||
EraseButton = buttons.GetChild<Button>("EraseButton");
|
||||
EraseButton.OnToggled += OnEraseToggled;
|
||||
|
||||
var leftSide = split.GetChild("Recipes");
|
||||
SearchBar = leftSide.GetChild<LineEdit>("Search");
|
||||
SearchBar.OnTextChanged += OnTextEntered;
|
||||
RecipeList = leftSide.GetChild<Tree>("Tree");
|
||||
RecipeList.OnItemSelected += OnItemSelected;
|
||||
|
||||
PopulatePrototypeList();
|
||||
PopulateTree();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Placement.PlacementCanceled -= OnPlacementCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
void OnItemSelected()
|
||||
{
|
||||
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
|
||||
|
||||
if (prototype == null)
|
||||
{
|
||||
InfoLabel.Text = "";
|
||||
InfoIcon.Texture = null;
|
||||
StepList.Clear();
|
||||
BuildButton.Disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildButton.Disabled = false;
|
||||
InfoLabel.Text = prototype.Description;
|
||||
InfoIcon.Texture = prototype.Icon.Frame0();
|
||||
|
||||
StepList.Clear();
|
||||
|
||||
foreach (var forward in prototype.Stages.Select(a => a.Forward))
|
||||
{
|
||||
if (forward == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Texture icon;
|
||||
string text;
|
||||
switch (forward)
|
||||
{
|
||||
case ConstructionStepMaterial mat:
|
||||
switch (mat.Material)
|
||||
{
|
||||
case ConstructionStepMaterial.MaterialType.Metal:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_metal.png");
|
||||
text = $"Metal x{mat.Amount}";
|
||||
break;
|
||||
case ConstructionStepMaterial.MaterialType.Glass:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_glass.png");
|
||||
text = $"Glass x{mat.Amount}";
|
||||
break;
|
||||
case ConstructionStepMaterial.MaterialType.Cable:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/cable_coil.png");
|
||||
text = $"Cable Coil x{mat.Amount}";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
break;
|
||||
case ConstructionStepTool tool:
|
||||
switch (tool.Tool)
|
||||
{
|
||||
case ConstructionStepTool.ToolType.Wrench:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wrench.png");
|
||||
text = "Wrench";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Crowbar:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/crowbar.png");
|
||||
text = "Crowbar";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Screwdriver:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/screwdriver.png");
|
||||
text = "Screwdriver";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Welder:
|
||||
icon = ResourceCache.GetResource<RSIResource>("/Textures/Objects/tools.rsi").RSI["welder"].Frame0;
|
||||
text = $"Welding tool ({tool.Amount} fuel)";
|
||||
break;
|
||||
case ConstructionStepTool.ToolType.Wirecutters:
|
||||
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wirecutter.png");
|
||||
text = "Wirecutters";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
StepList.AddItem(text, icon, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnTextEntered(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
var str = args.Text;
|
||||
PopulateTree(string.IsNullOrWhiteSpace(str) ? null : str.ToLowerInvariant());
|
||||
}
|
||||
|
||||
void OnBuildPressed(Button.ButtonEventArgs args)
|
||||
{
|
||||
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
|
||||
if (prototype == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (prototype.Type != ConstructionType.Structure)
|
||||
{
|
||||
// In-hand attackby doesn't exist so this is the best alternative.
|
||||
var loc = Owner.Owner.GetComponent<ITransformComponent>().LocalPosition;
|
||||
Owner.SpawnGhost(prototype, loc, Direction.North);
|
||||
return;
|
||||
}
|
||||
|
||||
var hijack = new ConstructionPlacementHijack(prototype, Owner);
|
||||
var info = new PlacementInformation
|
||||
{
|
||||
IsTile = false,
|
||||
PlacementOption = prototype.PlacementMode,
|
||||
};
|
||||
|
||||
|
||||
Placement.BeginHijackedPlacing(info, hijack);
|
||||
}
|
||||
|
||||
private void OnEraseToggled(BaseButton.ButtonToggledEventArgs args)
|
||||
{
|
||||
var hijack = new ConstructionPlacementHijack(null, Owner);
|
||||
Placement.ToggleEraserHijacked(hijack);
|
||||
}
|
||||
|
||||
void PopulatePrototypeList()
|
||||
{
|
||||
RootCategory = new CategoryNode("", null);
|
||||
int count = 1;
|
||||
|
||||
foreach (var prototype in PrototypeManager.EnumeratePrototypes<ConstructionPrototype>())
|
||||
{
|
||||
var currentNode = RootCategory;
|
||||
|
||||
foreach (var category in prototype.CategorySegments)
|
||||
{
|
||||
if (!currentNode.ChildCategories.TryGetValue(category, out var subNode))
|
||||
{
|
||||
count++;
|
||||
subNode = new CategoryNode(category, currentNode);
|
||||
currentNode.ChildCategories.Add(category, subNode);
|
||||
}
|
||||
currentNode = subNode;
|
||||
}
|
||||
|
||||
currentNode.Prototypes.Add(prototype);
|
||||
}
|
||||
|
||||
// Do a pass to sort the prototype lists and flatten the hierarchy.
|
||||
void Recurse(CategoryNode node)
|
||||
{
|
||||
// I give up we're using recursion to flatten this.
|
||||
// There probably IS a way to do it.
|
||||
// I'm too stupid to think of what that way is.
|
||||
foreach (var child in node.ChildCategories.Values)
|
||||
{
|
||||
Recurse(child);
|
||||
}
|
||||
|
||||
node.Prototypes.Sort(ComparePrototype);
|
||||
FlattenedCategories.Add(node);
|
||||
node.FlattenedIndex = FlattenedCategories.Count - 1;
|
||||
}
|
||||
|
||||
FlattenedCategories = new List<CategoryNode>(count);
|
||||
Recurse(RootCategory);
|
||||
}
|
||||
|
||||
void PopulateTree(string searchTerm = null)
|
||||
{
|
||||
RecipeList.Clear();
|
||||
|
||||
var categoryItems = new Tree.Item[FlattenedCategories.Count];
|
||||
categoryItems[RootCategory.FlattenedIndex] = RecipeList.CreateItem();
|
||||
|
||||
// Yay more recursion.
|
||||
Tree.Item ItemForNode(CategoryNode node)
|
||||
{
|
||||
if (categoryItems[node.FlattenedIndex] != null)
|
||||
{
|
||||
return categoryItems[node.FlattenedIndex];
|
||||
}
|
||||
|
||||
var item = RecipeList.CreateItem(ItemForNode(node.Parent));
|
||||
item.SetText(0, node.Name);
|
||||
item.SetSelectable(0, false);
|
||||
categoryItems[node.FlattenedIndex] = item;
|
||||
return item;
|
||||
}
|
||||
|
||||
foreach (var node in FlattenedCategories)
|
||||
{
|
||||
foreach (var prototype in node.Prototypes)
|
||||
{
|
||||
if (searchTerm != null)
|
||||
{
|
||||
var found = false;
|
||||
// TODO: don't run ToLowerInvariant() constantly.
|
||||
if (prototype.Name.ToLowerInvariant().IndexOf(searchTerm) != -1)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var keyw in prototype.Keywords.Concat(prototype.CategorySegments))
|
||||
{
|
||||
// TODO: don't run ToLowerInvariant() constantly.
|
||||
if (keyw.ToLowerInvariant().IndexOf(searchTerm) != -1)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var subItem = RecipeList.CreateItem(ItemForNode(node));
|
||||
subItem.SetText(0, prototype.Name);
|
||||
subItem.Metadata = prototype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlacementCanceled(object sender, EventArgs e)
|
||||
{
|
||||
EraseButton.Pressed = false;
|
||||
}
|
||||
|
||||
private static int ComparePrototype(ConstructionPrototype x, ConstructionPrototype y)
|
||||
{
|
||||
return x.Name.CompareTo(y.Name);
|
||||
}
|
||||
|
||||
class CategoryNode
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly CategoryNode Parent;
|
||||
public SortedDictionary<string, CategoryNode> ChildCategories = new SortedDictionary<string, CategoryNode>();
|
||||
public List<ConstructionPrototype> Prototypes = new List<ConstructionPrototype>();
|
||||
public int FlattenedIndex = -1;
|
||||
|
||||
public CategoryNode(string name, CategoryNode parent)
|
||||
{
|
||||
Name = name;
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Content.Client/Construction/ConstructionPlacementHijack.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using SS14.Client.Graphics;
|
||||
using SS14.Client.Interfaces.ResourceManagement;
|
||||
using SS14.Client.Placement;
|
||||
using SS14.Client.ResourceManagement;
|
||||
using SS14.Client.Utility;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Shared.Maths;
|
||||
|
||||
namespace Content.Client.Construction
|
||||
{
|
||||
public class ConstructionPlacementHijack : PlacementHijack
|
||||
{
|
||||
private readonly ConstructionPrototype Prototype;
|
||||
private readonly ConstructorComponent Owner;
|
||||
|
||||
public ConstructionPlacementHijack(ConstructionPrototype prototype, ConstructorComponent owner)
|
||||
{
|
||||
Prototype = prototype;
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public override bool HijackPlacementRequest(GridLocalCoordinates coords)
|
||||
{
|
||||
if (Prototype != null)
|
||||
{
|
||||
// Stupid god damn Y AXIS.
|
||||
var dir = Manager.Direction;
|
||||
if (dir == Direction.South)
|
||||
{
|
||||
dir = Direction.North;
|
||||
}
|
||||
else if (dir == Direction.North)
|
||||
{
|
||||
dir = Direction.South;
|
||||
}
|
||||
Owner.SpawnGhost(Prototype, coords, dir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HijackDeletion(IEntity entity)
|
||||
{
|
||||
if (entity.TryGetComponent(out ConstructionGhostComponent ghost))
|
||||
{
|
||||
Owner.ClearGhost(ghost.GhostID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void StartHijack(PlacementManager manager)
|
||||
{
|
||||
base.StartHijack(manager);
|
||||
|
||||
var res = IoCManager.Resolve<IResourceCache>();
|
||||
manager.CurrentBaseSprite = Prototype.Icon.DirFrame0();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,9 @@
|
||||
<Reference Include="YamlDotNet, Version=4.3.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)packages\YamlDotNet.4.3.1\lib\net45\YamlDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple">
|
||||
<HintPath>$(SolutionDir)packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="EntryPoint.cs" />
|
||||
@@ -107,5 +110,10 @@
|
||||
<None Include="packages.config" />
|
||||
<Compile Include="GameObjects\Components\Power\SmesVisualizer2D.cs" />
|
||||
<Compile Include="GameObjects\Components\Power\ApcVisualizer2D.cs" />
|
||||
<Compile Include="Construction\ConstructionMenu.cs" />
|
||||
<Compile Include="Construction\ConstructionButton.cs" />
|
||||
<Compile Include="GameObjects\Components\Construction\ConstructorComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Construction\ConstructionGhostComponent.cs" />
|
||||
<Compile Include="Construction\ConstructionPlacementHijack.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,10 +1,12 @@
|
||||
using Content.Client.GameObjects;
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Client.GameObjects.Components.Power;
|
||||
using Content.Client.GameObjects.Components.Storage;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using SS14.Shared.ContentPack;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client
|
||||
{
|
||||
@@ -13,6 +15,7 @@ namespace Content.Client
|
||||
public override void Init()
|
||||
{
|
||||
var factory = IoCManager.Resolve<IComponentFactory>();
|
||||
var prototypes = IoCManager.Resolve<IPrototypeManager>();
|
||||
|
||||
factory.RegisterIgnore("Item");
|
||||
factory.RegisterIgnore("Interactable");
|
||||
@@ -40,11 +43,18 @@ namespace Content.Client
|
||||
factory.RegisterIgnore("Storeable");
|
||||
factory.RegisterIgnore("Clothing");
|
||||
|
||||
factory.RegisterIgnore("Material");
|
||||
factory.RegisterIgnore("Stack");
|
||||
|
||||
factory.Register<HandsComponent>();
|
||||
factory.RegisterReference<HandsComponent, IHandsComponent>();
|
||||
factory.Register<ClientStorageComponent>();
|
||||
factory.Register<ClientInventoryComponent>();
|
||||
factory.Register<PowerDebugTool>();
|
||||
factory.Register<ConstructorComponent>();
|
||||
factory.Register<ConstructionGhostComponent>();
|
||||
|
||||
prototypes.RegisterIgnore("material");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Construction;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Construction
|
||||
{
|
||||
public class ConstructionGhostComponent : Component
|
||||
{
|
||||
public override string Name => "ConstructionGhost";
|
||||
|
||||
public ConstructionPrototype Prototype { get; set; }
|
||||
public ConstructorComponent Master { get; set; }
|
||||
public int GhostID { get; set; }
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case ClientEntityClickMsg clickMsg:
|
||||
Master.TryStartConstruction(GhostID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Construction;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.Components.Construction;
|
||||
using SS14.Client.GameObjects;
|
||||
using SS14.Client.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Log;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Construction
|
||||
{
|
||||
public class ConstructorComponent : SharedConstructorComponent
|
||||
{
|
||||
int nextId;
|
||||
readonly Dictionary<int, ConstructionGhostComponent> Ghosts = new Dictionary<int, ConstructionGhostComponent>();
|
||||
ConstructionButton Button;
|
||||
|
||||
ITransformComponent Transform;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Transform = Owner.GetComponent<ITransformComponent>();
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
if (Button == null)
|
||||
{
|
||||
Button = new ConstructionButton();
|
||||
Button.Owner = this;
|
||||
}
|
||||
Button.AddToScreen();
|
||||
break;
|
||||
|
||||
case PlayerDetachedMsg _:
|
||||
Button.RemoveFromScreen();
|
||||
break;
|
||||
|
||||
case AckStructureConstructionMessage ackMsg:
|
||||
ClearGhost(ackMsg.Ack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
Button?.Dispose();
|
||||
}
|
||||
|
||||
public void SpawnGhost(ConstructionPrototype prototype, GridLocalCoordinates loc, Direction dir)
|
||||
{
|
||||
var entMgr = IoCManager.Resolve<IClientEntityManager>();
|
||||
var ghost = entMgr.ForceSpawnEntityAt("constructionghost", loc);
|
||||
var comp = ghost.GetComponent<ConstructionGhostComponent>();
|
||||
comp.Prototype = prototype;
|
||||
comp.Master = this;
|
||||
comp.GhostID = nextId++;
|
||||
var transform = ghost.GetComponent<ITransformComponent>().LocalRotation = dir.ToAngle();
|
||||
var sprite = ghost.GetComponent<SpriteComponent>();
|
||||
sprite.LayerSetSprite(0, prototype.Icon);
|
||||
sprite.LayerSetShader(0, "unshaded");
|
||||
|
||||
Ghosts.Add(comp.GhostID, comp);
|
||||
}
|
||||
|
||||
public void TryStartConstruction(int ghostId)
|
||||
{
|
||||
var ghost = Ghosts[ghostId];
|
||||
var transform = ghost.Owner.GetComponent<ITransformComponent>();
|
||||
var msg = new TryStartStructureConstructionMessage(transform.LocalPosition, ghost.Prototype.ID, transform.LocalRotation, ghostId);
|
||||
SendNetworkMessage(msg);
|
||||
}
|
||||
|
||||
public void ClearGhost(int ghostId)
|
||||
{
|
||||
if (Ghosts.TryGetValue(ghostId, out var ghost))
|
||||
{
|
||||
ghost.Owner.Delete();
|
||||
Ghosts.Remove(ghostId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,10 @@ namespace Content.Server.AI
|
||||
|
||||
// point me at the target
|
||||
var tarPos = _curTarget.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var myPos = SelfEntity.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var selfTransform = SelfEntity.GetComponent<ITransformComponent>();
|
||||
var myPos = selfTransform.WorldPosition;
|
||||
|
||||
var curDir = SelfEntity.GetComponent<IServerTransformComponent>().LocalRotation.ToVec();
|
||||
var curDir = selfTransform.LocalRotation.ToVec();
|
||||
var tarDir = (tarPos - myPos).Normalized;
|
||||
|
||||
var fwdAng = Vector2.Dot(curDir, tarDir);
|
||||
@@ -92,7 +93,7 @@ namespace Content.Server.AI
|
||||
newDir = MoveTowards(curDir, tarDir, MaxAngSpeed, frameTime);
|
||||
}
|
||||
|
||||
SelfEntity.GetComponent<IServerTransformComponent>().LocalRotation = new Angle(newDir);
|
||||
selfTransform.LocalRotation = new Angle(newDir);
|
||||
|
||||
if (fwdAng > -0.9999)
|
||||
{
|
||||
@@ -105,7 +106,7 @@ namespace Content.Server.AI
|
||||
// "best" target is the closest one with LOS
|
||||
|
||||
var ents = _entMan.GetEntitiesInRange(SelfEntity, VisionRadius);
|
||||
var myTransform = SelfEntity.GetComponent<IServerTransformComponent>();
|
||||
var myTransform = SelfEntity.GetComponent<ITransformComponent>();
|
||||
var maxRayLen = VisionRadius * 2.5f; // circle inscribed in square, square diagonal = 2*r*sqrt(2)
|
||||
|
||||
_workList.Clear();
|
||||
@@ -116,7 +117,7 @@ namespace Content.Server.AI
|
||||
continue;
|
||||
|
||||
// build the ray
|
||||
var dir = entity.GetComponent<TransformComponent>().WorldPosition - myTransform.WorldPosition;
|
||||
var dir = entity.GetComponent<ITransformComponent>().WorldPosition - myTransform.WorldPosition;
|
||||
var ray = new Ray(myTransform.WorldPosition, dir.Normalized);
|
||||
|
||||
// cast the ray
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
<Reference Include="YamlDotNet, Version=4.3.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)packages\YamlDotNet.4.3.1\lib\net45\YamlDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple">
|
||||
<HintPath>$(SolutionDir)packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AI\AimShootLifeProcessor.cs" />
|
||||
@@ -146,5 +149,8 @@
|
||||
<Compile Include="GameObjects\Components\Power\ApcComponent.cs" />
|
||||
<Compile Include="Materials\Material.cs" />
|
||||
<Compile Include="GameObjects\Components\Materials\MaterialComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Stack\StackComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Construction\ConstructorComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Construction\ConstructionComponent.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -26,6 +26,8 @@ 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;
|
||||
|
||||
namespace Content.Server
|
||||
{
|
||||
@@ -95,6 +97,11 @@ namespace Content.Server
|
||||
factory.Register<SmesComponent>();
|
||||
factory.Register<ApcComponent>();
|
||||
factory.Register<MaterialComponent>();
|
||||
factory.Register<StackComponent>();
|
||||
|
||||
factory.Register<ConstructionComponent>();
|
||||
factory.Register<ConstructorComponent>();
|
||||
factory.RegisterIgnore("ConstructionGhost");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Interactable.Tools;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Construction;
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Server.GameObjects.EntitySystems;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using static Content.Shared.Construction.ConstructionStepMaterial;
|
||||
using static Content.Shared.Construction.ConstructionStepTool;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
public class ConstructionComponent : Component, IAttackby
|
||||
{
|
||||
public override string Name => "Construction";
|
||||
|
||||
public ConstructionPrototype Prototype { get; private set; }
|
||||
public int Stage { get; private set; }
|
||||
|
||||
SpriteComponent Sprite;
|
||||
ITransformComponent Transform;
|
||||
AudioSystem AudioSystem;
|
||||
Random random;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Sprite = Owner.GetComponent<SpriteComponent>();
|
||||
Transform = Owner.GetComponent<ITransformComponent>();
|
||||
var systemman = IoCManager.Resolve<IEntitySystemManager>();
|
||||
AudioSystem = systemman.GetEntitySystem<AudioSystem>();
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
public bool Attackby(IEntity user, IEntity attackwith)
|
||||
{
|
||||
var stage = Prototype.Stages[Stage];
|
||||
|
||||
if (TryProcessStep(stage.Forward, attackwith))
|
||||
{
|
||||
Stage++;
|
||||
if (Stage == Prototype.Stages.Count - 1)
|
||||
{
|
||||
// Oh boy we get to finish construction!
|
||||
var entMgr = IoCManager.Resolve<IServerEntityManager>();
|
||||
var ent = entMgr.ForceSpawnEntityAt(Prototype.Result, Transform.LocalPosition);
|
||||
ent.GetComponent<ITransformComponent>().LocalRotation = Transform.LocalRotation;
|
||||
Owner.Delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
stage = Prototype.Stages[Stage];
|
||||
if (stage.Icon != null)
|
||||
{
|
||||
Sprite.LayerSetSprite(0, stage.Icon);
|
||||
}
|
||||
}
|
||||
|
||||
else if (TryProcessStep(stage.Backward, attackwith))
|
||||
{
|
||||
Stage--;
|
||||
if (Stage == 0)
|
||||
{
|
||||
// Deconstruction complete.
|
||||
Owner.Delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
stage = Prototype.Stages[Stage];
|
||||
if (stage.Icon != null)
|
||||
{
|
||||
Sprite.LayerSetSprite(0, stage.Icon);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Init(ConstructionPrototype prototype)
|
||||
{
|
||||
Prototype = prototype;
|
||||
Stage = 1;
|
||||
Sprite.AddLayerWithSprite(prototype.Stages[1].Icon);
|
||||
}
|
||||
|
||||
bool TryProcessStep(ConstructionStep step, IEntity slapped)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case ConstructionStepMaterial matStep:
|
||||
if (!slapped.TryGetComponent(out StackComponent stack)
|
||||
|| !MaterialStackValidFor(matStep, stack)
|
||||
|| !stack.Use(matStep.Amount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (matStep.Material == MaterialType.Cable)
|
||||
AudioSystem.Play("/Audio/items/zip.ogg", Transform.LocalPosition);
|
||||
else
|
||||
AudioSystem.Play("/Audio/items/deconstruct.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
case ConstructionStepTool toolStep:
|
||||
switch (toolStep.Tool)
|
||||
{
|
||||
case ToolType.Crowbar:
|
||||
if (slapped.HasComponent<CrowbarComponent>())
|
||||
{
|
||||
AudioSystem.Play("/Audio/items/crowbar.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ToolType.Welder:
|
||||
if (slapped.TryGetComponent(out WelderComponent welder) && welder.TryUse(toolStep.Amount))
|
||||
{
|
||||
if (random.NextDouble() > 0.5)
|
||||
AudioSystem.Play("/Audio/items/welder.ogg", Transform.LocalPosition);
|
||||
else
|
||||
AudioSystem.Play("/Audio/items/welder2.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ToolType.Wrench:
|
||||
if (slapped.HasComponent<WrenchComponent>())
|
||||
{
|
||||
AudioSystem.Play("/Audio/items/ratchet.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ToolType.Screwdriver:
|
||||
if (slapped.HasComponent<ScrewdriverComponent>())
|
||||
{
|
||||
if (random.NextDouble() > 0.5)
|
||||
AudioSystem.Play("/Audio/items/screwdriver.ogg", Transform.LocalPosition);
|
||||
else
|
||||
AudioSystem.Play("/Audio/items/screwdriver2.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ToolType.Wirecutters:
|
||||
if (slapped.HasComponent<WirecutterComponent>())
|
||||
{
|
||||
AudioSystem.Play("/Audio/items/wirecutter.ogg", Transform.LocalPosition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<StackType, ConstructionStepMaterial.MaterialType> StackTypeMap
|
||||
= new Dictionary<StackType, ConstructionStepMaterial.MaterialType>
|
||||
{
|
||||
{ StackType.Cable, MaterialType.Cable },
|
||||
{ StackType.Glass, MaterialType.Glass },
|
||||
{ StackType.Metal, MaterialType.Metal }
|
||||
};
|
||||
|
||||
// Really this should check the actual materials at play..
|
||||
public static bool MaterialStackValidFor(ConstructionStepMaterial step, StackComponent stack)
|
||||
{
|
||||
return StackTypeMap.TryGetValue((StackType)stack.StackType, out var should) && should == step.Material;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Materials;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.Components.Construction;
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Server.GameObjects.EntitySystems;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Shared.Maths;
|
||||
using SS14.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
public class ConstructorComponent : SharedConstructorComponent
|
||||
{
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case TryStartStructureConstructionMessage tryStart:
|
||||
TryStartStructureConstruction(tryStart.Location, tryStart.PrototypeName, tryStart.Angle, tryStart.Ack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TryStartStructureConstruction(GridLocalCoordinates loc, string prototypeName, Angle angle, int ack)
|
||||
{
|
||||
var protoMan = IoCManager.Resolve<IPrototypeManager>();
|
||||
var prototype = protoMan.Index<ConstructionPrototype>(prototypeName);
|
||||
|
||||
var transform = Owner.GetComponent<ITransformComponent>();
|
||||
if (!loc.InRange(transform.LocalPosition, InteractionSystem.INTERACTION_RANGE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (prototype.Stages.Count < 2)
|
||||
{
|
||||
throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages.");
|
||||
}
|
||||
|
||||
var stage0 = prototype.Stages[0];
|
||||
if (!(stage0.Forward is ConstructionStepMaterial matStep))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Try to find the stack with the material in the user's hand.
|
||||
var hands = Owner.GetComponent<HandsComponent>();
|
||||
var activeHand = hands.GetActiveHand?.Owner;
|
||||
if (activeHand == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!activeHand.TryGetComponent(out StackComponent stack) || !ConstructionComponent.MaterialStackValidFor(matStep, stack))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stack.Use(matStep.Amount))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// OK WE'RE GOOD CONSTRUCTION STARTED.
|
||||
var entMgr = IoCManager.Resolve<IServerEntityManager>();
|
||||
var AudioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
AudioSystem.Play("/Audio/items/deconstruct.ogg", loc);
|
||||
if (prototype.Stages.Count == 2)
|
||||
{
|
||||
// Exactly 2 stages, so don't make an intermediate frame.
|
||||
var ent = entMgr.ForceSpawnEntityAt(prototype.Result, loc);
|
||||
ent.GetComponent<ITransformComponent>().LocalRotation = angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
var frame = entMgr.ForceSpawnEntityAt("structureconstructionframe", loc);
|
||||
var construction = frame.GetComponent<ConstructionComponent>();
|
||||
construction.Init(prototype);
|
||||
frame.GetComponent<ITransformComponent>().LocalRotation = angle;
|
||||
}
|
||||
|
||||
var msg = new AckStructureConstructionMessage(ack);
|
||||
SendNetworkMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using SS14.Server.Interfaces.Player;
|
||||
using SS14.Shared.ContentPack;
|
||||
using System.Linq;
|
||||
using SS14.Shared.Serialization;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
@@ -159,8 +160,8 @@ namespace Content.Server.GameObjects
|
||||
item.RemovedFromSlot();
|
||||
|
||||
// TODO: The item should be dropped to the container our owner is in, if any.
|
||||
var itemTransform = item.Owner.GetComponent<TransformComponent>();
|
||||
itemTransform.LocalPosition = Owner.GetComponent<TransformComponent>().LocalPosition;
|
||||
var itemTransform = item.Owner.GetComponent<ITransformComponent>();
|
||||
itemTransform.LocalPosition = Owner.GetComponent<ITransformComponent>().LocalPosition;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using SS14.Server.Interfaces.Player;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Input;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Serialization;
|
||||
@@ -162,8 +163,8 @@ namespace Content.Server.GameObjects
|
||||
item.RemovedFromSlot();
|
||||
|
||||
// TODO: The item should be dropped to the container our owner is in, if any.
|
||||
var itemTransform = item.Owner.GetComponent<TransformComponent>();
|
||||
itemTransform.LocalPosition = Owner.GetComponent<TransformComponent>().LocalPosition;
|
||||
var itemTransform = item.Owner.GetComponent<ITransformComponent>();
|
||||
itemTransform.LocalPosition = Owner.GetComponent<ITransformComponent>().LocalPosition;
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,17 @@ namespace Content.Server.GameObjects.Components.Interactable.Tools
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryUse(float value)
|
||||
{
|
||||
if (!Activated || !CanUse(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Fuel -= value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanUse(float value)
|
||||
{
|
||||
return Fuel > value;
|
||||
|
||||
@@ -8,6 +8,7 @@ using SS14.Server.Player;
|
||||
using SS14.Shared.Enums;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Log;
|
||||
@@ -214,8 +215,8 @@ namespace Content.Server.GameObjects
|
||||
var session = playerMan.GetSessionByChannel(netChannel);
|
||||
var playerentity = session.AttachedEntity;
|
||||
|
||||
var ourtransform = Owner.GetComponent<TransformComponent>();
|
||||
var playertransform = playerentity.GetComponent<TransformComponent>();
|
||||
var ourtransform = Owner.GetComponent<ITransformComponent>();
|
||||
var playertransform = playerentity.GetComponent<ITransformComponent>();
|
||||
|
||||
if (playertransform.LocalPosition.InRange(ourtransform.LocalPosition, 2)
|
||||
&& (ourtransform.IsMapTransform || playertransform.ContainsEntity(ourtransform)))
|
||||
@@ -233,7 +234,7 @@ namespace Content.Server.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
entity.GetComponent<TransformComponent>().WorldPosition = Owner.GetComponent<TransformComponent>().WorldPosition;
|
||||
entity.GetComponent<ITransformComponent>().WorldPosition = ourtransform.WorldPosition;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -67,8 +67,8 @@ namespace Content.Server.GameObjects.Components.Materials
|
||||
}
|
||||
|
||||
var refl = IoCManager.Resolve<IReflectionManager>();
|
||||
Value = serializer.ReadDataField("mat", "unobtanium");
|
||||
var key = serializer.ReadDataField("key", string.Empty);
|
||||
Value = serializer.ReadDataField<string>("mat");
|
||||
var key = serializer.ReadDataField<string>("key");
|
||||
if (refl.TryParseEnumReference(key, out var @enum))
|
||||
{
|
||||
Key = @enum;
|
||||
@@ -78,4 +78,9 @@ namespace Content.Server.GameObjects.Components.Materials
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MaterialKeys
|
||||
{
|
||||
Stack,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.GameObjects.Components.Power;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Map;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
@@ -49,7 +50,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
builder.Append(" Providers:\n");
|
||||
foreach (var provider in device.AvailableProviders)
|
||||
{
|
||||
var providerTransform = provider.Owner.GetComponent<IServerTransformComponent>();
|
||||
var providerTransform = provider.Owner.GetComponent<ITransformComponent>();
|
||||
builder.AppendFormat(" {0} ({1}) @ {2}", provider.Owner.Name, provider.Owner.Uid, providerTransform.LocalPosition);
|
||||
if (device.Provider == provider)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Serialization;
|
||||
using SS14.Shared.Utility;
|
||||
@@ -240,18 +241,18 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
return;
|
||||
|
||||
//Get the starting value for our loop
|
||||
var position = Owner.GetComponent<TransformComponent>().WorldPosition;
|
||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var bestprovider = AvailableProviders[0];
|
||||
|
||||
//If we are already connected to a power provider we need to do a loop to find the nearest one, otherwise skip it and use first entry
|
||||
if (Connected == DrawTypes.Provider)
|
||||
{
|
||||
var bestdistance = (bestprovider.Owner.GetComponent<TransformComponent>().WorldPosition - position).LengthSquared;
|
||||
var bestdistance = (bestprovider.Owner.GetComponent<ITransformComponent>().WorldPosition - position).LengthSquared;
|
||||
|
||||
foreach (var availprovider in AvailableProviders)
|
||||
{
|
||||
//Find distance to new provider
|
||||
var distance = (availprovider.Owner.GetComponent<TransformComponent>().WorldPosition - position).LengthSquared;
|
||||
var distance = (availprovider.Owner.GetComponent<ITransformComponent>().WorldPosition - position).LengthSquared;
|
||||
|
||||
//If new provider distance is shorter it becomes new best possible provider
|
||||
if (distance < bestdistance)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -56,10 +57,10 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
return;
|
||||
}
|
||||
var _emanager = IoCManager.Resolve<IServerEntityManager>();
|
||||
var position = Owner.GetComponent<TransformComponent>().WorldPosition;
|
||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var wires = _emanager.GetEntitiesIntersecting(Owner)
|
||||
.Where(x => x.HasComponent<PowerTransferComponent>())
|
||||
.OrderByDescending(x => (x.GetComponent<TransformComponent>().WorldPosition - position).Length);
|
||||
.OrderByDescending(x => (x.GetComponent<ITransformComponent>().WorldPosition - position).Length);
|
||||
var choose = wires.FirstOrDefault();
|
||||
if (choose != null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Log;
|
||||
using SS14.Shared.Serialization;
|
||||
@@ -139,7 +140,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
|
||||
//Find devices within range to take under our control
|
||||
var _emanager = IoCManager.Resolve<IServerEntityManager>();
|
||||
var position = Owner.GetComponent<TransformComponent>().WorldPosition;
|
||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var entities = _emanager.GetEntitiesInRange(Owner, PowerRange)
|
||||
.Where(x => x.HasComponent<PowerDeviceComponent>());
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using SS14.Shared.IoC;
|
||||
using System.Linq;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using Content.Server.GameObjects.Components.Interactable.Tools;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
public void SpreadPowernet()
|
||||
{
|
||||
var _emanager = IoCManager.Resolve<IServerEntityManager>();
|
||||
var position = Owner.GetComponent<TransformComponent>().WorldPosition;
|
||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
||||
var wires = _emanager.GetEntitiesInRange(Owner, 1.1f) //arbitrarily low, just scrape things //wip
|
||||
.Where(x => x.HasComponent<PowerTransferComponent>());
|
||||
|
||||
|
||||
122
Content.Server/GameObjects/Components/Stack/StackComponent.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.Reflection;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Stack
|
||||
{
|
||||
// TODO: Naming and presentation and such could use some improvement.
|
||||
public class StackComponent : Component, IAttackby, IExamine
|
||||
{
|
||||
private const string SerializationCache = "stack";
|
||||
private int _count = 50;
|
||||
private int _maxCount = 50;
|
||||
|
||||
public override string Name => "Stack";
|
||||
|
||||
public int Count
|
||||
{
|
||||
get => _count;
|
||||
private set
|
||||
{
|
||||
_count = value;
|
||||
if (_count <= 0)
|
||||
{
|
||||
Owner.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
public int MaxCount { get => _maxCount; private set => _maxCount = value; }
|
||||
public int AvailableSpace => MaxCount - Count;
|
||||
|
||||
public object StackType { get; private set; }
|
||||
|
||||
public void Add(int amount)
|
||||
{
|
||||
Count += amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to use an amount of items on this stack.
|
||||
/// </summary>
|
||||
/// <param name="amount"></param>
|
||||
/// <returns>True if there were enough items to remove, false if not in which case nothing was changed.</returns>
|
||||
public bool Use(int amount)
|
||||
{
|
||||
if (Count >= amount)
|
||||
{
|
||||
Count -= amount;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
serializer.DataFieldCached(ref _maxCount, "max", 50);
|
||||
serializer.DataFieldCached(ref _count, "count", MaxCount);
|
||||
|
||||
if (!serializer.Reading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (serializer.TryGetCacheData(SerializationCache, out object stackType))
|
||||
{
|
||||
StackType = stackType;
|
||||
return;
|
||||
}
|
||||
|
||||
if (serializer.TryReadDataFieldCached("stacktype", out string raw))
|
||||
{
|
||||
var refl = IoCManager.Resolve<IReflectionManager>();
|
||||
if (refl.TryParseEnumReference(raw, out var @enum))
|
||||
{
|
||||
stackType = @enum;
|
||||
}
|
||||
else
|
||||
{
|
||||
stackType = raw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stackType = Owner.Prototype.ID;
|
||||
}
|
||||
serializer.SetCacheData(SerializationCache, stackType);
|
||||
StackType = stackType;
|
||||
}
|
||||
|
||||
public bool Attackby(IEntity user, IEntity attackwith)
|
||||
{
|
||||
if (attackwith.TryGetComponent<StackComponent>(out var stack))
|
||||
{
|
||||
if (!stack.StackType.Equals(StackType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var toTransfer = Math.Min(Count, stack.AvailableSpace);
|
||||
Count -= toTransfer;
|
||||
stack.Add(toTransfer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Examine()
|
||||
{
|
||||
return $"There are {Count} things in the stack.";
|
||||
}
|
||||
}
|
||||
|
||||
public enum StackType
|
||||
{
|
||||
Metal,
|
||||
Glass,
|
||||
Cable,
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.Timing;
|
||||
using SS14.Shared.GameObjects.EntitySystemMessages;
|
||||
using SS14.Shared.Serialization;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Weapon.Melee
|
||||
{
|
||||
@@ -32,13 +33,13 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
||||
|
||||
void IAfterAttack.Afterattack(IEntity user, GridLocalCoordinates clicklocation, IEntity attacked)
|
||||
{
|
||||
var location = user.GetComponent<TransformComponent>().LocalPosition;
|
||||
var location = user.GetComponent<ITransformComponent>().LocalPosition;
|
||||
var angle = new Angle(clicklocation.ToWorld().Position - location.ToWorld().Position);
|
||||
var entities = IoCManager.Resolve<IServerEntityManager>().GetEntitiesInArc(user.GetComponent<TransformComponent>().LocalPosition, Range, angle, ArcWidth);
|
||||
var entities = IoCManager.Resolve<IServerEntityManager>().GetEntitiesInArc(user.GetComponent<ITransformComponent>().LocalPosition, Range, angle, ArcWidth);
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (!entity.GetComponent<TransformComponent>().IsMapTransform || entity == user)
|
||||
if (!entity.GetComponent<ITransformComponent>().IsMapTransform || entity == user)
|
||||
continue;
|
||||
|
||||
if (entity.TryGetComponent(out DamageableComponent damagecomponent))
|
||||
|
||||
@@ -4,6 +4,7 @@ using SS14.Shared.Audio;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.EntitySystemMessages;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Physics;
|
||||
using SS14.Shared.Interfaces.Timing;
|
||||
using SS14.Shared.IoC;
|
||||
@@ -22,11 +23,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
|
||||
protected override void Fire(IEntity user, GridLocalCoordinates clicklocation)
|
||||
{
|
||||
var userposition = user.GetComponent<TransformComponent>().WorldPosition; //Remember world positions are ephemeral and can only be used instantaneously
|
||||
var userposition = user.GetComponent<ITransformComponent>().WorldPosition; //Remember world positions are ephemeral and can only be used instantaneously
|
||||
var angle = new Angle(clicklocation.Position - userposition);
|
||||
|
||||
var ray = new Ray(userposition, angle.ToVec());
|
||||
var raycastresults = IoCManager.Resolve<ICollisionManager>().IntersectRay(ray, 20, Owner.GetComponent<TransformComponent>().GetMapTransform().Owner);
|
||||
var raycastresults = IoCManager.Resolve<ICollisionManager>().IntersectRay(ray, 20, Owner.GetComponent<ITransformComponent>().GetMapTransform().Owner);
|
||||
|
||||
Hit(raycastresults);
|
||||
AfterEffects(user, raycastresults, angle);
|
||||
@@ -51,7 +52,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
Born = time,
|
||||
DeathTime = time + TimeSpan.FromSeconds(1),
|
||||
Size = new Vector2(ray.Distance, 1f),
|
||||
Coordinates = user.GetComponent<TransformComponent>().LocalPosition.Translated(offset),
|
||||
Coordinates = user.GetComponent<ITransformComponent>().LocalPosition.Translated(offset),
|
||||
//Rotated from east facing
|
||||
Rotation = (float)angle.Theta,
|
||||
ColorDelta = new Vector4(0, 0, 0, -1500f),
|
||||
|
||||
@@ -3,6 +3,7 @@ using SS14.Server.GameObjects;
|
||||
using SS14.Server.GameObjects.EntitySystems;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Shared.Maths;
|
||||
@@ -19,7 +20,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
|
||||
|
||||
protected override void Fire(IEntity user, GridLocalCoordinates clicklocation)
|
||||
{
|
||||
var userposition = user.GetComponent<TransformComponent>().LocalPosition; //Remember world positions are ephemeral and can only be used instantaneously
|
||||
var userposition = user.GetComponent<ITransformComponent>().LocalPosition; //Remember world positions are ephemeral and can only be used instantaneously
|
||||
var angle = new Angle(clicklocation.Position - userposition.Position);
|
||||
|
||||
var theta = angle.Theta;
|
||||
@@ -34,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
|
||||
projectile.GetComponent<PhysicsComponent>().LinearVelocity = angle.ToVec() * _velocity;
|
||||
|
||||
//Rotate the bullets sprite to the correct direction, from north facing I guess
|
||||
projectile.GetComponent<TransformComponent>().LocalRotation = angle.Theta;
|
||||
projectile.GetComponent<ITransformComponent>().LocalRotation = angle.Theta;
|
||||
|
||||
// Sound!
|
||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().Play("/Audio/gunshot_c20.ogg");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using SS14.Server.Interfaces.Player;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
using SS14.Shared.Input;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.Network;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using SS14.Server.Interfaces.Chat;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Log;
|
||||
using System;
|
||||
@@ -33,7 +34,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return;
|
||||
|
||||
//Verify player has a transform component
|
||||
if (!player.TryGetComponent<IServerTransformComponent>(out var playerTransform))
|
||||
if (!player.TryGetComponent<ITransformComponent>(out var playerTransform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -9,6 +9,8 @@ using SS14.Shared.Input;
|
||||
using SS14.Shared.Log;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Server.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.GameObjects.Components.BoundingBox;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -87,8 +89,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
/// </summary>
|
||||
public class InteractionSystem : EntitySystem
|
||||
{
|
||||
private const float INTERACTION_RANGE = 2;
|
||||
private const float INTERACTION_RANGE_SQUARED = INTERACTION_RANGE * INTERACTION_RANGE;
|
||||
public const float INTERACTION_RANGE = 2;
|
||||
public const float INTERACTION_RANGE_SQUARED = INTERACTION_RANGE * INTERACTION_RANGE;
|
||||
|
||||
public void UserInteraction(ClickEventMessage msg, IEntity player)
|
||||
{
|
||||
@@ -98,7 +100,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
attacked = EntityManager.GetEntity(msg.Uid);
|
||||
|
||||
//Verify player has a transform component
|
||||
if (!player.TryGetComponent<IServerTransformComponent>(out var playerTransform))
|
||||
if (!player.TryGetComponent<ITransformComponent>(out var playerTransform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -136,7 +138,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
//Verify attacked object is on the map if we managed to click on it somehow
|
||||
if (!attacked.GetComponent<TransformComponent>().IsMapTransform)
|
||||
if (!attacked.GetComponent<ITransformComponent>().IsMapTransform)
|
||||
{
|
||||
Logger.Warning(string.Format("Player named {0} clicked on object {1} that isn't currently on the map somehow", player.Name, attacked.Name));
|
||||
return;
|
||||
@@ -154,7 +156,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
//RANGEDATTACK/AFTERATTACK: Check distance between user and clicked item, if too large parse it in the ranged function
|
||||
//TODO: have range based upon the item being used? or base it upon some variables of the player himself?
|
||||
var distance = (playerTransform.WorldPosition - attacked.GetComponent<IServerTransformComponent>().WorldPosition).LengthSquared;
|
||||
var distance = (playerTransform.WorldPosition - attacked.GetComponent<ITransformComponent>().WorldPosition).LengthSquared;
|
||||
if (distance > INTERACTION_RANGE_SQUARED)
|
||||
{
|
||||
if (item != null)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
using SS14.Shared.Interfaces.GameObjects;
|
||||
using SS14.Shared.IoC;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Interactable.Tools;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.GameObjects.System;
|
||||
using SS14.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SS14.Server.Interfaces.GameObjects;
|
||||
using SS14.Shared.Interfaces.GameObjects.Components;
|
||||
using SS14.Shared.Interfaces.Map;
|
||||
using SS14.Shared.IoC;
|
||||
using SS14.Shared.Map;
|
||||
@@ -20,11 +21,12 @@ namespace Content.Server.Placement
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IServerEntityManager>();
|
||||
var tBase = entMan.SpawnEntity("TurretBase");
|
||||
tBase.GetComponent<IServerTransformComponent>().LocalPosition = new GridLocalCoordinates(localPosition, grid);
|
||||
tBase.GetComponent<ITransformComponent>().LocalPosition = new GridLocalCoordinates(localPosition, grid);
|
||||
|
||||
var tTop = entMan.SpawnEntity("TurretTopLight");
|
||||
tTop.GetComponent<IServerTransformComponent>().LocalPosition = new GridLocalCoordinates(localPosition, grid);
|
||||
tTop.GetComponent<IServerTransformComponent>().AttachParent(tBase);
|
||||
var topTransform = tTop.GetComponent<ITransformComponent>();
|
||||
topTransform.LocalPosition = new GridLocalCoordinates(localPosition, grid);
|
||||
topTransform.AttachParent(tBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
221
Content.Shared/Construction/ConstructionPrototype.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SS14.Shared.Prototypes;
|
||||
using SS14.Shared.Serialization;
|
||||
using SS14.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Shared.Construction
|
||||
{
|
||||
[Prototype("construction")]
|
||||
public class ConstructionPrototype : IPrototype, IIndexedPrototype
|
||||
{
|
||||
private string _name;
|
||||
private string _description;
|
||||
private SpriteSpecifier _icon;
|
||||
private List<string> _keywords;
|
||||
private List<string> _categorySegments;
|
||||
private List<ConstructionStage> _stages = new List<ConstructionStage>();
|
||||
private ConstructionType _type;
|
||||
private string _id;
|
||||
private string _result;
|
||||
private string _placementMode;
|
||||
|
||||
/// <summary>
|
||||
/// Friendly name displayed in the construction GUI.
|
||||
/// </summary>
|
||||
public string Name => _name;
|
||||
|
||||
/// <summary>
|
||||
/// "Useful" description displayed in the construction GUI.
|
||||
/// </summary>
|
||||
public string Description => _description;
|
||||
|
||||
/// <summary>
|
||||
/// Texture path inside the construction GUI.
|
||||
/// </summary>
|
||||
public SpriteSpecifier Icon => _icon;
|
||||
|
||||
/// <summary>
|
||||
/// A list of keywords that are used for searching.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> Keywords => _keywords;
|
||||
|
||||
/// <summary>
|
||||
/// The split up segments of the category.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> CategorySegments => _categorySegments;
|
||||
|
||||
/// <summary>
|
||||
/// The list of stages of construction.
|
||||
/// Construction is separated into "stages" which is basically a state in a linear FSM.
|
||||
/// The stage has forward and optionally backwards "steps" which are the criteria to move around in the FSM.
|
||||
/// NOTE that the stages are mapped differently than they appear in the prototype.
|
||||
/// In the prototype, the forward step is displayed as "to move into this stage" and reverse "to move out of"
|
||||
/// Stage 0 is considered "construction not started" and last stage is considered "construction is finished".
|
||||
/// As such, neither last or 0 stage have actual stage DATA, only backward/forward steps respectively.
|
||||
/// This would be akward for a YAML prototype because it's always jagged.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ConstructionStage> Stages => _stages;
|
||||
|
||||
public ConstructionType Type => _type;
|
||||
|
||||
public string ID => _id;
|
||||
|
||||
/// <summary>
|
||||
/// The prototype name of the entity prototype when construction is done.
|
||||
/// </summary>
|
||||
public string Result => _result;
|
||||
|
||||
public string PlacementMode => _placementMode;
|
||||
|
||||
public void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
var ser = YamlObjectSerializer.NewReader(mapping);
|
||||
_name = ser.ReadDataField<string>("name");
|
||||
|
||||
ser.DataField(ref _id, "id", string.Empty);
|
||||
ser.DataField(ref _description, "description", string.Empty);
|
||||
ser.DataField(ref _icon, "icon", SpriteSpecifier.Invalid);
|
||||
ser.DataField(ref _type, "objecttype", ConstructionType.Structure);
|
||||
ser.DataField(ref _result, "result", null);
|
||||
ser.DataField(ref _placementMode, "placementmode", "PlaceFree");
|
||||
|
||||
_keywords = ser.ReadDataField<List<string>>("keywords", new List<string>());
|
||||
{
|
||||
var cat = ser.ReadDataField<string>("category");
|
||||
var split = cat.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
_categorySegments = split.ToList();
|
||||
}
|
||||
|
||||
{
|
||||
SpriteSpecifier nextIcon = null;
|
||||
ConstructionStep nextBackward = null;
|
||||
|
||||
foreach (var stepMap in mapping.GetNode<YamlSequenceNode>("steps").Cast<YamlMappingNode>())
|
||||
{
|
||||
var step = ReadStepPrototype(stepMap);
|
||||
_stages.Add(new ConstructionStage(step, nextIcon, nextBackward));
|
||||
if (stepMap.TryGetNode("icon", out var node))
|
||||
{
|
||||
nextIcon = SpriteSpecifier.FromYaml(node);
|
||||
}
|
||||
|
||||
if (stepMap.TryGetNode("reverse", out YamlMappingNode revMap))
|
||||
{
|
||||
nextBackward = ReadStepPrototype(revMap);
|
||||
}
|
||||
}
|
||||
|
||||
_stages.Add(new ConstructionStage(null, nextIcon, nextBackward));
|
||||
}
|
||||
}
|
||||
|
||||
ConstructionStep ReadStepPrototype(YamlMappingNode step)
|
||||
{
|
||||
int amount = 1;
|
||||
|
||||
if (step.TryGetNode("amount", out var node))
|
||||
{
|
||||
amount = node.AsInt();
|
||||
}
|
||||
if (step.TryGetNode("material", out node))
|
||||
{
|
||||
return new ConstructionStepMaterial(
|
||||
node.AsEnum<ConstructionStepMaterial.MaterialType>(),
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
if (step.TryGetNode("tool", out node))
|
||||
{
|
||||
return new ConstructionStepTool(
|
||||
node.AsEnum<ConstructionStepTool.ToolType>(),
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Not enough data specified to determine step.");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConstructionStage
|
||||
{
|
||||
/// <summary>
|
||||
/// The icon of the construction frame at this stage.
|
||||
/// </summary>
|
||||
public readonly SpriteSpecifier Icon;
|
||||
|
||||
/// <summary>
|
||||
/// The step that should be completed to move away from this stage to the next one.
|
||||
/// </summary>
|
||||
public readonly ConstructionStep Forward;
|
||||
|
||||
/// <summary>
|
||||
/// The optional step that can be completed to move away from this stage to the previous one.
|
||||
/// </summary>
|
||||
public readonly ConstructionStep Backward;
|
||||
|
||||
public ConstructionStage(ConstructionStep forward, SpriteSpecifier icon = null, ConstructionStep backward = null)
|
||||
{
|
||||
Icon = icon;
|
||||
Forward = forward;
|
||||
Backward = backward;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConstructionType
|
||||
{
|
||||
Structure,
|
||||
Item,
|
||||
}
|
||||
|
||||
public abstract class ConstructionStep
|
||||
{
|
||||
public readonly int Amount = 1;
|
||||
|
||||
protected ConstructionStep(int amount)
|
||||
{
|
||||
Amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConstructionStepTool : ConstructionStep
|
||||
{
|
||||
public readonly ToolType Tool;
|
||||
|
||||
public ConstructionStepTool(ToolType tool, int amount) : base(amount)
|
||||
{
|
||||
Tool = tool;
|
||||
}
|
||||
|
||||
public enum ToolType
|
||||
{
|
||||
Wrench,
|
||||
Welder,
|
||||
Screwdriver,
|
||||
Crowbar,
|
||||
Wirecutters,
|
||||
}
|
||||
}
|
||||
|
||||
public class ConstructionStepMaterial : ConstructionStep
|
||||
{
|
||||
public readonly MaterialType Material;
|
||||
|
||||
public ConstructionStepMaterial(MaterialType material, int amount) : base(amount)
|
||||
{
|
||||
Material = material;
|
||||
}
|
||||
|
||||
|
||||
public enum MaterialType
|
||||
{
|
||||
Metal,
|
||||
Glass,
|
||||
Cable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
<Reference Include="YamlDotNet, Version=4.3.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)packages\YamlDotNet.4.3.1\lib\net45\YamlDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple">
|
||||
<HintPath>$(SolutionDir)packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="EntryPoint.cs" />
|
||||
@@ -101,6 +104,8 @@
|
||||
<Compile Include="Utility\ContentHelpers.cs" />
|
||||
<Compile Include="GameObjects\Components\Power\SharedSmesComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Power\SharedApcComponent.cs" />
|
||||
<Compile Include="GameObjects\Components\Construction\SharedConstructorComponent.cs" />
|
||||
<Compile Include="Construction\ConstructionPrototype.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using SS14.Shared.GameObjects;
|
||||
using SS14.Shared.Map;
|
||||
using SS14.Shared.Maths;
|
||||
using SS14.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Construction
|
||||
{
|
||||
/// <summary>
|
||||
/// Basically handles the logic of "this mob can do construction".
|
||||
/// </summary>
|
||||
public abstract class SharedConstructorComponent : Component
|
||||
{
|
||||
public override string Name => "Constructor";
|
||||
public override uint? NetID => ContentNetIDs.CONSTRUCTOR;
|
||||
|
||||
/// <summary>
|
||||
/// Sent client -> server to to tell the server that we started building
|
||||
/// a structure-construction.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
protected class TryStartStructureConstructionMessage : ComponentMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Position to start building.
|
||||
/// </summary>
|
||||
public readonly GridLocalCoordinates Location;
|
||||
|
||||
/// <summary>
|
||||
/// The construction prototype to start building.
|
||||
/// </summary>
|
||||
public readonly string PrototypeName;
|
||||
|
||||
public readonly Angle Angle;
|
||||
|
||||
/// <summary>
|
||||
/// Identifier to be sent back in the acknowledgement so that the client can clean up its ghost.
|
||||
/// </summary>
|
||||
public readonly int Ack;
|
||||
|
||||
public TryStartStructureConstructionMessage(GridLocalCoordinates loc, string prototypeName, Angle angle, int ack)
|
||||
{
|
||||
Directed = true;
|
||||
Location = loc;
|
||||
PrototypeName = prototypeName;
|
||||
Angle = angle;
|
||||
Ack = ack;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
protected class AckStructureConstructionMessage : ComponentMessage
|
||||
{
|
||||
public readonly int Ack;
|
||||
|
||||
public AckStructureConstructionMessage(int ack)
|
||||
{
|
||||
Directed = true;
|
||||
Ack = ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,5 +10,6 @@
|
||||
public const uint STORAGE = 1005;
|
||||
public const uint INVENTORY = 1006;
|
||||
public const uint POWER_DEBUG_TOOL = 1007;
|
||||
public const uint CONSTRUCTOR = 1008;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Resources/Audio/items/crowbar.ogg
Normal file
BIN
Resources/Audio/items/deconstruct.ogg
Normal file
BIN
Resources/Audio/items/ratchet.ogg
Normal file
BIN
Resources/Audio/items/screwdriver.ogg
Normal file
BIN
Resources/Audio/items/screwdriver2.ogg
Normal file
BIN
Resources/Audio/items/welder.ogg
Normal file
BIN
Resources/Audio/items/welder2.ogg
Normal file
BIN
Resources/Audio/items/wirecutter.ogg
Normal file
BIN
Resources/Audio/items/zip.ogg
Normal file
27
Resources/Prototypes/Construction/machines.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
- type: construction
|
||||
name: Wall Light
|
||||
id: wall_light
|
||||
keywords: [fixture, lamp]
|
||||
category: Machines
|
||||
description: A simple wall-mounted light fixture.
|
||||
placementmode: SnapgridBorder
|
||||
icon:
|
||||
sprite: Objects/lighting.rsi
|
||||
state: on
|
||||
|
||||
result: poweredlight
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 1
|
||||
icon:
|
||||
sprite: Objects/lighting.rsi
|
||||
state: construct
|
||||
|
||||
- material: Cable
|
||||
amount: 1
|
||||
icon:
|
||||
sprite: Objects/lighting.rsi
|
||||
state: empty
|
||||
|
||||
- material: Glass
|
||||
amount: 1
|
||||
57
Resources/Prototypes/Construction/power.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
- type: construction
|
||||
name: SMES
|
||||
id: smes
|
||||
category: Machines/Power
|
||||
keywords: [battery, cell, storage]
|
||||
placementmode: SnapgridCenter
|
||||
description: A SMES is a large battery capable of connecting directly to a power grid.
|
||||
icon:
|
||||
sprite: Buildings/smes.rsi
|
||||
state: smes
|
||||
result: SMES
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 2
|
||||
icon:
|
||||
sprite: Buildings/smes.rsi
|
||||
state: smes
|
||||
|
||||
- material: Cable
|
||||
amount: 2
|
||||
|
||||
- type: construction
|
||||
name: Generator
|
||||
id: generator
|
||||
category: Machines/Power
|
||||
placementmode: SnapgridCenter
|
||||
description: A portable generator capable of producing power from thin air.
|
||||
icon: Objects/generator.png
|
||||
result: Generator
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 2
|
||||
icon: Objects/generator.png
|
||||
|
||||
- material: Cable
|
||||
amount: 2
|
||||
|
||||
- type: construction
|
||||
name: APC
|
||||
id: apc
|
||||
category: Machines/Power
|
||||
placementmode: SnapgridCenter
|
||||
description: Provides power from the grid wirelessly to other machines in the area.
|
||||
icon:
|
||||
sprite: Buildings/apc.rsi
|
||||
state: apc0
|
||||
result: APC
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 2
|
||||
icon:
|
||||
sprite: Buildings/apc.rsi
|
||||
state: apcmaint
|
||||
|
||||
- material: Cable
|
||||
amount: 2
|
||||
|
||||
31
Resources/Prototypes/Construction/structures.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
- type: construction
|
||||
name: Wall
|
||||
id: wall
|
||||
category: Structures
|
||||
description: Keeps the air in and the greytide out.
|
||||
icon: Tiles/wall_texture.png
|
||||
objecttype: Structure
|
||||
result: __engine_wall
|
||||
placementmode: SnapgridBorder
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 2
|
||||
icon: Buildings/wall_girder.png
|
||||
reverse:
|
||||
tool: Wrench
|
||||
|
||||
- material: Metal
|
||||
amount: 2
|
||||
reverse:
|
||||
tool: Welder
|
||||
|
||||
- type: construction
|
||||
name: Table
|
||||
id: table
|
||||
category: Structures
|
||||
icon: Objects/worktop_single.png
|
||||
result: __engine_worktop
|
||||
placementmode: SnapgridCenter
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 2
|
||||
18
Resources/Prototypes/Construction/weapons.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- type: construction
|
||||
name: Crude Spear
|
||||
id: spear
|
||||
category: Items/Weapons
|
||||
keywords: [melee]
|
||||
description: A crude spear for when you need to put holes in somebody.
|
||||
icon: Objects/spear.png
|
||||
objecttype: Item
|
||||
steps:
|
||||
- material: Metal
|
||||
amount: 1
|
||||
|
||||
- material: Cable
|
||||
amount: 3
|
||||
|
||||
# Should probably use a shard but y'know.
|
||||
- material: Glass
|
||||
amount: 1
|
||||
22
Resources/Prototypes/Entities/Construction.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
- type: entity
|
||||
name: spooky ghost
|
||||
id: constructionghost
|
||||
components:
|
||||
- type: Transform
|
||||
- type: Sprite
|
||||
color: '#3F38'
|
||||
- type: ConstructionGhost
|
||||
- type: BoundingBox
|
||||
- type: Clickable
|
||||
baseshader: unshaded
|
||||
selectionshader: selection_outline_unshaded
|
||||
|
||||
- type: entity
|
||||
name: somebody-messed-up frame
|
||||
id: structureconstructionframe
|
||||
components:
|
||||
- type: Transform
|
||||
- type: Sprite
|
||||
- type: Construction
|
||||
- type: BoundingBox
|
||||
- type: Clickable
|
||||
60
Resources/Prototypes/Entities/Materials.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
- type: entity
|
||||
name: Material Stack
|
||||
id: MaterialStack
|
||||
parent: BaseItem
|
||||
components:
|
||||
- type: Stack
|
||||
- type: Material
|
||||
|
||||
- type: entity
|
||||
name: Steel Sheet
|
||||
id: MetalStack
|
||||
parent: MaterialStack
|
||||
components:
|
||||
- type: Material
|
||||
materials:
|
||||
- key: enum.MaterialKeys.Stack
|
||||
mat: steel
|
||||
- type: Stack
|
||||
stacktype: enum.StackType.Metal
|
||||
- type: Sprite
|
||||
texture: Objects/sheet_metal.png
|
||||
- type: Icon
|
||||
texture: Objects/sheet_metal.png
|
||||
|
||||
- type: entity
|
||||
id: SteelSheet1
|
||||
name: Steel Sheet 1
|
||||
parent: MetalStack
|
||||
components:
|
||||
- type: Stack
|
||||
count: 1
|
||||
|
||||
- type: entity
|
||||
name: Glass Sheet
|
||||
id: GlassStack
|
||||
parent: MaterialStack
|
||||
components:
|
||||
- type: Material
|
||||
materials:
|
||||
- key: enum.MaterialKeys.Stack
|
||||
mat: glass
|
||||
- type: Stack
|
||||
stacktype: enum.StackType.Glass
|
||||
- type: Sprite
|
||||
texture: Objects/sheet_glass.png
|
||||
- type: Icon
|
||||
texture: Objects/sheet_glass.png
|
||||
|
||||
- type: entity
|
||||
name: Cable Coil
|
||||
id: CableStack
|
||||
parent: BaseItem
|
||||
components:
|
||||
- type: Stack
|
||||
stacktype: enum.StackType.Cable
|
||||
- type: Sprite
|
||||
texture: Objects/cable_coil.png
|
||||
color: red
|
||||
- type: Icon
|
||||
texture: Objects/cable_coil.png
|
||||
@@ -10,6 +10,7 @@
|
||||
- left
|
||||
- right
|
||||
- type: Inventory
|
||||
- type: Constructor
|
||||
|
||||
- type: entity
|
||||
id: MobObserver
|
||||
|
||||
@@ -114,6 +114,13 @@
|
||||
visuals:
|
||||
- type: SmesVisualizer2D
|
||||
|
||||
- type: entity
|
||||
id: smes_dry
|
||||
parent: SMES
|
||||
components:
|
||||
- type: PowerStorage
|
||||
charge: 0
|
||||
|
||||
- type: entity
|
||||
id: WiredMachine
|
||||
name: WiredMachine
|
||||
|
||||
@@ -26,3 +26,15 @@
|
||||
- type: Item
|
||||
Size: 24
|
||||
|
||||
- type: entity
|
||||
name: Spear
|
||||
parent: BaseItem
|
||||
id: Spear
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Objects/spear.png
|
||||
- type: Icon
|
||||
texture: Objects/spear.png
|
||||
- type: MeleeWeapon
|
||||
- type: Item
|
||||
Size: 24
|
||||
|
||||
26
Resources/Scenes/Construction/ConstructionButton.tscn
Normal file
@@ -0,0 +1,26 @@
|
||||
[gd_scene format=2]
|
||||
|
||||
[node name="Control" type="Button"]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -110.0
|
||||
margin_top = -70.0
|
||||
margin_right = -50.0
|
||||
margin_bottom = -50.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "Crafting"
|
||||
flat = false
|
||||
align = 1
|
||||
|
||||
273
Resources/Scenes/Construction/ConstructionMenu.tscn
Normal file
@@ -0,0 +1,273 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
|
||||
|
||||
[node name="SS14Window" index="0" instance=ExtResource( 1 )]
|
||||
margin_left = 99.0
|
||||
margin_right = 583.0
|
||||
margin_bottom = 357.0
|
||||
rect_clip_content = false
|
||||
|
||||
[node name="Contents" parent="." index="0"]
|
||||
rect_clip_content = false
|
||||
|
||||
[node name="HSplitContainer" type="HSplitContainer" parent="Contents" index="0"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 0
|
||||
split_offset = 15
|
||||
collapsed = false
|
||||
dragger_visibility = 0
|
||||
|
||||
[node name="Recipes" type="VBoxContainer" parent="Contents/HSplitContainer" index="0"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 163.0
|
||||
margin_bottom = 269.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
size_flags_stretch_ratio = 0.5
|
||||
alignment = 0
|
||||
_sections_unfolded = [ "Grow Direction", "Size Flags" ]
|
||||
|
||||
[node name="Search" type="LineEdit" parent="Contents/HSplitContainer/Recipes" index="0"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 163.0
|
||||
margin_bottom = 24.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 1
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
secret_character = "*"
|
||||
focus_mode = 2
|
||||
context_menu_enabled = true
|
||||
placeholder_text = "Search"
|
||||
placeholder_alpha = 0.6
|
||||
caret_blink = false
|
||||
caret_blink_speed = 0.65
|
||||
caret_position = 0
|
||||
|
||||
[node name="Tree" type="Tree" parent="Contents/HSplitContainer/Recipes" index="1"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 28.0
|
||||
margin_right = 163.0
|
||||
margin_bottom = 269.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = true
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 3
|
||||
columns = 1
|
||||
allow_reselect = false
|
||||
allow_rmb_select = false
|
||||
hide_folding = false
|
||||
hide_root = true
|
||||
drop_mode_flags = 0
|
||||
select_mode = 0
|
||||
_sections_unfolded = [ "Mouse" ]
|
||||
|
||||
[node name="Guide" type="VBoxContainer" parent="Contents/HSplitContainer" index="1"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 175.0
|
||||
margin_right = 464.0
|
||||
margin_bottom = 269.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
alignment = 0
|
||||
|
||||
[node name="Info" type="HBoxContainer" parent="Contents/HSplitContainer/Guide" index="0"]
|
||||
editor/display_folded = true
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 289.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="Contents/HSplitContainer/Guide/Info" index="0"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
stretch_mode = 0
|
||||
|
||||
[node name="Label" type="Label" parent="Contents/HSplitContainer/Guide/Info" index="1"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 4.0
|
||||
margin_right = 289.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
autowrap = true
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "Size Flags" ]
|
||||
|
||||
[node name="Label" type="Label" parent="Contents/HSplitContainer/Guide" index="1"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 127.0
|
||||
margin_top = 18.0
|
||||
margin_right = 162.0
|
||||
margin_bottom = 32.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
custom_colors/font_color = Color( 0.505882, 0.505882, 0.505882, 1 )
|
||||
text = "Steps"
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
|
||||
[node name="StepsList" type="ItemList" parent="Contents/HSplitContainer/Guide" index="2"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 36.0
|
||||
margin_right = 289.0
|
||||
margin_bottom = 245.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = true
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 3
|
||||
items = [ ]
|
||||
select_mode = 0
|
||||
allow_reselect = false
|
||||
icon_mode = 1
|
||||
fixed_icon_size = Vector2( 0, 0 )
|
||||
_sections_unfolded = [ "Icon", "Size Flags" ]
|
||||
|
||||
[node name="Buttons" type="HBoxContainer" parent="Contents/HSplitContainer/Guide" index="3"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 249.0
|
||||
margin_right = 289.0
|
||||
margin_bottom = 269.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
|
||||
[node name="BuildButton" type="Button" parent="Contents/HSplitContainer/Guide/Buttons" index="0"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 192.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
disabled = true
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "Build!"
|
||||
flat = false
|
||||
align = 1
|
||||
_sections_unfolded = [ "Size Flags" ]
|
||||
|
||||
[node name="EraseButton" type="Button" parent="Contents/HSplitContainer/Guide/Buttons" index="1"]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 196.0
|
||||
margin_right = 289.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = true
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "Clear Ghosts"
|
||||
flat = false
|
||||
align = 1
|
||||
|
||||
[node name="Header" parent="." index="1"]
|
||||
rect_clip_content = false
|
||||
|
||||
[node name="Header Text" parent="Header" index="0"]
|
||||
rect_clip_content = false
|
||||
|
||||
[node name="CloseButton" parent="Header" index="1"]
|
||||
rect_clip_content = false
|
||||
|
||||
@@ -1,170 +1 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi and modified.",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "smes",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1
|
||||
},
|
||||
{
|
||||
"name": "smes-display",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-crit",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-oc0",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-oc1",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-oc2",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-og1",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-og2",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-og3",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-og4",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-og5",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-op0",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-op1",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0,
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "smes-op2",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
{"version":1,"license":"CC-BY-SA-3.0","copyright":"Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi and modified.","size":{"x":32,"y":32},"states":[{"name":"smes","select":[],"flags":{},"directions":1},{"name":"smes-display","select":[],"flags":{},"directions":1,"delays":[[0.2,0.2,0.2,0.2,0.2]]},{"name":"smes-crit","select":[],"flags":{},"directions":1,"delays":[[0.2,0.2,0.2,0.2]]},{"name":"smes-oc0","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-oc1","select":[],"flags":{},"directions":1,"delays":[[0.5,0.5]]},{"name":"smes-oc2","select":[],"flags":{},"directions":1,"delays":[[0.5,0.5]]},{"name":"smes-og1","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-og2","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-og3","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-og4","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-og5","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-op0","select":[],"flags":{},"directions":1,"delays":[[1]]},{"name":"smes-op1","select":[],"flags":{},"directions":1,"delays":[[1,1]]},{"name":"smes-op2","select":[],"flags":{},"directions":1,"delays":[[1]]}]}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 581 B |
BIN
Resources/Textures/Buildings/wall_girder.png
Normal file
|
After Width: | Height: | Size: 302 B |
BIN
Resources/Textures/Objects/cable_coil.png
Normal file
|
After Width: | Height: | Size: 171 B |
BIN
Resources/Textures/Objects/lighting.rsi/construct.png
Normal file
|
After Width: | Height: | Size: 276 B |
BIN
Resources/Textures/Objects/lighting.rsi/empty.png
Normal file
|
After Width: | Height: | Size: 368 B |
@@ -1,21 +1 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "on",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "off",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
{"version":1,"size":{"x":32,"y":32},"states":[{"name":"on","select":[],"flags":{},"directions":4},{"name":"off","select":[],"flags":{},"directions":4},{"name":"construct","select":[],"flags":{},"directions":4},{"name":"empty","select":[],"flags":{},"directions":4}]}
|
||||
BIN
Resources/Textures/Objects/sheet_glass.png
Normal file
|
After Width: | Height: | Size: 781 B |
BIN
Resources/Textures/Objects/sheet_metal.png
Normal file
|
After Width: | Height: | Size: 883 B |
BIN
Resources/Textures/Objects/spear.png
Normal file
|
After Width: | Height: | Size: 171 B |