Skip to content

Commit

Permalink
Chitinid (From Delta-V) (#1644)
Browse files Browse the repository at this point in the history
port DeltaV-Station/Delta-v#2707 (with
permission)

:cl: ElusiveCoin
- add: Added a new species, the Chitinid.

---------

Signed-off-by: sleepyyapril <[email protected]>
Co-authored-by: ElusiveCoin <[email protected]>
Co-authored-by: rosieposie <[email protected]>
Co-authored-by: Delta-V bot <[email protected]>
Co-authored-by: Nemanja <[email protected]>
Co-authored-by: VMSolidus <[email protected]>
  • Loading branch information
6 people authored Jan 25, 2025
1 parent 3417f35 commit ce310bb
Show file tree
Hide file tree
Showing 142 changed files with 2,193 additions and 57 deletions.
18 changes: 9 additions & 9 deletions Content.IntegrationTests/Tests/StoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,22 @@ await server.WaitAssertion(() =>

var prototypeCost = prototype.Cost[UplinkSystem.TelecrystalCurrencyPrototype];
var discountDownTo = prototype.DiscountDownTo[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(plainDiscountedCost.Value, Is.GreaterThanOrEqualTo(discountDownTo.Value), "Expected discounted cost to be greater then DiscountDownTo value.");
Assert.That(plainDiscountedCost.Value, Is.LessThan(prototypeCost.Value), "Expected discounted cost to be lower then prototype cost.");
Assert.That(plainDiscountedCost.Value, Is.GreaterThanOrEqualTo(discountDownTo.Value), $"Expected discounted cost to be greater then DiscountDownTo value. ({itemId})");
Assert.That(plainDiscountedCost.Value, Is.LessThan(prototypeCost.Value), $"Expected discounted cost to be lower then prototype cost. ({itemId})");


var buyMsg = new StoreBuyListingMessage(discountedListingItem.ID){Actor = human};
server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, buyMsg);

var newBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(newBalance.Value, Is.EqualTo((originalBalance - plainDiscountedCost).Value), "Expected to have balance reduced by discounted cost");
Assert.That(newBalance.Value, Is.EqualTo((originalBalance - plainDiscountedCost).Value), $"Expected to have balance reduced by discounted cost ({itemId})");
Assert.That(
discountedListingItem.IsCostModified,
Is.False,
$"Expected item cost to not be modified after Buying discounted item."
$"Expected item cost to not be modified after Buying discounted item. ({itemId})"
);
var costAfterBuy = discountedListingItem.Cost[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(costAfterBuy.Value, Is.EqualTo(prototypeCost.Value), "Expected cost after discount refund to be equal to prototype cost.");
Assert.That(costAfterBuy.Value, Is.EqualTo(prototypeCost.Value), $"Expected cost after discount refund to be equal to prototype cost. ({itemId})");

var refundMsg = new StoreRequestRefundMessage { Actor = human };
server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, refundMsg);
Expand All @@ -136,20 +136,20 @@ await server.WaitAssertion(() =>
discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId);

var afterRefundBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(afterRefundBalance.Value, Is.EqualTo(originalBalance.Value), "Expected refund to return all discounted cost value.");
Assert.That(afterRefundBalance.Value, Is.EqualTo(originalBalance.Value), $"Expected refund to return all discounted cost value. ({itemId})");
Assert.That(
discountComponent.Discounts.First(x => x.ListingId == discountedListingItem.ID).Count,
Is.EqualTo(0),
"Discounted count should still be zero even after refund."
$"Discounted count should still be zero even after refund. ({itemId})"
);

Assert.That(
discountedListingItem.IsCostModified,
Is.False,
$"Expected item cost to not be modified after Buying discounted item (even after refund was done)."
$"Expected item cost to not be modified after Buying discounted item (even after refund was done). ({itemId})"
);
var costAfterRefund = discountedListingItem.Cost[UplinkSystem.TelecrystalCurrencyPrototype];
Assert.That(costAfterRefund.Value, Is.EqualTo(prototypeCost.Value), "Expected cost after discount refund to be equal to prototype cost.");
Assert.That(costAfterRefund.Value, Is.EqualTo(prototypeCost.Value), $"Expected cost after discount refund to be equal to prototype cost. ({itemId})");
});
}

Expand Down
30 changes: 30 additions & 0 deletions Content.Server/Chemistry/EntitySystems/InjectorSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using Content.Server.Abilities.Chitinid;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chat.Managers;
using Content.Shared.Chat;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
Expand All @@ -13,13 +16,19 @@
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Stacks;
using Robust.Server.Player;


namespace Content.Server.Chemistry.EntitySystems;

