Thrusters (shuttle go nyoom) (#5352)
@@ -10,7 +10,9 @@ using Robust.Client.UserInterface.XAML;
|
|||||||
using Robust.Client.Utility;
|
using Robust.Client.Utility;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||||
|
|
||||||
@@ -146,6 +148,15 @@ namespace Content.Client.Cargo.UI
|
|||||||
|
|
||||||
foreach (var order in Owner.Orders.Orders)
|
foreach (var order in Owner.Orders.Orders)
|
||||||
{
|
{
|
||||||
|
var productName = Owner.Market.GetProduct(order.ProductId)?.Name;
|
||||||
|
|
||||||
|
if (productName == null)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(false);
|
||||||
|
Logger.ErrorS("cargo", $"Unable to find product name for {order.ProductId}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var row = new CargoOrderRow
|
var row = new CargoOrderRow
|
||||||
{
|
{
|
||||||
Order = order,
|
Order = order,
|
||||||
@@ -154,7 +165,7 @@ namespace Content.Client.Cargo.UI
|
|||||||
{
|
{
|
||||||
Text = Loc.GetString(
|
Text = Loc.GetString(
|
||||||
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
|
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
|
||||||
("productName", Owner.Market.GetProduct(order.ProductId)?.Name!),
|
("productName", productName),
|
||||||
("orderAmount", order.Amount),
|
("orderAmount", order.Amount),
|
||||||
("orderRequester", order.Requester))
|
("orderRequester", order.Requester))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ namespace Content.Client.Entry
|
|||||||
"Lock",
|
"Lock",
|
||||||
"PresetIdCard",
|
"PresetIdCard",
|
||||||
"SolarControlConsole",
|
"SolarControlConsole",
|
||||||
|
"Thruster",
|
||||||
"FlashOnTrigger",
|
"FlashOnTrigger",
|
||||||
"SoundOnTrigger",
|
"SoundOnTrigger",
|
||||||
"TriggerOnCollide",
|
"TriggerOnCollide",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Shuttles
|
namespace Content.Client.Shuttles
|
||||||
|
|||||||
67
Content.Client/Shuttles/ThrusterVisualizer.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.Shuttles
|
||||||
|
{
|
||||||
|
public sealed class ThrusterVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
|
||||||
|
if (!component.Owner.TryGetComponent(out SpriteComponent? spriteComponent)) return;
|
||||||
|
|
||||||
|
component.TryGetData(ThrusterVisualState.State, out bool state);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case true:
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.ThrustOn, true);
|
||||||
|
|
||||||
|
if (component.TryGetData(ThrusterVisualState.Thrusting, out bool thrusting) && thrusting)
|
||||||
|
{
|
||||||
|
if (spriteComponent.LayerMapTryGet(ThrusterVisualLayers.Thrusting, out _))
|
||||||
|
{
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.Thrusting, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spriteComponent.LayerMapTryGet(ThrusterVisualLayers.ThrustingUnshaded, out _))
|
||||||
|
{
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.ThrustingUnshaded, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisableThrusting(component, spriteComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case false:
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.ThrustOn, false);
|
||||||
|
DisableThrusting(component, spriteComponent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableThrusting(AppearanceComponent component, SpriteComponent spriteComponent)
|
||||||
|
{
|
||||||
|
if (spriteComponent.LayerMapTryGet(ThrusterVisualLayers.Thrusting, out _))
|
||||||
|
{
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.Thrusting, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spriteComponent.LayerMapTryGet(ThrusterVisualLayers.ThrustingUnshaded, out _))
|
||||||
|
{
|
||||||
|
spriteComponent.LayerSetVisible(ThrusterVisualLayers.ThrustingUnshaded, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ThrusterVisualLayers : byte
|
||||||
|
{
|
||||||
|
Base,
|
||||||
|
ThrustOn,
|
||||||
|
Thrusting,
|
||||||
|
ThrustingUnshaded,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Shuttles;
|
using Content.Server.Shuttles;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Server.Shuttles;
|
using Content.Server.Shuttles;
|
||||||
|
using Content.Server.Shuttles.EntitySystems;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ namespace Content.Server.Cargo.Components
|
|||||||
public class CargoTelepadComponent : Component
|
public class CargoTelepadComponent : Component
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
|
|
||||||
public override string Name => "CargoTelepad";
|
public override string Name => "CargoTelepad";
|
||||||
|
|
||||||
private const float TeleportDuration = 0.5f;
|
private const float TeleportDuration = 0.5f;
|
||||||
@@ -120,11 +118,14 @@ namespace Content.Server.Cargo.Components
|
|||||||
// spawn the order
|
// spawn the order
|
||||||
if (!_prototypeManager.TryIndex(data.ProductId, out CargoProductPrototype? prototype))
|
if (!_prototypeManager.TryIndex(data.ProductId, out CargoProductPrototype? prototype))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var product = Owner.EntityManager.SpawnEntity(prototype.Product, Owner.Transform.Coordinates);
|
var product = Owner.EntityManager.SpawnEntity(prototype.Product, Owner.Transform.Coordinates);
|
||||||
|
|
||||||
|
product.Transform.Anchored = false;
|
||||||
|
|
||||||
// spawn a piece of paper.
|
// spawn a piece of paper.
|
||||||
var printed = Owner.EntityManager.SpawnEntity(PrinterOutput, Owner.Transform.Coordinates);
|
var printed = Owner.EntityManager.SpawnEntity(PrinterOutput, Owner.Transform.Coordinates);
|
||||||
if (!_entityManager.TryGetComponent(printed.Uid, out PaperComponent paper))
|
if (!Owner.EntityManager.TryGetComponent(printed.Uid, out PaperComponent paper))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// fill in the order data
|
// fill in the order data
|
||||||
@@ -137,7 +138,7 @@ namespace Content.Server.Cargo.Components
|
|||||||
("approver", data.Approver)));
|
("approver", data.Approver)));
|
||||||
|
|
||||||
// attempt to attach the label
|
// attempt to attach the label
|
||||||
if (_entityManager.TryGetComponent(product.Uid, out PaperLabelComponent label))
|
if (Owner.EntityManager.TryGetComponent(product.Uid, out PaperLabelComponent label))
|
||||||
{
|
{
|
||||||
EntitySystem.Get<ItemSlotsSystem>().TryInsert(OwnerUid, label.LabelSlot, printed);
|
EntitySystem.Get<ItemSlotsSystem>().TryInsert(OwnerUid, label.LabelSlot, printed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ using System.Collections.Generic;
|
|||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
using Content.Server.Items;
|
using Content.Server.Items;
|
||||||
using Content.Server.Movement.Components;
|
using Content.Server.Movement.Components;
|
||||||
using Content.Server.Shuttles;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.Audio;
|
using Content.Server.Shuttles.EntitySystems;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Content.Shared.Movement;
|
using Content.Shared.Movement;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Sound;
|
|
||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -21,12 +20,7 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Physics;
|
|
||||||
using Robust.Shared.Physics.Collision.Shapes;
|
|
||||||
using Robust.Shared.Physics.Dynamics;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Physics.Controllers
|
namespace Content.Server.Physics.Controllers
|
||||||
@@ -95,44 +89,120 @@ namespace Content.Server.Physics.Controllers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depending whether you have "cruise" mode on (tank controls, higher speed) or "docking" mode on (strafing, lower speed)
|
|
||||||
// inputs will do different things.
|
|
||||||
// TODO: Do that
|
|
||||||
float speedCap;
|
|
||||||
var angularSpeed = 0.075f;
|
|
||||||
|
|
||||||
// ShuttleSystem has already worked out the ratio so we'll just multiply it back by the mass.
|
// ShuttleSystem has already worked out the ratio so we'll just multiply it back by the mass.
|
||||||
var movement = (mover.VelocityDir.walking + mover.VelocityDir.sprinting);
|
var movement = mover.VelocityDir.walking + mover.VelocityDir.sprinting;
|
||||||
|
var system = EntitySystem.Get<ThrusterSystem>();
|
||||||
|
|
||||||
|
if (movement.Length.Equals(0f))
|
||||||
|
{
|
||||||
|
// TODO: This visualization doesn't work with multiple pilots so need to address that somehow.
|
||||||
|
system.DisableAllThrustDirections(shuttleComponent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var speedCap = 0f;
|
||||||
|
|
||||||
switch (shuttleComponent.Mode)
|
switch (shuttleComponent.Mode)
|
||||||
{
|
{
|
||||||
case ShuttleMode.Docking:
|
case ShuttleMode.Docking:
|
||||||
if (physicsComponent.LinearVelocity.LengthSquared == 0f)
|
system.DisableAllThrustDirections(shuttleComponent);
|
||||||
{
|
var dockDirection = movement.ToWorldAngle().GetDir();
|
||||||
movement *= 5f;
|
var dockFlag = dockDirection.AsFlag();
|
||||||
}
|
|
||||||
|
|
||||||
if (movement.Length != 0f)
|
// Won't just do cardinal directions.
|
||||||
physicsComponent.ApplyLinearImpulse(physicsComponent.Owner.Transform.WorldRotation.RotateVec(movement) * shuttleComponent.SpeedMultipler * physicsComponent.Mass);
|
foreach (DirectionFlag dir in Enum.GetValues(typeof(DirectionFlag)))
|
||||||
|
{
|
||||||
|
// Brain no worky but I just want cardinals
|
||||||
|
switch (dir)
|
||||||
|
{
|
||||||
|
case DirectionFlag.South:
|
||||||
|
case DirectionFlag.East:
|
||||||
|
case DirectionFlag.North:
|
||||||
|
case DirectionFlag.West:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dir & dockFlag) == 0x0) continue;
|
||||||
|
|
||||||
|
system.EnableThrustDirection(shuttleComponent, dir);
|
||||||
|
|
||||||
|
var index = (int) Math.Log2((int) dir);
|
||||||
|
|
||||||
|
var dockSpeed = shuttleComponent.LinearThrusterImpulse[index];
|
||||||
|
|
||||||
|
// TODO: Cvar for the speed drop
|
||||||
|
dockSpeed /= 5f;
|
||||||
|
|
||||||
|
if (physicsComponent.LinearVelocity.LengthSquared == 0f)
|
||||||
|
{
|
||||||
|
dockSpeed *= 5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
var moveAngle = movement.ToWorldAngle();
|
||||||
|
|
||||||
|
physicsComponent.ApplyLinearImpulse(moveAngle.RotateVec(physicsComponent.Owner.Transform.WorldRotation.ToWorldVec()) *
|
||||||
|
dockSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
speedCap = _shuttleDockSpeedCap;
|
speedCap = _shuttleDockSpeedCap;
|
||||||
break;
|
break;
|
||||||
case ShuttleMode.Cruise:
|
case ShuttleMode.Cruise:
|
||||||
if (movement.Length != 0.0f)
|
if (movement.Y == 0f)
|
||||||
{
|
{
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.South);
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.North);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var direction = movement.Y > 0f ? Direction.North : Direction.South;
|
||||||
|
var linearSpeed = shuttleComponent.LinearThrusterImpulse[(int) direction / 2];
|
||||||
|
|
||||||
if (physicsComponent.LinearVelocity.LengthSquared == 0f)
|
if (physicsComponent.LinearVelocity.LengthSquared == 0f)
|
||||||
{
|
{
|
||||||
movement.Y *= 5f;
|
linearSpeed *= 5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently this is slow BUT we'd have a separate multiplier for docking and cruising or whatever.
|
// Currently this is slow BUT we'd have a separate multiplier for docking and cruising or whatever.
|
||||||
physicsComponent.ApplyLinearImpulse((physicsComponent.Owner.Transform.WorldRotation + new Angle(MathF.PI / 2)).ToVec() *
|
physicsComponent.ApplyLinearImpulse(physicsComponent.Owner.Transform.WorldRotation.Opposite().ToWorldVec() *
|
||||||
shuttleComponent.SpeedMultipler *
|
linearSpeed *
|
||||||
physicsComponent.Mass *
|
movement.Y);
|
||||||
movement.Y *
|
|
||||||
2.5f);
|
|
||||||
|
|
||||||
physicsComponent.ApplyAngularImpulse(-movement.X * angularSpeed * physicsComponent.Mass);
|
switch (direction)
|
||||||
|
{
|
||||||
|
case Direction.North:
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.South);
|
||||||
|
system.EnableThrustDirection(shuttleComponent, DirectionFlag.North);
|
||||||
|
break;
|
||||||
|
case Direction.South:
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.North);
|
||||||
|
system.EnableThrustDirection(shuttleComponent, DirectionFlag.South);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var angularSpeed = shuttleComponent.AngularThrust;
|
||||||
|
|
||||||
|
if (movement.X == 0f)
|
||||||
|
{
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.West);
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.East);
|
||||||
|
}
|
||||||
|
else if (movement.X != 0f)
|
||||||
|
{
|
||||||
|
physicsComponent.ApplyAngularImpulse(-movement.X * angularSpeed);
|
||||||
|
|
||||||
|
if (movement.X < 0f)
|
||||||
|
{
|
||||||
|
system.EnableThrustDirection(shuttleComponent, DirectionFlag.West);
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.East);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
system.EnableThrustDirection(shuttleComponent, DirectionFlag.East);
|
||||||
|
system.DisableThrustDirection(shuttleComponent, DirectionFlag.West);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO WHEN THIS ACTUALLY WORKS
|
// TODO WHEN THIS ACTUALLY WORKS
|
||||||
@@ -142,15 +212,20 @@ namespace Content.Server.Physics.Controllers
|
|||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look don't my ride ass on this stuff most of the PR was just getting the thing working, we can
|
|
||||||
// ideaguys the shit out of it later.
|
|
||||||
|
|
||||||
var velocity = physicsComponent.LinearVelocity;
|
var velocity = physicsComponent.LinearVelocity;
|
||||||
|
var angVelocity = physicsComponent.AngularVelocity;
|
||||||
|
|
||||||
if (velocity.Length > speedCap)
|
if (velocity.Length > speedCap)
|
||||||
{
|
{
|
||||||
physicsComponent.LinearVelocity = velocity.Normalized * speedCap;
|
physicsComponent.LinearVelocity = velocity.Normalized * speedCap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Need to suss something out but this PR already BEEG
|
||||||
|
if (angVelocity > speedCap)
|
||||||
|
{
|
||||||
|
physicsComponent.AngularVelocity = speedCap;
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void HandleFootsteps(IMoverComponent mover, IMobMoverComponent mobMover)
|
protected override void HandleFootsteps(IMoverComponent mover, IMobMoverComponent mobMover)
|
||||||
|
|||||||
21
Content.Server/Shuttles/Components/DockingComponent.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Physics.Dynamics.Joints;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DockingComponent : SharedDockingComponent
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
public DockingComponent? DockedWith;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public Joint? DockJoint;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public override bool Docked => DockedWith != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
Content.Server/Shuttles/Components/ShuttleComponent.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class ShuttleComponent : SharedShuttleComponent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The cached impulse available for each cardinal direction
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public readonly float[] LinearThrusterImpulse = new float[4];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The thrusters contributing to each direction for impulse.
|
||||||
|
/// </summary>
|
||||||
|
public readonly List<ThrusterComponent>[] LinearThrusters = new List<ThrusterComponent>[4];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The thrusters contributing to the angular impulse of the shuttle.
|
||||||
|
/// </summary>
|
||||||
|
public readonly List<ThrusterComponent> AngularThrusters = new List<ThrusterComponent>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public float AngularThrust = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A bitmask of all the directions we are considered thrusting.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public DirectionFlag ThrustDirections = DirectionFlag.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Server.Shuttles
|
namespace Content.Server.Shuttles.Components
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(SharedShuttleConsoleComponent))]
|
[ComponentReference(typeof(SharedShuttleConsoleComponent))]
|
||||||
86
Content.Server/Shuttles/Components/ThrusterComponent.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.Shuttles.EntitySystems;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Robust.Shared.Analyzers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Physics.Collision.Shapes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
[Friend(typeof(ThrusterSystem))]
|
||||||
|
public sealed class ThrusterComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Thruster";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the thruster has been force to be enabled / disable (e.g. VV, interaction, etc.)
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("enabled")]
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
get => _enabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enabled == value) return;
|
||||||
|
_enabled = value;
|
||||||
|
|
||||||
|
var system = EntitySystem.Get<ThrusterSystem>();
|
||||||
|
|
||||||
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
system.DisableThruster(OwnerUid, this);
|
||||||
|
}
|
||||||
|
else if (system.CanEnable(OwnerUid, this))
|
||||||
|
{
|
||||||
|
system.EnableThruster(OwnerUid, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _enabled = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This determines whether the thruster is actually enabled for the purposes of thrust
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOn;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("impulse")]
|
||||||
|
public float Impulse = 5f;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("thrusterType")]
|
||||||
|
public ThrusterType Type = ThrusterType.Linear;
|
||||||
|
|
||||||
|
[DataField("burnShape")] public List<Vector2> BurnPoly = new()
|
||||||
|
{
|
||||||
|
new Vector2(-0.4f, 0.5f),
|
||||||
|
new Vector2(-0.1f, 1.2f),
|
||||||
|
new Vector2(0.1f, 1.2f),
|
||||||
|
new Vector2(0.4f, 0.5f)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much damage is done per second to anything colliding with our thrust.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] [DataField("damage")] public DamageSpecifier? Damage = new();
|
||||||
|
|
||||||
|
// Used for burns
|
||||||
|
|
||||||
|
public List<EntityUid> Colliding = new();
|
||||||
|
|
||||||
|
public bool Firing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ThrusterType
|
||||||
|
{
|
||||||
|
Linear,
|
||||||
|
// Angular meaning rotational.
|
||||||
|
Angular,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.Doors.Components;
|
using Content.Server.Doors.Components;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.Doors;
|
using Content.Shared.Doors;
|
||||||
using Content.Shared.Shuttles;
|
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -13,25 +12,10 @@ using Robust.Shared.Maths;
|
|||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Collision.Shapes;
|
using Robust.Shared.Physics.Collision.Shapes;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
using Robust.Shared.Physics.Dynamics;
|
||||||
using Robust.Shared.Physics.Dynamics.Joints;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Shuttles
|
namespace Content.Server.Shuttles.EntitySystems
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class DockingComponent : SharedDockingComponent
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
public DockingComponent? DockedWith;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public Joint? DockJoint;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public override bool Docked => DockedWith != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class DockingSystem : EntitySystem
|
public sealed class DockingSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.Alert;
|
using Content.Server.Alert;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Physics;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Shuttles
|
namespace Content.Server.Shuttles.EntitySystems
|
||||||
{
|
{
|
||||||
internal sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
internal sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||||
{
|
{
|
||||||
@@ -1,86 +1,54 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using Content.Shared.Shuttles;
|
using Content.Server.Shuttles.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Physics;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
|
|
||||||
namespace Content.Server.Shuttles
|
namespace Content.Server.Shuttles.EntitySystems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
internal sealed class ShuttleSystem : EntitySystem
|
internal sealed class ShuttleSystem : EntitySystem
|
||||||
{
|
{
|
||||||
private const float TileMassMultiplier = 1f;
|
private const float TileMassMultiplier = 4f;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<ShuttleComponent, ComponentStartup>(HandleShuttleStartup);
|
SubscribeLocalEvent<ShuttleComponent, ComponentAdd>(OnShuttleAdd);
|
||||||
SubscribeLocalEvent<ShuttleComponent, ComponentShutdown>(HandleShuttleShutdown);
|
SubscribeLocalEvent<ShuttleComponent, ComponentStartup>(OnShuttleStartup);
|
||||||
|
SubscribeLocalEvent<ShuttleComponent, ComponentShutdown>(OnShuttleShutdown);
|
||||||
|
|
||||||
SubscribeLocalEvent<GridInitializeEvent>(HandleGridInit);
|
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||||
SubscribeLocalEvent<GridFixtureChangeEvent>(HandleGridFixtureChange);
|
SubscribeLocalEvent<GridFixtureChangeEvent>(OnGridFixtureChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleGridFixtureChange(GridFixtureChangeEvent args)
|
private void OnShuttleAdd(EntityUid uid, ShuttleComponent component, ComponentAdd args)
|
||||||
|
{
|
||||||
|
// Easier than doing it in the comp and they don't have constructors.
|
||||||
|
for (var i = 0; i < component.LinearThrusters.Length; i++)
|
||||||
|
{
|
||||||
|
component.LinearThrusters[i] = new List<ThrusterComponent>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridFixtureChange(GridFixtureChangeEvent args)
|
||||||
{
|
{
|
||||||
// Look this is jank but it's a placeholder until we design it.
|
// Look this is jank but it's a placeholder until we design it.
|
||||||
if (args.NewFixtures.Count == 0) return;
|
if (args.NewFixtures.Count == 0) return;
|
||||||
|
|
||||||
var body = args.NewFixtures[0].Body;
|
|
||||||
|
|
||||||
foreach (var fixture in args.NewFixtures)
|
foreach (var fixture in args.NewFixtures)
|
||||||
{
|
{
|
||||||
fixture.Mass = fixture.Area * TileMassMultiplier;
|
fixture.Mass = fixture.Area * TileMassMultiplier;
|
||||||
fixture.Restitution = 0.1f;
|
fixture.Restitution = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body.Owner.TryGetComponent(out ShuttleComponent? shuttleComponent))
|
|
||||||
{
|
|
||||||
RecalculateSpeedMultiplier(shuttleComponent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleGridInit(GridInitializeEvent ev)
|
private void OnGridInit(GridInitializeEvent ev)
|
||||||
{
|
{
|
||||||
EntityManager.GetEntity(ev.EntityUid).EnsureComponent<ShuttleComponent>();
|
EntityManager.GetEntity(ev.EntityUid).EnsureComponent<ShuttleComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void OnShuttleStartup(EntityUid uid, ShuttleComponent component, ComponentStartup args)
|
||||||
/// Cache the thrust available to this shuttle.
|
|
||||||
/// </summary>
|
|
||||||
private void RecalculateSpeedMultiplier(SharedShuttleComponent shuttle, PhysicsComponent physics)
|
|
||||||
{
|
|
||||||
// TODO: Need per direction speed (Never Eat Soggy Weetbix).
|
|
||||||
// TODO: This will need hella tweaking.
|
|
||||||
var thrusters = physics.FixtureCount;
|
|
||||||
|
|
||||||
if (thrusters == 0)
|
|
||||||
{
|
|
||||||
shuttle.SpeedMultipler = 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float ThrustPerThruster = 0.25f;
|
|
||||||
const float MinimumThrustRequired = 0.005f;
|
|
||||||
|
|
||||||
// Just so someone can't slap a single thruster on a station and call it a day; need to hit a minimum amount.
|
|
||||||
var thrustRatio = Math.Max(0, thrusters * ThrustPerThruster / physics.Mass);
|
|
||||||
|
|
||||||
if (thrustRatio < MinimumThrustRequired)
|
|
||||||
shuttle.SpeedMultipler = 0f;
|
|
||||||
|
|
||||||
const float MaxThrust = 10f;
|
|
||||||
// This doesn't need to align with MinimumThrustRequired; if you set this higher it just means the first few additional
|
|
||||||
// thrusters won't do anything.
|
|
||||||
const float MinThrust = MinimumThrustRequired;
|
|
||||||
|
|
||||||
shuttle.SpeedMultipler = MathF.Max(MinThrust, MathF.Min(MaxThrust, thrustRatio));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleShuttleStartup(EntityUid uid, ShuttleComponent component, ComponentStartup args)
|
|
||||||
{
|
{
|
||||||
if (!component.Owner.HasComponent<IMapGridComponent>())
|
if (!component.Owner.HasComponent<IMapGridComponent>())
|
||||||
{
|
{
|
||||||
@@ -96,11 +64,6 @@ namespace Content.Server.Shuttles
|
|||||||
{
|
{
|
||||||
Enable(physicsComponent);
|
Enable(physicsComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.Owner.TryGetComponent(out ShuttleComponent? shuttleComponent))
|
|
||||||
{
|
|
||||||
RecalculateSpeedMultiplier(shuttleComponent, physicsComponent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Toggle(ShuttleComponent component)
|
public void Toggle(ShuttleComponent component)
|
||||||
@@ -136,7 +99,7 @@ namespace Content.Server.Shuttles
|
|||||||
component.FixedRotation = true;
|
component.FixedRotation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleShuttleShutdown(EntityUid uid, ShuttleComponent component, ComponentShutdown args)
|
private void OnShuttleShutdown(EntityUid uid, ShuttleComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent))
|
if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent))
|
||||||
{
|
{
|
||||||
476
Content.Server/Shuttles/EntitySystems/ThrusterSystem.cs
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Content.Server.Atmos.Components;
|
||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Audio;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Content.Shared.Physics;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Collision.Shapes;
|
||||||
|
using Robust.Shared.Physics.Dynamics;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Shuttles.EntitySystems
|
||||||
|
{
|
||||||
|
public sealed class ThrusterSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Robust.Shared.IoC.Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Robust.Shared.IoC.Dependency] private readonly AmbientSoundSystem _ambient = default!;
|
||||||
|
[Robust.Shared.IoC.Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
||||||
|
[Robust.Shared.IoC.Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
|
||||||
|
// Essentially whenever thruster enables we update the shuttle's available impulses which are used for movement.
|
||||||
|
// This is done for each direction available.
|
||||||
|
|
||||||
|
public const string BurnFixture = "thruster-burn";
|
||||||
|
|
||||||
|
private readonly HashSet<ThrusterComponent> _activeThrusters = new();
|
||||||
|
|
||||||
|
// Used for accumulating burn if someone touches a firing thruster.
|
||||||
|
|
||||||
|
private float _accumulator;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, ActivateInWorldEvent>(OnActivateThruster);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, ComponentInit>(OnThrusterInit);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, ComponentShutdown>(OnThrusterShutdown);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, PowerChangedEvent>(OnPowerChange);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, AnchorStateChangedEvent>(OnAnchorChange);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, RotateEvent>(OnRotate);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, StartCollideEvent>(OnStartCollide);
|
||||||
|
SubscribeLocalEvent<ThrusterComponent, EndCollideEvent>(OnEndCollide);
|
||||||
|
|
||||||
|
_mapManager.TileChanged += OnTileChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
_mapManager.TileChanged -= OnTileChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTileChange(object? sender, TileChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// If the old tile was space but the new one isn't then disable all adjacent thrusters
|
||||||
|
if (e.NewTile.IsSpace() || !e.OldTile.IsSpace()) return;
|
||||||
|
|
||||||
|
var tilePos = e.NewTile.GridIndices;
|
||||||
|
|
||||||
|
for (var x = -1; x <= 1; x++)
|
||||||
|
{
|
||||||
|
for (var y = -1; y <= 1; y++)
|
||||||
|
{
|
||||||
|
if (x != 0 && y != 0) continue;
|
||||||
|
|
||||||
|
var checkPos = tilePos + new Vector2i(x, y);
|
||||||
|
|
||||||
|
foreach (var ent in _mapManager.GetGrid(e.NewTile.GridIndex).GetAnchoredEntities(checkPos))
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(ent, out ThrusterComponent? thruster) || thruster.Type == ThrusterType.Angular) continue;
|
||||||
|
|
||||||
|
// Work out if the thruster is facing this direction
|
||||||
|
var direction = EntityManager.GetComponent<TransformComponent>(ent).LocalRotation.ToWorldVec();
|
||||||
|
|
||||||
|
if (new Vector2i((int) direction.X, (int) direction.Y) != new Vector2i(x, y)) continue;
|
||||||
|
|
||||||
|
DisableThruster(ent, thruster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActivateThruster(EntityUid uid, ThrusterComponent component, ActivateInWorldEvent args)
|
||||||
|
{
|
||||||
|
component.Enabled ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the thruster rotates change the direction where the linear thrust is applied
|
||||||
|
/// </summary>
|
||||||
|
private void OnRotate(EntityUid uid, ThrusterComponent component, ref RotateEvent args)
|
||||||
|
{
|
||||||
|
// TODO: Disable visualizer for old direction
|
||||||
|
|
||||||
|
if (!component.IsOn ||
|
||||||
|
component.Type != ThrusterType.Linear ||
|
||||||
|
!EntityManager.TryGetComponent(uid, out TransformComponent? xform) ||
|
||||||
|
!_mapManager.TryGetGrid(xform.GridID, out var grid) ||
|
||||||
|
!EntityManager.TryGetComponent(grid.GridEntityId, out ShuttleComponent? shuttleComponent)) return;
|
||||||
|
|
||||||
|
var oldDirection = (int) args.OldRotation.GetCardinalDir() / 2;
|
||||||
|
var direction = (int) args.NewRotation.GetCardinalDir() / 2;
|
||||||
|
|
||||||
|
shuttleComponent.LinearThrusterImpulse[oldDirection] -= component.Impulse;
|
||||||
|
DebugTools.Assert(shuttleComponent.LinearThrusters[oldDirection].Contains(component));
|
||||||
|
shuttleComponent.LinearThrusters[oldDirection].Remove(component);
|
||||||
|
|
||||||
|
shuttleComponent.LinearThrusterImpulse[direction] += component.Impulse;
|
||||||
|
DebugTools.Assert(!shuttleComponent.LinearThrusters[direction].Contains(component));
|
||||||
|
shuttleComponent.LinearThrusters[direction].Add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAnchorChange(EntityUid uid, ThrusterComponent component, ref AnchorStateChangedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Anchored && CanEnable(uid, component))
|
||||||
|
{
|
||||||
|
EnableThruster(uid, component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisableThruster(uid, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnThrusterInit(EntityUid uid, ThrusterComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
_ambient.SetAmbience(uid, false);
|
||||||
|
|
||||||
|
if (!component.Enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanEnable(uid, component))
|
||||||
|
{
|
||||||
|
EnableThruster(uid, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnThrusterShutdown(EntityUid uid, ThrusterComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
DisableThruster(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerChange(EntityUid uid, ThrusterComponent component, PowerChangedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Powered && CanEnable(uid, component))
|
||||||
|
{
|
||||||
|
EnableThruster(uid, component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisableThruster(uid, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to enable the thruster and turn it on. If it's already enabled it does nothing.
|
||||||
|
/// </summary>
|
||||||
|
public void EnableThruster(EntityUid uid, ThrusterComponent component, TransformComponent? xform = null)
|
||||||
|
{
|
||||||
|
if (component.IsOn ||
|
||||||
|
!Resolve(uid, ref xform) ||
|
||||||
|
!_mapManager.TryGetGrid(xform.GridID, out var grid)) return;
|
||||||
|
|
||||||
|
component.IsOn = true;
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent(grid.GridEntityId, out ShuttleComponent? shuttleComponent)) return;
|
||||||
|
|
||||||
|
Logger.DebugS("thruster", $"Enabled thruster {uid}");
|
||||||
|
|
||||||
|
switch (component.Type)
|
||||||
|
{
|
||||||
|
case ThrusterType.Linear:
|
||||||
|
var direction = (int) xform.LocalRotation.GetCardinalDir() / 2;
|
||||||
|
|
||||||
|
shuttleComponent.LinearThrusterImpulse[direction] += component.Impulse;
|
||||||
|
DebugTools.Assert(!shuttleComponent.LinearThrusters[direction].Contains(component));
|
||||||
|
shuttleComponent.LinearThrusters[direction].Add(component);
|
||||||
|
|
||||||
|
// Don't just add / remove the fixture whenever the thruster fires because perf
|
||||||
|
if (EntityManager.TryGetComponent(uid, out PhysicsComponent? physicsComponent) &&
|
||||||
|
component.BurnPoly.Count > 0)
|
||||||
|
{
|
||||||
|
var shape = new PolygonShape();
|
||||||
|
|
||||||
|
shape.SetVertices(component.BurnPoly);
|
||||||
|
|
||||||
|
var fixture = new Fixture(physicsComponent, shape)
|
||||||
|
{
|
||||||
|
ID = BurnFixture,
|
||||||
|
Hard = false,
|
||||||
|
CollisionLayer = (int) CollisionGroup.MobImpassable
|
||||||
|
};
|
||||||
|
|
||||||
|
_broadphase.CreateFixture(physicsComponent, fixture);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ThrusterType.Angular:
|
||||||
|
shuttleComponent.AngularThrust += component.Impulse;
|
||||||
|
DebugTools.Assert(!shuttleComponent.AngularThrusters.Contains(component));
|
||||||
|
shuttleComponent.AngularThrusters.Add(component);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(uid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.State, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ambient.SetAmbience(uid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to disable the thruster.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"></param>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
/// <param name="xform"></param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public void DisableThruster(EntityUid uid, ThrusterComponent component, TransformComponent? xform = null)
|
||||||
|
{
|
||||||
|
if (!component.IsOn ||
|
||||||
|
!Resolve(uid, ref xform) ||
|
||||||
|
!_mapManager.TryGetGrid(xform.GridID, out var grid)) return;
|
||||||
|
|
||||||
|
component.IsOn = false;
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent(grid.GridEntityId, out ShuttleComponent? shuttleComponent)) return;
|
||||||
|
|
||||||
|
Logger.DebugS("thruster", $"Disabled thruster {uid}");
|
||||||
|
|
||||||
|
switch (component.Type)
|
||||||
|
{
|
||||||
|
case ThrusterType.Linear:
|
||||||
|
var direction = ((int) xform.LocalRotation.GetCardinalDir() / 2);
|
||||||
|
|
||||||
|
shuttleComponent.LinearThrusterImpulse[direction] -= component.Impulse;
|
||||||
|
DebugTools.Assert(shuttleComponent.LinearThrusters[direction].Contains(component));
|
||||||
|
shuttleComponent.LinearThrusters[direction].Remove(component);
|
||||||
|
break;
|
||||||
|
case ThrusterType.Angular:
|
||||||
|
shuttleComponent.AngularThrust -= component.Impulse;
|
||||||
|
DebugTools.Assert(shuttleComponent.AngularThrusters.Contains(component));
|
||||||
|
shuttleComponent.AngularThrusters.Remove(component);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(uid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.State, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ambient.SetAmbience(uid, false);
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(uid, out PhysicsComponent? physicsComponent))
|
||||||
|
{
|
||||||
|
_broadphase.DestroyFixture(physicsComponent, BurnFixture);
|
||||||
|
}
|
||||||
|
|
||||||
|
_activeThrusters.Remove(component);
|
||||||
|
component.Colliding.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanEnable(EntityUid uid, ThrusterComponent component)
|
||||||
|
{
|
||||||
|
if (!component.Enabled) return false;
|
||||||
|
|
||||||
|
var xform = EntityManager.GetComponent<TransformComponent>(uid);
|
||||||
|
|
||||||
|
if (!xform.Anchored ||
|
||||||
|
EntityManager.TryGetComponent(uid, out ApcPowerReceiverComponent? receiver) && !receiver.Powered)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Type == ThrusterType.Angular)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var (x, y) = xform.LocalPosition + xform.LocalRotation.Opposite().ToWorldVec();
|
||||||
|
var tile = _mapManager.GetGrid(xform.GridID).GetTileRef(new Vector2i((int) Math.Floor(x), (int) Math.Floor(y)));
|
||||||
|
|
||||||
|
return tile.Tile.IsSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Burning
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
_accumulator += frameTime;
|
||||||
|
|
||||||
|
if (_accumulator < 1) return;
|
||||||
|
|
||||||
|
_accumulator -= 1;
|
||||||
|
|
||||||
|
foreach (var comp in _activeThrusters.ToArray())
|
||||||
|
{
|
||||||
|
if (!comp.Firing || comp.Damage == null || comp.Paused || comp.Deleted) continue;
|
||||||
|
|
||||||
|
DebugTools.Assert(comp.Colliding.Count > 0);
|
||||||
|
|
||||||
|
foreach (var uid in comp.Colliding.ToArray())
|
||||||
|
{
|
||||||
|
_damageable.TryChangeDamage(uid, comp.Damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartCollide(EntityUid uid, ThrusterComponent component, StartCollideEvent args)
|
||||||
|
{
|
||||||
|
if (args.OurFixture.ID != BurnFixture) return;
|
||||||
|
|
||||||
|
_activeThrusters.Add(component);
|
||||||
|
component.Colliding.Add(args.OtherFixture.Body.OwnerUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEndCollide(EntityUid uid, ThrusterComponent component, EndCollideEvent args)
|
||||||
|
{
|
||||||
|
if (args.OurFixture.ID != BurnFixture) return;
|
||||||
|
|
||||||
|
component.Colliding.Remove(args.OtherFixture.Body.OwnerUid);
|
||||||
|
|
||||||
|
if (component.Colliding.Count == 0)
|
||||||
|
{
|
||||||
|
_activeThrusters.Remove(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Considers a thrust direction as being active.
|
||||||
|
/// </summary>
|
||||||
|
public void EnableThrustDirection(ShuttleComponent component, DirectionFlag direction)
|
||||||
|
{
|
||||||
|
if ((component.ThrustDirections & direction) != 0x0) return;
|
||||||
|
|
||||||
|
component.ThrustDirections |= direction;
|
||||||
|
|
||||||
|
if ((direction & (DirectionFlag.East | DirectionFlag.West)) != 0x0)
|
||||||
|
{
|
||||||
|
switch (component.Mode)
|
||||||
|
{
|
||||||
|
case ShuttleMode.Cruise:
|
||||||
|
foreach (var comp in component.AngularThrusters)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = true;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShuttleMode.Docking:
|
||||||
|
var index = GetFlagIndex(direction);
|
||||||
|
|
||||||
|
foreach (var comp in component.LinearThrusters[index])
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = true;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var index = GetFlagIndex(direction);
|
||||||
|
|
||||||
|
foreach (var comp in component.LinearThrusters[index])
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = true;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disables a thrust direction.
|
||||||
|
/// </summary>
|
||||||
|
public void DisableThrustDirection(ShuttleComponent component, DirectionFlag direction)
|
||||||
|
{
|
||||||
|
if ((component.ThrustDirections & direction) == 0x0) return;
|
||||||
|
|
||||||
|
component.ThrustDirections &= ~direction;
|
||||||
|
|
||||||
|
if ((direction & (DirectionFlag.East | DirectionFlag.West)) != 0x0)
|
||||||
|
{
|
||||||
|
switch (component.Mode)
|
||||||
|
{
|
||||||
|
case ShuttleMode.Cruise:
|
||||||
|
foreach (var comp in component.AngularThrusters)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = false;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShuttleMode.Docking:
|
||||||
|
var index = GetFlagIndex(direction);
|
||||||
|
|
||||||
|
foreach (var comp in component.LinearThrusters[index])
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = false;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var index = GetFlagIndex(direction);
|
||||||
|
|
||||||
|
foreach (var comp in component.LinearThrusters[index])
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(comp.OwnerUid, out SharedAppearanceComponent? appearanceComponent))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comp.Firing = false;
|
||||||
|
appearanceComponent.SetData(ThrusterVisualState.Thrusting, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableAllThrustDirections(ShuttleComponent component)
|
||||||
|
{
|
||||||
|
foreach (DirectionFlag dir in Enum.GetValues(typeof(DirectionFlag)))
|
||||||
|
{
|
||||||
|
DisableThrustDirection(component, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugTools.Assert(component.ThrustDirections == DirectionFlag.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int GetFlagIndex(DirectionFlag flag)
|
||||||
|
{
|
||||||
|
return (int) Math.Log2((int) flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Content.Shared.Shuttles;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Server.Shuttles
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class ShuttleComponent : SharedShuttleComponent {}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ using Robust.Shared.Players;
|
|||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Shared.Shuttles
|
namespace Content.Shared.Shuttles.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores what shuttle this entity is currently piloting.
|
/// Stores what shuttle this entity is currently piloting.
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Shared.Shuttles
|
namespace Content.Shared.Shuttles.Components
|
||||||
{
|
{
|
||||||
public abstract class SharedDockingComponent : Component
|
public abstract class SharedDockingComponent : Component
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Shared.Shuttles
|
namespace Content.Shared.Shuttles.Components
|
||||||
{
|
{
|
||||||
public abstract class SharedShuttleComponent : Component
|
public abstract class SharedShuttleComponent : Component
|
||||||
{
|
{
|
||||||
@@ -10,12 +10,6 @@ namespace Content.Shared.Shuttles
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public virtual bool Enabled { get; set; } = true;
|
public virtual bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How much our linear impulse is multiplied by.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float SpeedMultipler { get; set; } = 200.0f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public ShuttleMode Mode { get; set; } = ShuttleMode.Cruise;
|
public ShuttleMode Mode { get; set; } = ShuttleMode.Cruise;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
namespace Content.Shared.Shuttles
|
namespace Content.Shared.Shuttles.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interact with to start piloting a shuttle.
|
/// Interact with to start piloting a shuttle.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Shuttles.Components
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum ThrusterVisualState : byte
|
||||||
|
{
|
||||||
|
State,
|
||||||
|
Thrusting,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Movement;
|
using Content.Shared.Movement;
|
||||||
|
using Content.Shared.Shuttles.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Shared.Shuttles
|
namespace Content.Shared.Shuttles
|
||||||
|
|||||||
BIN
Resources/Audio/Effects/shuttle_thruster.ogg
Normal file
@@ -1,4 +1,4 @@
|
|||||||
# RotatableComponenet
|
# RotatableComponent
|
||||||
rotatable-component-try-rotate-stuck = It's stuck.
|
rotatable-component-try-rotate-stuck = It's stuck.
|
||||||
|
|
||||||
# RotateVerb
|
# RotateVerb
|
||||||
|
|||||||
23
Resources/Prototypes/Catalog/Cargo/cargo_shuttle.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
- type: cargoProduct
|
||||||
|
name: shuttle thruster
|
||||||
|
id: ShuttleThruster
|
||||||
|
description: A thruster that allows a shuttle to move.
|
||||||
|
icon:
|
||||||
|
sprite: Structures/Shuttles/thruster.rsi
|
||||||
|
state: base
|
||||||
|
product: Thruster
|
||||||
|
cost: 1500
|
||||||
|
category: Shuttle
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
name: shuttle gyroscope
|
||||||
|
id: ShuttleGyroscope
|
||||||
|
description: 1 gyroscope for use in rotating a shuttle.
|
||||||
|
icon:
|
||||||
|
sprite: Structures/Shuttles/gyroscope.rsi
|
||||||
|
state: base
|
||||||
|
product: Gyroscope
|
||||||
|
cost: 4000
|
||||||
|
category: Shuttle
|
||||||
|
group: market
|
||||||
@@ -269,6 +269,8 @@
|
|||||||
- EngineSingularityGenerator
|
- EngineSingularityGenerator
|
||||||
- EngineSingularityContainment
|
- EngineSingularityContainment
|
||||||
- EngineParticleAccelerator
|
- EngineParticleAccelerator
|
||||||
|
- ShuttleThruster
|
||||||
|
- ShuttleGyroscope
|
||||||
- AtmosphericsAir
|
- AtmosphericsAir
|
||||||
- AtmosphericsOxygen
|
- AtmosphericsOxygen
|
||||||
- AtmosphericsNitrogen
|
- AtmosphericsNitrogen
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
- type: entity
|
||||||
|
id: BaseThruster
|
||||||
|
parent: BaseStructureDynamic
|
||||||
|
name: thruster
|
||||||
|
description: It goes nyooooooom.
|
||||||
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: AmbientSound
|
||||||
|
range: 4
|
||||||
|
volume: -5
|
||||||
|
sound:
|
||||||
|
path: /Audio/Effects/shuttle_thruster.ogg
|
||||||
|
- type: Transform
|
||||||
|
anchored: true
|
||||||
|
- type: Rotatable
|
||||||
|
rotateWhileAnchored: true
|
||||||
|
- type: Thruster
|
||||||
|
damage:
|
||||||
|
groups:
|
||||||
|
Burn: 40
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: ThrusterVisualizer
|
||||||
|
- type: ApcPowerReceiver
|
||||||
|
powerLoad: 1500
|
||||||
|
- type: ExtensionCableReceiver
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Inorganic
|
||||||
|
damageModifierSet: Metallic
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 300 # Considering we need a lot of thrusters didn't want to make an individual one too tanky
|
||||||
|
behaviors:
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: ["Destruction"]
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: Thruster
|
||||||
|
parent: BaseThruster
|
||||||
|
name: thruster
|
||||||
|
description: It goes nyooooooom.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Shuttles/thruster.rsi
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
map: ["enum.ThrusterVisualLayers.Base"]
|
||||||
|
- state: thrust
|
||||||
|
map: ["enum.ThrusterVisualLayers.ThrustOn"]
|
||||||
|
shader: unshaded
|
||||||
|
- state: thrust_burn_unshaded
|
||||||
|
map: ["enum.ThrusterVisualLayers.ThrustingUnshaded"]
|
||||||
|
shader: unshaded
|
||||||
|
offset: 0, 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: Gyroscope
|
||||||
|
parent: BaseThruster
|
||||||
|
name: Gyroscope
|
||||||
|
description: Increases the shuttle's potential angular rotation.
|
||||||
|
components:
|
||||||
|
- type: Thruster
|
||||||
|
thrusterType: Angular
|
||||||
|
impulse: 2
|
||||||
|
- type: Sprite
|
||||||
|
# Listen I'm not the biggest fan of the sprite but it was the most appropriate thing I could find.
|
||||||
|
sprite: Structures/Shuttles/gyroscope.rsi
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
map: ["enum.ThrusterVisualLayers.Base"]
|
||||||
|
- state: thrust
|
||||||
|
map: ["enum.ThrusterVisualLayers.ThrustOn"]
|
||||||
|
shader: unshaded
|
||||||
|
- state: thrust_burn
|
||||||
|
map: [ "enum.ThrusterVisualLayers.Thrusting" ]
|
||||||
|
- state: thrust_burn_unshaded
|
||||||
|
map: ["enum.ThrusterVisualLayers.ThrustingUnshaded"]
|
||||||
|
shader: unshaded
|
||||||
BIN
Resources/Textures/Structures/Shuttles/gyroscope.rsi/base.png
Normal file
|
After Width: | Height: | Size: 687 B |
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"copyright": "Taken from https://github.com/discordia-space/CEV-Eris/tree/23e73e051a838bc190a589d6d464a318c641b6a5",
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "base"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thrust"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thrust_burn",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thrust_burn_unshaded",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Structures/Shuttles/gyroscope.rsi/thrust.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
BIN
Resources/Textures/Structures/Shuttles/thruster.rsi/base.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"copyright": "Taken from https://github.com/Baystation12/Baystation12/tree/7274e5654c3cf82d4104dbf818ef00fdc0082aa8",
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "base",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thrust",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thrust_burn_unshaded",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1,
|
||||||
|
0.1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Structures/Shuttles/thruster.rsi/thrust.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |