7 using FarseerPhysics.Dynamics;
8 using Microsoft.Xna.Framework;
9 using Microsoft.Xna.Framework.Graphics;
11 using System.Collections.Generic;
26 private float findFocusedTimer;
30 private float hudInfoHeight = 100.0f;
32 private List<CharacterSound> sounds;
52 get {
return controlled; }
55 if (controlled == value)
return;
56 if ((!(controlled is
null)) && (!(
Screen.
Selected?.
Cam is
null)) && value is
null)
59 Lights.LightManager.ViewTarget =
null;
62 if (controlled !=
null) controlled.Enabled =
true;
67 private Dictionary<object, HUDProgressBar> hudProgressBars;
68 private readonly List<KeyValuePair<object, HUDProgressBar>> progressBarRemovals =
new List<KeyValuePair<object, HUDProgressBar>>();
72 get {
return hudProgressBars; }
75 private float blurStrength;
78 get {
return blurStrength; }
79 set { blurStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
82 private float distortStrength;
85 get {
return distortStrength; }
86 set { distortStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
89 private float radialDistortStrength;
92 get {
return radialDistortStrength; }
93 set { radialDistortStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
96 private float chromaticAberrationStrength;
99 get {
return chromaticAberrationStrength; }
100 set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
105 private float grainStrength;
108 get => grainStrength;
109 set => grainStrength = Math.Max(0, value);
123 float strength = MathHelper.Clamp(value, 0.0f, 1.0f);
127 Screen.
Selected.
Cam.
Rotation = strength * (PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.01f, (float)Timing.TotalTime * 0.05f) - 0.5f);
140 if (!MathUtils.IsValid(value)) {
return; }
149 private readonly List<ParticleEmitter> bloodEmitters =
new List<ParticleEmitter>();
152 get {
return bloodEmitters; }
155 private readonly List<ParticleEmitter> damageEmitters =
new List<ParticleEmitter>();
158 get {
return damageEmitters; }
161 private readonly List<ParticleEmitter> gibEmitters =
new List<ParticleEmitter>();
164 get {
return gibEmitters; }
169 public string RawText;
170 public Identifier Identifier;
176 get {
return _value; }
180 Text = RawText.Replace(
"[value]", _value.ToString());
186 public float Lifetime;
193 public GUIMessage(
string rawText, Color color,
float delay, Identifier identifier =
default,
int? value =
null,
float lifeTime = 3.0f)
195 RawText = Text = rawText;
198 Text = rawText.Replace(
"[value]", value.Value.ToString());
202 Size = GUIStyle.Font.MeasureString(Text);
204 Identifier = identifier;
209 private List<GUIMessage> guiMessages =
new List<GUIMessage>();
235 private readonly List<ObjectiveEntity> activeObjectiveEntities =
new List<ObjectiveEntity>();
238 get {
return activeObjectiveEntities; }
241 private static readonly List<SpeechBubble> speechBubbles =
new List<SpeechBubble>();
243 private SpeechBubble textlessSpeechBubble;
245 sealed
class SpeechBubble
247 public float LifeTime;
248 public Vector2 PrevPosition;
251 public float MoveUpAmount;
252 public readonly
string Text;
255 public readonly Vector2 TextSize;
260 public SpeechBubble(
Character character,
float lifeTime, Color color,
string text =
"")
262 Text = ToolBox.WrapText(text, GUI.IntScale(300), GUIStyle.SmallFont.GetFontForStr(text));
263 TextSize = GUIStyle.SmallFont.MeasureString(Text);
272 public Vector2 GetDesiredPosition()
274 return Character.Position + Vector2.UnitY * 100;
278 private float pressureEffectTimer;
280 partial
void InitProjSpecific(ContentXElement mainElement)
284 sounds =
new List<CharacterSound>();
285 Params.
Sounds.ForEach(s => sounds.Add(
new CharacterSound(s)));
287 foreach (var subElement
in mainElement.Elements())
289 switch (subElement.Name.ToString().ToLowerInvariant())
291 case "damageemitter":
303 hudProgressBars =
new Dictionary<object, HUDProgressBar>();
306 partial
void UpdateLimbLightSource(Limb limb)
308 if (limb.LightSource !=
null)
310 limb.LightSource.Enabled = enabled;
314 private readonly List<Item> previousInteractablesInRange =
new();
315 private readonly List<Item> interactablesInRange =
new();
317 private bool wasFiring;
329 if (key ==
null) {
continue; }
332 if (GUI.InputBlockingMenuOpen)
341 for (
int i = 0; i <
keys.Length; i++)
351 ResetInputIfPrimaryMouse(
InputType.Shoot);
352 ResetInputIfPrimaryMouse(
InputType.Select);
353 void ResetInputIfPrimaryMouse(
InputType inputType)
355 if (GameSettings.CurrentConfig.KeyMap.Bindings[inputType].MouseButton ==
MouseButton.PrimaryMouse)
357 keys[(int)inputType].Reset();
373 if (GameSettings.CurrentConfig.KeyMap.Bindings[
InputType.Shoot] == GameSettings.CurrentConfig.KeyMap.Bindings[
InputType.Select])
377 if (GameSettings.CurrentConfig.KeyMap.Bindings[
InputType.Shoot] == GameSettings.CurrentConfig.KeyMap.Bindings[
InputType.Use])
384 float targetOffsetAmount = 0.0f;
391 pressureEffectTimer += deltaTime;
392 if (pressureEffectTimer > 1.0f)
395 float zoomInEffectStrength = MathHelper.Clamp(pressure / 100.0f, 0.0f, 1.0f);
396 cam.
Zoom = MathHelper.Lerp(cam.
Zoom,
397 cam.
DefaultZoom + (Math.Max(pressure, 10) / 150.0f) * Rand.Range(0.9f, 1.1f),
398 zoomInEffectStrength);
403 pressureEffectTimer = 0.0f;
419 Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
420 if (GUI.PauseMenuOpen)
426 cam.
OffsetAmount = targetOffsetAmount = item.Prefab.OffsetOnSelected * item.OffsetOnSelectedMultiplier;
436 else if (!GameSettings.CurrentConfig.EnableMouseLook)
440 else if (Lights.LightManager.ViewTarget ==
this)
444 if (deltaTime > 0.0f)
463 targetOffsetAmount = Math.Max(250.0f, sightDist * 500.0f);
471 if (!GUI.InputBlockingMenuOpen)
485 findFocusedTimer = 0.2f;
502 partial
void UpdateControlled(
float deltaTime,
Camera cam)
504 if (controlled !=
this) {
return; }
508 Lights.LightManager.ViewTarget =
this;
511 if (hudProgressBars.Any())
513 foreach (var progressBar
in hudProgressBars)
515 if (progressBar.Value.FadeTimer <= 0.0f)
517 progressBarRemovals.Add(progressBar);
520 progressBar.Value.Update(deltaTime);
522 if (progressBarRemovals.Any())
524 progressBarRemovals.ForEach(pb => hudProgressBars.Remove(pb.Key));
525 progressBarRemovals.Clear();
532 keys[(int)input].Hit =
true;
538 if (attacker !=
null)
540 if (attackResult.
Damage <= 0.01f) {
return; }
544 if (attackResult.
Damage <= 1.0f) {
return; }
546 PlaySound(CharacterSound.SoundType.Damage, maxInterval: 2);
549 partial
void KillProjSpecific(
CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction,
bool log)
551 HintManager.OnCharacterKilled(
this);
553 if (GameMain.NetworkMember !=
null && controlled ==
this)
557 TextManager.Get(
"Self_CauseOfDeathDescription." +
CauseOfDeath.
Type.ToString(),
"Self_CauseOfDeathDescription.Damage");
559 if (GameMain.Client !=
null) { chatMessage +=
" " + TextManager.Get(
"DeathChatNotification"); }
563 GameMain.NetworkMember.AddChatMessage(chatMessage.Value,
ChatMessageType.Dead);
564 GameMain.LightManager.LosEnabled =
false;
566 if (Screen.Selected?.Cam is Camera cam)
568 cam.TargetPos = Vector2.Zero;
571 cam.MovementLockTimer = 2.0f;
572 Lights.LightManager.ViewTarget =
null;
579 partial
void DisposeProjSpecific()
581 if (controlled ==
this)
584 if (Screen.Selected?.Cam is not
null)
586 Screen.Selected.Cam.TargetPos = Vector2.Zero;
587 Lights.LightManager.ViewTarget =
null;
591 sounds.ForEach(s => s.Sound?.Dispose());
594 if (GameMain.GameSession?.CrewManager !=
null &&
595 GameMain.GameSession.CrewManager.GetCharacters().Contains(
this))
597 GameMain.GameSession.CrewManager.RemoveCharacter(
this);
600 if (GameMain.Client?.Character ==
this) { GameMain.Client.Character =
null; }
602 if (Lights.LightManager.ViewTarget ==
this) { Lights.LightManager.ViewTarget =
null; }
605 private void UpdateInteractablesInRange()
608 previousInteractablesInRange.Clear();
609 previousInteractablesInRange.AddRange(interactablesInRange);
611 interactablesInRange.Clear();
616 foreach (MapEntity entity
in entityList)
618 if (entity is not Item item) {
continue; }
620 if (item.body !=
null && !item.body.Enabled) {
continue; }
622 if (item.ParentInventory !=
null) {
continue; }
624 if (item.Prefab.RequireCampaignInteract &&
625 item.CampaignInteractionType == CampaignMode.InteractionType.None)
630 if (Screen.Selected is SubEditorScreen { WiringMode: true } &&
638 interactablesInRange.Add(item);
642 if (!interactablesInRange.SequenceEqual(previousInteractablesInRange))
644 InteractionLabelManager.RefreshInteractablesInRange(interactablesInRange);
648 private readonly List<Item> debugInteractablesInRange =
new List<Item>();
649 private readonly List<Item> debugInteractablesAtCursor =
new List<Item>();
650 private readonly List<(
Item item,
float dist)> debugInteractablesNearCursor =
new List<(Item item,
float dist)>();
659 public Item FindClosestItem(List<Item> itemCollection, Vector2 simPosition,
float aimAssistModifier = 0.0f)
666 debugInteractablesInRange.Clear();
667 debugInteractablesAtCursor.Clear();
668 debugInteractablesNearCursor.Clear();
675 float aimAssistAmount =
SelectedItem ==
null ? 100.0f * aimAssistModifier : 1.0f;
677 Vector2 displayPosition = ConvertUnits.ToDisplayUnits(simPosition);
679 Item closestItem =
null;
680 float closestItemDistance = Math.Max(aimAssistAmount, 2.0f);
681 foreach (var item
in itemCollection)
683 if (draggingItemToWorld)
685 if (item.OwnInventory ==
null ||
686 !item.OwnInventory.Container.AllowDragAndDrop ||
694 float distanceToItem =
float.PositiveInfinity;
695 if (item.IsInsideTrigger(displayPosition, out
Rectangle transformedTrigger))
697 debugInteractablesAtCursor.Add(item);
700 Math.Abs(transformedTrigger.Center.X - displayPosition.X) / transformedTrigger.Width +
701 Math.Abs((transformedTrigger.Y - transformedTrigger.Height / 2.0f) - displayPosition.Y) / transformedTrigger.Height;
703 distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (transformedTrigger.Width + transformedTrigger.Height) / 250.0f);
705 else if (!item.Prefab.RequireCursorInsideTrigger)
707 Rectangle itemDisplayRect =
new Rectangle(item.InteractionRect.X, item.InteractionRect.Y - item.InteractionRect.Height, item.InteractionRect.Width, item.InteractionRect.Height);
709 if (itemDisplayRect.Contains(displayPosition))
711 debugInteractablesAtCursor.Add(item);
714 Math.Abs(itemDisplayRect.Center.X - displayPosition.X) / itemDisplayRect.Width +
715 Math.Abs(itemDisplayRect.Center.Y - displayPosition.Y) / itemDisplayRect.Height;
717 distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (itemDisplayRect.Width + itemDisplayRect.Height) / 250.0f);
721 if (closestItemDistance < 2.0f) {
continue; }
723 Vector2 rectIntersectionPoint =
new Vector2(
724 MathHelper.Clamp(displayPosition.X, itemDisplayRect.X, itemDisplayRect.Right),
725 MathHelper.Clamp(displayPosition.Y, itemDisplayRect.Y, itemDisplayRect.Bottom));
726 distanceToItem = 2.0f + Vector2.Distance(rectIntersectionPoint, displayPosition);
730 if (distanceToItem > closestItemDistance) {
continue; }
733 debugInteractablesNearCursor.Add((item, 1.0f - distanceToItem / (100.0f * aimAssistModifier)));
735 closestItemDistance = distanceToItem;
745 maxDist = ConvertUnits.ToSimUnits(maxDist);
746 float closestDist = maxDist;
749 if (!
CanInteractWith(c, checkVisibility:
false) || (c.AnimController?.SimplePhysicsEnabled ??
true)) {
continue; }
752 if (dist < closestDist ||
753 (c.CampaignInteractionType != CampaignMode.InteractionType.None && closestCharacter?.CampaignInteractionType == CampaignMode.InteractionType.None && dist * 0.9f < closestDist))
755 closestCharacter = c;
760 return closestCharacter;
765 if (
this != controlled) {
return false; }
771 controller?.User ==
this && controller.HideHUD &&
776 partial
void UpdateProjSpecific(
float deltaTime,
Camera cam)
780 bool wasPending = message.
Timer < 0.0f;
781 message.
Timer += deltaTime;
782 if (wasPending && message.
Timer >= 0.0f && message.PlaySound)
787 guiMessages.RemoveAll(m => m.Timer >= m.Lifetime);
789 if (textlessSpeechBubble !=
null)
791 textlessSpeechBubble.LifeTime -= deltaTime;
792 if (textlessSpeechBubble.LifeTime <= 0) { textlessSpeechBubble =
null; }
795 if (!enabled) {
return; }
805 switch (enemyAI.State)
808 if (Rand.Value() > 0.5f)
810 PlaySound(CharacterSound.SoundType.Attack);
814 PlaySound(CharacterSound.SoundType.Idle);
818 var petBehavior = enemyAI.PetBehavior;
819 if (petBehavior !=
null &&
820 (petBehavior.Happiness < petBehavior.UnhappyThreshold || petBehavior.Hunger > petBehavior.HungryThreshold))
822 PlaySound(CharacterSound.SoundType.Unhappy);
826 PlaySound(CharacterSound.SoundType.Idle);
838 if (controlled ==
null)
852 hudInfoVisible = controlled.CanSeeTarget(
this, controlled.ViewTarget);
859 if (controlled ==
this)
865 partial
void SetOrderProjSpecific(Order order)
867 GameMain.GameSession?.CrewManager?.AddCurrentOrderIcon(
this, order);
880 if (controlled ==
this)
909 public void DrawHUD(SpriteBatch spriteBatch,
Camera cam,
bool drawHealth =
true)
923 messagePos.Y += hudInfoHeight;
924 messagePos = cam.
WorldToScreen(messagePos) - Vector2.UnitY * GUI.IntScale(60);
925 foreach (GUIMessage message
in guiMessages)
927 if (message.Timer < 0) {
continue; }
928 Vector2 drawPos = messagePos + Vector2.UnitX * (GUI.IntScale(60) - message.Size.X);
929 drawPos =
new Vector2((
int)drawPos.X, (
int)drawPos.Y);
930 float alpha = MathHelper.SmoothStep(1.0f, 0.0f, message.Timer / message.Lifetime);
931 GUI.DrawString(spriteBatch, drawPos, message.Text, message.Color * alpha);
932 messagePos -= Vector2.UnitY * message.Size.Y * 1.2f;
945 if (GUI.DisableHUD) {
return; }
951 GameSettings.CurrentConfig.Graphics.LosMode !=
LosMode.None)
966 pos.Y += hudInfoHeight;
971 hudInfoHeight = MathHelper.Lerp(hudInfoHeight, 100.0f - lowerAmount, 0.1f);
972 hudInfoHeight = Math.Max(hudInfoHeight, 20.0f);
976 hudInfoHeight = MathHelper.Lerp(hudInfoHeight, 100.0f, 0.1f);
981 if (
this == controlled)
986 cursorPos.Y = -cursorPos.Y;
987 foreach (
Item item
in debugInteractablesAtCursor)
989 GUI.DrawLine(spriteBatch, cursorPos,
992 foreach (
Item item
in debugInteractablesInRange)
997 foreach ((
Item item,
float dist) in debugInteractablesNearCursor)
999 GUI.DrawLine(spriteBatch,
1002 ToolBox.GradientLerp(dist, GUIStyle.Red, GUIStyle.Orange, GUIStyle.Green), width: 2);
1009 float hoverRange = 300.0f;
1010 float fadeOutRange = 200.0f;
1012 float hudInfoAlpha =
1014 MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f) :
1018 (controlled ==
null ||
this != controlled.FocusedCharacter ||
IsPet) && cam.
Zoom > 0.4f)
1023 if (controlled ==
null && name !=
Info.
Name)
1025 name +=
" " + TextManager.Get(
"Disguised");
1032 Vector2 nameSize = GUIStyle.Font.MeasureString(name);
1033 Vector2 namePos =
new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.
Zoom)) - nameSize * 0.5f / cam.
Zoom;
1039 namePos *= screenSize / viewportSize;
1040 namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
1041 namePos *= viewportSize / screenSize;
1047 if (iconStyle !=
null)
1050 Vector2 iconPos = headPos;
1051 iconPos.Y = -iconPos.Y;
1052 nameColor = iconStyle.Color;
1054 float iconScale = (30.0f / icon.Sprite.size.X / cam.
Zoom) * GUI.Scale;
1055 icon.Sprite.Draw(spriteBatch, iconPos +
new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
1059 GUIStyle.Font.DrawString(spriteBatch, name, namePos +
new Vector2(1.0f / cam.
Zoom, 1.0f / cam.
Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.
Zoom, SpriteEffects.None, 0.001f);
1060 GUIStyle.Font.DrawString(spriteBatch, name, namePos, nameColor * hudInfoAlpha, 0.0f, Vector2.Zero, 1.0f / cam.
Zoom, SpriteEffects.None, 0.0f);
1063 GUIStyle.Font.DrawString(spriteBatch,
ID.ToString(), namePos -
new Vector2(0.0f, 20.0f), Color.White);
1071 var iconStyle = GUIStyle.GetComponentStyle(
"PetIcon." + petStatus);
1072 if (iconStyle !=
null)
1075 Vector2 iconPos = headPos;
1076 iconPos.Y = -iconPos.Y;
1078 float iconScale = 30.0f / icon.Sprite.size.X / cam.
Zoom;
1079 icon.Sprite.Draw(spriteBatch, iconPos +
new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
1086 var healthBarMode =
GameMain.
NetworkMember?.ServerSettings.ShowEnemyHealthBars ?? GameSettings.CurrentConfig.ShowEnemyHealthBars;
1107 Vector2 healthBarPos =
new Vector2(pos.X - 50, -pos.Y);
1108 GUI.DrawProgressBar(spriteBatch, healthBarPos,
new Vector2(100.0f, 15.0f),
1111 new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
1115 if (textlessSpeechBubble !=
null)
1117 Vector2 iconPos = pos - Vector2.UnitY * 5;
1119 GUIStyle.SpeechBubbleIcon.Value.Sprite.Draw(spriteBatch, iconPos,
1120 textlessSpeechBubble.Color * Math.Min(textlessSpeechBubble.LifeTime, 1.0f), 0.0f,
1121 Math.Min(textlessSpeechBubble.LifeTime, 1.0f));
1127 if (!GameSettings.CurrentConfig.ChatSpeechBubbles)
1132 float duration = MathHelper.Lerp(1.0f, 8.0f, Math.Min(text.Length / 100.0f, 1.0f));
1133 speechBubbles.Add(
new SpeechBubble(
this, duration, color, text));
1134 textlessSpeechBubble =
null;
1139 if (speechBubbles.Any(sb => sb.Character ==
this)) {
return; }
1140 if (textlessSpeechBubble ==
null)
1142 textlessSpeechBubble =
new SpeechBubble(
this, duration, color);
1146 textlessSpeechBubble.Color = color;
1147 textlessSpeechBubble.LifeTime = Math.Max(textlessSpeechBubble.LifeTime, duration);
1153 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.None,
null,
null, cam.
Transform);
1154 foreach (var bubble
in speechBubbles)
1156 Vector2 iconPos = Timing.Interpolate(bubble.PrevPosition, bubble.Position);
1157 iconPos += Vector2.UnitY * bubble.MoveUpAmount;
1158 if (bubble.Submarine !=
null)
1160 iconPos += bubble.Submarine.DrawPosition;
1166 float textSize = bubble.TextSize.Length();
1167 if (mouseDist < textSize)
1169 alpha *= Math.Max(mouseDist / textSize, 0.5f);
1172 iconPos.Y = -iconPos.Y;
1173 if (GUIStyle.SpeechBubbleIconSliced.Value is { } speechBubbleIconSliced)
1175 Vector2 bubbleSize = bubble.TextSize + Vector2.One * GUI.IntScale(15);
1176 speechBubbleIconSliced.Draw(spriteBatch,
new RectangleF(iconPos - bubbleSize / 2, bubbleSize), bubble.Color * Math.Min(bubble.LifeTime, 1.0f) * alpha);
1178 GUI.DrawString(spriteBatch, iconPos - bubble.TextSize / 2, bubble.Text, bubble.Color * Math.Min(bubble.LifeTime, 1.0f) * alpha, font: GUIStyle.SmallFont);
1183 static partial
void UpdateSpeechBubbles(
float deltaTime)
1185 for (
int i = speechBubbles.Count - 1; i >= 0; i--)
1187 var bubble = speechBubbles[i];
1188 bubble.LifeTime -= deltaTime;
1189 if (bubble.LifeTime <= 0 || bubble.Character is { Removed: true })
1191 speechBubbles.RemoveAt(i);
1195 bubble.PrevPosition = bubble.Position;
1197 Vector2 desiredPos = bubble.GetDesiredPosition();
1198 Vector2 diff = desiredPos - bubble.Position;
1199 float dist = diff.Length();
1201 const float MoveThreshold = 100.0f;
1202 const float MaxSpeed = 1000.0f;
1205 bubble.Moving =
false;
1207 else if (dist > MoveThreshold || bubble.Moving)
1209 Vector2 moveAmount = diff / dist * MathHelper.Clamp(dist * 5, 0, MaxSpeed) * deltaTime;
1212 moveAmount.Y *= 0.1f;
1213 bubble.Position += moveAmount;
1214 bubble.Moving =
true;
1217 bubble.MoveUpAmount += deltaTime * 5.0f;
1219 for (
int j = i + 1; j < speechBubbles.Count; j++)
1221 var otherBubble = speechBubbles[j];
1223 if (Math.Abs(bubble.Position.X - otherBubble.Position.X) < (bubble.TextSize.X + otherBubble.TextSize.X) / 2 &&
1224 Math.Abs(bubble.Position.Y - otherBubble.Position.Y) < (bubble.TextSize.Y + otherBubble.TextSize.Y) / 2 + 10)
1226 bubble.Position += Vector2.UnitY * deltaTime * 50.0f;
1236 if (
Info?.IsDisguisedAsAnother !=
null)
1252 Color nameColor = GUIStyle.TextColorNormal;
1261 nameColor = GUIStyle.Red;
1267 public void AddMessage(
string rawText, Color color,
bool playSound, Identifier identifier =
default,
int? value =
null,
float lifetime = 3.0f)
1269 GUIMessage existingMessage =
null;
1272 if (guiMessages.Any())
1274 delay = guiMessages.Min(m => m.Timer) - 0.5f;
1278 if (guiMessages.Count > 5)
1281 guiMessages.Where(m => m.Timer < 0.0f).ForEach(m => m.Timer *= 0.9f);
1290 if (identifier !=
null)
1292 existingMessage = guiMessages.Find(m => m.Identifier == identifier && m.Timer < m.Lifetime * 0.5f);
1294 if (existingMessage ==
null || !value.HasValue)
1296 var newMessage =
new GUIMessage(rawText, color, delay, identifier, value, lifetime);
1297 guiMessages.Insert(0, newMessage);
1302 newMessage.PlaySound =
true;
1312 existingMessage.Value += value.Value;
1322 if (controlled !=
this) {
return null; }
1324 if (!hudProgressBars.TryGetValue(linkedObject, out
HUDProgressBar progressBar))
1327 hudProgressBars.Add(linkedObject, progressBar);
1331 progressBar.TextTag = textTag;
1334 progressBar.WorldPosition = worldPosition;
1335 progressBar.FadeTimer = Math.Max(progressBar.FadeTimer, 1.0f);
1336 progressBar.Progress = progress;
1341 private readonly List<CharacterSound> matchingSounds =
new List<CharacterSound>();
1346 if (sounds ==
null || sounds.Count == 0) {
return; }
1347 if (soundChannel !=
null && soundChannel.
IsPlaying) {
return; }
1351 matchingSounds.Clear();
1352 foreach (var s
in sounds)
1354 if (s.Type == soundType && (s.TagSet.None() || (info !=
null && s.TagSet.IsSubsetOf(info.
Head.
Preset.
TagSet))))
1356 matchingSounds.Add(s);
1359 var selectedSound = matchingSounds.GetRandomUnsynced();
1360 if (selectedSound?.
Sound ==
null) {
return; }
1361 soundChannel = SoundPlayer.PlaySound(selectedSound.Sound,
AnimController.
WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess:
CurrentHull, ignoreMuffling: selectedSound.IgnoreMuffling);
1367 if (activeObjectiveEntities.Any(aoe => aoe.Entity == entity))
return;
1369 activeObjectiveEntities.Add(objectiveEntity);
1374 ObjectiveEntity found = activeObjectiveEntities.Find(aoe => aoe.Entity == entity);
1375 if (found ==
null)
return;
1376 activeObjectiveEntities.Remove(found);
1382 public CharacterSound GetSound(Func<CharacterSound, bool> predicate =
null,
bool random =
false) => random ? sounds.GetRandomUnsynced(predicate) : sounds.FirstOrDefault(predicate);
1384 partial
void ImplodeFX()
1390 for (
int i = 0; i < 10; i++)
1394 Rand.Vector(10.0f));
1395 if (p !=
null) p.
Size *= 2.0f;
1398 ConvertUnits.ToDisplayUnits(centerOfMass) + Rand.Vector(5.0f),
1399 new Vector2(Rand.Range(-50f, 50f), Rand.Range(-100f, 50f)));
1403 Rand.Range(0.0f, MathHelper.TwoPi),
1404 Rand.Range(200.0f, 700.0f),
null);
1407 for (
int i = 0; i < 30; i++)
1411 Rand.Range(0.0f, MathHelper.TwoPi),
1412 Rand.Range(50.0f, 500.0f),
null);
1416 partial
void OnMoneyChanged(
int prevAmount,
int newAmount) { }
1418 partial
void OnTalentGiven(TalentPrefab talentPrefab)
1420 AddMessage(TextManager.Get(
"talentname." + talentPrefab.Identifier).Value, GUIStyle.Yellow, playSound:
this ==
Controlled);
AIObjective CurrentObjective
Includes orders.
Vector2 WorldToScreen(Vector2 coords)
Vector2 ScreenToWorld(Vector2 coords)
bool??????? ShowCampaignUI
readonly AfflictionPrefab Affliction
readonly CauseOfDeathType Type
ObjectiveEntity(Entity entity, Sprite sprite, Color? color=null)
static void AddToGUIUpdateList(Character character)
static bool IsCampaignInterfaceOpen
static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
static bool ShouldDrawInventory(Character character)
static CharacterHealth?? OpenHealthWindow
void AddToGUIUpdateList()
void DrawHUD(SpriteBatch spriteBatch)
void UpdateHUD(float deltaTime)
void UpdateClientSpecific(float deltaTime)
readonly CharacterParams Params
void ShowTextlessSpeechBubble(float duration, Color color)
Character(CharacterPrefab prefab, Vector2 position, string seed, CharacterInfo characterInfo=null, ushort id=Entity.NullEntityID, bool isRemotePlayer=false, RagdollParams ragdollParams=null, bool spawnInitialItems=true)
CauseOfDeath CauseOfDeath
static void DrawSpeechBubbles(SpriteBatch spriteBatch, Camera cam)
CharacterHealth CharacterHealth
bool CanInteractWith(Character c, float maxDist=200.0f, bool checkVisibility=true, bool skipDistanceCheck=false)
virtual AIController AIController
void DoVisibilityCheck(Camera cam)
const float MaxHighlightDistance
CampaignMode.InteractionType CampaignInteractionType
bool ShowInteractionLabels
IEnumerable< ParticleEmitter > DamageEmitters
void AddActiveObjectiveEntity(Entity entity, Sprite sprite, Color? color=null)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
IEnumerable< ParticleEmitter > GibEmitters
static readonly List< Character > CharacterList
void RemoveActiveObjectiveEntity(Entity entity)
void EmulateInput(InputType input)
virtual void AddToGUIUpdateList()
float????? CameraShake
Can be used to set camera shake from status effects
void AddMessage(string rawText, Color color, bool playSound, Identifier identifier=default, int? value=null, float lifetime=3.0f)
override Vector2 DrawPosition
float ChromaticAberrationStrength
static bool DisableControls
float???????? CollapseEffectStrength
Can be used by status effects
bool CanAccessInventory(Inventory inventory, CharacterInventory.AccessLevel accessLevel=CharacterInventory.AccessLevel.Limited)
Dictionary< object, HUDProgressBar > HUDProgressBars
Item FindClosestItem(List< Item > itemCollection, Vector2 simPosition, float aimAssistModifier=0.0f)
Finds the front (lowest depth) interactable item at a position. "Interactable" in this case means tha...
float GetDistanceToClosestLimb(Vector2 simPos)
void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor=1.0f, float maxInterval=0)
static bool DebugDrawInteract
void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam=true)
Control the Character according to player input
void DoInteractionUpdate(float deltaTime, Vector2 mouseSimPos)
static Character? Controlled
static void AddAllToGUIUpdateList()
IEnumerable< ObjectiveEntity > ActiveObjectiveEntities
HUDProgressBar UpdateHUDProgressBar(object linkedObject, Vector2 worldPosition, float progress, Color emptyColor, Color fullColor, string textTag="")
Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's...
void UpdateLocalCursor(Camera cam)
bool IsVisible
Is the character currently visible on the camera. Refresh the value by calling DoVisibilityCheck.
Character FocusedCharacter
CharacterSound GetSound(Func< CharacterSound, bool > predicate=null, bool random=false)
Note that when a predicate is provided, the random option uses Linq.Where() extension method,...
virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
override Vector2 Position
void DrawGUIMessages(SpriteBatch spriteBatch, Camera cam)
void Draw(SpriteBatch spriteBatch, Camera cam)
void ShowSpeechBubble(Color color, string text)
readonly AnimController AnimController
float RadialDistortStrength
bool IsProtectedFromPressure
Is the character currently protected from the pressure by immunity/ability or a status effect (e....
void DrawHUD(SpriteBatch spriteBatch, Camera cam, bool drawHealth=true)
IEnumerable< ParticleEmitter > BloodEmitters
float lastRecvPositionUpdateTime
readonly HeadPreset Preset
ImmutableHashSet< Identifier > TagSet
readonly List< SoundParams > Sounds
virtual Vector2 WorldPosition
virtual Vector2 DrawPosition
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
Vector2 MeasureString(LocalizedString str, bool removeExtraSpacing=false)
static GameSession?? GameSession
static int GraphicsHeight
static NetworkMember NetworkMember
static ParticleManager ParticleManager
static Sounds.SoundManager SoundManager
AIObjectiveManager ObjectiveManager
static bool IsFriendly(Character me, Character other, bool onlySameTeam=false)
static bool IsMouseOnInventory
static readonly List< Item > DraggingItems
static bool DraggingItemToWorld
IEnumerable< ItemComponent > ActiveHUDs
List< ItemComponent > Components
Vector2 CollapseEffectOrigin
float CollapseEffectStrength
float ChromaticAberrationStrength
override Vector2 SimPosition
static void ShowDeathPromptIfNeeded(float delay=1.0f)
Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess=null, float collisionIgnoreTimer=0f, Tuple< Vector2, Vector2 > tracerPoints=null)
StatusIndicatorType GetCurrentStatusIndicatorType()
void DebugDraw(SpriteBatch spriteBatch)
void Draw(SpriteBatch spriteBatch, Camera cam)
bool? SimplePhysicsEnabled
Limb GetLimb(LimbType limbType, bool excludeSevered=true)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
Vector2 GetCenterOfMass()
Submarine(SubmarineInfo info, bool showErrorMessages=true, Func< Submarine, List< MapEntity >> loadEntities=null, IdRemap linkedRemap=null)
override Vector2? WorldPosition
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).
static IEnumerable< MapEntity > VisibleEntities
override Vector2 SimPosition
static float LastPickedFraction