public sealed class InjectorSystem : SharedInjectorSystem
{
[Dependency] private readonly BloodstreamSystem _blood = default!;
[Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;

private const ChatChannel BlockInjectionDenyChannel = ChatChannel.Emotes;

public override void Initialize()
{
Expand Down Expand Up @@ -114,6 +123,24 @@ private void OnInjectorAfterInteract(Entity<InjectorComponent> entity, ref After
/// </summary>
private void InjectDoAfter(Entity<InjectorComponent> injector, EntityUid target, EntityUid user)
{
if (TryComp<BlockInjectionComponent>(target, out var blockComponent)) // DeltaV
{
var msg = Loc.GetString($"injector-component-deny-{blockComponent.BlockReason}");
Popup.PopupEntity(msg, target, user);

if (!_playerManager.TryGetSessionByEntity(target, out var session))
return;

_chat.ChatMessageToOne(
BlockInjectionDenyChannel,
msg,
msg,
EntityUid.Invalid,
false,
session.Channel);
return;
}

// Create a pop-up for the user
if (injector.Comp.ToggleState == InjectorToggleMode.Draw)
{
Expand Down Expand Up @@ -254,6 +281,9 @@ private void TryInjectIntoBloodstream(Entity<InjectorComponent> injector, Entity
private void TryInject(Entity<InjectorComponent> injector, EntityUid targetEntity,
Entity<SolutionComponent> targetSolution, EntityUid user, bool asRefill)
{
if (HasComp<BlockInjectionComponent>(targetEntity)) // DeltaV
return;

if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var soln,
out var solution) || solution.Volume == 0)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Content.Server.Administration.Logs;
using Content.Server.Construction.Components;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.Construction;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.EntitySystems;
Expand All @@ -11,6 +10,7 @@
using Content.Shared.Interaction;
using Content.Shared.Prying.Systems;
using Content.Shared.Radio.EntitySystems;
using Content.Shared.Temperature;
using Content.Shared.Tools.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ private void CookItem(EntityUid uid, DeepFryerComponent component, EntityUid ite
if (TryComp<TemperatureComponent>(item, out var tempComp))
{
// Push the temperature towards what it should be but no higher.
var delta = (component.PoweredTemperature - tempComp.CurrentTemperature) * tempComp.HeatCapacity;
var delta = (component.PoweredTemperature - tempComp.CurrentTemperature) * _temperature.GetHeatCapacity(item, tempComp);

if (delta > 0f)
_temperature.ChangeHeat(item, delta, false, tempComp);
Expand Down
14 changes: 2 additions & 12 deletions Content.Server/Temperature/Components/TemperatureComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Content.Server.Temperature.Systems;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
Expand Down Expand Up @@ -51,15 +50,6 @@ public sealed partial class TemperatureComponent : Component
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float AtmosTemperatureTransferEfficiency = 0.1f;

[Obsolete("Use system method")]
public float HeatCapacity
{
get
{
return IoCManager.Resolve<IEntityManager>().System<TemperatureSystem>().GetHeatCapacity(Owner, this);
}
}

[DataField, ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier ColdDamage = new();

Expand All @@ -71,15 +61,15 @@ public float HeatCapacity
/// </summary>
/// <remarks>
/// Okay it genuinely reaches this basically immediately for a plasma fire.
/// </summary>
/// </remarks>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 DamageCap = FixedPoint2.New(8);

/// <summary>
/// Used to keep track of when damage starts/stops. Useful for logs.
/// </summary>
[DataField]
public bool TakingDamage = false;
public bool TakingDamage;

[DataField]
public ProtoId<AlertPrototype> HotAlert = "Hot";
Expand Down
14 changes: 0 additions & 14 deletions Content.Server/Temperature/Systems/TemperatureSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,17 +414,3 @@ private void RecalculateAndApplyParentThresholds(EntityUid uid,
return (newHeatThreshold, newColdThreshold);
}
}

public sealed class OnTemperatureChangeEvent : EntityEventArgs
{
public float CurrentTemperature { get; }
public float LastTemperature { get; }
public float TemperatureDelta { get; }

public OnTemperatureChangeEvent(float current, float last, float delta)
{
CurrentTemperature = current;
LastTemperature = last;
TemperatureDelta = delta;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Content.Server.Abilities.Chitinid;


[RegisterComponent]
public sealed partial class BlockInjectionComponent : Component
{
[DataField]
public string BlockReason { get; set; } = string.Empty;
}
41 changes: 41 additions & 0 deletions Content.Server/_DV/Abilities/Chitinid/ChitinidComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;

namespace Content.Server.Abilities.Chitinid;

[RegisterComponent]
public sealed partial class ChitinidComponent : Component
{
[DataField]
public EntProtoId ChitzitePrototype = "Chitzite";

[DataField]
public EntProtoId ChitziteActionId = "ActionChitzite";

[DataField]
public EntityUid? ChitziteAction;

[DataField]
public FixedPoint2 AmountAbsorbed = 0f;

[DataField]
public DamageSpecifier Healing = new()
{
DamageDict = new()
{
{ "Radiation", -0.5 },
}
};

[DataField]
public FixedPoint2 MaximumAbsorbed = 30f;

[DataField]
public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1);

[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan NextUpdate;
}
97 changes: 97 additions & 0 deletions Content.Server/_DV/Abilities/Chitinid/ChitinidSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Content.Server.Nutrition.Components;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;
using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Server.Abilities.Chitinid;

public sealed partial class ChitinidSystem : EntitySystem
{
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;

public override void Initialize()
{
SubscribeLocalEvent<ChitinidComponent, ChitziteActionEvent>(OnChitzite);
SubscribeLocalEvent<ChitinidComponent, MapInitEvent>(OnMapInit);
}

public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<ChitinidComponent, DamageableComponent>();
while (query.MoveNext(out var uid, out var chitinid, out var damageable))
{
if (_timing.CurTime < chitinid.NextUpdate)
continue;

chitinid.NextUpdate += chitinid.UpdateInterval;

if (chitinid.AmountAbsorbed >= chitinid.MaximumAbsorbed || _mobState.IsDead(uid))
continue;

if (_damageable.TryChangeDamage(uid, chitinid.Healing, damageable: damageable) is {} delta)
{
chitinid.AmountAbsorbed += -delta.GetTotal().Float();
if (chitinid.ChitziteAction != null && chitinid.AmountAbsorbed >= chitinid.MaximumAbsorbed)
{
_actions.SetCharges(chitinid.ChitziteAction, 1); // You get the charge back and that's it. Tough.
_actions.SetEnabled(chitinid.ChitziteAction, true);
}
}
}

var entQuery = EntityQueryEnumerator<CoughingUpChitziteComponent, ChitinidComponent>();
while (entQuery.MoveNext(out var ent, out var chitzite, out var chitinid))
{
if (_timing.CurTime < chitzite.NextCough)
continue;

Spawn(chitinid.ChitzitePrototype, Transform(ent).Coordinates);
chitinid.AmountAbsorbed = 0f;
RemCompDeferred(ent, chitzite);
}
}

private void OnMapInit(Entity<ChitinidComponent> ent, ref MapInitEvent args)
{
if (ent.Comp.ChitziteAction != null)
return;

ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.UpdateInterval;

_actions.AddAction(ent, ref ent.Comp.ChitziteAction, ent.Comp.ChitziteActionId);
}

private void OnChitzite(Entity<ChitinidComponent> ent, ref ChitziteActionEvent args)
{
if (_inventory.TryGetSlotEntity(ent, "mask", out var maskUid) &&
TryComp<IngestionBlockerComponent>(maskUid, out var blocker) &&
blocker.Enabled)
{
_popup.PopupEntity(Loc.GetString("chitzite-mask", ("mask", maskUid)), ent, ent);
return;
}

_popup.PopupEntity(Loc.GetString("chitzite-cough", ("name", Identity.Entity(ent, EntityManager))), ent);
_audio.PlayPvs("/Audio/Animals/cat_hiss.ogg", ent, AudioHelpers.WithVariation(0.15f));

var chitzite = EnsureComp<CoughingUpChitziteComponent>(ent);
chitzite.NextCough = _timing.CurTime + chitzite.CoughUpTime;
args.Handled = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;

namespace Content.Server.Abilities.Chitinid;

[RegisterComponent, AutoGenerateComponentPause]
public sealed partial class CoughingUpChitziteComponent : Component
{
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan NextCough;

[DataField]
public TimeSpan CoughUpTime = TimeSpan.FromSeconds(2.15);
}
30 changes: 30 additions & 0 deletions Content.Shared/Temperature/Components/TemperatureSpeedComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.Temperature.Systems;
using Robust.Shared.GameStates;

namespace Content.Shared.Temperature.Components;

/// <summary>
/// This is used for an entity that varies in speed based on current temperature.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedTemperatureSystem)), AutoGenerateComponentState, AutoGenerateComponentPause]
public sealed partial class TemperatureSpeedComponent : Component
{
/// <summary>
/// Pairs of temperature thresholds to applied slowdown values.
/// </summary>
[DataField]
public Dictionary<float, float> Thresholds = new();

/// <summary>
/// The current speed modifier from <see cref="Thresholds"/> we reached.
/// Stored and networked so that the client doesn't mispredict temperature
/// </summary>
[DataField, AutoNetworkedField]
public float? CurrentSpeedModifier;

/// <summary>
/// The time at which the temperature slowdown is updated.
/// </summary>
[DataField, AutoNetworkedField, AutoPausedField]
public TimeSpan? NextSlowdownUpdate;
}
Loading

0 comments on commit ce310bb

Please sign in to comment.