Merge branch 'master' into moStuff
# Conflicts: # Barotrauma/BarotraumaShared/Source/Characters/Character.cs
This commit is contained in:
@@ -64,7 +64,7 @@ namespace Barotrauma
|
||||
protected override Vector2 DoSteeringSeek(Vector2 target, float speed = 1)
|
||||
{
|
||||
//find a new path if one hasn't been found yet or the target is different from the current target
|
||||
if (currentPath == null || Vector2.Distance(target, currentTarget)>1.0f || findPathTimer < -5.0f)
|
||||
if (currentPath == null || Vector2.Distance(target, currentTarget) > 1.0f || findPathTimer < -1.0f)
|
||||
{
|
||||
if (findPathTimer > 0.0f) return Vector2.Zero;
|
||||
|
||||
@@ -73,21 +73,21 @@ namespace Barotrauma
|
||||
if (character != null && character.Submarine == null)
|
||||
{
|
||||
var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false);
|
||||
if (targetHull!=null && targetHull.Submarine != null)
|
||||
if (targetHull != null && targetHull.Submarine != null)
|
||||
{
|
||||
pos -= targetHull.SimPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentPath = pathFinder.FindPath(pos, target);
|
||||
|
||||
findPathTimer = Rand.Range(1.0f,1.2f);
|
||||
findPathTimer = Rand.Range(1.0f, 1.2f);
|
||||
|
||||
return DiffToCurrentNode();
|
||||
}
|
||||
|
||||
|
||||
Vector2 diff = DiffToCurrentNode();
|
||||
|
||||
|
||||
var collider = character.AnimController.Collider;
|
||||
//if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
|
||||
if (!character.AnimController.InWater &&
|
||||
@@ -104,7 +104,7 @@ namespace Barotrauma
|
||||
|
||||
private Vector2 DiffToCurrentNode()
|
||||
{
|
||||
if (currentPath == null || currentPath.Finished || currentPath.Unreachable) return Vector2.Zero;
|
||||
if (currentPath == null || currentPath.Unreachable) return Vector2.Zero;
|
||||
|
||||
if (currentPath.Finished)
|
||||
{
|
||||
@@ -113,8 +113,8 @@ namespace Barotrauma
|
||||
{
|
||||
//todo: take multiple subs into account
|
||||
pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
|
||||
}
|
||||
return currentTarget-pos2;
|
||||
}
|
||||
return currentTarget - pos2;
|
||||
}
|
||||
|
||||
if (canOpenDoors && !character.LockHands) CheckDoorsInPath();
|
||||
|
||||
@@ -4,21 +4,13 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjective
|
||||
abstract class AIObjective
|
||||
{
|
||||
protected List<AIObjective> subObjectives;
|
||||
|
||||
protected readonly List<AIObjective> subObjectives;
|
||||
protected float priority;
|
||||
|
||||
protected Character character;
|
||||
|
||||
protected readonly Character character;
|
||||
protected string option;
|
||||
|
||||
public virtual bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool CanBeCompleted
|
||||
{
|
||||
get { return true; }
|
||||
@@ -27,15 +19,12 @@ namespace Barotrauma
|
||||
public string Option
|
||||
{
|
||||
get { return option; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public AIObjective(Character character, string option)
|
||||
{
|
||||
subObjectives = new List<AIObjective>();
|
||||
|
||||
this.character = character;
|
||||
|
||||
this.option = option;
|
||||
|
||||
#if DEBUG
|
||||
@@ -60,8 +49,6 @@ namespace Barotrauma
|
||||
Act(deltaTime);
|
||||
}
|
||||
|
||||
protected virtual void Act(float deltaTime) { }
|
||||
|
||||
public void AddSubObjective(AIObjective objective)
|
||||
{
|
||||
if (subObjectives.Any(o => o.IsDuplicate(objective))) return;
|
||||
@@ -69,19 +56,20 @@ namespace Barotrauma
|
||||
subObjectives.Add(objective);
|
||||
}
|
||||
|
||||
public virtual float GetPriority(Character character)
|
||||
public AIObjective GetCurrentSubObjective()
|
||||
{
|
||||
return 0.0f;
|
||||
AIObjective currentSubObjective = this;
|
||||
while (currentSubObjective.subObjectives.Count > 0)
|
||||
{
|
||||
currentSubObjective = subObjectives[0];
|
||||
}
|
||||
return currentSubObjective;
|
||||
}
|
||||
|
||||
public virtual bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
#if DEBUG
|
||||
throw new NotImplementedException();
|
||||
#else
|
||||
return (this.GetType() == otherObjective.GetType());
|
||||
#endif
|
||||
|
||||
}
|
||||
protected abstract void Act(float deltaTime);
|
||||
|
||||
public abstract bool IsCompleted();
|
||||
public abstract float GetPriority(AIObjectiveManager objectiveManager);
|
||||
public abstract bool IsDuplicate(AIObjective otherObjective);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
coolDownTimer = CoolDown;
|
||||
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
@@ -41,17 +40,24 @@ namespace Barotrauma
|
||||
coolDownTimer -= deltaTime;
|
||||
|
||||
var weapon = character.Inventory.FindItem("weapon");
|
||||
|
||||
if (weapon==null)
|
||||
|
||||
if (weapon == null)
|
||||
{
|
||||
Escape(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: make sure the weapon is ready to use (projectiles/batteries loaded)
|
||||
if (!character.SelectedItems.Contains(weapon))
|
||||
{
|
||||
character.Inventory.TryPutItem(weapon, 3, false, character);
|
||||
weapon.Equip(character);
|
||||
if (character.Inventory.TryPutItem(weapon, 3, false, character))
|
||||
{
|
||||
weapon.Equip(character);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
character.CursorPosition = enemy.Position;
|
||||
character.SetInput(InputType.Aim, false, true);
|
||||
@@ -99,8 +105,13 @@ namespace Barotrauma
|
||||
return enemy.IsDead || coolDownTimer <= 0.0f;
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
//clamp the strength to the health of this character
|
||||
//(it doesn't make a difference whether the enemy does 200 or 600 damage, it's one hit kill anyway)
|
||||
|
||||
|
||||
+10
-9
@@ -19,15 +19,6 @@ namespace Barotrauma
|
||||
{
|
||||
this.itemName = itemName;
|
||||
this.container = container;
|
||||
|
||||
//check if the container has room for more items
|
||||
//canBeCompleted = false;
|
||||
//foreach (Item contained in container.inventory.Items)
|
||||
//{
|
||||
// if (contained != null) continue;
|
||||
// canBeCompleted = true;
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
@@ -35,6 +26,16 @@ namespace Barotrauma
|
||||
return isCompleted || container.Inventory.FindItem(itemName)!=null;
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (isCompleted) return;
|
||||
|
||||
+8
-5
@@ -15,7 +15,7 @@ namespace Barotrauma
|
||||
if (item == null) return false;
|
||||
|
||||
var containedItems = item.ContainedItems;
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Name == "Oxygen Tank" && i.Condition > 0.0f);
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank") && i.Condition > 0.0f);
|
||||
return oxygenTank != null;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma
|
||||
if (containedItems == null) return;
|
||||
|
||||
//check if there's an oxygen tank in the mask
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Name == "Oxygen Tank");
|
||||
var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank"));
|
||||
|
||||
if (oxygenTank != null)
|
||||
{
|
||||
@@ -66,15 +66,18 @@ namespace Barotrauma
|
||||
if (subObjective != null)
|
||||
{
|
||||
subObjective.TryComplete(deltaTime);
|
||||
|
||||
//isCompleted = subObjective.IsCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (character.AnimController.CurrentHull == null) return 100.0f;
|
||||
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
return 100.0f - character.Oxygen;
|
||||
}
|
||||
|
||||
|
||||
+41
-43
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -27,39 +28,23 @@ namespace Barotrauma
|
||||
unreachable = new List<Hull>();
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
|
||||
var currentHull = character.AnimController.CurrentHull;
|
||||
|
||||
currenthullSafety = OverrideCurrentHullSafety == null ?
|
||||
GetHullSafety(currentHull, character) : (float)OverrideCurrentHullSafety;
|
||||
|
||||
if (currentHull != null)
|
||||
|
||||
if (NeedsDivingGear())
|
||||
{
|
||||
if (NeedsDivingGear())
|
||||
{
|
||||
if (!FindDivingGear(deltaTime)) return;
|
||||
}
|
||||
|
||||
if (currenthullSafety > MinSafety)
|
||||
{
|
||||
if (Math.Abs(currentHull.WorldPosition.X - character.WorldPosition.X) > 100.0f)
|
||||
{
|
||||
character.AIController.SteeringManager.SteeringSeek(currentHull.SimPosition, 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
character.AIController.SteeringManager.Reset();
|
||||
}
|
||||
|
||||
character.AIController.SelectTarget(null);
|
||||
|
||||
goToObjective = null;
|
||||
return;
|
||||
}
|
||||
if (!FindDivingGear(deltaTime)) return;
|
||||
}
|
||||
|
||||
|
||||
if (searchHullTimer > 0.0f)
|
||||
{
|
||||
@@ -79,7 +64,7 @@ namespace Barotrauma
|
||||
if (goToObjective != null)
|
||||
{
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering!=null && pathSteering.CurrentPath!= null &&
|
||||
if (pathSteering != null && pathSteering.CurrentPath != null &&
|
||||
pathSteering.CurrentPath.Unreachable && !unreachable.Contains(goToObjective.Target))
|
||||
{
|
||||
unreachable.Add(goToObjective.Target as Hull);
|
||||
@@ -92,7 +77,7 @@ namespace Barotrauma
|
||||
|
||||
private bool FindDivingGear(float deltaTime)
|
||||
{
|
||||
if (divingGearObjective==null)
|
||||
if (divingGearObjective == null)
|
||||
{
|
||||
divingGearObjective = new AIObjectiveFindDivingGear(character, false);
|
||||
}
|
||||
@@ -113,8 +98,9 @@ namespace Barotrauma
|
||||
if (hull == character.AnimController.CurrentHull || unreachable.Contains(hull)) continue;
|
||||
|
||||
float hullValue = GetHullSafety(hull, character);
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X - hull.Position.X));
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y) * 2.0f);
|
||||
//slight preference over hulls that are closer
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X - hull.Position.X)) * 0.1f;
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y)) * 0.2f;
|
||||
|
||||
if (bestHull == null || hullValue > bestValue)
|
||||
{
|
||||
@@ -144,13 +130,13 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (character.Oxygen < 80.0f)
|
||||
{
|
||||
return 150.0f - character.Oxygen;
|
||||
}
|
||||
|
||||
|
||||
if (character.AnimController.CurrentHull == null) return 5.0f;
|
||||
currenthullSafety = GetHullSafety(character.AnimController.CurrentHull, character);
|
||||
priority = 100.0f - currenthullSafety;
|
||||
@@ -171,13 +157,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (NeedsDivingGear())
|
||||
{
|
||||
if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f;
|
||||
}
|
||||
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
@@ -185,11 +170,28 @@ namespace Barotrauma
|
||||
{
|
||||
if (hull == null) return 0.0f;
|
||||
|
||||
float safety = 100.0f;
|
||||
|
||||
float waterPercentage = (hull.WaterVolume / hull.Volume) * 100.0f;
|
||||
if (hull.LethalPressure > 0.0f && character.PressureProtection <= 0.0f)
|
||||
{
|
||||
safety -= 100.0f;
|
||||
}
|
||||
else if (character.OxygenAvailable <= 0.0f)
|
||||
{
|
||||
safety -= waterPercentage;
|
||||
}
|
||||
else
|
||||
{
|
||||
safety -= waterPercentage * 0.1f;
|
||||
}
|
||||
|
||||
if (hull.OxygenPercentage < 30.0f) safety -= (30.0f - hull.OxygenPercentage) * 5.0f;
|
||||
|
||||
if (safety <= 0.0f) return 0.0f;
|
||||
|
||||
float fireAmount = 0.0f;
|
||||
|
||||
var nearbyHulls = hull.GetConnectedHulls(3);
|
||||
|
||||
foreach (Hull hull2 in nearbyHulls)
|
||||
{
|
||||
foreach (FireSource fireSource in hull2.FireSources)
|
||||
@@ -204,13 +206,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
safety -= fireAmount;
|
||||
|
||||
float safety = 100.0f - fireAmount;
|
||||
|
||||
if (waterPercentage > 30.0f && character.OxygenAvailable <= 0.0f) safety -= waterPercentage;
|
||||
if (hull.OxygenPercentage < 30.0f) safety -= (30.0f - hull.OxygenPercentage) * 5.0f;
|
||||
|
||||
return safety;
|
||||
return MathHelper.Clamp(safety, 0.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveFixLeak : AIObjective
|
||||
{
|
||||
private Gap leak;
|
||||
private readonly Gap leak;
|
||||
|
||||
private AIObjectiveGoTo gotoObjective;
|
||||
|
||||
public Gap Leak
|
||||
{
|
||||
@@ -20,15 +22,20 @@ namespace Barotrauma
|
||||
this.leak = leak;
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return leak.Open <= 0.0f || leak.Removed;
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (leak.Open == 0.0f) return 0.0f;
|
||||
|
||||
float leakSize = (leak.IsHorizontal ? leak.Rect.Height : leak.Rect.Width) * Math.Max(leak.Open, 0.1f);
|
||||
|
||||
float dist = Vector2.DistanceSquared(character.SimPosition, leak.SimPosition);
|
||||
dist = Math.Max(dist/100.0f, 1.0f);
|
||||
return Math.Min(leakSize/dist, 40.0f);
|
||||
dist = Math.Max(dist / 100.0f, 1.0f);
|
||||
return Math.Min(leakSize / dist, 40.0f);
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
@@ -44,7 +51,7 @@ namespace Barotrauma
|
||||
|
||||
if (weldingTool == null)
|
||||
{
|
||||
subObjectives.Add(new AIObjectiveGetItem(character, "Welding Tool", true));
|
||||
AddSubObjective(new AIObjectiveGetItem(character, "Welding Tool", true));
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -52,25 +59,31 @@ namespace Barotrauma
|
||||
var containedItems = weldingTool.ContainedItems;
|
||||
if (containedItems == null) return;
|
||||
|
||||
var fuelTank = Array.Find(containedItems, i => i.Name == "Welding Fuel Tank" && i.Condition > 0.0f);
|
||||
var fuelTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Welding Fuel Tank") && i.Condition > 0.0f);
|
||||
|
||||
if (fuelTank == null)
|
||||
{
|
||||
AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent<ItemContainer>()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var repairTool = weldingTool.GetComponent<RepairTool>();
|
||||
if (repairTool == null) return;
|
||||
|
||||
if (Vector2.Distance(character.WorldPosition, leak.WorldPosition) > 300.0f)
|
||||
Vector2 standPosition = GetStandPosition();
|
||||
|
||||
if (Vector2.DistanceSquared(character.WorldPosition, leak.WorldPosition) > 100.0f * 100.0f)
|
||||
{
|
||||
AddSubObjective(new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character));
|
||||
var gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(standPosition), character);
|
||||
if (!gotoObjective.IsCompleted())
|
||||
{
|
||||
AddSubObjective(gotoObjective);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", leak));
|
||||
}
|
||||
|
||||
AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", true, leak));
|
||||
}
|
||||
|
||||
private Vector2 GetStandPosition()
|
||||
|
||||
@@ -7,38 +7,80 @@ namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveFixLeaks : AIObjective
|
||||
{
|
||||
const float UpdateGapListInterval = 10.0f;
|
||||
const float UpdateGapListInterval = 5.0f;
|
||||
|
||||
private float updateGapListTimer;
|
||||
private double lastGapUpdate;
|
||||
|
||||
private AIObjectiveIdle idleObjective;
|
||||
|
||||
private AIObjectiveFindDivingGear findDivingGear;
|
||||
|
||||
private List<AIObjectiveFixLeak> objectiveList;
|
||||
|
||||
public AIObjectiveFixLeaks(Character character)
|
||||
: base (character, "")
|
||||
{
|
||||
objectiveList = new List<AIObjectiveFixLeak>();
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
|
||||
{
|
||||
UpdateGapList();
|
||||
lastGapUpdate = Timing.TotalTime;
|
||||
}
|
||||
|
||||
return objectiveList.Count == 0;
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
|
||||
{
|
||||
UpdateGapList();
|
||||
lastGapUpdate = Timing.TotalTime;
|
||||
}
|
||||
|
||||
float priority = 0.0f;
|
||||
foreach (AIObjectiveFixLeak fixObjective in objectiveList)
|
||||
{
|
||||
//gaps from outside to inside significantly increase the priority
|
||||
if (!fixObjective.Leak.IsRoomToRoom)
|
||||
{
|
||||
priority = Math.Max(priority + fixObjective.Leak.Open * 100.0f, 50.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
priority += fixObjective.Leak.Open * 10.0f;
|
||||
}
|
||||
|
||||
if (priority >= 100.0f) break;
|
||||
}
|
||||
|
||||
return Math.Min(priority, 100.0f);
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
updateGapListTimer -= deltaTime;
|
||||
|
||||
if (updateGapListTimer<=0.0f)
|
||||
if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
|
||||
{
|
||||
UpdateGapList();
|
||||
|
||||
updateGapListTimer = UpdateGapListInterval;
|
||||
lastGapUpdate = Timing.TotalTime;
|
||||
}
|
||||
|
||||
if (objectiveList.Any())
|
||||
{
|
||||
if (!objectiveList[objectiveList.Count - 1].Leak.IsRoomToRoom)
|
||||
{
|
||||
if (findDivingGear == null) findDivingGear = new AIObjectiveFindDivingGear(character, true);
|
||||
|
||||
if (!findDivingGear.IsCompleted() && findDivingGear.CanBeCompleted)
|
||||
{
|
||||
findDivingGear.TryComplete(deltaTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
objectiveList[objectiveList.Count - 1].TryComplete(deltaTime);
|
||||
|
||||
if (!objectiveList[objectiveList.Count - 1].CanBeCompleted ||
|
||||
@@ -56,6 +98,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateGapList()
|
||||
{
|
||||
if (objectiveList == null) objectiveList = new List<AIObjectiveFixLeak>();
|
||||
objectiveList.Clear();
|
||||
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -26,6 +27,16 @@ namespace Barotrauma
|
||||
get { return canBeCompleted; }
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, Item targetItem, bool equip = false)
|
||||
: base(character, "")
|
||||
{
|
||||
|
||||
@@ -18,6 +18,16 @@ namespace Barotrauma
|
||||
|
||||
private bool getDivingGearIfNeeded;
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get
|
||||
@@ -93,7 +103,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Vector2.Distance(currTargetPos, character.SimPosition) < 1.0f)
|
||||
if (Vector2.DistanceSquared(currTargetPos, character.SimPosition) < 0.5f * 0.5f)
|
||||
{
|
||||
character.AIController.SteeringManager.Reset();
|
||||
character.AnimController.TargetDir = currTargetPos.X > character.SimPosition.X ? Direction.Right : Direction.Left;
|
||||
@@ -104,7 +114,7 @@ namespace Barotrauma
|
||||
|
||||
var indoorsSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
|
||||
if (indoorsSteering.CurrentPath==null || indoorsSteering.CurrentPath.Unreachable)
|
||||
if (indoorsSteering.CurrentPath == null || indoorsSteering.CurrentPath.Unreachable)
|
||||
{
|
||||
indoorsSteering.SteeringWander();
|
||||
}
|
||||
@@ -130,7 +140,7 @@ namespace Barotrauma
|
||||
if (item.IsInsideTrigger(character.WorldPosition)) completed = true;
|
||||
}
|
||||
|
||||
completed = completed || Vector2.Distance(target != null ? target.SimPosition : targetPos, character.SimPosition) < allowedDistance;
|
||||
completed = completed || Vector2.DistanceSquared(target != null ? target.SimPosition : targetPos, character.SimPosition) < allowedDistance * allowedDistance;
|
||||
|
||||
if (completed) character.AIController.SteeringManager.Reset();
|
||||
|
||||
|
||||
@@ -9,15 +9,21 @@ namespace Barotrauma
|
||||
{
|
||||
const float WallAvoidDistance = 150.0f;
|
||||
|
||||
AITarget currentTarget;
|
||||
private AITarget currentTarget;
|
||||
private float newTargetTimer;
|
||||
|
||||
private AIObjectiveFindSafety findSafety;
|
||||
|
||||
public AIObjectiveIdle(Character character) : base(character, "")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
@@ -31,6 +37,14 @@ namespace Barotrauma
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
//attempt to find a safer place if in water
|
||||
if (findSafety == null) findSafety = new AIObjectiveFindSafety(character);
|
||||
findSafety.TryComplete(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newTargetTimer <= 0.0f)
|
||||
{
|
||||
@@ -92,17 +106,10 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
character.AIController.SteeringManager.SteeringManual(deltaTime, new Vector2(0.0f, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
character.AIController.SteeringManager.SteeringWander();
|
||||
//reset vertical steering to prevent dropping down from platforms etc
|
||||
character.AIController.SteeringManager.ResetY();
|
||||
}
|
||||
|
||||
character.AIController.SteeringManager.SteeringWander();
|
||||
//reset vertical steering to prevent dropping down from platforms etc
|
||||
character.AIController.SteeringManager.ResetY();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,15 +11,17 @@ namespace Barotrauma
|
||||
|
||||
private Character character;
|
||||
|
||||
private AIObjective currentObjective;
|
||||
private AIObjective currentOrder;
|
||||
|
||||
public AIObjective CurrentOrder
|
||||
{
|
||||
get { return currentOrder; }
|
||||
}
|
||||
|
||||
public AIObjective CurrentObjective
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentObjective != null) return currentObjective;
|
||||
return objectives.Any() ? objectives[0] : null;
|
||||
}
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public AIObjectiveManager(Character character)
|
||||
@@ -47,8 +49,13 @@ namespace Barotrauma
|
||||
|
||||
public float GetCurrentPriority(Character character)
|
||||
{
|
||||
if (currentObjective != null) return OrderPriority;
|
||||
return (CurrentObjective == null) ? 0.0f : CurrentObjective.GetPriority(character);
|
||||
if (CurrentOrder != null &&
|
||||
(objectives.Count == 0 || currentOrder.GetPriority(this) > objectives[0].GetPriority(this)))
|
||||
{
|
||||
return CurrentOrder.GetPriority(this);
|
||||
}
|
||||
|
||||
return objectives.Count == 0 ? 0.0f : objectives[0].GetPriority(this);
|
||||
}
|
||||
|
||||
public void UpdateObjectives()
|
||||
@@ -59,43 +66,46 @@ namespace Barotrauma
|
||||
objectives = objectives.FindAll(o => !o.IsCompleted() && o.CanBeCompleted);
|
||||
|
||||
//sort objectives according to priority
|
||||
objectives.Sort((x, y) => y.GetPriority(character).CompareTo(x.GetPriority(character)));
|
||||
objectives.Sort((x, y) => y.GetPriority(this).CompareTo(x.GetPriority(this)));
|
||||
}
|
||||
|
||||
public void DoCurrentObjective(float deltaTime)
|
||||
{
|
||||
if (currentObjective != null && (!objectives.Any() || objectives[0].GetPriority(character) < OrderPriority))
|
||||
if (currentOrder != null && (!objectives.Any() || objectives[0].GetPriority(this) < currentOrder.GetPriority(this)))
|
||||
{
|
||||
currentObjective.TryComplete(deltaTime);
|
||||
CurrentObjective = currentOrder;
|
||||
currentOrder.TryComplete(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!objectives.Any()) return;
|
||||
objectives[0].TryComplete(deltaTime);
|
||||
|
||||
CurrentObjective = objectives[0];
|
||||
}
|
||||
|
||||
public void SetOrder(Order order, string option)
|
||||
{
|
||||
if (order == null) return;
|
||||
|
||||
currentObjective = null;
|
||||
currentOrder = null;
|
||||
|
||||
switch (order.Name.ToLowerInvariant())
|
||||
{
|
||||
case "follow":
|
||||
currentObjective = new AIObjectiveGoTo(Character.Controlled, character, true);
|
||||
currentOrder = new AIObjectiveGoTo(Character.Controlled, character, true);
|
||||
break;
|
||||
case "wait":
|
||||
currentObjective = new AIObjectiveGoTo(character, character, true);
|
||||
currentOrder = new AIObjectiveGoTo(character, character, true);
|
||||
break;
|
||||
case "fixleaks":
|
||||
case "fix leaks":
|
||||
currentObjective = new AIObjectiveFixLeaks(character);
|
||||
currentOrder = new AIObjectiveFixLeaks(character);
|
||||
break;
|
||||
default:
|
||||
if (order.TargetItem == null) return;
|
||||
|
||||
currentObjective = new AIObjectiveOperateItem(order.TargetItem, character, option, null, order.UseController);
|
||||
currentOrder = new AIObjectiveOperateItem(order.TargetItem, character, option, false, null, order.UseController);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
+53
-3
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -14,6 +15,8 @@ namespace Barotrauma
|
||||
|
||||
private bool canBeCompleted;
|
||||
|
||||
private bool requireEquip;
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get
|
||||
@@ -27,11 +30,21 @@ namespace Barotrauma
|
||||
get { return operateTarget; }
|
||||
}
|
||||
|
||||
public AIObjectiveOperateItem(ItemComponent item, Character character, string option, Entity operateTarget = null, bool useController = false)
|
||||
:base (character, option)
|
||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this)
|
||||
{
|
||||
return AIObjectiveManager.OrderPriority;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public AIObjectiveOperateItem(ItemComponent item, Character character, string option, bool requireEquip, Entity operateTarget = null, bool useController = false)
|
||||
: base (character, option)
|
||||
{
|
||||
this.component = item;
|
||||
|
||||
this.requireEquip = requireEquip;
|
||||
this.operateTarget = operateTarget;
|
||||
|
||||
if (useController)
|
||||
@@ -72,6 +85,43 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (requireEquip && !character.HasEquippedItem(component.Item))
|
||||
{
|
||||
//the item has to be equipped before using it if it's holdable
|
||||
var holdable = component.Item.GetComponent<Holdable>();
|
||||
if (holdable == null)
|
||||
{
|
||||
DebugConsole.ThrowError("AIObjectiveOperateItem failed - equipping item " + component.Item + " is required but the item has no Holdable component");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < CharacterInventory.limbSlots.Length; i++)
|
||||
{
|
||||
if (CharacterInventory.limbSlots[i] == InvSlotType.Any ||
|
||||
!holdable.AllowedSlots.Any(s => s.HasFlag(CharacterInventory.limbSlots[i])))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//equip slot already taken
|
||||
if (character.Inventory.Items[i] != null)
|
||||
{
|
||||
//try to put the item in an Any slot, and drop it if that fails
|
||||
if (!character.Inventory.Items[i].AllowedSlots.Contains(InvSlotType.Any) ||
|
||||
!character.Inventory.TryPutItem(character.Inventory.Items[i], character, new List<InvSlotType>() { InvSlotType.Any }))
|
||||
{
|
||||
character.Inventory.Items[i].Drop();
|
||||
}
|
||||
}
|
||||
if (character.Inventory.TryPutItem(component.Item, i, true, character))
|
||||
{
|
||||
component.Item.Equip(character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.AIOperate(deltaTime, character, this)) isCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Diagnostics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveRescue : AIObjective
|
||||
/*class AIObjectiveRescue : AIObjective
|
||||
{
|
||||
private readonly Character targetCharacter;
|
||||
|
||||
@@ -30,5 +30,5 @@ namespace Barotrauma
|
||||
return targetCharacter.IsDead ? 1000.0f / distance : 10000.0f / distance;
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveRescueAll : AIObjective
|
||||
/*class AIObjectiveRescueAll : AIObjective
|
||||
{
|
||||
private List<Character> rescueTargets;
|
||||
|
||||
@@ -44,5 +44,5 @@ namespace Barotrauma
|
||||
AddSubObjective(new AIObjectiveRescue(character, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Barotrauma
|
||||
public enum Animation { None, Climbing, UsingConstruction, Struggle, CPR };
|
||||
public Animation Anim;
|
||||
|
||||
public LimbType GrabLimb;
|
||||
|
||||
protected Character character;
|
||||
|
||||
protected float walkSpeed, swimSpeed;
|
||||
|
||||
+164
-31
@@ -20,6 +20,7 @@ namespace Barotrauma
|
||||
private float thighTorque;
|
||||
|
||||
private float cprAnimState;
|
||||
private float cprPump;
|
||||
|
||||
private float inWaterTimer;
|
||||
private bool swimming;
|
||||
@@ -872,7 +873,34 @@ namespace Barotrauma
|
||||
character.SelectedConstruction = null;
|
||||
IgnorePlatforms = false;
|
||||
}
|
||||
else if (character.SelectedCharacter != null && !character.SelectedCharacter.AllowInput)
|
||||
{
|
||||
Limb targetLeftHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.LeftHand);
|
||||
Limb targetRightHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.RightHand);
|
||||
Limb targetTorso = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso);
|
||||
|
||||
if (character.SelectedCharacter.AnimController.Dir != Dir)
|
||||
character.SelectedCharacter.AnimController.Flip();
|
||||
|
||||
targetTorso.pullJoint.Enabled = true;
|
||||
targetTorso.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * -Dir) * 0.2f;
|
||||
targetTorso.pullJoint.MaxForce = 5000.0f;
|
||||
|
||||
if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLeftHand.pullJoint.Enabled = true;
|
||||
targetLeftHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f;
|
||||
targetLeftHand.pullJoint.MaxForce = 5000.0f;
|
||||
}
|
||||
if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetRightHand.pullJoint.Enabled = true;
|
||||
targetRightHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f;
|
||||
targetRightHand.pullJoint.MaxForce = 5000.0f;
|
||||
}
|
||||
|
||||
character.SelectedCharacter.AnimController.IgnorePlatforms = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCPR(float deltaTime)
|
||||
@@ -883,11 +911,16 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
Character target = character.SelectedCharacter;
|
||||
|
||||
Crouching = true;
|
||||
|
||||
Vector2 diff = character.SelectedCharacter.SimPosition - character.SimPosition;
|
||||
var targetHead = character.SelectedCharacter.AnimController.GetLimb(LimbType.Head);
|
||||
|
||||
Vector2 diff = target.SimPosition - character.SimPosition;
|
||||
Limb targetHead = target.AnimController.GetLimb(LimbType.Head);
|
||||
Limb targetTorso = target.AnimController.GetLimb(LimbType.Torso);
|
||||
Limb head = GetLimb(LimbType.Head);
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
|
||||
Vector2 headDiff = targetHead == null ? diff : targetHead.SimPosition - character.SimPosition;
|
||||
|
||||
targetMovement = new Vector2(diff.X, 0.0f);
|
||||
@@ -895,21 +928,98 @@ namespace Barotrauma
|
||||
|
||||
UpdateStanding();
|
||||
|
||||
Vector2 handPos = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso).SimPosition + Vector2.UnitY * 0.2f;
|
||||
Vector2 handPos = targetTorso.SimPosition + Vector2.UnitY * 0.2f;
|
||||
|
||||
Grab(handPos, handPos);
|
||||
|
||||
float yPos = (float)Math.Sin(cprAnimState) * 0.1f;
|
||||
cprAnimState += deltaTime * 8.0f;
|
||||
Vector2 colliderPos = GetColliderBottom();
|
||||
|
||||
var head = GetLimb(LimbType.Head);
|
||||
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.6f + yPos);
|
||||
head.pullJoint.Enabled = true;
|
||||
if (GameMain.Client == null) //Serverside code
|
||||
{
|
||||
if (target.Bleeding <= 0.5f && target.Oxygen <= 0.0f) //If they're bleeding too hard CPR will hurt them
|
||||
{
|
||||
target.Oxygen += deltaTime * 0.5f; //Stabilize them
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int skill = character.GetSkillLevel("Medical");
|
||||
if (cprAnimState % 17 > 15.0f)
|
||||
{
|
||||
float yPos = (float)Math.Sin(cprAnimState) * 0.2f;
|
||||
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.3f + yPos);
|
||||
head.pullJoint.Enabled = true;
|
||||
torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.2f));
|
||||
torso.pullJoint.Enabled = true;
|
||||
|
||||
if (GameMain.Client == null) //Serverside code
|
||||
{
|
||||
float cpr = skill / 2.0f; //Max possible oxygen addition is 20 per second
|
||||
character.Oxygen -= (30.0f - cpr) * deltaTime; //Worse skill = more oxygen required
|
||||
if (character.Oxygen > 0.0f) //we didn't suffocate yet did we
|
||||
target.Oxygen += cpr * deltaTime;
|
||||
|
||||
//DebugConsole.NewMessage("CPR Us: " + character.Oxygen + " Them: " + target.Oxygen + " How good we are: restore " + cpr + " use " + (30.0f - cpr), Color.Aqua);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.8f);
|
||||
head.pullJoint.Enabled = true;
|
||||
torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.1f));
|
||||
torso.pullJoint.Enabled = true;
|
||||
if (cprPump >= 1)
|
||||
{
|
||||
torso.body.ApplyForce(new Vector2(0, -1000f));
|
||||
targetTorso.body.ApplyForce(new Vector2(0, -1000f));
|
||||
cprPump = 0;
|
||||
|
||||
if (target.Bleeding <= 0.5f && target.Health <= 0.0f && !target.IsDead) //Have a chance to revive them to 2 HP if they were damaged.
|
||||
{
|
||||
if (GameMain.Client == null) //Serverside code
|
||||
{
|
||||
float reviveChance = (cprAnimState % 17) * (skill / 50.0f); //~5% max chance for 10 skill, ~50% max chance for 100 skill
|
||||
float rng = Rand.Int(100, Rand.RandSync.Server);
|
||||
|
||||
//DebugConsole.NewMessage("CPR Pump cprAnimState: " + (cprAnimState % 17) + " revive chance: " + reviveChance + " rng: " + rng, Color.Aqua);
|
||||
if (rng <= reviveChance) //HOLY CRAP YOU SAVED HIM!!!
|
||||
{
|
||||
target.Oxygen = Math.Max(target.Oxygen, 10.0f);
|
||||
target.Health = 2.0f;
|
||||
Anim = Animation.None;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (target.Bleeding > 0.5f || skill < 50) //We will hurt them if they're bleeding or we suck
|
||||
{
|
||||
//If not bleeding: 10% skill causes 0.8 damage per pump, 40% skill causes only 0.2
|
||||
if (target.Bleeding <= 0.5f)
|
||||
target.AddDamage(CauseOfDeath.Damage, (50 - skill) * 0.02f, character);
|
||||
else //If bleeding: 2 HP damage per pump. Basically speeds up their death. Don't pump bleeding people!
|
||||
{
|
||||
target.AddDamage(CauseOfDeath.Bloodloss, 1.0f, character);
|
||||
#if CLIENT
|
||||
SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, 25.0f, targetTorso.body);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", targetTorso.WorldPosition, Rand.Vector(10.0f), 0.0f, target.AnimController.CurrentHull);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
cprPump += deltaTime;
|
||||
}
|
||||
|
||||
cprAnimState += deltaTime;
|
||||
}
|
||||
public override void DragCharacter(Character target)
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
Limb leftHand = GetLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetLimb(LimbType.RightHand);
|
||||
|
||||
@@ -922,31 +1032,34 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Limb targetLimb = target.AnimController.GetLimb(LimbType.Torso);
|
||||
Limb targetLimb = target.AnimController.GetLimb(GrabLimb);
|
||||
|
||||
if (i == 0)
|
||||
if (targetLimb == null || targetLimb.IsSevered)
|
||||
{
|
||||
if (!targetLeftHand.IsSevered)
|
||||
targetLimb = target.AnimController.GetLimb(LimbType.Torso);
|
||||
if (i == 0)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
}
|
||||
else if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
}
|
||||
}
|
||||
else if (!targetRightHand.IsSevered)
|
||||
else
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
}
|
||||
else if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
}
|
||||
else if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
}
|
||||
}
|
||||
|
||||
Limb pullLimb = i == 0 ? leftHand : rightHand;
|
||||
|
||||
if (i == 1 && inWater)
|
||||
@@ -958,12 +1071,32 @@ namespace Barotrauma
|
||||
Vector2 diff = ConvertUnits.ToSimUnits(targetLimb.WorldPosition - pullLimb.WorldPosition);
|
||||
|
||||
pullLimb.pullJoint.Enabled = true;
|
||||
pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff;
|
||||
pullLimb.pullJoint.MaxForce = 10000.0f;
|
||||
if (targetLimb.type == LimbType.Torso)
|
||||
{
|
||||
pullLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition;
|
||||
pullLimb.pullJoint.MaxForce = 5000.0f;
|
||||
targetMovement *= 0.7f; //Carrying people like that takes a lot of effort.
|
||||
|
||||
if (target.AnimController.Dir != Dir)
|
||||
target.AnimController.Flip();
|
||||
}
|
||||
else
|
||||
{
|
||||
pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff;
|
||||
pullLimb.pullJoint.MaxForce = 5000.0f;
|
||||
}
|
||||
|
||||
targetLimb.pullJoint.Enabled = true;
|
||||
targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff;
|
||||
targetLimb.pullJoint.MaxForce = 10000.0f;
|
||||
if (targetLimb.type == LimbType.Torso)
|
||||
{
|
||||
targetLimb.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * Dir) * 0.6f;
|
||||
targetLimb.pullJoint.MaxForce = 300.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff;
|
||||
targetLimb.pullJoint.MaxForce = 5000.0f;
|
||||
}
|
||||
|
||||
target.AnimController.movement = -diff;
|
||||
}
|
||||
|
||||
@@ -1384,7 +1384,7 @@ namespace Barotrauma
|
||||
findFocusedTimer -= deltaTime;
|
||||
}
|
||||
|
||||
if (SelectedCharacter != null && IsKeyHit(InputType.Select))
|
||||
if (SelectedCharacter != null && focusedItem == null && IsKeyHit(InputType.Select)) //Let people use ladders and buttons and stuff when dragging chars
|
||||
{
|
||||
DeselectCharacter();
|
||||
}
|
||||
@@ -1542,26 +1542,42 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//Skip health effects as critical health handles it differently
|
||||
if (IsUnconscious)
|
||||
{
|
||||
UpdateUnconscious(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
|
||||
if (IsForceRagdolled)
|
||||
IsRagdolled = IsForceRagdolled;
|
||||
else if (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f) //Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
||||
else if ((GameMain.Server == null || GameMain.Server.AllowRagdollButton) && (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f)) //Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
||||
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
||||
|
||||
//Health effects
|
||||
if (needsAir) UpdateOxygen(deltaTime);
|
||||
|
||||
Health -= bleeding * deltaTime;
|
||||
Bleeding -= BleedingDecreaseSpeed * deltaTime;
|
||||
|
||||
if (health <= minHealth) Kill(CauseOfDeath.Bloodloss);
|
||||
|
||||
if (!IsDead) LockHands = false;
|
||||
|
||||
//ragdoll button
|
||||
if (IsRagdolled)
|
||||
{
|
||||
if (AnimController is HumanoidAnimController) ((HumanoidAnimController)AnimController).Crouching = false;
|
||||
|
||||
if(GameMain.Server != null)
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
AnimController.ResetPullJoints();
|
||||
selectedConstruction = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//AI and control stuff
|
||||
|
||||
Control(deltaTime, cam);
|
||||
if (controlled != this && (!(this is AICharacter) || IsRemotePlayer))
|
||||
{
|
||||
@@ -1574,11 +1590,6 @@ namespace Barotrauma
|
||||
selectedConstruction = null;
|
||||
}
|
||||
|
||||
if (SelectedCharacter != null && AnimController.Anim == AnimController.Animation.CPR)
|
||||
{
|
||||
if (GameMain.Client == null) SelectedCharacter.Oxygen += (GetSkillLevel("Medical") / 10.0f) * deltaTime;
|
||||
}
|
||||
|
||||
UpdateSightRange();
|
||||
if (aiTarget != null) aiTarget.SoundRange = 0.0f;
|
||||
|
||||
@@ -1595,6 +1606,7 @@ namespace Barotrauma
|
||||
if (health <= minHealth) Kill(CauseOfDeath.Bloodloss);
|
||||
|
||||
if (!IsDead) LockHands = false;
|
||||
//CPR stuff is handled in the UpdateCPR function in HumanoidAnimController
|
||||
}
|
||||
|
||||
partial void UpdateControlled(float deltaTime, Camera cam);
|
||||
@@ -1634,12 +1646,17 @@ namespace Barotrauma
|
||||
AnimController.ResetPullJoints();
|
||||
selectedConstruction = null;
|
||||
|
||||
if (oxygen <= 0.0f) Oxygen -= deltaTime * 0.5f;
|
||||
Oxygen -= deltaTime * 0.5f; //We're critical - our heart stopped!
|
||||
|
||||
if (health <= 0.0f)
|
||||
if (health <= 0.0f) //Critical health - use current state for crit time
|
||||
{
|
||||
AddDamage(bleeding > 0.5f ? CauseOfDeath.Bloodloss : CauseOfDeath.Damage, Math.Max(bleeding, 1.0f) * deltaTime, null);
|
||||
}
|
||||
else //Keep on bleedin'
|
||||
{
|
||||
Health -= bleeding * deltaTime;
|
||||
Bleeding -= BleedingDecreaseSpeed * deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSightRange()
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace Barotrauma
|
||||
break;
|
||||
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
int eventType = msg.ReadRangedInteger(0,2);
|
||||
int eventType = msg.ReadRangedInteger(0,3);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0:
|
||||
@@ -357,6 +357,9 @@ namespace Barotrauma
|
||||
Kill(lastAttackCauseOfDeath);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
AnimController.GrabLimb = (LimbType)msg.ReadUInt16();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -436,6 +439,7 @@ namespace Barotrauma
|
||||
if (AnimController is HumanoidAnimController)
|
||||
{
|
||||
tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching);
|
||||
tempBuffer.Write((UInt16)AnimController.GrabLimb);
|
||||
}
|
||||
|
||||
bool hasAttackLimb = AnimController.Limbs.Any(l => l != null && l.attack != null);
|
||||
@@ -534,6 +538,8 @@ namespace Barotrauma
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(Stun, 0.0f, MaxStun), 0.0f, MaxStun, 8);
|
||||
}
|
||||
|
||||
msg.Write(IsRagdolled);
|
||||
|
||||
msg.Write(HuskInfectionState > 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -103,11 +103,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character == null) return false;
|
||||
if (!character.IsKeyDown(InputType.Aim)) return false;
|
||||
|
||||
//if (DoesUseFail(Character)) return false;
|
||||
|
||||
//targetPosition = targetPosition.X, -targetPosition.Y);
|
||||
|
||||
|
||||
float degreeOfSuccess = DegreeOfSuccess(character)/100.0f;
|
||||
|
||||
if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
|
||||
@@ -241,7 +237,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Gap leak = objective.OperateTarget as Gap;
|
||||
if (leak == null) return true;
|
||||
|
||||
|
||||
float dist = Vector2.Distance(leak.WorldPosition, item.WorldPosition);
|
||||
|
||||
//too far away -> consider this done and hope the AI is smart enough to move closer
|
||||
|
||||
@@ -258,9 +258,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (batteryToLoad == null) return true;
|
||||
|
||||
if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed*0.4f)
|
||||
if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
|
||||
{
|
||||
objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, ""));
|
||||
objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "", false));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,14 +678,13 @@ namespace Barotrauma
|
||||
|
||||
if (!MathUtils.IsValid(damage)) return;
|
||||
|
||||
float damageDiff = damage - sections[sectionIndex].damage;
|
||||
|
||||
|
||||
if (GameMain.Server != null && damage != sections[sectionIndex].damage)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
|
||||
AdjustKarma(attacker, damageDiff);
|
||||
if (damage < prefab.Health*0.5f)
|
||||
{
|
||||
if (sections[sectionIndex].gap != null)
|
||||
@@ -717,10 +716,14 @@ namespace Barotrauma
|
||||
|
||||
sections[sectionIndex].gap.Open = (damage / prefab.Health - 0.5f) * 2.0f;
|
||||
}
|
||||
|
||||
|
||||
float damageDiff = damage - sections[sectionIndex].damage;
|
||||
bool hadHole = SectionBodyDisabled(sectionIndex);
|
||||
sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, prefab.Health);
|
||||
|
||||
if (sections[sectionIndex].damage < prefab.Health) //otherwise it's possible to infinitely gain karma by welding fixed things
|
||||
AdjustKarma(attacker, damageDiff);
|
||||
|
||||
bool hasHole = SectionBodyDisabled(sectionIndex);
|
||||
|
||||
if (hadHole == hasHole) return;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
enum ChatMessageType
|
||||
{
|
||||
Default, Error, Dead, Server, Radio, Private, MessageBox
|
||||
Default, Error, Dead, Server, Radio, Private, Console, MessageBox
|
||||
}
|
||||
|
||||
partial class ChatMessage
|
||||
@@ -25,7 +25,8 @@ namespace Barotrauma.Networking
|
||||
new Color(63, 72, 204), //dead
|
||||
new Color(157, 225, 160), //server
|
||||
new Color(238, 208, 0), //radio
|
||||
new Color(64, 240, 89) //private
|
||||
new Color(64, 240, 89), //private
|
||||
new Color(255, 255, 255) //console
|
||||
};
|
||||
|
||||
public readonly string Text;
|
||||
|
||||
@@ -1,29 +1,10 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
[Flags]
|
||||
enum ClientPermissions
|
||||
{
|
||||
None = 0,
|
||||
[Description("End round")]
|
||||
EndRound = 1,
|
||||
[Description("Kick")]
|
||||
Kick = 2,
|
||||
[Description("Ban")]
|
||||
Ban = 4,
|
||||
[Description("Select submarine")]
|
||||
SelectSub = 8,
|
||||
[Description("Select game mode")]
|
||||
SelectMode = 16,
|
||||
[Description("Manage campaign")]
|
||||
ManageCampaign = 32
|
||||
}
|
||||
|
||||
class Client
|
||||
{
|
||||
public string Name;
|
||||
@@ -96,6 +77,11 @@ namespace Barotrauma.Networking
|
||||
public float DeleteDisconnectedTimer;
|
||||
|
||||
public ClientPermissions Permissions = ClientPermissions.None;
|
||||
public List<DebugConsole.Command> PermittedConsoleCommands
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool SpectateOnly;
|
||||
|
||||
@@ -130,6 +116,7 @@ namespace Barotrauma.Networking
|
||||
this.Name = name;
|
||||
this.ID = ID;
|
||||
|
||||
PermittedConsoleCommands = new List<DebugConsole.Command>();
|
||||
kickVoters = new List<Client>();
|
||||
|
||||
votes = new object[Enum.GetNames(typeof(VoteType)).Length];
|
||||
@@ -171,9 +158,10 @@ namespace Barotrauma.Networking
|
||||
return rName;
|
||||
}
|
||||
|
||||
public void SetPermissions(ClientPermissions permissions)
|
||||
public void SetPermissions(ClientPermissions permissions, List<DebugConsole.Command> permittedConsoleCommands)
|
||||
{
|
||||
this.Permissions = permissions;
|
||||
this.PermittedConsoleCommands = new List<DebugConsole.Command>(permittedConsoleCommands);
|
||||
}
|
||||
|
||||
public void GivePermission(ClientPermissions permission)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
[Flags]
|
||||
enum ClientPermissions
|
||||
{
|
||||
None = 0,
|
||||
[Description("End round")]
|
||||
EndRound = 1,
|
||||
[Description("Kick")]
|
||||
Kick = 2,
|
||||
[Description("Ban")]
|
||||
Ban = 4,
|
||||
[Description("Select submarine")]
|
||||
SelectSub = 8,
|
||||
[Description("Select game mode")]
|
||||
SelectMode = 16,
|
||||
[Description("Manage campaign")]
|
||||
ManageCampaign = 32,
|
||||
[Description("Console commands")]
|
||||
ConsoleCommands = 64
|
||||
}
|
||||
|
||||
class PermissionPreset
|
||||
{
|
||||
public static List<PermissionPreset> List = new List<PermissionPreset>();
|
||||
|
||||
public readonly string Name;
|
||||
public readonly string Description;
|
||||
public readonly ClientPermissions Permissions;
|
||||
public readonly List<DebugConsole.Command> PermittedCommands;
|
||||
|
||||
public PermissionPreset(XElement element)
|
||||
{
|
||||
Name = element.GetAttributeString("name", "");
|
||||
Description = element.GetAttributeString("description", "");
|
||||
|
||||
string permissionsStr = element.GetAttributeString("permissions", "");
|
||||
if (!Enum.TryParse(permissionsStr, out Permissions))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in permission preset \"" + Name + "\" - " + permissionsStr + " is not a valid permission!");
|
||||
}
|
||||
|
||||
PermittedCommands = new List<DebugConsole.Command>();
|
||||
if (Permissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "command") continue;
|
||||
string commandName = subElement.GetAttributeString("name", "");
|
||||
|
||||
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
|
||||
if (command == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in permission preset \"" + Name + "\" - " + commandName + "\" is not a valid console command.");
|
||||
continue;
|
||||
}
|
||||
|
||||
PermittedCommands.Add(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadAll(string file)
|
||||
{
|
||||
if (!File.Exists(file)) return;
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
List.Add(new PermissionPreset(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,8 +125,9 @@ namespace Barotrauma.Networking
|
||||
banList = new BanList();
|
||||
|
||||
LoadSettings();
|
||||
PermissionPreset.LoadAll(PermissionPresetFile);
|
||||
LoadClientPermissions();
|
||||
|
||||
|
||||
CoroutineManager.StartCoroutine(StartServer(isPublic));
|
||||
}
|
||||
|
||||
@@ -795,6 +796,11 @@ namespace Barotrauma.Networking
|
||||
campaign.ServerRead(inc, sender);
|
||||
}
|
||||
break;
|
||||
case ClientPermissions.ConsoleCommands:
|
||||
string consoleCommand = inc.ReadString();
|
||||
Vector2 clientCursorPos = new Vector2(inc.ReadSingle(), inc.ReadSingle());
|
||||
DebugConsole.ExecuteClientCommand(sender, clientCursorPos, consoleCommand);
|
||||
break;
|
||||
}
|
||||
|
||||
inc.ReadPadBits();
|
||||
@@ -853,7 +859,7 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(GameStarted);
|
||||
outmsg.Write(AllowSpectating);
|
||||
|
||||
outmsg.Write((byte)c.Permissions);
|
||||
WritePermissions(outmsg, c);
|
||||
}
|
||||
|
||||
private void ClientWriteIngame(Client c)
|
||||
@@ -1636,6 +1642,18 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void SendChatMessage(string txt, Client recipient)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Server, null);
|
||||
SendChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
public void SendConsoleMessage(string txt, Client recipient)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, null);
|
||||
SendChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
public void SendChatMessage(ChatMessage msg, Client recipient)
|
||||
{
|
||||
msg.NetStateID = recipient.ChatMsgQueue.Count > 0 ?
|
||||
@@ -1936,16 +1954,34 @@ namespace Barotrauma.Networking
|
||||
clientPermissions.Add(new SavedClientPermission(
|
||||
client.Name,
|
||||
client.Connection.RemoteEndPoint.Address.ToString(),
|
||||
client.Permissions));
|
||||
client.Permissions,
|
||||
client.PermittedConsoleCommands));
|
||||
}
|
||||
|
||||
var msg = server.CreateMessage();
|
||||
msg.Write((byte)ServerPacketHeader.PERMISSIONS);
|
||||
msg.Write((byte)client.Permissions);
|
||||
WritePermissions(msg, client);
|
||||
|
||||
server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered);
|
||||
|
||||
SaveClientPermissions();
|
||||
}
|
||||
|
||||
private void WritePermissions(NetBuffer msg, Client client)
|
||||
{
|
||||
msg.Write((byte)client.Permissions);
|
||||
if (client.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
msg.Write((UInt16)client.PermittedConsoleCommands.Sum(c => c.names.Length));
|
||||
foreach (DebugConsole.Command command in client.PermittedConsoleCommands)
|
||||
{
|
||||
foreach (string commandName in command.names)
|
||||
{
|
||||
msg.Write(commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetClientCharacter(Client client, Character newCharacter)
|
||||
{
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
|
||||
return;
|
||||
}
|
||||
Client nameTaken = ConnectedClients.Find(c => c.Name.ToLower() == clName.ToLower());
|
||||
Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));
|
||||
if (nameTaken != null)
|
||||
{
|
||||
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||
@@ -218,11 +218,11 @@ namespace Barotrauma.Networking
|
||||
var savedPermissions = clientPermissions.Find(cp => cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());
|
||||
if (savedPermissions != null)
|
||||
{
|
||||
newClient.SetPermissions(savedPermissions.Permissions);
|
||||
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
|
||||
}
|
||||
else
|
||||
{
|
||||
newClient.SetPermissions(ClientPermissions.None);
|
||||
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,20 +25,23 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public readonly string IP;
|
||||
public readonly string Name;
|
||||
public List<DebugConsole.Command> PermittedCommands;
|
||||
|
||||
public ClientPermissions Permissions;
|
||||
|
||||
public SavedClientPermission(string name, string ip, ClientPermissions permissions)
|
||||
public SavedClientPermission(string name, string ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
||||
{
|
||||
this.Name = name;
|
||||
this.IP = ip;
|
||||
|
||||
this.Permissions = permissions;
|
||||
this.PermittedCommands = permittedCommands;
|
||||
}
|
||||
}
|
||||
|
||||
public const string SettingsFile = "serversettings.xml";
|
||||
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.txt";
|
||||
public static readonly string PermissionPresetFile = "Data" + Path.DirectorySeparatorChar + "permissionpresets.xml";
|
||||
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
@@ -130,6 +133,13 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowRagdollButton
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowFileTransfers
|
||||
{
|
||||
@@ -210,6 +220,20 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool TraitorUseRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(0.2f, true)]
|
||||
public float TraitorRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(false,true)]
|
||||
public bool KarmaEnabled
|
||||
{
|
||||
@@ -323,12 +347,67 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void LoadClientPermissions()
|
||||
{
|
||||
if (!File.Exists(ClientPermissionsFile)) return;
|
||||
|
||||
clientPermissions.Clear();
|
||||
|
||||
if (File.Exists("Data/clientpermissions.txt") && !File.Exists(ClientPermissionsFile))
|
||||
{
|
||||
LoadClientPermissionsOld("Data/clientpermissions.txt");
|
||||
return;
|
||||
}
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(ClientPermissionsFile);
|
||||
foreach (XElement clientElement in doc.Root.Elements())
|
||||
{
|
||||
string clientName = clientElement.GetAttributeString("name", "");
|
||||
string clientIP = clientElement.GetAttributeString("ip", "");
|
||||
if (string.IsNullOrWhiteSpace(clientName) || string.IsNullOrWhiteSpace(clientIP))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
|
||||
continue;
|
||||
}
|
||||
|
||||
string permissionsStr = clientElement.GetAttributeString("permissions", "");
|
||||
ClientPermissions permissions;
|
||||
if (!Enum.TryParse(permissionsStr, out permissions))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
|
||||
continue;
|
||||
}
|
||||
|
||||
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
|
||||
if (permissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (XElement commandElement in clientElement.Elements())
|
||||
{
|
||||
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
|
||||
|
||||
string commandName = commandElement.GetAttributeString("name", "");
|
||||
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
|
||||
if (command == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
|
||||
continue;
|
||||
}
|
||||
|
||||
permittedCommands.Add(command);
|
||||
}
|
||||
}
|
||||
|
||||
clientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method for loading old .txt client permission files to provide backwards compatibility
|
||||
/// </summary>
|
||||
private void LoadClientPermissionsOld(string file)
|
||||
{
|
||||
if (!File.Exists(file)) return;
|
||||
|
||||
string[] lines;
|
||||
try
|
||||
{
|
||||
lines = File.ReadAllLines(ClientPermissionsFile);
|
||||
lines = File.ReadAllLines(file);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -337,36 +416,63 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
clientPermissions.Clear();
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string[] separatedLine = line.Split('|');
|
||||
if (separatedLine.Length < 3) continue;
|
||||
|
||||
string name = String.Join("|", separatedLine.Take(separatedLine.Length - 2));
|
||||
string name = string.Join("|", separatedLine.Take(separatedLine.Length - 2));
|
||||
string ip = separatedLine[separatedLine.Length - 2];
|
||||
|
||||
ClientPermissions permissions = ClientPermissions.None;
|
||||
if (Enum.TryParse<ClientPermissions>(separatedLine.Last(), out permissions))
|
||||
if (Enum.TryParse(separatedLine.Last(), out permissions))
|
||||
{
|
||||
clientPermissions.Add(new SavedClientPermission(name, ip, permissions));
|
||||
clientPermissions.Add(new SavedClientPermission(name, ip, permissions, new List<DebugConsole.Command>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveClientPermissions()
|
||||
{
|
||||
GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
|
||||
//delete old client permission file
|
||||
if (File.Exists("Data/clientpermissions.txt"))
|
||||
{
|
||||
File.Delete("Data/clientpermissions.txt");
|
||||
}
|
||||
|
||||
List<string> lines = new List<string>();
|
||||
Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
|
||||
|
||||
XDocument doc = new XDocument(new XElement("ClientPermissions"));
|
||||
|
||||
foreach (SavedClientPermission clientPermission in clientPermissions)
|
||||
{
|
||||
lines.Add(clientPermission.Name + "|" + clientPermission.IP+"|"+clientPermission.Permissions.ToString());
|
||||
XElement clientElement = new XElement("Client",
|
||||
new XAttribute("name", clientPermission.Name),
|
||||
new XAttribute("ip", clientPermission.IP),
|
||||
new XAttribute("permissions", clientPermission.Permissions.ToString()));
|
||||
|
||||
if (clientPermission.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
|
||||
{
|
||||
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
|
||||
}
|
||||
}
|
||||
|
||||
doc.Root.Add(clientElement);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllLines(ClientPermissionsFile, lines);
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
settings.NewLineOnAttributes = true;
|
||||
|
||||
using (var writer = XmlWriter.Create(ClientPermissionsFile, settings))
|
||||
{
|
||||
doc.Save(writer);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -28,18 +28,20 @@ namespace Barotrauma.Networking
|
||||
Attack,
|
||||
Spawning,
|
||||
ServerMessage,
|
||||
ConsoleUsage,
|
||||
Error
|
||||
}
|
||||
|
||||
private readonly Color[] messageColor =
|
||||
{
|
||||
Color.LightBlue,
|
||||
new Color(255, 142, 0),
|
||||
new Color(238, 208, 0),
|
||||
new Color(204, 74, 78),
|
||||
new Color(163, 73, 164),
|
||||
new Color(157, 225, 160),
|
||||
Color.Red
|
||||
Color.LightBlue, //Chat
|
||||
new Color(255, 142, 0), //ItemInteraction
|
||||
new Color(238, 208, 0), //Inventory
|
||||
new Color(204, 74, 78), //Attack
|
||||
new Color(163, 73, 164), //Spawning
|
||||
new Color(157, 225, 160), //ServerMessage
|
||||
new Color(0, 162, 232), //ConsoleUsage
|
||||
Color.Red //Error
|
||||
};
|
||||
|
||||
private readonly string[] messageTypeName =
|
||||
@@ -50,6 +52,7 @@ namespace Barotrauma.Networking
|
||||
"Attack & death",
|
||||
"Spawning",
|
||||
"Server message",
|
||||
"Console usage",
|
||||
"Error"
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user