Skip to content

Commit

Permalink
Merge branch 'master' into сrossbow
Browse files Browse the repository at this point in the history
  • Loading branch information
Spatison authored Oct 16, 2024
2 parents 063a800 + 8141e99 commit 3023dc7
Show file tree
Hide file tree
Showing 41 changed files with 720 additions and 89 deletions.
60 changes: 60 additions & 0 deletions Content.Client/_White/Overlays/MindSlave/MindSlaveIconsSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Content.Client.Overlays;
using Content.Shared._White.Implants.MindSlave;
using Content.Shared.StatusIcon;
using Content.Shared.StatusIcon.Components;
using Robust.Client.Player;
using Robust.Shared.Prototypes;

namespace Content.Client._White.Overlays.MindSlave;

public sealed class MindSlaveIconsSystem : EquipmentHudSystem<MindSlaveComponent>
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IPlayerManager _player = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<MindSlaveComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
}

private void OnGetStatusIconsEvent(
EntityUid uid,
MindSlaveComponent mindSlaveComponent,
ref GetStatusIconsEvent args)
{
if (!IsActive
|| args.InContainer
|| !TryComp(_player.LocalEntity, out MindSlaveComponent? ownerMindSlave))
return;

var mindSlaveIcon = MindSlaveIcon(uid, ownerMindSlave);
args.StatusIcons.AddRange(mindSlaveIcon);
}

private IEnumerable<StatusIconPrototype> MindSlaveIcon(EntityUid uid, MindSlaveComponent mindSlave)
{
var result = new List<StatusIconPrototype>();
string iconType;
var netUid = GetNetEntity(uid);

if (mindSlave.Master == netUid)
{
iconType = mindSlave.MasterStatusIcon;
}
else if (mindSlave.Slaves.Contains(netUid))
{
iconType = mindSlave.SlaveStatusIcon;
}
else
{
return result;
}

if (_prototype.TryIndex<StatusIconPrototype>(iconType, out var mindslaveIcon))
result.Add(mindslaveIcon);

return result;
}
}
17 changes: 15 additions & 2 deletions Content.Server/Body/Systems/BloodstreamSystem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Server._White.Other.BloodLust;
using Content.Server.Body.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.ReactionEffects;
Expand All @@ -14,6 +15,7 @@
using Content.Shared.Drunk;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Rejuvenate;
using Content.Shared.Speech.EntitySystems;
Expand All @@ -39,6 +41,7 @@ public sealed class BloodstreamSystem : EntitySystem
[Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; // WD

public override void Initialize()
{
Expand Down Expand Up @@ -352,7 +355,7 @@ public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamCom
/// <summary>
/// Attempts to modify the blood level of this entity directly.
/// </summary>
public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null)
public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null, bool createPuddle = true) // WD EDIT
{
if (!Resolve(uid, ref component, logMissing: false)
|| !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution))
Expand All @@ -373,7 +376,7 @@ public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamCo

tempSolution.AddSolution(newSol, _prototypeManager);

if (tempSolution.Volume > component.BleedPuddleThreshold)
if (tempSolution.Volume > component.BleedPuddleThreshold && createPuddle) // WD EDIT
{
// Pass some of the chemstream into the spilled blood.
if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution))
Expand Down Expand Up @@ -406,6 +409,16 @@ public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamCompone
component.BleedAmount += amount;
component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount);

// WD EDIT START
if (HasComp<BloodLustComponent>(uid))
{
if (component.BleedAmount == 0f)
RemComp<BloodLustComponent>(uid);

_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
}
// WD EDIT END

