4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
7 using System.Collections.Generic;
12 partial class CharacterHealth
14 private static bool toggledThisFrame;
36 private Point screenResolution;
38 private float uiScale, inventoryScale;
43 get {
return alignment; }
46 if (alignment == value) {
return; }
57 private float healthShadowSize;
58 private float healthShadowDelay;
59 private float healthBarPulsateTimer;
60 private float healthBarPulsatePhase;
62 private float bloodParticleTimer;
74 private static readonly Color oxygenLowGrainColor =
new Color(0.1f, 0.1f, 0.1f, 1f);
77 private float limbIndicatorOverlayAnimState;
80 private float medUIExtraAnimState;
82 private int highlightedLimbIndex = -1;
83 private int selectedLimbIndex = -1;
84 private LimbHealth currentDisplayedLimb;
90 private float afflictionIconRefreshTimer;
91 const float AfflictionIconRefreshInterval = 1.0f;
93 private GUIButton showHiddenAfflictionsButton;
106 private GUIListBox recommendedTreatmentContainer;
108 private float distortTimer;
111 private float damageIntensity;
112 private readonly
float damageIntensityDropdownRate = 0.1f;
116 private float updateDisplayedAfflictionsTimer;
117 private const float UpdateDisplayedAfflictionsInterval = 0.5f;
118 private List<Affliction> currentDisplayedAfflictions =
new List<Affliction>();
124 get {
return highlightedLimbIndex > -1; }
132 return openHealthWindow;
136 if (openHealthWindow == value) {
return; }
139 if (!value.UseHealthWindow || value.Character.DisableHealthWindow) {
return; }
142 var prevOpenHealthWindow = openHealthWindow;
144 if (prevOpenHealthWindow !=
null)
146 prevOpenHealthWindow.highlightedLimbIndex = -1;
149 openHealthWindow = value;
150 toggledThisFrame =
true;
161 if (openHealthWindow !=
null)
165 openHealthWindow.characterName.Text = value.Character.Name;
169 openHealthWindow.characterName.Text = value.Character.Info.DisplayName;
170 value.Character.Info.CheckDisguiseStatus(
false);
175 HintManager.OnShowHealthInterface();
181 get {
return cprButton; }
192 get {
return healthBarPulsateTimer; }
193 set { healthBarPulsateTimer = MathHelper.Clamp(value, 0.0f, 10.0f); }
211 var nameContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.2f), healthWindowVerticalLayout.RectTransform) { MinSize = new Point(0, 20) }, isHorizontal:
true)
216 new GUICustomComponent(
new RectTransform(
new Vector2(0.2f, 1.0f), nameContainer.RectTransform,
Anchor.CenterLeft),
217 onDraw: (spriteBatch, component) =>
219 character.Info?.DrawPortrait(spriteBatch, new Vector2(component.Rect.X, component.Rect.Center.Y - component.Rect.Width / 2), Vector2.Zero, component.Rect.Width, false, character != Character.Controlled);
221 characterName =
new GUITextBlock(
new RectTransform(
new Vector2(0.6f, 1.0f), nameContainer.RectTransform),
"", textAlignment:
Alignment.CenterLeft, font: GUIStyle.SubHeadingFont)
223 AutoScaleHorizontal =
true
225 new GUICustomComponent(
new RectTransform(
new Vector2(0.2f, 1.0f), nameContainer.RectTransform),
226 onDraw: (spriteBatch, component) =>
228 character.Info?.DrawJobIcon(spriteBatch, component.Rect, character != Character.Controlled);
232 var healthBarContainer =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.07f), healthWindowVerticalLayout.RectTransform), style:
null);
233 var healthBarIcon =
new GUIFrame(
new RectTransform(
new Vector2(0.095f, 1.0f), healthBarContainer.RectTransform), style:
"GUIHealthBarIcon");
234 healthWindowHealthBarShadow =
new GUIProgressBar(
new RectTransform(
new Vector2(0.91f, 1.0f), healthBarContainer.RectTransform,
Anchor.CenterRight),
235 barSize: 1.0f, color: GUIStyle.Green, style:
"GUIHealthBar")
239 healthWindowHealthBar =
new GUIProgressBar(
new RectTransform(
new Vector2(0.91f, 1.0f), healthBarContainer.RectTransform,
Anchor.CenterRight),
240 barSize: 1.0f, color: GUIStyle.Green, style:
"GUIHealthBar")
246 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.05f), healthWindowVerticalLayout.RectTransform), style:
null);
248 var characterIndicatorArea =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.95f), healthWindowVerticalLayout.RectTransform), isHorizontal:
true)
254 InventorySlotContainer =
new GUICustomComponent(
new RectTransform(
new Vector2(0.1f, 1.0f), characterIndicatorArea.RectTransform,
Anchor.TopLeft,
Pivot.TopRight),
255 (spriteBatch, component) =>
257 for (int i = 0; i < character.Inventory.Capacity; i++)
259 if (character.Inventory.SlotTypes[i] != InvSlotType.HealthInterface) { continue; }
260 if (character.Inventory.HideSlot(i)) { continue; }
263 bool drawItem = !Inventory.DraggingItems.Any() || !Character.Inventory.GetItemsAt(i).All(it => Inventory.DraggingItems.Contains(it)) || character.Inventory.visualSlots[i].MouseOn();
265 Inventory.DrawSlot(spriteBatch, Character.Inventory, Character.Inventory.visualSlots[i], Character.Inventory.GetItemAt(i), i, drawItem, Character.Inventory.SlotTypes[i]);
267 if (medUIExtra != null)
269 float overlayScale = Math.Min(
270 Character.Inventory.visualSlots[i].Rect.Width / (float)medUIExtra.FrameSize.X,
271 Character.Inventory.visualSlots[i].Rect.Height / (float)medUIExtra.FrameSize.Y);
273 int frame = (int)medUIExtraAnimState;
275 medUIExtra.Draw(spriteBatch, frame, Character.Inventory.visualSlots[i].Rect.Center.ToVector2(), Color.Gray, origin: medUIExtra.FrameSize.ToVector2() / 2, rotate: 0.0f,
276 scale: Vector2.One * overlayScale);
282 if (!GameMain.Instance.Paused)
284 medUIExtraAnimState = (medUIExtraAnimState + dt * 10.0f) % 16.0f;
289 cprButton =
new GUIButton(
new RectTransform(
new Vector2(0.17f, 0.17f), characterIndicatorArea.RectTransform,
Anchor.BottomLeft, scaleBasis:
ScaleBasis.Smallest), text:
"", style:
"CPRButton")
292 OnClicked = (button, userData) =>
295 if (selectedCharacter ==
null || (!selectedCharacter.IsUnconscious && selectedCharacter.Stun <= 0.0f))
301 AnimController.Animation.None : AnimController.Animation.CPR;
303 selectedCharacter.AnimController.ResetPullJoints();
305 if (GameMain.Client !=
null)
312 ToolTip = TextManager.Get(
"doctor.cprobjective"),
313 IgnoreLayoutGroups =
true,
317 var limbSelection =
new GUICustomComponent(
new RectTransform(
new Vector2(0.4f, 1.0f), characterIndicatorArea.RectTransform),
318 (spriteBatch, component) =>
320 DrawHealthWindow(spriteBatch, component.RectTransform.Rect, true);
322 (deltaTime, component) =>
324 UpdateLimbIndicators(deltaTime, component.RectTransform.Rect);
327 deadIndicator =
new GUITextBlock(
new RectTransform(
new Vector2(0.9f, 0.1f), limbSelection.RectTransform,
Anchor.Center),
328 text: TextManager.Get(
"Deceased"), font: GUIStyle.LargeFont, textAlignment:
Alignment.Center, style:
"GUIToolTip")
335 deadIndicator.
Wrap =
true;
342 afflictionIconList =
new GUIListBox(
new RectTransform(
new Vector2(0.25f, 1.0f), characterIndicatorArea.RectTransform), style:
null);
344 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.1f), healthWindowVerticalLayout.RectTransform),
345 TextManager.Get(
"SuitableTreatments"), font: GUIStyle.SubHeadingFont, textAlignment:
Alignment.BottomCenter);
347 treatmentLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.15f), healthWindowVerticalLayout.RectTransform),
true)
352 recommendedTreatmentContainer =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 1.0f), treatmentLayout.
RectTransform,
Anchor.Center,
Pivot.Center), isHorizontal:
true, style:
null)
354 Spacing = GUI.IntScale(4),
355 KeepSpaceForScrollBar =
false,
356 ScrollBarVisible =
false,
357 AutoHideScrollBar =
false
359 new GUITextBlock(
new RectTransform(Vector2.One, recommendedTreatmentContainer.
Content.
RectTransform), TextManager.Get(
"none"), textAlignment:
Alignment.Center)
364 characterIndicatorArea.Recalculate();
366 healthBarHolder =
new GUIFrame(
new RectTransform(Point.Zero, GUI.Canvas), style:
null)
375 healthBarShadow =
new GUIProgressBar(
new RectTransform(Vector2.One, healthBarHolder.
RectTransform,
Anchor.BottomRight),
376 barSize: 1.0f, color: Color.Green, style:
"CharacterHealthBar", showFrame:
false)
380 healthShadowSize = 1.0f;
382 healthBar =
new GUIProgressBar(
new RectTransform(Vector2.One, healthBarHolder.
RectTransform,
Anchor.BottomRight),
383 barSize: 1.0f, color: GUIStyle.HealthBarColorHigh, style:
"CharacterHealthBar")
386 ToolTip = TextManager.GetWithVariable(
"hudbutton.healthinterface",
"[key]", GameSettings.CurrentConfig.KeyMap.KeyBindText(
InputType.Health)),
390 afflictionIconContainer =
new GUILayoutGroup(
391 HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAfflictionArea, GUI.Canvas),
392 isHorizontal:
true, childAnchor:
Anchor.CenterRight)
394 AbsoluteSpacing = GUI.IntScale(5)
397 showHiddenAfflictionsButton =
new GUIButton(
new RectTransform(
new Point(afflictionIconContainer.
Rect.Height), afflictionIconContainer.
RectTransform), style:
"GUIButtonCircular")
403 hiddenAfflictionIconContainer =
new GUILayoutGroup(
404 HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAfflictionArea, GUI.Canvas),
405 isHorizontal:
true, childAnchor:
Anchor.CenterRight)
407 AbsoluteSpacing = GUI.IntScale(5)
412 SuicideButton =
new GUIButton(
new RectTransform(
new Vector2(0.1f, 0.02f), GUI.Canvas,
Anchor.TopCenter)
414 MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f)
416 TextManager.Get(
"GiveInButton"), style:
"GUIButtonLarge")
419 ToolTip = TextManager.Get(GameMain.NetworkMember ==
null ?
"GiveInHelpSingleplayer" :
"GiveInHelpMultiplayer"),
420 OnClicked = (button, userData) =>
422 GUI.ForceMouseOn(
null);
425 if (GameMain.Client !=
null)
431 var (
type, affliction) = GetCauseOfDeath();
443 foreach (var subElement
in element.
Elements())
445 switch (subElement.Name.ToString().ToLowerInvariant())
448 case "meduisilhouette":
449 limbIndicatorOverlay =
new SpriteSheet(subElement);
452 medUIExtra =
new SpriteSheet(subElement);
458 healthWindowVerticalLayout.Recalculate();
461 private void OnAttacked(Character attacker, AttackResult attackResult)
463 if (Math.Abs(attackResult.Damage) < 0.01f) {
return; }
464 DamageOverlayTimer = MathHelper.Clamp(attackResult.Damage / MaxVitality, DamageOverlayTimer, 1.0f);
465 if (healthShadowDelay <= 0.0f) { healthShadowDelay = 1.0f; }
467 if (healthBarPulsateTimer <= 0.0f) { healthBarPulsatePhase = 0.0f; }
468 healthBarPulsateTimer = 1.0f;
470 float additionalIntensity = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, 0.1f, attackResult.Damage / MaxVitality));
471 damageIntensity = MathHelper.Clamp(damageIntensity + additionalIntensity, 0, 1);
473 DisplayVitalityDelay = 0.5f;
476 private void UpdateAlignment()
478 screenResolution =
new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
479 inventoryScale = Inventory.UIScale;
484 for (
int i = afflictionIconContainer.
CountChildren - 1; i >= 0; i--)
486 var child = afflictionIconContainer.
GetChild(i);
487 if (child.UserData is AfflictionPrefab)
501 healthWindow.
RectTransform.
AbsoluteOffset =
new Point(HUDLayoutSettings.InventoryAreaLower.X, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
503 case Alignment.Right:
505 healthWindow.
RectTransform.
AbsoluteOffset =
new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
511 Character.Inventory?.RefreshSlotPositions();
518 DisplayedVitality = Vitality;
522 DisplayVitalityDelay -= deltaTime;
523 if (DisplayVitalityDelay <= 0.0f)
525 DisplayedVitality = Vitality;
529 if (damageIntensity > 0)
531 damageIntensity -= deltaTime * damageIntensityDropdownRate;
532 if (damageIntensity < 0)
537 if (DamageOverlayTimer > 0.0f)
539 DamageOverlayTimer -= deltaTime;
543 private float timeUntilNextHeartbeatSound = 0.0f;
544 private bool nextHeartbeatSoundIsSystole =
true;
545 private const string diastoleSoundTag =
"heartbeatdiastole", systoleSoundTag =
"heartbeatsystole";
547 partial
void UpdateOxygenProjSpecific(
float prevOxygen,
float deltaTime)
558 var charInfoPrefab = CharacterPrefab.HumanPrefab.CharacterInfoPrefab;
559 soundName = charInfoPrefab.ReplaceVars($
"drown[{charInfoPrefab.MenuCategoryVar}]", charInfoPrefab.Heads.First());
561 SoundPlayer.PlaySound(soundName);
564 if (Character ==
Character.Controlled && !IsUnconscious && !
Character.IsDead && OxygenAmount < LowOxygenThreshold)
566 timeUntilNextHeartbeatSound -= deltaTime;
567 if (timeUntilNextHeartbeatSound < 0.0f)
569 if (nextHeartbeatSoundIsSystole)
571 SoundPlayer.PlaySound(systoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
572 timeUntilNextHeartbeatSound = MathHelper.Lerp(0.18f, 0.3f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
576 SoundPlayer.PlaySound(diastoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
577 timeUntilNextHeartbeatSound = MathHelper.Lerp(0.3f, 0.5f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
579 nextHeartbeatSoundIsSystole = !nextHeartbeatSoundIsSystole;
584 partial
void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb,
float deltaTime)
586 if (
Character.InvisibleTimer > 0.0f) {
return; }
588 bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
589 if (bloodParticleTimer <= 0.0f)
591 Limb limb = targetLimb ??
Character.AnimController.MainLimb;
593 bool inWater =
Character.AnimController.InWater;
594 var drawTarget = inWater ? Particles.ParticlePrefab.DrawTargetType.Water : Particles.ParticlePrefab.DrawTargetType.Air;
595 var emitter =
Character.BloodEmitters.FirstOrDefault(e => e.Prefab.ParticlePrefab?.DrawTarget == drawTarget || e.Prefab.ParticlePrefab?.DrawTarget == Particles.ParticlePrefab.DrawTargetType.Both);
596 float particleMinScale = emitter?.Prefab.Properties.ScaleMin ?? 0.5f;
597 float particleMaxScale = emitter?.Prefab.Properties.ScaleMax ?? 1;
598 float severity = Math.Min(affliction.Strength / affliction.Prefab.MaxStrength *
Character.Params.BleedParticleMultiplier, 1);
599 float bloodParticleSize = MathHelper.Lerp(particleMinScale, particleMaxScale, severity);
601 Vector2 velocity = Rand.Vector(affliction.Strength * 0.1f);
604 bloodParticleSize *= 2.0f;
605 velocity = limb.LinearVelocity * 100.0f;
609 var blood = GameMain.ParticleManager.CreateParticle(
611 limb.WorldPosition, velocity, 0.0f,
Character.AnimController.CurrentHull);
615 blood.Size *= bloodParticleSize;
616 if (!inWater && !
string.IsNullOrEmpty(
Character.BloodDecalName) && Rand.Range(0.0f, 1.0f) < 0.05f)
618 blood.OnCollision += (Vector2 pos, Hull hull) =>
620 var decal = hull?.AddDecal(
Character.BloodDecalName, pos, Rand.Range(1.0f, 2.0f), isNetworkEvent:
true);
623 decal.FadeTimer = decal.LifeTime - decal.FadeOutTime * 2;
628 bloodParticleTimer = MathHelper.Lerp(2, 0.5f, severity);
640 if (GUI.DisableHUD) {
return; }
641 if (openHealthWindow !=
null)
645 openHealthWindow =
null;
650 bool forceAfflictionContainerUpdate =
false;
651 if (updateDisplayedAfflictionsTimer > 0.0f)
653 updateDisplayedAfflictionsTimer -= deltaTime;
657 forceAfflictionContainerUpdate =
true;
658 currentDisplayedAfflictions = GetAllAfflictions(mergeSameAfflictions:
true, predicate: a => a.ShouldShowIcon(
Character) && a.Prefab.Icon !=
null);
659 currentDisplayedAfflictions.Sort((a1, a2) =>
661 int dmgPerSecond = Math.Sign(a1.DamagePerSecond - a2.DamagePerSecond);
662 if (dmgPerSecond != 0) {
return dmgPerSecond; }
663 return Math.Sign(GetStr(a1) - GetStr(a2));
669 HintManager.OnAfflictionDisplayed(
Character, currentDisplayedAfflictions);
670 updateDisplayedAfflictionsTimer = UpdateDisplayedAfflictionsInterval;
673 if (healthShadowDelay > 0.0f)
675 healthShadowDelay -= deltaTime;
679 healthShadowSize = healthBar.
BarSize > healthShadowSize ?
680 Math.Min(healthShadowSize + deltaTime, healthBar.
BarSize) :
681 Math.Max(healthShadowSize - deltaTime, healthBar.
BarSize);
684 float blurStrength = 0.0f;
685 float distortStrength = 0.0f;
686 float distortSpeed = 0.0f;
687 float radialDistortStrength = 0.0f;
688 float chromaticAberrationStrength = 0.0f;
689 float grainStrength = 0.0f;
690 Color grainColor = Color.Transparent;
692 float oxygenLowStrength = 0.0f;
698 else if (OxygenAmount < 100.0f)
700 oxygenLowStrength = Math.Min(1.0f - (OxygenAmount - LowOxygenThreshold) / LowOxygenThreshold, 1.0f);
701 blurStrength = MathHelper.Lerp(0.5f, 1.0f, 1.0f - Vitality / MaxVitality) * oxygenLowStrength;
702 distortStrength = blurStrength * oxygenLowStrength;
703 distortSpeed = blurStrength + 1.0f;
704 distortSpeed *= distortSpeed * distortSpeed * distortSpeed;
706 grainStrength = MathHelper.Lerp(0.5f, 10.0f, oxygenLowStrength);
707 grainColor = oxygenLowGrainColor;
710 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
712 var affliction = kvp.Key;
713 distortStrength = Math.Max(distortStrength, affliction.GetScreenDistortStrength());
714 blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
715 radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
716 chromaticAberrationStrength = Math.Max(chromaticAberrationStrength, affliction.GetChromaticAberrationStrength());
718 float afflictionGrainStrength = affliction.GetScreenGrainStrength();
719 if (afflictionGrainStrength > 0.0f)
721 grainStrength = Math.Max(grainStrength, afflictionGrainStrength);
722 Color afflictionGrainColor = affliction.GetActiveEffect()?.GrainColor ?? Color.White;
723 grainColor = Color.Lerp(grainColor, afflictionGrainColor, (
float)Math.Pow(1.0f - oxygenLowStrength, 2));
731 if (blurStrength > 0.0f)
733 distortTimer = (distortTimer + deltaTime * distortSpeed) % MathHelper.TwoPi;
744 UpdateStatusHUD(deltaTime);
749 if (openHealthWindow !=
null)
751 OpenHealthWindow =
null;
756 OpenHealthWindow =
this;
757 forceAfflictionContainerUpdate =
true;
760 else if (openHealthWindow ==
this)
762 if (HUD.CloseHUD(healthWindow.
Rect))
769 OpenHealthWindow =
null;
775 if (affliction.AppliedAsFailedTreatmentTime > Timing.TotalTime - 1.0 && afflictionIcon.
FlashTimer <= 0.0f)
777 afflictionIcon.
Flash(GUIStyle.Red);
779 else if (affliction.AppliedAsSuccessfulTreatmentTime > Timing.TotalTime - 1.0 && afflictionIcon.
FlashTimer <= 0.0f)
781 afflictionIcon.
Flash(GUIStyle.Green);
789 if (afflictionTooltip ==
null || afflictionTooltip.
UserData != affliction)
793 UserData = affliction,
797 CreateAfflictionInfoElements(afflictionTooltip.
Content, affliction);
799 int height = afflictionTooltip.
Content.
Children.Sum(c => c.Rect.Height) + 10;
801 if (Alignment == Alignment.Right)
816 labelContainer.
RectTransform.
Resize(
new Point(labelContainer.Rect.Width, (
int)(GUIStyle.LargeFont.Size * 1.5f)));
821 afflictionTooltip =
null;
824 toggledThisFrame =
false;
826 if (OpenHealthWindow ==
this)
828 var highlightedLimb = highlightedLimbIndex < 0 ? null : limbHealths[highlightedLimbIndex];
829 if (highlightedLimbIndex < 0 && selectedLimbIndex < 0)
832 var affliction = SortAfflictionsBySeverity(GetAllAfflictions(a => a.Prefab.IndicatorLimb !=
LimbType.None)).FirstOrDefault();
833 if (affliction !=
null && (affliction.DamagePerSecond > 0 || affliction.Strength > 0))
835 var limbHealth = GetMatchingLimbHealth(affliction);
836 if (limbHealth !=
null)
838 selectedLimbIndex = limbHealths.IndexOf(limbHealth);
844 var limbHealth = limbHealths.OrderByDescending(l => GetTotalDamage(l)).FirstOrDefault();
845 selectedLimbIndex = limbHealths.IndexOf(limbHealth);
848 LimbHealth selectedLimb = selectedLimbIndex < 0 ? highlightedLimb : limbHealths[selectedLimbIndex];
849 if (selectedLimb != currentDisplayedLimb || forceAfflictionContainerUpdate)
851 UpdateAfflictionContainer(selectedLimb);
852 currentDisplayedLimb = selectedLimb;
855 UpdateAfflictionInfos(displayedAfflictions.Select(d => d.affliction));
860 if (treatmentButton?.UserData is not
ItemPrefab itemPrefab) {
continue; }
862 treatmentButton.Enabled = matchingItem !=
null;
866 var rootContainer = matchingItem.
RootContainer ?? matchingItem;
874 if (matchingItem !=
null && !treatmentButton.ToolTip.IsNullOrEmpty()) {
continue; }
875 treatmentButton.ToolTip =
RichString.
Rich($
"‖color:255,255,255,255‖{itemPrefab.Name}‖color:end‖" +
'\n' + itemPrefab.Description);
876 if (treatmentButton.Enabled)
878 treatmentButton.ToolTip =
880 $
"‖color:gui.green‖[{PlayerInput.PrimaryMouseLabel}] "
881 + $
"{TextManager.Get("quickuseaction.usetreatment
")}‖color:end‖" +
'\n'
882 + treatmentButton.ToolTip.NestedStr);
886 child.
Enabled = treatmentButton.Enabled;
893 healthBar.
Color = healthWindowHealthBar.
Color = Color.Black;
898 healthBar.
Color = healthWindowHealthBar.
Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, GUIStyle.HealthBarColorLow, GUIStyle.HealthBarColorMedium, GUIStyle.HealthBarColorHigh);
901 (DisplayedVitality > 0.0f) ?
902 (MaxVitality > 0.0f ? DisplayedVitality / MaxVitality : 0.0f) :
903 (Math.Abs(MinVitality) > 0.0f ? 1.0f - DisplayedVitality / MinVitality : 0.0f);
905 if (healthBarPulsateTimer > 0.0f)
908 float pulsateAmount = (float)(Math.Sin(healthBarPulsatePhase) + 1.0f) / 2.0f;
911 healthBarPulsatePhase += deltaTime * 5.0f;
912 healthBarPulsateTimer -= deltaTime;
920 if (OpenHealthWindow ==
this)
924 openHealthWindow =
null;
929 if (highlightedLimbIndex > -1)
931 selectedLimbIndex = highlightedLimbIndex;
939 openHealthWindow =
null;
941 highlightedLimbIndex = -1;
951 OpenHealthWindow = openHealthWindow ==
this ? null :
this;
965 if (endRoundButton !=
null)
967 if (SuicideButton.Visible)
969 Point offset =
new Point(0, SuicideButton.Rect.Height);
976 if (readyCheckButton !=
null)
987 && openHealthWindow ==
this;
998 if (GUI.DisableHUD) {
return; }
999 if (OpenHealthWindow ==
this)
1008 if (hiddenAfflictionIconContainer.
Visible)
1015 SuicideButton.AddToGUIUpdateList();
1017 if (cprButton !=
null && cprButton.Visible)
1019 cprButton.AddToGUIUpdateList();
1029 Math.Abs(uiScale - GUI.Scale) > 0.01f)
1034 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
1036 var affliction = kvp.Key;
1037 affliction.Prefab.AfflictionOverlay?.Draw(spriteBatch, Vector2.Zero, Color.White * affliction.GetAfflictionOverlayMultiplier(), Vector2.Zero, 0.0f,
1041 float damageOverlayAlpha = DamageOverlayTimer;
1042 if (Vitality < MaxVitality * 0.1f)
1044 damageOverlayAlpha = Math.Max(1.0f - (Vitality / UnmodifiedMaxVitality * 10.0f), damageOverlayAlpha);
1048 float pulsateAmount = (float)(Math.Sin(healthBarPulsatePhase) + 1.0f) / 2.0f;
1049 damageOverlayAlpha = pulsateAmount * healthBarPulsateTimer * damageIntensity;
1052 if (damageOverlayAlpha > 0.0f)
1054 DamageOverlay?.
Draw(spriteBatch, Vector2.Zero, Color.White * damageOverlayAlpha, Vector2.Zero, 0.0f,
1063 if (healthBarHolder !=
null)
1072 private readonly List<Affliction> statusIcons =
new List<Affliction>();
1073 private readonly Dictionary<AfflictionPrefab, float> statusIconVisibleTime =
new Dictionary<AfflictionPrefab, float>();
1074 private const float HideStatusIconDelay = 5.0f;
1080 statusIcons.Clear();
1083 statusIcons.Add(pressureAffliction);
1087 statusIcons.Add(oxygenLowAffliction);
1090 foreach (
Affliction affliction
in currentDisplayedAfflictions)
1092 statusIcons.Add(affliction);
1095 int spacing = GUI.IntScale(10);
1100 hiddenAfflictionIconContainer.
RectTransform.
ScreenSpaceOffset =
new Point(0, -hiddenAfflictionIconContainer.
Rect.Height - spacing + HUDLayoutSettings.PortraitArea.Height);
1109 RemoveNonExistentIcons(afflictionIconContainer);
1110 RemoveNonExistentIcons(hiddenAfflictionIconContainer);
1117 if (!statusIcons.Any(s => s.Prefab == afflictionPrefab))
1120 statusIconVisibleTime.Remove(afflictionPrefab);
1125 foreach (var statusIcon
in statusIcons)
1130 if (!statusIconVisibleTime.ContainsKey(afflictionPrefab)) { statusIconVisibleTime.Add(afflictionPrefab, 0.0f); }
1131 statusIconVisibleTime[afflictionPrefab] += deltaTime;
1136 if (matchingIcon ==
null)
1140 UserData = afflictionPrefab,
1142 CanBeSelected =
false
1144 if (affliction == pressureAffliction)
1146 matchingIcon.ToolTip = TextManager.Get(
"PressureHUDWarning");
1148 else if (affliction == pressureAffliction)
1150 matchingIcon.ToolTip = TextManager.Get(
"OxygenHUDWarning");
1154 CanBeFocused =
false
1157 if (afflictionPrefab.
HideIconAfterDelay && statusIconVisibleTime[afflictionPrefab] > HideStatusIconDelay)
1162 image.
Color = GetAfflictionIconColor(afflictionPrefab, affliction);
1163 image.HoverColor = Color.Lerp(image.Color, Color.White, 0.5f);
1165 if (affliction.
DamagePerSecond > 1.0f && matchingIcon.FlashTimer <= 0.0f)
1167 matchingIcon.Flash(useCircularFlash:
true, flashDuration: 1.5f, flashRectInflate: Vector2.One * 15.0f * GUI.Scale);
1168 image.Pulsate(Vector2.One, Vector2.One * 1.2f, 1.0f);
1172 afflictionIconRefreshTimer -= deltaTime;
1173 if (afflictionIconRefreshTimer <= 0.0f)
1177 if (r1.GUIComponent.UserData is not
AfflictionPrefab prefab1) { return -1; }
1178 if (r2.GUIComponent.UserData is not
AfflictionPrefab prefab2) { return 1; }
1179 var index1 = statusIcons.IndexOf(s => s.Prefab == prefab1);
1180 var index2 = statusIcons.IndexOf(s => s.Prefab == prefab2);
1181 return index1.CompareTo(index2);
1183 (afflictionIconContainer as
GUILayoutGroup).NeedsToRecalculate =
true;
1184 afflictionIconRefreshTimer = AfflictionIconRefreshInterval;
1187 Rectangle hiddenAfflictionHoverArea = showHiddenAfflictionsButton.
Rect;
1190 hiddenAfflictionHoverArea =
Rectangle.Union(hiddenAfflictionHoverArea, child.
Rect);
1193 afflictionIconContainer.
Visible =
true;
1194 hiddenAfflictionIconContainer.
Visible =
1199 showHiddenAfflictionsButton.
Text = $
"+{hiddenAfflictionIconContainer.CountChildren}";
1201 if (Vitality > 0.0f)
1203 float currHealth = healthBar.
BarSize;
1204 Color prevColor = healthBar.
Color;
1205 healthBarShadow.
BarSize = healthShadowSize;
1206 healthBarShadow.
Color = Color.Lerp(GUIStyle.Red, Color.Black, 0.5f);
1207 healthBarShadow.
Visible =
true;
1208 healthBar.
BarSize = currHealth;
1209 healthBar.
Color = prevColor;
1213 healthBarShadow.
Visible =
false;
1218 afflictionIconContainer.
Visible = hiddenAfflictionIconContainer.
Visible =
false;
1219 if (Vitality > 0.0f)
1221 float currHealth = healthWindowHealthBar.
BarSize;
1222 Color prevColor = healthWindowHealthBar.
Color;
1223 healthWindowHealthBarShadow.
BarSize = healthShadowSize;
1224 healthWindowHealthBarShadow.
Color = GUIStyle.Red;
1225 healthWindowHealthBarShadow.
Visible =
true;
1226 healthWindowHealthBar.
BarSize = currHealth;
1227 healthWindowHealthBar.
Color = prevColor;
1231 healthWindowHealthBarShadow.
Visible =
false;
1238 return GetAfflictionIconColor(prefab, affliction.
Strength);
1245 float colorT = MathF.Sqrt(afflictionStrength / prefab.
MaxStrength);
1251 return ToolBox.GradientLerp(colorT, GUIStyle.BuffColorLow, GUIStyle.BuffColorMedium, GUIStyle.BuffColorHigh);
1254 return ToolBox.GradientLerp(colorT, GUIStyle.DebuffColorLow, GUIStyle.DebuffColorMedium, GUIStyle.DebuffColorHigh);
1256 return ToolBox.GradientLerp(colorT, prefab.
IconColors);
1261 private readonly List<(
Affliction affliction,
float strength)> displayedAfflictions =
new List<(
Affliction affliction,
float strength)>();
1263 private void UpdateAfflictionContainer(
LimbHealth selectedLimb)
1265 if (selectedLimb ==
null)
1271 if (afflictionsDirty() || selectedLimb != currentDisplayedLimb)
1273 var currentAfflictions = afflictions.Where(a => ShouldDisplayAfflictionOnLimb(a, selectedLimb)).Select(a => a.Key);
1274 CreateAfflictionInfos(currentAfflictions);
1275 CreateRecommendedTreatments();
1278 else if (displayedAfflictions.Any(d => Math.Abs(d.strength - d.affliction.Strength) > 1.0f))
1280 CreateRecommendedTreatments();
1283 bool afflictionsDirty()
1286 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
1288 if (!ShouldDisplayAfflictionOnLimb(kvp, selectedLimb)) {
continue; }
1289 if (!displayedAfflictions.Any(d => d.affliction == kvp.Key)) {
return true; }
1292 foreach ((Affliction affliction,
float strength) in displayedAfflictions)
1294 if (afflictions.None(a => a.Key == affliction && a.Key.ShouldShowIcon(Character))) {
return true; }
1300 private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
1303 displayedAfflictions.Clear();
1305 Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions, excludeBuffs:
false).FirstOrDefault();
1306 GUIButton buttonToSelect =
null;
1308 foreach (Affliction affliction
in afflictions)
1310 displayedAfflictions.Add((affliction, affliction.Strength));
1312 var frame =
new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.25f), afflictionIconList.
Content.
RectTransform), style:
"ListBoxElement")
1314 UserData = affliction,
1315 OnClicked = SelectAffliction
1318 new GUIFrame(
new RectTransform(Vector2.One, frame.RectTransform), style:
"GUIFrameListBox") { CanBeFocused =
false };
1320 var content =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.9f, 0.85f), frame.RectTransform,
Anchor.Center), childAnchor:
Anchor.TopCenter)
1323 CanBeFocused =
false
1326 var progressbarBg =
new GUIProgressBar(
new RectTransform(
new Vector2(1.0f, 0.18f), content.RectTransform), 0.0f, GUIStyle.Green, style:
"GUIAfflictionBar")
1328 UserData =
"afflictionstrengthprediction",
1329 CanBeFocused =
false
1331 new GUIProgressBar(
new RectTransform(Vector2.One, progressbarBg.RectTransform), 0.0f, Color.Transparent, showFrame:
false, style:
"GUIAfflictionBar")
1333 UserData =
"afflictionstrength",
1334 CanBeFocused =
false
1338 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.15f), content.RectTransform), style:
null) { CanBeFocused =
false };
1340 if (affliction == mostSevereAffliction)
1342 buttonToSelect = frame;
1345 var afflictionIcon =
new GUIImage(
new RectTransform(Vector2.One * 0.8f, content.RectTransform), affliction.Prefab.Icon, scaleToFit:
true)
1347 Color = GetAfflictionIconColor(affliction),
1348 CanBeFocused =
false
1350 afflictionIcon.PressedColor = afflictionIcon.Color;
1351 afflictionIcon.HoverColor = Color.Lerp(afflictionIcon.Color, Color.White, 0.6f);
1352 afflictionIcon.SelectedColor = Color.Lerp(afflictionIcon.Color, Color.White, 0.5f);
1354 var nameText =
new GUITextBlock(
new RectTransform(
new Vector2(1.1f, 0.0f), content.RectTransform),
1355 affliction.Prefab.Name, font: GUIStyle.SmallFont, textAlignment: Alignment.BottomCenter)
1357 CanBeFocused =
false
1359 nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, nameText.Rect.Width);
1360 nameText.RectTransform.MinSize =
new Point(0, (
int)(nameText.TextSize.Y));
1361 nameText.RectTransform.SizeChanged += () =>
1363 nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, nameText.Rect.Width);
1366 content.Recalculate();
1369 buttonToSelect?.OnClicked(buttonToSelect, buttonToSelect.UserData);
1373 private void CreateRecommendedTreatments()
1375 ItemPrefab prevHighlightedItem =
null;
1376 if (GUI.MouseOn?.UserData is ItemPrefab && recommendedTreatmentContainer.
Content.
IsParentOf(GUI.MouseOn))
1378 prevHighlightedItem = (ItemPrefab)GUI.MouseOn.UserData;
1383 float characterSkillLevel =
Character.Controlled ==
null ? 0.0f :
Character.Controlled.GetSkillLevel(
"medical");
1387 Dictionary<Identifier, float> treatmentSuitability =
new Dictionary<Identifier, float>();
1388 GetSuitableTreatments(treatmentSuitability,
1390 ignoreHiddenAfflictions:
true,
1391 limb: selectedLimbIndex == -1 ?
null :
Character.AnimController.Limbs.Find(l => l.HealthIndex == selectedLimbIndex));
1393 foreach (Identifier treatment
in treatmentSuitability.Keys.ToList())
1396 if (
Character.Controlled.Inventory.FindItemByIdentifier(treatment, recursive:
true) !=
null)
1398 treatmentSuitability[treatment] *= 10.0f;
1402 if (!treatmentSuitability.Any())
1404 new GUITextBlock(
new RectTransform(Vector2.One, recommendedTreatmentContainer.
Content.
RectTransform), TextManager.Get(
"none"), textAlignment: Alignment.Center)
1406 CanBeFocused =
false
1417 List<KeyValuePair<Identifier, float>> treatmentSuitabilities = treatmentSuitability.OrderByDescending(t => t.Value).ToList();
1420 foreach (KeyValuePair<Identifier, float> treatment
in treatmentSuitabilities)
1423 if (treatment.Value < 0) {
continue; }
1426 if (count > 5) {
break; }
1427 if (MapEntityPrefab.FindByIdentifier(treatment.Key) is not ItemPrefab item) {
continue; }
1429 var itemSlot =
new GUIFrame(
new RectTransform(
new Vector2(1.0f / 6.0f, 1.0f), recommendedTreatmentContainer.
Content.
RectTransform,
Anchor.TopLeft),
1435 var innerFrame =
new GUIButton(
new RectTransform(Vector2.One, itemSlot.RectTransform,
Anchor.Center,
Pivot.Center, scaleBasis:
ScaleBasis.Smallest), style:
"SubtreeHeader")
1438 DisabledColor = Color.White * 0.1f,
1439 PlaySoundOnSelect =
false,
1440 OnClicked = (btn, userdata) =>
1442 if (userdata is not ItemPrefab itemPrefab) {
return false; }
1443 var item = AIObjectiveRescue.FindMedicalItem(
Character.Controlled.Inventory, it => it.Prefab == itemPrefab);
1444 if (item ==
null) {
return false; }
1445 Limb targetLimb =
Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == selectedLimbIndex);
1446 item.ApplyTreatment(
Character.Controlled, Character, targetLimb);
1452 new GUIImage(
new RectTransform(Vector2.One, innerFrame.RectTransform,
Anchor.Center), style:
"TalentBackgroundGlow")
1454 CanBeFocused =
false,
1455 Color = GUIStyle.Green,
1456 HoverColor = Color.White,
1457 PressedColor = Color.DarkGray,
1458 SelectedColor = Color.Transparent,
1459 DisabledColor = Color.Transparent
1462 Sprite itemSprite = item.InventoryIcon ?? item.Sprite;
1463 Color itemColor = itemSprite == item.Sprite ? item.SpriteColor : item.InventoryIconColor;
1464 var itemIcon =
new GUIImage(
new RectTransform(
new Vector2(0.8f, 0.8f), innerFrame.RectTransform,
Anchor.Center),
1465 itemSprite, scaleToFit:
true)
1467 CanBeFocused =
false,
1468 Color = itemColor * 0.9f,
1469 HoverColor = itemColor,
1470 SelectedColor = itemColor,
1471 DisabledColor = itemColor * 0.8f
1474 if (item == prevHighlightedItem)
1476 innerFrame.State = GUIComponent.ComponentState.Hover;
1477 innerFrame.Children.ForEach(c => c.State = GUIComponent.ComponentState.Hover);
1485 var first = r1.GUIComponent.UserData as
Affliction;
1486 var second = r2.GUIComponent.UserData as
Affliction;
1487 int dmgPerSecond = Math.Sign(second.DamagePerSecond - first.DamagePerSecond);
1488 return dmgPerSecond != 0 ? dmgPerSecond : Math.Sign(second.Strength - first.Strength);
1493 var treatmentIconSize = recommendedTreatmentContainer.
Content.
Children.Sum(c => c.Rect.Width + recommendedTreatmentContainer.
Spacing);
1494 if (treatmentIconSize < recommendedTreatmentContainer.
Content.
Rect.Width)
1496 var spacing =
new GUIFrame(
new RectTransform(
new Point((recommendedTreatmentContainer.
Content.
Rect.Width - treatmentIconSize) / 2, 0), recommendedTreatmentContainer.
Content.
RectTransform), style:
null)
1498 CanBeFocused =
false
1500 spacing.RectTransform.SetAsFirstChild();
1505 private void CreateAfflictionInfoElements(GUIComponent parent, Affliction affliction)
1507 var labelContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.2f), parent.RectTransform), isHorizontal:
true)
1510 AbsoluteSpacing = 10,
1512 CanBeFocused =
false
1515 var afflictionName =
new GUITextBlock(
new RectTransform(
new Vector2(0.65f, 1.0f), labelContainer.RectTransform), affliction.Prefab.Name, textAlignment: Alignment.CenterLeft, font: GUIStyle.LargeFont)
1517 CanBeFocused =
false,
1518 AutoScaleHorizontal =
true
1520 var afflictionStrength =
new GUITextBlock(
new RectTransform(
new Vector2(0.35f, 0.6f), labelContainer.RectTransform),
"", textAlignment: Alignment.TopRight, font: GUIStyle.SubHeadingFont)
1522 UserData =
"strength",
1523 CanBeFocused =
false
1525 var vitality =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.4f), labelContainer.RectTransform,
Anchor.BottomRight),
"", textAlignment: Alignment.BottomRight)
1527 Padding = afflictionStrength.Padding,
1528 IgnoreLayoutGroups =
true,
1529 UserData =
"vitality",
1530 CanBeFocused =
false
1533 var description =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.3f), parent.RectTransform),
1534 affliction.Prefab.GetDescription(
1535 affliction.Strength,
1536 Character ==
Character.Controlled ? AfflictionPrefab.Description.TargetType.Self : AfflictionPrefab.Description.TargetType.OtherCharacter),
1537 textAlignment: Alignment.TopLeft, wrap:
true)
1539 CanBeFocused =
false
1542 if (description.Font.MeasureString(description.WrappedText).Y > description.Rect.Height)
1544 description.Font = GUIStyle.SmallFont;
1547 Point nameDims =
new Point(afflictionName.Rect.Width, (
int)(GUIStyle.LargeFont.Size * 1.5f));
1549 afflictionStrength.Text = affliction.GetStrengthText();
1551 Vector2 strengthDims = GUIStyle.SubHeadingFont.MeasureString(afflictionStrength.Text);
1553 labelContainer.RectTransform.Resize(
new Point(labelContainer.Rect.Width, nameDims.Y));
1554 afflictionName.RectTransform.Resize(
new Point((
int)(labelContainer.Rect.Width - strengthDims.X * 0.99f), nameDims.Y));
1555 afflictionStrength.RectTransform.Resize(
new Point(labelContainer.Rect.Width - afflictionName.Rect.Width, nameDims.Y));
1557 afflictionStrength.TextColor = Color.Lerp(GUIStyle.Orange, GUIStyle.Red,
1558 affliction.Strength / affliction.Prefab.MaxStrength);
1560 description.RectTransform.Resize(
new Point(description.Rect.Width, (
int)(description.TextSize.Y + 10)));
1562 int vitalityDecrease = (int)GetVitalityDecreaseWithVitalityMultipliers(affliction);
1563 if (vitalityDecrease == 0)
1565 vitality.Visible =
false;
1569 vitality.Visible =
true;
1570 vitality.Text = TextManager.Get(
"Vitality") +
" -" + vitalityDecrease;
1571 vitality.TextColor = vitalityDecrease <= 0 ? GUIStyle.Green :
1572 Color.Lerp(GUIStyle.Orange, GUIStyle.Red, affliction.Strength / affliction.Prefab.MaxStrength);
1575 vitality.AutoDraw =
true;
1578 private bool SelectAffliction(GUIButton button,
object userData)
1580 bool selected = button.Selected;
1583 if (child is GUIButton btn)
1585 btn.Selected = btn == button && !selected;
1592 private void UpdateAfflictionInfos(IEnumerable<Affliction> afflictions)
1594 var potentialTreatment = Inventory.DraggingItems.FirstOrDefault();
1595 if (potentialTreatment ==
null && GUI.MouseOn?.UserData is ItemPrefab itemPrefab)
1597 potentialTreatment =
Character.Controlled.Inventory.FindItem(it => it.Prefab == itemPrefab, recursive:
true);
1599 potentialTreatment ??= Inventory.SelectedSlot?.Item;
1601 foreach (Affliction affliction
in afflictions)
1603 float afflictionVitalityDecrease = GetVitalityDecreaseWithVitalityMultipliers(affliction);
1604 Color afflictionEffectColor = Color.White;
1605 if (afflictionVitalityDecrease > 0.0f)
1607 afflictionEffectColor = GUIStyle.Red;
1609 else if (afflictionVitalityDecrease < 0.0f)
1611 afflictionEffectColor = GUIStyle.Green;
1616 var afflictionStrengthPredictionBar = child.
GetChild<GUILayoutGroup>().GetChildByUserData(
"afflictionstrengthprediction") as GUIProgressBar;
1617 afflictionStrengthPredictionBar.BarSize = 0.0f;
1618 var afflictionStrengthBar = afflictionStrengthPredictionBar.GetChildByUserData("afflictionstrength") as GUIProgressBar;
1619 afflictionStrengthBar.BarSize = affliction.Strength / affliction.Prefab.MaxStrength;
1620 afflictionStrengthBar.Color = afflictionEffectColor;
1622 float afflictionStrengthPrediction = GetAfflictionStrengthPrediction(potentialTreatment, affliction);
1623 if (!MathUtils.NearlyEqual(afflictionStrengthPrediction, affliction.Strength))
1625 float t = (float)Math.Max(0.5f, (Math.Sin(Timing.TotalTime * 5) + 1.0f) / 2.0f);
1626 if (afflictionStrengthPrediction < affliction.Strength)
1628 afflictionStrengthBar.
Color = afflictionEffectColor;
1629 afflictionStrengthPredictionBar.Color = GUIStyle.Blue * t;
1630 afflictionStrengthPredictionBar.BarSize = afflictionStrengthBar.BarSize;
1631 afflictionStrengthBar.BarSize = afflictionStrengthPrediction / affliction.Prefab.MaxStrength;
1635 afflictionStrengthPredictionBar.Color = Color.Red * t;
1636 afflictionStrengthPredictionBar.BarSize = afflictionStrengthPrediction / affliction.Prefab.MaxStrength;
1640 if (!affliction.Prefab.ShowBarInHealthMenu)
1642 afflictionStrengthBar.BarSize = 1f;
1645 if (afflictionTooltip !=
null && afflictionTooltip.
UserData == affliction)
1647 UpdateAfflictionInfo(afflictionTooltip.
Content, affliction);
1652 private float GetAfflictionStrengthPrediction(Item item, Affliction affliction)
1654 float strength = affliction.Strength;
1655 if (item ==
null) {
return strength; }
1661 foreach (StatusEffect effect
in statusEffects)
1663 foreach (var reduceAffliction
in effect.ReduceAffliction)
1665 if (reduceAffliction.AfflictionIdentifier != affliction.Identifier && reduceAffliction.AfflictionIdentifier != affliction.Prefab.AfflictionType) {
continue; }
1666 strength -= reduceAffliction.ReduceAmount * (effect.Duration > 0 ? effect.Duration : 1.0f);
1668 foreach (var addAffliction
in effect.Afflictions)
1670 if (addAffliction.Prefab != affliction.Prefab) {
continue; }
1671 strength += addAffliction.Strength * (effect.Duration > 0 ? effect.Duration : 1.0f);
1678 private void UpdateAfflictionInfo(GUIComponent parent, Affliction affliction)
1680 var labelContainer = parent.GetChildByUserData(
"label");
1682 var strengthText = labelContainer.GetChildByUserData(
"strength") as GUITextBlock;
1684 strengthText.Text = affliction.GetStrengthText();
1686 strengthText.TextColor = Color.Lerp(GUIStyle.Orange, GUIStyle.Red,
1687 affliction.Strength / affliction.Prefab.MaxStrength);
1689 var vitalityText = labelContainer.GetChildByUserData(
"vitality") as GUITextBlock;
1690 int vitalityDecrease = (int)GetVitalityDecreaseWithVitalityMultipliers(affliction);
1691 if (vitalityDecrease == 0)
1693 vitalityText.Visible =
false;
1697 vitalityText.Visible =
true;
1698 vitalityText.Text = TextManager.Get(
"Vitality") +
" -" + vitalityDecrease;
1699 vitalityText.TextColor = vitalityDecrease <= 0 ? GUIStyle.Green :
1700 Color.Lerp(GUIStyle.Orange, GUIStyle.Red, affliction.Strength / affliction.Prefab.MaxStrength);
1707 if (!ignoreMousePos &&
1716 if (!ignoreMousePos)
1718 if (highlightedLimbIndex > -1)
1720 selectedLimbIndex = highlightedLimbIndex;
1730 private void UpdateLimbIndicators(
float deltaTime, Rectangle drawArea)
1734 limbIndicatorOverlayAnimState += deltaTime * 8.0f;
1737 highlightedLimbIndex = -1;
1739 foreach (LimbHealth limbHealth
in limbHealths)
1741 if (limbHealth.IndicatorSprite ==
null) {
continue; }
1743 float scale = Math.Min(drawArea.Width / (
float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (
float)limbHealth.IndicatorSprite.SourceRect.Height);
1745 Rectangle highlightArea = GetLimbHighlightArea(limbHealth, drawArea);
1747 if (highlightArea.Contains(PlayerInput.MousePosition))
1749 highlightedLimbIndex = i;
1754 if (PlayerInput.PrimaryMouseButtonClicked() && highlightedLimbIndex > -1)
1756 selectedLimbIndex = highlightedLimbIndex;
1760 private static readonly List<Affliction> afflictionsDisplayedOnLimb =
new List<Affliction>();
1761 private void DrawHealthWindow(SpriteBatch spriteBatch, Rectangle drawArea,
bool allowHighlight)
1766 spriteBatch.Begin(SpriteSortMode.Immediate, blendState: BlendState.NonPremultiplied, rasterizerState: GameMain.ScissorTestEnable, effect: GameMain.GameScreen.GradientEffect);
1769 foreach (LimbHealth limbHealth
in limbHealths)
1771 if (limbHealth.IndicatorSprite ==
null) {
continue; }
1773 Rectangle limbEffectiveArea =
new Rectangle(limbHealth.IndicatorSprite.SourceRect.X + limbHealth.HighlightArea.X,
1774 limbHealth.IndicatorSprite.SourceRect.Y + limbHealth.HighlightArea.Y,
1775 limbHealth.HighlightArea.Width,
1776 limbHealth.HighlightArea.Height);
1778 float totalDamage = GetTotalDamage(limbHealth);
1780 float damageLerp = totalDamage > 0.0f ? MathHelper.Lerp(0.2f, 1.0f, totalDamage / 100.0f) : 0.0f;
1782 float negativeEffect = 0.0f, positiveEffect = 0.0f;
1783 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
1785 if (kvp.Value != limbHealth) {
continue; }
1786 var affliction = kvp.Key;
1787 if (!affliction.ShouldShowIcon(Character)) {
continue; }
1788 if (!affliction.Prefab.IsBuff)
1790 negativeEffect += affliction.Strength * GetVitalityMultiplier(affliction, limbHealth);
1794 positiveEffect += affliction.Strength * 0.2f;
1798 float midPoint = (float)limbEffectiveArea.Center.Y / (
float)limbHealth.IndicatorSprite.Texture.Height;
1799 float fadeDist = 0.6f * (float)limbEffectiveArea.Height / (
float)limbHealth.IndicatorSprite.Texture.Height;
1801 if (negativeEffect > 0.0f && negativeEffect < 5.0f) { negativeEffect = 10.0f; }
1802 if (positiveEffect > 0.0f && positiveEffect < 5.0f) { positiveEffect = 10.0f; }
1804 Color positiveColor = Color.Lerp(Color.Orange, Color.Lime, Math.Min(positiveEffect / 25.0f, 1.0f));
1805 Color negativeColor = Color.Lerp(Color.Orange, Color.Red, Math.Min(negativeEffect / 25.0f, 1.0f));
1807 Color color1 = Color.Orange;
1808 Color color2 = Color.Orange;
1810 if (negativeEffect + positiveEffect > 0.0f)
1812 if (negativeEffect >= positiveEffect)
1814 color1 = Color.Lerp(positiveColor, negativeColor, (negativeEffect - positiveEffect) / negativeEffect);
1815 color2 = negativeColor;
1819 color1 = positiveColor;
1820 color2 = Color.Lerp(negativeColor, positiveColor, (positiveEffect - negativeEffect) / positiveEffect);
1826 color1 = Color.Lerp(color1, Color.Black, 0.75f);
1827 color2 = Color.Lerp(color2, Color.Black, 0.75f);
1830 GameMain.GameScreen.GradientEffect.Parameters[
"color1"].SetValue(color1.ToVector4());
1831 GameMain.GameScreen.GradientEffect.Parameters[
"color2"].SetValue(color2.ToVector4());
1832 GameMain.GameScreen.GradientEffect.Parameters[
"midPoint"].SetValue(midPoint);
1833 GameMain.GameScreen.GradientEffect.Parameters[
"fadeDist"].SetValue(fadeDist);
1835 float scale = Math.Min(drawArea.Width / (
float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
1837 limbHealth.IndicatorSprite.Draw(spriteBatch,
1838 drawArea.Center.ToVector2(), Color.White,
1839 limbHealth.IndicatorSprite.Origin,
1842 if (GameMain.DebugDraw)
1844 Rectangle highlightArea = GetLimbHighlightArea(limbHealth, drawArea);
1846 GUI.DrawRectangle(spriteBatch, highlightArea, Color.Red,
false);
1847 GUI.DrawRectangle(spriteBatch, drawArea, Color.Red,
false);
1855 spriteBatch.Begin(SpriteSortMode.Deferred, Lights.CustomBlendStates.Multiplicative);
1857 if (limbIndicatorOverlay !=
null)
1859 float overlayScale = Math.Min(
1860 drawArea.Width / (
float)limbIndicatorOverlay.
FrameSize.X,
1861 drawArea.Height / (
float)limbIndicatorOverlay.
FrameSize.Y);
1864 int frameCount = 17;
1865 if (limbIndicatorOverlayAnimState >= frameCount * 2) limbIndicatorOverlayAnimState = 0.0f;
1866 if (limbIndicatorOverlayAnimState < frameCount)
1868 frame = (int)limbIndicatorOverlayAnimState;
1872 frame = frameCount - (int)(limbIndicatorOverlayAnimState - (frameCount - 1));
1875 limbIndicatorOverlay.
Draw(spriteBatch, frame, drawArea.Center.ToVector2(), Color.Gray, origin: limbIndicatorOverlay.
FrameSize.ToVector2() / 2, rotate: 0.0f,
1876 scale: Vector2.One * overlayScale);
1882 foreach (LimbHealth limbHealth
in limbHealths)
1884 if (limbHealth.HighlightSprite ==
null) {
continue; }
1886 float scale = Math.Min(drawArea.Width / (
float)limbHealth.HighlightSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.HighlightSprite.SourceRect.Height);
1889 if (i == highlightedLimbIndex) { drawCount++; }
1890 if (i == selectedLimbIndex) { drawCount++; }
1891 for (
int j = 0; j < drawCount; j++)
1893 limbHealth.HighlightSprite.Draw(spriteBatch,
1894 drawArea.Center.ToVector2(), Color.White,
1895 limbHealth.HighlightSprite.Origin,
1902 spriteBatch.Begin(SpriteSortMode.Deferred, blendState: BlendState.NonPremultiplied, rasterizerState: GameMain.ScissorTestEnable);
1905 foreach (LimbHealth limbHealth
in limbHealths)
1907 afflictionsDisplayedOnLimb.Clear();
1908 foreach (var affliction
in afflictions)
1910 if (ShouldDisplayAfflictionOnLimb(affliction, limbHealth)) { afflictionsDisplayedOnLimb.Add(affliction.Key); }
1913 if (!afflictionsDisplayedOnLimb.Any()) { i++;
continue; }
1914 if (limbHealth.IndicatorSprite ==
null) {
continue; }
1916 float scale = Math.Min(drawArea.Width / (
float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
1918 Rectangle highlightArea = GetLimbHighlightArea(limbHealth, drawArea);
1920 float iconScale = 0.25f * scale;
1921 Vector2 iconPos = highlightArea.Center.ToVector2();
1924 Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictionsDisplayedOnLimb, excludeBuffs:
false).FirstOrDefault();
1925 if (mostSevereAffliction !=
null) { DrawLimbAfflictionIcon(spriteBatch, mostSevereAffliction, iconScale, ref iconPos); }
1927 if (afflictionsDisplayedOnLimb.Count() > 1)
1929 string additionalAfflictionCount = $
"+{afflictionsDisplayedOnLimb.Count() - 1}";
1930 Vector2 displace = GUIStyle.SubHeadingFont.MeasureString(additionalAfflictionCount);
1931 GUIStyle.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos +
new Vector2(displace.X * 1.1f, -displace.Y * 0.45f), Color.Black * 0.75f);
1932 GUIStyle.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos +
new Vector2(displace.X, -displace.Y * 0.5f), Color.White);
1940 LimbHealth limbHealth = limbHealths[selectedLimbIndex];
1941 if (limbHealth?.IndicatorSprite !=
null)
1943 Rectangle selectedLimbArea = GetLimbHighlightArea(limbHealth, drawArea);
1944 GUI.DrawLine(spriteBatch,
1945 new Vector2(afflictionIconList.
Rect.X, afflictionIconList.
Rect.Y),
1946 selectedLimbArea.Center.ToVector2(),
1947 Color.LightGray * 0.5f, width: 4);
1953 private bool ShouldDisplayAfflictionOnLimb(KeyValuePair<Affliction, LimbHealth> kvp, LimbHealth limbHealth)
1955 if (!kvp.Key.ShouldShowIcon(Character)) {
return false; }
1956 if (kvp.Value == limbHealth)
1960 else if (kvp.Value ==
null)
1962 Limb indicatorLimb =
Character.AnimController.GetLimb(kvp.Key.Prefab.IndicatorLimb);
1963 return indicatorLimb !=
null && indicatorLimb.HealthIndex == limbHealths.IndexOf(limbHealth);
1968 private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction,
float iconScale, ref Vector2 iconPos)
1970 if (!affliction.ShouldShowIcon(Character) || affliction.Prefab.Icon ==
null) {
return; }
1971 Vector2 iconSize = affliction.Prefab.Icon.size * iconScale;
1973 float showIconThreshold =
Character.Controlled?.CharacterHealth ==
this ? affliction.Prefab.ShowIconThreshold : affliction.Prefab.ShowIconToOthersThreshold;
1976 float alpha = MathHelper.Lerp(0.3f, 1.0f,
1977 (affliction.Strength - showIconThreshold) / Math.Min(affliction.Prefab.MaxStrength - showIconThreshold, 10.0f));
1979 affliction.Prefab.Icon.Draw(spriteBatch, iconPos - iconSize / 2.0f, GetAfflictionIconColor(affliction) * alpha, 0, iconScale);
1980 iconPos +=
new Vector2(10.0f, 20.0f) * iconScale;
1983 private Rectangle GetLimbHighlightArea(LimbHealth limbHealth, Rectangle drawArea)
1985 float scale = Math.Min(drawArea.Width / (
float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (
float)limbHealth.IndicatorSprite.SourceRect.Height);
1987 (
int)(drawArea.Center.X - (limbHealth.IndicatorSprite.SourceRect.Width / 2 - limbHealth.HighlightArea.X) * scale),
1988 (
int)(drawArea.Center.Y - (limbHealth.IndicatorSprite.SourceRect.Height / 2 - limbHealth.HighlightArea.Y) * scale),
1989 (
int)(limbHealth.HighlightArea.Width * scale),
1990 (
int)(limbHealth.HighlightArea.Height * scale));
1995 healthBarHolder.
Visible = value;
1998 private readonly List<(LimbHealth limb,
AfflictionPrefab afflictionPrefab,
float strength)> newAfflictions =
new List<(LimbHealth limb,
AfflictionPrefab afflictionPrefab,
float strength)>();
2003 newAfflictions.Clear();
2004 newPeriodicEffects.Clear();
2005 bool newAdded =
false;
2006 byte afflictionCount = inc.
ReadByte();
2007 for (
int i = 0; i < afflictionCount; i++)
2011 if (afflictionPrefab ==
null)
2013 DebugConsole.ThrowError(
"Error while reading character health data: affliction with the uint ID " + afflictionID +
" not found.");
2016 int _periodicAfflictionCount = inc.
ReadByte();
2017 for (
int j = 0; j < _periodicAfflictionCount; j++)
2024 int periodicAfflictionCount = inc.
ReadByte();
2025 for (
int j = 0; j < periodicAfflictionCount; j++)
2028 newPeriodicEffects.Add((afflictionPrefab.
PeriodicEffects[j], periodicAfflictionTimer));
2030 newAfflictions.Add((
null, afflictionPrefab, afflictionStrength));
2033 byte limbAfflictionCount = inc.
ReadByte();
2034 for (
int i = 0; i < limbAfflictionCount; i++)
2039 if (afflictionPrefab ==
null)
2041 DebugConsole.ThrowError(
"Error while reading character health data: affliction with the uint ID " + afflictionID +
" not found.");
2044 int _periodicAfflictionCount = inc.
ReadByte();
2045 for (
int j = 0; j < _periodicAfflictionCount; j++)
2052 int periodicAfflictionCount = inc.
ReadByte();
2053 for (
int j = 0; j < periodicAfflictionCount; j++)
2056 newPeriodicEffects.Add((afflictionPrefab.
PeriodicEffects[j], periodicAfflictionTimer));
2058 newAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
2061 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
2064 if (!newAfflictions.Any(a => kvp.Key.Prefab == a.afflictionPrefab && kvp.Value == a.limb))
2066 kvp.Key.Strength = 0.0f;
2070 foreach (var (limb, afflictionPrefab, strength) in newAfflictions)
2073 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
2075 if (kvp.Key.Prefab == afflictionPrefab && kvp.Value == limb)
2077 existingAffliction = kvp.Key;
2081 if (existingAffliction ==
null)
2083 existingAffliction = afflictionPrefab.Instantiate(strength);
2084 afflictions.Add(existingAffliction, limb);
2088 if (existingAffliction == stunAffliction)
2092 foreach (var periodicEffect
in newPeriodicEffects)
2094 if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) {
continue; }
2095 if (existingAffliction.Strength < periodicEffect.effect.MinStrength) {
continue; }
2096 if (periodicEffect.effect.MaxStrength > 0 && existingAffliction.Strength > periodicEffect.effect.MaxStrength) {
continue; }
2098 if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
2100 foreach (
StatusEffect effect
in periodicEffect.effect.StatusEffects)
2103 existingAffliction.ApplyStatusEffect(
ActionType.OnActive, effect, deltaTime: 1.0f,
this, targetLimb: targetLimb);
2106 existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
2110 CalculateVitality();
2111 DisplayedVitality = Vitality;
2115 MedicalClinic.OnAfflictionCountChanged(
Character);
2119 partial
void UpdateSkinTint()
2121 FaceTint = DefaultFaceTint;
2122 BodyTint = Color.TransparentBlack;
2126 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
2128 var affliction = kvp.Key;
2129 Color faceTint = affliction.GetFaceTint();
2130 if (faceTint.A > FaceTint.A) { FaceTint = faceTint; }
2131 Color bodyTint = affliction.GetBodyTint();
2132 if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; }
2136 partial
void UpdateLimbAfflictionOverlays()
2138 foreach (Limb limb
in Character.AnimController.Limbs)
2140 if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) {
continue; }
2141 limb.BurnOverlayStrength = 0.0f;
2142 limb.DamageOverlayStrength = 0.0f;
2143 foreach (KeyValuePair<Affliction, LimbHealth> kvp
in afflictions)
2145 var affliction = kvp.Key;
2146 float burnStrength = affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.BurnOverlayAlpha;
2147 if (kvp.Value == limbHealths[limb.HealthIndex] || !affliction.Prefab.LimbSpecific)
2149 limb.BurnOverlayStrength += burnStrength;
2150 limb.DamageOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.DamageOverlayAlpha;
2154 limb.BurnOverlayStrength += burnStrength / 2;
2160 partial
void RemoveProjSpecific()
2162 foreach (LimbHealth limbHealth
in limbHealths)
2164 if (limbHealth.IndicatorSprite !=
null)
2166 limbHealth.IndicatorSprite.Remove();
2167 limbHealth.IndicatorSprite =
null;
2176 limbIndicatorOverlay?.
Remove();
2177 limbIndicatorOverlay =
null;
2179 if (healthWindow !=
null)
2182 healthWindow =
null;
2184 if (healthBarHolder !=
null)
2187 healthBarHolder =
null;
2189 if (SuicideButton !=
null)
2192 SuicideButton =
null;
2194 if (afflictionTooltip !=
null)
2197 afflictionTooltip =
null;
static Item FindMedicalItem(Inventory inventory, Identifier itemIdentifier)
void SetStrength(float strength)
Use this method to skip clamping and additional logic of the setters. Ideally we would keep this priv...
readonly AfflictionPrefab Prefab
PeriodicEffect applies StatusEffects to the character periodically.
AfflictionPrefab is a prefab that defines a type of affliction that can be applied to a character....
IList< PeriodicEffect > PeriodicEffects
readonly bool IsBuff
If set to true, the game will recognize this affliction as a buff. This means, among other things,...
readonly bool HideIconAfterDelay
If set to true, this affliction's icon will be hidden from the HUD after 5 seconds.
readonly Color[] IconColors
A gradient that defines which color to render this affliction's icon with, based on the affliction's ...
readonly float MaxStrength
The maximum strength this affliction can have.
readonly LocalizedString Name
static readonly PrefabCollection< AfflictionPrefab > Prefabs
readonly Sprite Icon
An icon that’s used in the UI to represent this affliction.
static bool IsCampaignInterfaceOpen
readonly Sprite DamageOverlay
DamageOverlayPrefab(ContentXElement element, AfflictionsFile file)
static readonly PrefabSelector< DamageOverlayPrefab > Prefabs
readonly Character Character
static Sprite DamageOverlay
static CharacterHealth?? OpenHealthWindow
bool OnItemDropped(Item item, bool ignoreMousePos)
static Color GetAfflictionIconColor(Affliction affliction)
static bool IsMouseOnHealthBar()
GUIComponent InventorySlotContainer
static Color GetAfflictionIconColor(AfflictionPrefab prefab, float afflictionStrength)
void SetHealthBarVisibility(bool value)
void UpdateStatusHUD(float deltaTime)
void AddToGUIUpdateList()
float HealthBarPulsateTimer
void DrawHUD(SpriteBatch spriteBatch)
static Color GetAfflictionIconColor(AfflictionPrefab prefab, Affliction affliction)
void ClientRead(IReadMessage inc)
void UpdateHUD(float deltaTime)
void UpdateClientSpecific(float deltaTime)
readonly CharacterParams Params
CharacterHealth CharacterHealth
void SetStun(float newStun, bool allowStunDecrease=false, bool isNetworkMessage=false)
bool HasEquippedItem(Item item, InvSlotType? slotType=null, Func< InvSlotType, bool > predicate=null)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
bool InPressure
Can be used by status effects to check whether the characters is in a high-pressure environment
void EmulateInput(InputType input)
Character SelectedCharacter
CharacterInventory Inventory
OnAttackedHandler OnAttacked
void Kill(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool isNetworkMessage=false, bool log=true)
float ChromaticAberrationStrength
static Character? Controlled
Character FocusedCharacter
bool IsKnockedDown
Is the character knocked down regardless whether the technical state is dead, unconcious,...
readonly AnimController AnimController
float RadialDistortStrength
bool DisableInteract
Prevents the character from interacting with items or characters
string ReplaceVars(string str)
bool ApplyAfflictionColors
IEnumerable< ContentXElement > Elements()
GUIComponent GetChild(int index)
virtual void RemoveChild(GUIComponent child)
virtual ComponentState State
virtual void Flash(Color? color=null, float flashDuration=1.5f, bool useRectangleFlash=false, bool useCircularFlash=false, Vector2? flashRectInflate=null)
virtual void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
bool IsParentOf(GUIComponent component, bool recursive=true)
GUIComponent GetChildByUserData(object obj)
virtual void ClearChildren()
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
RectTransform RectTransform
IEnumerable< GUIComponent > Children
void RecalculateChildren()
override void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
bool AutoHideScrollBar
Automatically hides the scroll bar when the content fits in.
override void ClearChildren()
bool AutoScaleHorizontal
When enabled, the text is automatically scaled down to fit the textblock horizontally.
static GameSession?? GameSession
static int GraphicsHeight
static NetworkMember NetworkMember
static readonly List< Item > DraggingItems
static SlotReference?? SelectedSlot
int FindIndex(Item item)
Find the index of the first slot the item is contained in.
void ApplyTreatment(Character user, Character character, Limb targetLimb)
bool UseInHealthInterface
The base class for components holding the different functionalities of the item
readonly Dictionary< ActionType, List< StatusEffect > > statusEffectLists
bool Contains(string str, StringComparison stringComparison=StringComparison.Ordinal)
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
override void Draw(ISpriteBatch spriteBatch, Vector2 pos, Color color, Vector2 origin, float rotate, Vector2 scale, SpriteEffects spriteEffect=SpriteEffects.None, float? depth=default(float?))
StatusEffects can be used to execute various kinds of effects: modifying the state of some entity in ...
void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount=0.5f)
Highlights an UI element of some kind. Generally used in tutorials.
int ReadRangedInteger(int min, int max)
Single ReadRangedSingle(Single min, Single max, int bitCount)
ActionType
ActionTypes define when a StatusEffect is executed.