Merge branch 'master' into moStuff
This commit is contained in:
+56
-13
@@ -1,29 +1,63 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveContainItem: AIObjective
|
||||
{
|
||||
private string itemName;
|
||||
public int MinContainedAmount = 1;
|
||||
|
||||
private string[] itemNames;
|
||||
|
||||
private ItemContainer container;
|
||||
|
||||
bool isCompleted;
|
||||
|
||||
private bool isCompleted;
|
||||
|
||||
public bool IgnoreAlreadyContainedItems;
|
||||
|
||||
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
private AIObjectiveGetItem getItemObjective;
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
|
||||
public AIObjectiveContainItem(Character character, string itemName, ItemContainer container)
|
||||
: this(character, new string[] { itemName }, container)
|
||||
{
|
||||
}
|
||||
|
||||
public AIObjectiveContainItem(Character character, string[] itemNames, ItemContainer container)
|
||||
: base (character, "")
|
||||
{
|
||||
this.itemName = itemName;
|
||||
this.itemNames = itemNames;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return isCompleted || container.Inventory.FindItem(itemName)!=null;
|
||||
if (isCompleted) return true;
|
||||
|
||||
int containedItemCount = 0;
|
||||
foreach (Item item in container.Inventory.Items)
|
||||
{
|
||||
if (item != null && itemNames.Any(name => item.Prefab.NameMatches(name) || item.HasTag(name))) containedItemCount++;
|
||||
}
|
||||
|
||||
return containedItemCount >= MinContainedAmount;
|
||||
}
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
if (goToObjective != null)
|
||||
{
|
||||
return goToObjective.CanBeCompleted;
|
||||
}
|
||||
|
||||
return getItemObjective == null || !getItemObjective.CanBeCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
@@ -41,12 +75,13 @@ namespace Barotrauma
|
||||
if (isCompleted) return;
|
||||
|
||||
//get the item that should be contained
|
||||
var itemToContain = character.Inventory.FindItem(itemName);
|
||||
var itemToContain = character.Inventory.FindItem(itemNames);
|
||||
if (itemToContain == null)
|
||||
{
|
||||
var getItem = new AIObjectiveGetItem(character, itemName);
|
||||
getItem.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
||||
AddSubObjective(getItem);
|
||||
getItemObjective = new AIObjectiveGetItem(character, itemNames);
|
||||
getItemObjective.GetItemPriority = GetItemPriority;
|
||||
getItemObjective.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
||||
AddSubObjective(getItemObjective);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,9 +98,10 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance
|
||||
&& !container.Item.IsInsideTrigger(character.Position))
|
||||
&& !container.Item.IsInsideTrigger(character.WorldPosition))
|
||||
{
|
||||
AddSubObjective(new AIObjectiveGoTo(container.Item, character));
|
||||
goToObjective = new AIObjectiveGoTo(container.Item, character);
|
||||
AddSubObjective(goToObjective);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,8 +115,15 @@ namespace Barotrauma
|
||||
{
|
||||
AIObjectiveContainItem objective = otherObjective as AIObjectiveContainItem;
|
||||
if (objective == null) return false;
|
||||
if (objective.container != container) return false;
|
||||
if (objective.itemNames.Length != itemNames.Length) return false;
|
||||
|
||||
return objective.itemName == itemName && objective.container == container;
|
||||
for (int i = 0; i < itemNames.Length; i++)
|
||||
{
|
||||
if (objective.itemNames[i] != itemNames[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+24
-17
@@ -11,12 +11,20 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
var item = character.Inventory.FindItem(gearName);
|
||||
if (item == null) return false;
|
||||
for (int i = 0; i < character.Inventory.Items.Length; i++)
|
||||
{
|
||||
if (CharacterInventory.limbSlots[i] == InvSlotType.Any || character.Inventory.Items[i] == null) continue;
|
||||
if (character.Inventory.Items[i].Prefab.NameMatches(gearName) || character.Inventory.Items[i].HasTag(gearName))
|
||||
{
|
||||
var containedItems = character.Inventory.Items[i].ContainedItems;
|
||||
if (containedItems == null) continue;
|
||||
|
||||
var containedItems = item.ContainedItems;
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank") && i.Condition > 0.0f);
|
||||
return oxygenTank != null;
|
||||
var oxygenTank = Array.Find(containedItems, it => (it.Prefab.NameMatches("Oxygen Tank") || it.HasTag("oxygensource")) && it.Condition > 0.0f);
|
||||
if (oxygenTank != null) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public AIObjectiveFindDivingGear(Character character, bool needDivingSuit)
|
||||
@@ -41,25 +49,24 @@ namespace Barotrauma
|
||||
var containedItems = item.ContainedItems;
|
||||
if (containedItems == null) return;
|
||||
|
||||
//check if there's an oxygen tank in the mask
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank"));
|
||||
|
||||
if (oxygenTank != null)
|
||||
//check if there's an oxygen tank in the mask/suit
|
||||
foreach (Item containedItem in containedItems)
|
||||
{
|
||||
if (oxygenTank.Condition > 0.0f)
|
||||
if (containedItem == null) continue;
|
||||
if (containedItem.Condition <= 0.0f)
|
||||
{
|
||||
containedItem.Drop();
|
||||
}
|
||||
else if (containedItem.Prefab.NameMatches("Oxygen Tank") || containedItem.HasTag("oxygensource"))
|
||||
{
|
||||
//we've got an oxygen source inside the mask/suit, all good
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
oxygenTank.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!(subObjective is AIObjectiveContainItem) || subObjective.IsCompleted())
|
||||
{
|
||||
subObjective = new AIObjectiveContainItem(character, "Oxygen Tank", item.GetComponent<ItemContainer>());
|
||||
subObjective = new AIObjectiveContainItem(character, new string[] { "Oxygen Tank", "oxygensource" }, item.GetComponent<ItemContainer>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,9 @@ namespace Barotrauma
|
||||
if (gap.ConnectedWall == null) continue;
|
||||
if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue;
|
||||
|
||||
//TODO: prevent the AI characters from fixing leaks in the enemy sub in sub-vs-sub missions if/when multiplayer bots are implemented
|
||||
if (gap.Submarine == null) continue;
|
||||
|
||||
float gapPriority = GetGapFixPriority(gap);
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveGetItem : AIObjective
|
||||
{
|
||||
private string itemName;
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
private string[] itemNames;
|
||||
|
||||
private Item targetItem, moveToTarget;
|
||||
|
||||
@@ -20,6 +22,8 @@ namespace Barotrauma
|
||||
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
|
||||
private float currItemPriority;
|
||||
|
||||
private bool equip;
|
||||
|
||||
public override bool CanBeCompleted
|
||||
@@ -49,24 +53,33 @@ namespace Barotrauma
|
||||
this.targetItem = targetItem;
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, string itemName, bool equip=false)
|
||||
: base (character, "")
|
||||
public AIObjectiveGetItem(Character character, string itemName, bool equip = false)
|
||||
: this(character, new string[] { itemName }, equip)
|
||||
{
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, string[] itemNames, bool equip = false)
|
||||
: base(character, "")
|
||||
{
|
||||
canBeCompleted = true;
|
||||
|
||||
this.equip = equip;
|
||||
|
||||
currSearchIndex = 0;
|
||||
|
||||
this.itemName = itemName;
|
||||
|
||||
this.itemNames = itemNames;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
FindTargetItem();
|
||||
if (targetItem == null || moveToTarget == null) return;
|
||||
if (targetItem == null || moveToTarget == null)
|
||||
{
|
||||
character?.AIController?.SteeringManager?.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.InteractDistance*2.0f)
|
||||
if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.InteractDistance * 2.0f)
|
||||
{
|
||||
int targetSlot = -1;
|
||||
if (equip)
|
||||
@@ -82,8 +95,8 @@ namespace Barotrauma
|
||||
foreach (InvSlotType slots in pickable.AllowedSlots)
|
||||
{
|
||||
if (slots.HasFlag(InvSlotType.Any)) continue;
|
||||
|
||||
for (int i = 0; i<character.Inventory.Items.Length; i++)
|
||||
|
||||
for (int i = 0; i < character.Inventory.Items.Length; i++)
|
||||
{
|
||||
//slot not needed by the item, continue
|
||||
if (!slots.HasFlag(CharacterInventory.limbSlots[i])) continue;
|
||||
@@ -111,15 +124,19 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (goToObjective == null)
|
||||
if (goToObjective == null || moveToTarget != goToObjective.Target)
|
||||
{
|
||||
bool gettingDivingGear = itemName == "diving" || itemName == "Diving Gear";
|
||||
//check if we're already looking for a diving gear
|
||||
bool gettingDivingGear = (targetItem != null && targetItem.Prefab.NameMatches("Diving Gear") || targetItem.HasTag("diving")) ||
|
||||
(itemNames != null && (itemNames.Contains("diving") || itemNames.Contains("Diving Gear")));
|
||||
|
||||
//don't attempt to get diving gear to reach the destination if the item we're trying to get is diving gear
|
||||
goToObjective = new AIObjectiveGoTo(moveToTarget, character, false, !gettingDivingGear);
|
||||
}
|
||||
|
||||
goToObjective.TryComplete(deltaTime);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,14 +144,14 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private void FindTargetItem()
|
||||
{
|
||||
if (itemName == null)
|
||||
if (itemNames == null)
|
||||
{
|
||||
if (targetItem == null) canBeCompleted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
float currDist = moveToTarget == null ? 0.0f : Vector2.DistanceSquared(moveToTarget.Position, character.Position);
|
||||
|
||||
|
||||
for (int i = 0; i < 10 && currSearchIndex < Item.ItemList.Count - 2; i++)
|
||||
{
|
||||
currSearchIndex++;
|
||||
@@ -143,21 +160,38 @@ namespace Barotrauma
|
||||
|
||||
if (item.CurrentHull == null || item.Condition <= 0.0f) continue;
|
||||
if (IgnoreContainedItems && item.Container != null) continue;
|
||||
if (item.Name != itemName && !item.HasTag(itemName)) continue;
|
||||
if (!itemNames.Any(name => item.Prefab.NameMatches(name) || item.HasTag(name))) continue;
|
||||
|
||||
//if the item is inside a character's inventory, don't steal it
|
||||
if (item.ParentInventory is CharacterInventory) continue;
|
||||
|
||||
//if the item is inside an item, which is inside a character's inventory, don't steal it
|
||||
if (item.ParentInventory != null && item.ParentInventory.Owner is Item)
|
||||
//if the item is inside a character's inventory, don't steal it unless the character is dead
|
||||
if (item.ParentInventory is CharacterInventory)
|
||||
{
|
||||
if (((Item)item.ParentInventory.Owner).ParentInventory is CharacterInventory) continue;
|
||||
Character owner = item.ParentInventory.Owner as Character;
|
||||
if (owner != null && !owner.IsDead) continue;
|
||||
}
|
||||
|
||||
//ignore if item is further away than the currently targeted item
|
||||
//if the item is inside an item, which is inside a character's inventory, don't steal it
|
||||
Item rootContainer = item.GetRootContainer();
|
||||
if (moveToTarget != null && Vector2.DistanceSquared((rootContainer ?? item).Position, character.Position) > currDist) continue;
|
||||
|
||||
if (rootContainer != null && rootContainer.ParentInventory is CharacterInventory)
|
||||
{
|
||||
Character owner = rootContainer.ParentInventory.Owner as Character;
|
||||
if (owner != null && !owner.IsDead) continue;
|
||||
}
|
||||
|
||||
float itemPriority = 0.0f;
|
||||
if (GetItemPriority != null)
|
||||
{
|
||||
//ignore if the item has zero priority
|
||||
itemPriority = GetItemPriority(item);
|
||||
if (itemPriority <= 0.0f) continue;
|
||||
}
|
||||
|
||||
itemPriority = itemPriority - Vector2.Distance((rootContainer ?? item).Position, character.Position) * 0.01f;
|
||||
|
||||
//ignore if the item has a lower priority than the currently selected one
|
||||
if (moveToTarget != null && itemPriority < currItemPriority) continue;
|
||||
|
||||
currItemPriority = itemPriority;
|
||||
|
||||
targetItem = item;
|
||||
moveToTarget = rootContainer ?? item;
|
||||
}
|
||||
@@ -165,23 +199,44 @@ namespace Barotrauma
|
||||
//if searched through all the items and a target wasn't found, can't be completed
|
||||
if (currSearchIndex >= Item.ItemList.Count && targetItem == null) canBeCompleted = false;
|
||||
}
|
||||
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem;
|
||||
if (getItem == null) return false;
|
||||
return (getItem.itemName == itemName);
|
||||
if (getItem.equip != equip) return false;
|
||||
if (getItem.itemNames != null && itemNames != null)
|
||||
{
|
||||
if (getItem.itemNames.Length != itemNames.Length) return false;
|
||||
for (int i = 0; i < getItem.itemNames.Length; i++)
|
||||
{
|
||||
if (getItem.itemNames[i] != itemNames[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (getItem.itemNames == null && itemNames == null)
|
||||
{
|
||||
return getItem.targetItem == targetItem;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
if (itemName!=null)
|
||||
if (itemNames != null)
|
||||
{
|
||||
return character.Inventory.FindItem(itemName) != null;
|
||||
foreach (string itemName in itemNames)
|
||||
{
|
||||
var matchingItem = character.Inventory.FindItem(itemName);
|
||||
if (matchingItem != null && (!equip || character.HasEquippedItem(matchingItem))) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
else if (targetItem!= null)
|
||||
else if (targetItem != null)
|
||||
{
|
||||
return character.Inventory.Items.Contains(targetItem);
|
||||
return character.Inventory.Items.Contains(targetItem) && (!equip || character.HasEquippedItem(targetItem));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//re-enable collider
|
||||
if (!Collider.FarseerBody.Enabled)
|
||||
if (!Collider.Enabled)
|
||||
{
|
||||
var lowestLimb = FindLowestLimb();
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Barotrauma
|
||||
Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
|
||||
0.0f);
|
||||
|
||||
Collider.FarseerBody.Enabled = true;
|
||||
Collider.Enabled = true;
|
||||
}
|
||||
|
||||
ResetPullJoints();
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Barotrauma
|
||||
|
||||
|
||||
//re-enable collider
|
||||
if (!Collider.FarseerBody.Enabled)
|
||||
if (!Collider.Enabled)
|
||||
{
|
||||
var lowestLimb = FindLowestLimb();
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Barotrauma
|
||||
Collider.Rotation);
|
||||
|
||||
Collider.FarseerBody.ResetDynamics();
|
||||
Collider.FarseerBody.Enabled = true;
|
||||
Collider.Enabled = true;
|
||||
}
|
||||
|
||||
if (swimming)
|
||||
@@ -1034,7 +1034,8 @@ namespace Barotrauma
|
||||
{
|
||||
Limb targetLimb = target.AnimController.GetLimb(GrabLimb);
|
||||
|
||||
if (targetLimb == null || targetLimb.IsSevered)
|
||||
//grab hands if GrabLimb is not specified (or torso if the character has no hands)
|
||||
if (GrabLimb == LimbType.None || targetLimb.IsSevered)
|
||||
{
|
||||
targetLimb = target.AnimController.GetLimb(LimbType.Torso);
|
||||
if (i == 0)
|
||||
|
||||
@@ -527,7 +527,7 @@ namespace Barotrauma
|
||||
|
||||
public void SeverLimbJoint(LimbJoint limbJoint)
|
||||
{
|
||||
if (!limbJoint.CanBeSevered)
|
||||
if (!limbJoint.CanBeSevered || limbJoint.IsSevered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -541,12 +541,29 @@ namespace Barotrauma
|
||||
GetConnectedLimbs(connectedLimbs, checkedJoints, MainLimb);
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (!connectedLimbs.Contains(limb))
|
||||
if (connectedLimbs.Contains(limb)) continue;
|
||||
|
||||
limb.IsSevered = true;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (character.UseBloodParticles)
|
||||
{
|
||||
foreach (Limb limb in new Limb[] { limbJoint.LimbA, limbJoint.LimbB })
|
||||
{
|
||||
limb.IsSevered = true;
|
||||
for (int i = 0; i < MathHelper.Clamp(limb.Mass * 2.0f, 1.0f, 50.0f); i++)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("gib", limb.WorldPosition, Rand.Range(0.0f, MathHelper.TwoPi), Rand.Range(200.0f, 700.0f), character.CurrentHull);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MathHelper.Clamp(limb.Mass * 2.0f, 1.0f, 10.0f); i++)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("heavygib", limb.WorldPosition, Rand.Range(0.0f, MathHelper.TwoPi), Rand.Range(50.0f, 250.0f), character.CurrentHull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(character, new object[] { NetEntityEvent.Type.Status });
|
||||
@@ -1469,5 +1486,12 @@ namespace Barotrauma
|
||||
list.Remove(this);
|
||||
}
|
||||
|
||||
public static void RemoveAll()
|
||||
{
|
||||
for (int i = list.Count - 1; i >= 0; i--)
|
||||
{
|
||||
list[i].Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace Barotrauma
|
||||
Any = Blunt | Slash | Burn
|
||||
}
|
||||
|
||||
public enum HitDetection
|
||||
{
|
||||
Distance,
|
||||
Contact
|
||||
}
|
||||
|
||||
struct AttackResult
|
||||
{
|
||||
public readonly float Damage;
|
||||
@@ -39,90 +45,87 @@ namespace Barotrauma
|
||||
|
||||
partial class Attack
|
||||
{
|
||||
public readonly float Range;
|
||||
public readonly float DamageRange;
|
||||
public readonly float Duration;
|
||||
[Serialize(HitDetection.Distance, false)]
|
||||
public HitDetection HitDetectionType { get; private set; }
|
||||
|
||||
public readonly DamageType DamageType;
|
||||
[Serialize(0.0f, false)]
|
||||
public float Range { get; private set; }
|
||||
|
||||
private readonly float structureDamage;
|
||||
private readonly float damage;
|
||||
private readonly float bleedingDamage;
|
||||
[Serialize(0.0f, false)]
|
||||
public float DamageRange { get; private set; }
|
||||
|
||||
private readonly bool onlyHumans;
|
||||
[Serialize(0.0f, false)]
|
||||
public float Duration { get; private set; }
|
||||
|
||||
private readonly List<StatusEffect> statusEffects;
|
||||
[Serialize(DamageType.None, false)]
|
||||
public DamageType DamageType { get; private set; }
|
||||
|
||||
public readonly float Force;
|
||||
[Serialize(0.0f, false)]
|
||||
public float StructureDamage { get; private set; }
|
||||
|
||||
public readonly float Torque;
|
||||
[Serialize(0.0f, false)]
|
||||
public float Damage { get; private set; }
|
||||
|
||||
public readonly float TargetForce;
|
||||
[Serialize(0.0f, false)]
|
||||
public float BleedingDamage { get; private set; }
|
||||
|
||||
public readonly float SeverLimbsProbability;
|
||||
[Serialize(0.0f, false)]
|
||||
public float Stun { get; private set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool OnlyHumans { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float Force { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float Torque { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float TargetForce { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float SeverLimbsProbability { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float Priority { get; private set; }
|
||||
|
||||
//the indices of the limbs Force is applied on
|
||||
//(if none, force is applied only to the limb the attack is attached to)
|
||||
public readonly List<int> ApplyForceOnLimbs;
|
||||
|
||||
public readonly float Stun;
|
||||
|
||||
private float priority;
|
||||
private readonly List<StatusEffect> statusEffects;
|
||||
|
||||
public float GetDamage(float deltaTime)
|
||||
{
|
||||
return (Duration == 0.0f) ? damage : damage * deltaTime;
|
||||
return (Duration == 0.0f) ? Damage : Damage * deltaTime;
|
||||
}
|
||||
|
||||
public float GetBleedingDamage(float deltaTime)
|
||||
{
|
||||
return (Duration == 0.0f) ? bleedingDamage : bleedingDamage * deltaTime;
|
||||
return (Duration == 0.0f) ? BleedingDamage : BleedingDamage * deltaTime;
|
||||
}
|
||||
|
||||
public float GetStructureDamage(float deltaTime)
|
||||
{
|
||||
return (Duration == 0.0f) ? structureDamage : structureDamage * deltaTime;
|
||||
return (Duration == 0.0f) ? StructureDamage : StructureDamage * deltaTime;
|
||||
}
|
||||
|
||||
public Attack(float damage, float structureDamage, float bleedingDamage, float range = 0.0f)
|
||||
{
|
||||
Range = range;
|
||||
DamageRange = range;
|
||||
this.damage = damage;
|
||||
this.structureDamage = structureDamage;
|
||||
this.bleedingDamage = bleedingDamage;
|
||||
this.Damage = damage;
|
||||
this.StructureDamage = structureDamage;
|
||||
this.BleedingDamage = bleedingDamage;
|
||||
}
|
||||
|
||||
public Attack(XElement element)
|
||||
{
|
||||
try
|
||||
{
|
||||
DamageType = (DamageType)Enum.Parse(typeof(DamageType), element.GetAttributeString("damagetype", "None"), true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
DamageType = DamageType.None;
|
||||
}
|
||||
|
||||
damage = element.GetAttributeFloat("damage", 0.0f);
|
||||
structureDamage = element.GetAttributeFloat("structuredamage", 0.0f);
|
||||
bleedingDamage = element.GetAttributeFloat("bleedingdamage", 0.0f);
|
||||
Stun = element.GetAttributeFloat("stun", 0.0f);
|
||||
|
||||
SeverLimbsProbability = element.GetAttributeFloat("severlimbsprobability", 0.0f);
|
||||
|
||||
Force = element.GetAttributeFloat("force", 0.0f);
|
||||
TargetForce = element.GetAttributeFloat("targetforce", 0.0f);
|
||||
Torque = element.GetAttributeFloat("torque", 0.0f);
|
||||
|
||||
Range = element.GetAttributeFloat("range", 0.0f);
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
DamageRange = element.GetAttributeFloat("damagerange", Range);
|
||||
Duration = element.GetAttributeFloat("duration", 0.0f);
|
||||
|
||||
priority = element.GetAttributeFloat("priority", 1.0f);
|
||||
|
||||
onlyHumans = element.GetAttributeBool("onlyhumans", false);
|
||||
|
||||
|
||||
InitProjSpecific(element);
|
||||
|
||||
string limbIndicesStr = element.GetAttributeString("applyforceonlimbs", "");
|
||||
@@ -158,7 +161,7 @@ namespace Barotrauma
|
||||
|
||||
public AttackResult DoDamage(Character attacker, IDamageable target, Vector2 worldPosition, float deltaTime, bool playSound = true)
|
||||
{
|
||||
if (onlyHumans)
|
||||
if (OnlyHumans)
|
||||
{
|
||||
Character character = target as Character;
|
||||
if (character != null && character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
||||
@@ -189,7 +192,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (targetLimb == null) return new AttackResult();
|
||||
|
||||
if (onlyHumans)
|
||||
if (OnlyHumans)
|
||||
{
|
||||
if (targetLimb.character != null && targetLimb.character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
||||
}
|
||||
|
||||
@@ -344,18 +344,18 @@ namespace Barotrauma
|
||||
if (GameMain.Client != null) return;
|
||||
|
||||
float newHealth = MathHelper.Clamp(value, minHealth, maxHealth);
|
||||
if (newHealth == health) return;
|
||||
//if (newHealth == health) return;
|
||||
|
||||
health = newHealth;
|
||||
|
||||
if (GameMain.Server != null)
|
||||
/*if (GameMain.Server != null)
|
||||
{
|
||||
if (Math.Abs(health - lastSentHealth) > (maxHealth - minHealth) / 255.0f || Math.Sign(health) != Math.Sign(lastSentHealth))
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
lastSentHealth = health;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,12 +374,12 @@ namespace Barotrauma
|
||||
if (!DoesBleed) return;
|
||||
|
||||
float newBleeding = MathHelper.Clamp(value, 0.0f, 5.0f);
|
||||
if (newBleeding == bleeding) return;
|
||||
//if (newBleeding == bleeding) return;
|
||||
|
||||
bleeding = newBleeding;
|
||||
|
||||
if (GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
|
||||
/*if (GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +426,12 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool UseBloodParticles
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float BleedingDecreaseSpeed
|
||||
{
|
||||
get;
|
||||
@@ -634,6 +640,7 @@ namespace Barotrauma
|
||||
health = maxHealth;
|
||||
|
||||
DoesBleed = doc.Root.GetAttributeBool("doesbleed", true);
|
||||
UseBloodParticles = doc.Root.GetAttributeBool("usebloodparticles", true);
|
||||
BleedingDecreaseSpeed = doc.Root.GetAttributeFloat("bleedingdecreasespeed", 0.05f);
|
||||
|
||||
needsAir = doc.Root.GetAttributeBool("needsair", false);
|
||||
@@ -1046,6 +1053,17 @@ namespace Barotrauma
|
||||
return !inventory.IsInLimbSlot(item, InvSlotType.Any);
|
||||
}
|
||||
|
||||
public bool HasEquippedItem(string itemName)
|
||||
{
|
||||
for (int i = 0; i < inventory.Items.Length; i++)
|
||||
{
|
||||
if (CharacterInventory.limbSlots[i] == InvSlotType.Any || inventory.Items[i] == null) continue;
|
||||
if (inventory.Items[i].Prefab.NameMatches(itemName) || inventory.Items[i].HasTag(itemName)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasSelectedItem(Item item)
|
||||
{
|
||||
return selectedItems.Contains(item);
|
||||
@@ -1541,11 +1559,11 @@ namespace Barotrauma
|
||||
if (stunTimer > 0.0f)
|
||||
{
|
||||
stunTimer -= deltaTime;
|
||||
if (stunTimer < 0.0f && GameMain.Server != null)
|
||||
/*if (stunTimer < 0.0f && GameMain.Server != null)
|
||||
{
|
||||
//stun ended -> notify clients
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
//Skip health effects as critical health handles it differently
|
||||
@@ -1575,8 +1593,8 @@ namespace Barotrauma
|
||||
if (IsRagdolled)
|
||||
{
|
||||
if (AnimController is HumanoidAnimController) ((HumanoidAnimController)AnimController).Crouching = false;
|
||||
if(GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
/*if(GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });*/
|
||||
AnimController.ResetPullJoints();
|
||||
selectedConstruction = null;
|
||||
return;
|
||||
@@ -1831,11 +1849,11 @@ namespace Barotrauma
|
||||
|
||||
if ((newStun <= stunTimer && !allowStunDecrease) || !MathUtils.IsValid(newStun)) return;
|
||||
|
||||
if (GameMain.Server != null &&
|
||||
/*if (GameMain.Server != null &&
|
||||
(Math.Sign(newStun) != Math.Sign(stunTimer) || Math.Abs(newStun - stunTimer) > 0.1f))
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
}
|
||||
}*/
|
||||
|
||||
if (Math.Sign(newStun) != Math.Sign(stunTimer)) AnimController.ResetPullJoints();
|
||||
|
||||
@@ -1894,11 +1912,11 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
/*if (GameMain.NetworkMember != null)
|
||||
{
|
||||
if (GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
}
|
||||
}*/
|
||||
|
||||
AnimController.Frozen = false;
|
||||
|
||||
|
||||
@@ -332,6 +332,7 @@ namespace Barotrauma
|
||||
inventory.ServerRead(type, msg, c);
|
||||
break;
|
||||
case 1:
|
||||
bool doingCPR = msg.ReadBoolean();
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
@@ -340,7 +341,6 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
bool doingCPR = msg.ReadBoolean();
|
||||
AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None;
|
||||
break;
|
||||
case 2:
|
||||
@@ -358,7 +358,15 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
AnimController.GrabLimb = (LimbType)msg.ReadUInt16();
|
||||
LimbType grabLimb = (LimbType)msg.ReadUInt16();
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
AnimController.GrabLimb = grabLimb;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -384,10 +392,6 @@ namespace Barotrauma
|
||||
Client owner = ((Client)extraData[1]);
|
||||
msg.Write(owner == null ? (byte)0 : owner.ID);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(0, 2, 2);
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
}
|
||||
msg.WritePadBits();
|
||||
}
|
||||
@@ -474,6 +478,8 @@ namespace Barotrauma
|
||||
tempBuffer.Write(SimPosition.Y);
|
||||
tempBuffer.Write(AnimController.Collider.Rotation);
|
||||
|
||||
WriteStatus(tempBuffer);
|
||||
|
||||
tempBuffer.WritePadBits();
|
||||
|
||||
msg.Write((byte)tempBuffer.LengthBytes);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
@@ -386,23 +387,25 @@ namespace Barotrauma
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
|
||||
}
|
||||
|
||||
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
||||
|
||||
for (int i = 0; i < bloodParticleAmount; i++)
|
||||
if (character.UseBloodParticles)
|
||||
{
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
if (blood != null)
|
||||
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
||||
|
||||
for (int i = 0; i < bloodParticleAmount; i++)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
if (blood != null)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodParticleAmount > 0 && character.CurrentHull != null)
|
||||
{
|
||||
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodParticleAmount > 0 && character.CurrentHull != null)
|
||||
{
|
||||
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (damageType == DamageType.Burn)
|
||||
@@ -479,12 +482,69 @@ namespace Barotrauma
|
||||
|
||||
body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque);
|
||||
|
||||
if (dist < attack.DamageRange)
|
||||
bool wasHit = false;
|
||||
|
||||
if (damageTarget != null)
|
||||
{
|
||||
switch (attack.HitDetectionType)
|
||||
{
|
||||
case HitDetection.Distance:
|
||||
wasHit = dist < attack.DamageRange;
|
||||
break;
|
||||
case HitDetection.Contact:
|
||||
List<Body> targetBodies = new List<Body>();
|
||||
if (damageTarget is Character)
|
||||
{
|
||||
Character targetCharacter = (Character)damageTarget;
|
||||
foreach (Limb limb in targetCharacter.AnimController.Limbs)
|
||||
{
|
||||
if (!limb.IsSevered && limb.body?.FarseerBody != null) targetBodies.Add(limb.body.FarseerBody);
|
||||
}
|
||||
}
|
||||
else if (damageTarget is Structure)
|
||||
{
|
||||
Structure targetStructure = (Structure)damageTarget;
|
||||
|
||||
if (character.Submarine == null && targetStructure.Submarine != null)
|
||||
{
|
||||
targetBodies.Add(targetStructure.Submarine.PhysicsBody.FarseerBody);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetBodies.AddRange(targetStructure.Bodies);
|
||||
}
|
||||
}
|
||||
else if (damageTarget is Item)
|
||||
{
|
||||
Item targetItem = damageTarget as Item;
|
||||
if (targetItem.body?.FarseerBody != null) targetBodies.Add(targetItem.body.FarseerBody);
|
||||
}
|
||||
|
||||
if (targetBodies != null)
|
||||
{
|
||||
ContactEdge contactEdge = body.FarseerBody.ContactList;
|
||||
while (contactEdge != null)
|
||||
{
|
||||
if (contactEdge.Contact != null &&
|
||||
contactEdge.Contact.IsTouching &&
|
||||
targetBodies.Any(b => b == contactEdge.Contact.FixtureA?.Body || b == contactEdge.Contact.FixtureB?.Body))
|
||||
{
|
||||
wasHit = true;
|
||||
break;
|
||||
}
|
||||
|
||||
contactEdge = contactEdge.Next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wasHit)
|
||||
{
|
||||
if (AttackTimer >= attack.Duration && damageTarget != null)
|
||||
{
|
||||
attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
|
||||
|
||||
SoundTimer = SoundInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@ namespace Barotrauma
|
||||
{
|
||||
public string Text;
|
||||
public Color Color;
|
||||
public bool IsCommand;
|
||||
|
||||
public readonly string Time;
|
||||
|
||||
public ColoredText(string text, Color color)
|
||||
public ColoredText(string text, Color color, bool isCommand)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Color = color;
|
||||
this.IsCommand = isCommand;
|
||||
|
||||
Time = DateTime.Now.ToString();
|
||||
}
|
||||
@@ -44,6 +46,8 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private Action<Client, Vector2, string[]> onClientRequestExecute;
|
||||
|
||||
public Func<string[][]> GetValidArgs;
|
||||
|
||||
public bool RelayToServer
|
||||
{
|
||||
get { return onClientExecute == null; }
|
||||
@@ -54,7 +58,7 @@ namespace Barotrauma
|
||||
/// <param name="onExecute">The default action when executing the command.</param>
|
||||
/// <param name="onClientExecute">The action when a client attempts to execute the command. If null, the command is relayed to the server as-is.</param>
|
||||
/// <param name="onClientRequestExecute">The server-side action when a client requests executing the command. If null, the default action is executed.</param>
|
||||
public Command(string name, string help, Action<string[]> onExecute, Action<string[]> onClientExecute, Action<Client, Vector2, string[]> onClientRequestExecute)
|
||||
public Command(string name, string help, Action<string[]> onExecute, Action<string[]> onClientExecute, Action<Client, Vector2, string[]> onClientRequestExecute, Func<string[][]> getValidArgs = null)
|
||||
{
|
||||
names = name.Split('|');
|
||||
this.help = help;
|
||||
@@ -62,19 +66,23 @@ namespace Barotrauma
|
||||
this.onExecute = onExecute;
|
||||
this.onClientExecute = onClientExecute;
|
||||
this.onClientRequestExecute = onClientRequestExecute;
|
||||
|
||||
this.GetValidArgs = getValidArgs;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use this constructor to create a command that executes the same action regardless of whether it's executed by a client or the server.
|
||||
/// </summary>
|
||||
public Command(string name, string help, Action<string[]> onExecute)
|
||||
public Command(string name, string help, Action<string[]> onExecute, Func<string[][]> getValidArgs = null)
|
||||
{
|
||||
names = name.Split('|');
|
||||
this.help = help;
|
||||
|
||||
this.onExecute = onExecute;
|
||||
this.onClientExecute = onExecute;
|
||||
|
||||
this.GetValidArgs = getValidArgs;
|
||||
}
|
||||
|
||||
public void Execute(string[] args)
|
||||
@@ -194,7 +202,7 @@ namespace Barotrauma
|
||||
UpdaterUtil.SaveFileList("filelist.xml");
|
||||
}));
|
||||
|
||||
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename] [near/inside/outside]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine).", (string[] args) =>
|
||||
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename] [near/inside/outside/cursor]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine).", (string[] args) =>
|
||||
{
|
||||
string errorMsg;
|
||||
SpawnCharacter(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), out errorMsg);
|
||||
@@ -212,6 +220,20 @@ namespace Barotrauma
|
||||
{
|
||||
ThrowError(errorMsg);
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
List<string> characterFiles = GameMain.Config.SelectedContentPackage.GetFilesOfType(ContentType.Character);
|
||||
for (int i = 0; i < characterFiles.Count; i++)
|
||||
{
|
||||
characterFiles[i] = Path.GetFileNameWithoutExtension(characterFiles[i]).ToLowerInvariant();
|
||||
}
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
characterFiles.ToArray(),
|
||||
new string[] { "near", "inside", "outside", "cursor" }
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.",
|
||||
@@ -233,6 +255,21 @@ namespace Barotrauma
|
||||
{
|
||||
ThrowError(errorMsg);
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
List<string> itemNames = new List<string>();
|
||||
foreach (MapEntityPrefab prefab in MapEntityPrefab.List)
|
||||
{
|
||||
ItemPrefab itemPrefab = prefab as ItemPrefab;
|
||||
if (itemPrefab != null) itemNames.Add(itemPrefab.Name);
|
||||
}
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
itemNames.ToArray(),
|
||||
new string[] { "cursor", "inventory" }
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) =>
|
||||
@@ -570,6 +607,15 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.NetworkMember.KickPlayer(playerName, reason);
|
||||
});
|
||||
},
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) =>
|
||||
@@ -615,6 +661,15 @@ namespace Barotrauma
|
||||
GameMain.NetworkMember.BanPlayer(clientName, reason, false, banDuration);
|
||||
});
|
||||
});
|
||||
},
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) =>
|
||||
@@ -728,6 +783,13 @@ namespace Barotrauma
|
||||
tpCharacter.Submarine = null;
|
||||
tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cursorWorldPos));
|
||||
tpCharacter.AnimController.FindHull(cursorWorldPos, true);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("godmode", "godmode: Toggle submarine godmode. Makes the main submarine invulnerable to damage.", (string[] args) =>
|
||||
@@ -810,6 +872,13 @@ namespace Barotrauma
|
||||
healedCharacter.Bleeding = 0.0f;
|
||||
healedCharacter.SetStun(0.0f, true);
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) =>
|
||||
@@ -866,6 +935,13 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("freeze", "", (string[] args) =>
|
||||
@@ -894,6 +970,13 @@ namespace Barotrauma
|
||||
{
|
||||
ragdolledCharacter.IsForceRagdolled = !ragdolledCharacter.IsForceRagdolled;
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("freecamera|freecam", "freecam: Detach the camera from the controlled character.", (string[] args) =>
|
||||
@@ -1067,6 +1150,16 @@ namespace Barotrauma
|
||||
|
||||
var character = FindMatchingCharacter(argsRight, false);
|
||||
GameMain.Server.SetClientCharacter(client, character);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray(),
|
||||
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("campaigninfo|campaignstatus", "campaigninfo: Display information about the state of the currently active campaign.", (string[] args) =>
|
||||
@@ -1267,28 +1360,80 @@ namespace Barotrauma
|
||||
|
||||
public static string AutoComplete(string command)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentAutoCompletedCommand))
|
||||
{
|
||||
currentAutoCompletedCommand = command;
|
||||
}
|
||||
string[] splitCommand = SplitCommand(command);
|
||||
string[] args = splitCommand.Skip(1).ToArray();
|
||||
|
||||
List<string> matchingCommands = new List<string>();
|
||||
foreach (Command c in commands)
|
||||
//if an argument is given or the last character is a space, attempt to autocomplete the argument
|
||||
if (args.Length > 0 || (command.Length > 0 && command.Last() == ' '))
|
||||
{
|
||||
foreach (string name in c.names)
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommand[0]));
|
||||
if (matchingCommand == null || matchingCommand.GetValidArgs == null) return command;
|
||||
|
||||
int autoCompletedArgIndex = args.Length > 0 && command.Last() != ' ' ? args.Length - 1 : args.Length;
|
||||
|
||||
//get all valid arguments for the given command
|
||||
string[][] allArgs = matchingCommand.GetValidArgs();
|
||||
if (allArgs == null || allArgs.GetLength(0) < autoCompletedArgIndex + 1) return command;
|
||||
|
||||
if (string.IsNullOrEmpty(currentAutoCompletedCommand))
|
||||
{
|
||||
if (currentAutoCompletedCommand.Length > name.Length) continue;
|
||||
if (currentAutoCompletedCommand == name.Substring(0, currentAutoCompletedCommand.Length))
|
||||
currentAutoCompletedCommand = autoCompletedArgIndex > args.Length - 1 ? " " : args.Last();
|
||||
}
|
||||
|
||||
//find all valid autocompletions for the given argument
|
||||
string[] validArgs = allArgs[autoCompletedArgIndex].Where(arg =>
|
||||
currentAutoCompletedCommand.Trim().Length <= arg.Length &&
|
||||
arg.Substring(0, currentAutoCompletedCommand.Trim().Length).ToLower() == currentAutoCompletedCommand.Trim().ToLower()).ToArray();
|
||||
|
||||
if (validArgs.Length == 0) return command;
|
||||
|
||||
currentAutoCompletedIndex = currentAutoCompletedIndex % validArgs.Length;
|
||||
string autoCompletedArg = validArgs[currentAutoCompletedIndex++];
|
||||
|
||||
//add quotation marks to args that contain spaces
|
||||
if (autoCompletedArg.Contains(' ')) autoCompletedArg = '"' + autoCompletedArg + '"';
|
||||
for (int i = 0; i < splitCommand.Length; i++)
|
||||
{
|
||||
if (splitCommand[i].Contains(' ')) splitCommand[i] = '"' + splitCommand[i] + '"';
|
||||
}
|
||||
|
||||
return string.Join(" ", autoCompletedArgIndex >= args.Length ? splitCommand : splitCommand.Take(splitCommand.Length - 1)) + " " + autoCompletedArg;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentAutoCompletedCommand))
|
||||
{
|
||||
currentAutoCompletedCommand = command;
|
||||
}
|
||||
|
||||
List<string> matchingCommands = new List<string>();
|
||||
foreach (Command c in commands)
|
||||
{
|
||||
foreach (string name in c.names)
|
||||
{
|
||||
matchingCommands.Add(name);
|
||||
if (currentAutoCompletedCommand.Length > name.Length) continue;
|
||||
if (currentAutoCompletedCommand == name.Substring(0, currentAutoCompletedCommand.Length))
|
||||
{
|
||||
matchingCommands.Add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingCommands.Count == 0) return command;
|
||||
|
||||
currentAutoCompletedIndex = currentAutoCompletedIndex % matchingCommands.Count;
|
||||
return matchingCommands[currentAutoCompletedIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingCommands.Count == 0) return command;
|
||||
|
||||
currentAutoCompletedIndex = currentAutoCompletedIndex % matchingCommands.Count;
|
||||
return matchingCommands[currentAutoCompletedIndex++];
|
||||
private static string AutoCompleteStr(string str, IEnumerable<string> validStrings)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str)) return str;
|
||||
foreach (string validStr in validStrings)
|
||||
{
|
||||
if (validStr.Length > str.Length && validStr.Substring(0, str.Length) == str) return validStr;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static void ResetAutoComplete()
|
||||
@@ -1303,9 +1448,14 @@ namespace Barotrauma
|
||||
|
||||
direction = MathHelper.Clamp(direction, -1, 1);
|
||||
|
||||
selectedIndex += direction;
|
||||
if (selectedIndex < 0) selectedIndex = Messages.Count - 1;
|
||||
selectedIndex = selectedIndex % Messages.Count;
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
selectedIndex += direction;
|
||||
if (selectedIndex < 0) selectedIndex = Messages.Count - 1;
|
||||
selectedIndex = selectedIndex % Messages.Count;
|
||||
if (++i >= Messages.Count) break;
|
||||
} while (!Messages[selectedIndex].IsCommand);
|
||||
|
||||
return Messages[selectedIndex].Text;
|
||||
}
|
||||
@@ -1317,7 +1467,7 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
activeQuestionText = null;
|
||||
#endif
|
||||
NewMessage(command, Color.White);
|
||||
NewMessage(command, Color.White, true);
|
||||
//reset the variable before invoking the delegate because the method may need to activate another question
|
||||
var temp = activeQuestionCallback;
|
||||
activeQuestionCallback = null;
|
||||
@@ -1331,7 +1481,7 @@ namespace Barotrauma
|
||||
|
||||
if (!splitCommand[0].ToLowerInvariant().Equals("admin"))
|
||||
{
|
||||
NewMessage(command, Color.White);
|
||||
NewMessage(command, Color.White, true);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
@@ -1611,12 +1761,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void NewMessage(string msg, Color color)
|
||||
public static void NewMessage(string msg, Color color, bool isCommand = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty((msg))) return;
|
||||
|
||||
#if SERVER
|
||||
Messages.Add(new ColoredText(msg, color));
|
||||
Messages.Add(new ColoredText(msg, color, isCommand));
|
||||
|
||||
//TODO: REMOVE
|
||||
Console.ForegroundColor = XnaToConsoleColor.Convert(color);
|
||||
@@ -1631,7 +1781,7 @@ namespace Barotrauma
|
||||
#elif CLIENT
|
||||
lock (queuedMessages)
|
||||
{
|
||||
queuedMessages.Enqueue(new ColoredText(msg, color));
|
||||
queuedMessages.Enqueue(new ColoredText(msg, color, isCommand));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,43 +16,39 @@ namespace Barotrauma
|
||||
|
||||
public void Greet(GameServer server, string codeWords, string codeResponse)
|
||||
{
|
||||
//Greeting messages TODO: Move this to a function in Traitor class
|
||||
string greetingMessage = "You are the Traitor! Your secret task is to assassinate " + TargetCharacter.Name + "! Discretion is an utmost concern; sinking the submarine and killing the entire crew "
|
||||
+ "will arouse suspicion amongst the Fleet. If possible, make the death look like an accident.";
|
||||
string moreAgentsMessage = "It is possible that there are other agents on this submarine. You don't know their names, but you do have a method of communication. "
|
||||
+ "Use the code words to greet the agent and code response to respond. Disguise such words in a normal-looking phrase so the crew doesn't suspect anything.";
|
||||
moreAgentsMessage += "\nThe code words are: " + codeWords + ".";
|
||||
moreAgentsMessage += "\nThe code response is: " + codeResponse + ".\n";
|
||||
string greetingMessage = TextManager.Get("TraitorStartMessage").Replace("[targetname]", TargetCharacter.Name);
|
||||
string moreAgentsMessage = TextManager.Get("TraitorMoreAgentsMessage")
|
||||
.Replace("[codewords]", codeWords)
|
||||
.Replace("[coderesponse]", codeResponse);
|
||||
|
||||
if (server.Character != Character)
|
||||
{
|
||||
var chatMsg = ChatMessage.Create(
|
||||
null,
|
||||
greetingMessage + "\n" + moreAgentsMessage,
|
||||
(ChatMessageType)ChatMessageType.Server,
|
||||
null);
|
||||
|
||||
var msgBox = ChatMessage.Create(
|
||||
null,
|
||||
"There might be other agents. Use these to communicate with them." +
|
||||
"\nThe code words are: " + codeWords + "." +
|
||||
"\nThe code response is: " + codeResponse + ".",
|
||||
(ChatMessageType)ChatMessageType.MessageBox,
|
||||
null);
|
||||
var greetingChatMsg = ChatMessage.Create(null, greetingMessage, ChatMessageType.Server, null);
|
||||
var moreAgentsChatMsg = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.Server, null);
|
||||
|
||||
var greetingMsgBox = ChatMessage.Create(null, greetingMessage, ChatMessageType.MessageBox, null);
|
||||
var moreAgentsMsgBox = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.MessageBox, null);
|
||||
|
||||
Client client = server.ConnectedClients.Find(c => c.Character == Character);
|
||||
GameMain.Server.SendChatMessage(chatMsg, client);
|
||||
GameMain.Server.SendChatMessage(msgBox, client);
|
||||
GameMain.Server.SendChatMessage(greetingChatMsg, client);
|
||||
GameMain.Server.SendChatMessage(moreAgentsChatMsg, client);
|
||||
GameMain.Server.SendChatMessage(greetingMsgBox, client);
|
||||
GameMain.Server.SendChatMessage(moreAgentsMsgBox, client);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (server.Character == null)
|
||||
{
|
||||
new GUIMessageBox("New traitor", Character.Name + " is the traitor and the target is " + TargetCharacter.Name+".");
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("NewTraitor"),
|
||||
TextManager.Get("TraitorStartMessageServer").Replace("[targetname]", TargetCharacter.Name).Replace("[traitorname]", Character.Name));
|
||||
}
|
||||
else if (server.Character == Character)
|
||||
{
|
||||
TraitorManager.CreateStartPopUp(TargetCharacter.Name);
|
||||
new GUIMessageBox("", greetingMessage);
|
||||
new GUIMessageBox("", moreAgentsMessage);
|
||||
|
||||
GameMain.NetworkMember.AddChatMessage(greetingMessage, ChatMessageType.Server);
|
||||
GameMain.NetworkMember.AddChatMessage(moreAgentsMessage, ChatMessageType.Server);
|
||||
return;
|
||||
}
|
||||
@@ -151,72 +147,43 @@ namespace Barotrauma
|
||||
{
|
||||
Character traitorCharacter = traitor.Character;
|
||||
Character targetCharacter = traitor.TargetCharacter;
|
||||
endMessage += traitorCharacter.Name + " was a traitor! ";
|
||||
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "His" : "Her";
|
||||
endMessage += " task was to assassinate " + targetCharacter.Name;
|
||||
string messageTag;
|
||||
|
||||
if (targetCharacter.IsDead) //Partial or complete mission success
|
||||
{
|
||||
endMessage += ". The task was successful";
|
||||
if (traitorCharacter.IsDead)
|
||||
{
|
||||
endMessage += ", but luckily the bastard didn't make it out alive either.";
|
||||
messageTag = "TraitorEndMessageSuccessTraitorDead";
|
||||
}
|
||||
else if (traitorCharacter.LockHands)
|
||||
{
|
||||
endMessage += ", but ";
|
||||
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "he" : "she";
|
||||
endMessage += " was successfuly detained.";
|
||||
messageTag = "TraitorEndMessageSuccessTraitorDetained";
|
||||
}
|
||||
else
|
||||
endMessage += ".";
|
||||
messageTag = "TraitorEndMessageSuccess";
|
||||
}
|
||||
else //Partial or complete failure
|
||||
{
|
||||
if (traitorCharacter.IsDead)
|
||||
{
|
||||
endMessage += ", but ";
|
||||
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "he" : "she";
|
||||
endMessage += " got " + ((traitorCharacter.Info.Gender == Gender.Male) ? "himself" : "herself");
|
||||
endMessage += " killed before completing it.";
|
||||
messageTag = "TraitorEndMessageFailureTraitorDead";
|
||||
}
|
||||
else if (traitorCharacter.LockHands)
|
||||
{
|
||||
messageTag = "TraitorEndMessageFailureTraitorDetained";
|
||||
}
|
||||
else
|
||||
{
|
||||
endMessage += ". The task was unsuccessful";
|
||||
if (traitorCharacter.LockHands)
|
||||
{
|
||||
endMessage += " - ";
|
||||
endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "he" : "she";
|
||||
endMessage += " was successfuly detained";
|
||||
}
|
||||
if (Submarine.MainSub.AtEndPosition)
|
||||
{
|
||||
endMessage += (traitorCharacter.LockHands ? " and " : " - ");
|
||||
endMessage += "the submarine has reached its destination";
|
||||
}
|
||||
endMessage += ".";
|
||||
messageTag = "TraitorEndMessageFailure";
|
||||
}
|
||||
}
|
||||
endMessage += "\n";
|
||||
|
||||
endMessage += (TextManager.ReplaceGenderPronouns(TextManager.Get(messageTag), traitorCharacter.Info.Gender) + "\n")
|
||||
.Replace("[traitorname]", traitorCharacter.Name)
|
||||
.Replace("[targetname]", targetCharacter.Name);
|
||||
}
|
||||
|
||||
return endMessage;
|
||||
return endMessage;
|
||||
}
|
||||
|
||||
//public void CharacterLeft(Character character)
|
||||
//{
|
||||
// if (character != traitorCharacter && character != targetCharacter) return;
|
||||
|
||||
// if (character == traitorCharacter)
|
||||
// {
|
||||
// string endMessage = "The traitor has disconnected from the server.";
|
||||
// End(endMessage);
|
||||
// }
|
||||
// else if (character == targetCharacter)
|
||||
// {
|
||||
// string endMessage = "The traitor's target has disconnected from the server.";
|
||||
// End(endMessage);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
static class InfoTextManager
|
||||
{
|
||||
|
||||
private static Dictionary<string, List<string>> infoTexts;
|
||||
|
||||
static InfoTextManager()
|
||||
{
|
||||
LoadInfoTexts(Path.Combine("Content", "InfoTexts.xml"));
|
||||
}
|
||||
|
||||
|
||||
private static void LoadInfoTexts(string file)
|
||||
{
|
||||
infoTexts = new Dictionary<string, List<string>>();
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
foreach (XElement subElement in doc.Root.Elements())
|
||||
{
|
||||
string infoName = subElement.Name.ToString().ToLowerInvariant();
|
||||
List<string> infoList = null;
|
||||
if (!infoTexts.TryGetValue(infoName, out infoList))
|
||||
{
|
||||
infoList = new List<string>();
|
||||
infoTexts.Add(infoName, infoList);
|
||||
}
|
||||
|
||||
infoList.Add(subElement.ElementInnerText());
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetInfoText(string infoName)
|
||||
{
|
||||
List<string> infoList = null;
|
||||
if (!infoTexts.TryGetValue(infoName.ToLowerInvariant(), out infoList) || !infoList.Any())
|
||||
{
|
||||
#if DEBUG
|
||||
return "Info text \"" + infoName + "\" not found";
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
string text = infoList[Rand.Int(infoList.Count)];
|
||||
|
||||
#if CLIENT
|
||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
||||
{
|
||||
text = text.Replace("[" + inputType.ToString() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Submarine.MainSub != null) text = text.Replace("[sub]", Submarine.MainSub.Name);
|
||||
if (GameMain.GameSession != null && GameMain.GameSession.StartLocation != null)
|
||||
{
|
||||
text = text.Replace("[location]", GameMain.GameSession.StartLocation.Name);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +454,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float[] skillSuccess = new float[requiredSkills.Count];
|
||||
|
||||
for (int i = 0; i < requiredSkills.Count; i++ )
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
{
|
||||
int characterLevel = character.GetSkillLevel(requiredSkills[i].Name);
|
||||
|
||||
@@ -463,7 +463,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float average = skillSuccess.Average();
|
||||
|
||||
return (average+100.0f)/2.0f;
|
||||
return (average + 100.0f) / 2.0f;
|
||||
}
|
||||
|
||||
public virtual void FlipX() { }
|
||||
@@ -570,6 +570,7 @@ namespace Barotrauma.Items.Components
|
||||
case "requireditem":
|
||||
if (!overrideRequiredItems) requiredItems.Clear();
|
||||
overrideRequiredItems = true;
|
||||
|
||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement);
|
||||
|
||||
if (newRequiredItem == null) continue;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -141,6 +142,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public float AvailableFuel { get; set; }
|
||||
|
||||
private float availableHeat, availableCooling;
|
||||
private float prevTemperature, temperatureChange;
|
||||
|
||||
[Serialize(500.0f, true)]
|
||||
public float ShutDownTemp
|
||||
{
|
||||
@@ -191,12 +195,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
fissionRate = Math.Min(fissionRate, AvailableFuel);
|
||||
|
||||
float heat = 80 * fissionRate * (AvailableFuel / 2000.0f);
|
||||
float heatDissipation = 50 * coolingRate + Math.Max(ExtraCooling, 5.0f);
|
||||
//the amount of cooling is always non-zero, so that the reactor always needs
|
||||
//to generate some amount of heat to prevent the temperature from dropping
|
||||
availableCooling = Math.Max(ExtraCooling, 5.0f);
|
||||
availableHeat = 80 * (AvailableFuel / 2000.0f);
|
||||
|
||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
||||
float heat = availableHeat * fissionRate;
|
||||
float heatDissipation = 50 * coolingRate + availableCooling;
|
||||
|
||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
||||
Temperature = temperature + deltaTemp;
|
||||
|
||||
temperatureChange = Temperature - prevTemperature;
|
||||
prevTemperature = temperature;
|
||||
|
||||
if (temperature > fireTemp && temperature - deltaTemp < fireTemp)
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -345,37 +357,71 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||
{
|
||||
float degreeOfSuccess = DegreeOfSuccess(character);
|
||||
|
||||
//characters with insufficient skill levels don't refuel the reactor
|
||||
if (degreeOfSuccess > 0.2f)
|
||||
{
|
||||
//remove used-up fuel from the reactor
|
||||
var containedItems = item.ContainedItems;
|
||||
foreach (Item item in containedItems)
|
||||
{
|
||||
if (item != null && item.Condition <= 0.0f)
|
||||
{
|
||||
item.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
//the temperature is too low and not increasing even though the fission rate is high and cooling low
|
||||
// -> we need more fuel
|
||||
if (temperature < load * 0.5f && temperatureChange <= 0.0f && fissionRate > 0.9f && coolingRate < 0.1f)
|
||||
{
|
||||
var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "Fuel Rod", "reactorfuel" }, item.GetComponent<ItemContainer>());
|
||||
containFuelObjective.MinContainedAmount = containedItems.Count(i => i != null && i.Prefab.NameMatches("Fuel Rod") || i.HasTag("reactorfuel")) + 1;
|
||||
containFuelObjective.GetItemPriority = (Item fuelItem) =>
|
||||
{
|
||||
if (fuelItem.ParentInventory?.Owner is Item)
|
||||
{
|
||||
//don't take fuel from other reactors
|
||||
if (((Item)fuelItem.ParentInventory.Owner).GetComponent<Reactor>() != null) return 0.0f;
|
||||
}
|
||||
return 1.0f;
|
||||
};
|
||||
objective.AddSubObjective(containFuelObjective);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (objective.Option.ToLowerInvariant())
|
||||
{
|
||||
case "power up":
|
||||
float tempDiff = load - temperature;
|
||||
{
|
||||
case "power up":
|
||||
float tempDiff = load - temperature;
|
||||
|
||||
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
||||
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
||||
|
||||
//temperature too high/low
|
||||
if (Math.Abs(tempDiff)>500.0f)
|
||||
{
|
||||
AutoTemp = false;
|
||||
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff);
|
||||
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff);
|
||||
}
|
||||
//temperature OK
|
||||
else
|
||||
{
|
||||
AutoTemp = true;
|
||||
}
|
||||
//characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
|
||||
if (Math.Abs(tempDiff) < 500.0f || degreeOfSuccess < 0.5f)
|
||||
{
|
||||
AutoTemp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoTemp = false;
|
||||
//higher skill levels make the character adjust the temperature faster
|
||||
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||
}
|
||||
break;
|
||||
case "shutdown":
|
||||
shutDownTemp = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case "shutdown":
|
||||
|
||||
shutDownTemp = 0.0f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
|
||||
{
|
||||
switch (connection.Name)
|
||||
|
||||
@@ -98,7 +98,6 @@ namespace Barotrauma.Items.Components
|
||||
: base(item, element)
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
@@ -128,8 +127,10 @@ namespace Barotrauma.Items.Components
|
||||
unsentChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (voltage < minVoltage && powerConsumption > 0.0f) return;
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
static float fullPower;
|
||||
static float fullLoad;
|
||||
|
||||
//private bool updated;
|
||||
|
||||
|
||||
private int updateTimer;
|
||||
|
||||
const float FireProbability = 0.15f;
|
||||
@@ -19,35 +17,82 @@ namespace Barotrauma.Items.Components
|
||||
//affects how fast changes in power/load are carried over the grid
|
||||
static float inertia = 5.0f;
|
||||
|
||||
static HashSet<Powered> connectedList = new HashSet<Powered>();
|
||||
|
||||
private HashSet<PowerTransfer> connectedPoweredList = new HashSet<PowerTransfer>();
|
||||
private List<Connection> powerConnections;
|
||||
|
||||
private Dictionary<Connection, bool> connectionDirty = new Dictionary<Connection, bool>();
|
||||
|
||||
//a list of connections a given connection is connected to, either directly or via other power transfer components
|
||||
private Dictionary<Connection, HashSet<Connection>> connectedRecipients = new Dictionary<Connection, HashSet<Connection>>();
|
||||
|
||||
private float powerLoad;
|
||||
|
||||
private bool isBroken;
|
||||
|
||||
public float PowerLoad
|
||||
{
|
||||
get { return powerLoad; }
|
||||
}
|
||||
|
||||
//can the component transfer power
|
||||
public virtual bool CanTransfer
|
||||
private bool canTransfer;
|
||||
public bool CanTransfer
|
||||
{
|
||||
get { return IsActive; }
|
||||
get { return canTransfer; }
|
||||
set
|
||||
{
|
||||
if (canTransfer == value) return;
|
||||
canTransfer = value;
|
||||
SetAllConnectionsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.IsActive;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (base.IsActive != value) SetAllConnectionsDirty();
|
||||
base.IsActive = value;
|
||||
}
|
||||
}
|
||||
|
||||
public PowerTransfer(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
IsActive = true;
|
||||
canTransfer = true;
|
||||
|
||||
powerConnections = new List<Connection>();
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
base.UpdateBroken(deltaTime, cam);
|
||||
|
||||
if (!isBroken)
|
||||
{
|
||||
SetAllConnectionsDirty();
|
||||
isBroken = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (!CanTransfer) return;
|
||||
|
||||
if (isBroken)
|
||||
{
|
||||
SetAllConnectionsDirty();
|
||||
isBroken = false;
|
||||
}
|
||||
|
||||
RefreshConnections();
|
||||
|
||||
if (updateTimer > 0)
|
||||
{
|
||||
//this junction box has already been updated this frame
|
||||
@@ -60,16 +105,13 @@ namespace Barotrauma.Items.Components
|
||||
fullPower = 0.0f;
|
||||
fullLoad = 0.0f;
|
||||
|
||||
connectedList.Clear();
|
||||
connectedPoweredList.Clear();
|
||||
|
||||
CheckJunctions(deltaTime);
|
||||
CheckPower(deltaTime);
|
||||
updateTimer = 0;
|
||||
|
||||
foreach (Powered p in connectedList)
|
||||
{
|
||||
PowerTransfer pt = p as PowerTransfer;
|
||||
if (pt == null) continue;
|
||||
|
||||
foreach (PowerTransfer pt in connectedPoweredList)
|
||||
{
|
||||
pt.powerLoad += (fullLoad - pt.powerLoad) / inertia;
|
||||
pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia;
|
||||
pt.Item.SendSignal(0, "", "power", null, fullPower / Math.Max(fullLoad, 1.0f));
|
||||
@@ -112,39 +154,99 @@ namespace Barotrauma.Items.Components
|
||||
return picker != null;
|
||||
}
|
||||
|
||||
private void RefreshConnections()
|
||||
{
|
||||
var connections = item.Connections;
|
||||
foreach (Connection c in connections)
|
||||
{
|
||||
if (!connectionDirty[c]) continue;
|
||||
|
||||
HashSet<Connection> connected = new HashSet<Connection>();
|
||||
if (!connectedRecipients.ContainsKey(c))
|
||||
{
|
||||
connectedRecipients.Add(c, connected);
|
||||
}
|
||||
else
|
||||
{
|
||||
//mark all previous recipients as dirty
|
||||
foreach (Connection recipient in connectedRecipients[c])
|
||||
{
|
||||
var pt = recipient.Item.GetComponent<PowerTransfer>();
|
||||
if (pt != null) pt.connectionDirty[recipient] = true;
|
||||
}
|
||||
}
|
||||
|
||||
//find all connections that are connected to this one (directly or via another PowerTransfer)
|
||||
connected.Add(c);
|
||||
GetConnected(c, connected);
|
||||
connectedRecipients[c] = connected;
|
||||
|
||||
//go through all the PowerTransfers and we're connected to and set their connections to match the ones we just calculated
|
||||
//(no need to go through the recursive GetConnected method again)
|
||||
foreach (Connection recipient in connected)
|
||||
{
|
||||
var recipientPowerTransfer = recipient.Item.GetComponent<PowerTransfer>();
|
||||
if (recipientPowerTransfer == null) continue;
|
||||
|
||||
if (!connectedRecipients.ContainsKey(recipient))
|
||||
{
|
||||
connectedRecipients.Add(recipient, connected);
|
||||
}
|
||||
|
||||
recipientPowerTransfer.connectedRecipients[recipient] = connected;
|
||||
recipientPowerTransfer.connectionDirty[recipient] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Finds all the connections that can receive a signal sent into the given connection and stores them in the hashset.
|
||||
private void GetConnected(Connection c, HashSet<Connection> connected)
|
||||
{
|
||||
var recipients = c.Recipients;
|
||||
|
||||
foreach (Connection recipient in recipients)
|
||||
{
|
||||
if (recipient == null || connected.Contains(recipient)) continue;
|
||||
|
||||
Item it = recipient.Item;
|
||||
if (it == null || it.Condition <= 0.0f) continue;
|
||||
|
||||
connected.Add(recipient);
|
||||
|
||||
var powerTransfer = it.GetComponent<PowerTransfer>();
|
||||
if (powerTransfer != null && powerTransfer.CanTransfer && powerTransfer.IsActive)
|
||||
{
|
||||
GetConnected(recipient, connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//a recursive function that goes through all the junctions and adds up
|
||||
//all the generated/consumed power of the constructions connected to the grid
|
||||
private void CheckJunctions(float deltaTime)
|
||||
private void CheckPower(float deltaTime)
|
||||
{
|
||||
updateTimer = 1;
|
||||
connectedList.Add(this);
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
connectedPoweredList.Clear();
|
||||
|
||||
foreach (Connection c in powerConnections)
|
||||
{
|
||||
var recipients = c.Recipients;
|
||||
|
||||
HashSet<Connection> recipients = connectedRecipients[c];
|
||||
foreach (Connection recipient in recipients)
|
||||
{
|
||||
if (recipient == null) continue;
|
||||
|
||||
Item it = recipient.Item;
|
||||
if (it == null) continue;
|
||||
|
||||
if (it.Condition <= 0.0f) continue;
|
||||
if (it == null || it.Condition <= 0.0f) continue;
|
||||
|
||||
foreach (Powered powered in it.GetComponents<Powered>())
|
||||
{
|
||||
if (powered == null || !powered.IsActive) continue;
|
||||
|
||||
if (connectedList.Contains(powered)) continue;
|
||||
|
||||
PowerTransfer powerTransfer = powered as PowerTransfer;
|
||||
if (powerTransfer != null)
|
||||
{
|
||||
if (!powerTransfer.CanTransfer) continue;
|
||||
powerTransfer.CheckJunctions(deltaTime);
|
||||
connectedPoweredList.Add(powerTransfer);
|
||||
powerTransfer.updateTimer = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -162,25 +264,38 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
connectedList.Add(powered);
|
||||
//positive power consumption = the construction requires power -> increase load
|
||||
if (powered.CurrPowerConsumption > 0.0f)
|
||||
{
|
||||
fullLoad += powered.CurrPowerConsumption;
|
||||
}
|
||||
else if (powered.CurrPowerConsumption < 0.0f)
|
||||
//negative power consumption = the construction is a
|
||||
//generator/battery or another junction box
|
||||
//negative power consumption = the construction is a /generator/battery
|
||||
{
|
||||
fullPower -= powered.CurrPowerConsumption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAllConnectionsDirty()
|
||||
{
|
||||
if (item.Connections == null) return;
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
connectionDirty[c] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetConnectionDirty(Connection connection)
|
||||
{
|
||||
var connections = item.Connections;
|
||||
if (connections == null || !connections.Contains(connection)) return;
|
||||
connectionDirty[connection] = true;
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
var connections = item.Connections;
|
||||
@@ -189,18 +304,38 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
powerConnections = connections.FindAll(c => c.IsPower);
|
||||
if (powerConnections.Count == 0) IsActive = false;
|
||||
|
||||
SetAllConnectionsDirty();
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power);
|
||||
|
||||
if (!connectedRecipients.ContainsKey(connection)) return;
|
||||
|
||||
if (connection.Name.Length > 5 && connection.Name.Substring(0, 6).ToLowerInvariant() == "signal")
|
||||
{
|
||||
connection.SendSignal(stepsTaken, signal, source, sender, 0.0f);
|
||||
foreach (Connection recipient in connectedRecipients[connection])
|
||||
{
|
||||
if (recipient.Item == item || recipient.Item == source) continue;
|
||||
|
||||
foreach (ItemComponent ic in recipient.Item.components)
|
||||
{
|
||||
//powertransfer components don't need to receive the signal because we relay it straight
|
||||
//to the connected items without going through the whole chain of junction boxes
|
||||
if (ic is PowerTransfer) continue;
|
||||
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, 0.0f);
|
||||
}
|
||||
|
||||
foreach (StatusEffect effect in recipient.effects)
|
||||
{
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private static Wire draggingConnected;
|
||||
|
||||
private List<StatusEffect> effects;
|
||||
public readonly List<StatusEffect> effects;
|
||||
|
||||
public readonly ushort[] wireId;
|
||||
|
||||
@@ -167,8 +167,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (StatusEffect effect in recipient.effects)
|
||||
{
|
||||
|
||||
//effect.Apply(ActionType.OnUse, 1.0f, recipient.item, recipient.item);
|
||||
recipient.item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,21 +31,14 @@ namespace Barotrauma.Items.Components
|
||||
set
|
||||
{
|
||||
isOn = value;
|
||||
CanTransfer = value;
|
||||
if (!isOn)
|
||||
{
|
||||
currPowerConsumption = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanTransfer
|
||||
{
|
||||
get
|
||||
{
|
||||
return isOn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public RelayComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
|
||||
@@ -30,21 +30,13 @@ namespace Barotrauma.Items.Components
|
||||
const float nodeDistance = 32.0f;
|
||||
const float heightFromFloor = 128.0f;
|
||||
|
||||
static Sprite wireSprite;
|
||||
|
||||
private List<Vector2> nodes;
|
||||
private List<WireSection> sections;
|
||||
|
||||
Connection[] connections;
|
||||
private Connection[] connections;
|
||||
|
||||
private Vector2 newNodePos;
|
||||
|
||||
|
||||
|
||||
private static Wire draggingWire;
|
||||
private static int? selectedNodeIndex;
|
||||
private static int? highlightedNodeIndex;
|
||||
|
||||
public bool Hidden, Locked;
|
||||
|
||||
public Connection[] Connections
|
||||
@@ -55,12 +47,14 @@ namespace Barotrauma.Items.Components
|
||||
public Wire(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
#if CLIENT
|
||||
if (wireSprite == null)
|
||||
{
|
||||
wireSprite = new Sprite("Content/Items/wireHorizontal.png", new Vector2(0.5f, 0.5f));
|
||||
wireSprite.Depth = 0.85f;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
nodes = new List<Vector2>();
|
||||
sections = new List<WireSection>();
|
||||
|
||||
@@ -86,14 +80,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void RemoveConnection(Item item)
|
||||
{
|
||||
for (int i = 0; i<2; i++)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (connections[i]==null || connections[i].Item!=item) continue;
|
||||
|
||||
for (int n = 0; n< connections[i].Wires.Length; n++)
|
||||
if (connections[i] == null || connections[i].Item != item) continue;
|
||||
|
||||
for (int n = 0; n < connections[i].Wires.Length; n++)
|
||||
{
|
||||
if (connections[i].Wires[n] != this) continue;
|
||||
|
||||
SetConnectedDirty();
|
||||
connections[i].Wires[n] = null;
|
||||
}
|
||||
connections[i] = null;
|
||||
@@ -104,6 +99,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (connection == connections[0]) connections[0] = null;
|
||||
if (connection == connections[1]) connections[1] = null;
|
||||
|
||||
SetConnectedDirty();
|
||||
}
|
||||
|
||||
public bool Connect(Connection newConnection, bool addNode = true, bool sendNetworkEvent = false)
|
||||
@@ -137,8 +134,7 @@ namespace Barotrauma.Items.Components
|
||||
if (newConnection.Item.Submarine == null) continue;
|
||||
|
||||
if (nodes.Count > 0 && nodes[0] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break;
|
||||
if (nodes.Count > 1 && nodes[nodes.Count-1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break;
|
||||
|
||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
@@ -148,11 +144,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
nodes.Add(newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SetConnectedDirty();
|
||||
|
||||
if (connections[0] != null && connections[1] != null)
|
||||
{
|
||||
foreach (ItemComponent ic in item.components)
|
||||
@@ -323,6 +320,8 @@ namespace Barotrauma.Items.Components
|
||||
connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
}
|
||||
|
||||
SetConnectedDirty();
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -363,6 +362,18 @@ namespace Barotrauma.Items.Components
|
||||
return position;
|
||||
}
|
||||
|
||||
public void SetConnectedDirty()
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (connections[i]?.Item != null)
|
||||
{
|
||||
var pt = connections[i].Item.GetComponent<PowerTransfer>();
|
||||
if (pt != null) pt.SetConnectionDirty(connections[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanNodes()
|
||||
{
|
||||
for (int i = nodes.Count - 2; i > 0; i--)
|
||||
|
||||
@@ -143,10 +143,21 @@ namespace Barotrauma
|
||||
public Item FindItem(string itemName)
|
||||
{
|
||||
if (itemName == null) return null;
|
||||
|
||||
return Items.FirstOrDefault(i => i != null && (i.Prefab.NameMatches(itemName) || i.HasTag(itemName)));
|
||||
}
|
||||
|
||||
public Item FindItem(string[] itemNames)
|
||||
{
|
||||
if (itemNames == null) return null;
|
||||
|
||||
foreach (string itemName in itemNames)
|
||||
{
|
||||
var item = FindItem(itemName);
|
||||
if (item != null) return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void RemoveItem(Item item)
|
||||
{
|
||||
if (item == null) return;
|
||||
|
||||
@@ -1207,7 +1207,7 @@ namespace Barotrauma
|
||||
Color color = Color.Red;
|
||||
if (ic.HasRequiredSkills(character) && ic.HasRequiredItems(character, false)) color = Color.Orange;
|
||||
|
||||
texts.Add(new ColoredText(ic.Msg, color));
|
||||
texts.Add(new ColoredText(ic.Msg, color, false));
|
||||
}
|
||||
|
||||
return texts;
|
||||
@@ -1608,7 +1608,7 @@ namespace Barotrauma
|
||||
msg.Write(body.FarseerBody.Awake);
|
||||
if (body.FarseerBody.Awake)
|
||||
{
|
||||
body.FarseerBody.Enabled = true;
|
||||
body.Enabled = true;
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), -MaxVel, MaxVel, 12);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel), -MaxVel, MaxVel, 12);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Barotrauma
|
||||
public Explosion(float range, float force, float damage, float structureDamage)
|
||||
{
|
||||
attack = new Attack(damage, structureDamage, 0.0f, range);
|
||||
attack.SeverLimbsProbability = 1.0f;
|
||||
this.force = force;
|
||||
sparks = true;
|
||||
shockwave = true;
|
||||
@@ -118,7 +119,7 @@ namespace Barotrauma
|
||||
|
||||
explosionPos = ConvertUnits.ToSimUnits(explosionPos);
|
||||
|
||||
bool wasDead = c.IsDead;
|
||||
Dictionary<Limb, float> distFactors = new Dictionary<Limb, float>();
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
float dist = Vector2.Distance(limb.WorldPosition, worldPosition);
|
||||
@@ -134,6 +135,8 @@ namespace Barotrauma
|
||||
|
||||
//solid obstacles between the explosion and the limb reduce the effect of the explosion by 90%
|
||||
if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null) distFactor *= 0.1f;
|
||||
|
||||
distFactors.Add(limb, distFactor);
|
||||
|
||||
c.AddDamage(limb.WorldPosition, DamageType.None,
|
||||
attack.GetDamage(1.0f) / c.AnimController.Limbs.Length * distFactor,
|
||||
@@ -143,17 +146,27 @@ namespace Barotrauma
|
||||
|
||||
if (limb.WorldPosition != worldPosition && force > 0.0f)
|
||||
{
|
||||
limb.body.ApplyLinearImpulse(Vector2.Normalize(limb.WorldPosition - worldPosition) * distFactor * force);
|
||||
Vector2 limbDiff = Vector2.Normalize(limb.WorldPosition - worldPosition);
|
||||
Vector2 impulsePoint = limb.SimPosition - limbDiff * limbRadius;
|
||||
limb.body.ApplyLinearImpulse(limbDiff * distFactor * force, impulsePoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasDead && c.IsDead)
|
||||
//sever joints
|
||||
if (c.IsDead && attack.SeverLimbsProbability > 0.0f)
|
||||
{
|
||||
foreach (LimbJoint joint in c.AnimController.LimbJoints)
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability)
|
||||
if (!distFactors.ContainsKey(limb)) continue;
|
||||
|
||||
foreach (LimbJoint joint in c.AnimController.LimbJoints)
|
||||
{
|
||||
c.AnimController.SeverLimbJoint(joint);
|
||||
if (joint.IsSevered || (joint.LimbA != limb && joint.LimbB != limb)) continue;
|
||||
|
||||
if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability * distFactors[limb])
|
||||
{
|
||||
c.AnimController.SeverLimbJoint(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,8 +264,8 @@ namespace Barotrauma
|
||||
|
||||
Vector2 nodeInterval = generationParams.MainPathNodeIntervalRange;
|
||||
|
||||
for (float x = startPosition.X + Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
|
||||
x < endPosition.X - Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
|
||||
for (float x = startPosition.X + nodeInterval.X;
|
||||
x < endPosition.X - nodeInterval.X;
|
||||
x += Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server))
|
||||
{
|
||||
pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, Rand.RandSync.Server)));
|
||||
@@ -275,7 +275,7 @@ namespace Barotrauma
|
||||
|
||||
if (pathNodes.Count <= 2)
|
||||
{
|
||||
pathNodes.Add((startPosition + endPosition) / 2);
|
||||
pathNodes.Insert(1, borders.Center.ToVector2());
|
||||
}
|
||||
|
||||
GenerateTunnels(pathNodes, minWidth);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Created by SharpDevelop.
|
||||
* User: Burhan
|
||||
* Date: 17/06/2014
|
||||
@@ -8,31 +8,31 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 James Humphreys. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY James Humphreys ``AS IS\" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of James Humphreys.
|
||||
Copyright 2011 James Humphreys. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY James Humphreys ``AS IS\" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of James Humphreys.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -58,63 +58,63 @@ using System.Collections.Generic;
|
||||
namespace Voronoi2
|
||||
{
|
||||
public class Point
|
||||
{
|
||||
public double x, y;
|
||||
|
||||
public void setPoint ( double x, double y )
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// use for sites and vertecies
|
||||
public class Site
|
||||
{
|
||||
public Point coord;
|
||||
public int sitenbr;
|
||||
{
|
||||
public double x, y;
|
||||
|
||||
public void setPoint ( double x, double y )
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// use for sites and vertecies
|
||||
public class Site
|
||||
{
|
||||
public Point coord;
|
||||
public int sitenbr;
|
||||
|
||||
public void SetPoint(Vector2 point)
|
||||
{
|
||||
coord.setPoint(point.X, point.Y);
|
||||
}
|
||||
|
||||
public Site ()
|
||||
{
|
||||
coord = new Point();
|
||||
}
|
||||
}
|
||||
|
||||
public class Edge
|
||||
{
|
||||
public double a = 0, b = 0, c = 0;
|
||||
public Site[] ep;
|
||||
public Site[] reg;
|
||||
public int edgenbr;
|
||||
|
||||
public Edge ()
|
||||
{
|
||||
ep = new Site[2];
|
||||
reg = new Site[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Halfedge
|
||||
{
|
||||
public Halfedge ELleft, ELright;
|
||||
public Edge ELedge;
|
||||
public bool deleted;
|
||||
public int ELpm;
|
||||
public Site vertex;
|
||||
public double ystar;
|
||||
public Halfedge PQnext;
|
||||
|
||||
public Halfedge ()
|
||||
{
|
||||
PQnext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Site ()
|
||||
{
|
||||
coord = new Point();
|
||||
}
|
||||
}
|
||||
|
||||
public class Edge
|
||||
{
|
||||
public double a = 0, b = 0, c = 0;
|
||||
public Site[] ep;
|
||||
public Site[] reg;
|
||||
public int edgenbr;
|
||||
|
||||
public Edge ()
|
||||
{
|
||||
ep = new Site[2];
|
||||
reg = new Site[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Halfedge
|
||||
{
|
||||
public Halfedge ELleft, ELright;
|
||||
public Edge ELedge;
|
||||
public bool deleted;
|
||||
public int ELpm;
|
||||
public Site vertex;
|
||||
public double ystar;
|
||||
public Halfedge PQnext;
|
||||
|
||||
public Halfedge ()
|
||||
{
|
||||
PQnext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CellType
|
||||
{
|
||||
@@ -187,11 +187,11 @@ namespace Voronoi2
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class GraphEdge
|
||||
{
|
||||
|
||||
public class GraphEdge
|
||||
{
|
||||
public Vector2 point1, point2;
|
||||
public Site site1, site2;
|
||||
public Site site1, site2;
|
||||
public VoronoiCell cell1, cell2;
|
||||
|
||||
public bool isSolid;
|
||||
@@ -239,20 +239,20 @@ namespace Voronoi2
|
||||
|
||||
return normal;
|
||||
}
|
||||
}
|
||||
|
||||
// للترتيب
|
||||
public class SiteSorterYX : IComparer<Site>
|
||||
{
|
||||
public int Compare ( Site p1, Site p2 )
|
||||
{
|
||||
Point s1 = p1.coord;
|
||||
Point s2 = p2.coord;
|
||||
if ( s1.y < s2.y ) return -1;
|
||||
if ( s1.y > s2.y ) return 1;
|
||||
if ( s1.x < s2.x ) return -1;
|
||||
if ( s1.x > s2.x ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// للترتيب
|
||||
public class SiteSorterYX : IComparer<Site>
|
||||
{
|
||||
public int Compare ( Site p1, Site p2 )
|
||||
{
|
||||
Point s1 = p1.coord;
|
||||
Point s2 = p2.coord;
|
||||
if ( s1.y < s2.y ) return -1;
|
||||
if ( s1.y > s2.y ) return 1;
|
||||
if ( s1.x < s2.x ) return -1;
|
||||
if ( s1.x > s2.x ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +89,11 @@ namespace Barotrauma
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected bool ResizeHorizontal
|
||||
public bool ResizeHorizontal
|
||||
{
|
||||
get { return prefab != null && prefab.ResizeHorizontal; }
|
||||
}
|
||||
protected bool ResizeVertical
|
||||
public bool ResizeVertical
|
||||
{
|
||||
get { return prefab != null && prefab.ResizeVertical; }
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ namespace Barotrauma
|
||||
get { return prefab.Body; }
|
||||
}
|
||||
|
||||
public List<Body> Bodies
|
||||
{
|
||||
get { return bodies; }
|
||||
}
|
||||
|
||||
public bool CastShadow
|
||||
{
|
||||
get { return prefab.CastShadow; }
|
||||
@@ -272,7 +277,13 @@ namespace Barotrauma
|
||||
|
||||
public override MapEntity Clone()
|
||||
{
|
||||
return new Structure(rect, prefab, Submarine);
|
||||
var clone = new Structure(rect, prefab, Submarine);
|
||||
foreach (KeyValuePair<string, SerializableProperty> property in SerializableProperties)
|
||||
{
|
||||
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
|
||||
clone.SerializableProperties[property.Key].TrySetValue(property.Value.GetValue());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
private void CreateStairBodies()
|
||||
@@ -651,23 +662,28 @@ namespace Barotrauma
|
||||
Vector2 transformedPos = worldPosition;
|
||||
if (Submarine != null) transformedPos -= Submarine.Position;
|
||||
|
||||
int i = FindSectionIndex(transformedPos);
|
||||
if (i == -1) return new AttackResult(0.0f, 0.0f);
|
||||
|
||||
float damageAmount = attack.GetStructureDamage(deltaTime);
|
||||
|
||||
AddDamage(i, damageAmount, attacker);
|
||||
float damageAmount = 0.0f;
|
||||
for (int i = 0; i < SectionCount; i++)
|
||||
{
|
||||
if (Vector2.DistanceSquared(SectionPosition(i, true), worldPosition) <= attack.DamageRange * attack.DamageRange)
|
||||
{
|
||||
damageAmount = attack.GetStructureDamage(deltaTime);
|
||||
AddDamage(i, damageAmount, attacker);
|
||||
|
||||
#if CLIENT
|
||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (playSound)// && !SectionBodyDisabled(i))
|
||||
{
|
||||
string damageSoundType = (attack.DamageType == DamageType.Blunt) ? "StructureBlunt" : "StructureSlash";
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return new AttackResult(damageAmount, 0.0f);
|
||||
}
|
||||
|
||||
@@ -838,6 +854,7 @@ namespace Barotrauma
|
||||
{
|
||||
StairDirection = StairDirection == Direction.Left ? Direction.Right : Direction.Left;
|
||||
bodies.ForEach(b => GameMain.World.RemoveBody(b));
|
||||
bodies.Clear();
|
||||
|
||||
CreateStairBodies();
|
||||
}
|
||||
|
||||
@@ -1208,9 +1208,9 @@ namespace Barotrauma
|
||||
Item.ItemList.Clear();
|
||||
}
|
||||
|
||||
PhysicsBody.RemoveAll();
|
||||
Ragdoll.RemoveAll();
|
||||
|
||||
Ragdoll.list.Clear();
|
||||
PhysicsBody.RemoveAll();
|
||||
|
||||
GameMain.World.Clear();
|
||||
|
||||
|
||||
@@ -491,6 +491,22 @@ namespace Barotrauma
|
||||
if (contactDot > 0.0f)
|
||||
{
|
||||
Body.LinearVelocity -= Vector2.Normalize(Body.LinearVelocity) * contactDot;
|
||||
|
||||
float damageAmount = contactDot * Body.Mass / limb.character.Mass;
|
||||
|
||||
Vector2 n;
|
||||
FixedArray2<Vector2> contactPos;
|
||||
contact.GetWorldManifold(out n, out contactPos);
|
||||
limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(contactPos[0]), limb, DamageType.Blunt, damageAmount, 0.0f, 0.0f, true, 0.0f);
|
||||
|
||||
if (limb.character.IsDead)
|
||||
{
|
||||
foreach (LimbJoint limbJoint in limb.character.AnimController.LimbJoints)
|
||||
{
|
||||
if (limbJoint.IsSevered || (limbJoint.LimbA != limb && limbJoint.LimbB != limb)) continue;
|
||||
limb.character.AnimController.SeverLimbJoint(limbJoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,6 +150,20 @@ namespace Barotrauma
|
||||
wayPoint.Remove();
|
||||
}
|
||||
|
||||
//find all open doors and temporarily activate their bodies to prevent visibility checks
|
||||
//from ignoring the doors and generating waypoint connections that go straight through the door
|
||||
List<Door> openDoors = new List<Door>();
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
var door = item.GetComponent<Door>();
|
||||
if (door != null && !door.Body.Enabled)
|
||||
{
|
||||
openDoors.Add(door);
|
||||
door.Body.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float minDist = 150.0f;
|
||||
float heightFromFloor = 110.0f;
|
||||
|
||||
@@ -201,15 +215,15 @@ namespace Barotrauma
|
||||
|
||||
borders.Height += inflateAmount;
|
||||
}
|
||||
|
||||
WayPoint[,] cornerWaypoint = new WayPoint[2,2];
|
||||
|
||||
for (int i = 0; i<2; i++)
|
||||
WayPoint[,] cornerWaypoint = new WayPoint[2, 2];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
for (float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
|
||||
{
|
||||
var wayPoint = new WayPoint(
|
||||
new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
|
||||
new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
|
||||
SpawnType.Path, submarine);
|
||||
|
||||
if (x == borders.X + outSideWaypointInterval)
|
||||
@@ -218,13 +232,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
wayPoint.ConnectTo(WayPoint.WayPointList[WayPointList.Count-2]);
|
||||
wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
|
||||
}
|
||||
}
|
||||
|
||||
cornerWaypoint[i, 1] = WayPoint.WayPointList[WayPointList.Count - 1];
|
||||
cornerWaypoint[i, 1] = WayPointList[WayPointList.Count - 1];
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
WayPoint wayPoint = null;
|
||||
@@ -300,7 +314,7 @@ namespace Barotrauma
|
||||
|
||||
while (prevPoint != ladderPoints[1])
|
||||
{
|
||||
var pickedBody = Submarine.PickBody(prevPos, ladderPoints[1].SimPosition, ignoredBodies);
|
||||
var pickedBody = Submarine.PickBody(prevPos, ladderPoints[1].SimPosition, ignoredBodies, null, false);
|
||||
|
||||
if (pickedBody == null) break;
|
||||
|
||||
@@ -333,19 +347,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
prevPoint.ConnectTo(ladderPoints[1]);
|
||||
|
||||
|
||||
|
||||
//for (float y = ladderPoints[0].Position.Y+100.0f; y < ladderPoints[1].Position.Y; y+=100.0f )
|
||||
//{
|
||||
// var midPoint = new WayPoint(new Vector2(item.Rect.Center.X, y), SpawnType.Path, Submarine.Loaded);
|
||||
// midPoint.Ladders = ladders;
|
||||
|
||||
// midPoint.ConnectTo(prevPoint);
|
||||
// prevPoint = midPoint;
|
||||
//}
|
||||
//ladderPoints[1].ConnectTo(prevPoint);
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ladderPoints[i].Ladders = ladders;
|
||||
@@ -357,8 +359,6 @@ namespace Barotrauma
|
||||
ladderPoints[i].ConnectTo(closest);
|
||||
}
|
||||
}
|
||||
|
||||
//ladderPoints[0].ConnectTo(ladderPoints[1]);
|
||||
}
|
||||
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
@@ -394,7 +394,7 @@ namespace Barotrauma
|
||||
if (gap.Rect.Width < 100.0f) continue;
|
||||
|
||||
var wayPoint = new WayPoint(
|
||||
new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height/2), SpawnType.Path, submarine, gap);
|
||||
new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height / 2), SpawnType.Path, submarine, gap);
|
||||
|
||||
for (int dir = -1; dir <= 1; dir += 2)
|
||||
{
|
||||
@@ -410,6 +410,12 @@ namespace Barotrauma
|
||||
{
|
||||
wp.Remove();
|
||||
}
|
||||
|
||||
//re-disable the bodies of the doors that are supposed to be open
|
||||
foreach (Door door in openDoors)
|
||||
{
|
||||
door.Body.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private WayPoint FindClosest(int dir, bool horizontalSearch, Vector2 tolerance, Body ignoredBody = null)
|
||||
@@ -443,7 +449,7 @@ namespace Barotrauma
|
||||
float dist = Vector2.Distance(wp.Position, Position);
|
||||
if (closest == null || dist < closestDist)
|
||||
{
|
||||
var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, true, true);
|
||||
var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, true, true, false);
|
||||
if (body != null && body != ignoredBody && !(body.UserData is Submarine))
|
||||
{
|
||||
if (body.UserData is Structure || body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) continue;
|
||||
|
||||
@@ -166,11 +166,11 @@ namespace Barotrauma.Networking
|
||||
if (c.ChatSpamCount > 3)
|
||||
{
|
||||
//kick for spamming too much
|
||||
GameMain.Server.KickClient(c, "You have been kicked by the spam filter.");
|
||||
GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatMessage denyMsg = ChatMessage.Create("", "You have been blocked by the spam filter. Try again after 10 seconds.", ChatMessageType.Server, null);
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendChatMessage(denyMsg, c);
|
||||
}
|
||||
@@ -181,7 +181,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (c.ChatSpamTimer > 0.0f)
|
||||
{
|
||||
ChatMessage denyMsg = ChatMessage.Create("", "You have been blocked by the spam filter. Try again after 10 seconds.", ChatMessageType.Server, null);
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendChatMessage(denyMsg, c);
|
||||
return;
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public static bool IsValidName(string name)
|
||||
{
|
||||
if (name.Contains("\n") || name.Contains("\r\n")) return false;
|
||||
if (name.Contains("\n") || name.Contains("\r")) return false;
|
||||
|
||||
return (name.All(c =>
|
||||
c != ';' &&
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (clName.ToLower() == Name.ToLower())
|
||||
if (Homoglyphs.Compare(clName.ToLower(),Name.ToLower()))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
No = 0, Maybe = 1, Yes = 2
|
||||
}
|
||||
|
||||
|
||||
partial class GameServer : NetworkMember, ISerializableEntity
|
||||
{
|
||||
private class SavedClientPermission
|
||||
@@ -48,7 +48,7 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
public Dictionary<string, int> extraCargo;
|
||||
|
||||
public bool ShowNetStats;
|
||||
@@ -57,24 +57,24 @@ namespace Barotrauma.Networking
|
||||
private TimeSpan sparseUpdateInterval = new TimeSpan(0, 0, 0, 3);
|
||||
|
||||
private SelectionMode subSelectionMode, modeSelectionMode;
|
||||
|
||||
|
||||
private bool registeredToMaster;
|
||||
|
||||
private WhiteList whitelist;
|
||||
private BanList banList;
|
||||
|
||||
private string password;
|
||||
|
||||
|
||||
public float AutoRestartTimer;
|
||||
|
||||
|
||||
private bool autoRestart;
|
||||
|
||||
private bool isPublic;
|
||||
|
||||
private int maxPlayers;
|
||||
|
||||
|
||||
private List<SavedClientPermission> clientPermissions = new List<SavedClientPermission>();
|
||||
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool RandomizeSeed
|
||||
{
|
||||
@@ -170,7 +170,7 @@ namespace Barotrauma.Networking
|
||||
AutoRestartTimer = autoRestart ? AutoRestartInterval : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowRespawn
|
||||
{
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
get { return modeSelectionMode; }
|
||||
}
|
||||
|
||||
|
||||
public BanList BanList
|
||||
{
|
||||
get { return banList; }
|
||||
@@ -234,7 +234,7 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(false,true)]
|
||||
[Serialize(false, true)]
|
||||
public bool KarmaEnabled
|
||||
{
|
||||
get;
|
||||
@@ -246,7 +246,7 @@ namespace Barotrauma.Networking
|
||||
XDocument doc = new XDocument(new XElement("serversettings"));
|
||||
|
||||
SerializableProperty.SerializeProperties(this, doc.Root, true);
|
||||
|
||||
|
||||
doc.Root.SetAttributeValue("name", name);
|
||||
doc.Root.SetAttributeValue("public", isPublic);
|
||||
doc.Root.SetAttributeValue("port", config.Port);
|
||||
@@ -257,7 +257,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
doc.Root.SetAttributeValue("SubSelection", subSelectionMode.ToString());
|
||||
doc.Root.SetAttributeValue("ModeSelection", modeSelectionMode.ToString());
|
||||
|
||||
|
||||
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||
|
||||
#if SERVER
|
||||
@@ -272,7 +272,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
doc.Root.SetAttributeValue("ServerMessage", GameMain.NetLobbyScreen.ServerMessageText);
|
||||
}
|
||||
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
settings.NewLineOnAttributes = true;
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma.Networking
|
||||
if (File.Exists(SettingsFile))
|
||||
{
|
||||
doc = XMLExtensions.TryLoadXml(SettingsFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (doc == null || doc.Root == null)
|
||||
{
|
||||
@@ -318,13 +318,16 @@ namespace Barotrauma.Networking
|
||||
Enum.TryParse<YesNoMaybe>(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
TraitorsEnabled = traitorsEnabled;
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
|
||||
if (GameMain.NetLobbyScreen != null
|
||||
#if CLIENT
|
||||
&& GameMain.NetLobbyScreen.ServerMessage != null
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if SERVER
|
||||
GameMain.NetLobbyScreen.ServerName = doc.Root.GetAttributeString("name", "");
|
||||
#endif
|
||||
GameMain.NetLobbyScreen.ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
|
||||
}
|
||||
|
||||
@@ -349,9 +352,12 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
clientPermissions.Clear();
|
||||
|
||||
if (File.Exists("Data/clientpermissions.txt") && !File.Exists(ClientPermissionsFile))
|
||||
if (!File.Exists(ClientPermissionsFile))
|
||||
{
|
||||
LoadClientPermissionsOld("Data/clientpermissions.txt");
|
||||
if (File.Exists("Data/clientpermissions.txt"))
|
||||
{
|
||||
LoadClientPermissionsOld("Data/clientpermissions.txt");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -94,9 +94,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
class Key
|
||||
{
|
||||
private bool hit, hitQueue;
|
||||
class Key
|
||||
{
|
||||
private bool hit, hitQueue;
|
||||
private bool held, heldQueue;
|
||||
|
||||
|
||||
@@ -106,23 +106,23 @@ namespace Barotrauma
|
||||
//{
|
||||
// get { return canBeHeld; }
|
||||
//}
|
||||
|
||||
public Key(KeyOrMouse binding)
|
||||
{
|
||||
|
||||
public Key(KeyOrMouse binding)
|
||||
{
|
||||
this.binding = binding;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Hit
|
||||
{
|
||||
get
|
||||
{
|
||||
return hit;
|
||||
}
|
||||
set
|
||||
{
|
||||
hit = value;
|
||||
}
|
||||
}
|
||||
public bool Hit
|
||||
{
|
||||
get
|
||||
{
|
||||
return hit;
|
||||
}
|
||||
set
|
||||
{
|
||||
hit = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Held
|
||||
{
|
||||
@@ -141,14 +141,14 @@ namespace Barotrauma
|
||||
get { return binding; }
|
||||
}
|
||||
|
||||
public void SetState()
|
||||
{
|
||||
hit = binding.IsHit();
|
||||
if (hit) hitQueue = true;
|
||||
public void SetState()
|
||||
{
|
||||
hit = binding.IsHit();
|
||||
if (hit) hitQueue = true;
|
||||
|
||||
held = binding.IsDown();
|
||||
if (held) heldQueue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetState(bool hit, bool held)
|
||||
{
|
||||
@@ -156,12 +156,12 @@ namespace Barotrauma
|
||||
if (held) heldQueue = true;
|
||||
}
|
||||
|
||||
public bool DequeueHit()
|
||||
{
|
||||
bool value = hitQueue;
|
||||
hitQueue = false;
|
||||
return value;
|
||||
}
|
||||
public bool DequeueHit()
|
||||
{
|
||||
bool value = hitQueue;
|
||||
hitQueue = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool DequeueHeld()
|
||||
{
|
||||
@@ -187,11 +187,11 @@ namespace Barotrauma
|
||||
held = false;
|
||||
}
|
||||
|
||||
public void ResetHit()
|
||||
{
|
||||
hit = false;
|
||||
//stateQueue = false;
|
||||
}
|
||||
public void ResetHit()
|
||||
{
|
||||
hit = false;
|
||||
//stateQueue = false;
|
||||
}
|
||||
|
||||
|
||||
public void ResetHeld()
|
||||
@@ -199,5 +199,5 @@ namespace Barotrauma
|
||||
held = false;
|
||||
//stateQueue = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
static class TextManager
|
||||
{
|
||||
private static Dictionary<string, List<string>> texts;
|
||||
|
||||
static TextManager()
|
||||
{
|
||||
Load(Path.Combine("Content", "Texts.xml"));
|
||||
}
|
||||
|
||||
private static void Load(string file)
|
||||
{
|
||||
texts = new Dictionary<string, List<string>>();
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
foreach (XElement subElement in doc.Root.Elements())
|
||||
{
|
||||
string infoName = subElement.Name.ToString().ToLowerInvariant();
|
||||
List<string> infoList = null;
|
||||
if (!texts.TryGetValue(infoName, out infoList))
|
||||
{
|
||||
infoList = new List<string>();
|
||||
texts.Add(infoName, infoList);
|
||||
}
|
||||
|
||||
infoList.Add(subElement.ElementInnerText());
|
||||
}
|
||||
}
|
||||
|
||||
public static string Get(string textTag)
|
||||
{
|
||||
List<string> textList = null;
|
||||
if (!texts.TryGetValue(textTag.ToLowerInvariant(), out textList) || !textList.Any())
|
||||
{
|
||||
DebugConsole.ThrowError("Text \"" + textTag + "\" not found");
|
||||
return textTag;
|
||||
}
|
||||
|
||||
string text = textList[Rand.Int(textList.Count)].Replace(@"\n", "\n");
|
||||
|
||||
//todo: get rid of these and only do where needed?
|
||||
#if CLIENT
|
||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
||||
{
|
||||
text = text.Replace("[" + inputType.ToString() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
||||
}
|
||||
#endif
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string ReplaceGenderPronouns(string text, Gender gender)
|
||||
{
|
||||
if (gender == Gender.Male)
|
||||
{
|
||||
return text.Replace("[genderpronoun]", Get("PronounMale").ToLower())
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveMale").ToLower())
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveMale").ToLower())
|
||||
.Replace("[Genderpronoun]", Capitalize(Get("PronounMale")))
|
||||
.Replace("[Genderpronounpossessive]", Capitalize(Get("PronounPossessiveMale")))
|
||||
.Replace("[Genderpronounreflexive]", Capitalize(Get("PronounReflexiveMale")));
|
||||
}
|
||||
else
|
||||
{
|
||||
return text.Replace("[genderpronoun]", Get("PronounFemale").ToLower())
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveFemale").ToLower())
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveFemale").ToLower())
|
||||
.Replace("[Genderpronoun]", Capitalize(Get("PronounFemale")))
|
||||
.Replace("[Genderpronounpossessive]", Capitalize(Get("PronounPossessiveFemale")))
|
||||
.Replace("[Genderpronounreflexive]", Capitalize(Get("PronounReflexiveFemale")));
|
||||
}
|
||||
}
|
||||
|
||||
private static string Capitalize(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
return char.ToUpper(str[0]) + str.Substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,6 +336,11 @@ namespace Barotrauma
|
||||
float xDiff = lineB.X - lineA.X;
|
||||
float yDiff = lineB.Y - lineA.Y;
|
||||
|
||||
if (xDiff == 0 && yDiff == 0)
|
||||
{
|
||||
return Vector2.Distance(lineA, point);
|
||||
}
|
||||
|
||||
return (float)(Math.Abs(xDiff * (lineA.Y - point.Y) - yDiff * (lineA.X - point.X)) /
|
||||
Math.Sqrt(xDiff * xDiff + yDiff * yDiff));
|
||||
}
|
||||
@@ -508,6 +513,52 @@ namespace Barotrauma
|
||||
// Return formatted number with suffix
|
||||
return readable.ToString("0.# ") + suffix;
|
||||
}
|
||||
|
||||
public static void SplitRectanglesHorizontal(List<Rectangle> rects, Vector2 point)
|
||||
{
|
||||
for (int i = 0; i < rects.Count; i++)
|
||||
{
|
||||
if (point.Y > rects[i].Y && point.Y < rects[i].Y + rects[i].Height)
|
||||
{
|
||||
Rectangle rect1 = rects[i];
|
||||
Rectangle rect2 = rects[i];
|
||||
|
||||
rect1.Height = (int)(point.Y - rects[i].Y);
|
||||
|
||||
rect2.Height = rects[i].Height - rect1.Height;
|
||||
rect2.Y = rect1.Y + rect1.Height;
|
||||
rects[i] = rect1;
|
||||
rects.Insert(i + 1, rect2); i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SplitRectanglesVertical(List<Rectangle> rects, Vector2 point)
|
||||
{
|
||||
for (int i = 0; i < rects.Count; i++)
|
||||
{
|
||||
if (point.X>rects[i].X && point.X<rects[i].X+rects[i].Width)
|
||||
{
|
||||
Rectangle rect1 = rects[i];
|
||||
Rectangle rect2 = rects[i];
|
||||
|
||||
rect1.Width = (int)(point.X-rects[i].X);
|
||||
|
||||
rect2.Width = rects[i].Width - rect1.Width;
|
||||
rect2.X = rect1.X + rect1.Width;
|
||||
rects[i] = rect1;
|
||||
rects.Insert(i + 1, rect2); i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*for (int i = 0; i < rects.Count; i++)
|
||||
{
|
||||
if (rects[i].Width <= 0 || rects[i].Height <= 0)
|
||||
{
|
||||
rects.RemoveAt(i); i--;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
class CompareCCW : IComparer<Vector2>
|
||||
|
||||
Reference in New Issue
Block a user