Construction System. (#87)

* Construction WiP

* Construction kinda works!

* Lots more construction work.

* It mostly works!
This commit is contained in:
Pieter-Jan Briers
2018-08-02 08:29:55 +02:00
committed by GitHub
parent f051078c79
commit d7074bf74f
72 changed files with 1925 additions and 245 deletions

View 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);
}
}
}

View 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;
}
}
}
}

View 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();
}
}
}

View File

@@ -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>

View File

@@ -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");
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -60,7 +60,7 @@ namespace Content.Client.GameObjects
public void UseActiveHand()
{
if(GetEntity(ActiveIndex) != null)
if (GetEntity(ActiveIndex) != null)
{
SendNetworkMessage(new ActivateInhandMsg());
}

View File

@@ -2,4 +2,4 @@
<packages>
<package id="System.ValueTuple" version="4.4.0" targetFramework="net451" />
<package id="YamlDotNet" version="4.3.1" targetFramework="net451" />
</packages>
</packages>

View File

@@ -25,7 +25,7 @@ namespace Content.Server.AI
private readonly List<IEntity> _workList = new List<IEntity>();
private const float MaxAngSpeed = (float) (Math.PI / 2); // how fast our turret can rotate
private const float MaxAngSpeed = (float)(Math.PI / 2); // how fast our turret can rotate
private const float ScanPeriod = 1.0f; // tweak this for performance and gameplay experience
private float _lastScan;
@@ -56,7 +56,7 @@ namespace Content.Server.AI
var curTime = _timeMan.CurTime.TotalSeconds;
if (curTime - _lastScan > ScanPeriod)
{
_lastScan = (float) curTime;
_lastScan = (float)curTime;
_curTarget = FindBestTarget();
}
}
@@ -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

View File

@@ -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>

View File

@@ -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 />

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,
}
}

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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>());

View File

@@ -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>());

View 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,
}
}

View File

@@ -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))

View File

@@ -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),

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -1,5 +1,5 @@
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.System;
using SS14.Shared.GameObjects.Systems;
namespace Content.Server.GameObjects.EntitySystems
{

View File

@@ -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
{

View File

@@ -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
{
@@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems
{
EntityQuery = new TypeEntityQuery(typeof(SmesComponent));
}
public override void Update(float frameTime)
{
foreach (var entity in RelevantEntities)

View File

@@ -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;

View File

@@ -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
{

View File

@@ -1,5 +1,5 @@
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.System;
using SS14.Shared.GameObjects.Systems;
namespace Content.Server.GameObjects
{

View File

@@ -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);
}
}
}

View 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,
}
}
}

View File

@@ -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>
</Project>

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -10,6 +10,7 @@
- left
- right
- type: Inventory
- type: Constructor
- type: entity
id: MobObserver

View File

@@ -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

View File

@@ -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

View 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

View 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

View File

@@ -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]]}]}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

View File

@@ -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}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B