2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
5 using System.Collections.Generic;
10 partial class StatusHUD : ItemComponent
12 private static readonly LocalizedString[] BleedingTexts =
14 TextManager.Get(
"MinorBleeding"),
15 TextManager.Get(
"Bleeding"),
16 TextManager.Get(
"HeavyBleeding"),
17 TextManager.Get(
"CatastrophicBleeding")
20 private static readonly LocalizedString[] OxygenTexts =
22 TextManager.Get(
"OxygenNormal"),
23 TextManager.Get(
"OxygenReduced"),
24 TextManager.Get(
"OxygenLow"),
25 TextManager.Get(
"NotBreathing")
28 [Serialize(500.0f,
IsPropertySaveable.No, description:
"How close to a target the user must be to see their health data (in pixels).")]
77 private readonly List<Character> visibleCharacters =
new List<Character>();
79 private const float UpdateInterval = 0.5f;
80 private float updateTimer;
84 private bool isEquippable;
86 private float thermalEffectState;
92 if (equipper ==
null || equipper.
Removed) {
return Enumerable.Empty<
Character>(); }
93 return visibleCharacters;
100 if (!isEquippable) {
IsActive =
true; }
105 base.Update(deltaTime, cam);
107 Entity refEntity = equipper;
110 if (equipper ==
null || equipper.
Removed)
126 thermalEffectState += deltaTime;
127 thermalEffectState %= 10000.0f;
129 if (updateTimer > 0.0f)
131 updateTimer -= deltaTime;
135 visibleCharacters.Clear();
142 float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.
WorldPosition);
146 if (
Submarine.
CheckVisibility(refEntity.SimPosition, refEntity.SimPosition + ConvertUnits.ToSimUnits(diff)) ==
null)
148 visibleCharacters.Add(c);
153 updateTimer = UpdateInterval;
159 equipper = character;
176 if (character ==
null) {
return; }
187 float closestDist =
float.PositiveInfinity;
188 foreach (
Character c
in visibleCharacters)
193 if (dist < closestDist)
195 closestCharacter = c;
200 if (closestCharacter !=
null)
210 GameMain.
LightManager.SolidColorEffect.Parameters[
"color"].SetValue(Color.Red.ToVector4() * (0.3f + MathF.Sin(thermalEffectState) * 0.05f));
212 GameMain.
LightManager.SolidColorEffect.Parameters[
"blurDistance"].SetValue(0.01f + MathF.Sin(thermalEffectState) * 0.005f);
216 Entity refEntity = equipper;
217 if (!isEquippable || refEntity ==
null)
227 float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.
WorldPosition);
230 Sprite pingCircle = GUIStyle.UIThermalGlow.Value.
Sprite;
234 float noise1 = PerlinNoise.GetPerlin((thermalEffectState + limb.
Params.ID + c.
ID) * 0.01f, (thermalEffectState + limb.
Params.ID + c.
ID) * 0.02f);
235 float noise2 = PerlinNoise.GetPerlin((thermalEffectState + limb.
Params.ID + c.
ID) * 0.01f, (thermalEffectState + limb.
Params.ID + c.
ID) * 0.008f);
236 Vector2 spriteScale = ConvertUnits.ToDisplayUnits(limb.
body.
GetSize()) / pingCircle.size * (noise1 * 0.5f + 2f);
238 pingCircle.Draw(spriteBatch, drawPos, 0.0f, scale: Math.Max(spriteScale.X, spriteScale.Y));
243 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
247 private void DrawCharacterInfo(SpriteBatch spriteBatch,
Character target,
float alpha = 1.0f)
250 hudPos += Vector2.UnitX * 50.0f;
252 List<LocalizedString> texts =
new List<LocalizedString>();
253 List<Color> textColors =
new List<Color>();
255 Color nameColor = GUIStyle.TextColorNormal;
260 textColors.Add(nameColor);
264 texts.Add(TextManager.Get(
"Deceased"));
265 textColors.Add(GUIStyle.Red);
270 TextManager.AddPunctuation(
':', TextManager.Get(
"CauseOfDeath"), TextManager.Get(
"CauseOfDeath." + target.
CauseOfDeath.
Type.ToString())));
271 textColors.Add(GUIStyle.Red);
279 textColors.Add(GUIStyle.Green);
284 textColors.Add(GUIStyle.Green);
286 if (equipper?.FocusedCharacter == target && target.
CanBeHealedBy(equipper, checkFriendlyTeam:
false))
289 textColors.Add(GUIStyle.Green);
294 textColors.Add(GUIStyle.Green);
299 texts.Add(TextManager.Get(
"Unconscious"));
300 textColors.Add(GUIStyle.Orange);
302 if (target.
Stun > 0.01f)
304 texts.Add(TextManager.Get(
"Stunned"));
305 textColors.Add(GUIStyle.Orange);
308 int oxygenTextIndex = MathHelper.Clamp((
int)Math.Floor((1.0f - (target.
Oxygen / 100.0f)) * OxygenTexts.Length), 0, OxygenTexts.Length - 1);
309 texts.Add(OxygenTexts[oxygenTextIndex]);
310 textColors.Add(Color.Lerp(GUIStyle.Red, GUIStyle.Green, target.
Oxygen / 100.0f));
314 int bleedingTextIndex = MathHelper.Clamp((
int)Math.Floor(target.
Bleeding / 100.0f * BleedingTexts.Length), 0, BleedingTexts.Length - 1);
315 texts.Add(BleedingTexts[bleedingTextIndex]);
316 textColors.Add(Color.Lerp(GUIStyle.Orange, GUIStyle.Red, target.
Bleeding / 100.0f));
320 Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths =
new Dictionary<AfflictionPrefab, float>();
321 foreach (Affliction affliction
in allAfflictions)
323 if (affliction.Strength <= 0f) {
continue; }
324 if (affliction.Strength < affliction.Prefab.ShowInHealthScannerThreshold)
326 if (target.
IsHuman || target.
IsOnPlayerTeam || (affliction.Prefab.AfflictionType != AfflictionPrefab.PoisonType && affliction.Prefab.AfflictionType != AfflictionPrefab.ParalysisType))
335 if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
337 combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
341 combinedAfflictionStrengths[affliction.Prefab] = affliction.Strength;
345 foreach (AfflictionPrefab affliction
in combinedAfflictionStrengths.Keys)
347 texts.Add(TextManager.AddPunctuation(
':', affliction.Name, Math.Max((
int)combinedAfflictionStrengths[affliction], 1).ToString() +
" %"));
348 textColors.Add(Color.Lerp(GUIStyle.Orange, GUIStyle.Red, combinedAfflictionStrengths[affliction] / affliction.MaxStrength));
352 GUI.DrawString(spriteBatch, hudPos, texts[0].Value, textColors[0] * alpha, Color.Black * 0.7f * alpha, 2, GUIStyle.SubHeadingFont,
ForceUpperCase.No);
353 hudPos.X += 5.0f * GUI.Scale;
354 hudPos.Y += GUIStyle.SubHeadingFont.MeasureString(texts[0].Value).Y;
356 hudPos.X = (int)hudPos.X;
357 hudPos.Y = (
int)hudPos.Y;
359 for (
int i = 1; i < texts.Count; i++)
361 GUI.DrawString(spriteBatch, hudPos, texts[i], textColors[i] * alpha, Color.Black * 0.7f * alpha, 2, GUIStyle.SmallFont);
362 hudPos.Y += (int)(GUIStyle.SubHeadingFont.MeasureString(texts[i].Value).Y);
readonly LocalizedString CauseOfDeathDescription
Vector2 WorldToScreen(Vector2 coords)
Vector2 ScreenToWorld(Vector2 coords)
readonly AfflictionPrefab Affliction
readonly CauseOfDeathType Type
IReadOnlyCollection< Affliction > GetAllAfflictions()
readonly CharacterParams Params
CauseOfDeath CauseOfDeath
CharacterHealth CharacterHealth
static readonly List< Character > CharacterList
bool CanBeHealedBy(Character character, bool checkFriendlyTeam=true)
override Vector2 DrawPosition
bool CanBeDraggedBy(Character character)
static Character? Controlled
LocalizedString CustomInteractHUDText
readonly AnimController AnimController
bool HideInThermalGoggles
virtual Vector2 WorldPosition
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
bool InDetectable
Indetectable characters can't be spotted by AIs and aren't visible on the sonar or health scanner.
static int GraphicsHeight
static Lights.LightManager LightManager
static GameScreen GameScreen
static double DebugWiringEnabledUntil
override void OnItemLoaded()
Called when all the components of the item have been loaded. Use to initialize connections between co...
IEnumerable< Character > VisibleCharacters
override void Unequip(Character character)
override void DrawHUD(SpriteBatch spriteBatch, Character character)
override void Update(float deltaTime, Camera cam)
override void Equip(Character character)
override void Drop(Character dropper, bool setTransform=true)
a Character has dropped the item
readonly LimbParams Params
Sprite(ContentXElement element, string path="", string file="", bool lazyLoad=false, float sourceRectScale=1)
static Body CheckVisibility(Vector2 rayStart, Vector2 rayEnd, bool ignoreLevel=false, bool ignoreSubs=false, bool ignoreSensors=true, bool ignoreDisabledWalls=true, bool ignoreBranches=true, Predicate< Fixture > blocksVisibilityPredicate=null)
Check visibility between two points (in sim units).