Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into unstable

This commit is contained in:
EvilFactory
2022-09-29 12:13:55 -03:00
602 changed files with 19759 additions and 16312 deletions
@@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Networking;
namespace Barotrauma
{
@@ -158,11 +157,11 @@ namespace Barotrauma
/// </summary>
public readonly bool SpawnIfCantBeContained;
public readonly float Impulse;
public readonly float Rotation;
public readonly float RotationRad;
public readonly int Count;
public readonly float Spread;
public readonly SpawnRotationType RotationType;
public readonly float AimSpread;
public readonly float AimSpreadRad;
public readonly bool Equip;
public readonly float Condition;
@@ -198,14 +197,14 @@ namespace Barotrauma
SpawnIfInventoryFull = element.GetAttributeBool("spawnifinventoryfull", false);
SpawnIfCantBeContained = element.GetAttributeBool("spawnifcantbecontained", true);
Impulse = element.GetAttributeFloat("impulse", element.GetAttributeFloat("speed", 0.0f));
Impulse = element.GetAttributeFloat("impulse", element.GetAttributeFloat("launchimpulse", element.GetAttributeFloat("speed", 0.0f)));
Condition = MathHelper.Clamp(element.GetAttributeFloat("condition", 1.0f), 0.0f, 1.0f);
Rotation = element.GetAttributeFloat("rotation", 0.0f);
RotationRad = MathHelper.ToRadians(element.GetAttributeFloat("rotation", 0.0f));
Count = element.GetAttributeInt("count", 1);
Spread = element.GetAttributeFloat("spread", 0f);
AimSpread = element.GetAttributeFloat("aimspread", 0f);
AimSpreadRad = MathHelper.ToRadians(element.GetAttributeFloat("aimspread", 0f));
Equip = element.GetAttributeBool("equip", false);
string spawnTypeStr = element.GetAttributeString("spawnposition", "This");
@@ -213,7 +212,7 @@ namespace Barotrauma
{
DebugConsole.ThrowError("Error in StatusEffect config - \"" + spawnTypeStr + "\" is not a valid spawn position.");
}
string rotationTypeStr = element.GetAttributeString("rotationtype", Rotation != 0 ? "Fixed" : "Target");
string rotationTypeStr = element.GetAttributeString("rotationtype", RotationRad != 0 ? "Fixed" : "Target");
if (!Enum.TryParse(rotationTypeStr, ignoreCase: true, out RotationType))
{
DebugConsole.ThrowError("Error in StatusEffect config - \"" + rotationTypeStr + "\" is not a valid rotation type.");
@@ -264,12 +263,36 @@ namespace Barotrauma
public string Name => $"Character Spawn Info ({SpeciesName})";
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; set; }
[Serialize(false, IsPropertySaveable.No)]
public bool TransferBuffs { get; private set; }
[Serialize(false, IsPropertySaveable.No)]
public bool TransferAfflictions { get; private set; }
[Serialize(false, IsPropertySaveable.No)]
public bool TransferInventory { get; private set; }
[Serialize("", IsPropertySaveable.No)]
public Identifier SpeciesName { get; private set; }
[Serialize(1, IsPropertySaveable.No)]
public int Count { get; private set; }
[Serialize(0, IsPropertySaveable.No)]
public int Stun { get; private set; }
[Serialize("", IsPropertySaveable.No)]
public Identifier AfflictionOnSpawn { get; private set; }
[Serialize(1, IsPropertySaveable.No)]
public int AfflictionStrength { get; private set; }
[Serialize(false, IsPropertySaveable.No)]
public bool TransferControl { get; private set; }
[Serialize(false, IsPropertySaveable.No)]
public bool RemovePreviousCharacter { get; private set; }
[Serialize(0f, IsPropertySaveable.No)]
public float Spread { get; private set; }
@@ -1548,24 +1571,23 @@ namespace Barotrauma
{
Character targetCharacter = CharacterFromTarget(target);
if (targetCharacter?.Info == null) { continue; }
if (!TalentTree.JobTalentTrees.TryGet(targetCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { continue; }
// for the sake of technical simplicity, for now do not allow talents to be given if the character could unlock them in their talent tree as well
IEnumerable<Identifier> disallowedTalents = talentTree.TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier)));
if (!TalentTree.JobTalentTrees.TryGet(targetCharacter.Info.Job.Prefab.Identifier, out TalentTree characterTalentTree)) { continue; }
foreach (GiveTalentInfo giveTalentInfo in giveTalentInfos)
{
IEnumerable<Identifier> viableTalents = giveTalentInfo.TalentIdentifiers.Where(s => !targetCharacter.Info.UnlockedTalents.Contains(s) && !disallowedTalents.Contains(s));
if (viableTalents.None()) { continue; }
if (giveTalentInfo.GiveRandom)
{
{
// for the sake of technical simplicity, for now do not allow talents to be given if the character could unlock them in their talent tree as well
IEnumerable<Identifier> viableTalents = giveTalentInfo.TalentIdentifiers.Where(id => !targetCharacter.Info.UnlockedTalents.Contains(id) && !characterTalentTree.AllTalentIdentifiers.Contains(id));
if (viableTalents.None()) { continue; }
targetCharacter.GiveTalent(viableTalents.GetRandomUnsynced(), true);
}
else
{
foreach (Identifier talent in viableTalents)
foreach (Identifier id in giveTalentInfo.TalentIdentifiers)
{
targetCharacter.GiveTalent(talent, true);
if (targetCharacter.Info.UnlockedTalents.Contains(id) || characterTalentTree.AllTalentIdentifiers.Contains(id)) { continue; }
targetCharacter.GiveTalent(id, true);
}
}
}
@@ -1629,6 +1651,64 @@ namespace Barotrauma
{
SwarmBehavior.CreateSwarm(characters.Cast<AICharacter>());
}
if (!characterSpawnInfo.AfflictionOnSpawn.IsEmpty)
{
if (!AfflictionPrefab.Prefabs.TryGet(characterSpawnInfo.AfflictionOnSpawn, out AfflictionPrefab afflictionPrefab))
{
DebugConsole.NewMessage($"Could not apply an affliction to the spawned character(s). No affliction with the identifier \"{characterSpawnInfo.AfflictionOnSpawn}\" found.", Color.Red);
return;
}
newCharacter.CharacterHealth.ApplyAffliction(newCharacter.AnimController.MainLimb, afflictionPrefab.Instantiate(characterSpawnInfo.AfflictionStrength));
}
if (characterSpawnInfo.Stun > 0)
{
newCharacter.SetStun(characterSpawnInfo.Stun);
}
foreach (var target in targets)
{
if (!(target is Character character)) { continue; }
if (characterSpawnInfo.TransferInventory && character.Inventory != null && newCharacter.Inventory != null)
{
if (character.Inventory.Capacity != newCharacter.Inventory.Capacity) { return; }
for (int i = 0; i < character.Inventory.Capacity && i < newCharacter.Inventory.Capacity; i++)
{
character.Inventory.GetItemsAt(i).ForEachMod(item => newCharacter.Inventory.TryPutItem(item, i, allowSwapping: true, allowCombine: false, user: null));
}
}
if (characterSpawnInfo.TransferBuffs || characterSpawnInfo.TransferAfflictions)
{
foreach (Affliction affliction in character.CharacterHealth.GetAllAfflictions())
{
if (!characterSpawnInfo.TransferAfflictions && characterSpawnInfo.TransferBuffs && affliction.Prefab.IsBuff)
{
newCharacter.CharacterHealth.ApplyAffliction(newCharacter.AnimController.MainLimb, affliction.Prefab.Instantiate(affliction.Strength));
}
if (characterSpawnInfo.TransferAfflictions)
{
newCharacter.CharacterHealth.ApplyAffliction(newCharacter.AnimController.MainLimb, affliction.Prefab.Instantiate(affliction.Strength));
}
}
}
if (i == characterSpawnInfo.Count) // Only perform the below actions if this is the last character being spawned.
{
if (characterSpawnInfo.TransferControl)
{
#if CLIENT
if (Character.Controlled == target)
{
Character.Controlled = newCharacter;
}
#elif SERVER
/*foreach (Client c in GameMain.Server.ConnectedClients)
{
if (c.Character != target) { continue; }
GameMain.Server.SetClientCharacter(c, newCharacter);
}*/
#endif
}
if (characterSpawnInfo.RemovePreviousCharacter) { Entity.Spawner?.AddEntityToRemoveQueue(character); }
}
}
});
}
}
@@ -1656,92 +1736,101 @@ namespace Barotrauma
case ItemSpawnInfo.SpawnPositionType.This:
Entity.Spawner.AddItemToSpawnQueue(chosenItemSpawnInfo.ItemPrefab, position + Rand.Vector(chosenItemSpawnInfo.Spread, Rand.RandSync.Unsynced), onSpawned: newItem =>
{
Item parentItem = entity as Item;
Projectile projectile = newItem.GetComponent<Projectile>();
if (projectile != null && user != null && sourceBody != null && entity != null)
if (entity != null)
{
var rope = newItem.GetComponent<Rope>();
if (rope != null && sourceBody.UserData is Limb sourceLimb)
if (rope != null && sourceBody != null && sourceBody.UserData is Limb sourceLimb)
{
rope.Attach(sourceLimb, newItem);
#if SERVER
newItem.CreateServerEvent(rope);
#endif
}
float spread = MathHelper.ToRadians(Rand.Range(-chosenItemSpawnInfo.AimSpread, chosenItemSpawnInfo.AimSpread));
var worldPos = sourceBody.Position;
float rotation = 0;
if (user.Submarine != null)
float spread = Rand.Range(-chosenItemSpawnInfo.AimSpreadRad, chosenItemSpawnInfo.AimSpreadRad);
float rotation = chosenItemSpawnInfo.RotationRad;
Vector2 worldPos;
if (sourceBody != null)
{
worldPos += user.Submarine.Position;
worldPos = sourceBody.Position;
if (user?.Submarine != null)
{
worldPos += user.Submarine.Position;
}
}
else
{
worldPos = entity.WorldPosition;
}
switch (chosenItemSpawnInfo.RotationType)
{
case ItemSpawnInfo.SpawnRotationType.Fixed:
rotation = sourceBody.TransformRotation(chosenItemSpawnInfo.Rotation);
if (sourceBody != null)
{
rotation = sourceBody.TransformRotation(chosenItemSpawnInfo.RotationRad);
}
else if (parentItem?.body != null)
{
rotation = parentItem.body.TransformRotation(chosenItemSpawnInfo.RotationRad);
}
break;
case ItemSpawnInfo.SpawnRotationType.Target:
rotation = MathUtils.VectorToAngle(entity.WorldPosition - worldPos);
break;
case ItemSpawnInfo.SpawnRotationType.Limb:
rotation = sourceBody.TransformedRotation;
if (sourceBody != null)
{
rotation = sourceBody.TransformedRotation;
}
break;
case ItemSpawnInfo.SpawnRotationType.Collider:
rotation = user.AnimController.Collider.Rotation + MathHelper.PiOver2;
if (parentItem?.body != null)
{
rotation = parentItem.body.Rotation;
}
else if (user != null)
{
rotation = user.AnimController.Collider.Rotation + MathHelper.PiOver2;
}
break;
case ItemSpawnInfo.SpawnRotationType.MainLimb:
rotation = user.AnimController.MainLimb.body.TransformedRotation;
if (user != null)
{
rotation = user.AnimController.MainLimb.body.TransformedRotation;
}
break;
case ItemSpawnInfo.SpawnRotationType.Random:
DebugConsole.ShowError("Random rotation is not supported for Projectiles.");
if (projectile != null)
{
DebugConsole.LogError("Random rotation is not supported for Projectiles.");
}
else
{
rotation = Rand.Range(0f, MathHelper.TwoPi, Rand.RandSync.Unsynced);
}
break;
default:
throw new NotImplementedException("Projectile spawn rotation type not implemented: " + chosenItemSpawnInfo.RotationType);
throw new NotImplementedException("Item spawn rotation type not implemented: " + chosenItemSpawnInfo.RotationType);
}
rotation += MathHelper.ToRadians(chosenItemSpawnInfo.Rotation * user.AnimController.Dir);
projectile.Shoot(user, ConvertUnits.ToSimUnits(worldPos), ConvertUnits.ToSimUnits(worldPos), rotation + spread, ignoredBodies: user.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true);
}
else
{
var body = newItem.body;
if (body != null)
if (user != null)
{
float rotation = MathHelper.ToRadians(chosenItemSpawnInfo.Rotation);
switch (chosenItemSpawnInfo.RotationType)
{
case ItemSpawnInfo.SpawnRotationType.Fixed:
if (sourceBody != null)
{
rotation = sourceBody.TransformRotation(chosenItemSpawnInfo.Rotation);
}
break;
case ItemSpawnInfo.SpawnRotationType.Limb:
if (sourceBody != null)
{
rotation += sourceBody.Rotation;
}
break;
case ItemSpawnInfo.SpawnRotationType.Collider:
if (entity is Character character)
{
rotation += character.AnimController.Collider.Rotation + MathHelper.PiOver2;
}
break;
case ItemSpawnInfo.SpawnRotationType.MainLimb:
if (entity is Character c)
{
rotation = c.AnimController.MainLimb.body.TransformedRotation;
}
break;
case ItemSpawnInfo.SpawnRotationType.Random:
rotation = Rand.Range(0f, MathHelper.TwoPi, Rand.RandSync.Unsynced);
break;
case ItemSpawnInfo.SpawnRotationType.Target:
break;
default:
throw new NotImplementedException("Spawn rotation type not implemented: " + chosenItemSpawnInfo.RotationType);
}
body.SetTransform(newItem.SimPosition, rotation);
body.ApplyLinearImpulse(Rand.Vector(1) * chosenItemSpawnInfo.Impulse);
rotation += chosenItemSpawnInfo.RotationRad * user.AnimController.Dir;
}
rotation += spread;
if (projectile != null)
{
projectile.Shoot(user,
ConvertUnits.ToSimUnits(worldPos),
ConvertUnits.ToSimUnits(worldPos),
rotation,
ignoredBodies: user?.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true);
}
else if (newItem.body != null)
{
newItem.body.SetTransform(newItem.SimPosition, rotation);
Vector2 impulseDir = new Vector2(MathF.Cos(rotation), MathF.Sin(rotation));
newItem.body.ApplyLinearImpulse(impulseDir * chosenItemSpawnInfo.Impulse);
}
}
newItem.Condition = newItem.MaxCondition * chosenItemSpawnInfo.Condition;
@@ -1930,7 +2019,7 @@ namespace Barotrauma
{
continue;
}
element.Parent.ApplyToProperty(target, property, n, CoroutineManager.UnscaledDeltaTime);
element.Parent.ApplyToProperty(target, property, n, CoroutineManager.DeltaTime);
}
foreach (Affliction affliction in element.Parent.Afflictions)
@@ -2033,7 +2122,7 @@ namespace Barotrauma
if (!MathUtils.NearlyEqual(afflictionMultiplier, 1.0f))
{
return affliction.CreateMultiplied(afflictionMultiplier);
return affliction.CreateMultiplied(afflictionMultiplier, affliction.Probability);
}
return affliction;
}