mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
Make DamageSpecifier serializable (#43049)
* pt1 damageable refactor * fixes * thusd unused * sparse damagespecifiers * fix thongs * aaaaaa * fix tests * de-crash
This commit is contained in:
parent
9cdc009e00
commit
e361944ef6
46 changed files with 307 additions and 421 deletions
|
|
@ -135,7 +135,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer
|
|||
damageable.DamagePerGroup.OrderByDescending(damage => damage.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
IReadOnlyDictionary<string, FixedPoint2> damagePerType = damageable.Damage.DamageDict;
|
||||
var damagePerType = damageable.Damage.DamageDict;
|
||||
|
||||
DrawDiagnosticGroups(damageSortedGroups, damagePerType);
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer
|
|||
|
||||
private void DrawDiagnosticGroups(
|
||||
Dictionary<string, FixedPoint2> groups,
|
||||
IReadOnlyDictionary<string, FixedPoint2> damageDict)
|
||||
IReadOnlyDictionary<ProtoId<DamageTypePrototype>, FixedPoint2> damageDict)
|
||||
{
|
||||
GroupsContainer.RemoveAllChildren();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Damageable;
|
||||
|
||||
|
|
@ -39,14 +41,14 @@ public sealed class DamageSpecifierTest
|
|||
Assert.That(difference, Is.EqualTo(output5));
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Input1 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Input1 = new()
|
||||
{
|
||||
{ "A", 1.5f },
|
||||
{ "B", 2 },
|
||||
{ "C", 3 }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Input2 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Input2 = new()
|
||||
{
|
||||
{ "A", 1 },
|
||||
{ "B", 2 },
|
||||
|
|
@ -54,28 +56,28 @@ public sealed class DamageSpecifierTest
|
|||
{ "D", 0.05f }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Output1 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Output1 = new()
|
||||
{
|
||||
{ "A", -1.5f },
|
||||
{ "B", -2 },
|
||||
{ "C", -3 }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Output2 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Output2 = new()
|
||||
{
|
||||
{ "A", 0.75f },
|
||||
{ "B", 1 },
|
||||
{ "C", 1.5 }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Output3 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Output3 = new()
|
||||
{
|
||||
{ "A", 3f },
|
||||
{ "B", 4 },
|
||||
{ "C", 6 }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Output4 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Output4 = new()
|
||||
{
|
||||
{ "A", 0.5f },
|
||||
{ "B", 0 },
|
||||
|
|
@ -83,7 +85,7 @@ public sealed class DamageSpecifierTest
|
|||
{ "D", -0.05f }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, FixedPoint2> Output5 = new()
|
||||
private static readonly Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> Output5 = new()
|
||||
{
|
||||
{ "A", 0.25f },
|
||||
{ "B", 0 },
|
||||
|
|
|
|||
|
|
@ -148,17 +148,6 @@ namespace Content.IntegrationTests.Tests.Damageable
|
|||
{
|
||||
var uid = sDamageableEntity;
|
||||
|
||||
// Check that the correct types are supported.
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type1.ID), Is.False);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type2a.ID), Is.True);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type2b.ID), Is.False);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3a.ID), Is.True);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3b.ID), Is.True);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3c.ID), Is.True);
|
||||
});
|
||||
|
||||
// Check that damage is evenly distributed over a group if its a nice multiple
|
||||
var types = group3.DamageTypes;
|
||||
var damageToDeal = FixedPoint2.New(types.Count * 5);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
using System.Text.Json;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server.Administration.Logs.Converters;
|
||||
|
||||
[AdminLogConverter]
|
||||
public sealed class DamageSpecifierConverter : AdminLogConverter<DamageSpecifier>
|
||||
{
|
||||
public override void Write(Utf8JsonWriter writer, DamageSpecifier value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
foreach (var (damage, amount) in value.DamageDict)
|
||||
{
|
||||
writer.WriteNumber(damage.Id, amount.Double());
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ public sealed partial class DeltaPressureComponent : Component
|
|||
[DataField]
|
||||
public DamageSpecifier BaseDamage = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
DamageDict = new ()
|
||||
{
|
||||
{ "Structural", 10 },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public sealed partial class ChangelingDevourComponent : Component
|
|||
[DataField, AutoNetworkedField]
|
||||
public DamageSpecifier DamagePerTick = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
DamageDict = new ()
|
||||
{
|
||||
{ "Slash", 10},
|
||||
{ "Piercing", 10 },
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public sealed partial class CluwneComponent : Component
|
|||
{
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Genetic", 300.0 },
|
||||
{ "Cellular", 300.0 },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Content.Shared.Damage.Components;
|
|||
/// may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
[NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
|
||||
public sealed partial class DamageableComponent : Component
|
||||
{
|
||||
|
|
@ -25,7 +25,7 @@ public sealed partial class DamageableComponent : Component
|
|||
/// This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
|
||||
/// If null, all damage types will be supported.
|
||||
/// </summary>
|
||||
[DataField("damageContainer")]
|
||||
[DataField("damageContainer"), AutoNetworkedField]
|
||||
// ReSharper disable once InconsistentNaming - This is wrong but fixing it is potentially annoying for downstreams.
|
||||
public ProtoId<DamageContainerPrototype>? DamageContainerID;
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ public sealed partial class DamageableComponent : Component
|
|||
/// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
|
||||
/// to reduce duplication.
|
||||
/// </remarks>
|
||||
[DataField("damageModifierSet")]
|
||||
[DataField("damageModifierSet"), AutoNetworkedField]
|
||||
public ProtoId<DamageModifierSetPrototype>? DamageModifierSetId;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,7 +46,7 @@ public sealed partial class DamageableComponent : Component
|
|||
/// <remarks>
|
||||
/// If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
|
||||
/// </remarks>
|
||||
[DataField(readOnly: true)] //TODO FULL GAME SAVE
|
||||
[DataField, AutoNetworkedField]
|
||||
public DamageSpecifier Damage = new();
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -87,20 +87,6 @@ public sealed partial class DamageableComponent : Component
|
|||
[DataField]
|
||||
public ProtoId<HealthIconPrototype> RottingIcon = "HealthIconRotting";
|
||||
|
||||
[DataField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public FixedPoint2? HealthBarThreshold;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class DamageableComponentState(
|
||||
Dictionary<string, FixedPoint2> damageDict,
|
||||
ProtoId<DamageContainerPrototype>? damageContainerId,
|
||||
ProtoId<DamageModifierSetPrototype>? modifierSetId,
|
||||
FixedPoint2? healthBarThreshold)
|
||||
: ComponentState
|
||||
{
|
||||
public readonly Dictionary<string, FixedPoint2> DamageDict = damageDict;
|
||||
public readonly ProtoId<DamageContainerPrototype>? DamageContainerId = damageContainerId;
|
||||
public readonly ProtoId<DamageModifierSetPrototype>? ModifierSetId = modifierSetId;
|
||||
public readonly FixedPoint2? HealthBarThreshold = healthBarThreshold;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ using System.Text.Json.Serialization;
|
|||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
|
||||
|
||||
namespace Content.Shared.Damage
|
||||
{
|
||||
|
|
@ -19,31 +18,13 @@ namespace Content.Shared.Damage
|
|||
/// functions to apply resistance sets and supports basic math operations to modify this dictionary.
|
||||
/// </remarks>
|
||||
[DataDefinition, Serializable, NetSerializable]
|
||||
public sealed partial class DamageSpecifier : IEquatable<DamageSpecifier>
|
||||
public sealed partial class DamageSpecifier : IEquatable<DamageSpecifier>, IRobustCloneable<DamageSpecifier>
|
||||
{
|
||||
// For the record I regret so many of the decisions i made when rewriting damageable
|
||||
// Why is it just shitting out dictionaries left and right
|
||||
// One day Arrays, stackalloc spans, and SIMD will save the day.
|
||||
// TODO DAMAGEABLE REFACTOR
|
||||
|
||||
// These exist solely so the wiki works. Please do not touch them or use them.
|
||||
[JsonPropertyName("types")]
|
||||
[DataField("types", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, DamageTypePrototype>))]
|
||||
[UsedImplicitly]
|
||||
private Dictionary<string, FixedPoint2>? _damageTypeDictionary;
|
||||
|
||||
[JsonPropertyName("groups")]
|
||||
[DataField("groups", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, DamageGroupPrototype>))]
|
||||
[UsedImplicitly]
|
||||
private Dictionary<string, FixedPoint2>? _damageGroupDictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Main DamageSpecifier dictionary. Most DamageSpecifier functions exist to somehow modifying this.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[IncludeDataField(customTypeSerializer: typeof(DamageSpecifierDictionarySerializer), readOnly: true)]
|
||||
public Dictionary<string, FixedPoint2> DamageDict { get; set; } = new();
|
||||
[DataField("types")]
|
||||
public Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2> DamageDict { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a sum of the damage values.
|
||||
|
|
@ -84,6 +65,11 @@ namespace Content.Shared.Damage
|
|||
[JsonIgnore]
|
||||
public bool Empty => DamageDict.Count == 0;
|
||||
|
||||
public DamageSpecifier Clone()
|
||||
{
|
||||
return new DamageSpecifier(this);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "DamageSpecifier(" + string.Join("; ", DamageDict.Select(x => x.Key + ":" + x.Value)) + ")";
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Validation;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
|
||||
namespace Content.Shared.Damage;
|
||||
|
||||
//todo writing
|
||||
public sealed class DamageSpecifierDictionarySerializer : ITypeReader<Dictionary<string, FixedPoint2>, MappingDataNode>
|
||||
{
|
||||
private ITypeValidator<Dictionary<string, FixedPoint2>, MappingDataNode> _damageTypeSerializer = new PrototypeIdDictionarySerializer<FixedPoint2, DamageTypePrototype>();
|
||||
private ITypeValidator<Dictionary<string, FixedPoint2>, MappingDataNode> _damageGroupSerializer = new PrototypeIdDictionarySerializer<FixedPoint2, DamageGroupPrototype>();
|
||||
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||
{
|
||||
var vals = new Dictionary<ValidationNode, ValidationNode>();
|
||||
if (node.TryGet<MappingDataNode>("types", out var typesNode))
|
||||
{
|
||||
vals.Add(new ValidatedValueNode(new ValueDataNode("types")), _damageTypeSerializer.Validate(serializationManager, typesNode, dependencies, context));
|
||||
}
|
||||
|
||||
if (node.TryGet<MappingDataNode>("groups", out var groupsNode))
|
||||
{
|
||||
vals.Add(new ValidatedValueNode(new ValueDataNode("groups")), _damageGroupSerializer.Validate(serializationManager, groupsNode, dependencies, context));
|
||||
}
|
||||
|
||||
return new ValidatedMappingNode(vals);
|
||||
}
|
||||
|
||||
public Dictionary<string, FixedPoint2> Read(ISerializationManager serializationManager, MappingDataNode node, IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<Dictionary<string, FixedPoint2>>? instanceProvider = null)
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new();
|
||||
// Add all the damage types by just copying the type dictionary (if it is not null).
|
||||
if (node.TryGet<MappingDataNode>("types", out var typesNode))
|
||||
{
|
||||
serializationManager.Read(typesNode, instanceProvider: () => dict, notNullableOverride: true);
|
||||
}
|
||||
|
||||
if (!node.TryGet<MappingDataNode>("groups", out var groupsNode))
|
||||
return dict;
|
||||
|
||||
// Then resolve damage groups and add them
|
||||
var prototypeManager = dependencies.Resolve<IPrototypeManager>();
|
||||
foreach (var entry in serializationManager.Read<Dictionary<string, FixedPoint2>>(groupsNode, notNullableOverride: true))
|
||||
{
|
||||
if (!prototypeManager.TryIndex<DamageGroupPrototype>(entry.Key, out var group))
|
||||
{
|
||||
// This can happen if deserialized before prototypes are loaded.
|
||||
// i made this a warning bc it was failing tests -paul
|
||||
dependencies.Resolve<ILogManager>().RootSawmill.Error($"Unknown damage group given to DamageSpecifier: {entry.Key}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Simply distribute evenly (except for rounding).
|
||||
// We do this by reducing remaining the # of types and damage every loop.
|
||||
var remainingTypes = group.DamageTypes.Count;
|
||||
var remainingDamage = entry.Value;
|
||||
foreach (var damageType in group.DamageTypes)
|
||||
{
|
||||
var damage = remainingDamage / FixedPoint2.New(remainingTypes);
|
||||
if (!dict.TryAdd(damageType, damage))
|
||||
{
|
||||
// Key already exists, add values
|
||||
dict[damageType] += damage;
|
||||
}
|
||||
remainingDamage -= damage;
|
||||
remainingTypes -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ namespace Content.Shared.Damage.Prototypes
|
|||
/// to change/get/set damage in a <see cref="DamageableComponent"/>.
|
||||
/// </remarks>
|
||||
[Prototype(2)]
|
||||
[Obsolete("Do not rely on DamageGroupPrototype for anything besides grouping logically similar damage in UIs")]
|
||||
public sealed partial class DamageGroupPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; private set; } = default!;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@ namespace Content.Shared.Damage.Systems;
|
|||
|
||||
public sealed partial class DamageableSystem
|
||||
{
|
||||
/// <returns>If the damage container can take the given damage type</returns>
|
||||
private bool SupportsType(ProtoId<DamageContainerPrototype>? container, ProtoId<DamageTypePrototype> type)
|
||||
{
|
||||
if (container is null)
|
||||
return true;
|
||||
|
||||
return _supportedTypesByContainer[container.Value].Contains(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directly sets the damage in a damageable component.
|
||||
/// This method keeps the damage types supported by the DamageContainerPrototype in the component.
|
||||
|
|
@ -25,30 +34,15 @@ public sealed partial class DamageableSystem
|
|||
|
||||
foreach (var type in ent.Comp.Damage.DamageDict.Keys)
|
||||
{
|
||||
if (damage.DamageDict.TryGetValue(type, out var value))
|
||||
ent.Comp.Damage.DamageDict[type] = value;
|
||||
else
|
||||
ent.Comp.Damage.DamageDict[type] = 0;
|
||||
if (!damage.DamageDict.ContainsKey(type))
|
||||
ent.Comp.Damage.DamageDict.Remove(type);
|
||||
}
|
||||
|
||||
OnEntityDamageChanged((ent, ent.Comp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directly sets the damage specifier of a damageable component.
|
||||
/// This will overwrite the complete damage dict, meaning it will bulldoze the supported damage types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This may break persistance as the supported types are reset in case the component is initialized again.
|
||||
/// So this only makes sense if you also change the DamageContainerPrototype in the component at the same time.
|
||||
/// Only use this method if you know what you are doing.
|
||||
/// </remarks>
|
||||
public void SetDamageSpecifier(Entity<DamageableComponent?> ent, DamageSpecifier damage)
|
||||
{
|
||||
if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
|
||||
return;
|
||||
|
||||
ent.Comp.Damage = damage;
|
||||
foreach (var (type, amount) in damage.DamageDict)
|
||||
{
|
||||
if (SupportsType(ent.Comp.DamageContainerID, type))
|
||||
ent.Comp.Damage.DamageDict[type] = amount;
|
||||
}
|
||||
|
||||
OnEntityDamageChanged((ent, ent.Comp));
|
||||
}
|
||||
|
|
@ -167,10 +161,10 @@ public sealed partial class DamageableSystem
|
|||
var dict = ent.Comp.Damage.DamageDict;
|
||||
foreach (var (type, value) in damage.DamageDict)
|
||||
{
|
||||
// CollectionsMarshal my beloved.
|
||||
if (!dict.TryGetValue(type, out var oldValue))
|
||||
if (!SupportsType(ent.Comp.DamageContainerID, type))
|
||||
continue;
|
||||
|
||||
var oldValue = dict.GetValueOrDefault(type);
|
||||
var newValue = FixedPoint2.Max(FixedPoint2.Zero, oldValue + value);
|
||||
if (newValue == oldValue)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Content.Shared.Inventory;
|
|||
using Content.Shared.Radiation.Events;
|
||||
using Content.Shared.Rejuvenate;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Damage.Systems;
|
||||
|
||||
|
|
@ -13,11 +14,13 @@ public sealed partial class DamageableSystem
|
|||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
RebuildContainerCache();
|
||||
|
||||
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
|
||||
SubscribeLocalEvent<DamageableComponent, ComponentInit>(DamageableInit);
|
||||
SubscribeLocalEvent<DamageableComponent, ComponentHandleState>(DamageableHandleState);
|
||||
SubscribeLocalEvent<DamageableComponent, ComponentGetState>(DamageableGetState);
|
||||
SubscribeLocalEvent<DamageableComponent, OnIrradiatedEvent>(OnIrradiated);
|
||||
SubscribeLocalEvent<DamageableComponent, RejuvenateEvent>(OnRejuvenate);
|
||||
SubscribeLocalEvent<DamageableComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
|
||||
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
|
||||
_damageableQuery = GetEntityQuery<DamageableComponent>();
|
||||
|
|
@ -119,41 +122,49 @@ public sealed partial class DamageableSystem
|
|||
);
|
||||
}
|
||||
|
||||
private void OnPrototypesReloaded(PrototypesReloadedEventArgs ev)
|
||||
{
|
||||
if (!ev.WasModified<DamageContainerPrototype>() && !ev.WasModified<DamageGroupPrototype>())
|
||||
return;
|
||||
|
||||
RebuildContainerCache();
|
||||
}
|
||||
|
||||
private void RebuildContainerCache()
|
||||
{
|
||||
_supportedTypesByContainer.Clear();
|
||||
|
||||
foreach (var proto in _prototypeManager.EnumeratePrototypes<DamageContainerPrototype>())
|
||||
{
|
||||
var set = new HashSet<ProtoId<DamageTypePrototype>>();
|
||||
_supportedTypesByContainer[proto.ID] = set;
|
||||
|
||||
foreach (var type in proto.SupportedTypes)
|
||||
{
|
||||
set.Add(type);
|
||||
}
|
||||
|
||||
foreach (var groupId in proto.SupportedGroups)
|
||||
{
|
||||
var group = _prototypeManager.Index(groupId);
|
||||
foreach (var type in group.DamageTypes)
|
||||
{
|
||||
set.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<DamageableComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
OnEntityDamageChanged(ent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a damageable component
|
||||
/// </summary>
|
||||
private void DamageableInit(Entity<DamageableComponent> ent, ref ComponentInit _)
|
||||
{
|
||||
if (
|
||||
ent.Comp.DamageContainerID is null ||
|
||||
!_prototypeManager.Resolve(ent.Comp.DamageContainerID, out var damageContainerPrototype)
|
||||
)
|
||||
{
|
||||
// No DamageContainerPrototype was given. So we will allow the container to support all damage types
|
||||
foreach (var type in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
|
||||
{
|
||||
ent.Comp.Damage.DamageDict.TryAdd(type.ID, FixedPoint2.Zero);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize damage dictionary, using the types and groups from the damage
|
||||
// container prototype
|
||||
foreach (var type in damageContainerPrototype.SupportedTypes)
|
||||
{
|
||||
ent.Comp.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
|
||||
}
|
||||
|
||||
foreach (var groupId in damageContainerPrototype.SupportedGroups)
|
||||
{
|
||||
var group = _prototypeManager.Index(groupId);
|
||||
foreach (var type in group.DamageTypes)
|
||||
{
|
||||
ent.Comp.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ent.Comp.Damage.GetDamagePerGroup(_prototypeManager, ent.Comp.DamagePerGroup);
|
||||
ent.Comp.TotalDamage = ent.Comp.Damage.GetTotal();
|
||||
}
|
||||
|
|
@ -179,28 +190,6 @@ public sealed partial class DamageableSystem
|
|||
ClearAllDamage(ent.AsNullable());
|
||||
_mobThreshold.SetAllowRevives(ent, false);
|
||||
}
|
||||
|
||||
private void DamageableHandleState(Entity<DamageableComponent> ent, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not DamageableComponentState state)
|
||||
return;
|
||||
|
||||
ent.Comp.DamageContainerID = state.DamageContainerId;
|
||||
ent.Comp.DamageModifierSetId = state.ModifierSetId;
|
||||
ent.Comp.HealthBarThreshold = state.HealthBarThreshold;
|
||||
|
||||
// Has the damage actually changed?
|
||||
DamageSpecifier newDamage = new() { DamageDict = new Dictionary<string, FixedPoint2>(state.DamageDict) };
|
||||
var delta = newDamage - ent.Comp.Damage;
|
||||
delta.TrimZeros();
|
||||
|
||||
if (delta.Empty)
|
||||
return;
|
||||
|
||||
ent.Comp.Damage = newDamage;
|
||||
|
||||
OnEntityDamageChanged(ent, delta);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ public sealed partial class DamageableSystem : EntitySystem
|
|||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly INetManager _netMan = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!;
|
||||
|
|
@ -38,6 +37,8 @@ public sealed partial class DamageableSystem : EntitySystem
|
|||
public float UniversalTopicalsHealModifier { get; private set; } = 1f;
|
||||
public float UniversalMobDamageModifier { get; private set; } = 1f;
|
||||
|
||||
private Dictionary<ProtoId<DamageContainerPrototype>, HashSet<ProtoId<DamageTypePrototype>>> _supportedTypesByContainer = new();
|
||||
|
||||
/// <summary>
|
||||
/// If the damage in a DamageableComponent was changed this function should be called.
|
||||
/// </summary>
|
||||
|
|
@ -70,31 +71,6 @@ public sealed partial class DamageableSystem : EntitySystem
|
|||
// byref struct event.
|
||||
RaiseLocalEvent(ent, new DamageChangedEvent(ent.Comp, damageDelta, interruptsDoAfters, origin));
|
||||
}
|
||||
private void DamageableGetState(Entity<DamageableComponent> ent, ref ComponentGetState args)
|
||||
{
|
||||
if (_netMan.IsServer)
|
||||
{
|
||||
args.State = new DamageableComponentState(
|
||||
ent.Comp.Damage.DamageDict,
|
||||
ent.Comp.DamageContainerID,
|
||||
ent.Comp.DamageModifierSetId,
|
||||
ent.Comp.HealthBarThreshold
|
||||
);
|
||||
// TODO BODY SYSTEM pass damage onto body system
|
||||
// BOBBY WHEN? 😭
|
||||
// BOBBY SOON 🫡
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid mispredicting damage on newly spawned entities.
|
||||
args.State = new DamageableComponentState(
|
||||
ent.Comp.Damage.DamageDict.ShallowClone(),
|
||||
ent.Comp.DamageContainerID,
|
||||
ent.Comp.DamageModifierSetId,
|
||||
ent.Comp.HealthBarThreshold
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Goes through an entity damage's and saves them inside a dictionary if the value is higher than 0
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@ public sealed partial class DamageGroupTrigger : IThresholdTrigger
|
|||
|
||||
public bool Reached(Entity<DamageableComponent> damageable, SharedDestructibleSystem system)
|
||||
{
|
||||
return damageable.Comp.DamagePerGroup[DamageGroup] >= Damage;
|
||||
return damageable.Comp.DamagePerGroup.GetValueOrDefault(DamageGroup) >= Damage;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public sealed partial class DamageGroupEntityConditionSystem : EntityConditionSy
|
|||
{
|
||||
protected override void Condition(Entity<DamageableComponent> entity, ref EntityConditionEvent<DamageGroupCondition> args)
|
||||
{
|
||||
var value = entity.Comp.DamagePerGroup[args.Condition.DamageGroup];
|
||||
var value = entity.Comp.DamagePerGroup.GetValueOrDefault(args.Condition.DamageGroup);
|
||||
args.Result = value >= args.Condition.Min && value <= args.Condition.Max;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public sealed partial class KitchenSpikeComponent : Component
|
|||
[DataField, AutoNetworkedField]
|
||||
public DamageSpecifier SpikeDamage = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Piercing", 10 },
|
||||
},
|
||||
|
|
@ -70,7 +70,7 @@ public sealed partial class KitchenSpikeComponent : Component
|
|||
[DataField, AutoNetworkedField]
|
||||
public DamageSpecifier ButcherDamage = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Slash", 20 },
|
||||
},
|
||||
|
|
@ -82,7 +82,7 @@ public sealed partial class KitchenSpikeComponent : Component
|
|||
[DataField, AutoNetworkedField]
|
||||
public DamageSpecifier TimeDamage = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Blunt", 1 }, // Mobs are only gibbed from blunt (at least for now).
|
||||
},
|
||||
|
|
|
|||
|
|
@ -136,12 +136,11 @@
|
|||
# even if it's a meme - I did research
|
||||
methods: [ Touch ]
|
||||
effects: # TODO: when magic is around - make a milk transformation to a skeleton monster
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
groups: # these groups are the only 3 possible ways to damage a skeleton. numerical values obviously up to discussion
|
||||
Burn: -1
|
||||
Brute: -0.75
|
||||
Metaphysical: -2 # Gameplay: skeletons need some way to heal holy damage. Lore: milk is an unholy liquid that shuns the light of god. (/j)
|
||||
- !type:EvenHealthChange
|
||||
damage: # these groups are the only 3 possible ways to damage a skeleton. numerical values obviously up to discussion
|
||||
Burn: -1
|
||||
Brute: -0.75
|
||||
Metaphysical: -2 # Gameplay: skeletons need some way to heal holy damage. Lore: milk is an unholy liquid that shuns the light of god. (/j)
|
||||
- !type:PopupMessage
|
||||
type: Local
|
||||
visualType: Large
|
||||
|
|
|
|||
|
|
@ -120,8 +120,9 @@
|
|||
damage:
|
||||
types:
|
||||
Heat: -0.14
|
||||
groups:
|
||||
Brute: -0.14
|
||||
Blunt: -0.05
|
||||
Piercing: -0.05
|
||||
Slash: -0.05
|
||||
- type: DamageVisuals
|
||||
damageOverlayGroups:
|
||||
Brute:
|
||||
|
|
|
|||
|
|
@ -229,8 +229,9 @@
|
|||
types:
|
||||
Heat: -0.07
|
||||
Poison: -0.2 # needs to be less than the PendingZombieComponent does or they never become zombies by the disease.
|
||||
groups:
|
||||
Brute: -0.07
|
||||
Blunt: -0.02
|
||||
Piercing: -0.02
|
||||
Slash: -0.02
|
||||
- type: DamageVisuals
|
||||
damageOverlayGroups:
|
||||
Brute:
|
||||
|
|
|
|||
|
|
@ -186,8 +186,9 @@
|
|||
damage:
|
||||
types:
|
||||
Heat: -0.07
|
||||
groups:
|
||||
Brute: -0.07
|
||||
Blunt: -0.05
|
||||
Piercing: -0.05
|
||||
Slash: -0.05
|
||||
- type: Fingerprint
|
||||
- type: Blindable
|
||||
- type: Temperature
|
||||
|
|
|
|||
|
|
@ -2424,8 +2424,8 @@
|
|||
angle: 0
|
||||
animation: WeaponArcBite
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Piercing: 5
|
||||
- type: Item
|
||||
size: Normal
|
||||
sprite: Mobs/Animals/grenadepenguin.rsi
|
||||
|
|
@ -2592,9 +2592,12 @@
|
|||
damage:
|
||||
types:
|
||||
Poison: -0.07
|
||||
groups:
|
||||
Brute: -0.07
|
||||
Burn: -0.07
|
||||
Blunt: -0.03
|
||||
Slash: -0.03
|
||||
Piercing: -0.03
|
||||
Heat: -0.03
|
||||
Cold: -0.03
|
||||
Shock: -0.03
|
||||
|
||||
- type: entity
|
||||
parent: MobSpiderBase
|
||||
|
|
|
|||
|
|
@ -102,26 +102,23 @@
|
|||
- reagents: [ Water ]
|
||||
methods: [ Touch ]
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.15
|
||||
Brute: -0.15
|
||||
- reagents: [ Blood ]
|
||||
methods: [ Touch ]
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.25
|
||||
Burn: -0.25
|
||||
Brute: -0.25
|
||||
Burn: -0.25
|
||||
- reagents: [ RobustHarvest ]
|
||||
methods: [ Touch ]
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Brute: -1
|
||||
Burn: -1
|
||||
Brute: -1
|
||||
Burn: -1
|
||||
- reagents: [ WeedKiller, PlantBGone ]
|
||||
methods: [ Touch ]
|
||||
effects:
|
||||
|
|
@ -202,8 +199,10 @@
|
|||
- type: MeleeWeapon
|
||||
hidden: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: 9
|
||||
types:
|
||||
Blunt: 3
|
||||
Piercing: 3
|
||||
Slash: 3
|
||||
animation: WeaponArcBite
|
||||
- type: Climbing
|
||||
- type: NameIdentifier
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@
|
|||
angle: 0
|
||||
animation: WeaponArcBite
|
||||
damage:
|
||||
groups:
|
||||
Brute: 2
|
||||
types:
|
||||
Piercing: 2
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
melee:
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@
|
|||
collection: AlienClaw
|
||||
animation: WeaponArcBite
|
||||
damage:
|
||||
groups:
|
||||
Brute: 6
|
||||
types:
|
||||
Piercing: 6
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
|
|
@ -176,8 +176,8 @@
|
|||
40: 0.7
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 6
|
||||
types:
|
||||
Slash: 6
|
||||
- type: MovementSpeedModifier
|
||||
baseSprintSpeed: 4
|
||||
- type: Fixtures
|
||||
|
|
@ -214,8 +214,8 @@
|
|||
- type: MovementSpeedModifier
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 12
|
||||
types:
|
||||
Slash: 12
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
|
|
@ -251,8 +251,8 @@
|
|||
baseSprintSpeed: 4
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 10
|
||||
types:
|
||||
Slash: 10
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
50: 0.7
|
||||
|
|
@ -284,8 +284,8 @@
|
|||
baseSprintSpeed: 6.0
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Slash: 5
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
|
|
@ -506,8 +506,8 @@
|
|||
collection: AlienClaw
|
||||
animation: WeaponArcBite
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Slash: 5
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
|
|
|
|||
|
|
@ -229,8 +229,8 @@
|
|||
amount: 1
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 12
|
||||
types:
|
||||
Piercing: 12
|
||||
|
||||
- type: entity
|
||||
parent: BaseAction
|
||||
|
|
|
|||
|
|
@ -161,8 +161,8 @@
|
|||
soundHit:
|
||||
collection: MetalThud
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Blunt: 5
|
||||
|
||||
# Used for mobs that are affected by atmospherics, pressure, and heat
|
||||
- type: entity
|
||||
|
|
|
|||
|
|
@ -999,8 +999,8 @@
|
|||
path: /Audio/Animals/dog_bark1.ogg
|
||||
hidden: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: 1
|
||||
types:
|
||||
Blunt: 1
|
||||
|
||||
- type: entity
|
||||
parent: FoodBreadBase
|
||||
|
|
|
|||
|
|
@ -1121,8 +1121,8 @@
|
|||
path: /Audio/Animals/cat_hiss.ogg
|
||||
hidden: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: 1
|
||||
types:
|
||||
Blunt: 1
|
||||
|
||||
# Suppermatter
|
||||
# I can't figure out where to put this. It kind of acts like a cake I guess?
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
Blunt: 1
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
types: {}
|
||||
|
||||
- type: entity
|
||||
id: BookSpaceEncyclopedia
|
||||
|
|
|
|||
|
|
@ -71,9 +71,10 @@
|
|||
components:
|
||||
- type: Repairable # Negative values represent healing
|
||||
damage:
|
||||
groups:
|
||||
Brute: -60 # 20 of each Brute Type - 20% of a basic shield HP
|
||||
types:
|
||||
Blunt: -20
|
||||
Slash: -20
|
||||
Piercing: -20
|
||||
Heat: -20
|
||||
fuelCost: 10 # 1/2 of a Welder for a full repair
|
||||
doAfterDelay: 5
|
||||
|
|
|
|||
|
|
@ -8,13 +8,19 @@
|
|||
delay: 10.0
|
||||
- type: Bible
|
||||
damage:
|
||||
groups:
|
||||
Brute: -15
|
||||
Burn: -15
|
||||
types:
|
||||
Blunt: -5
|
||||
Piercing: -5
|
||||
Slash: -5
|
||||
Heat: -5
|
||||
Cold: -5
|
||||
Shock: -5
|
||||
damageOnFail:
|
||||
groups:
|
||||
Brute: 15
|
||||
Airloss: 15
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 5
|
||||
Slash: 5
|
||||
Asphyxiation: 15
|
||||
damageOnUntrainedUse: ## What a non-chaplain takes when attempting to heal someone
|
||||
types:
|
||||
Heat: 10
|
||||
|
|
@ -66,9 +72,11 @@
|
|||
types:
|
||||
Caustic: 20 ## ~15 dps
|
||||
damageOnFail:
|
||||
groups:
|
||||
Brute: 15
|
||||
Airloss: 25
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 5
|
||||
Slash: 5
|
||||
Asphyxiation: 25
|
||||
damageOnUntrainedUse:
|
||||
types:
|
||||
Caustic: 50
|
||||
|
|
|
|||
|
|
@ -130,8 +130,10 @@
|
|||
damageContainers:
|
||||
- Biological
|
||||
damage:
|
||||
groups:
|
||||
Brute: -15 # 5 for each type in the group
|
||||
types:
|
||||
Blunt: -5
|
||||
Piercing: -5
|
||||
Slash: -5
|
||||
healingBeginSound:
|
||||
path: "/Audio/Items/Medical/brutepack_begin.ogg"
|
||||
params:
|
||||
|
|
@ -176,8 +178,10 @@
|
|||
damageContainers:
|
||||
- Biological
|
||||
damage:
|
||||
groups:
|
||||
Brute: -30 # 10 for each type in the group
|
||||
types:
|
||||
Blunt: -10
|
||||
Piercing: -10
|
||||
Slash: -10
|
||||
bloodlossModifier: -10 # a suture should stop ongoing bleeding
|
||||
healingBeginSound:
|
||||
path: "/Audio/Items/Medical/brutepack_begin.ogg"
|
||||
|
|
@ -268,9 +272,8 @@
|
|||
damageContainers:
|
||||
- Biological
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5 # Tourniquets HURT!
|
||||
types:
|
||||
Blunt: 5 # Tourniquets HURT
|
||||
Asphyxiation: 5 # Essentially Stopping all blood reaching a part of your body
|
||||
bloodlossModifier: -10 # Tourniquets stop bleeding
|
||||
delay: 0.5
|
||||
|
|
@ -368,10 +371,14 @@
|
|||
damageContainers:
|
||||
- Biological
|
||||
damage:
|
||||
groups: # these are all split across multiple types
|
||||
Brute: -150
|
||||
Burn: -150
|
||||
Toxin: -150
|
||||
types: # these are all split across multiple types
|
||||
Blunt: -50
|
||||
Piercing: -50
|
||||
Slash: -50
|
||||
Heat: -50
|
||||
Cold: -50
|
||||
Shock: -50
|
||||
Poison: -150
|
||||
bloodlossModifier: -20
|
||||
delay: 1
|
||||
selfHealPenaltyMultiplier: 0
|
||||
|
|
|
|||
|
|
@ -209,8 +209,8 @@
|
|||
heldPrefix: improv
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 10
|
||||
types:
|
||||
Slash: 10
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: Tool
|
||||
|
|
@ -228,8 +228,8 @@
|
|||
heldPrefix: electric
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 15
|
||||
types:
|
||||
Slash: 15
|
||||
soundHit:
|
||||
path: /Audio/Items/drill_hit.ogg
|
||||
- type: Tool
|
||||
|
|
|
|||
|
|
@ -106,8 +106,7 @@
|
|||
deleteOnCollide: false
|
||||
onlyCollideWhenShot: true
|
||||
damage:
|
||||
types:
|
||||
Brute: 0
|
||||
types: {}
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
sprite: Structures/Storage/closet.rsi
|
||||
|
|
@ -246,11 +245,18 @@
|
|||
color: white
|
||||
- type: Projectile
|
||||
damage:
|
||||
groups: # good enough. Maybe make it call the rejuvenate command later.
|
||||
Brute: -900
|
||||
Burn: -900
|
||||
Airloss: -600
|
||||
Toxin: -600
|
||||
types: # good enough. Maybe make it call the rejuvenate command later.
|
||||
Asphyxiation: -200
|
||||
Bloodloss: -200
|
||||
Blunt: -200
|
||||
Caustic: -200
|
||||
Cold: -200
|
||||
Heat: -200
|
||||
Piercing: -200
|
||||
Poison: -200
|
||||
Radiation: -200
|
||||
Shock: -200
|
||||
Slash: -200
|
||||
ignoreResistances: true
|
||||
|
||||
- type: entity
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@
|
|||
params:
|
||||
volume: -3
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Piercing: 5
|
||||
- type: Wieldable
|
||||
- type: IncreaseDamageOnWield
|
||||
damage:
|
||||
groups:
|
||||
Brute: 10
|
||||
types:
|
||||
Piercing: 10
|
||||
Structural: 30
|
||||
- type: Item
|
||||
size: Normal
|
||||
|
|
@ -62,9 +61,8 @@
|
|||
path: "/Audio/Items/drill_hit.ogg"
|
||||
attackRate: 4
|
||||
damage:
|
||||
groups:
|
||||
Brute: 3
|
||||
types:
|
||||
Piercing: 3
|
||||
Structural: 15
|
||||
|
||||
- type: entity
|
||||
|
|
@ -84,9 +82,8 @@
|
|||
path: "/Audio/Items/drill_hit.ogg"
|
||||
attackRate: 4
|
||||
damage:
|
||||
groups:
|
||||
Brute: 6
|
||||
types:
|
||||
Piercing: 6
|
||||
Structural: 30
|
||||
|
||||
|
||||
|
|
@ -132,8 +129,10 @@
|
|||
delay: 0.9
|
||||
- type: LeechOnMarker
|
||||
leech:
|
||||
groups:
|
||||
Brute: -6
|
||||
types:
|
||||
Blunt: -2
|
||||
Slash: -2
|
||||
Piercing: -2
|
||||
- type: Gun
|
||||
soundGunshot: /Audio/Weapons/plasma_cutter.ogg
|
||||
fireRate: 1
|
||||
|
|
@ -238,8 +237,10 @@
|
|||
count: 1
|
||||
- type: LeechOnMarker
|
||||
leech:
|
||||
groups:
|
||||
Brute: -21
|
||||
types:
|
||||
Blunt: -5
|
||||
Piercing: -5
|
||||
Slash: -5
|
||||
- type: Tag
|
||||
tags:
|
||||
- Pickaxe
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@
|
|||
# why does Flammable even have a required damage
|
||||
damage:
|
||||
types:
|
||||
burn: 0
|
||||
Heat: 0
|
||||
considerations:
|
||||
- !type:TargetDistanceCon
|
||||
curve: !type:PresetCurve
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@
|
|||
damage:
|
||||
types:
|
||||
Poison: 0.02
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
reagent: Ethanol
|
||||
|
|
@ -175,8 +175,7 @@
|
|||
- !type:MetabolizerTypeCondition
|
||||
type: [ Dwarf ]
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.1
|
||||
Brute: -0.1
|
||||
- !type:Vomit
|
||||
probability: 0.04
|
||||
conditions:
|
||||
|
|
@ -877,13 +876,12 @@
|
|||
factor: 2
|
||||
- !type:SatiateHunger
|
||||
factor: -2
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Burn: -1
|
||||
Brute: -1
|
||||
Airloss: -1
|
||||
Toxin: -1
|
||||
Burn: -1
|
||||
Brute: -1
|
||||
Airloss: -1
|
||||
Toxin: -1
|
||||
|
||||
- type: reagent
|
||||
id: DriestMartini
|
||||
|
|
|
|||
|
|
@ -29,12 +29,11 @@
|
|||
metabolisms:
|
||||
Metabolites: #This makes it not compete with medicines, a large bonus for something that can heal
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
probability: 0.5
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.5
|
||||
Burn: -0.5
|
||||
Brute: -0.5
|
||||
Burn: -0.5
|
||||
# Helps you stop bleeding to an extent.
|
||||
- !type:ModifyBleed
|
||||
amount: -0.25
|
||||
|
|
@ -58,11 +57,10 @@
|
|||
metabolisms:
|
||||
Metabolites:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
probability: 0.5
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.4
|
||||
Brute: -0.4
|
||||
- !type:ModifyBloodLevel
|
||||
amount: 1 # weaker than iron but pretty good all things considered
|
||||
- !type:SatiateHunger
|
||||
|
|
|
|||
|
|
@ -25,14 +25,13 @@
|
|||
- !type:MetabolizerTypeCondition
|
||||
type: [ Human ]
|
||||
inverted: true
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
- !type:MetabolizerTypeCondition
|
||||
type: [ Bloodsucker ]
|
||||
damage:
|
||||
groups:
|
||||
Brute: -3
|
||||
Burn: -1.25
|
||||
Brute: -3
|
||||
Burn: -1.25
|
||||
Bloodstream: # Don't inject someone else's blood into yourself! Your own blood won't actually metabolise.
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@
|
|||
- !type:ReagentCondition
|
||||
reagent: Ammonia
|
||||
min: 0.25
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
- !type:MetabolizerTypeCondition
|
||||
type: [ Rat ]
|
||||
|
|
@ -259,11 +259,9 @@
|
|||
min: 1
|
||||
ignoreResistances: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: -2.5
|
||||
Burn: -2.5
|
||||
types:
|
||||
Bloodloss: -5
|
||||
Brute: -2.5
|
||||
Burn: -2.5
|
||||
Airloss: -5
|
||||
- !type:ModifyBloodLevel
|
||||
amount: 1
|
||||
conditions:
|
||||
|
|
|
|||
|
|
@ -209,10 +209,9 @@
|
|||
metabolisms:
|
||||
Bloodstream:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Brute: -4
|
||||
Brute: -4
|
||||
- !type:GenericStatusEffect
|
||||
key: Adrenaline
|
||||
component: IgnoreSlowOnDamage
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
reagent: Dylovene
|
||||
min: 20
|
||||
damage:
|
||||
groups:
|
||||
Brute: 2
|
||||
types:
|
||||
Blunt: 2
|
||||
- !type:Jitter
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
@ -133,8 +133,7 @@
|
|||
damage:
|
||||
types:
|
||||
Radiation: -3
|
||||
groups:
|
||||
Brute: 1.5
|
||||
Blunt: 1.5
|
||||
|
||||
- type: reagent
|
||||
id: Bicaridine
|
||||
|
|
@ -246,8 +245,7 @@
|
|||
types:
|
||||
Asphyxiation: 1
|
||||
Cold: 2
|
||||
groups:
|
||||
Brute: 0.5
|
||||
Blunt: 0.5
|
||||
- !type:Jitter
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
@ -344,9 +342,17 @@
|
|||
types:
|
||||
Asphyxiation: -3
|
||||
Poison: -0.5
|
||||
groups:
|
||||
Brute: -0.5
|
||||
Burn: -0.5
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
# they gotta be in crit first
|
||||
- !type:MobStateCondition
|
||||
mobstate: Critical
|
||||
- !type:ReagentCondition
|
||||
reagent: Epinephrine
|
||||
max: 20
|
||||
damage:
|
||||
Brute: -0.5
|
||||
Burn: -0.5
|
||||
- !type:HealthChange
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
@ -626,12 +632,10 @@
|
|||
metabolisms:
|
||||
Bloodstream:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
damage:
|
||||
groups:
|
||||
Brute: -3.5
|
||||
types:
|
||||
Asphyxiation: -2.5
|
||||
Brute: -1.75
|
||||
Airloss: -1
|
||||
- !type:HealthChange
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
@ -812,18 +816,14 @@
|
|||
metabolisms:
|
||||
Bloodstream:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
- !type:TotalDamageCondition
|
||||
max: 50
|
||||
damage:
|
||||
groups:
|
||||
Brute: -1
|
||||
types:
|
||||
Poison: -0.5 ##Should be about what it was when it healed the toxin group
|
||||
Heat: -0.33
|
||||
Shock: -0.33
|
||||
Cold: -0.33
|
||||
Brute: -1
|
||||
Burn: -1
|
||||
Toxin: -0.5
|
||||
|
||||
- type: reagent
|
||||
id: Lipozine
|
||||
|
|
@ -887,8 +887,8 @@
|
|||
min: 0
|
||||
max: 20
|
||||
damage:
|
||||
groups:
|
||||
Brute: 1.5
|
||||
types:
|
||||
Blunt: 1.5
|
||||
- !type:EvenHealthChange
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
@ -902,8 +902,8 @@
|
|||
reagent: Ultravasculine
|
||||
min: 20
|
||||
damage:
|
||||
groups:
|
||||
Brute: 6
|
||||
types:
|
||||
Blunt: 6
|
||||
- !type:AdjustReagent
|
||||
conditions:
|
||||
- !type:ReagentCondition
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
damage:
|
||||
types:
|
||||
Poison: 0.55
|
||||
Blunt: 0.5
|
||||
Blunt: 1.1 # meant to be slightly more than tricordrazine heals
|
||||
# OD
|
||||
- !type:HealthChange
|
||||
conditions:
|
||||
|
|
|
|||
|
|
@ -332,8 +332,9 @@
|
|||
effects:
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
groups:
|
||||
Airloss: 10
|
||||
types:
|
||||
Asphyxiation: 5
|
||||
Bloodloss: 5
|
||||
|
||||
- type: reagent
|
||||
id: MindbreakerToxin
|
||||
|
|
@ -368,8 +369,8 @@
|
|||
- !type:HealthChange
|
||||
probability: 0.1
|
||||
damage:
|
||||
groups:
|
||||
Brute: 2
|
||||
types:
|
||||
Blunt: 2
|
||||
# todo: cough, sneeze
|
||||
- !type:HealthChange
|
||||
conditions:
|
||||
|
|
@ -377,10 +378,9 @@
|
|||
reagent: Histamine
|
||||
min: 45
|
||||
damage:
|
||||
groups:
|
||||
Brute: 2
|
||||
Airloss: 2
|
||||
types:
|
||||
Blunt: 2
|
||||
Asphyxiation: 2
|
||||
Poison: 2
|
||||
- !type:PopupMessage
|
||||
type: Local
|
||||
|
|
@ -660,8 +660,9 @@
|
|||
sprintSpeedModifier: 0.8
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
groups:
|
||||
Airloss: 2
|
||||
types:
|
||||
Asphyxiation: 1
|
||||
Bloodloss: 1
|
||||
|
||||
- type: reagent
|
||||
id: Tazinide
|
||||
|
|
|
|||
|
|
@ -1256,9 +1256,13 @@
|
|||
components:
|
||||
- MobState
|
||||
damage:
|
||||
groups:
|
||||
Brute: -300
|
||||
Burn: -300
|
||||
types:
|
||||
Blunt: -100
|
||||
Piercing: -100
|
||||
Slash: -100
|
||||
Heat: -100
|
||||
Cold: -100
|
||||
Shock: -100
|
||||
|
||||
- type: entity
|
||||
id: XenoArtifactTesla
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue