Skip to content

Commit

Permalink
Merge pull request #272 from Schrodinger71/update-felinid
Browse files Browse the repository at this point in the history
Новые компоненты для фелинидов.
  • Loading branch information
Schrodinger71 authored Jan 2, 2024
2 parents 7c23b08 + d1f5040 commit 8dff581
Show file tree
Hide file tree
Showing 17 changed files with 510 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Content.Server.ADT.Abilities.Felinid;

[RegisterComponent]
public sealed partial class CoughingUpHairballComponent : Component
{
[DataField("accumulator")]
public float Accumulator = 0f;

[DataField("coughUpTime")]
public TimeSpan CoughUpTime = TimeSpan.FromSeconds(2.15); // length of hairball.ogg
}
20 changes: 20 additions & 0 deletions Content.Server/ADT/Abilities/Felinid/FelinidComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Prototypes;

namespace Content.Server.ADT.Abilities.Felinid;

[RegisterComponent]
public sealed partial class FelinidComponent : Component
{
/// <summary>
/// The hairball prototype to use.
/// </summary>
[DataField("hairballPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string HairballPrototype = "Hairball";

public EntityUid? HairballAction = null;

public EntityUid? EatMouse = null;

public EntityUid? PotentialTarget = null;
}
5 changes: 5 additions & 0 deletions Content.Server/ADT/Abilities/Felinid/FelinidFoodComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Content.Server.ADT.Abilities.Felinid;

[RegisterComponent]
public sealed partial class FelinidFoodComponent : Component
{}
197 changes: 197 additions & 0 deletions Content.Server/ADT/Abilities/Felinid/FelinidSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using Content.Server.Actions;
using Content.Shared.Actions;
using Content.Shared.StatusEffect;
using Content.Shared.Throwing;
using Content.Shared.Item;
using Content.Shared.Inventory;
using Content.Shared.Hands;
using Content.Shared.IdentityManagement;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Medical;
using Content.Server.Nutrition.EntitySystems;
using Content.Server.Popups;
using Content.Shared.ADT.Psionics.Events;
using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Content.Server.Clothing;

namespace Content.Server.ADT.Abilities.Felinid;

public sealed class FelinidSystem : EntitySystem
{

[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly HungerSystem _hungerSystem = default!;
[Dependency] private readonly VomitSystem _vomitSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FelinidComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<FelinidComponent, HairballActionEvent>(OnHairball);
SubscribeLocalEvent<FelinidComponent, EatMouseActionEvent>(OnEatMouse);
SubscribeLocalEvent<FelinidComponent, DidEquipHandEvent>(OnEquipped);
SubscribeLocalEvent<FelinidComponent,DidUnequipHandEvent>(OnUnequipped);
SubscribeLocalEvent<HairballComponent, ThrowDoHitEvent>(OnHairballHit);
SubscribeLocalEvent<HairballComponent, GettingPickedUpAttemptEvent>(OnHairballPickupAttempt);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<CoughingUpHairballComponent, FelinidComponent>();
while (query.MoveNext(out var entityUid, out var hairballComp, out var catComp))
{
hairballComp.Accumulator += frameTime;
if (hairballComp.Accumulator < hairballComp.CoughUpTime.TotalSeconds)
continue;

hairballComp.Accumulator = 0;
SpawnHairball(entityUid, catComp);
RemCompDeferred<CoughingUpHairballComponent>(entityUid);
}
}

[ValidatePrototypeId<EntityPrototype>] private const string ActionHairball = "ActionHairball";
[ValidatePrototypeId<EntityPrototype>] private const string ActionEatMouse = "ActionEatMouse";

private void OnInit(EntityUid uid, FelinidComponent component, ComponentInit args)
{
_actions.AddAction(uid, ref component.HairballAction, ActionHairball);

if (_actions.TryGetActionData(component.HairballAction, out var action) && action?.UseDelay != null)
{
_actions.SetCooldown(component.HairballAction,
_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) action?.UseDelay!);
}
}

private void OnEquipped(EntityUid uid, FelinidComponent component, DidEquipHandEvent args)
{
if (!HasComp<FelinidFoodComponent>(args.Equipped))
return;

component.PotentialTarget = args.Equipped;

_actions.AddAction(uid, ref component.EatMouse, ActionEatMouse);
}

private void OnUnequipped(EntityUid uid, FelinidComponent component, DidUnequipHandEvent args)
{
if (args.Unequipped == component.PotentialTarget)
{
component.PotentialTarget = null;

_actions.RemoveAction(uid, component.EatMouse);
}
}

private static readonly SoundSpecifier HairballPlay = new SoundPathSpecifier("/Audio/ADT/Felinid/hairball.ogg",
AudioParams.Default.WithVariation(0.15f));

private void OnHairball(EntityUid uid, FelinidComponent component, HairballActionEvent args)
{
//if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
// EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
// blocker.Enabled)
//{
// _popupSystem.PopupEntity(Loc.GetString("hairball-mask", ("mask", maskUid)), uid, uid);
// return;
//}

_popupSystem.PopupEntity(Loc.GetString("hairball-cough", ("name", Identity.Entity(uid, EntityManager))), uid);
_audio.PlayPredicted(HairballPlay, uid, null);

EnsureComp<CoughingUpHairballComponent>(uid);
args.Handled = true;
}

private static readonly SoundSpecifier EatMousePlay = new SoundPathSpecifier("/Audio/Items/eatfood.ogg",
AudioParams.Default.WithVariation(0.15f));

private void OnEatMouse(EntityUid uid, FelinidComponent component, EatMouseActionEvent args)
{
if (component.PotentialTarget == null)
return;

if (!TryComp<HungerComponent>(uid, out var hunger))
return;

if (hunger.CurrentThreshold == Shared.Nutrition.Components.HungerThreshold.Overfed)
{
_popupSystem.PopupEntity(Loc.GetString("food-system-you-cannot-eat-any-more"), uid, uid, Shared.Popups.PopupType.SmallCaution);
return;
}

//if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
// EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
// blocker.Enabled)
//{
// _popupSystem.PopupEntity(Loc.GetString("hairball-mask", ("mask", maskUid)), uid, uid, Shared.Popups.PopupType.SmallCaution);
// return;
//}

if (component.HairballAction != null && _actions.TryGetActionData(component.HairballAction, out var skill))
{
_actionsSystem.SetCharges(component.HairballAction, skill?.Charges + 1);
_actionsSystem.SetEnabled(component.HairballAction, true);
}
Del(component.PotentialTarget.Value);
component.PotentialTarget = null;

_audio.PlayPredicted(EatMousePlay, uid, null);

_hungerSystem.ModifyHunger(uid, 70f, hunger);

_actions.RemoveAction(uid, component.EatMouse);
}

private void SpawnHairball(EntityUid uid, FelinidComponent component)
{
var hairball = EntityManager.SpawnEntity(component.HairballPrototype, Transform(uid).Coordinates);
var hairballComp = Comp<HairballComponent>(hairball);

if (TryComp<BloodstreamComponent>(uid, out var bloodstream))
{
var temp = bloodstream.ChemicalSolution.SplitSolution(20);

if (_solutionSystem.TryGetSolution(hairball, hairballComp.SolutionName, out var hairballSolution))
{
_solutionSystem.TryAddSolution(hairball, hairballSolution, temp);
}
}
}
private void OnHairballHit(EntityUid uid, HairballComponent component, ThrowDoHitEvent args)
{
if (HasComp<FelinidComponent>(args.Target) || !HasComp<StatusEffectsComponent>(args.Target))
return;
if (_robustRandom.Prob(0.2f))
_vomitSystem.Vomit(args.Target);
}

private void OnHairballPickupAttempt(EntityUid uid, HairballComponent component, GettingPickedUpAttemptEvent args)
{
if (HasComp<FelinidComponent>(args.User) || !HasComp<StatusEffectsComponent>(args.User))
return;

if (_robustRandom.Prob(0.2f))
{
_vomitSystem.Vomit(args.User);
args.Cancel();
}
}
}
7 changes: 7 additions & 0 deletions Content.Server/ADT/Abilities/Felinid/HairballComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Content.Server.ADT.Abilities.Felinid;

[RegisterComponent]
public sealed partial class HairballComponent : Component
{
public string SolutionName = "hairball";
}
124 changes: 124 additions & 0 deletions Content.Server/Clothing/MaskSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//using Content.Server.Actions;
//using Content.Server.Atmos.Components;
//using Content.Server.Atmos.EntitySystems;
//using Content.Server.Body.Components;
//using Content.Server.Body.Systems;
//using Content.Server.Clothing.Components;
//using Content.Server.IdentityManagement;
//using Content.Server.Nutrition.EntitySystems;
//using Content.Server.Popups;
//using Content.Server.VoiceMask;
//using Content.Shared.Actions;
//using Content.Shared.Clothing;
//using Content.Shared.Clothing.Components;
//using Content.Shared.Clothing.EntitySystems;
//using Content.Shared.IdentityManagement.Components;
//using Content.Shared.Inventory;
//using Content.Shared.Inventory.Events;

//namespace Content.Server.Clothing
//{
// public sealed class MaskSystem : EntitySystem
// {
// [Dependency] private readonly ActionsSystem _actionSystem = default!;
// [Dependency] private readonly AtmosphereSystem _atmos = default!;
// [Dependency] private readonly InternalsSystem _internals = default!;
// [Dependency] private readonly InventorySystem _inventorySystem = default!;
// [Dependency] private readonly PopupSystem _popupSystem = default!;
// [Dependency] private readonly IdentitySystem _identity = default!;
// [Dependency] private readonly ClothingSystem _clothing = default!;

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

// SubscribeLocalEvent<MaskComponent, ToggleMaskEvent>(OnToggleMask);
// SubscribeLocalEvent<MaskComponent, GetItemActionsEvent>(OnGetActions);
// SubscribeLocalEvent<MaskComponent, GotUnequippedEvent>(OnGotUnequipped);
// }

// private void OnGetActions(EntityUid uid, MaskComponent component, GetItemActionsEvent args)
// {
// if (!args.InHands)
// args.AddAction(ref component.ToggleActionEntity, component.ToggleAction);
// }

// private void OnToggleMask(Entity<MaskComponent> ent, ref ToggleMaskEvent args)
// {
// var (uid, mask) = ent;
// if (mask.ToggleActionEntity == null)
// return;

// if (!_inventorySystem.TryGetSlotEntity(args.Performer, "mask", out var existing) || !uid.Equals(existing))
// return;

// //mask.IsToggled ^= true;
// //_actionSystem.SetToggled(mask.ToggleActionEntity, mask.IsToggled);

// // Pulling mask down can change identity, so we want to update that
// _identity.QueueIdentityUpdate(args.Performer);

// if (mask.IsToggled)
// _popupSystem.PopupEntity(Loc.GetString("action-mask-pull-down-popup-message", ("mask", uid)), args.Performer, args.Performer);
// else
// _popupSystem.PopupEntity(Loc.GetString("action-mask-pull-up-popup-message", ("mask", uid)), args.Performer, args.Performer);

// ToggleMaskComponents(uid, mask, args.Performer);
// }

// // set to untoggled when unequipped, so it isn't left in a 'pulled down' state
// private void OnGotUnequipped(EntityUid uid, MaskComponent mask, GotUnequippedEvent args)
// {
// if (mask.ToggleActionEntity == null)
// return;

// //mask.IsToggled = false;
// //_actionSystem.SetToggled(mask.ToggleActionEntity, mask.IsToggled);

// ToggleMaskComponents(uid, mask, args.Equipee, true);
// }

// private void ToggleMaskComponents(EntityUid uid, MaskComponent mask, EntityUid wearer, bool isEquip = false)
// {
// // toggle visuals
// if (TryComp<ClothingComponent>(uid, out var clothing))
// {
// //TODO: sprites for 'pulled down' state. defaults to invisible due to no sprite with this prefix
// _clothing.SetEquippedPrefix(uid, mask.IsToggled ? "toggled" : null, clothing);
// }

// // shouldn't this be an event?

// // toggle ingestion blocking
// if (TryComp<IngestionBlockerComponent>(uid, out var blocker))
// blocker.Enabled = !mask.IsToggled;

// // toggle identity
// if (TryComp<IdentityBlockerComponent>(uid, out var identity))
// identity.Enabled = !mask.IsToggled;

// // toggle voice masking
// if (TryComp<VoiceMaskComponent>(wearer, out var voiceMask))
// voiceMask.Enabled = !mask.IsToggled;

// // toggle breath tool connection (skip during equip since that is handled in LungSystem)
// if (isEquip || !TryComp<BreathToolComponent>(uid, out var breathTool))
// return;

// if (mask.IsToggled)
// {
// _atmos.DisconnectInternals(breathTool);
// }
// else
// {
// breathTool.IsFunctional = true;

// if (TryComp(wearer, out InternalsComponent? internals))
// {
// breathTool.ConnectedInternalsEntity = wearer;
// _internals.ConnectBreathTool((wearer, internals), uid);
// }
// }
// }
// }
//}
Loading

0 comments on commit 8dff581

Please sign in to comment.