Death Nettle changes (#25253)
* Added ThornyComponent, ThornyImmuneComponent, and ThornySystem, as well as changed Botanists glove's to have the ThornyImmuneComponent, and for Death Nettle to have the ThornyComponent. * Added heat damage to the player if they pickup nettle without gloves. Also displays a popup message . * Revised OnHandPickUp method and reduced whitespace * Touching death nettle without gloves now does damage split between heat and caustic, and does more damage. * File-scoped namespace adherence * Code revisions, and removal of old file. * Removed thornyImmune key from botanist's gloves in gloves.yml for cleanup / yaml linter * Adds new generic DamageOnPickup, still very WIP * Starting on localization, removed _Notes.txt, adds immunity component * Added OnPickupDamageImmune component to botanists gloves * Removed botany specific components/system, moved to generic DamageOnPickup. Added code comments. Extra checks in component for whether to toss an item, damage an entity. Still WIP. * changes to audio and popups * Removes my system/component/ftl in favor of DamageOnInteract, tweaking values * me stupid * Death nettle will 'wilt' after 5 hits * added interaction delay to stop spam clicking, added a 10% stun (paralyze) chance * minor changes/cleanup * more minor changes and cleanup * Reduced maximum amatoxin within fly amanita spores. * Readjusted to allow more than 5 amatoxin above 50 potency * Remove Debug.Log statement from system * Mark Death Nettle as major contraband.
This commit is contained in:
@@ -44,4 +44,46 @@ public sealed partial class DamageOnInteractComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public bool IsDamageActive = true;
|
public bool IsDamageActive = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the thing should be thrown from its current position when they interact with the entity
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool Throw = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The speed applied to the thing when it is thrown
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public int ThrowSpeed = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time between being able to interact with this entity
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public uint InteractTimer = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks the last time this entity was interacted with, but only if the interaction resulted in the user taking damage
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan LastInteraction = TimeSpan.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks the time that this entity can be interacted with, but only if the interaction resulted in the user taking damage
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan NextInteraction = TimeSpan.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Probability that the user will be stunned when they interact with with this entity and took damage
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public float StunChance = 0.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Duration, in seconds, of the stun applied to the user when they interact with the entity and took damage
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public float StunSeconds = 0.0f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,15 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Content.Shared.Throwing;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Content.Shared.Random;
|
||||||
|
using Content.Shared.Movement.Pulling.Components;
|
||||||
|
using Content.Shared.Effects;
|
||||||
|
using Content.Shared.Stunnable;
|
||||||
|
|
||||||
namespace Content.Shared.Damage.Systems;
|
namespace Content.Shared.Damage.Systems;
|
||||||
|
|
||||||
@@ -17,6 +23,10 @@ public sealed class DamageOnInteractSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -35,6 +45,13 @@ public sealed class DamageOnInteractSystem : EntitySystem
|
|||||||
/// <param name="args">Contains the user that interacted with the entity</param>
|
/// <param name="args">Contains the user that interacted with the entity</param>
|
||||||
private void OnHandInteract(Entity<DamageOnInteractComponent> entity, ref InteractHandEvent args)
|
private void OnHandInteract(Entity<DamageOnInteractComponent> entity, ref InteractHandEvent args)
|
||||||
{
|
{
|
||||||
|
// Stop the interaction if the user attempts to interact with the object before the timer is finished
|
||||||
|
if (_gameTiming.CurTime < entity.Comp.NextInteraction)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!entity.Comp.IsDamageActive)
|
if (!entity.Comp.IsDamageActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -47,9 +64,8 @@ public sealed class DamageOnInteractSystem : EntitySystem
|
|||||||
|
|
||||||
// or checking the entity for the comp itself if the inventory didn't work
|
// or checking the entity for the comp itself if the inventory didn't work
|
||||||
if (protectiveEntity.Comp == null && TryComp<DamageOnInteractProtectionComponent>(args.User, out var protectiveComp))
|
if (protectiveEntity.Comp == null && TryComp<DamageOnInteractProtectionComponent>(args.User, out var protectiveComp))
|
||||||
{
|
|
||||||
protectiveEntity = (args.User, protectiveComp);
|
protectiveEntity = (args.User, protectiveComp);
|
||||||
}
|
|
||||||
|
|
||||||
// if protectiveComp isn't null after all that, it means the user has protection,
|
// if protectiveComp isn't null after all that, it means the user has protection,
|
||||||
// so let's calculate how much they resist
|
// so let's calculate how much they resist
|
||||||
@@ -59,17 +75,31 @@ public sealed class DamageOnInteractSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target);
|
totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target);
|
||||||
|
|
||||||
if (totalDamage != null && totalDamage.AnyPositive())
|
if (totalDamage != null && totalDamage.AnyPositive())
|
||||||
{
|
{
|
||||||
|
// Record this interaction and determine when a user is allowed to interact with this entity again
|
||||||
|
entity.Comp.LastInteraction = _gameTiming.CurTime;
|
||||||
|
entity.Comp.NextInteraction = _gameTiming.CurTime + TimeSpan.FromSeconds(entity.Comp.InteractTimer);
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
_adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured their hand by interacting with {ToPrettyString(args.Target):target} and received {totalDamage.GetTotal():damage} damage");
|
_adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured their hand by interacting with {ToPrettyString(args.Target):target} and received {totalDamage.GetTotal():damage} damage");
|
||||||
_audioSystem.PlayPredicted(entity.Comp.InteractSound, args.Target, args.User);
|
_audioSystem.PlayPredicted(entity.Comp.InteractSound, args.Target, args.User);
|
||||||
|
|
||||||
if (entity.Comp.PopupText != null)
|
if (entity.Comp.PopupText != null)
|
||||||
_popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User);
|
_popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User);
|
||||||
|
|
||||||
|
// Attempt to paralyze the user after they have taken damage
|
||||||
|
if (_random.Prob(entity.Comp.StunChance))
|
||||||
|
_stun.TryParalyze(args.User, TimeSpan.FromSeconds(entity.Comp.StunSeconds), true);
|
||||||
}
|
}
|
||||||
|
// Check if the entity's Throw bool is false, or if the entity has the PullableComponent, then if the entity is currently being pulled.
|
||||||
|
// BeingPulled must be checked because the entity will be spastically thrown around without this.
|
||||||
|
if (!entity.Comp.Throw || !TryComp<PullableComponent>(entity, out var pullComp) || pullComp.BeingPulled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_throwingSystem.TryThrow(entity, _random.NextVector2(), entity.Comp.ThrowSpeed, doSpin: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetIsDamageActiveTo(Entity<DamageOnInteractComponent> entity, bool mode)
|
public void SetIsDamageActiveTo(Entity<DamageOnInteractComponent> entity, bool mode)
|
||||||
|
|||||||
@@ -171,6 +171,11 @@
|
|||||||
fiberMaterial: fibers-leather
|
fiberMaterial: fibers-leather
|
||||||
fiberColor: fibers-brown
|
fiberColor: fibers-brown
|
||||||
- type: FingerprintMask
|
- type: FingerprintMask
|
||||||
|
- type: DamageOnInteractProtection
|
||||||
|
damageProtection:
|
||||||
|
flatReductions:
|
||||||
|
Heat: 10
|
||||||
|
Caustic: 5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHandsBase
|
parent: ClothingHandsBase
|
||||||
|
|||||||
@@ -250,7 +250,7 @@
|
|||||||
name: death nettle
|
name: death nettle
|
||||||
description: This nettle's out for blood.
|
description: This nettle's out for blood.
|
||||||
id: DeathNettle
|
id: DeathNettle
|
||||||
parent: ProduceBase
|
parent: [ProduceBase, BaseMajorContraband]
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Specific/Hydroponics/death_nettle.rsi
|
sprite: Objects/Specific/Hydroponics/death_nettle.rsi
|
||||||
@@ -261,24 +261,56 @@
|
|||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Heat: 8.5
|
Heat: 8
|
||||||
Caustic: 8.5
|
Caustic: 8
|
||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
food:
|
food:
|
||||||
reagents:
|
reagents:
|
||||||
- ReagentId: SulfuricAcid
|
- ReagentId: SulfuricAcid
|
||||||
Quantity: 3
|
Quantity: 15
|
||||||
- ReagentId: FluorosulfuricAcid
|
- ReagentId: FluorosulfuricAcid
|
||||||
Quantity: 3
|
Quantity: 15
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seedId: deathNettle
|
seedId: deathNettle
|
||||||
- type: MeleeChemicalInjector
|
- type: MeleeChemicalInjector
|
||||||
transferAmount: 2
|
transferAmount: 5
|
||||||
solution: food
|
solution: food
|
||||||
pierceArmor: false
|
pierceArmor: true
|
||||||
- type: Extractable
|
- type: Extractable
|
||||||
grindableSolutionName: food
|
grindableSolutionName: food
|
||||||
|
- type: DamageOnInteract
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Heat: 4
|
||||||
|
Caustic: 4
|
||||||
|
throw: true
|
||||||
|
throwSpeed: 3
|
||||||
|
interactTimer: 2 # Stop the player from spam clicking the entity
|
||||||
|
ignoreResistances: false
|
||||||
|
popupText: powered-light-component-burn-hand
|
||||||
|
interactSound: /Audio/Effects/lightburn.ogg
|
||||||
|
stunChance: 0.10
|
||||||
|
stunSeconds: 1.5
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Inorganic
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 25
|
||||||
|
behaviors:
|
||||||
|
- !type:PlaySoundBehavior
|
||||||
|
sound:
|
||||||
|
path: /Audio/Voice/Diona/diona_salute.ogg
|
||||||
|
params:
|
||||||
|
volume: -5
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
|
- type: DamageOnHit
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5 # The nettle will "wilt" after 5 hits.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: banana
|
name: banana
|
||||||
@@ -1791,10 +1823,10 @@
|
|||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
food:
|
food:
|
||||||
maxVol: 30
|
maxVol: 15
|
||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Amatoxin
|
- ReagentId: Amatoxin
|
||||||
Quantity: 25
|
Quantity: 10
|
||||||
- ReagentId: Nutriment
|
- ReagentId: Nutriment
|
||||||
Quantity: 5
|
Quantity: 5
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
|||||||
@@ -1402,8 +1402,8 @@
|
|||||||
chemicals:
|
chemicals:
|
||||||
Amatoxin:
|
Amatoxin:
|
||||||
Min: 1
|
Min: 1
|
||||||
Max: 25
|
Max: 10
|
||||||
PotencyDivisor: 4
|
PotencyDivisor: 12
|
||||||
Nutriment: ## yumby :)
|
Nutriment: ## yumby :)
|
||||||
Min: 1
|
Min: 1
|
||||||
Max: 5
|
Max: 5
|
||||||
|
|||||||
Reference in New Issue
Block a user