if (component.BleedAmount == 0)
_alertsSystem.ClearAlert(uid, AlertType.Bleed);
else
Expand Down
12 changes: 8 additions & 4 deletions Content.Server/Implants/ImplanterSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,20 @@ private void OnImplanterAfterInteract(EntityUid uid, ImplanterComponent componen
}
else
{
if (!CanImplant(args.User, target, uid, component, out var implant, out _))
if (!CanImplant(args.User, target, uid, component, out var implant, out _, out var popup)) // WD EDIT
{
// no popup if implant doesn't exist
if (implant == null)
return;

// show popup to the user saying implant failed
var name = Identity.Name(target, EntityManager, args.User);
var msg = Loc.GetString("implanter-component-implant-failed", ("implant", implant), ("target", name));
_popup.PopupEntity(msg, target, args.User);
if (popup) // WD EDIT
{
var name = Identity.Name(target, EntityManager, args.User);
var msg = Loc.GetString("implanter-component-implant-failed", ("implant", implant),
("target", name));
_popup.PopupEntity(msg, target, args.User);
}
// prevent further interaction since popup was shown
args.Handled = true;
return;
Expand Down
152 changes: 141 additions & 11 deletions Content.Server/_White/Implants/ImplantsSystem.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using Content.Server.Administration.Logs;
using Content.Server.Chat.Managers;
using Content.Server.Mind;
using Content.Server.Popups;
using Content.Server.Roles;
using Content.Server.Roles.Jobs;
using Content.Shared._White.Implants.MindSlave;
using Content.Shared._White.Implants.NeuroStabilization;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
Expand All @@ -14,33 +18,42 @@ namespace Content.Server._White.Implants;

public sealed class ImplantsSystem : EntitySystem
{
[Dependency] private readonly IAdminLogManager _adminLogManager = default!;
[Dependency] private readonly RoleSystem _roleSystem = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly JobSystem _job = default!;

[ValidatePrototypeId<TagPrototype>]
private const string MindShieldTag = "MindShield";

[ValidatePrototypeId<TagPrototype>]
private const string NeuroStabilizationTag = "NeuroStabilization";

[ValidatePrototypeId<TagPrototype>]
private const string MindSlaveTag = "MindSlave";

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SubdermalImplantComponent, SubdermalImplantInserted>(OnImplantInserted);
SubscribeLocalEvent<SubdermalImplantComponent, SubdermalImplantRemoved>(OnImplantRemoved);
SubscribeLocalEvent<SubdermalImplantComponent, AttemptSubdermalImplantInserted>(AttemptImplantInserted);
}

private void OnImplantInserted(EntityUid uid, SubdermalImplantComponent component, SubdermalImplantInserted args)
{
if (_tag.HasTag(uid, MindShieldTag)
&& RevolutionCheck(uid, args.Target))
&& MindShieldCheck(uid, args.Target))
EnsureComp<MindShieldComponent>(args.Target);

if (_tag.HasTag(uid, NeuroStabilizationTag))
EnsureComp<NeuroStabilizationComponent>(args.Target);

if (_tag.HasTag(uid, MindSlaveTag))
MindSlaveInserted(args.User, args.Target);
}

private void OnImplantRemoved(EntityUid uid, SubdermalImplantComponent component, SubdermalImplantRemoved args)
Expand All @@ -50,27 +63,144 @@ private void OnImplantRemoved(EntityUid uid, SubdermalImplantComponent component

if (_tag.HasTag(uid, NeuroStabilizationTag))
RemComp<NeuroStabilizationComponent>(args.Target);

if (_tag.HasTag(uid, MindSlaveTag))
MindSlaveRemoved(args.User, args.Target);
}

private void AttemptImplantInserted(EntityUid uid, SubdermalImplantComponent component, ref AttemptSubdermalImplantInserted args)
{
if (_tag.HasTag(uid, MindSlaveTag)
&& !MindSlaveCheck(args.User, args.Target))
{
args.Popup = false;
args.Cancel();
}
}

#region MindShield

/// <summary>
/// Checks if the implanted person was a Rev or Head Rev and remove role or destroy mindshield respectively.
/// </summary>
private bool RevolutionCheck(EntityUid uid, EntityUid target)
private bool MindShieldCheck(EntityUid uid, EntityUid target)
{
if (HasComp<HeadRevolutionaryComponent>(target))
if (HasComp<HeadRevolutionaryComponent>(target)
|| (TryComp<MindSlaveComponent>(target, out var mindSlave)
&& mindSlave.Master.HasValue))
{
_popupSystem.PopupEntity(Loc.GetString("head-rev-break-mindshield"), target);
_popup.PopupEntity(Loc.GetString("head-rev-break-mindshield"), target);
QueueDel(uid);
return false;
}

if (_mindSystem.TryGetMind(target, out var mindId, out _)
&& _roleSystem.MindTryRemoveRole<RevolutionaryRoleComponent>(mindId))
if (_mind.TryGetMind(target, out var mindId, out _)
&& _role.MindTryRemoveRole<RevolutionaryRoleComponent>(mindId))
{
_adminLogManager.Add(LogType.Mind, LogImpact.Medium,
_adminLog.Add(LogType.Mind, LogImpact.Medium,
$"{ToPrettyString(target)} was deconverted due to being implanted with a Mindshield.");
}

return true;
}

#endregion

#region MindSlave

private void MindSlaveInserted(EntityUid user, EntityUid target)
{
var slaveComponent = EnsureComp<MindSlaveComponent>(target);
slaveComponent.Master = GetNetEntity(user);

var masterComponent = EnsureComp<MindSlaveComponent>(user);
masterComponent.Slaves.Add(GetNetEntity(target));

Dirty(user, masterComponent);
Dirty(target, slaveComponent);

if (!_mind.TryGetMind(target, out var targetMindId, out var targetMind)
|| targetMind.Session is null)
return;

var jobName = _job.MindTryGetJobName(user);

// send message to chat
var message = Loc.GetString("mindslave-chat-message", ("player", user), ("role", jobName));
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
_chat.ChatMessageToOne(ChatChannel.Server, message, wrappedMessage, default, false,
targetMind.Session.Channel, Color.FromHex("#5e9cff"));

// add briefing in character menu
if (TryComp<RoleBriefingComponent>(targetMindId, out var roleBriefing))
{
roleBriefing.Briefing += Loc.GetString("mindslave-briefing", ("player", user), ("role", jobName));
Dirty(targetMindId, roleBriefing);
}
else
{
_role.MindAddRole(targetMindId, new RoleBriefingComponent
{
Briefing = Loc.GetString("mindslave-briefing", ("player", user), ("role", jobName))
}, targetMind);
}

_adminLog.Add(LogType.Mind, LogImpact.High,
$"{ToPrettyString(user)} MindSlaved {ToPrettyString(target)}");
}

private void MindSlaveRemoved(EntityUid user, EntityUid target)
{
if (!TryComp(target, out MindSlaveComponent? mindslave)
|| !mindslave.Master.HasValue)
return;

var master = GetEntity(mindslave.Master.Value);
if (_mind.TryGetMind(target, out var mindId, out _))
{
_role.MindTryRemoveRole<RoleBriefingComponent>(mindId);
_popup.PopupEntity(Loc.GetString("mindslave-freed", ("player", master)), target, target);
}

if (TryComp(master, out MindSlaveComponent? masterMindslave))
{
masterMindslave.Slaves.Remove(GetNetEntity(target));
if (masterMindslave.Slaves.Count == 0)
RemComp<MindSlaveComponent>(master);
}

RemComp<MindSlaveComponent>(target);

_adminLog.Add(LogType.Mind, LogImpact.High,
$"{ToPrettyString(user)} UnMindSlaved {ToPrettyString(target)}");
}

/// <summary>
/// Checks if the target can be an MindSlaved
/// </summary>
private bool MindSlaveCheck(EntityUid user, EntityUid target)
{
string message;
if (target == user)
{
message = Loc.GetString("mindslave-target-self");
}
else if (HasComp<MindShieldComponent>(target)
|| HasComp<RevolutionaryComponent>(target)
|| !_mind.TryGetMind(target, out _, out _)
|| (TryComp<MindSlaveComponent>(target, out var mindSlave)
&& mindSlave.Master.HasValue))
{
message = Loc.GetString("mindslave-cant-insert");
}
else
{
return true;
}

_popup.PopupEntity(message, target, user);
return false;
}

#endregion
}
17 changes: 17 additions & 0 deletions Content.Server/_White/Melee/BloodAbsorb/BloodAbsorbComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Content.Server._White.Melee.BloodAbsorb;

[RegisterComponent]
public sealed partial class BloodAbsorbComponent : Component
{
[DataField]
public bool BloodLust;

[DataField]
public int MinAbsorb = 1;

[DataField]
public int MaxAbsorb = 20;

[DataField]
public float AbsorbModifierOnHeavy = 0.7f;
}
Loading

0 comments on commit 3023dc7

Please sign in to comment.