6
Content.Client/Devour/DevourSystem.cs
Normal file
6
Content.Client/Devour/DevourSystem.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using Content.Shared.Devour;
|
||||||
|
|
||||||
|
namespace Content.Client.Devour;
|
||||||
|
public sealed class DevourSystem : SharedDevourSystem
|
||||||
|
{
|
||||||
|
}
|
||||||
51
Content.Server/Devour/DevourSystem.cs
Normal file
51
Content.Server/Devour/DevourSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Content.Shared.Devour;
|
||||||
|
using Content.Server.Body.Systems;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Server.Devour.Components;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Devour;
|
||||||
|
|
||||||
|
public sealed class DevourSystem : SharedDevourSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DevourerComponent, DevourDoAfterEvent>(OnDoAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoAfter(EntityUid uid, DevourerComponent component, DevourDoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled || args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ichorInjection = new Solution(component.Chemical, component.HealRate);
|
||||||
|
|
||||||
|
if (component.FoodPreference == FoodPreference.All ||
|
||||||
|
(component.FoodPreference == FoodPreference.Humanoid && HasComp<HumanoidAppearanceComponent>(args.Args.Target)))
|
||||||
|
{
|
||||||
|
ichorInjection.ScaleSolution(0.5f);
|
||||||
|
|
||||||
|
if (component.ShouldStoreDevoured && args.Args.Target is not null)
|
||||||
|
{
|
||||||
|
component.Stomach.Insert(args.Args.Target.Value);
|
||||||
|
}
|
||||||
|
_bloodstreamSystem.TryAddToChemicals(uid, ichorInjection);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Figure out a better way of removing structures via devour that still entails standing still and waiting for a DoAfter. Somehow.
|
||||||
|
//If it's not human, it must be a structure
|
||||||
|
else if (args.Args.Target != null)
|
||||||
|
{
|
||||||
|
QueueDel(args.Args.Target.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_audioSystem.PlayPvs(component.SoundDevour, uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -13,23 +13,6 @@ namespace Content.Server.Dragon
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class DragonComponent : Component
|
public sealed class DragonComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The chemical ID injected upon devouring
|
|
||||||
/// </summary>
|
|
||||||
[DataField("devourChemical", customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
|
||||||
public string DevourChem = "Ichor";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of ichor injected per devour
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("devourHealRate")]
|
|
||||||
public float DevourHealRate = 15f;
|
|
||||||
|
|
||||||
[DataField("devourActionId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityTargetActionPrototype>))]
|
|
||||||
public string DevourActionId = "DragonDevour";
|
|
||||||
|
|
||||||
[DataField("devourAction")]
|
|
||||||
public EntityTargetAction? DevourAction;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If we have active rifts.
|
/// If we have active rifts.
|
||||||
@@ -68,58 +51,15 @@ namespace Content.Server.Dragon
|
|||||||
[ViewVariables(VVAccess.ReadWrite), DataField("riftPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[ViewVariables(VVAccess.ReadWrite), DataField("riftPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
public string RiftPrototype = "CarpRift";
|
public string RiftPrototype = "CarpRift";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of time it takes to devour something
|
|
||||||
/// <remarks>
|
|
||||||
/// NOTE: original intended design was to increase this proportionally with damage thresholds, but those proved quite difficult to get consistently. right now it devours the structure at a fixed timer.
|
|
||||||
/// </remarks>
|
|
||||||
/// </summary>
|
|
||||||
[DataField("structureDevourTime")]
|
|
||||||
public float StructureDevourTime = 10f;
|
|
||||||
|
|
||||||
[DataField("devourTime")]
|
|
||||||
public float DevourTime = 3f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundDeath")]
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundDeath")]
|
||||||
public SoundSpecifier? SoundDeath = new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg");
|
public SoundSpecifier? SoundDeath = new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg");
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundDevour")]
|
|
||||||
public SoundSpecifier? SoundDevour = new SoundPathSpecifier("/Audio/Effects/demon_consume.ogg")
|
|
||||||
{
|
|
||||||
Params = AudioParams.Default.WithVolume(-3f),
|
|
||||||
};
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundStructureDevour")]
|
|
||||||
public SoundSpecifier? SoundStructureDevour = new SoundPathSpecifier("/Audio/Machines/airlock_creaking.ogg")
|
|
||||||
{
|
|
||||||
Params = AudioParams.Default.WithVolume(-3f),
|
|
||||||
};
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundRoar")]
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundRoar")]
|
||||||
public SoundSpecifier? SoundRoar =
|
public SoundSpecifier? SoundRoar =
|
||||||
new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg")
|
new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg")
|
||||||
{
|
{
|
||||||
Params = AudioParams.Default.WithVolume(3f),
|
Params = AudioParams.Default.WithVolume(3f),
|
||||||
};
|
};
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("devourWhitelist")]
|
|
||||||
public EntityWhitelist? DevourWhitelist = new()
|
|
||||||
{
|
|
||||||
Components = new[]
|
|
||||||
{
|
|
||||||
"Door",
|
|
||||||
"MobState",
|
|
||||||
},
|
|
||||||
Tags = new List<string>
|
|
||||||
{
|
|
||||||
"Wall",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Where the entities go when dragon devours them, empties when the dragon is butchered.
|
|
||||||
/// </summary>
|
|
||||||
public Container DragonStomach = default!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class DragonDevourActionEvent : EntityTargetActionEvent {}
|
public sealed class DragonDevourActionEvent : EntityTargetActionEvent {}
|
||||||
|
|||||||
@@ -59,12 +59,9 @@ namespace Content.Server.Dragon
|
|||||||
|
|
||||||
SubscribeLocalEvent<DragonComponent, ComponentStartup>(OnStartup);
|
SubscribeLocalEvent<DragonComponent, ComponentStartup>(OnStartup);
|
||||||
SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<DragonComponent, DragonDevourActionEvent>(OnDevourAction);
|
|
||||||
SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnDragonRift);
|
SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnDragonRift);
|
||||||
SubscribeLocalEvent<DragonComponent, RefreshMovementSpeedModifiersEvent>(OnDragonMove);
|
SubscribeLocalEvent<DragonComponent, RefreshMovementSpeedModifiersEvent>(OnDragonMove);
|
||||||
|
|
||||||
SubscribeLocalEvent<DragonComponent, DragonDevourDoAfterEvent>(OnDoAfter);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<DragonComponent, MobStateChangedEvent>(OnMobStateChanged);
|
SubscribeLocalEvent<DragonComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
|
|
||||||
SubscribeLocalEvent<DragonRiftComponent, ComponentShutdown>(OnRiftShutdown);
|
SubscribeLocalEvent<DragonRiftComponent, ComponentShutdown>(OnRiftShutdown);
|
||||||
@@ -75,29 +72,6 @@ namespace Content.Server.Dragon
|
|||||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRiftRoundEnd);
|
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRiftRoundEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, DragonComponent component, DragonDevourDoAfterEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || args.Cancelled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var ichorInjection = new Solution(component.DevourChem, component.DevourHealRate);
|
|
||||||
|
|
||||||
//Humanoid devours allow dragon to get eggs, corpses included
|
|
||||||
if (HasComp<HumanoidAppearanceComponent>(args.Args.Target))
|
|
||||||
{
|
|
||||||
ichorInjection.ScaleSolution(0.5f);
|
|
||||||
component.DragonStomach.Insert(args.Args.Target.Value);
|
|
||||||
_bloodstreamSystem.TryAddToChemicals(uid, ichorInjection);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Figure out a better way of removing structures via devour that still entails standing still and waiting for a DoAfter. Somehow.
|
|
||||||
//If it's not human, it must be a structure
|
|
||||||
else if (args.Args.Target != null)
|
|
||||||
EntityManager.QueueDeleteEntity(args.Args.Target.Value);
|
|
||||||
|
|
||||||
_audioSystem.PlayPvs(component.SoundDevour, uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
@@ -303,8 +277,6 @@ namespace Content.Server.Dragon
|
|||||||
if (component.SoundDeath != null)
|
if (component.SoundDeath != null)
|
||||||
_audioSystem.PlayPvs(component.SoundDeath, uid, component.SoundDeath.Params);
|
_audioSystem.PlayPvs(component.SoundDeath, uid, component.SoundDeath.Params);
|
||||||
|
|
||||||
component.DragonStomach.EmptyContainer();
|
|
||||||
|
|
||||||
foreach (var rift in component.Rifts)
|
foreach (var rift in component.Rifts)
|
||||||
{
|
{
|
||||||
QueueDel(rift);
|
QueueDel(rift);
|
||||||
@@ -322,62 +294,10 @@ namespace Content.Server.Dragon
|
|||||||
|
|
||||||
private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args)
|
private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
//Dragon doesn't actually chew, since he sends targets right into his stomach.
|
|
||||||
//I did it mom, I added ERP content into upstream. Legally!
|
|
||||||
component.DragonStomach = _containerSystem.EnsureContainer<Container>(uid, "dragon_stomach");
|
|
||||||
|
|
||||||
if (component.DevourAction != null)
|
|
||||||
_actionsSystem.AddAction(uid, component.DevourAction, null);
|
|
||||||
|
|
||||||
if (component.SpawnRiftAction != null)
|
if (component.SpawnRiftAction != null)
|
||||||
_actionsSystem.AddAction(uid, component.SpawnRiftAction, null);
|
_actionsSystem.AddAction(uid, component.SpawnRiftAction, null);
|
||||||
|
|
||||||
Roar(component);
|
Roar(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The devour action
|
|
||||||
/// </summary>
|
|
||||||
private void OnDevourAction(EntityUid uid, DragonComponent component, DragonDevourActionEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || component.DevourWhitelist?.IsValid(args.Target, EntityManager) != true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
var target = args.Target;
|
|
||||||
|
|
||||||
// Structure and mob devours handled differently.
|
|
||||||
if (EntityManager.TryGetComponent(target, out MobStateComponent? targetState))
|
|
||||||
{
|
|
||||||
switch (targetState.CurrentState)
|
|
||||||
{
|
|
||||||
case MobState.Critical:
|
|
||||||
case MobState.Dead:
|
|
||||||
|
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(uid, component.DevourTime, new DragonDevourDoAfterEvent(), uid, target: target, used: uid)
|
|
||||||
{
|
|
||||||
BreakOnTargetMove = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("devour-action-popup-message-fail-target-alive"), uid, uid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("devour-action-popup-message-structure"), uid, uid);
|
|
||||||
|
|
||||||
if (component.SoundStructureDevour != null)
|
|
||||||
_audioSystem.PlayPvs(component.SoundStructureDevour, uid, component.SoundStructureDevour.Params);
|
|
||||||
|
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(uid, component.StructureDevourTime, new DragonDevourDoAfterEvent(), uid, target: target, used: uid)
|
|
||||||
{
|
|
||||||
BreakOnTargetMove = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
82
Content.Shared/Devour/Components/DevourerComponent.cs
Normal file
82
Content.Shared/Devour/Components/DevourerComponent.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.Actions.ActionTypes;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.Devour;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Server.Devour.Components;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[Access(typeof(SharedDevourSystem))]
|
||||||
|
public sealed class DevourerComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("devourActionId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityTargetActionPrototype>))]
|
||||||
|
public string DevourActionId = "Devour";
|
||||||
|
|
||||||
|
[DataField("devourAction")]
|
||||||
|
public EntityTargetAction? DevourAction;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundDevour")]
|
||||||
|
public SoundSpecifier? SoundDevour = new SoundPathSpecifier("/Audio/Effects/demon_consume.ogg")
|
||||||
|
{
|
||||||
|
Params = AudioParams.Default.WithVolume(-3f),
|
||||||
|
};
|
||||||
|
|
||||||
|
[DataField("devourTime")]
|
||||||
|
public float DevourTime = 3f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time it takes to devour something
|
||||||
|
/// <remarks>
|
||||||
|
/// NOTE: original intended design was to increase this proportionally with damage thresholds, but those proved quite difficult to get consistently. right now it devours the structure at a fixed timer.
|
||||||
|
/// </remarks>
|
||||||
|
/// </summary>
|
||||||
|
[DataField("structureDevourTime")]
|
||||||
|
public float StructureDevourTime = 10f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundStructureDevour")]
|
||||||
|
public SoundSpecifier? SoundStructureDevour = new SoundPathSpecifier("/Audio/Machines/airlock_creaking.ogg")
|
||||||
|
{
|
||||||
|
Params = AudioParams.Default.WithVolume(-3f),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Where the entities go when it devours them, empties when it is butchered.
|
||||||
|
/// </summary>
|
||||||
|
public Container Stomach = default!;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("shouldStoreDevoured")]
|
||||||
|
public bool ShouldStoreDevoured = true;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("whitelist")]
|
||||||
|
public EntityWhitelist? Whitelist = new()
|
||||||
|
{
|
||||||
|
Components = new[]
|
||||||
|
{
|
||||||
|
"MobState",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chemical ID injected upon devouring
|
||||||
|
/// </summary>
|
||||||
|
[DataField("chemical", customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
||||||
|
public string Chemical = "Ichor";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of ichor injected per devour
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("healRate")]
|
||||||
|
public float HealRate = 15f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The favorite food not only feeds you, but also heals
|
||||||
|
/// </summary>
|
||||||
|
[DataField("foodPreference")]
|
||||||
|
public FoodPreference FoodPreference = FoodPreference.All;
|
||||||
|
}
|
||||||
|
|
||||||
94
Content.Shared/Devour/SharedDevourSystem.cs
Normal file
94
Content.Shared/Devour/SharedDevourSystem.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
|
using Content.Shared.Mobs;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Content.Server.Devour.Components;
|
||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Devour;
|
||||||
|
|
||||||
|
public abstract class SharedDevourSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] protected readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DevourerComponent, ComponentStartup>(OnStartup);
|
||||||
|
SubscribeLocalEvent<DevourerComponent, DevourActionEvent>(OnDevourAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnStartup(EntityUid uid, DevourerComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
//Devourer doesn't actually chew, since he sends targets right into his stomach.
|
||||||
|
//I did it mom, I added ERP content into upstream. Legally!
|
||||||
|
component.Stomach = _containerSystem.EnsureContainer<Container>(uid, "stomach");
|
||||||
|
|
||||||
|
if (component.DevourAction != null)
|
||||||
|
_actionsSystem.AddAction(uid, component.DevourAction, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The devour action
|
||||||
|
/// </summary>
|
||||||
|
protected void OnDevourAction(EntityUid uid, DevourerComponent component, DevourActionEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled || component.Whitelist?.IsValid(args.Target, EntityManager) != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
var target = args.Target;
|
||||||
|
|
||||||
|
// Structure and mob devours handled differently.
|
||||||
|
if (TryComp(target, out MobStateComponent? targetState))
|
||||||
|
{
|
||||||
|
switch (targetState.CurrentState)
|
||||||
|
{
|
||||||
|
case MobState.Critical:
|
||||||
|
case MobState.Dead:
|
||||||
|
|
||||||
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(uid, component.DevourTime, new DevourDoAfterEvent(), uid, target: target, used: uid)
|
||||||
|
{
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("devour-action-popup-message-fail-target-alive"), uid, uid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("devour-action-popup-message-structure"), uid, uid);
|
||||||
|
|
||||||
|
if (component.SoundStructureDevour != null)
|
||||||
|
_audioSystem.PlayPvs(component.SoundStructureDevour, uid, component.SoundStructureDevour.Params);
|
||||||
|
|
||||||
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(uid, component.StructureDevourTime, new DevourDoAfterEvent(), uid, target: target, used: uid)
|
||||||
|
{
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DevourActionEvent : EntityTargetActionEvent { }
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class DevourDoAfterEvent : SimpleDoAfterEvent { }
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum FoodPreference : byte
|
||||||
|
{
|
||||||
|
Humanoid = 0,
|
||||||
|
All = 1
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using Content.Shared.DoAfter;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.Dragon;
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class DragonDevourDoAfterEvent : SimpleDoAfterEvent
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -97,22 +97,25 @@
|
|||||||
types:
|
types:
|
||||||
Piercing: 15
|
Piercing: 15
|
||||||
Slash: 15
|
Slash: 15
|
||||||
- type: Dragon
|
- type: Devourer
|
||||||
spawnsLeft: 2
|
foodPreference: Humanoid
|
||||||
spawnsProto: MobCarpDragon
|
shouldStoreDevoured: true
|
||||||
|
chemical: Ichor
|
||||||
|
healRate: 15.0
|
||||||
|
whitelist:
|
||||||
|
components:
|
||||||
|
- MobState
|
||||||
|
- Door
|
||||||
|
tags:
|
||||||
|
- Wall
|
||||||
devourAction:
|
devourAction:
|
||||||
event: !type:DragonDevourActionEvent
|
event: !type:DevourActionEvent
|
||||||
icon: Interface/Actions/devour.png
|
icon: Interface/Actions/devour.png
|
||||||
name: action-name-devour
|
name: action-name-devour
|
||||||
description: action-description-devour
|
description: action-description-devour
|
||||||
devourChemical: Ichor
|
- type: Dragon
|
||||||
devourHealRate: 15.0
|
spawnsLeft: 2
|
||||||
whitelist:
|
spawnsProto: MobCarpDragon
|
||||||
components:
|
|
||||||
- MobState
|
|
||||||
- Door
|
|
||||||
tags:
|
|
||||||
- Wall
|
|
||||||
spawnRiftAction:
|
spawnRiftAction:
|
||||||
event: !type:DragonSpawnRiftActionEvent
|
event: !type:DragonSpawnRiftActionEvent
|
||||||
icon:
|
icon:
|
||||||
|
|||||||
Reference in New Issue
Block a user