Merge branch 'master' of https://github.com/Faerdan/Barotrauma into Faerdan-master

Conflicts:
	Barotrauma/BarotraumaClient/Source/Map/MapEntity.cs
	Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs
	Barotrauma/BarotraumaShared/Source/Characters/Character.cs
	Barotrauma/BarotraumaShared/Source/Items/Item.cs
This commit is contained in:
Joonas Rikkonen
2017-07-05 19:32:34 +03:00
47 changed files with 473 additions and 483 deletions
@@ -141,7 +141,7 @@ namespace Barotrauma
{
if (character.SelectedConstruction != currentPath.CurrentNode.Ladders.Item && currentPath.CurrentNode.Ladders.Item.IsInsideTrigger(character.WorldPosition))
{
currentPath.CurrentNode.Ladders.Item.Pick(character, false, true);
currentPath.CurrentNode.Ladders.Item.TryInteract(character, false, true);
}
}
@@ -239,7 +239,7 @@ namespace Barotrauma
foreach (Controller controller in buttons)
{
float dist = Vector2.Distance(controller.Item.WorldPosition, character.WorldPosition);
if (dist > controller.Item.PickDistance * 2.0f) continue;
if (dist > controller.Item.InteractDistance * 2.0f) continue;
if (dist < closestDist || closestButton == null)
{
@@ -256,7 +256,7 @@ namespace Barotrauma
return;
}
closestButton.Item.Pick(character, false, true);
closestButton.Item.TryInteract(character, false, true);
break;
}
}
@@ -61,7 +61,7 @@ namespace Barotrauma
}
else
{
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.PickDistance
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance
&& !container.Item.IsInsideTrigger(character.Position))
{
AddSubObjective(new AIObjectiveGoTo(container.Item, character));
@@ -55,7 +55,7 @@ namespace Barotrauma
FindTargetItem();
if (targetItem == null || moveToTarget == null) return;
if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.PickDistance*2.0f)
if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.InteractDistance*2.0f)
{
int targetSlot = -1;
if (equip)
@@ -91,7 +91,7 @@ namespace Barotrauma
}
}
targetItem.Pick(character, false, true);
targetItem.TryInteract(character, false, true);
if (targetSlot > -1 && character.Inventory.IsInLimbSlot(targetItem, InvSlotType.Any))
{
@@ -126,7 +126,7 @@ namespace Barotrauma
if (item != null)
{
allowedDistance = Math.Max(ConvertUnits.ToSimUnits(item.PickDistance), allowedDistance);
allowedDistance = Math.Max(ConvertUnits.ToSimUnits(item.InteractDistance), allowedDistance);
if (item.IsInsideTrigger(character.WorldPosition)) completed = true;
}
@@ -50,12 +50,12 @@ namespace Barotrauma
if (target.CanBeSelected)
{
if (Vector2.Distance(character.Position, target.Item.Position) < target.Item.PickDistance
if (Vector2.Distance(character.Position, target.Item.Position) < target.Item.InteractDistance
|| target.Item.IsInsideTrigger(character.WorldPosition))
{
if (character.SelectedConstruction != target.Item && target.CanBeSelected)
{
target.Item.Pick(character, false, true);
target.Item.TryInteract(character, false, true);
}
if (component.AIOperate(deltaTime, character, this)) isCompleted = true;
@@ -1213,7 +1213,7 @@ namespace Barotrauma
var newSelectedConstruction = (Item)character.MemState[0].Interact;
if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction)
{
newSelectedConstruction.Pick(character, true, true);
newSelectedConstruction.TryInteract(character, true, true);
}
character.SelectedConstruction = newSelectedConstruction;
}
@@ -1305,7 +1305,7 @@ namespace Barotrauma
var newSelectedConstruction = (Item)serverPos.Interact;
if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction)
{
newSelectedConstruction.Pick(character, true, true);
newSelectedConstruction.TryInteract(character, true, true);
}
character.SelectedConstruction = newSelectedConstruction;
}
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
namespace Barotrauma
{
@@ -71,8 +72,8 @@ namespace Barotrauma
private float health, lastSentHealth;
protected float minHealth, maxHealth;
protected Item closestItem;
private Character closestCharacter, selectedCharacter;
protected Item focusedItem;
private Character focusedCharacter, selectedCharacter;
private bool isDead;
private CauseOfDeath lastAttackCauseOfDeath;
@@ -154,6 +155,11 @@ namespace Barotrauma
get { return !IsUnconscious && Stun <= 0.0f && !isDead; }
}
public bool CanInteract
{
get { return AllowInput && !LockHands; }
}
public Vector2 CursorPosition
{
get { return cursorPosition; }
@@ -169,9 +175,9 @@ namespace Barotrauma
get { return Submarine == null ? cursorPosition : cursorPosition + Submarine.Position; }
}
public Character ClosestCharacter
public Character FocusedCharacter
{
get { return closestCharacter; }
get { return focusedCharacter; }
}
public Character SelectedCharacter
@@ -386,9 +392,9 @@ namespace Barotrauma
set { selectedConstruction = value; }
}
public Item ClosestItem
public Item FocusedItem
{
get { return closestItem; }
get { return focusedItem; }
}
public virtual AIController AIController
@@ -569,7 +575,7 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(item != null);
if (item == null) continue;
item.Pick(this, true, true, true);
item.TryInteract(this, true, true, true);
inventory.TryPutItem(item, i, false, false);
}
}
@@ -713,7 +719,7 @@ namespace Barotrauma
return (Info==null || Info.Job==null) ? 0 : Info.Job.GetSkillLevel(skillName);
}
float findClosestTimer;
float findFocusedTimer;
public Vector2 GetTargetMovement()
{
@@ -950,7 +956,7 @@ namespace Barotrauma
public bool CanAccessInventory(Inventory inventory)
{
if (!AllowInput || LockHands) return false;
if (!CanInteract) return false;
//the inventory belongs to some other character
if (inventory.Owner is Character && inventory.Owner != this)
@@ -958,14 +964,13 @@ namespace Barotrauma
var owner = (Character)inventory.Owner;
//can only be accessed if the character is incapacitated and has been selected
return selectedCharacter == owner &&
(owner.isDead || owner.IsUnconscious || owner.Stun > 0.0f || owner.LockHands);
return selectedCharacter == owner && (!owner.CanInteract);
}
if (inventory.Owner is Item)
{
var owner = (Item)inventory.Owner;
if (!CanAccessItem(owner))
if (!CanInteractWith(owner))
{
return false;
}
@@ -973,53 +978,162 @@ namespace Barotrauma
return true;
}
public bool CanAccessItem(Item item)
public bool CanInteractWith(Item item)
{
if (!AllowInput || LockHands) return false;
float distanceToItem;
return CanInteractWith(item, out distanceToItem);
}
public bool CanInteractWith(Item item, out float distanceToItem)
{
distanceToItem = -1.0f;
if (!CanInteract) return false;
if (item.ParentInventory != null)
{
return CanAccessInventory(item.ParentInventory);
}
float maxDist = item.PickDistance * 1.2f;
if (maxDist <= 0.01f)
{
maxDist = 150.0f;
}
if (item.InteractDistance == 0.0f && !item.Prefab.Triggers.Any()) return false;
if (Vector2.DistanceSquared(WorldPosition, item.WorldPosition) < maxDist*maxDist ||
item.IsInsideTrigger(WorldPosition))
{
return true;
}
Pickable pickableComponent = item.GetComponent<Pickable>();
if (pickableComponent != null && (pickableComponent.Picker != null && !pickableComponent.Picker.IsDead)) return false;
Vector2 characterDirection = Vector2.Transform(Vector2.UnitY, Matrix.CreateFromAxisAngle(Vector3.UnitZ, AnimController.Collider.Rotation));
return item.GetComponent<Items.Components.Ladder>() != null;
}
private Item FindClosestItem(Vector2 mouseSimPos, out float distance)
{
distance = 0.0f;
Limb torso = AnimController.GetLimb(LimbType.Torso);
if (torso == null) return null;
Vector2 pos = (torso.body.TargetPosition != null) ? (Vector2)torso.body.TargetPosition : torso.SimPosition;
Vector2 pickPos = mouseSimPos;
Vector2 upperBodyPosition = Position + (characterDirection * 20.0f);
Vector2 lowerBodyPosition = Position - (characterDirection * 60.0f);
if (Submarine != null)
{
pos += Submarine.SimPosition;
pickPos += Submarine.SimPosition;
upperBodyPosition += Submarine.Position;
lowerBodyPosition += Submarine.Position;
}
if (selectedConstruction != null) pickPos = ConvertUnits.ToSimUnits(selectedConstruction.WorldPosition);
Vector2 playerDistanceCheckPosition;
Rectangle itemDisplayRect;
return Item.FindPickable(pos, pickPos, AnimController.CurrentHull, selectedItems, out distance);
bool insideTrigger = false;
if (item.Prefab.Triggers.Any())
{
foreach (Rectangle trigger in item.Prefab.Triggers)
{
Rectangle transformedTrigger = new Rectangle(
item.WorldRect.X + trigger.X,
(item.WorldRect.Y + trigger.Y) - ((trigger.Height == 0) ? item.Rect.Height : trigger.Height),
(trigger.Width == 0) ? item.Rect.Width : trigger.Width,
(trigger.Height == 0) ? item.Rect.Height : trigger.Height);
// Get the point along the line between lowerBodyPosition and upperBodyPosition which is closest to the center of itemDisplayRect
playerDistanceCheckPosition = Vector2.Clamp(transformedTrigger.Center.ToVector2(), lowerBodyPosition, upperBodyPosition);
if (!transformedTrigger.Contains(upperBodyPosition)) return false;
insideTrigger = true;
}
if (!insideTrigger) return false;
}
itemDisplayRect = new Rectangle(item.InteractionRect.X, item.InteractionRect.Y - item.InteractionRect.Height, item.InteractionRect.Width, item.InteractionRect.Height);
// Get the point along the line between lowerBodyPosition and upperBodyPosition which is closest to the center of itemDisplayRect
playerDistanceCheckPosition = Vector2.Clamp(itemDisplayRect.Center.ToVector2(), lowerBodyPosition, upperBodyPosition);
// Here we get the point on the itemDisplayRect which is closest to playerDistanceCheckPosition
Vector2 rectIntersectionPoint = new Vector2(Math.Max(itemDisplayRect.X, Math.Min(itemDisplayRect.X + itemDisplayRect.Width, playerDistanceCheckPosition.X)), Math.Max(itemDisplayRect.Y, Math.Min(itemDisplayRect.Y + itemDisplayRect.Height, playerDistanceCheckPosition.Y)));
// If playerDistanceCheckPosition is inside the itemDisplayRect then we consider the character to within 0 distance of the item
if (!itemDisplayRect.Contains(playerDistanceCheckPosition))
{
distanceToItem = Vector2.Distance(rectIntersectionPoint, playerDistanceCheckPosition);
}
if (distanceToItem > item.InteractDistance && item.InteractDistance > 0.0f) return false;
if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.EditMapScreen && !insideTrigger)
{
Vector2 itemPosition = item.SimPosition;
if (Submarine == null && item.Submarine != null)
{
//character is outside, item inside
itemPosition += item.Submarine.SimPosition;
}
else if (Submarine != null && item.Submarine == null)
{
//character is inside, item outside
itemPosition -= Submarine.SimPosition;
}
else if (Submarine != item.Submarine)
{
//character and the item are inside different subs
itemPosition += item.Submarine.SimPosition;
itemPosition -= Submarine.SimPosition;
}
var body = Submarine.CheckVisibility(SimPosition, itemPosition, true);
if (body != null && body.UserData as Item != item) return false;
}
return true;
}
private Character FindClosestCharacter(Vector2 mouseSimPos, float maxDist = 150.0f)
/// <summary>
/// Finds the front (lowest depth) interactable item at a position. "Interactable" in this case means that the character can "reach" the item.
/// </summary>
/// <param name="character">The Character who is looking for the interactable item, only items that are close enough to this character are returned</param>
/// <param name="simPosition">The item at the simPosition, with the lowest depth, is returned</param>
/// <param name="allowFindingNearestItem">If this is true and an item cannot be found at simPosition then a nearest item will be returned if possible</param>
/// <param name="hull">If a hull is specified, only items within that hull are returned</param>
public Item FindItemAtPosition(Vector2 simPosition, float aimAssistModifier = 0.0f, Hull hull = null, Item[] ignoredItems = null)
{
if (Submarine != null)
{
simPosition += Submarine.SimPosition;
}
Vector2 displayPosition = ConvertUnits.ToDisplayUnits(simPosition);
Item highestPriorityItemAtPosition = null;
Item closestItem = null;
float closestItemDistance = 0.0f;
foreach (Item item in Item.ItemList)
{
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
if (item.body != null && !item.body.Enabled) continue;
if (CanInteractWith(item))
{
if (item.IsMouseOn(displayPosition))
{
Console.WriteLine("Name: " + item.Name + " Priority:" + item.InteractPriority);
}
if (item.IsMouseOn(displayPosition) && (highestPriorityItemAtPosition == null ||
((highestPriorityItemAtPosition.InteractPriority < item.InteractPriority) ||
(highestPriorityItemAtPosition.InteractPriority == item.InteractPriority && highestPriorityItemAtPosition.GetDrawDepth() > item.GetDrawDepth()))))
{
highestPriorityItemAtPosition = item;
}
else if (aimAssistModifier > 0.0f)
{
float distanceToItem = Vector2.Distance(item.WorldPosition, displayPosition);
if (distanceToItem < (100.0f * aimAssistModifier) && (closestItem == null || distanceToItem < closestItemDistance))
{
closestItem = item;
closestItemDistance = distanceToItem;
}
}
}
}
if (highestPriorityItemAtPosition == null)
{
return closestItem;
}
return highestPriorityItemAtPosition;
}
private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = 150.0f)
{
Character closestCharacter = null;
float closestDist = 0.0f;
@@ -1028,17 +1142,25 @@ namespace Barotrauma
foreach (Character c in CharacterList)
{
if (c == this || !c.enabled) continue;
if (Vector2.DistanceSquared(SimPosition, c.SimPosition) > maxDist*maxDist) continue;
if (c == this || !c.enabled || c.info == null || !c.IsHumanoid || !c.CanBeSelected) continue;
float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition);
if (dist < maxDist*maxDist && (closestCharacter==null || dist<closestDist))
if (dist < maxDist*maxDist && (closestCharacter == null || dist < closestDist))
{
closestCharacter = c;
closestDist = dist;
continue;
}
/*FarseerPhysics.Common.Transform transform;
c.AnimController.Collider.FarseerBody.GetTransform(out transform);
for (int i = 0; i < c.AnimController.Collider.FarseerBody.FixtureList.Count; i++)
{
if (c.AnimController.Collider.FarseerBody.FixtureList[i].Shape.TestPoint(ref transform, ref mouseSimPos))
{
Console.WriteLine("Hit: " + i);
closestCharacter = c;
}
}*/
}
return closestCharacter;
@@ -1086,7 +1208,66 @@ namespace Barotrauma
selectedCharacter = null;
}
public void DoInteractionUpdate(float deltaTime, Vector2 mouseSimPos)
{
bool isLocalPlayer = (controlled == this);
if (!isLocalPlayer && (this is AICharacter || !IsRemotePlayer))
{
return;
}
if (!AllowInput || LockHands)
{
if (selectedCharacter != null)
{
DeselectCharacter();
}
selectedConstruction = null;
focusedItem = null;
focusedCharacter = null;
return;
}
if ((!isLocalPlayer && IsKeyHit(InputType.Select) && GameMain.Server == null) || (isLocalPlayer && (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.EditMapScreen)))
{
focusedCharacter = FindCharacterAtPosition(mouseSimPos);
if (focusedCharacter != null)
{
focusedItem = null; // We can only focus one thing at a time
}
else
{
focusedItem = FindItemAtPosition(mouseSimPos, AnimController.InWater ? 0.5f : 0.25f);
}
findFocusedTimer = 0.05f;
}
else
{
findFocusedTimer -= deltaTime;
}
if (focusedCharacter != null && IsKeyHit(InputType.Select))
{
if (selectedCharacter != null)
{
DeselectCharacter();
}
else
{
SelectCharacter(focusedCharacter);
}
}
else if (focusedItem != null)
{
focusedItem.IsHighlighted = true;
focusedItem.TryInteract(this);
}
else if (IsKeyHit(InputType.Select) && selectedConstruction != null)
{
selectedConstruction = null;
}
}
public static void UpdateAnimAll(float deltaTime)
{
foreach (Character c in CharacterList)
@@ -1194,7 +1375,7 @@ namespace Barotrauma
}
}
UpdateControlled(deltaTime,cam);
UpdateControlled(deltaTime, cam);
if (Stun > 0.0f)
{
@@ -1211,77 +1392,17 @@ namespace Barotrauma
UpdateUnconscious(deltaTime);
return;
}
Control(deltaTime, cam);
if (selectedConstruction != null && !selectedConstruction.IsInPickRange(WorldPosition))
{
selectedConstruction = null;
}
Control(deltaTime, cam);
if (controlled != this && (!(this is AICharacter) || IsRemotePlayer))
{
if (!LockHands)
{
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
if (IsKeyHit(InputType.Select) && GameMain.Server==null)
{
closestCharacter = FindClosestCharacter(mouseSimPos);
if (closestCharacter != null && closestCharacter.info == null)
{
closestCharacter = null;
}
float closestItemDist = 0.0f;
closestItem = FindClosestItem(mouseSimPos, out closestItemDist);
if (closestCharacter != null && closestItem != null)
{
if (closestItem != null) closestItemDist = (closestItem.Position - AnimController.Collider.Position).Length();
if (Vector2.Distance(closestCharacter.SimPosition, mouseSimPos) < ConvertUnits.ToSimUnits(closestItemDist))
{
if (selectedConstruction != closestItem) closestItem = null;
}
else
{
closestCharacter = null;
}
}
}
if (selectedCharacter == null && closestItem != null)
{
//DebugConsole.NewMessage(closestItem.ToString(), Color.Yellow);
//closestItem.IsHighlighted = true;
if (!LockHands && closestItem.Pick(this))
{
if (AnimController.Anim == AnimController.Animation.Climbing)
{
//DebugConsole.NewMessage("ladder woo",Color.Lime);
}
}
}
if (IsKeyHit(InputType.Select))
{
if (selectedCharacter != null)
{
DeselectCharacter();
}
else if (closestCharacter != null && closestCharacter.IsHumanoid && closestCharacter.CanBeSelected)
{
SelectCharacter(closestCharacter);
}
}
}
else
{
if (selectedCharacter != null) DeselectCharacter();
selectedConstruction = null;
closestItem = null;
closestCharacter = null;
}
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
DoInteractionUpdate(deltaTime, mouseSimPos);
}
if (selectedConstruction != null && !CanInteractWith(selectedConstruction))
{
selectedConstruction = null;
}
if (selectedCharacter != null && AnimController.Anim == AnimController.Animation.CPR)
@@ -1304,7 +1425,7 @@ namespace Barotrauma
if (!IsDead) LockHands = false;
}
partial void UpdateControlled(float deltaTime,Camera cam);
partial void UpdateControlled(float deltaTime, Camera cam);
private void UpdateOxygen(float deltaTime)
{
@@ -1355,7 +1476,7 @@ namespace Barotrauma
speechBubbleTimer = Math.Max(speechBubbleTimer, duration);
speechBubbleColor = color;
}
public virtual void AddDamage(CauseOfDeath causeOfDeath, float amount, IDamageable attacker)
{
Health = health-amount;
@@ -1616,7 +1737,7 @@ namespace Barotrauma
foreach (Character c in CharacterList)
{
if (c.closestCharacter == this) c.closestCharacter = null;
if (c.focusedCharacter == this) c.focusedCharacter = null;
if (c.selectedCharacter == this) c.selectedCharacter = null;
}
}
@@ -147,13 +147,13 @@ namespace Barotrauma
var closestEntity = Entity.FindEntityByID(memInput[memInput.Count - 1].interact);
if (closestEntity is Item)
{
closestItem = (Item)closestEntity;
closestCharacter = null;
focusedItem = (Item)closestEntity;
focusedCharacter = null;
}
else if (closestEntity is Character)
{
closestCharacter = (Character)closestEntity;
closestItem = null;
focusedCharacter = (Character)closestEntity;
focusedItem = null;
}
memInput.RemoveAt(memInput.Count - 1);
@@ -205,13 +205,13 @@ namespace Barotrauma
NetInputMem newMem = new NetInputMem();
newMem.states = newInput;
newMem.intAim = intAngle;
if (closestItem != null)
if (focusedItem != null)
{
newMem.interact = closestItem.ID;
newMem.interact = focusedItem.ID;
}
else if (closestCharacter != null)
else if (focusedCharacter != null)
{
newMem.interact = closestCharacter.ID;
newMem.interact = focusedCharacter.ID;
}
memInput.Insert(0, newMem);
@@ -101,9 +101,7 @@ namespace Barotrauma.Items.Components
pickTimer = 0.0f;
while (pickTimer < requiredTime && Screen.Selected != GameMain.EditMapScreen)
{
if (picker.IsKeyDown(InputType.Aim) ||
!item.IsInPickRange(picker.WorldPosition) ||
picker.Stun > 0.0f || picker.IsDead)
if (picker.IsKeyDown(InputType.Aim) || !picker.CanInteractWith(item))
{
StopPicking(picker);
yield return CoroutineStatus.Success;
@@ -76,10 +76,8 @@ namespace Barotrauma.Items.Components
this.cam = cam;
if (character == null
|| character.IsDead
|| character.Stun > 0.0f
|| character.SelectedConstruction != item
|| Vector2.Distance(character.Position, item.Position) > item.PickDistance * 2.0f)
|| !character.CanInteractWith(item))
{
if (character != null)
{
@@ -149,7 +147,7 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character activator = null)
{
if (character == null || activator != character || character.SelectedConstruction != item)
if (character == null || activator != character || character.SelectedConstruction != item || !character.CanInteractWith(item))
{
character = null;
return false;
@@ -164,7 +162,7 @@ namespace Barotrauma.Items.Components
public override void SecondaryUse(float deltaTime, Character character = null)
{
if (this.character == null || this.character != character || this.character.SelectedConstruction != item)
if (this.character == null || this.character != character || this.character.SelectedConstruction != item || !character.CanInteractWith(item))
{
character = null;
return;
@@ -128,19 +128,33 @@ namespace Barotrauma
{
get { return prefab.ImpactTolerance; }
}
public float PickDistance
public float InteractDistance
{
get { return prefab.PickDistance; }
get { return prefab.InteractDistance; }
}
public float InteractPriority
{
get { return prefab.InteractPriority; }
}
public override Vector2 SimPosition
{
get
{
return (body==null) ? base.SimPosition : body.SimPosition;
return (body == null) ? base.SimPosition : body.SimPosition;
}
}
public Rectangle InteractionRect
{
get
{
return WorldRect;
}
}
public bool NeedsPositionUpdate
{
get
@@ -910,7 +924,7 @@ namespace Barotrauma
{
return drawableComponents.Count > 0 || body == null || body.Enabled;
}
public List<T> GetConnectedComponents<T>(bool recursive = false)
{
List<T> connectedComponents = new List<T>();
@@ -999,77 +1013,11 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
public static Item FindPickable(Vector2 position, Vector2 pickPosition, Hull hull = null, Item[] ignoredItems = null)
public float GetDrawDepth()
{
float dist;
return FindPickable(position, pickPosition, hull, ignoredItems, out dist);
return Sprite.Depth + ((ID % 255) * 0.000001f);
}
/// <param name="position">Position of the Character doing the pick, only items that are close enough to this are checked</param>
/// <param name="pickPosition">the item closest to pickPosition is returned</param>
/// <param name="hull">If a hull is specified, only items within that hull are checked</param>
public static Item FindPickable(Vector2 position, Vector2 pickPosition, Hull hull, Item[] ignoredItems, out float distance)
{
float closestDist = 0.0f, dist;
Item closest = null;
Vector2 displayPos = ConvertUnits.ToDisplayUnits(position);
Vector2 displayPickPos = ConvertUnits.ToDisplayUnits(pickPosition);
distance = 1000.0f;
foreach (Item item in ItemList)
{
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
if (item.body != null && !item.body.Enabled) continue;
if (item.PickDistance == 0.0f && !item.prefab.Triggers.Any()) continue;
Pickable pickableComponent = item.GetComponent<Pickable>();
if (pickableComponent != null && (pickableComponent.Picker != null && !pickableComponent.Picker.IsDead)) continue;
float pickDist = Vector2.Distance(item.WorldPosition, displayPickPos);
bool insideTrigger = false;
foreach (Rectangle trigger in item.prefab.Triggers)
{
Rectangle transformedTrigger = item.TransformTrigger(trigger, true);
if (!Submarine.RectContains(transformedTrigger, displayPos)) continue;
insideTrigger = true;
Vector2 triggerCenter = new Vector2(transformedTrigger.Center.X, transformedTrigger.Y - transformedTrigger.Height / 2);
pickDist = Math.Min(Math.Abs(triggerCenter.X - displayPickPos.X), Math.Abs(triggerCenter.Y - displayPickPos.Y));
}
if (!insideTrigger && item.prefab.Triggers.Any()) continue;
if (pickDist > item.PickDistance && item.PickDistance > 0.0f) continue;
dist = item.Sprite.Depth * 10.0f + pickDist;
if (item.IsMouseOn(displayPickPos)) dist = dist * 0.1f;
if (closest == null || dist < closestDist)
{
if (item.PickDistance > 0.0f && Vector2.Distance(displayPos, item.WorldPosition) > item.prefab.PickDistance) continue;
if (!item.prefab.PickThroughWalls && Screen.Selected != GameMain.EditMapScreen && !insideTrigger)
{
Body body = Submarine.CheckVisibility(item.Submarine == null ? position : position - item.Submarine.SimPosition, item.SimPosition, true);
if (body != null && body.UserData as Item != item) continue;
}
closestDist = dist;
closest = item;
distance = pickDist;
}
}
return closest;
}
public bool IsInsideTrigger(Vector2 worldPosition)
{
foreach (Rectangle trigger in prefab.Triggers)
@@ -1082,26 +1030,19 @@ namespace Barotrauma
return false;
}
public bool IsInPickRange(Vector2 worldPosition)
{
if (IsInsideTrigger(worldPosition)) return true;
return Vector2.Distance(WorldPosition, worldPosition) < PickDistance;
}
public bool CanClientAccess(Client c)
{
return c != null && c.Character != null && c.Character.CanAccessItem(this);
return c != null && c.Character != null && c.Character.CanInteractWith(this);
}
public bool Pick(Character picker, bool ignoreRequiredItems=false, bool forceSelectKey=false, bool forceActionKey=false)
public bool TryInteract(Character picker, bool ignoreRequiredItems=false, bool forceSelectKey=false, bool forceActionKey=false)
{
bool hasRequiredSkills = true;
bool picked = false, selected = false;
Skill requiredSkill = null;
foreach (ItemComponent ic in components)
{
bool pickHit = false, selectHit = false;
@@ -1129,7 +1070,6 @@ namespace Barotrauma
}
}
if (!pickHit && !selectHit) continue;
Skill tempRequiredSkill;
@@ -1139,7 +1079,7 @@ namespace Barotrauma
bool showUiMsg = picker == Character.Controlled && Screen.Selected != GameMain.EditMapScreen;
if (!ignoreRequiredItems && !ic.HasRequiredItems(picker, showUiMsg)) continue;
if ((ic.CanBePicked && pickHit && ic.Pick(picker)) ||
if ((ic.CanBePicked && pickHit && ic.Pick(picker)) ||
(ic.CanBeSelected && selectHit && ic.Select(picker)))
{
picked = true;
@@ -1164,24 +1104,24 @@ namespace Barotrauma
if (picker.IsKeyHit(InputType.Select) || forceSelectKey) picker.SelectedConstruction = null;
}
else if (selected)
{
{
picker.SelectedConstruction = this;
}
#if CLIENT
if (!hasRequiredSkills && Character.Controlled==picker && Screen.Selected != GameMain.EditMapScreen)
if (!hasRequiredSkills && Character.Controlled == picker && Screen.Selected != GameMain.EditMapScreen)
{
GUI.AddMessage("Your skills may be insufficient to use the item!", Color.Red, 5.0f);
if (requiredSkill != null)
{
GUI.AddMessage("("+requiredSkill.Name+" level "+requiredSkill.Level+" required)", Color.Red, 5.0f);
GUI.AddMessage("(" + requiredSkill.Name + " level " + requiredSkill.Level + " required)", Color.Red, 5.0f);
}
}
#endif
if (Container!=null) Container.RemoveContained(this);
if (Container != null) Container.RemoveContained(this);
return true;
return true;
}
@@ -1366,7 +1306,7 @@ namespace Barotrauma
int requirementIndex = FixRequirements.Count == 1 ?
0 : msg.ReadRangedInteger(0, FixRequirements.Count - 1);
if (c.Character == null || !c.Character.CanAccessItem(this)) return;
if (c.Character == null || !c.Character.CanInteractWith(this)) return;
if (!FixRequirements[requirementIndex].CanBeFixed(c.Character)) return;
FixRequirements[requirementIndex].Fixed = true;
@@ -1379,7 +1319,7 @@ namespace Barotrauma
break;
case NetEntityEvent.Type.ApplyStatusEffect:
if (c.Character == null || !c.Character.CanAccessItem(this)) return;
if (c.Character == null || !c.Character.CanInteractWith(this)) return;
ApplyStatusEffects(ActionType.OnUse, (float)Timing.Step, c.Character);
@@ -33,9 +33,11 @@ namespace Barotrauma
protected Vector2 size;
//how close the Character has to be to the item to pick it up
private float pickDistance;
private float interactDistance;
// this can be used to allow items which are behind other items tp
private float interactPriority;
private bool pickThroughWalls;
private bool interactThroughWalls;
//an area next to the construction
//the construction can be Activated() by a Character inside the area
@@ -78,14 +80,19 @@ namespace Barotrauma
private set;
}
public float PickDistance
public float InteractDistance
{
get { return pickDistance; }
get { return interactDistance; }
}
public bool PickThroughWalls
public float InteractPriority
{
get { return pickThroughWalls; }
get { return interactPriority; }
}
public bool InteractThroughWalls
{
get { return interactThroughWalls; }
}
public override bool IsLinkable
@@ -238,9 +245,10 @@ namespace Barotrauma
Description = ToolBox.GetAttributeString(element, "description", "");
pickThroughWalls = ToolBox.GetAttributeBool(element, "pickthroughwalls", false);
pickDistance = ToolBox.GetAttributeFloat(element, "pickdistance", 0.0f);
interactThroughWalls = ToolBox.GetAttributeBool(element, "interactthroughwalls", false);
interactDistance = ToolBox.GetAttributeFloat(element, "interactdistance", 120.0f); // Default to 120 as the new item picking method is tuned to this number
interactPriority = ToolBox.GetAttributeFloat(element, "interactpriority", 0.0f);
isLinkable = ToolBox.GetAttributeBool(element, "linkable", false);
resizeHorizontal = ToolBox.GetAttributeBool(element, "resizehorizontal", false);
@@ -91,12 +91,9 @@ namespace Barotrauma
if (Level.Loaded != null) Level.Loaded.Update((float)deltaTime);
#if CLIENT
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null)
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction))
{
if (Character.Controlled.SelectedConstruction == Character.Controlled.ClosestItem)
{
Character.Controlled.SelectedConstruction.UpdateHUD(cam, Character.Controlled);
}
Character.Controlled.SelectedConstruction.UpdateHUD(cam, Character.Controlled);
}
#endif