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));
345 if (currentEffect ==
null) {
return 0.0f; }
346 if (!currentEffect.ResistanceFor.Any(r =>
347 r == affliction.Identifier ||
348 r == affliction.AfflictionType))
352 return MathHelper.Lerp(
353 currentEffect.MinResistance,
354 currentEffect.MaxResistance,
355 currentEffect.GetStrengthFactor(
this));
362 if (currentEffect ==
null) {
return 1.0f; }
363 return MathHelper.Lerp(
364 currentEffect.MinSpeedMultiplier,
365 currentEffect.MaxSpeedMultiplier,
366 currentEffect.GetStrengthFactor(
this));
373 if (!currentEffect.AfflictionStatValues.TryGetValue(statType, out var appliedStat)) {
return 0.0f; }
375 return MathHelper.Lerp(appliedStat.MinValue, appliedStat.MaxValue, currentEffect.GetStrengthFactor(
this));
381 return currentEffect.AfflictionAbilityFlags.HasFlag(flagType);
394 if (
Strength <= periodicEffect.MinStrength) {
continue; }
395 if (periodicEffect.MaxStrength > 0 &&
Strength > periodicEffect.MaxStrength) {
continue; }
405 foreach (
StatusEffect statusEffect
in periodicEffect.StatusEffects)
408 PeriodicEffectTimers[periodicEffect] = Rand.Range(periodicEffect.MinInterval, periodicEffect.MaxInterval);
415 if (currentEffect ==
null) {
return; }
417 fluctuationTimer += deltaTime * currentEffect.ScreenEffectFluctuationFrequency;
418 fluctuationTimer %= 1.0f;
420 if (currentEffect.StrengthChange < 0)
427 float durationMultiplier = 1f / (1f + stat);
429 _strength += currentEffect.StrengthChange * deltaTime * StrengthDiminishMultiplier.
Value * durationMultiplier;
431 else if (currentEffect.StrengthChange > 0)
439 foreach (
StatusEffect statusEffect
in currentEffect.StatusEffects)
444 float amount = deltaTime;
445 if (
Prefab.GrainBurst > 0)
447 amount /=
Prefab.GrainBurst;
458 GameMain.
LuaCs.
Hook.
Call(
"afflictionUpdate",
new object[] {
this, characterHealth, targetLimb, deltaTime });
464 if (currentEffect !=
null)
466 foreach (var statusEffect
in currentEffect.StatusEffects)
473 private readonly List<ISerializableEntity> targets =
new List<ISerializableEntity>();
485 statusEffect.
Apply(type, deltaTime, characterHealth.
Character, targetLimb);
496 statusEffect.
Apply(type, deltaTime, characterHealth.
Character, targets);
506 if (!MathUtils.IsValid(strength))
509 DebugConsole.ThrowError($
"Attempted to set an affliction to an invalid strength ({strength})\n" + Environment.StackTrace.CleanupStackTrace());
513 _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)
float GetResistance(Identifier afflictionId)
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
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)
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.