Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/Source/Items/Item.cs

511 lines
21 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;
namespace Barotrauma
{
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
{
public override Sprite Sprite
{
get { return prefab.GetActiveSprite(condition); }
}
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].spriteColor;
break;
}
}
}
return color;
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!Visible) return;
Color color = (IsSelected && editing) ? Color.Red : GetSpriteColor();
if (isHighlighted) color = Color.Orange;
Sprite activeSprite = prefab.sprite;
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
if (condition < 100.0f)
{
for (int i = 0; i < prefab.BrokenSprites.Count; i++)
{
if (condition <= prefab.BrokenSprites[i].MaxCondition)
{
activeSprite = prefab.BrokenSprites[i].Sprite;
break;
}
if (prefab.BrokenSprites[i].FadeIn)
{
float min = i > 0 ? prefab.BrokenSprites[i].MaxCondition : 0.0f;
float max = i < prefab.BrokenSprites.Count - 1 ? prefab.BrokenSprites[i + 1].MaxCondition : 100.0f;
fadeInBrokenSpriteAlpha = 1.0f - ((condition - min) / (max - min));
if (fadeInBrokenSpriteAlpha > 0.0f && fadeInBrokenSpriteAlpha < 1.0f)
{
fadeInBrokenSprite = prefab.BrokenSprites[i];
}
}
}
}
Sprite selectedSprite = prefab.GetActiveSprite(condition);
if (selectedSprite != null)
{
SpriteEffects oldEffects = selectedSprite.effects;
selectedSprite.effects ^= SpriteEffects;
float depth = GetDrawDepth();
if (body == null)
{
if (prefab.ResizeHorizontal || prefab.ResizeVertical || SpriteEffects.HasFlag(SpriteEffects.FlipHorizontally) || SpriteEffects.HasFlag(SpriteEffects.FlipVertically))
{
selectedSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)), new Vector2(rect.Width, rect.Height), color: color);
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: selectedSprite.Depth - 0.000001f);
}
else
{
selectedSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color, 0.0f, 1.0f, SpriteEffects.None, depth);
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color * fadeInBrokenSpriteAlpha, 0.0f, 1.0f, SpriteEffects.None, depth - 0.000001f);
}
}
else if (body.Enabled)
{
var holdable = GetComponent<Holdable>();
if (holdable != null && holdable.Picker?.AnimController != null)
{
if (holdable.Picker.SelectedItems[0] == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightHand);
depth = holdLimb.sprite.Depth + 0.000001f;
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
{
if (!wearableSprite.InheritLimbDepth && wearableSprite.Sprite != null) depth = Math.Min(wearableSprite.Sprite.Depth, depth);
}
}
else if (holdable.Picker.SelectedItems[1] == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftHand);
depth = holdLimb.sprite.Depth - 0.000001f;
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
{
if (!wearableSprite.InheritLimbDepth && wearableSprite.Sprite != null) depth = Math.Max(wearableSprite.Sprite.Depth, depth);
}
}
}
body.Draw(spriteBatch, selectedSprite, color, depth);
if (fadeInBrokenSprite != null) body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, depth - 0.000001f);
}
selectedSprite.effects = oldEffects;
}
List<IDrawableComponent> staticDrawableComponents = new List<IDrawableComponent>(drawableComponents); //static list to compensate for drawable toggling
for (int i = 0; i < staticDrawableComponents.Count; i++)
{
staticDrawableComponents[i].Draw(spriteBatch, editing);
}
if (GameMain.DebugDraw && aiTarget != null) 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.Green, false, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
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)
{
GUI.DrawLine(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
new Vector2(e.WorldPosition.X, -e.WorldPosition.Y),
Color.Red * 0.3f);
}
}
public override void UpdateEditing(Camera cam)
{
if (editingHUD == null || editingHUD.UserData as Item != this)
{
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
}
editingHUD.Update((float)Timing.Step);
if (Screen.Selected != GameMain.SubEditorScreen) return;
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);
if (lClick)
{
foreach (MapEntity entity in mapEntityList)
{
if (entity == this || !entity.IsHighlighted) continue;
if (linkedTo.Contains(entity)) continue;
if (!entity.IsMouseOn(position)) continue;
linkedTo.Add(entity);
if (entity.Linkable && entity.linkedTo != null) entity.linkedTo.Add(this);
}
}
else
{
foreach (MapEntity entity in mapEntityList)
{
if (entity == this || !entity.IsHighlighted) continue;
if (!linkedTo.Contains(entity)) continue;
if (!entity.IsMouseOn(position)) continue;
linkedTo.Remove(entity);
if (entity.linkedTo != null && entity.linkedTo.Contains(this)) entity.linkedTo.Remove(this);
}
}
}
public override void DrawEditing(SpriteBatch spriteBatch, Camera cam)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.Draw(spriteBatch);
}
private GUIComponent CreateEditingHUD(bool inGame = false)
{
int width = 450;
int height = 150;
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30;
editingHUD = new GUIListBox(new Rectangle(x, y, width, height), "");
editingHUD.UserData = this;
GUIListBox listBox = (GUIListBox)editingHUD;
listBox.Spacing = 5;
var itemEditor = new SerializableEntityEditor(this, inGame, editingHUD, true);
if (!inGame && Linkable)
{
itemEditor.AddCustomContent(new GUITextBlock(new Rectangle(0, 0, 0, 20), "Hold space to link to another item", "", null, GUI.SmallFont), 1);
}
foreach (ItemComponent ic in components)
{
if (ic.requiredItems.Count == 0)
{
if (inGame)
{
if (SerializableProperty.GetProperties<InGameEditable>(ic).Count == 0) continue;
}
else
{
if (SerializableProperty.GetProperties<Editable>(ic).Count == 0) continue;
}
}
var componentEditor = new SerializableEntityEditor(ic, inGame, editingHUD, !inGame);
if (inGame) continue;
foreach (RelatedItem relatedItem in ic.requiredItems)
{
var textBlock = new GUITextBlock(new Rectangle(0, 0, 0, 20), relatedItem.Type.ToString() + " required", "", Alignment.TopLeft, Alignment.CenterLeft, null, false, GUI.SmallFont);
textBlock.Padding = new Vector4(10.0f, 0.0f, 10.0f, 0.0f);
componentEditor.AddCustomContent(textBlock, 1);
GUITextBox namesBox = new GUITextBox(new Rectangle(0, 0, 180, 20), Alignment.Right, "", textBlock);
namesBox.Font = GUI.SmallFont;
namesBox.Text = relatedItem.JoinedNames;
namesBox.OnDeselected += (textBox, key) =>
{
relatedItem.JoinedNames = textBox.Text;
textBox.Text = relatedItem.JoinedNames;
};
namesBox.OnEnterPressed += (textBox, text) =>
{
relatedItem.JoinedNames = text;
textBox.Text = relatedItem.JoinedNames;
return true;
};
y += 20;
}
}
int contentHeight = (int)(editingHUD.children.Sum(c => c.Rect.Height) + (listBox.children.Count - 1) * listBox.Spacing + listBox.Padding.Y + listBox.Padding.W);
editingHUD.SetDimensions(new Point(editingHUD.Rect.Width, MathHelper.Clamp(contentHeight, 50, editingHUD.Rect.Height)));
return editingHUD;
}
public virtual void UpdateHUD(Camera cam, Character character)
{
if (condition <= 0.0f)
{
FixRequirement.UpdateHud(this, character);
return;
}
if (HasInGameEditableProperties)
{
UpdateEditing(cam);
}
foreach (ItemComponent ic in components)
{
if (ic.CanBeSelected) ic.UpdateHUD(character);
}
}
public virtual void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
{
if (condition <= 0.0f)
{
FixRequirement.DrawHud(spriteBatch, this, character);
return;
}
if (HasInGameEditableProperties)
{
DrawEditing(spriteBatch, cam);
}
foreach (ItemComponent ic in components)
{
if (ic.CanBeSelected) ic.DrawHUD(spriteBatch, character);
}
}
public override void AddToGUIUpdateList()
{
if (Screen.Selected is SubEditorScreen)
{
if (editingHUD != null) editingHUD.AddToGUIUpdateList();
}
else
{
if (HasInGameEditableProperties)
{
if (editingHUD != null) editingHUD.AddToGUIUpdateList();
}
}
if (Character.Controlled != null && Character.Controlled.SelectedConstruction == this)
{
if (condition <= 0.0f)
{
FixRequirement.AddToGUIUpdateList();
return;
}
foreach (ItemComponent ic in components)
{
if (ic.CanBeSelected) ic.AddToGUIUpdateList();
}
}
}
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:
ownInventory.ClientRead(type, msg, sendingTime);
break;
case NetEntityEvent.Type.Status:
condition = msg.ReadRangedSingle(0.0f, prefab.Health, 8);
if (FixRequirements.Count > 0)
{
if (Condition <= 0.0f)
{
for (int i = 0; i < FixRequirements.Count; i++)
FixRequirements[i].Fixed = msg.ReadBoolean();
}
else
{
for (int i = 0; i < FixRequirements.Count; i++)
FixRequirements[i].Fixed = true;
}
}
break;
case NetEntityEvent.Type.ApplyStatusEffect:
ActionType actionType = (ActionType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ActionType)).Length - 1);
ushort targetID = msg.ReadUInt16();
Character target = FindEntityByID(targetID) as Character;
ApplyStatusEffects(actionType, (float)Timing.Step, target, true);
break;
case NetEntityEvent.Type.ChangeProperty:
ReadPropertyChange(msg);
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:
ownInventory.ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.Repair:
if (FixRequirements.Count > 0)
{
int requirementIndex = (int)extraData[1];
msg.WriteRangedInteger(0, FixRequirements.Count - 1, requirementIndex);
}
break;
case NetEntityEvent.Type.ApplyStatusEffect:
//no further data needed, the server applies the effect
//on the character of the client who sent the message
break;
case NetEntityEvent.Type.ChangeProperty:
WritePropertyChange(msg, extraData);
break;
}
msg.WritePadBits();
}
public void ClientReadPosition(ServerNetObject type, NetBuffer msg, float sendingTime)
{
Vector2 newPosition = new Vector2(msg.ReadFloat(), msg.ReadFloat());
float newRotation = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 7);
bool awake = msg.ReadBoolean();
Vector2 newVelocity = Vector2.Zero;
if (awake)
{
newVelocity = new Vector2(
msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
}
if (body == null)
{
DebugConsole.ThrowError("Received a position update for an item with no physics body (" + Name + ")");
return;
}
body.FarseerBody.Awake = awake;
if (body.FarseerBody.Awake)
{
if ((newVelocity - body.LinearVelocity).Length() > 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)
{
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 });
}
}
}