v1.13.3.1 (Summer Update 2026)

This commit is contained in:
Regalis11
2026-06-16 15:35:36 +03:00
parent 81f57ea3e7
commit 1cd0178e0a
73 changed files with 1165 additions and 406 deletions
@@ -251,7 +251,7 @@ namespace Barotrauma
GameMain.NetworkMember.ShowNetStats = !GameMain.NetworkMember.ShowNetStats;
}));
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename/jobname] [near/inside/outside/cursor] [team] [add to crew (true/false)]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine). You can also enter the name of a job (e.g. \"Mechanic\") to spawn a character with a specific job and the appropriate equipment.", null,
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename/jobname] [near/inside/outside/cursor] [team] [add to crew (true/false)] [name]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine). You can also enter the name of a job (e.g. \"Mechanic\") to spawn a character with a specific job and the appropriate equipment.", null,
() =>
{
string[] creatureAndJobNames =
@@ -270,7 +270,7 @@ namespace Barotrauma
};
}, isCheat: true));
commands.Add(new Command("give|giveitem", "give|giveitem [itemname/itemidentifier] [amount] [condition]: Spawn an item in the inventory of the controlled character",
commands.Add(new Command("give|giveitem", "give|giveitem [itemname/itemidentifier] [amount] [condition] [quality]: Spawn an item in the inventory of the controlled character",
(string[] args) =>
{
if (Character.Controlled == null)
@@ -291,9 +291,12 @@ namespace Barotrauma
},
getValidArgs: () =>
{
return new string[][]
return new string[][]
{
GetItemNameOrIdParams().ToArray()
GetItemNameOrIdParams().ToArray(),
new string[] { "1" },
new string[] { "100" },
ItemQualityNames.ToArray()
};
}, isCheat: true));
@@ -310,7 +313,7 @@ namespace Barotrauma
};
}, isCheat: true));
commands.Add(new Command("spawnitem", "spawnitem [itemname/itemidentifier] [cursor/inventory/cargo/random/[name]] [amount] [condition]: Spawn an item at the position of the cursor, in the inventory of the controlled character, in the inventory of the client with the given name, or at a random spawnpoint if the location parameter is omitted or \"random\".",
commands.Add(new Command("spawnitem", "spawnitem [itemname/itemidentifier] [cursor/inventory/cargo/random/[name]] [amount] [condition] [quality]: Spawn an item at the position of the cursor, in the inventory of the controlled character, in the inventory of the client with the given name, or at a random spawnpoint if the location parameter is omitted or \"random\".",
(string[] args) =>
{
TrySpawnItem(args);
@@ -320,7 +323,10 @@ namespace Barotrauma
return new string[][]
{
GetItemNameOrIdParams().ToArray(),
GetSpawnPosParams().ToArray()
GetSpawnPosParams().ToArray(),
new string[] { "1" },
new string[] { "100" },
ItemQualityNames.ToArray()
};
}, isCheat: true));
@@ -1323,6 +1329,7 @@ namespace Barotrauma
}
else
{
if (GameMain.GameSession?.Map is Map map) { NewMessage("Map seed: " + map.Seed); }
NewMessage("Level seed: " + Level.Loaded.Seed);
NewMessage("Level generation params: " + Level.Loaded.GenerationParams.Identifier);
NewMessage("Adjacent locations: " + (Level.Loaded.StartLocation?.Type.Identifier ?? "none".ToIdentifier()) + ", " + (Level.Loaded.StartLocation?.Type.Identifier ?? "none".ToIdentifier()));
@@ -1332,17 +1339,29 @@ namespace Barotrauma
}
},null));
commands.Add(new Command("teleportsub", "teleportsub [start/end/endoutpost/cursor]: Teleport the submarine to the position of the cursor, or the start or end of the level. The 'endoutpost' argument also automatically docks the sub with the outpost at the end of the level. WARNING: does not take outposts into account, so often leads to physics glitches. Only use for debugging.",
commands.Add(new Command("teleportsub", "teleportsub [start/end/endoutpost/cursor] [submarine_team]: Teleport the submarine to the position of the cursor, or the start or end of the level. The 'endoutpost' argument also automatically docks the sub with the outpost at the end of the level. WARNING: does not take outposts into account, so often leads to physics glitches. Only use for debugging.",
onExecute:(string[] args) =>
{
if (Submarine.MainSub == null) { return; }
Submarine submarineToTeleport = Submarine.MainSub;
if (args.Length > 1)
{
foreach (Submarine sub in Submarine.Loaded.Where(s => s.PhysicsBody.BodyType == FarseerPhysics.BodyType.Dynamic))
{
if ((sub.Info.Name + "_" + sub.TeamID) == args[1])
{
submarineToTeleport = sub;
break;
}
}
}
if (args.Length == 0 || args[0].Equals("cursor", StringComparison.OrdinalIgnoreCase))
{
#if SERVER
ThrowError("Cannot teleport the sub to the position of the cursor. Use \"start\" or \"end\", or execute the command as a client.");
#else
Submarine.MainSub.SetPosition(Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition));
submarineToTeleport.SetPosition(Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition));
#endif
}
else if (args[0].Equals("start", StringComparison.OrdinalIgnoreCase))
@@ -1355,9 +1374,9 @@ namespace Barotrauma
Vector2 pos = Level.Loaded.StartPosition;
if (Level.Loaded.StartOutpost != null)
{
pos -= Vector2.UnitY * (Submarine.MainSub.Borders.Height + Level.Loaded.StartOutpost.Borders.Height) / 2;
pos -= Vector2.UnitY * (submarineToTeleport.Borders.Height + Level.Loaded.StartOutpost.Borders.Height) / 2;
}
Submarine.MainSub.SetPosition(pos);
submarineToTeleport.SetPosition(pos);
}
else if (args[0].Equals("end", StringComparison.OrdinalIgnoreCase))
{
@@ -1369,9 +1388,9 @@ namespace Barotrauma
Vector2 pos = Level.Loaded.EndPosition;
if (Level.Loaded.EndOutpost != null)
{
pos -= Vector2.UnitY * (Submarine.MainSub.Borders.Height + Level.Loaded.EndOutpost.Borders.Height) / 2;
pos -= Vector2.UnitY * (submarineToTeleport.Borders.Height + Level.Loaded.EndOutpost.Borders.Height) / 2;
}
Submarine.MainSub.SetPosition(pos);
submarineToTeleport.SetPosition(pos);
}
else if (args[0].Equals("endoutpost", StringComparison.OrdinalIgnoreCase))
{
@@ -1380,8 +1399,8 @@ namespace Barotrauma
NewMessage("Can't teleport the sub to the end outpost (no outpost at the end of the level).", Color.Red);
return;
}
Submarine.MainSub.SetPosition(Level.Loaded.EndExitPosition - Vector2.UnitY * Submarine.MainSub.Borders.Height);
var submarineDockingPort = DockingPort.List.FirstOrDefault(d => d.Item.Submarine == Submarine.MainSub);
submarineToTeleport.SetPosition(Level.Loaded.EndExitPosition - Vector2.UnitY * submarineToTeleport.Borders.Height);
var submarineDockingPort = DockingPort.List.FirstOrDefault(d => d.Item.Submarine == submarineToTeleport);
var outpostDockingPort = DockingPort.List.FirstOrDefault(d => d.Item.Submarine == Level.Loaded.EndOutpost);
if (submarineDockingPort != null && outpostDockingPort != null)
{
@@ -1393,7 +1412,8 @@ namespace Barotrauma
{
return new string[][]
{
new string[] { "start", "end", "endoutpost", "cursor" }
new string[] { "start", "end", "endoutpost", "cursor" },
ListAvailableSubmarines()
};
}, isCheat: true));
@@ -2566,7 +2586,17 @@ namespace Barotrauma
return locationNames.ToArray();
}
private static string[] ListAvailableSubmarines()
{
List<string> submarineNames = new();
foreach (var submarine in Submarine.Loaded.Where(s => s.PhysicsBody.BodyType == FarseerPhysics.BodyType.Dynamic))
{
submarineNames.Add(submarine.Info.Name + "_" + submarine.TeamID);
}
return submarineNames.ToArray();
}
private static bool TryFindTeleportPosition(string locationName, out Vector2 teleportPosition)
{
if (Submarine.MainSub is Submarine mainSub && string.Equals(locationName, "mainsub", StringComparison.InvariantCultureIgnoreCase))
@@ -2949,7 +2979,7 @@ namespace Barotrauma
isHuman = job != null || characterLowerCase == CharacterPrefab.HumanSpeciesName;
}
ParseOptionalArgs(out Vector2 spawnPosition, out WayPoint spawnPoint, out CharacterTeamType? teamType, out bool addToCrew);
ParseOptionalArgs(out Vector2 spawnPosition, out WayPoint spawnPoint, out CharacterTeamType? teamType, out bool addToCrew, out string renameCharacter);
if (usePreConfiguredNPC)
{
@@ -2980,6 +3010,14 @@ namespace Barotrauma
CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: job, variant: variant);
Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, spawnPosition, characterInfo, onSpawn: newCharacter =>
{
if (renameCharacter != null)
{
if (renameCharacter.Length > 31)
{
renameCharacter = renameCharacter.Substring(0, 32);
}
newCharacter.Info.Name = renameCharacter;
}
SetTeamAndCrew(newCharacter);
newCharacter.GiveJobItems(isPvPMode: GameMain.GameSession?.GameMode is PvPMode, spawnPoint);
newCharacter.GiveIdCardTags(spawnPoint);
@@ -3007,7 +3045,7 @@ namespace Barotrauma
}
}
void ParseOptionalArgs(out Vector2 spawnPosition, out WayPoint spawnPoint, out CharacterTeamType? teamType, out bool addToCrew)
void ParseOptionalArgs(out Vector2 spawnPosition, out WayPoint spawnPoint, out CharacterTeamType? teamType, out bool addToCrew, out string renameCharacter)
{
spawnPosition = Vector2.Zero;
spawnPoint = null;
@@ -3093,6 +3131,12 @@ namespace Barotrauma
ThrowError($"Could not parse the \"add to crew\" argument ({args[argIndex]}). Defaulting to {addToCrew}.");
}
}
argIndex++;
renameCharacter = null;
if (args.Length > argIndex)
{
renameCharacter = args[argIndex];
}
}
}
@@ -3100,6 +3144,7 @@ namespace Barotrauma
{
yield return "cursor";
yield return "inventory";
yield return "cargo";
#if SERVER
if (GameMain.Server != null)
@@ -3140,6 +3185,8 @@ namespace Barotrauma
}
}
private static ImmutableArray<string> ItemQualityNames = ["normal", "good", "excellent", "masterwork"];
private static void TrySpawnItem(string[] args)
{
try
@@ -3200,7 +3247,8 @@ namespace Barotrauma
int amount = 1;
int conditionPrc = 100;
int itemQuality = 0;
if (TryGetSpawnPosParam(out string spawnLocation, out int spawnLocationIndex))
{
switch (spawnLocation)
@@ -3220,7 +3268,7 @@ namespace Barotrauma
break;
default:
var matchingCharacter = FindMatchingCharacter(args.Skip(1).Take(1).ToArray());
if (matchingCharacter != null){ spawnInventory = matchingCharacter.Inventory; }
if (matchingCharacter != null) { spawnInventory = matchingCharacter.Inventory; }
break;
}
@@ -3229,10 +3277,21 @@ namespace Barotrauma
if (!int.TryParse(args[spawnLocationIndex + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out amount)) { amount = 1; }
amount = Math.Min(amount, 100);
}
if (args.Length > spawnLocationIndex + 2)
{
if (!int.TryParse(args[^1], NumberStyles.Any, CultureInfo.InvariantCulture, out conditionPrc)) { conditionPrc = 100; }
if (!int.TryParse(args[spawnLocationIndex + 2], NumberStyles.Any, CultureInfo.InvariantCulture, out conditionPrc)) { conditionPrc = 100; }
}
if (args.Length > spawnLocationIndex + 3)
{
for (int i = 0; i <= Quality.MaxQuality; i++)
{
if (args[spawnLocationIndex + 3].ToLowerInvariant() == ItemQualityNames[i])
{
itemQuality = i;
}
}
}
}
@@ -3254,7 +3313,7 @@ namespace Barotrauma
}
else
{
Entity.Spawner?.AddItemToSpawnQueue(itemPrefab, spawnPos.Value, condition: itemCondition);
Entity.Spawner?.AddItemToSpawnQueue(itemPrefab, spawnPos.Value, condition: itemCondition, quality: itemQuality);
}
}
else if (spawnInventory != null)
@@ -3281,6 +3340,7 @@ namespace Barotrauma
}
item.Condition = item.Health * Math.Clamp(conditionPrc / 100f, 0f, 1f);
item.Quality = itemQuality;
}
}
}