Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/Source/Items/Item.cs
2019-03-27 20:52:47 +02:00

1086 lines
46 KiB
C#

using Barotrauma.Items.Components;
using Barotrauma.Networking;
using FarseerPhysics;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
{
public static bool ShowItems = true;
private readonly List<PosInfo> positionBuffer = new List<PosInfo>();
private List<ItemComponent> activeHUDs = new List<ItemComponent>();
public IEnumerable<ItemComponent> ActiveHUDs => activeHUDs;
class SpriteState
{
public float RotationState;
public float OffsetState;
public bool IsActive = true;
}
private Dictionary<ItemPrefab.DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<ItemPrefab.DecorativeSprite, SpriteState>();
private Sprite activeSprite;
public override Sprite Sprite
{
get { return activeSprite; }
}
private GUITextBlock itemInUseWarning;
private GUITextBlock ItemInUseWarning
{
get
{
if (itemInUseWarning == null)
{
itemInUseWarning = new GUITextBlock(new RectTransform(new Point(10), GUI.Canvas), "",
textColor: Color.Orange, color: Color.Black,
textAlignment:Alignment.Center, style: "OuterGlow");
}
return itemInUseWarning;
}
}
public override bool SelectableInEditor
{
get
{
return parentInventory == null && (body == null || body.Enabled) && ShowItems;
}
}
public float SpriteRotation;
public Color GetSpriteColor()
{
Color color = spriteColor;
if (Prefab.UseContainedSpriteColor && ownInventory != null)
{
for (int i = 0; i < ownInventory.Items.Length; i++)
{
if (ownInventory.Items[i] != null)
{
color = ownInventory.Items[i].ContainerColor;
break;
}
}
}
return color;
}
public Color GetInventoryIconColor()
{
Color color = InventoryIconColor;
if (Prefab.UseContainedInventoryIconColor && ownInventory != null)
{
for (int i = 0; i < ownInventory.Items.Length; i++)
{
if (ownInventory.Items[i] != null)
{
color = ownInventory.Items[i].ContainerColor;
break;
}
}
}
return color;
}
partial void SetActiveSprite()
{
activeSprite = prefab.sprite;
if (Container != null)
{
foreach (ContainedItemSprite containedSprite in Prefab.ContainedSprites)
{
if (containedSprite.MatchesContainer(Container))
{
activeSprite = containedSprite.Sprite;
return;
}
}
}
foreach (BrokenItemSprite brokenSprite in Prefab.BrokenSprites)
{
if (condition <= brokenSprite.MaxCondition)
{
activeSprite = brokenSprite.Sprite;
break;
}
}
}
partial void InitProjSpecific()
{
foreach (var decorativeSprite in ((ItemPrefab)prefab).DecorativeSprites)
{
spriteAnimState.Add(decorativeSprite, new SpriteState());
}
}
public override bool IsVisible(Rectangle worldView)
{
//no drawable components and the body has been disabled = nothing to draw
if (drawableComponents.Count == 0 && body != null && !body.Enabled)
{
return false;
}
float padding = 100.0f;
Vector2 size = new Vector2(rect.Width + padding, rect.Height + padding);
foreach (IDrawableComponent drawable in drawableComponents)
{
size.X = Math.Max(drawable.DrawSize.X, size.X);
size.Y = Math.Max(drawable.DrawSize.Y, size.Y);
}
size *= 0.5f;
Vector2 worldPosition = WorldPosition;
if (worldPosition.X - size.X > worldView.Right || worldPosition.X + size.X < worldView.X) return false;
if (worldPosition.Y + size.Y < worldView.Y - worldView.Height || worldPosition.Y - size.Y > worldView.Y) return false;
return true;
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!Visible || (!editing && hiddenInGame)) return;
if (editing && !ShowItems) return;
Color color = isHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? Color.Orange : GetSpriteColor();
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
Sprite activeSprite = prefab.sprite;
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
if (condition < Prefab.Health)
{
for (int i = 0; i < Prefab.BrokenSprites.Count; i++)
{
if (Prefab.BrokenSprites[i].FadeIn)
{
float min = i > 0 ? Prefab.BrokenSprites[i - i].MaxCondition : 0.0f;
float max = Prefab.BrokenSprites[i].MaxCondition;
fadeInBrokenSpriteAlpha = 1.0f - ((condition - min) / (max - min));
if (fadeInBrokenSpriteAlpha > 0.0f && fadeInBrokenSpriteAlpha < 1.0f)
{
fadeInBrokenSprite = Prefab.BrokenSprites[i];
}
continue;
}
if (condition <= Prefab.BrokenSprites[i].MaxCondition)
{
activeSprite = Prefab.BrokenSprites[i].Sprite;
break;
}
}
}
if (activeSprite != null)
{
SpriteEffects oldEffects = activeSprite.effects;
activeSprite.effects ^= SpriteEffects;
SpriteEffects oldBrokenSpriteEffects = SpriteEffects.None;
if (fadeInBrokenSprite != null)
{
oldBrokenSpriteEffects = fadeInBrokenSprite.Sprite.effects;
fadeInBrokenSprite.Sprite.effects ^= SpriteEffects;
}
float depth = GetDrawDepth();
if (body == null)
{
bool flipHorizontal = (SpriteEffects & SpriteEffects.FlipHorizontally) != 0;
bool flipVertical = (SpriteEffects & SpriteEffects.FlipVertically) != 0;
if (prefab.ResizeHorizontal || prefab.ResizeVertical)
{
activeSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)), new Vector2(rect.Width, rect.Height), color: color,
depth: depth);
fadeInBrokenSprite?.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)), new Vector2(rect.Width, rect.Height), color: color * fadeInBrokenSpriteAlpha,
depth: depth - 0.000001f);
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
decorativeSprite.Sprite.DrawTiled(spriteBatch,
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
new Vector2(rect.Width, rect.Height), color: color,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
}
else
{
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color, SpriteRotation, Scale, activeSprite.effects, depth);
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color * fadeInBrokenSpriteAlpha, SpriteRotation, Scale, activeSprite.effects, depth - 0.000001f);
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
SpriteRotation + rotation, Scale, activeSprite.effects,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
}
}
else if (body.Enabled)
{
var holdable = GetComponent<Holdable>();
if (holdable != null && holdable.Picker?.AnimController != null)
{
float depthStep = 0.000001f;
if (holdable.Picker.SelectedItems[0] == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightHand);
depth = holdLimb.ActiveSprite.Depth + depthStep * 2;
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
{
if (!wearableSprite.InheritLimbDepth && wearableSprite.Sprite != null) depth = Math.Max(wearableSprite.Sprite.Depth + depthStep, depth);
}
}
else if (holdable.Picker.SelectedItems[1] == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftHand);
depth = holdLimb.ActiveSprite.Depth - depthStep * 2;
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
{
if (!wearableSprite.InheritLimbDepth && wearableSprite.Sprite != null) depth = Math.Min(wearableSprite.Sprite.Depth - depthStep, depth);
}
}
}
body.Draw(spriteBatch, activeSprite, color, depth, Scale);
if (fadeInBrokenSprite != null) body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, depth - 0.000001f, Scale);
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
var ca = (float)Math.Cos(-body.Rotation);
var sa = (float)Math.Sin(-body.Rotation);
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + transformedOffset.X, -(DrawPosition.Y + transformedOffset.Y)), color,
-body.Rotation + rotation, Scale, activeSprite.effects,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
}
activeSprite.effects = oldEffects;
if (fadeInBrokenSprite != null)
{
fadeInBrokenSprite.Sprite.effects = oldEffects;
}
}
//use a backwards for loop because the drawable components may disable drawing,
//causing them to be removed from the list
for (int i = drawableComponents.Count - 1; i >= 0; i--)
{
drawableComponents[i].Draw(spriteBatch, editing);
}
if (GameMain.DebugDraw)
{
aiTarget?.Draw(spriteBatch);
var containedItems = ContainedItems;
if (containedItems != null)
{
foreach (Item item in containedItems)
{
item.AiTarget?.Draw(spriteBatch);
}
}
}
if (!editing || (body != null && !body.Enabled))
{
return;
}
if (IsSelected || IsHighlighted)
{
GUI.DrawRectangle(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)), new Vector2(rect.Width, rect.Height),
Color.White, false, 0, thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
foreach (Rectangle t in Prefab.Triggers)
{
Rectangle transformedTrigger = TransformTrigger(t);
Vector2 rectWorldPos = new Vector2(transformedTrigger.X, transformedTrigger.Y);
if (Submarine != null) rectWorldPos += Submarine.Position;
rectWorldPos.Y = -rectWorldPos.Y;
GUI.DrawRectangle(spriteBatch,
rectWorldPos,
new Vector2(transformedTrigger.Width, transformedTrigger.Height),
Color.Green,
false,
0,
(int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
}
}
if (!ShowLinks) return;
foreach (MapEntity e in linkedTo)
{
bool isLinkAllowed = prefab.IsLinkAllowed(e.prefab);
Color lineColor = Color.Red * 0.5f;
if (isLinkAllowed)
{
lineColor = e is Item i && (DisplaySideBySideWhenLinked || i.DisplaySideBySideWhenLinked) ? Color.Purple * 0.5f : Color.LightGreen * 0.5f;
}
Vector2 from = new Vector2(WorldPosition.X, -WorldPosition.Y);
Vector2 to = new Vector2(e.WorldPosition.X, -e.WorldPosition.Y);
GUI.DrawLine(spriteBatch, from, to, lineColor * 0.25f, width: 3);
GUI.DrawLine(spriteBatch, from, to, lineColor, width: 1);
//GUI.DrawString(spriteBatch, from, $"Linked to {e.Name}", lineColor, Color.Black * 0.5f);
}
}
public void UpdateSpriteStates(float deltaTime)
{
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
{
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
{
var decorativeSprite = Prefab.DecorativeSpriteGroups[spriteGroup][i];
if (decorativeSprite == null) { continue; }
if (spriteGroup > 0)
{
int activeSpriteIndex = ID % Prefab.DecorativeSpriteGroups[spriteGroup].Count;
if (i != activeSpriteIndex)
{
spriteAnimState[decorativeSprite].IsActive = false;
continue;
}
}
//check if the sprite is active (whether it should be drawn or not)
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = true;
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
{
if (!ConditionalMatches(conditional))
{
spriteState.IsActive = false;
break;
}
}
if (!spriteState.IsActive) { continue; }
//check if the sprite should be animated
bool animate = true;
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
{
if (!ConditionalMatches(conditional)) { animate = false; break; }
}
if (!animate) { continue; }
spriteState.OffsetState += deltaTime;
spriteState.RotationState += deltaTime;
bool ConditionalMatches(PropertyConditional conditional)
{
if (string.IsNullOrEmpty(conditional.TargetItemComponentName))
{
if (!conditional.Matches(this)) { return false; }
}
else
{
foreach (ItemComponent component in components)
{
if (component.Name != conditional.TargetItemComponentName) { continue; }
if (!conditional.Matches(component)) { return false; }
}
}
return true;
}
}
}
}
public override void UpdateEditing(Camera cam)
{
if (editingHUD == null || editingHUD.UserData as Item != this)
{
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
}
if (Screen.Selected != GameMain.SubEditorScreen) return;
if (Character.Controlled == null) activeHUDs.Clear();
if (!Linkable) return;
if (!PlayerInput.KeyDown(Keys.Space)) return;
bool lClick = PlayerInput.LeftButtonClicked();
bool rClick = PlayerInput.RightButtonClicked();
if (!lClick && !rClick) return;
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
var otherEntity = mapEntityList.FirstOrDefault(e => e != this && e.IsHighlighted && e.IsMouseOn(position));
if (otherEntity != null)
{
if (linkedTo.Contains(otherEntity))
{
linkedTo.Remove(otherEntity);
if (otherEntity.linkedTo != null && otherEntity.linkedTo.Contains(this)) otherEntity.linkedTo.Remove(this);
}
else
{
linkedTo.Add(otherEntity);
if (otherEntity.Linkable && otherEntity.linkedTo != null) otherEntity.linkedTo.Add(this);
}
}
}
public GUIComponent CreateEditingHUD(bool inGame = false)
{
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null)
{
Spacing = 5
};
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true);
if (!inGame)
{
if (Linkable)
{
var linkText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("HoldToLink"), font: GUI.SmallFont);
var itemsText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("AllowedLinks") + ": ", font: GUI.SmallFont);
if (AllowedLinks.None())
{
itemsText.Text += TextManager.Get("None");
}
};
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
{
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
OnClicked = (button, data) =>
{
for (int i = 0; i < AllowedLinks.Count; i++)
{
itemsText.Text += AllowedLinks[i];
if (i < AllowedLinks.Count - 1)
{
itemsText.Text += ", ";
}
}
}
itemEditor.AddCustomContent(linkText, 1);
itemEditor.AddCustomContent(itemsText, 2);
linkText.TextColor = Color.Yellow;
itemsText.TextColor = Color.Yellow;
}
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, 20)), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.02f
};
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"))
{
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
OnClicked = (button, data) =>
{
FlipX(relativeToSub: false);
return true;
}
};
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
{
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
OnClicked = (button, data) =>
{
FlipY(relativeToSub: false);
return true;
}
};
if (Sprite != null)
{
var reloadTextureButton = new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ReloadSprite"));
reloadTextureButton.OnClicked += (button, data) =>
{
Sprite.ReloadXML();
Sprite.ReloadTexture();
return true;
};
}
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ResetToPrefab"))
{
OnClicked = (button, data) =>
{
Reset();
CreateEditingHUD();
return true;
}
};
itemEditor.AddCustomContent(buttonContainer, itemEditor.ContentCount);
}
foreach (ItemComponent ic in components)
{
if (inGame)
{
if (!ic.AllowInGameEditing) continue;
if (SerializableProperty.GetProperties<InGameEditable>(ic).Count == 0) continue;
}
else
{
if (ic.requiredItems.Count == 0 && SerializableProperty.GetProperties<Editable>(ic).Count == 0) continue;
}
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame);
if (inGame) continue;
foreach (var kvp in ic.requiredItems)
{
foreach (RelatedItem relatedItem in kvp.Value)
{
var textBlock = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)),
relatedItem.Type.ToString() + " required", font: GUI.SmallFont)
{
Padding = new Vector4(10.0f, 0.0f, 10.0f, 0.0f)
};
componentEditor.AddCustomContent(textBlock, 1);
GUITextBox namesBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight))
{
Font = GUI.SmallFont,
Text = relatedItem.JoinedIdentifiers
};
namesBox.OnDeselected += (textBox, key) =>
{
relatedItem.JoinedIdentifiers = textBox.Text;
textBox.Text = relatedItem.JoinedIdentifiers;
};
namesBox.OnEnterPressed += (textBox, text) =>
{
relatedItem.JoinedIdentifiers = text;
textBox.Text = relatedItem.JoinedIdentifiers;
return true;
};
}
}
}
PositionEditingHUD();
SetHUDLayout();
return editingHUD;
}
/// <summary>
/// Reposition currently active item interfaces to make sure they don't overlap with each other
/// </summary>
private void SetHUDLayout()
{
//reset positions first
List<GUIComponent> elementsToMove = new List<GUIComponent>();
if (editingHUD != null && editingHUD.UserData == this)
{
elementsToMove.Add(editingHUD);
}
foreach (ItemComponent ic in activeHUDs)
{
if (ic.GuiFrame == null || ic.AllowUIOverlap || ic.GetLinkUIToComponent() != null) continue;
ic.GuiFrame.RectTransform.ScreenSpaceOffset = Point.Zero;
elementsToMove.Add(ic.GuiFrame);
}
List<Rectangle> disallowedAreas = new List<Rectangle>();
if (GameMain.GameSession?.CrewManager != null)
{
disallowedAreas.Add(GameMain.GameSession.CrewManager.GetCharacterListArea());
}
GUI.PreventElementOverlap(elementsToMove, disallowedAreas,
new Rectangle(
20, 20,
GameMain.GraphicsWidth - 40,
HUDLayoutSettings.InventoryTopY > 0 ? HUDLayoutSettings.InventoryTopY - 20 : GameMain.GraphicsHeight - 80));
foreach (ItemComponent ic in activeHUDs)
{
if (ic.GuiFrame == null) continue;
var linkUIToComponent = ic.GetLinkUIToComponent();
if (linkUIToComponent == null) continue;
ic.GuiFrame.RectTransform.ScreenSpaceOffset = linkUIToComponent.GuiFrame.RectTransform.ScreenSpaceOffset;
}
}
public void UpdateHUD(Camera cam, Character character, float deltaTime)
{
bool editingHUDCreated = false;
if (HasInGameEditableProperties ||
Screen.Selected == GameMain.SubEditorScreen)
{
GUIComponent prevEditingHUD = editingHUD;
UpdateEditing(cam);
editingHUDCreated = editingHUD != null && editingHUD != prevEditingHUD;
}
List<ItemComponent> prevActiveHUDs = new List<ItemComponent>(activeHUDs);
List<ItemComponent> activeComponents = new List<ItemComponent>(components);
foreach (MapEntity entity in linkedTo)
{
if (prefab.IsLinkAllowed(entity.prefab) && entity is Item i)
{
if (!i.DisplaySideBySideWhenLinked) continue;
activeComponents.AddRange(i.components);
}
}
activeHUDs.Clear();
//the HUD of the component with the highest priority will be drawn
//if all components have a priority of 0, all of them are drawn
List<ItemComponent> maxPriorityHUDs = new List<ItemComponent>();
foreach (ItemComponent ic in activeComponents)
{
if (ic.CanBeSelected && ic.HudPriority > 0 && ic.ShouldDrawHUD(character) &&
(maxPriorityHUDs.Count == 0 || ic.HudPriority >= maxPriorityHUDs[0].HudPriority))
{
if (maxPriorityHUDs.Count > 0 && ic.HudPriority > maxPriorityHUDs[0].HudPriority) maxPriorityHUDs.Clear();
maxPriorityHUDs.Add(ic);
}
}
if (maxPriorityHUDs.Count > 0)
{
activeHUDs.AddRange(maxPriorityHUDs);
}
else
{
foreach (ItemComponent ic in activeComponents)
{
if (ic.CanBeSelected && ic.ShouldDrawHUD(character)) activeHUDs.Add(ic);
}
}
//active HUDs have changed, need to reposition
if (!prevActiveHUDs.SequenceEqual(activeHUDs) || editingHUDCreated)
{
SetHUDLayout();
}
Rectangle mergedHUDRect = Rectangle.Empty;
foreach (ItemComponent ic in activeHUDs)
{
ic.UpdateHUD(character, deltaTime, cam);
if (ic.GuiFrame != null && ic.GuiFrame.Rect.Height < GameMain.GraphicsHeight)
{
mergedHUDRect = mergedHUDRect == Rectangle.Empty ?
ic.GuiFrame.Rect :
Rectangle.Union(mergedHUDRect, ic.GuiFrame.Rect);
}
}
if (itemInUseWarning != null && mergedHUDRect != Rectangle.Empty)
{
itemInUseWarning.Visible = false;
foreach (Character otherCharacter in Character.CharacterList)
{
if (otherCharacter != character &&
otherCharacter.SelectedConstruction == character.SelectedConstruction)
{
ItemInUseWarning.Visible = true;
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
itemInUseWarning.RectTransform.ScreenSpaceOffset = new Point(mergedHUDRect.X, mergedHUDRect.Bottom);
itemInUseWarning.RectTransform.NonScaledSize = new Point(mergedHUDRect.Width, (int)(50 * GUI.Scale));
if (itemInUseWarning.UserData != otherCharacter)
{
itemInUseWarning.Text = TextManager.Get("ItemInUse").Replace("[character]", otherCharacter.Name);
itemInUseWarning.UserData = otherCharacter;
}
break;
}
}
}
}
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
{
if (HasInGameEditableProperties)
{
DrawEditing(spriteBatch, cam);
}
foreach (ItemComponent ic in activeHUDs)
{
if (ic.CanBeSelected)
{
ic.DrawHUD(spriteBatch, character);
}
}
}
public override void AddToGUIUpdateList()
{
AddToGUIUpdateList(addLinkedHUDs: true);
}
private void AddToGUIUpdateList(bool addLinkedHUDs)
{
if (Screen.Selected is SubEditorScreen)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
}
else
{
if (HasInGameEditableProperties)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
}
}
if (Character.Controlled != null && Character.Controlled?.SelectedConstruction != this) return;
bool needsLayoutUpdate = false;
foreach (ItemComponent ic in activeHUDs)
{
if (!ic.CanBeSelected) { continue; }
bool useAlternativeLayout = ic.Item != this;
bool wasUsingAlternativeLayout = ic.UseAlternativeLayout;
ic.UseAlternativeLayout = useAlternativeLayout;
needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout;
ic.AddToGUIUpdateList();
}
if (itemInUseWarning != null && itemInUseWarning.Visible)
{
itemInUseWarning.AddToGUIUpdateList();
}
if (needsLayoutUpdate)
{
SetHUDLayout();
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
if (type == ServerNetObject.ENTITY_POSITION)
{
ClientReadPosition(type, msg, sendingTime);
return;
}
NetEntityEvent.Type eventType =
(NetEntityEvent.Type)msg.ReadRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
switch (eventType)
{
case NetEntityEvent.Type.ComponentState:
{
int componentIndex = msg.ReadRangedInteger(0, components.Count - 1);
(components[componentIndex] as IServerSerializable).ClientRead(type, msg, sendingTime);
}
break;
case NetEntityEvent.Type.InventoryState:
{
int containerIndex = msg.ReadRangedInteger(0, components.Count - 1);
(components[containerIndex] as ItemContainer).Inventory.ClientRead(type, msg, sendingTime);
}
break;
case NetEntityEvent.Type.Status:
float prevCondition = condition;
condition = msg.ReadSingle();
if (prevCondition > 0.0f && condition <= 0.0f)
{
ApplyStatusEffects(ActionType.OnBroken, 1.0f);
foreach (ItemComponent ic in components)
{
ic.PlaySound(ActionType.OnBroken, WorldPosition);
}
}
break;
case NetEntityEvent.Type.ApplyStatusEffect:
{
ActionType actionType = (ActionType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ActionType)).Length - 1);
byte componentIndex = msg.ReadByte();
ushort targetID = msg.ReadUInt16();
byte targetLimbID = msg.ReadByte();
ItemComponent targetComponent = componentIndex < components.Count ? components[componentIndex] : null;
Character target = FindEntityByID(targetID) as Character;
Limb targetLimb = target != null && targetLimbID < target.AnimController.Limbs.Length ? target.AnimController.Limbs[targetLimbID] : null;
if (targetComponent == null)
{
ApplyStatusEffects(actionType, 1.0f, target, targetLimb, true);
}
else
{
targetComponent.ApplyStatusEffects(actionType, 1.0f, target, targetLimb);
}
}
break;
case NetEntityEvent.Type.ChangeProperty:
ReadPropertyChange(msg, false);
break;
case NetEntityEvent.Type.Invalid:
break;
}
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
if (extraData == null || extraData.Length == 0 || !(extraData[0] is NetEntityEvent.Type))
{
return;
}
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
msg.WriteRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
switch (eventType)
{
case NetEntityEvent.Type.ComponentState:
int componentIndex = (int)extraData[1];
msg.WriteRangedInteger(0, components.Count - 1, componentIndex);
(components[componentIndex] as IClientSerializable).ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.InventoryState:
int containerIndex = (int)extraData[1];
msg.WriteRangedInteger(0, components.Count - 1, containerIndex);
(components[containerIndex] as ItemContainer).Inventory.ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.Treatment:
UInt16 characterID = (UInt16)extraData[1];
Limb targetLimb = (Limb)extraData[2];
Character targetCharacter = FindEntityByID(characterID) as Character;
msg.Write(characterID);
msg.Write(targetCharacter == null ? (byte)255 : (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb));
break;
case NetEntityEvent.Type.ChangeProperty:
WritePropertyChange(msg, extraData, true);
break;
}
msg.WritePadBits();
}
partial void UpdateNetPosition(float deltaTime)
{
if (GameMain.Client == null) { return; }
if (parentInventory != null || body == null || !body.Enabled || Removed)
{
return;
}
Vector2 newVelocity = body.LinearVelocity;
Vector2 newPosition = body.SimPosition;
float newAngularVelocity = body.AngularVelocity;
float newRotation = body.Rotation;
body.CorrectPosition(positionBuffer, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);
body.LinearVelocity = newVelocity;
body.AngularVelocity = newAngularVelocity;
if (Vector2.DistanceSquared(newPosition, body.SimPosition) > 0.0001f ||
Math.Abs(newRotation - body.Rotation) > 0.01f)
{
body.TargetPosition = newPosition;
body.TargetRotation = newRotation;
body.MoveToTargetPosition(lerp: true);
}
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
}
public void ClientReadPosition(ServerNetObject type, NetBuffer msg, float sendingTime)
{
if (body == null)
{
DebugConsole.ThrowError("Received a position update for an item with no physics body (" + Name + ")");
return;
}
var posInfo = body.ClientRead(type, msg, sendingTime, parentDebugName: Name);
msg.ReadPadBits();
if (posInfo != null)
{
int index = 0;
while (index < positionBuffer.Count && sendingTime > positionBuffer[index].Timestamp)
{
index++;
}
positionBuffer.Insert(index, posInfo);
}
/*body.FarseerBody.Awake = awake;
if (body.FarseerBody.Awake)
{
if ((newVelocity - body.LinearVelocity).LengthSquared() > 8.0f * 8.0f) body.LinearVelocity = newVelocity;
}
else
{
try
{
body.FarseerBody.Enabled = false;
}
catch (Exception e)
{
DebugConsole.ThrowError("Exception in PhysicsBody.Enabled = false (" + body.PhysEnabled + ")", e);
if (body.UserData != null) DebugConsole.NewMessage("PhysicsBody UserData: " + body.UserData.GetType().ToString(), Color.Red);
if (GameMain.World.ContactManager == null) DebugConsole.NewMessage("ContactManager is null!", Color.Red);
else if (GameMain.World.ContactManager.BroadPhase == null) DebugConsole.NewMessage("Broadphase is null!", Color.Red);
if (body.FarseerBody.FixtureList == null) DebugConsole.NewMessage("FixtureList is null!", Color.Red);
}
}
if ((newPosition - SimPosition).Length() > body.LinearVelocity.Length() * 2.0f)
{
if (body.SetTransform(newPosition, newRotation))
{
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
}
}*/
}
public void CreateClientEvent<T>(T ic) where T : ItemComponent, IClientSerializable
{
if (GameMain.Client == null) return;
int index = components.IndexOf(ic);
if (index == -1) return;
GameMain.Client.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.ComponentState, index });
}
public static Item ReadSpawnData(NetBuffer msg, bool spawn = true)
{
string itemName = msg.ReadString();
string itemIdentifier = msg.ReadString();
bool descriptionChanged = msg.ReadBoolean();
string itemDesc = "";
if (descriptionChanged)
{
itemDesc = msg.ReadString();
}
ushort itemId = msg.ReadUInt16();
ushort inventoryId = msg.ReadUInt16();
DebugConsole.Log("Received entity spawn message for item " + itemName + ".");
Vector2 pos = Vector2.Zero;
Submarine sub = null;
int itemContainerIndex = -1;
int inventorySlotIndex = -1;
if (inventoryId > 0)
{
itemContainerIndex = msg.ReadByte();
inventorySlotIndex = msg.ReadByte();
}
else
{
pos = new Vector2(msg.ReadSingle(), msg.ReadSingle());
ushort subID = msg.ReadUInt16();
if (subID > 0)
{
sub = Submarine.Loaded.Find(s => s.ID == subID);
}
}
byte teamID = msg.ReadByte();
bool tagsChanged = msg.ReadBoolean();
string tags = "";
if (tagsChanged)
{
tags = msg.ReadString();
}
if (!spawn) return null;
//----------------------------------------
var itemPrefab = MapEntityPrefab.Find(itemName, itemIdentifier) as ItemPrefab;
if (itemPrefab == null) return null;
Inventory inventory = null;
var inventoryOwner = FindEntityByID(inventoryId);
if (inventoryOwner != null)
{
if (inventoryOwner is Character)
{
inventory = (inventoryOwner as Character).Inventory;
}
else if (inventoryOwner is Item)
{
if ((inventoryOwner as Item).components[itemContainerIndex] is ItemContainer container)
{
inventory = container.Inventory;
}
}
}
var item = new Item(itemPrefab, pos, sub)
{
ID = itemId
};
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
{
wifiComponent.TeamID = (Character.TeamType)teamID;
}
if (descriptionChanged) item.Description = itemDesc;
if (tagsChanged) item.Tags = tags;
if (sub != null)
{
item.CurrentHull = Hull.FindHull(pos + sub.Position, null, true);
item.Submarine = item.CurrentHull?.Submarine;
}
if (inventory != null)
{
if (inventorySlotIndex >= 0 && inventorySlotIndex < 255 &&
inventory.TryPutItem(item, inventorySlotIndex, false, false, null, false))
{
return null;
}
inventory.TryPutItem(item, null, item.AllowedSlots, false);
}
return item;
}
partial void RemoveProjSpecific()
{
if (Inventory.draggingItem == this)
{
Inventory.draggingItem = null;
Inventory.draggingSlot = null;
}
}
}
}