Files
tbd-station-14/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs
Paul Ritter 512d6a38c3 get that crap outta here (completely rewrites inventorysystem) (#5807)
* some work

* equip: done
unequip: todo

* unequipping done & refactored events

* workin

* movin

* reee namespaces

* stun

* mobstate

* fixes

* some work on events

* removes serverside itemcomp & misc fixes

* work

* smol merge fix

* ports template to prototype & finishes ui

* moves relay & adds containerenumerator

* actions & cuffs

* my god what is actioncode

* more fixes

* im loosing my grasp on reality

* more fixes

* more work

* explosions

* yes

* more work

* more fixes

* merge master & misc fixed because i forgot to commit before merging master

* more fixes

* fixes

* moar

* more work

* moar fixes

* suffixmap

* more work on client

* motivation low

* no. no containers

* mirroring client to server

* fixes

* move serverinvcomp

* serverinventorycomponent is dead

* gaming

* only strippable & ai left...

* only ai and richtext left

* fixes ai

* fixes

* fixes sprite layers

* more fixes

* resolves optional

* yes

* stable™️

* fixes

* moar fixes

* moar

* fix some tests

* lmao

* no comment

* good to merge™️

* fixes build but for real

* adresses some reviews

* adresses some more reviews

* nullables, yo

* fixes lobbyscreen

* timid refactor to differentiate actor & target

* adresses more reviews

* more

* my god what a mess

* removed the rest of duplicates

* removed duplicate slotflags and renamed shoes to feet

* removes another unused one

* yes

* fixes lobby & makes tryunequip return unequipped item

* fixes

* some funny renames

* fixes

* misc improvements to attemptevents

* fixes

* merge fixes

Co-authored-by: Paul Ritter <ritter.paul1@gmail.com>
2021-12-30 22:56:10 +01:00

314 lines
12 KiB
C#

using System;
using Content.Server.Access.Systems;
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Popups;
using Content.Shared.ActionBlocker;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Medical.SuitSensor;
using Content.Shared.MobState.Components;
using Content.Shared.Verbs;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Medical.SuitSensors
{
public class SuitSensorSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private const float UpdateRate = 0.5f;
private float _updateDif;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SuitSensorComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SuitSensorComponent, GotEquippedEvent>(OnEquipped);
SubscribeLocalEvent<SuitSensorComponent, GotUnequippedEvent>(OnUnequipped);
SubscribeLocalEvent<SuitSensorComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<SuitSensorComponent, GetInteractionVerbsEvent>(OnVerb);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
// check update rate
_updateDif += frameTime;
if (_updateDif < UpdateRate)
return;
_updateDif -= UpdateRate;
var curTime = _gameTiming.CurTime;
var sensors = EntityManager.EntityQuery<SuitSensorComponent, DeviceNetworkComponent>();
foreach (var (sensor, device) in sensors)
{
// check if sensor is ready to update
if (curTime - sensor.LastUpdate < TimeSpan.FromSeconds(sensor.UpdateRate))
continue;
sensor.LastUpdate = curTime;
// get sensor status
var status = GetSensorState(sensor.Owner, sensor);
if (status == null)
continue;
// broadcast it to device network
var payload = SuitSensorToPacket(status);
_deviceNetworkSystem.QueuePacket(sensor.Owner, DeviceNetworkConstants.NullAddress, device.Frequency, payload, true);
}
}
private void OnMapInit(EntityUid uid, SuitSensorComponent component, MapInitEvent args)
{
// generate random mode
if (component.RandomMode)
{
//make the sensor mode favor higher levels, except coords.
var modesDist = new[]
{
SuitSensorMode.SensorOff,
SuitSensorMode.SensorBinary, SuitSensorMode.SensorBinary,
SuitSensorMode.SensorVitals, SuitSensorMode.SensorVitals, SuitSensorMode.SensorVitals,
SuitSensorMode.SensorCords, SuitSensorMode.SensorCords
};
component.Mode = _random.Pick(modesDist);
}
}
private void OnEquipped(EntityUid uid, SuitSensorComponent component, GotEquippedEvent args)
{
if (args.Slot != component.ActivationSlot)
return;
component.User = args.Equipee;
}
private void OnUnequipped(EntityUid uid, SuitSensorComponent component, GotUnequippedEvent args)
{
if (args.Slot != component.ActivationSlot)
return;
component.User = null;
}
private void OnExamine(EntityUid uid, SuitSensorComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange)
return;
string msg;
switch (component.Mode)
{
case SuitSensorMode.SensorOff:
msg = "suit-sensor-examine-off";
break;
case SuitSensorMode.SensorBinary:
msg = "suit-sensor-examine-binary";
break;
case SuitSensorMode.SensorVitals:
msg = "suit-sensor-examine-vitals";
break;
case SuitSensorMode.SensorCords:
msg = "suit-sensor-examine-cords";
break;
default:
return;
}
args.PushMarkup(Loc.GetString(msg));
}
private void OnVerb(EntityUid uid, SuitSensorComponent component, GetInteractionVerbsEvent args)
{
// check if user can change sensor
if (component.ControlsLocked)
return;
// standard interaction checks
if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanDrop(args.User))
return;
args.Verbs.UnionWith(new[]
{
CreateVerb(uid, component, args.User, SuitSensorMode.SensorOff),
CreateVerb(uid, component, args.User, SuitSensorMode.SensorBinary),
CreateVerb(uid, component, args.User, SuitSensorMode.SensorVitals),
CreateVerb(uid, component, args.User, SuitSensorMode.SensorCords)
});
}
private Verb CreateVerb(EntityUid uid, SuitSensorComponent component, EntityUid userUid, SuitSensorMode mode)
{
return new Verb()
{
Text = GetModeName(mode),
Disabled = component.Mode == mode,
Priority = -(int) mode, // sort them in descending order
Category = VerbCategory.SetSensor,
Act = () => SetSensor(uid, mode, userUid, component)
};
}
private string GetModeName(SuitSensorMode mode)
{
string name;
switch (mode)
{
case SuitSensorMode.SensorOff:
name = "suit-sensor-mode-off";
break;
case SuitSensorMode.SensorBinary:
name = "suit-sensor-mode-binary";
break;
case SuitSensorMode.SensorVitals:
name = "suit-sensor-mode-vitals";
break;
case SuitSensorMode.SensorCords:
name = "suit-sensor-mode-cords";
break;
default:
return "";
}
return Loc.GetString(name);
}
public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = null,
SuitSensorComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
component.Mode = mode;
if (userUid != null)
{
var msg = Loc.GetString("suit-sensor-mode-state", ("mode", GetModeName(mode)));
_popupSystem.PopupEntity(msg, uid, Filter.Entities(userUid.Value));
}
}
public SuitSensorStatus? GetSensorState(EntityUid uid, SuitSensorComponent? sensor = null, TransformComponent? transform = null)
{
if (!Resolve(uid, ref sensor, ref transform))
return null;
// check if sensor is enabled and worn by user
if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null)
return null;
// try to get mobs id from ID slot
var userName = Loc.GetString("suit-sensor-component-unknown-name");
var userJob = Loc.GetString("suit-sensor-component-unknown-job");
if (_idCardSystem.TryFindIdCard(sensor.User.Value, out var card))
{
if (card.FullName != null)
userName = card.FullName;
if (card.JobTitle != null)
userJob = card.JobTitle;
}
// get health mob state
var isAlive = false;
if (EntityManager.TryGetComponent(sensor.User.Value, out MobStateComponent? mobState))
{
isAlive = mobState.IsAlive();
}
// get mob total damage
var totalDamage = 0;
if (EntityManager.TryGetComponent(sensor.User.Value, out DamageableComponent? damageable))
{
totalDamage = damageable.TotalDamage.Int();
}
// finally, form suit sensor status
var status = new SuitSensorStatus(userName, userJob);
switch (sensor.Mode)
{
case SuitSensorMode.SensorBinary:
status.IsAlive = isAlive;
break;
case SuitSensorMode.SensorVitals:
status.IsAlive = isAlive;
status.TotalDamage = totalDamage;
break;
case SuitSensorMode.SensorCords:
status.IsAlive = isAlive;
status.TotalDamage = totalDamage;
status.Coordinates = transform.MapPosition;
break;
}
return status;
}
/// <summary>
/// Serialize suit sensor status into device network package.
/// </summary>
public NetworkPayload SuitSensorToPacket(SuitSensorStatus status)
{
var payload = new NetworkPayload()
{
[DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState,
[SuitSensorConstants.NET_NAME] = status.Name,
[SuitSensorConstants.NET_JOB] = status.Job,
[SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive,
};
if (status.TotalDamage != null)
payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE, status.TotalDamage);
if (status.Coordinates != null)
payload.Add(SuitSensorConstants.NET_CORDINATES, status.Coordinates);
return payload;
}
/// <summary>
/// Try to deserialize device network message into suit sensor status
/// </summary>
public SuitSensorStatus? PacketToSuitSensor(NetworkPayload payload)
{
// check command
if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command))
return null;
if (command != DeviceNetworkConstants.CmdUpdatedState)
return null;
// check name, job and alive
if (!payload.TryGetValue(SuitSensorConstants.NET_NAME, out string? name)) return null;
if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null;
if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null;
// try get total damage and cords (optionals)
payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage);
payload.TryGetValue(SuitSensorConstants.NET_CORDINATES, out MapCoordinates? cords);
var status = new SuitSensorStatus(name, job)
{
IsAlive = isAlive.Value,
TotalDamage = totalDamage,
Coordinates = cords
};
return status;
}
}
}