2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
21 private float fluctuationTimer;
24 private float prevActiveEffectStrength;
35 if (!MathUtils.IsValid(value))
38 DebugConsole.ThrowError($
"Attempted to set an affliction to an invalid strength ({value})\n" + Environment.StackTrace.CleanupStackTrace());
43 if (_nonClampedStrength < 0 && value > 0)
45 _nonClampedStrength = value;
47 float newValue = MathHelper.Clamp(value, 0.0f,
Prefab.MaxStrength);
58 private float _nonClampedStrength = -1;
67 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Explosion damage is applied per each affected limb. Should this affliction damage be divided by the count of affected limbs (1-15) or applied in full? Default: true. Only affects explosions."),
Editable]
92 TextManager.Get(
"AfflictionStrengthLow"),
93 TextManager.Get(
"AfflictionStrengthMedium"),
94 TextManager.Get(
"AfflictionStrengthHigh")
109 foreach (var periodicEffect
in prefab.PeriodicEffects)
111 PeriodicEffectTimers[periodicEffect] = Rand.Range(periodicEffect.MinInterval, periodicEffect.MaxInterval);
134 if (element.GetAttribute(
"amount") !=
null && element.GetAttribute(
"strength") ==
null)
136 Strength = element.GetAttributeFloat(
"amount", 0.0f);
147 public override string ToString() =>
Prefab ==
null ?
"Affliction (Invalid)" : $
"Affliction ({Prefab.Name})";
156 return strengthTexts[
157 MathHelper.Clamp((
int)Math.Floor(strength / maxStrength * strengthTexts.Length), 0, strengthTexts.Length - 1)];
178 if (strength <
Prefab.ActivationThreshold) {
return 0.0f; }
179 strength = MathHelper.Clamp(strength, 0.0f,
Prefab.MaxStrength);
181 if (currentEffect ==
null) {
return 0.0f; }
182 if (currentEffect.MaxStrength - currentEffect.MinStrength <= 0.0f) {
return 0.0f; }
184 float currVitalityDecrease = MathHelper.Lerp(
185 currentEffect.MinVitalityDecrease,
186 currentEffect.MaxVitalityDecrease,
187 currentEffect.GetStrengthFactor(strength));
189 if (currentEffect.MultiplyByMaxVitality)
191 currVitalityDecrease *= characterHealth?.
MaxVitality ?? 100.0f;
194 return currVitalityDecrease;
202 if (currentEffect ==
null) {
return 0.0f; }
203 if (MathUtils.NearlyEqual(currentEffect.MaxGrainStrength, 0f)) {
return 0.0f; }
205 float amount = MathHelper.Lerp(
206 currentEffect.MinGrainStrength,
207 currentEffect.MaxGrainStrength,
208 currentEffect.GetStrengthFactor(
this)) * GetScreenEffectFluctuation(currentEffect);
222 if (currentEffect ==
null) {
return 0.0f; }
223 if (currentEffect.MaxScreenDistort - currentEffect.MinScreenDistort < 0.0f) {
return 0.0f; }
225 return MathHelper.Lerp(
226 currentEffect.MinScreenDistort,
227 currentEffect.MaxScreenDistort,
228 currentEffect.GetStrengthFactor(
this)) * GetScreenEffectFluctuation(currentEffect);
235 if (currentEffect ==
null) {
return 0.0f; }
236 if (currentEffect.MaxRadialDistort - currentEffect.MinRadialDistort < 0.0f) {
return 0.0f; }
238 return MathHelper.Lerp(
239 currentEffect.MinRadialDistort,
240 currentEffect.MaxRadialDistort,
241 currentEffect.GetStrengthFactor(
this)) * GetScreenEffectFluctuation(currentEffect);
248 if (currentEffect ==
null) {
return 0.0f; }
249 if (currentEffect.MaxChromaticAberration - currentEffect.MinChromaticAberration < 0.0f) {
return 0.0f; }
251 return MathHelper.Lerp(
252 currentEffect.MinChromaticAberration,
253 currentEffect.MaxChromaticAberration,
254 currentEffect.GetStrengthFactor(
this)) * GetScreenEffectFluctuation(currentEffect);
263 if (currentEffect ==
null) {
return 0.0f; }
264 if (currentEffect.MaxAfflictionOverlayAlphaMultiplier - currentEffect.MinAfflictionOverlayAlphaMultiplier < 0.0f) {
return 0.0f; }
266 return MathHelper.Lerp(
267 currentEffect.MinAfflictionOverlayAlphaMultiplier,
268 currentEffect.MaxAfflictionOverlayAlphaMultiplier,
269 currentEffect.GetStrengthFactor(
this));
274 if (
Strength <
Prefab.ActivationThreshold) {
return Color.TransparentBlack; }
276 if (currentEffect ==
null) {
return Color.TransparentBlack; }
279 currentEffect.MinFaceTint,
280 currentEffect.MaxFaceTint,
281 currentEffect.GetStrengthFactor(
this));
286 if (
Strength <
Prefab.ActivationThreshold) {
return Color.TransparentBlack; }
288 if (currentEffect ==
null) {
return Color.TransparentBlack; }
291 currentEffect.MinBodyTint,
292 currentEffect.MaxBodyTint,
293 currentEffect.GetStrengthFactor(
this));
300 if (currentEffect ==
null) {
return 0.0f; }
301 if (currentEffect.MaxScreenBlur - currentEffect.MinScreenBlur < 0.0f) {
return 0.0f; }
303 return MathHelper.Lerp(
304 currentEffect.MinScreenBlur,
305 currentEffect.MaxScreenBlur,
306 currentEffect.GetStrengthFactor(
this)) * GetScreenEffectFluctuation(currentEffect);
311 if (currentEffect ==
null || currentEffect.ScreenEffectFluctuationFrequency <= 0.0f) {
return 1.0f; }
312 return ((
float)Math.Sin(fluctuationTimer * MathHelper.TwoPi) + 1.0f) * 0.5f;
319 if (currentEffect ==
null) {
return 1.0f; }
321 float amount = MathHelper.Lerp(
322 currentEffect.MinSkillMultiplier,
323 currentEffect.MaxSkillMultiplier,
324 currentEffect.GetStrengthFactor(
this));
348 if (currentEffect ==
null) {
return 0.0f; }
350 bool hasResistanceForAffliction = currentEffect.ResistanceFor.Any(identifier =>
351 identifier == affliction.Identifier ||
352 identifier == affliction.AfflictionType);
353 if (!hasResistanceForAffliction) {
return 0.0f; }
355 bool hasResistanceForLimb = limbType ==
LimbType.None || currentEffect.ResistanceLimbs.None() || currentEffect.ResistanceLimbs.Contains(limbType);
356 if (!hasResistanceForLimb) {
return 0.0f; }
358 return MathHelper.Lerp(
359 currentEffect.MinResistance,
360 currentEffect.MaxResistance,
361 currentEffect.GetStrengthFactor(
this));
368 if (currentEffect ==
null) {
return 1.0f; }
369 return MathHelper.Lerp(
370 currentEffect.MinSpeedMultiplier,
371 currentEffect.MaxSpeedMultiplier,
372 currentEffect.GetStrengthFactor(
this));
379 if (!currentEffect.AfflictionStatValues.TryGetValue(statType, out var appliedStat)) {
return 0.0f; }
381 return MathHelper.Lerp(appliedStat.MinValue, appliedStat.MaxValue, currentEffect.GetStrengthFactor(
this));
387 return currentEffect.AfflictionAbilityFlags.HasFlag(flagType);
400 if (
Strength <= periodicEffect.MinStrength) {
continue; }
401 if (periodicEffect.MaxStrength > 0 &&
Strength > periodicEffect.MaxStrength) {
continue; }
411 foreach (
StatusEffect statusEffect
in periodicEffect.StatusEffects)
414 PeriodicEffectTimers[periodicEffect] = Rand.Range(periodicEffect.MinInterval, periodicEffect.MaxInterval);
421 if (currentEffect ==
null) {
return; }
423 fluctuationTimer += deltaTime * currentEffect.ScreenEffectFluctuationFrequency;
424 fluctuationTimer %= 1.0f;
426 if (currentEffect.StrengthChange < 0)
433 float durationMultiplier = 1f / (1f + stat);
435 _strength += currentEffect.StrengthChange * deltaTime * StrengthDiminishMultiplier.
Value * durationMultiplier;
437 else if (currentEffect.StrengthChange > 0)
445 foreach (
StatusEffect statusEffect
in currentEffect.StatusEffects)
450 float amount = deltaTime;
451 if (
Prefab.GrainBurst > 0)
453 amount /=
Prefab.GrainBurst;
464 GameMain.
LuaCs.
Hook.
Call(
"afflictionUpdate",
new object[] {
this, characterHealth, targetLimb, deltaTime });
470 if (currentEffect !=
null)
472 foreach (var statusEffect
in currentEffect.StatusEffects)
479 private readonly List<ISerializableEntity> targets =
new List<ISerializableEntity>();
491 statusEffect.
Apply(type, deltaTime, characterHealth.
Character, targetLimb);
502 statusEffect.
Apply(type, deltaTime, characterHealth.
Character, targets);
512 if (!MathUtils.IsValid(strength))
515 DebugConsole.ThrowError($
"Attempted to set an affliction to an invalid strength ({strength})\n" + Environment.StackTrace.CleanupStackTrace());
519 _nonClampedStrength = strength;
override string ToString()
static LocalizedString GetStrengthText(float strength, float maxStrength)
LocalizedString GetStrengthText()
bool ShouldShowIcon(Character afflictedCharacter)
void Deserialize(XElement element)
float GetRadialDistortStrength()
readonly Dictionary< AfflictionPrefab.PeriodicEffect, float > PeriodicEffectTimers
float PreviousVitalityDecrease
float GetChromaticAberrationStrength()
float GetVitalityDecrease(CharacterHealth characterHealth)
void CopyProperties(Affliction source)
Copy properties here instead of using SerializableProperties (with reflection).
bool HasFlag(AbilityFlags flagType)
float GetAfflictionOverlayMultiplier()
float DamagePerSecondTimer
Affliction CreateMultiplied(float multiplier, Affliction affliction)
float GetStatValue(StatTypes statType)
float GetScreenDistortStrength()
void CalculateDamagePerSecond(float currentVitalityDecrease)
AfflictionPrefab.Effect GetActiveEffect()
void SetStrength(float strength)
Use this method to skip clamping and additional logic of the setters. Ideally we would keep this priv...
virtual void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
void Serialize(XElement element)
double AppliedAsSuccessfulTreatmentTime
float GetSpeedMultiplier()
float GetSkillMultiplier()
bool MultiplyByMaxVitality
Dictionary< Identifier, SerializableProperty > SerializableProperties
float GetResistance(Identifier afflictionId, LimbType limbType)
How much resistance to the specified affliction does this affliction currently give?
Character Source
Which character gave this affliction
float PendingGrainEffectStrength
Affliction(AfflictionPrefab prefab, float strength)
float GetScreenBlurStrength()
readonly AfflictionPrefab Prefab
float GetVitalityDecrease(CharacterHealth characterHealth, float strength)
float GrainEffectStrength
void ApplyStatusEffect(ActionType type, StatusEffect statusEffect, float deltaTime, CharacterHealth characterHealth, Limb targetLimb)
void ApplyStatusEffects(ActionType type, float deltaTime, CharacterHealth characterHealth, Limb targetLimb)
float GetScreenGrainStrength()
Effects are the primary way to add functionality to afflictions.
PeriodicEffect applies StatusEffects to the character periodically.
AfflictionPrefab is a prefab that defines a type of affliction that can be applied to a character....
void ReloadSoundsIfNeeded()
readonly float Duration
The duration of the affliction, in seconds. If set to 0, the affliction does not expire.
static readonly PrefabCollection< AfflictionPrefab > Prefabs
readonly Character Character
float GetResistance(AfflictionPrefab afflictionPrefab, LimbType limbType)
How much resistance all the afflictions the character has give to the specified affliction?
float GetStatValue(StatTypes statType, bool includeSaved=true)
static Character? Controlled
readonly AnimController AnimController
virtual Vector2 WorldPosition
static NetworkMember NetworkMember
object Call(string name, params object[] args)
readonly Identifier Identifier
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
static void SerializeProperties(ISerializableEntity obj, XElement element, bool saveIfDefault=false, bool ignoreEditable=false)
StatusEffects can be used to execute various kinds of effects: modifying the state of some entity in ...
bool HasTargetType(TargetType targetType)
void SetUser(Character user)
void AddNearbyTargets(Vector2 worldPosition, List< ISerializableEntity > targets)
bool HasRequiredAfflictions(AttackResult attackResult)
virtual void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition=null)
AbilityFlags
AbilityFlags are a set of toggleable flags that can be applied to characters.
ActionType
ActionTypes define when a StatusEffect is executed.
StatTypes
StatTypes are used to alter several traits of a character. They are mostly used by talents.