* RPED

* sound effect

* wires must be open

finished me appy slices yum yum

* Update Resources/Audio/Items/attributions.yml

Co-authored-by: Zonespace <41448081+Zonespace27@users.noreply.github.com>

* Update attributions.yml

Co-authored-by: Zonespace <41448081+Zonespace27@users.noreply.github.com>
This commit is contained in:
Nemanja
2022-11-14 11:36:13 -08:00
committed by GitHub
parent d5ae5658a1
commit 72e7a9ee93
14 changed files with 251 additions and 2 deletions

View File

@@ -10,7 +10,9 @@ namespace Content.Server.Construction.Components
[DataField("board", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? BoardPrototype { get; private set; }
[ViewVariables]
public Container BoardContainer = default!;
[ViewVariables]
public Container PartContainer = default!;
}

View File

@@ -0,0 +1,32 @@
using System.Threading;
using Robust.Shared.Audio;
namespace Content.Server.Construction.Components;
[RegisterComponent]
public sealed class PartExchangerComponent : Component
{
/// <summary>
/// How long it takes to exchange the parts
/// </summary>
[DataField("exchangeDuration")]
public float ExchangeDuration = 3;
/// <summary>
/// Whether or not the distance check is needed.
/// Good for BRPED.
/// </summary>
/// <remarks>
/// I fucking hate BRPED and if you ever add it
/// i will personally kill your dog.
/// </remarks>
[DataField("doDistanceCheck")]
public bool DoDistanceCheck = true;
[DataField("exchangeSound")]
public SoundSpecifier ExchangeSound = new SoundPathSpecifier("/Audio/Items/rped.ogg");
public IPlayingAudioStream? AudioStream;
public CancellationTokenSource? Token;
}

View File

@@ -0,0 +1,142 @@
using System.Linq;
using System.Threading;
using Content.Server.Construction.Components;
using Content.Server.DoAfter;
using Content.Server.Storage.Components;
using Content.Server.Storage.EntitySystems;
using Content.Server.Wires;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Construction;
public sealed class PartExchangerSystem : EntitySystem
{
[Dependency] private readonly ConstructionSystem _construction = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StorageSystem _storage = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PartExchangerComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<PartExchangerComponent, RpedExchangeFinishedEvent>(OnFinished);
SubscribeLocalEvent<PartExchangerComponent, RpedExchangeCancelledEvent>(OnCancelled);
}
private void OnFinished(EntityUid uid, PartExchangerComponent component, RpedExchangeFinishedEvent args)
{
component.Token = null;
component.AudioStream?.Stop();
if (!TryComp<MachineComponent>(args.Target, out var machine))
return;
if (!TryComp<ServerStorageComponent>(uid, out var storage) || storage.Storage == null)
return; //the parts are stored in here
var board = machine.BoardContainer.ContainedEntities.FirstOrNull();
if (board == null || !TryComp<MachineBoardComponent>(board, out var macBoardComp))
return;
var machineParts = new List<MachinePartComponent>();
foreach (var ent in storage.Storage.ContainedEntities) //get parts in RPED
{
if (TryComp<MachinePartComponent>(ent, out var part))
machineParts.Add(part);
}
foreach (var ent in new List<EntityUid>(machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
{
if (TryComp<MachinePartComponent>(ent, out var part))
{
machineParts.Add(part);
_container.RemoveEntity(machine.Owner, ent);
}
}
//order by highest rating
machineParts = machineParts.OrderByDescending(p => p.Rating).ToList();
var updatedParts = new List<MachinePartComponent>();
foreach (var (type, amount) in macBoardComp.Requirements)
{
var target = machineParts.Where(p => p.PartType == type).Take(amount);
updatedParts.AddRange(target);
}
foreach (var part in updatedParts)
{
machine.PartContainer.Insert(part.Owner, EntityManager);
machineParts.Remove(part);
}
//put the unused parts back into rped. (this also does the "swapping")
foreach (var unused in machineParts)
{
storage.Storage.Insert(unused.Owner);
_storage.Insert(uid, unused.Owner, null, false);
}
_construction.RefreshParts(machine);
}
private void OnCancelled(EntityUid uid, PartExchangerComponent component, RpedExchangeCancelledEvent args)
{
component.Token = null;
component.AudioStream?.Stop();
}
private void OnAfterInteract(EntityUid uid, PartExchangerComponent component, AfterInteractEvent args)
{
if (component.Token != null)
return;
if (component.DoDistanceCheck && !args.CanReach)
return;
if (args.Target == null)
return;
if (!HasComp<MachineComponent>(args.Target))
return;
if (TryComp<WiresComponent>(args.Target, out var wires) && !wires.IsPanelOpen)
{
_popup.PopupEntity(Loc.GetString("construction-step-condition-wire-panel-open"),
args.Target.Value, Filter.Pvs(args.Target.Value, entityManager: EntityManager));
return;
}
component.AudioStream = _audio.PlayPvs(component.ExchangeSound, uid);
component.Token = new CancellationTokenSource();
_doAfter.DoAfter(new DoAfterEventArgs(args.User, component.ExchangeDuration, component.Token.Token, args.Target, args.Used)
{
BreakOnDamage = true,
BreakOnStun = true,
BreakOnUserMove = true,
UsedFinishedEvent = new RpedExchangeFinishedEvent(args.Target.Value),
UsedCancelledEvent = new RpedExchangeCancelledEvent()
});
}
}
public sealed class RpedExchangeFinishedEvent : EntityEventArgs
{
public readonly EntityUid Target;
public RpedExchangeFinishedEvent(EntityUid target)
{
Target = target;
}
}
public readonly struct RpedExchangeCancelledEvent
{
}

View File

@@ -89,6 +89,16 @@ namespace Content.Server.DoAfter
/// </summary>
public object? UserFinishedEvent { get; set; }
/// <summary>
/// Event to be raised directed to the <see cref="Used"/> entity when the DoAfter is cancelled.
/// </summary>
public object? UsedCancelledEvent { get; set; }
/// <summary>
/// Event to be raised directed to the <see cref="Used"/> entity when the DoAfter is finished successfully.
/// </summary>
public object? UsedFinishedEvent { get; set; }
/// <summary>
/// Event to be raised directed to the <see cref="Target"/> entity when the DoAfter is cancelled.
/// </summary>

View File

@@ -153,6 +153,9 @@ namespace Content.Server.DoAfter
if(EntityManager.EntityExists(doAfter.EventArgs.User) && doAfter.EventArgs.UserCancelledEvent != null)
RaiseLocalEvent(doAfter.EventArgs.User, doAfter.EventArgs.UserCancelledEvent, false);
if (doAfter.EventArgs.Used is {} used && EntityManager.EntityExists(used) && doAfter.EventArgs.UsedCancelledEvent != null)
RaiseLocalEvent(used, doAfter.EventArgs.UsedCancelledEvent);
if(doAfter.EventArgs.Target is {} target && EntityManager.EntityExists(target) && doAfter.EventArgs.TargetCancelledEvent != null)
RaiseLocalEvent(target, doAfter.EventArgs.TargetCancelledEvent, false);
@@ -167,6 +170,9 @@ namespace Content.Server.DoAfter
if(EntityManager.EntityExists(doAfter.EventArgs.User) && doAfter.EventArgs.UserFinishedEvent != null)
RaiseLocalEvent(doAfter.EventArgs.User, doAfter.EventArgs.UserFinishedEvent, false);
if(doAfter.EventArgs.Used is {} used && EntityManager.EntityExists(used) && doAfter.EventArgs.UsedFinishedEvent != null)
RaiseLocalEvent(used, doAfter.EventArgs.UsedFinishedEvent);
if(doAfter.EventArgs.Target is {} target && EntityManager.EntityExists(target) && doAfter.EventArgs.TargetFinishedEvent != null)
RaiseLocalEvent(target, doAfter.EventArgs.TargetFinishedEvent, false);

View File

@@ -6,4 +6,9 @@
- files: ["trayhit2.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Time immemorial"
source: "https://github.com/tgstation/tgstation/blob/172b533d0257fcc1f8a05406f1c9fad514c14d88/sound/items/trayhit2.ogg"
source: "https://github.com/tgstation/tgstation/blob/172b533d0257fcc1f8a05406f1c9fad514c14d88/sound/items/trayhit2.ogg"
- files: ["rped.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Time immemorial"
source: "https://github.com/tgstation/tgstation/blob/172b533d0257fcc1f8a05406f1c9fad514c14d88/sound/items/rped.ogg"

Binary file not shown.

View File

@@ -245,6 +245,7 @@
- FireAlarmElectronics
- MailingUnitElectronics
- HolofanProjector
- RPED
- type: technology
name: technologies-material-sheet-printing
@@ -438,7 +439,6 @@
requiredPoints: 8000
requiredTechnologies:
- BasicPartsTechnology
- IndustrialEngineering
- PowerCellBasic
unlockedRecipes:
- AdvancedCapacitorStockPart

View File

@@ -0,0 +1,18 @@
- type: entity
parent: BaseStorageItem
id: RPED
name: RPED
description: A Rapid Part Exchange Device, perfect for quickly upgrading machines.
components:
- type: Sprite
sprite: Objects/Specific/Research/rped.rsi
state: icon
- type: Item
sprite: Objects/Specific/Research/rped.rsi
size: 50
- type: PartExchanger
- type: Storage
capacity: 150
whitelist:
components:
- MachinePart

View File

@@ -189,3 +189,15 @@
Glass: 350
Plastic: 150
Gold: 10
- type: latheRecipe
id: RPED
icon:
sprite: Objects/Specific/Research/rped.rsi
state: icon
result: RPED
completetime: 10
materials:
Steel: 650
Plastic: 150
Gold: 50

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

View File

@@ -0,0 +1,22 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a, inhands created by EmoGarbage404",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}