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