Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -17,6 +17,8 @@ namespace Barotrauma
MainSub,
Outpost,
MainPath,
Cave,
AbyssCave,
Ruin,
Wreck,
BeaconStation,
@@ -38,6 +40,9 @@ namespace Barotrauma
[Serialize("", IsPropertySaveable.Yes, description: "Identifier of the item to spawn.")]
public Identifier ItemIdentifier { get; set; }
[Serialize("", IsPropertySaveable.Yes, description: "Tag of the item to spawn.")]
public Identifier ItemTag { get; set; }
[Serialize("", IsPropertySaveable.Yes, description: "The spawned entity will be assigned this tag. The tag can be used to refer to the entity by other actions of the event.")]
public Identifier TargetTag { get; set; }
@@ -67,6 +72,9 @@ namespace Barotrauma
[Serialize(1, IsPropertySaveable.Yes, description: "Number of entities to spawn.")]
public int Amount { get; set; }
[Serialize(true, IsPropertySaveable.Yes, description: "Should the item be spawned even if the target inventory is full (just spawning it at the position of the target)? Only valid if spawning an item in an inventory.")]
public bool SpawnIfInventoryFull { get; set; }
[Serialize(100.0f, IsPropertySaveable.Yes, description: "Random offset to add to the spawn position.")]
public float Offset { get; set; }
@@ -94,6 +102,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes, description: "If disabled, the action will choose a spawn position away from players' views if one is available.")]
public bool AllowInPlayerView { get; set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Should the event continue even if the entity failed to spawn for whatever reason?")]
public bool ContinueIfFailedToSpawn { get; set; }
private bool spawned;
private Entity spawnedEntity;
@@ -115,9 +126,9 @@ namespace Barotrauma
public override bool IsFinished(ref string goTo)
{
if (spawnedEntity != null)
if (spawnedEntity != null || ContinueIfFailedToSpawn)
{
return true;
return spawned;
}
else
{
@@ -157,7 +168,7 @@ namespace Barotrauma
logError: false);
}
humanPrefab ??= NPCSet.Get(NPCSetIdentifier, NPCIdentifier, logError: true);
humanPrefab ??= NPCSet.Get(NPCSetIdentifier, NPCIdentifier, logError: true, contentPackageToLogInError: ParentEvent.Prefab.ContentPackage);
if (humanPrefab != null)
{
@@ -176,7 +187,11 @@ namespace Barotrauma
{
if (newCharacter == null) { return; }
newCharacter.HumanPrefab = humanPrefab;
newCharacter.TeamID = TeamID;
//don't set the TeamID directly: we want to leave the character's original team untouched,
//so they can behave offensively (and otherwise act "normally") if we spawn them in a hostile team inside a sub/outpost that doesn't belong to that team
//process the team change immediately in case the character is killed or made unconscious by the event (in which case the team change would not be processed)
newCharacter.SetOriginalTeamAndChangeTeam(TeamID, processImmediately: true);
newCharacter.EnableDespawn = false;
humanPrefab.GiveItems(newCharacter, newCharacter.Submarine, spawnPos as WayPoint);
if (LootingIsStealing)
@@ -233,74 +248,82 @@ namespace Barotrauma
}
}
}
else if (!ItemIdentifier.IsEmpty)
else if (!ItemIdentifier.IsEmpty || !ItemTag.IsEmpty)
{
if (MapEntityPrefab.FindByIdentifier(ItemIdentifier) is not ItemPrefab itemPrefab)
ItemPrefab itemPrefab = null;
if (!ItemIdentifier.IsEmpty)
{
DebugConsole.ThrowError("Error in SpawnAction (item prefab \"" + ItemIdentifier + "\" not found)",
contentPackage: ParentEvent.Prefab.ContentPackage);
}
else
{
Inventory spawnInventory = null;
if (!TargetInventory.IsEmpty)
itemPrefab = MapEntityPrefab.FindByIdentifier(ItemIdentifier) as ItemPrefab;
if (itemPrefab == null)
{
var targets = ParentEvent.GetTargets(TargetInventory);
if (targets.Any())
{
var target = targets.First(t => t is Item || t is Character);
if (target is Character character)
{
spawnInventory = character.Inventory;
}
else if (target is Item item)
{
spawnInventory = item.OwnInventory;
}
}
DebugConsole.ThrowError($"Error in SpawnAction (item prefab \"{ItemIdentifier}\" not found)",
contentPackage: ParentEvent.Prefab.ContentPackage);
}
}
else if (!ItemTag.IsEmpty)
{
itemPrefab = ItemPrefab.Prefabs.Where(ip => ip.Tags.Contains(ItemTag)).GetRandom(Rand.RandSync.Unsynced);
}
if (spawnInventory == null)
Inventory spawnInventory = null;
if (!TargetInventory.IsEmpty)
{
var targets = ParentEvent.GetTargets(TargetInventory);
if (targets.Any())
{
var target = targets.First(t => t is Item || t is Character);
if (target is Character character)
{
DebugConsole.ThrowError($"Could not spawn \"{ItemIdentifier}\" in target inventory \"{TargetInventory}\" - matching target not found.",
contentPackage: ParentEvent.Prefab.ContentPackage);
spawnInventory = character.Inventory;
}
else if (target is Item item)
{
spawnInventory = item.OwnInventory;
}
}
if (spawnInventory == null)
{
ISpatialEntity spawnPos = GetSpawnPos();
if (spawnPos != null)
{
for (int i = 0; i < Amount; i++)
{
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, OffsetSpawnPos(spawnPos.WorldPosition, Rand.Range(0.0f, Offset)), onSpawned: onSpawned);
}
}
DebugConsole.ThrowError($"Could not spawn \"{ItemIdentifier}\" in target inventory \"{TargetInventory}\" - matching target not found.",
contentPackage: ParentEvent.Prefab.ContentPackage);
}
else
}
if (spawnInventory == null)
{
ISpatialEntity spawnPos = GetSpawnPos();
if (spawnPos != null)
{
for (int i = 0; i < Amount; i++)
{
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, spawnInventory, onSpawned: onSpawned);
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, OffsetSpawnPos(spawnPos.WorldPosition, Rand.Range(0.0f, Offset)), onSpawned: onSpawned);
}
}
void onSpawned(Item newItem)
{
if (newItem != null)
{
if (!TargetTag.IsEmpty)
{
ParentEvent.AddTarget(TargetTag, newItem);
}
if (IgnoreByAI)
{
newItem.AddTag("ignorebyai");
}
}
spawnedEntity = newItem;
}
}
else
{
for (int i = 0; i < Amount; i++)
{
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, spawnInventory, spawnIfInventoryFull: SpawnIfInventoryFull, onSpawned: onSpawned);
}
}
void onSpawned(Item newItem)
{
if (newItem != null)
{
if (!TargetTag.IsEmpty)
{
ParentEvent.AddTarget(TargetTag, newItem);
}
if (IgnoreByAI)
{
newItem.AddTag("ignorebyai");
}
}
spawnedEntity = newItem;
}
}
spawned = true;
@@ -353,8 +376,7 @@ namespace Barotrauma
{
SpawnLocationType.Any => true,
SpawnLocationType.MainSub => submarine == Submarine.MainSub,
SpawnLocationType.NearMainSub => submarine == null,
SpawnLocationType.MainPath => submarine == null,
SpawnLocationType.NearMainSub or SpawnLocationType.MainPath or SpawnLocationType.Cave or SpawnLocationType.AbyssCave => submarine == null,
SpawnLocationType.Outpost => submarine is { Info.IsOutpost: true },
SpawnLocationType.Wreck => submarine is { Info.IsWreck: true },
SpawnLocationType.Ruin => submarine is { Info.IsRuin: true },
@@ -443,10 +465,25 @@ namespace Barotrauma
return potentialSpawnPoints.GetRandomUnsynced();
}
if (spawnLocation == SpawnLocationType.MainPath || spawnLocation == SpawnLocationType.NearMainSub)
switch (spawnLocation)
{
validSpawnPoints = validSpawnPoints.Where(p =>
Submarine.Loaded.None(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(p.WorldPosition)));
case SpawnLocationType.MainPath:
case SpawnLocationType.NearMainSub:
validSpawnPoints = validSpawnPoints.Where(p =>
Submarine.Loaded.None(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(p.WorldPosition)));
if (Level.Loaded != null)
{
validSpawnPoints = validSpawnPoints.Where(p =>
p.WorldPosition.Y > Level.Loaded.AbyssStart &&
p.Cave == null && p.Ruin == null);
}
break;
case SpawnLocationType.Cave:
validSpawnPoints = validSpawnPoints.Where(p => p.WorldPosition.Y > Level.Loaded.AbyssStart && p.Cave != null);
break;
case SpawnLocationType.AbyssCave:
validSpawnPoints = validSpawnPoints.Where(p => p.WorldPosition.Y < Level.Loaded.AbyssStart && p.Cave != null);
break;
}
//avoid using waypoints if there's any actual spawnpoints available