2ad9b5d...2f107db
commit 2f107db0475bf4b9a8b6f405b9ce8ec489cbc0ba Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 16:30:24 2019 +0200 Another nullref fix to the OpenHealthWindow property setter. Closes #1090 commit 1d15d18d2501bedaa1b42ac8e0e7e09e2600960e Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 16:19:05 2019 +0200 Fixed crashing when an incompatible content package is selected in config.xml or if the content package cannot be found. Happened because the game attempted to use TextManager.Get before text files had been loaded. Partially fixes #1093 commit 9ec1980fe90bcae65333c188b265ba16a6db6c05 Author: ezjamsen <ezjames.fi@gmail.com> Date: Thu Feb 7 16:16:53 2019 +0200 added correct effects for alien blood commit b6d2c56910b5d58477703abc6785ef80719a89a6 Author: ezjamsen <ezjames.fi@gmail.com> Date: Thu Feb 7 15:41:25 2019 +0200 adjustments to fent, glue and antibiotics commit 8df16acdaac0a521fe09fb62c6815a46a87f6f25 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 15:30:51 2019 +0200 More descriptive ping exception error messages (only shown in debug builds now), some extra checks to prevent using the workshop without steam (although the checks that actually matter are implemented at Steam's side now) commit 959c503c140196287ab60ec2357feb8bd5c85b18 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 14:00:48 2019 +0200 Don't allow severing the joint between a moloch's shell and the "bladder" commit 0c0b033016c2e82b8cf1b5a4e3f6faa9cde39f40 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 13:51:58 2019 +0200 Fixed incorrect item panel positioning in the crew command interface when the sub is docked to something. Closes #1082 commit 68366a4bf3c73b70288f043199d3ab9b2f5f4d06 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 13:23:38 2019 +0200 Fixed outdated damage modifiers in security and clown gear (used damage types instead of afflictions), not defining any affliction types for a damage modifier makes it affect all types of damage. Closes #1088 commit 5d3ab5084b8bc5357bc4a53993ad8dfcc44d0412 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 13:04:55 2019 +0200 Fixed client-side nullref exception if the round ends while the health window is open. Closes #1090 commit 8249d789a60dfe4bcdd1705d26d6ca36ed407058 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Thu Feb 7 12:48:34 2019 +0200 The dedicated server doesn't initialize a Steam client (not required to use any of the Steam server functionality). Fixes players being unable to log in as a client when they're hosting a dedicated server on another machine. TODO: SteamCMD support commit 55fb0bb1ba4bb8385dabbf6e40d4651bf86294a9 Author: ezjamsen <ezjames.fi@gmail.com> Date: Thu Feb 7 12:31:46 2019 +0200 Added linked hulls commit 937d50dca50d8c889a7c11b55765c208d2d16b67 Merge: 8109ae1a3 57731761f Author: EdusFF <pitkanen.eetu@gmail.com> Date: Thu Feb 7 12:16:43 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 8109ae1a3377910ff9bf066ccac582d879dfb0a4 Author: EdusFF <pitkanen.eetu@gmail.com> Date: Thu Feb 7 12:16:37 2019 +0200 Fixed: AI not reloading coilgun if an empty box of ammunition is inserted. commit 57731761f64bb33a4f4e7baa38367cfb7cf1f873 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Thu Feb 7 12:10:59 2019 +0200 Refactor character head customization logic and store the data in a dedicated class. In the net lobby, generate new head when the user presses the right arrow button. Pressing the left arrow will restore the previous head. When the user presses the right arrow after the left arrow, the first head is restored again. So it's effectively (and technically) undo/redo logic. commit 37577931e2706ce432cee2d48cd55990bc2bab4a Author: itchyOwl <lauri.harkanen@gmail.com> Date: Thu Feb 7 12:04:49 2019 +0200 Add properties for getting the count of the undo and redo stacks. commit f226beb05a55749ac961e3a33ac594fdf903fc3b Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Wed Feb 6 21:15:56 2019 +0200 Fixes to hull linking & displaying them as one hull on the minimap: - Links between hulls are now saved. - Simplified grouping logic (just store a list of linked hulls in hulldata). - Fixed water/oxygen calculations (use the average of the values instead of their sum). TODO: DRY (there's now duplicate linking logic in Item and Hull), merge the hull sprites on the minimap, maybe automatize the linking? commit 5dfea1fbb24c5bd91605caf65baaac9aca9cfbbf Merge: 2ad9b5de4 d06a1557f Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Wed Feb 6 20:18:31 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit d06a1557ffb85cd32bbb884fadef60b6d9dd27cf Author: Alex <olimpickusa6@gmail.com> Date: Wed Feb 6 18:26:40 2019 +0200 Test for connecting hulls task
This commit is contained in:
@@ -95,15 +95,18 @@ namespace Barotrauma
|
||||
if (openHealthWindow == value) return;
|
||||
if (value != null && !value.UseHealthWindow) return;
|
||||
|
||||
openHealthWindow = value;
|
||||
toggledThisFrame = true;
|
||||
if (Character.Controlled == null) { return; }
|
||||
|
||||
if (value == null &&
|
||||
Character.Controlled?.SelectedCharacter?.CharacterHealth == openHealthWindow &&
|
||||
Character.Controlled?.SelectedCharacter?.CharacterHealth != null &&
|
||||
Character.Controlled.SelectedCharacter.CharacterHealth == openHealthWindow &&
|
||||
!Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
|
||||
{
|
||||
Character.Controlled.DeselectCharacter();
|
||||
}
|
||||
|
||||
openHealthWindow = value;
|
||||
toggledThisFrame = true;
|
||||
Character.Controlled.ResetInteract = true;
|
||||
if (openHealthWindow != null)
|
||||
{
|
||||
|
||||
@@ -157,10 +157,10 @@ namespace Barotrauma
|
||||
float scale = targetWidth * 0.9f / Portrait.size.X;
|
||||
Vector2 offset = Portrait.size * backgroundScale / 4;
|
||||
Portrait.Draw(spriteBatch, screenPos + offset, scale: scale, spriteEffect: SpriteEffects.FlipHorizontally);
|
||||
if (AttachmentsSprites != null)
|
||||
if (AttachmentSprites != null)
|
||||
{
|
||||
float depthStep = 0.000001f;
|
||||
foreach (var attachment in AttachmentsSprites)
|
||||
foreach (var attachment in AttachmentSprites)
|
||||
{
|
||||
DrawAttachmentSprite(spriteBatch, attachment, Portrait, screenPos + offset, scale, depthStep, SpriteEffects.FlipHorizontally);
|
||||
depthStep += depthStep;
|
||||
@@ -175,10 +175,10 @@ namespace Barotrauma
|
||||
{
|
||||
float scale = Math.Min(targetAreaSize.X / HeadSprite.size.X, targetAreaSize.Y / HeadSprite.size.Y);
|
||||
HeadSprite.Draw(spriteBatch, screenPos, scale: scale);
|
||||
if (AttachmentsSprites != null)
|
||||
if (AttachmentSprites != null)
|
||||
{
|
||||
float depthStep = 0.000001f;
|
||||
foreach (var attachment in AttachmentsSprites)
|
||||
foreach (var attachment in AttachmentSprites)
|
||||
{
|
||||
DrawAttachmentSprite(spriteBatch, attachment, HeadSprite, screenPos, scale, depthStep);
|
||||
depthStep += depthStep;
|
||||
@@ -189,7 +189,7 @@ namespace Barotrauma
|
||||
|
||||
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||
{
|
||||
var list = AttachmentsSprites.ToList();
|
||||
var list = AttachmentSprites.ToList();
|
||||
if (attachment.InheritSourceRect)
|
||||
{
|
||||
if (attachment.SheetIndex.HasValue)
|
||||
|
||||
@@ -177,9 +177,7 @@ namespace Barotrauma
|
||||
Config.WasGameUpdated = false;
|
||||
Config.Save();
|
||||
}
|
||||
|
||||
TextManager.LoadTextPacks();
|
||||
|
||||
|
||||
ApplyGraphicsSettings();
|
||||
|
||||
Content.RootDirectory = "Content";
|
||||
|
||||
@@ -800,6 +800,12 @@ namespace Barotrauma
|
||||
style: "InnerFrame");
|
||||
optionFrames.Add(optionFrame);
|
||||
|
||||
new GUIFrame(new RectTransform(Vector2.One, optionFrame.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow")
|
||||
{
|
||||
Color = Color.Black * 0.7f
|
||||
};
|
||||
|
||||
var optionContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f), optionFrame.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
@@ -868,7 +874,9 @@ namespace Barotrauma
|
||||
}
|
||||
int shadowSize = (int)(200 * GUI.Scale);
|
||||
orderTargetFrameShadow = new GUIFrame(new RectTransform(orderTargetFrame.Rect.Size + new Point(shadowSize * 2), GUI.Canvas)
|
||||
{ AbsoluteOffset = orderTargetFrame.Rect.Location - new Point(shadowSize) }, style: "OuterGlow", color: Color.Black * 0.65f);
|
||||
{ AbsoluteOffset = orderTargetFrame.Rect.Location - new Point(shadowSize) },
|
||||
style: "OuterGlow",
|
||||
color: matchingItems.Count > 1 ? Color.Black * 0.9f : Color.Black * 0.7f);
|
||||
}
|
||||
|
||||
private void DrawMiniMapOverlay(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
|
||||
@@ -306,13 +306,13 @@ namespace Barotrauma.Items.Components
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), text,
|
||||
textColor: inadequateSkills.Any() ? Color.Red : Color.LightGreen, font: GUI.SmallFont);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SelectItem(Character user, FabricableItem selectedItem)
|
||||
{
|
||||
selectedItemFrame.ClearChildren();
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f, Stretch = true };
|
||||
if (tooltip != null)
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
|
||||
tooltip = null;
|
||||
}
|
||||
}
|
||||
|
||||
float degreeOfSuccess = user == null ? 0.0f : DegreeOfSuccess(user, selectedItem.RequiredSkills);
|
||||
if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; }
|
||||
|
||||
@@ -98,14 +98,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
{
|
||||
Hull mouseOnHull = null;
|
||||
hullInfoFrame.Visible = false;
|
||||
if (item.Submarine == null || !hasPower)
|
||||
{
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
var hullFrame = submarineContainer.Children.First().FindChild(hull);
|
||||
if (hullFrame == null) continue;
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
var hullFrame = submarineContainer.Children.First().FindChild(hull);
|
||||
if (hullFrame == null) { continue; }
|
||||
|
||||
if (GUI.MouseOn == hullFrame || hullFrame.IsParentOf(GUI.MouseOn))
|
||||
{
|
||||
mouseOnHull = hull;
|
||||
}
|
||||
if (item.Submarine == null || !hasPower)
|
||||
{
|
||||
hullFrame.Color = Color.DarkCyan * 0.3f;
|
||||
hullFrame.Children.First().Color = Color.DarkCyan * 0.3f;
|
||||
}
|
||||
@@ -123,6 +129,7 @@ namespace Barotrauma.Items.Components
|
||||
if (hullData == null)
|
||||
{
|
||||
hullData = new HullData();
|
||||
GetLinkedHulls(hull, hullData.LinkedHulls);
|
||||
hullDatas.Add(hull, hullData);
|
||||
}
|
||||
|
||||
@@ -171,13 +178,33 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.MouseOn == hullFrame || hullFrame.IsParentOf(GUI.MouseOn))
|
||||
if (mouseOnHull == hull ||
|
||||
hullData.LinkedHulls.Contains(mouseOnHull))
|
||||
{
|
||||
hullInfoFrame.RectTransform.ScreenSpaceOffset = hullFrame.Rect.Center;
|
||||
borderColor = Color.Lerp(borderColor, Color.White, 0.5f);
|
||||
hullFrame.Children.First().Color = Color.White;
|
||||
hullFrame.Color = borderColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
hullFrame.Children.First().Color = Color.DarkCyan * 0.8f;
|
||||
}
|
||||
|
||||
if (mouseOnHull == hull)
|
||||
{
|
||||
hullInfoFrame.RectTransform.ScreenSpaceOffset = hullFrame.Rect.Center;
|
||||
hullInfoFrame.Visible = true;
|
||||
hullNameText.Text = hull.RoomName;
|
||||
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
gapOpenSum += linkedHull.ConnectedGaps.Where(g => !g.IsRoomToRoom).Sum(g => g.Open);
|
||||
oxygenAmount += linkedHull.OxygenPercentage;
|
||||
waterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
|
||||
}
|
||||
oxygenAmount /= (hullData.LinkedHulls.Count + 1);
|
||||
waterAmount /= (hullData.LinkedHulls.Count + 1);
|
||||
|
||||
hullBreachText.Text = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : "";
|
||||
hullBreachText.TextColor = Color.Red;
|
||||
|
||||
@@ -186,17 +213,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
hullWaterText.Text = waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.Get("MiniMapWaterLevel") + ": " + (int)(waterAmount * 100.0f) + " %";
|
||||
hullWaterText.TextColor = waterAmount == null ? Color.Red : Color.Lerp(Color.LightGreen, Color.Red, (float)waterAmount);
|
||||
|
||||
borderColor = Color.Lerp(borderColor, Color.White, 0.5f);
|
||||
hullFrame.Children.First().Color = Color.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
hullFrame.Children.First().Color = Color.DarkCyan * 0.8f;
|
||||
}
|
||||
|
||||
hullFrame.Color = borderColor;
|
||||
}
|
||||
|
||||
|
||||
foreach (Submarine sub in subs)
|
||||
{
|
||||
if (sub.HullVertices == null) { continue; }
|
||||
@@ -222,5 +243,18 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetLinkedHulls(Hull hull, List<Hull> linkedHulls)
|
||||
{
|
||||
foreach (var linkedEntity in hull.linkedTo)
|
||||
{
|
||||
if (linkedEntity is Hull linkedHull)
|
||||
{
|
||||
if (linkedHulls.Contains(linkedHull)) { continue; }
|
||||
linkedHulls.Add(linkedHull);
|
||||
GetLinkedHulls(linkedHull, linkedHulls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
|
||||
if (entity.Linkable && entity.linkedTo != null) entity.linkedTo.Add(this);
|
||||
if (entity.Linkable && entity.linkedTo != null)
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -103,8 +106,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this)) entity.linkedTo.Remove(this);
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this))
|
||||
{
|
||||
entity.linkedTo.Remove(this);
|
||||
linkedTo.Remove(entity);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,6 +256,33 @@ namespace Barotrauma
|
||||
new Vector2(rect.Width - 10, rect.Height - 10),
|
||||
isHighlighted ? Color.LightBlue * 0.5f : Color.Red * 0.5f, true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
|
||||
}
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
if (e is Hull)
|
||||
{
|
||||
Hull linkedHull = (Hull)e;
|
||||
Rectangle connectedHullRect = e.Submarine == null ?
|
||||
linkedHull.rect :
|
||||
new Rectangle(
|
||||
(int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X),
|
||||
(int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y),
|
||||
linkedHull.WorldRect.Width, linkedHull.WorldRect.Height);
|
||||
|
||||
//center of the hull
|
||||
Rectangle currentHullRect = Submarine == null ?
|
||||
WorldRect :
|
||||
new Rectangle(
|
||||
(int)(Submarine.DrawPosition.X + WorldPosition.X),
|
||||
(int)(Submarine.DrawPosition.Y + WorldPosition.Y),
|
||||
WorldRect.Width, WorldRect.Height);
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(currentHullRect.X, -currentHullRect.Y),
|
||||
new Vector2(connectedHullRect.X, -connectedHullRect.Y),
|
||||
Color.Green, width: 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, WaterRenderer renderer)
|
||||
|
||||
@@ -284,8 +284,8 @@ namespace Barotrauma
|
||||
foreach (Entity entity in pointsOfInterest)
|
||||
{
|
||||
Vector2 relativePos = new Vector2(
|
||||
(entity.WorldPosition.X - worldBorders.X) / Borders.Width,
|
||||
(worldBorders.Y - entity.WorldPosition.Y) / Borders.Height);
|
||||
(entity.WorldPosition.X - worldBorders.X) / worldBorders.Width,
|
||||
(worldBorders.Y - entity.WorldPosition.Y) / worldBorders.Height);
|
||||
new GUIFrame(new RectTransform(new Point(1, 1), hullContainer.RectTransform) { RelativeOffset = relativePos }, style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
|
||||
@@ -1191,6 +1191,15 @@ namespace Barotrauma.Networking
|
||||
ConnectedClients.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
//remove clients that aren't present anymore
|
||||
for (int i = ConnectedClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (!currentClients.Contains(ConnectedClients[i]))
|
||||
{
|
||||
GameMain.NetLobbyScreen.RemovePlayer(ConnectedClients[i].Name);
|
||||
ConnectedClients.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
Voting.AllowSubVoting = allowSubVoting;
|
||||
Voting.AllowModeVoting = allowModeVoting;
|
||||
|
||||
@@ -163,6 +163,7 @@ namespace Barotrauma
|
||||
{
|
||||
steamWorkshopButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SteamWorkshopButton"), style: "GUIButtonLarge")
|
||||
{
|
||||
Enabled = false,
|
||||
OnClicked = SteamWorkshopClicked
|
||||
};
|
||||
}
|
||||
@@ -363,6 +364,7 @@ namespace Barotrauma
|
||||
|
||||
private bool SteamWorkshopClicked(GUIButton button, object obj)
|
||||
{
|
||||
if (!Steam.SteamManager.IsInitialized) { return false; }
|
||||
GameMain.SteamWorkshopScreen.Select();
|
||||
return true;
|
||||
}
|
||||
@@ -453,6 +455,10 @@ namespace Barotrauma
|
||||
}
|
||||
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
}
|
||||
#else
|
||||
joinServerButton.Enabled = true;
|
||||
hostServerButton.Enabled = true;
|
||||
steamWorkshopButton.Enabled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ namespace Barotrauma
|
||||
|
||||
private GUITextBox serverMessage;
|
||||
|
||||
private GUIButton faceSelectionLeft;
|
||||
private GUIButton faceSelectionRight;
|
||||
|
||||
private float autoRestartTimer;
|
||||
|
||||
//persistent characterinfo provided by the server
|
||||
@@ -715,17 +718,15 @@ namespace Barotrauma
|
||||
if (!playYourself.Selected) return;
|
||||
if (characterInfo == null)
|
||||
{
|
||||
characterInfo =
|
||||
new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, GameMain.Config.CharacterGender, null)
|
||||
{
|
||||
Race = GameMain.Config.CharacterRace,
|
||||
HeadSpriteId = GameMain.Config.CharacterHeadIndex,
|
||||
HairIndex = GameMain.Config.CharacterHairIndex,
|
||||
BeardIndex = GameMain.Config.CharacterBeardIndex,
|
||||
MoustacheIndex = GameMain.Config.CharacterMoustacheIndex,
|
||||
FaceAttachmentIndex = GameMain.Config.CharacterFaceAttachmentIndex,
|
||||
};
|
||||
// Need to reload the attachments because the indices may have changed
|
||||
characterInfo = new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, GameMain.Config.CharacterGender, null)
|
||||
{
|
||||
Race = GameMain.Config.CharacterRace,
|
||||
HairIndex = GameMain.Config.CharacterHairIndex,
|
||||
BeardIndex = GameMain.Config.CharacterBeardIndex,
|
||||
MoustacheIndex = GameMain.Config.CharacterMoustacheIndex,
|
||||
FaceAttachmentIndex = GameMain.Config.CharacterFaceAttachmentIndex,
|
||||
};
|
||||
characterInfo.Head.HeadSpriteId = GameMain.Config.CharacterHeadIndex;
|
||||
characterInfo.LoadHeadAttachments();
|
||||
GameMain.NetworkMember.CharacterInfo = characterInfo;
|
||||
}
|
||||
@@ -744,11 +745,13 @@ namespace Barotrauma
|
||||
|
||||
if (allowEditing)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), headContainer.RectTransform), "", style: "GUIButtonHorizontalArrow")
|
||||
faceSelectionLeft = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), headContainer.RectTransform), "", style: "GUIButtonHorizontalArrow")
|
||||
{
|
||||
Enabled = generatedHeads.UndoCount > 1,
|
||||
UserData = -1,
|
||||
OnClicked = ToggleHead
|
||||
}.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
|
||||
OnClicked = SwitchHead
|
||||
};
|
||||
faceSelectionLeft.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
|
||||
}
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.3f, 1.0f), headContainer.RectTransform),
|
||||
@@ -756,10 +759,10 @@ namespace Barotrauma
|
||||
|
||||
if (allowEditing)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), headContainer.RectTransform), style: "GUIButtonHorizontalArrow")
|
||||
faceSelectionRight = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), headContainer.RectTransform), style: "GUIButtonHorizontalArrow")
|
||||
{
|
||||
UserData = 1,
|
||||
OnClicked = ToggleHead
|
||||
OnClicked = SwitchHead
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), infoContainer.RectTransform),
|
||||
@@ -1511,29 +1514,66 @@ namespace Barotrauma
|
||||
if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f;
|
||||
}
|
||||
|
||||
// TODO: remember the previous head(s), check that the next is unique
|
||||
private bool ToggleHead(GUIButton button, object userData)
|
||||
private Memento<CharacterInfo.HeadInfo> generatedHeads = new Memento<CharacterInfo.HeadInfo>();
|
||||
|
||||
private bool SwitchHead(GUIButton button, object userData)
|
||||
{
|
||||
if (GameMain.NetworkMember.CharacterInfo == null) return true;
|
||||
int dir = (int)userData;
|
||||
var info = GameMain.NetworkMember.CharacterInfo;
|
||||
info.SetRandomRace();
|
||||
info.SetRandomHead();
|
||||
info.LoadHeadAttachments();
|
||||
info.LoadHeadSprite();
|
||||
if (generatedHeads.Current == null)
|
||||
{
|
||||
// Add the current head in the memory
|
||||
generatedHeads.Store(info.Head);
|
||||
}
|
||||
if (dir == 1)
|
||||
{
|
||||
// Try redo, if not possible, generate new
|
||||
var previousHead = generatedHeads.Redo();
|
||||
if (previousHead == info.Head || previousHead == null)
|
||||
{
|
||||
// Generate new and add to the list
|
||||
// If the head id is the same, regenerate until it's not
|
||||
// The counter is there to prevent stack overflow if we for some reason cannot get unique ids (e.g. an issue with the head id range or simply if there is no heads defined).
|
||||
int newHeadId = previousHead.HeadSpriteId;
|
||||
int counter = 0;
|
||||
while (newHeadId == previousHead.HeadSpriteId && counter < 10)
|
||||
{
|
||||
newHeadId = info.GetRandomHeadID();
|
||||
counter++;
|
||||
}
|
||||
info.Head = new CharacterInfo.HeadInfo(newHeadId) { gender = GameMain.Config.CharacterGender };
|
||||
generatedHeads.Store(info.Head);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Head = previousHead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undo, if not possible, the button should be disabled
|
||||
var previousHead = generatedHeads.Undo();
|
||||
if (previousHead != info.Head && previousHead != null)
|
||||
{
|
||||
info.Head = previousHead;
|
||||
}
|
||||
}
|
||||
info.ReloadHeadAttachments();
|
||||
StoreHead();
|
||||
GameMain.Config.Save();
|
||||
faceSelectionLeft.Enabled = generatedHeads.UndoCount > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SwitchGender(GUIButton button, object obj)
|
||||
{
|
||||
generatedHeads.Clear();
|
||||
Gender gender = (Gender)obj;
|
||||
var info = GameMain.NetworkMember.CharacterInfo;
|
||||
info.Gender = gender;
|
||||
info.SetRandomHead();
|
||||
info.LoadHeadAttachments();
|
||||
info.LoadHeadSprite();
|
||||
StoreHead();
|
||||
GameMain.Config.Save();
|
||||
return true;
|
||||
|
||||
@@ -714,9 +714,11 @@ namespace Barotrauma
|
||||
}
|
||||
catch (PingException ex)
|
||||
{
|
||||
string errorMsg = "Failed to ping a server (" + serverInfo.ServerName + ", " + serverInfo.IP + ") - " + ex.Message;
|
||||
string errorMsg = "Failed to ping a server (" + serverInfo.ServerName + ", " + serverInfo.IP + ") - " + (ex?.InnerException?.Message ?? ex.Message);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + serverInfo.IP, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,9 +69,7 @@ namespace Barotrauma
|
||||
Config.WasGameUpdated = false;
|
||||
Config.Save();
|
||||
}
|
||||
|
||||
TextManager.LoadTextPacks();
|
||||
|
||||
|
||||
SteamManager.Initialize();
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsManager.Init();
|
||||
|
||||
|
||||
@@ -2734,6 +2734,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\Objectives\AIObjectiveRepairItems.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\Objectives\AIObjectiveRescue.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\Objectives\AIObjectiveRescueAll.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\Objectives\AIObjectiveDecontainItem.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\Order.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\PathFinder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\AI\SteeringManager.cs" />
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Barotrauma
|
||||
foreach (string identifier in itemIdentifiers)
|
||||
{
|
||||
itemToContain = character.Inventory.FindItemByIdentifier(identifier) ?? character.Inventory.FindItemByTag(identifier);
|
||||
if (itemToContain != null) break;
|
||||
if (itemToContain != null && itemToContain.Condition > 0.0f) break;
|
||||
}
|
||||
|
||||
if (itemToContain == null)
|
||||
@@ -138,8 +138,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveDecontainItem : AIObjective
|
||||
{
|
||||
//can either be a tag or an identifier
|
||||
private string[] itemIdentifiers;
|
||||
|
||||
private ItemContainer container;
|
||||
|
||||
private bool isCompleted;
|
||||
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
private AIObjectiveGetItem getItemObjective;
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
private Item targetItem;
|
||||
|
||||
public AIObjectiveDecontainItem(Character character, Item targetItem, ItemContainer container)
|
||||
: base(character, "")
|
||||
{
|
||||
this.targetItem = targetItem;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
|
||||
public AIObjectiveDecontainItem(Character character, string itemIdentifier, ItemContainer container)
|
||||
: this(character, new string[] { itemIdentifier }, container)
|
||||
{
|
||||
}
|
||||
|
||||
public AIObjectiveDecontainItem(Character character, string[] itemIdentifiers, ItemContainer container)
|
||||
: base(character, "")
|
||||
{
|
||||
this.itemIdentifiers = itemIdentifiers;
|
||||
for (int i = 0; i < itemIdentifiers.Length; i++)
|
||||
{
|
||||
itemIdentifiers[i] = itemIdentifiers[i].ToLowerInvariant();
|
||||
}
|
||||
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
if (goToObjective != null)
|
||||
{
|
||||
return goToObjective.CanBeCompleted;
|
||||
}
|
||||
|
||||
return getItemObjective == null || getItemObjective.CanBeCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Item itemToDecontain = null;
|
||||
|
||||
//get the item that should be de-contained
|
||||
if (targetItem == null)
|
||||
{
|
||||
if (itemIdentifiers != null)
|
||||
{
|
||||
foreach (string identifier in itemIdentifiers)
|
||||
{
|
||||
itemToDecontain = container.Inventory.FindItemByIdentifier(identifier) ?? container.Inventory.FindItemByTag(identifier);
|
||||
if (itemToDecontain != null) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToDecontain = targetItem;
|
||||
}
|
||||
|
||||
if (itemToDecontain == null || itemToDecontain.Container != container.Item) // Item not found or already de-contained, consider complete
|
||||
{
|
||||
isCompleted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemToDecontain.OwnInventory != character.Inventory && itemToDecontain.ParentInventory != character.Inventory)
|
||||
{
|
||||
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance
|
||||
&& !container.Item.IsInsideTrigger(character.WorldPosition))
|
||||
{
|
||||
goToObjective = new AIObjectiveGoTo(container.Item, character);
|
||||
AddSubObjective(goToObjective);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemToDecontain.Drop(character);
|
||||
isCompleted = true;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveDecontainItem decontainItem = otherObjective as AIObjectiveDecontainItem;
|
||||
if (decontainItem == null) return false;
|
||||
if (decontainItem.itemIdentifiers != null && itemIdentifiers != null)
|
||||
{
|
||||
if (decontainItem.itemIdentifiers.Length != itemIdentifiers.Length) return false;
|
||||
for (int i = 0; i < decontainItem.itemIdentifiers.Length; i++)
|
||||
{
|
||||
if (decontainItem.itemIdentifiers[i] != itemIdentifiers[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (decontainItem.itemIdentifiers == null && itemIdentifiers == null)
|
||||
{
|
||||
return decontainItem.targetItem == targetItem;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -754,7 +754,7 @@ namespace Barotrauma
|
||||
if (head == null) { return; }
|
||||
if (headId.HasValue)
|
||||
{
|
||||
Info.HeadSpriteId = headId.Value;
|
||||
Info.Head.HeadSpriteId = headId.Value;
|
||||
Info.LoadHeadSprite();
|
||||
Info.HairIndex = hairIndex ?? -1;
|
||||
Info.BeardIndex = beardIndex ?? -1;
|
||||
|
||||
@@ -14,8 +14,83 @@ namespace Barotrauma
|
||||
public enum Gender { None, Male, Female };
|
||||
public enum Race { None, White, Black, Asian };
|
||||
|
||||
// TODO: Generating the HeadInfo could be simplified.
|
||||
partial class CharacterInfo
|
||||
{
|
||||
public class HeadInfo
|
||||
{
|
||||
private int _headSpriteId;
|
||||
public int HeadSpriteId
|
||||
{
|
||||
get { return _headSpriteId; }
|
||||
set
|
||||
{
|
||||
_headSpriteId = value;
|
||||
if (_headSpriteId < (int)headSpriteRange.X)
|
||||
{
|
||||
_headSpriteId = (int)headSpriteRange.Y;
|
||||
}
|
||||
if (_headSpriteId > (int)headSpriteRange.Y)
|
||||
{
|
||||
_headSpriteId = (int)headSpriteRange.X;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Vector2 headSpriteRange;
|
||||
public Gender gender;
|
||||
public Race race;
|
||||
|
||||
public int HairIndex { get; set; } = -1;
|
||||
public int BeardIndex { get; set; } = -1;
|
||||
public int MoustacheIndex { get; set; } = -1;
|
||||
public int FaceAttachmentIndex { get; set; } = -1;
|
||||
|
||||
public XElement HairElement { get; set; }
|
||||
public XElement BeardElement { get; set; }
|
||||
public XElement MoustacheElement { get; set; }
|
||||
public XElement FaceAttachment { get; set; }
|
||||
|
||||
public HeadInfo() { }
|
||||
|
||||
public HeadInfo(int headId)
|
||||
{
|
||||
_headSpriteId = headId;
|
||||
}
|
||||
|
||||
public void ResetAttachmentIndices()
|
||||
{
|
||||
HairIndex = -1;
|
||||
BeardIndex = -1;
|
||||
MoustacheIndex = -1;
|
||||
FaceAttachmentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private HeadInfo head = new HeadInfo();
|
||||
public HeadInfo Head
|
||||
{
|
||||
get { return head; }
|
||||
set
|
||||
{
|
||||
if (head != value && value != null)
|
||||
{
|
||||
head = value;
|
||||
if (head.race == Race.None)
|
||||
{
|
||||
head.race = GetRandomRace();
|
||||
}
|
||||
if (head.gender == Gender.None)
|
||||
{
|
||||
head.gender = GetRandomGender();
|
||||
}
|
||||
CalculateHeadSpriteRange();
|
||||
Head.HeadSpriteId = value.HeadSpriteId;
|
||||
HeadSprite = null;
|
||||
AttachmentSprites = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, XDocument> cachedConfigs = new Dictionary<string, XDocument>();
|
||||
|
||||
private static ushort idCounter;
|
||||
@@ -70,7 +145,97 @@ namespace Barotrauma
|
||||
|
||||
public int Salary;
|
||||
|
||||
private Vector2 headSpriteRange;
|
||||
private Sprite headSprite;
|
||||
public Sprite HeadSprite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (headSprite == null)
|
||||
{
|
||||
LoadHeadSprite();
|
||||
}
|
||||
return headSprite;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (headSprite != null)
|
||||
{
|
||||
headSprite.Remove();
|
||||
}
|
||||
headSprite = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite portrait;
|
||||
public Sprite Portrait
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portrait == null)
|
||||
{
|
||||
LoadHeadSprite();
|
||||
}
|
||||
return portrait;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (portrait != null)
|
||||
{
|
||||
portrait.Remove();
|
||||
}
|
||||
portrait = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite portraitBackground;
|
||||
public Sprite PortraitBackground
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portraitBackground == null)
|
||||
{
|
||||
var portraitBackgroundElement = SourceElement.Element("portraitbackground");
|
||||
if (portraitBackgroundElement != null)
|
||||
{
|
||||
portraitBackground = new Sprite(portraitBackgroundElement.Element("sprite"));
|
||||
}
|
||||
}
|
||||
return portraitBackground;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (portraitBackground != null)
|
||||
{
|
||||
portraitBackground.Remove();
|
||||
}
|
||||
portraitBackground = value;
|
||||
}
|
||||
}
|
||||
|
||||
private List<WearableSprite> attachmentSprites;
|
||||
public List<WearableSprite> AttachmentSprites
|
||||
{
|
||||
get
|
||||
{
|
||||
if (attachmentSprites == null)
|
||||
{
|
||||
LoadAttachmentSprites();
|
||||
}
|
||||
return attachmentSprites;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (attachmentSprites != null)
|
||||
{
|
||||
attachmentSprites.ForEach(s => s.Sprite?.Remove());
|
||||
}
|
||||
attachmentSprites = value;
|
||||
}
|
||||
}
|
||||
|
||||
public XElement SourceElement { get; set; }
|
||||
|
||||
public readonly string ragdollFileName = string.Empty;
|
||||
|
||||
private Sprite headSprite;
|
||||
public Sprite HeadSprite
|
||||
@@ -114,35 +279,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite portraitBackground;
|
||||
public Sprite PortraitBackground
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portraitBackground == null)
|
||||
{
|
||||
var portraitBackgroundElement = SourceElement.Element("portraitbackground");
|
||||
if (portraitBackgroundElement != null)
|
||||
{
|
||||
portraitBackground = new Sprite(portraitBackgroundElement.Element("sprite"));
|
||||
}
|
||||
}
|
||||
return portraitBackground;
|
||||
}
|
||||
}
|
||||
private NPCPersonalityTrait personalityTrait;
|
||||
|
||||
private List<WearableSprite> attachmentSprites;
|
||||
public List<WearableSprite> AttachmentsSprites
|
||||
{
|
||||
get
|
||||
{
|
||||
if (attachmentSprites == null)
|
||||
{
|
||||
LoadAttachmentSprites();
|
||||
}
|
||||
return attachmentSprites;
|
||||
}
|
||||
}
|
||||
//unique ID given to character infos in MP
|
||||
//used by clients to identify which infos are the same to prevent duplicate characters in round summary
|
||||
public ushort ID;
|
||||
|
||||
public XElement InventoryData;
|
||||
|
||||
|
||||
public XElement SourceElement { get; set; }
|
||||
|
||||
@@ -186,22 +330,17 @@ namespace Barotrauma
|
||||
get { return personalityTrait; }
|
||||
}
|
||||
|
||||
private int headSpriteId;
|
||||
/// <summary>
|
||||
/// Setting the value with this property also resets the head attachments. Use Head.headSpriteId if you don't want that.
|
||||
/// </summary>
|
||||
public int HeadSpriteId
|
||||
{
|
||||
get { return headSpriteId; }
|
||||
get { return Head.HeadSpriteId; }
|
||||
set
|
||||
{
|
||||
int oldId = headSpriteId;
|
||||
|
||||
headSpriteId = value;
|
||||
Vector2 spriteRange = headSpriteRange;
|
||||
|
||||
if (headSpriteId < (int)spriteRange.X) headSpriteId = (int)(spriteRange.Y);
|
||||
if (headSpriteId > (int)spriteRange.Y) headSpriteId = (int)(spriteRange.X);
|
||||
|
||||
headSprite = null;
|
||||
attachmentSprites = null;
|
||||
Head.HeadSpriteId = value;
|
||||
HeadSprite = null;
|
||||
AttachmentSprites = null;
|
||||
ResetHeadAttachments();
|
||||
}
|
||||
}
|
||||
@@ -209,47 +348,50 @@ namespace Barotrauma
|
||||
private Gender gender;
|
||||
public Gender Gender
|
||||
{
|
||||
get { return gender; }
|
||||
get { return Head.gender; }
|
||||
set
|
||||
{
|
||||
if (gender == value) return;
|
||||
gender = value;
|
||||
if (gender == Gender.None)
|
||||
if (Head.gender == value) return;
|
||||
Head.gender = value;
|
||||
if (Head.gender == Gender.None)
|
||||
{
|
||||
Gender = Gender.Male;
|
||||
//SetRandomGender();
|
||||
Head.gender = Gender.Male;
|
||||
}
|
||||
CalculateHeadSpriteRange();
|
||||
ResetHeadAttachments();
|
||||
headSprite = null;
|
||||
attachmentSprites = null;
|
||||
//SetRandomHead();
|
||||
//LoadHeadSprite();
|
||||
HeadSprite = null;
|
||||
AttachmentSprites = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Race race;
|
||||
public Race Race
|
||||
{
|
||||
get { return race; }
|
||||
get { return Head.race; }
|
||||
set
|
||||
{
|
||||
if (race == value) { return; }
|
||||
race = value;
|
||||
if (race == Race.None)
|
||||
if (Head.race == value) { return; }
|
||||
Head.race = value;
|
||||
if (Head.race == Race.None)
|
||||
{
|
||||
race = Race.White;
|
||||
//SetRandomRace();
|
||||
Head.race = Race.White;
|
||||
}
|
||||
CalculateHeadSpriteRange();
|
||||
ResetHeadAttachments();
|
||||
headSprite = null;
|
||||
attachmentSprites = null;
|
||||
//SetRandomHead();
|
||||
//LoadHeadSprite();
|
||||
HeadSprite = null;
|
||||
AttachmentSprites = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int HairIndex { get => Head.HairIndex; set => Head.HairIndex = value; }
|
||||
public int BeardIndex { get => Head.BeardIndex; set => Head.BeardIndex = value; }
|
||||
public int MoustacheIndex { get => Head.MoustacheIndex; set => Head.MoustacheIndex = value; }
|
||||
public int FaceAttachmentIndex { get => Head.FaceAttachmentIndex; set => Head.FaceAttachmentIndex = value; }
|
||||
|
||||
public XElement HairElement { get => Head.HairElement; set => Head.HairElement = value; }
|
||||
public XElement BeardElement { get => Head.BeardElement; set => Head.BeardElement = value; }
|
||||
public XElement MoustacheElement { get => Head.MoustacheElement; set => Head.MoustacheElement = value; }
|
||||
public XElement FaceAttachment { get => Head.FaceAttachment; set => Head.FaceAttachment = value; }
|
||||
|
||||
private RagdollParams ragdoll;
|
||||
public RagdollParams Ragdoll
|
||||
{
|
||||
@@ -268,6 +410,8 @@ namespace Barotrauma
|
||||
set { ragdoll = value; }
|
||||
}
|
||||
|
||||
public bool IsAttachmentsLoaded => HairIndex > -1 && BeardIndex > -1 && MoustacheIndex > -1 && FaceAttachmentIndex > -1;
|
||||
|
||||
// Used for creating the data
|
||||
public CharacterInfo(string file, string name = "", Gender gender = Gender.None, JobPrefab jobPrefab = null, string ragdollFileName = null)
|
||||
{
|
||||
@@ -279,18 +423,18 @@ namespace Barotrauma
|
||||
SourceElement = doc.Root;
|
||||
if (doc.Root.GetAttributeBool("genders", false))
|
||||
{
|
||||
this.gender = gender == Gender.None ? GetRandomGender() : gender;
|
||||
Head.gender = gender == Gender.None ? GetRandomGender() : gender;
|
||||
}
|
||||
if (!Enum.TryParse(doc.Root.GetAttributeString("race", "None"), true, out race))
|
||||
if (!Enum.TryParse(doc.Root.GetAttributeString("race", "None"), true, out Head.race))
|
||||
{
|
||||
race = GetRandomRace();
|
||||
Head.race = GetRandomRace();
|
||||
}
|
||||
if (race == Race.None)
|
||||
if (Head.race == Race.None)
|
||||
{
|
||||
race = GetRandomRace();
|
||||
Head.race = GetRandomRace();
|
||||
}
|
||||
CalculateHeadSpriteRange();
|
||||
SetRandomHeadID();
|
||||
Head.HeadSpriteId = GetRandomHeadID();
|
||||
Job = (jobPrefab == null) ? Job.Random(Rand.RandSync.Server) : new Job(jobPrefab);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
@@ -304,14 +448,14 @@ namespace Barotrauma
|
||||
string firstNamePath = doc.Root.Element("name").GetAttributeString("firstname", "");
|
||||
if (firstNamePath != "")
|
||||
{
|
||||
firstNamePath = firstNamePath.Replace("[GENDER]", (this.gender == Gender.Female) ? "female" : "male");
|
||||
firstNamePath = firstNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||
Name = ToolBox.GetRandomLine(firstNamePath);
|
||||
}
|
||||
|
||||
string lastNamePath = doc.Root.Element("name").GetAttributeString("lastname", "");
|
||||
if (lastNamePath != "")
|
||||
{
|
||||
lastNamePath = lastNamePath.Replace("[GENDER]", (this.gender == Gender.Female) ? "female" : "male");
|
||||
lastNamePath = lastNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||
if (Name != "") Name += " ";
|
||||
Name += ToolBox.GetRandomLine(lastNamePath);
|
||||
}
|
||||
@@ -333,16 +477,16 @@ namespace Barotrauma
|
||||
idCounter++;
|
||||
Name = element.GetAttributeString("name", "unnamed");
|
||||
string genderStr = element.GetAttributeString("gender", "male").ToLowerInvariant();
|
||||
gender = (genderStr == "male") ? Gender.Male : Gender.Female;
|
||||
Enum.TryParse(element.GetAttributeString("race", "white"), true, out race);
|
||||
Head.gender = (genderStr == "male") ? Gender.Male : Gender.Female;
|
||||
Enum.TryParse(element.GetAttributeString("race", "white"), true, out Head.race);
|
||||
File = element.GetAttributeString("file", "");
|
||||
SourceElement = GetConfig(File).Root;
|
||||
Salary = element.GetAttributeInt("salary", 1000);
|
||||
headSpriteId = element.GetAttributeInt("headspriteid", 1);
|
||||
HairIndex = element.GetAttributeInt("hairindex", -1);
|
||||
BeardIndex = element.GetAttributeInt("beardindex", -1);
|
||||
MoustacheIndex = element.GetAttributeInt("moustacheindex", -1);
|
||||
FaceAttachmentIndex = element.GetAttributeInt("faceattachmentindex", -1);
|
||||
Head.HeadSpriteId = element.GetAttributeInt("headspriteid", 1);
|
||||
Head.HairIndex = element.GetAttributeInt("hairindex", -1);
|
||||
Head.BeardIndex = element.GetAttributeInt("beardindex", -1);
|
||||
Head.MoustacheIndex = element.GetAttributeInt("moustacheindex", -1);
|
||||
Head.FaceAttachmentIndex = element.GetAttributeInt("faceattachmentindex", -1);
|
||||
StartItemsGiven = element.GetAttributeBool("startitemsgiven", false);
|
||||
string personalityName = element.GetAttributeString("personality", "");
|
||||
ragdollFileName = element.GetAttributeString("ragdoll", string.Empty);
|
||||
@@ -369,8 +513,8 @@ namespace Barotrauma
|
||||
|
||||
string spritePath = spriteElement.Attribute("texture").Value;
|
||||
|
||||
spritePath = spritePath.Replace("[GENDER]", (gender == Gender.Female) ? "female" : "male");
|
||||
spritePath = spritePath.Replace("[RACE]", race.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||
spritePath = spritePath.Replace("[RACE]", Head.race.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[HEADID]", HeadSpriteId.ToString());
|
||||
|
||||
string fileName = Path.GetFileNameWithoutExtension(spritePath);
|
||||
@@ -386,8 +530,8 @@ namespace Barotrauma
|
||||
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
|
||||
if (fileWithoutTags != fileName) continue;
|
||||
|
||||
headSprite = new Sprite(spriteElement, "", file);
|
||||
portrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
|
||||
HeadSprite = new Sprite(spriteElement, "", file);
|
||||
Portrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
|
||||
|
||||
//extract the tags out of the filename
|
||||
SpriteTags = file.Split('[', ']').Skip(1).ToList();
|
||||
@@ -416,22 +560,11 @@ namespace Barotrauma
|
||||
|
||||
public Gender SetRandomGender() => Gender = GetRandomGender();
|
||||
public Race SetRandomRace() => Race = GetRandomRace();
|
||||
public int SetRandomHead() => HeadSpriteId = SetRandomHeadID();
|
||||
public int SetRandomHead() => HeadSpriteId = GetRandomHeadID();
|
||||
|
||||
public Gender GetRandomGender() => (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < SourceElement.GetAttributeFloat("femaleratio", 0.5f)) ? Gender.Female : Gender.Male;
|
||||
public Race GetRandomRace() => new Race[] { Race.White, Race.Black, Race.Asian }.GetRandom(Rand.RandSync.Server);
|
||||
|
||||
private int SetRandomHeadID()
|
||||
{
|
||||
if (headSpriteRange != Vector2.Zero)
|
||||
{
|
||||
headSpriteId = Rand.Range((int)headSpriteRange.X, (int)headSpriteRange.Y + 1, Rand.RandSync.Server);
|
||||
}
|
||||
else
|
||||
{
|
||||
headSpriteId = 0;
|
||||
}
|
||||
return headSpriteId;
|
||||
}
|
||||
public int GetRandomHeadID() => Head.headSpriteRange != Vector2.Zero ? Rand.Range((int)Head.headSpriteRange.X, (int)Head.headSpriteRange.Y + 1, Rand.RandSync.Server) : 0;
|
||||
|
||||
private List<XElement> hairs;
|
||||
private List<XElement> beards;
|
||||
@@ -459,27 +592,27 @@ namespace Barotrauma
|
||||
{
|
||||
if (elements == null) { return elements; }
|
||||
return elements.Where(w =>
|
||||
Enum.TryParse(w.GetAttributeString("gender", "male"), true, out Gender g) && g == gender &&
|
||||
Enum.TryParse(w.GetAttributeString("race", "None"), true, out Race r) && r == race);
|
||||
Enum.TryParse(w.GetAttributeString("gender", "male"), true, out Gender g) && g == Head.gender &&
|
||||
Enum.TryParse(w.GetAttributeString("race", "None"), true, out Race r) && r == Head.race);
|
||||
}
|
||||
|
||||
private void CalculateHeadSpriteRange()
|
||||
{
|
||||
if (SourceElement == null) { return; }
|
||||
headSpriteRange = SourceElement.GetAttributeVector2("headidrange", Vector2.Zero);
|
||||
if (headSpriteRange == Vector2.Zero)
|
||||
Head.headSpriteRange = SourceElement.GetAttributeVector2("headidrange", Vector2.Zero);
|
||||
if (Head.headSpriteRange == Vector2.Zero)
|
||||
{
|
||||
// If range is defined, we use it as it is
|
||||
// Else we calculate the range from the wearables.
|
||||
var wearables = FilterElementsByGenderAndRace(Wearables);
|
||||
if (wearables == null)
|
||||
{
|
||||
headSpriteRange = Vector2.Zero;
|
||||
Head.headSpriteRange = Vector2.Zero;
|
||||
return;
|
||||
}
|
||||
if (wearables.None())
|
||||
{
|
||||
DebugConsole.ThrowError($"[CharacterInfo] No headidrange defined and no wearables matching the gender {gender} and the race {race} could be found. Total wearables found: {Wearables.Count()}.");
|
||||
DebugConsole.ThrowError($"[CharacterInfo] No headidrange defined and no wearables matching the gender {Head.gender} and the race {Head.race} could be found. Total wearables found: {Wearables.Count()}.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -492,7 +625,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
ids = ids.OrderBy(id => id);
|
||||
headSpriteRange = new Vector2(ids.First(), ids.Last());
|
||||
Head.headSpriteRange = new Vector2(ids.First(), ids.Last());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,41 +654,41 @@ namespace Barotrauma
|
||||
faceAttachments = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables), WearableType.FaceAttachment), WearableType.FaceAttachment);
|
||||
}
|
||||
|
||||
if (IsValidIndex(HairIndex, hairs))
|
||||
if (IsValidIndex(Head.HairIndex, hairs))
|
||||
{
|
||||
HairElement = hairs[HairIndex];
|
||||
Head.HairElement = hairs[Head.HairIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
HairElement = GetRandomElement(hairs);
|
||||
HairIndex = hairs.IndexOf(HairElement);
|
||||
Head.HairElement = GetRandomElement(hairs);
|
||||
Head.HairIndex = hairs.IndexOf(Head.HairElement);
|
||||
}
|
||||
if (IsValidIndex(BeardIndex, beards))
|
||||
if (IsValidIndex(Head.BeardIndex, beards))
|
||||
{
|
||||
BeardElement = beards[BeardIndex];
|
||||
Head.BeardElement = beards[Head.BeardIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
BeardElement = GetRandomElement(beards);
|
||||
BeardIndex = beards.IndexOf(BeardElement);
|
||||
Head.BeardElement = GetRandomElement(beards);
|
||||
Head.BeardIndex = beards.IndexOf(Head.BeardElement);
|
||||
}
|
||||
if (IsValidIndex(MoustacheIndex, moustaches))
|
||||
if (IsValidIndex(Head.MoustacheIndex, moustaches))
|
||||
{
|
||||
MoustacheElement = moustaches[MoustacheIndex];
|
||||
Head.MoustacheElement = moustaches[Head.MoustacheIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
MoustacheElement = GetRandomElement(moustaches);
|
||||
MoustacheIndex = moustaches.IndexOf(MoustacheElement);
|
||||
Head.MoustacheElement = GetRandomElement(moustaches);
|
||||
Head.MoustacheIndex = moustaches.IndexOf(Head.MoustacheElement);
|
||||
}
|
||||
if (IsValidIndex(FaceAttachmentIndex, faceAttachments))
|
||||
if (IsValidIndex(Head.FaceAttachmentIndex, faceAttachments))
|
||||
{
|
||||
FaceAttachment = faceAttachments[FaceAttachmentIndex];
|
||||
Head.FaceAttachment = faceAttachments[Head.FaceAttachmentIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
FaceAttachment = GetRandomElement(faceAttachments);
|
||||
FaceAttachmentIndex = faceAttachments.IndexOf(FaceAttachment);
|
||||
Head.FaceAttachment = GetRandomElement(faceAttachments);
|
||||
Head.FaceAttachmentIndex = faceAttachments.IndexOf(Head.FaceAttachment);
|
||||
}
|
||||
|
||||
List<XElement> AddEmpty(IEnumerable<XElement> elements, WearableType type)
|
||||
@@ -583,14 +716,14 @@ namespace Barotrauma
|
||||
if (Enum.TryParse(e.GetAttributeString("type", ""), true, out WearableType type) && type != targetType) { return false; }
|
||||
int headId = e.GetAttributeInt("headid", -1);
|
||||
// if the head id is less than 1, the id is not valid and the condition is ignored.
|
||||
return headId < 1 || headId == headSpriteId;
|
||||
return headId < 1 || headId == Head.HeadSpriteId;
|
||||
});
|
||||
}
|
||||
|
||||
bool IsWearableAllowed(XElement element)
|
||||
{
|
||||
string spriteName = element.Element("sprite").GetAttributeString("name", string.Empty);
|
||||
return IsAllowed(HairElement, spriteName) && IsAllowed(BeardElement, spriteName) && IsAllowed(MoustacheElement, spriteName) && IsAllowed(FaceAttachment, spriteName);
|
||||
return IsAllowed(Head.HairElement, spriteName) && IsAllowed(Head.BeardElement, spriteName) && IsAllowed(Head.MoustacheElement, spriteName) && IsAllowed(Head.FaceAttachment, spriteName);
|
||||
}
|
||||
|
||||
bool IsAllowed(XElement element, string spriteName)
|
||||
@@ -671,8 +804,8 @@ namespace Barotrauma
|
||||
charElement.Add(
|
||||
new XAttribute("name", Name),
|
||||
new XAttribute("file", File),
|
||||
new XAttribute("gender", gender == Gender.Male ? "male" : "female"),
|
||||
new XAttribute("race", race.ToString()),
|
||||
new XAttribute("gender", Head.gender == Gender.Male ? "male" : "female"),
|
||||
new XAttribute("race", Head.race.ToString()),
|
||||
new XAttribute("salary", Salary),
|
||||
new XAttribute("headspriteid", HeadSpriteId),
|
||||
new XAttribute("hairindex", HairIndex),
|
||||
@@ -735,10 +868,10 @@ namespace Barotrauma
|
||||
msg.Write(Gender == Gender.Female);
|
||||
msg.Write((byte)Race);
|
||||
msg.Write((byte)HeadSpriteId);
|
||||
msg.Write((byte)HairIndex);
|
||||
msg.Write((byte)BeardIndex);
|
||||
msg.Write((byte)MoustacheIndex);
|
||||
msg.Write((byte)FaceAttachmentIndex);
|
||||
msg.Write((byte)Head.HairIndex);
|
||||
msg.Write((byte)Head.BeardIndex);
|
||||
msg.Write((byte)Head.MoustacheIndex);
|
||||
msg.Write((byte)Head.FaceAttachmentIndex);
|
||||
msg.Write(ragdollFileName);
|
||||
|
||||
if (Job != null)
|
||||
@@ -791,13 +924,13 @@ namespace Barotrauma
|
||||
CharacterInfo ch = new CharacterInfo(configPath, newName, isFemale ? Gender.Female : Gender.Male, jobPrefab, ragdollFile)
|
||||
{
|
||||
ID = infoID,
|
||||
race = (Race)race,
|
||||
headSpriteId = headSpriteID,
|
||||
HairIndex = hairIndex,
|
||||
BeardIndex = beardIndex,
|
||||
MoustacheIndex = moustacheIndex,
|
||||
FaceAttachmentIndex = faceAttachmentIndex
|
||||
};
|
||||
ch.Head.race = (Race)race;
|
||||
ch.Head.HeadSpriteId = headSpriteID;
|
||||
ch.HairIndex = hairIndex;
|
||||
ch.BeardIndex = beardIndex;
|
||||
ch.MoustacheIndex = moustacheIndex;
|
||||
ch.FaceAttachmentIndex = faceAttachmentIndex;
|
||||
ch.CalculateHeadSpriteRange();
|
||||
ch.ReloadHeadAttachments();
|
||||
|
||||
@@ -832,10 +965,7 @@ namespace Barotrauma
|
||||
|
||||
private void ResetAttachmentIndices()
|
||||
{
|
||||
HairIndex = -1;
|
||||
BeardIndex = -1;
|
||||
MoustacheIndex = -1;
|
||||
FaceAttachmentIndex = -1;
|
||||
Head.ResetAttachmentIndices();
|
||||
}
|
||||
|
||||
private void ResetLoadedAttachments()
|
||||
@@ -849,26 +979,10 @@ namespace Barotrauma
|
||||
public void Remove()
|
||||
{
|
||||
Character = null;
|
||||
if (headSprite != null)
|
||||
{
|
||||
headSprite.Remove();
|
||||
headSprite = null;
|
||||
}
|
||||
if (portrait != null)
|
||||
{
|
||||
portrait.Remove();
|
||||
portrait = null;
|
||||
}
|
||||
if (portraitBackground != null)
|
||||
{
|
||||
portraitBackground.Remove();
|
||||
portraitBackground = null;
|
||||
}
|
||||
if (attachmentSprites != null)
|
||||
{
|
||||
attachmentSprites.ForEach(a => a.Sprite.Remove());
|
||||
attachmentSprites = null;
|
||||
}
|
||||
HeadSprite = null;
|
||||
Portrait = null;
|
||||
PortraitBackground = null;
|
||||
AttachmentSprites = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,8 @@ namespace Barotrauma
|
||||
|
||||
public bool MatchesAffliction(Affliction affliction)
|
||||
{
|
||||
if (AfflictionIdentifiers.Length == 0) { return true; }
|
||||
|
||||
foreach (string afflictionName in AfflictionIdentifiers)
|
||||
{
|
||||
if (affliction.Prefab.Identifier.ToLowerInvariant() == afflictionName) return true;
|
||||
|
||||
@@ -411,8 +411,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
UnsavedSettings = false;
|
||||
|
||||
bool invalidPackagesFound = false;
|
||||
|
||||
List<string> missingPackagePaths = new List<string>();
|
||||
List<ContentPackage> incompatiblePackages = new List<ContentPackage>();
|
||||
foreach (XElement subElement in doc.Root.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -422,27 +423,35 @@ namespace Barotrauma
|
||||
var matchingContentPackage = ContentPackage.List.Find(cp => System.IO.Path.GetFullPath(cp.Path) == path);
|
||||
if (matchingContentPackage == null)
|
||||
{
|
||||
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", path), createMessageBox: true);
|
||||
missingPackagePaths.Add(path);
|
||||
}
|
||||
else if (!matchingContentPackage.IsCompatible())
|
||||
{
|
||||
invalidPackagesFound = true;
|
||||
DebugConsole.ThrowError(
|
||||
TextManager.Get(matchingContentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
|
||||
.Replace("[packagename]", matchingContentPackage.Name)
|
||||
.Replace("[packageversion]", matchingContentPackage.GameVersion.ToString())
|
||||
.Replace("[gameversion]", GameMain.Version.ToString()),
|
||||
createMessageBox: true);
|
||||
incompatiblePackages.Add(matchingContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
invalidPackagesFound = true;
|
||||
SelectedContentPackages.Add(matchingContentPackage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextManager.LoadTextPacks(SelectedContentPackages);
|
||||
|
||||
//display error messages after all content packages have been loaded
|
||||
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
|
||||
foreach (string missingPackagePath in missingPackagePaths)
|
||||
{
|
||||
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
|
||||
}
|
||||
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
|
||||
{
|
||||
DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
|
||||
.Replace("[packagename]", incompatiblePackage.Name)
|
||||
.Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
|
||||
.Replace("[gameversion]", GameMain.Version.ToString()));
|
||||
}
|
||||
foreach (ContentPackage contentPackage in SelectedContentPackages)
|
||||
{
|
||||
foreach (ContentFile file in contentPackage.Files)
|
||||
@@ -465,9 +474,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//save to get rid of the invalid selected packages in the config file
|
||||
if (invalidPackagesFound) { Save(); }
|
||||
if (missingPackagePaths.Count > 0 || incompatiblePackages.Count > 0) { Save(); }
|
||||
}
|
||||
|
||||
|
||||
public KeyOrMouse KeyBind(InputType inputType)
|
||||
{
|
||||
return keyMapping[(int)inputType];
|
||||
|
||||
@@ -14,8 +14,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public bool Distort;
|
||||
public float DistortionTimer;
|
||||
|
||||
public List<Hull> LinkedHulls = new List<Hull>();
|
||||
}
|
||||
|
||||
|
||||
private DateTime resetDataTime;
|
||||
|
||||
private bool hasPower;
|
||||
|
||||
@@ -404,7 +404,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
int projectileCount = 0;
|
||||
int usableProjectileCount = 0;
|
||||
int maxProjectileCount = 0;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
@@ -416,11 +416,22 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
var container = projectileContainer.GetComponent<ItemContainer>();
|
||||
if (containedItems != null) maxProjectileCount += container.Capacity;
|
||||
projectileCount += containedItems.Length;
|
||||
|
||||
int projectiles = 0;
|
||||
|
||||
for (int i = 0; i < containedItems.Length; i++)
|
||||
{
|
||||
if (containedItems[i].Condition > 0.0f)
|
||||
{
|
||||
projectiles++;
|
||||
}
|
||||
}
|
||||
|
||||
usableProjectileCount += projectiles;
|
||||
}
|
||||
}
|
||||
|
||||
if (projectileCount == 0 || (projectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill"))
|
||||
if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill"))
|
||||
{
|
||||
ItemContainer container = null;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
@@ -434,11 +445,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (container == null || container.ContainableItems.Count == 0) return true;
|
||||
|
||||
if (container.Inventory.Items[0] != null && container.Inventory.Items[0].Condition <= 0.0f)
|
||||
{
|
||||
var removeShellObjective = new AIObjectiveDecontainItem(character, container.Inventory.Items[0], container);
|
||||
objective.AddSubObjective(removeShellObjective);
|
||||
}
|
||||
|
||||
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container);
|
||||
character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
|
||||
containShellObjective.MinContainedAmount = projectileCount + 1;
|
||||
containShellObjective.MinContainedAmount = usableProjectileCount + 1;
|
||||
containShellObjective.IgnoreAlreadyContainedItems = true;
|
||||
objective.AddSubObjective(containShellObjective);
|
||||
objective.AddSubObjective(containShellObjective);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2265,12 +2265,7 @@ namespace Barotrauma
|
||||
if (linkedTo != null && linkedTo.Count > 0)
|
||||
{
|
||||
var saveableLinked = linkedTo.Where(l => l.ShouldBeSaved).ToList();
|
||||
string[] linkedToIDs = new string[saveableLinked.Count];
|
||||
for (int i = 0; i < saveableLinked.Count; i++)
|
||||
{
|
||||
linkedToIDs[i] = saveableLinked[i].ID.ToString();
|
||||
}
|
||||
element.Add(new XAttribute("linked", string.Join(",", linkedToIDs)));
|
||||
element.Add(new XAttribute("linked", string.Join(",", saveableLinked.Select(l => l.ID.ToString()))));
|
||||
}
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
|
||||
@@ -206,6 +206,9 @@ namespace Barotrauma
|
||||
OxygenPercentage = 100.0f;
|
||||
|
||||
FireSources = new List<FireSource>();
|
||||
linkedTo = new System.Collections.ObjectModel.ObservableCollection<MapEntity>();
|
||||
|
||||
|
||||
|
||||
properties = SerializableProperty.GetProperties(this);
|
||||
|
||||
@@ -938,7 +941,18 @@ namespace Barotrauma
|
||||
waterVolume = element.GetAttributeFloat("pressure", 0.0f),
|
||||
ID = (ushort)int.Parse(element.Attribute("ID").Value)
|
||||
};
|
||||
|
||||
|
||||
hull.linkedToID = new List<ushort>();
|
||||
string linkedToString = element.GetAttributeString("linked", "");
|
||||
if (linkedToString != "")
|
||||
{
|
||||
string[] linkedToIds = linkedToString.Split(',');
|
||||
for (int i = 0; i < linkedToIds.Length; i++)
|
||||
{
|
||||
hull.linkedToID.Add((ushort)int.Parse(linkedToIds[i]));
|
||||
}
|
||||
}
|
||||
|
||||
SerializableProperty.DeserializeProperties(hull, element);
|
||||
if (element.Attribute("oxygen") == null) { hull.Oxygen = hull.Volume; }
|
||||
|
||||
@@ -965,6 +979,12 @@ namespace Barotrauma
|
||||
rect.Width + "," + rect.Height),
|
||||
new XAttribute("water", waterVolume)
|
||||
);
|
||||
|
||||
if (linkedTo != null && linkedTo.Count > 0)
|
||||
{
|
||||
var saveableLinked = linkedTo.Where(l => l.ShouldBeSaved).ToList();
|
||||
element.Add(new XAttribute("linked", string.Join(",", saveableLinked.Select(l => l.ID.ToString()))));
|
||||
}
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
parentElement.Add(element);
|
||||
return element;
|
||||
|
||||
@@ -430,6 +430,13 @@ namespace Barotrauma
|
||||
}
|
||||
CurrentLocation.SelectedMissionIndex = missionIndex;
|
||||
|
||||
//the destination must be the same as the destination of the mission
|
||||
if (CurrentLocation.SelectedMission != null &&
|
||||
CurrentLocation.SelectedMission.Locations[1] != SelectedLocation)
|
||||
{
|
||||
SelectLocation(CurrentLocation.SelectedMission.Locations[1]);
|
||||
}
|
||||
|
||||
SelectedLocation = location;
|
||||
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
|
||||
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
|
||||
|
||||
@@ -111,8 +111,10 @@ namespace Barotrauma
|
||||
Description = TextManager.Get("EntityDescription.hull"),
|
||||
constructor = typeof(Hull).GetConstructor(new Type[] { typeof(MapEntityPrefab), typeof(Rectangle) }),
|
||||
ResizeHorizontal = true,
|
||||
ResizeVertical = true
|
||||
ResizeVertical = true,
|
||||
Linkable = true
|
||||
};
|
||||
ep.AllowedLinks.Add("hull");
|
||||
List.Add(ep);
|
||||
|
||||
ep = new MapEntityPrefab
|
||||
|
||||
@@ -7,6 +7,9 @@ namespace Barotrauma
|
||||
{
|
||||
public T Current { get; private set; }
|
||||
|
||||
public int UndoCount => undoStack.Count;
|
||||
public int RedoCount => redoStack.Count;
|
||||
|
||||
private Stack<T> undoStack = new Stack<T>();
|
||||
private Stack<T> redoStack = new Stack<T>();
|
||||
|
||||
|
||||
@@ -2423,13 +2423,12 @@ namespace Barotrauma.Networking
|
||||
sender.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, sender.Name, gender)
|
||||
{
|
||||
Race = race,
|
||||
HeadSpriteId = headSpriteId,
|
||||
HairIndex = hairIndex,
|
||||
BeardIndex = beardIndex,
|
||||
MoustacheIndex = moustacheIndex,
|
||||
FaceAttachmentIndex = faceAttachmentIndex
|
||||
};
|
||||
// Need to reload the attachments because the indices may have changed
|
||||
sender.CharacterInfo.Head.HeadSpriteId = headSpriteId;
|
||||
sender.CharacterInfo.LoadHeadAttachments();
|
||||
|
||||
//if the client didn't provide job preferences, we'll use the preferences that are randomly assigned in the Client constructor
|
||||
|
||||
@@ -75,6 +75,10 @@ namespace Barotrauma.Steam
|
||||
|
||||
private SteamManager()
|
||||
{
|
||||
#if SERVER
|
||||
return;
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
client = new Facepunch.Steamworks.Client(AppID);
|
||||
@@ -118,34 +122,112 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
public static ulong GetSteamID()
|
||||
|
||||
#region Server
|
||||
|
||||
public static bool CreateServer(Networking.GameServer server, bool isPublic)
|
||||
{
|
||||
|
||||
#if !SERVER
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
ServerInit options = new ServerInit("Barotrauma", "Barotrauma")
|
||||
{
|
||||
GamePort = (ushort)server.Port,
|
||||
QueryPort = (ushort)server.QueryPort
|
||||
};
|
||||
|
||||
instance.server = new Server(AppID, options, isPublic);
|
||||
if (!instance.server.IsValid)
|
||||
{
|
||||
instance.server.Dispose();
|
||||
instance.server = null;
|
||||
DebugConsole.ThrowError("Initializing Steam server failed.");
|
||||
return false;
|
||||
}
|
||||
#if SERVER
|
||||
instance.isInitialized = true;
|
||||
#endif
|
||||
RefreshServerDetails(server);
|
||||
|
||||
instance.server.Auth.OnAuthChange = server.OnAuthChange;
|
||||
Instance.server.LogOnAnonymous();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RefreshServerDetails(Networking.GameServer server)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
return instance.client.SteamId;
|
||||
|
||||
// These server state variables may be changed at any time. Note that there is no lnoger a mechanism
|
||||
// to send the player count. The player count is maintained by steam and you should use the player
|
||||
// creation/authentication functions to maintain your player count.
|
||||
instance.server.ServerName = server.Name;
|
||||
instance.server.MaxPlayers = server.MaxPlayers;
|
||||
instance.server.Passworded = server.HasPassword;
|
||||
Instance.server.SetKey("message", GameMain.NetLobbyScreen.ServerMessageText);
|
||||
Instance.server.SetKey("version", GameMain.Version.ToString());
|
||||
Instance.server.SetKey("contentpackage", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name)));
|
||||
Instance.server.SetKey("contentpackagehash", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.MD5hash.Hash)));
|
||||
Instance.server.SetKey("contentpackageurl", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
|
||||
Instance.server.SetKey("usingwhitelist", (server.WhiteList != null && server.WhiteList.Enabled).ToString());
|
||||
Instance.server.SetKey("modeselectionmode", server.ModeSelectionMode.ToString());
|
||||
Instance.server.SetKey("subselectionmode", server.SubSelectionMode.ToString());
|
||||
Instance.server.SetKey("allowspectating", server.AllowSpectating.ToString());
|
||||
Instance.server.SetKey("allowrespawn", server.AllowRespawn.ToString());
|
||||
Instance.server.SetKey("traitors", server.TraitorsEnabled.ToString());
|
||||
Instance.server.SetKey("gamestarted", server.GameStarted.ToString());
|
||||
Instance.server.SetKey("gamemode", server.GameModeIdentifier);
|
||||
|
||||
#if SERVER
|
||||
instance.server.DedicatedServer = true;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ulong GetWorkshopItemIDFromUrl(string url)
|
||||
public static bool StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(url);
|
||||
string idStr = HttpUtility.ParseQueryString(uri.Query).Get("id");
|
||||
if (ulong.TryParse(idStr, out ulong id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to get Workshop item ID from the url \""+url+"\"!", e);
|
||||
}
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return false;
|
||||
|
||||
return 0;
|
||||
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
|
||||
if (!instance.server.Auth.StartSession(authTicketData, clientSteamID))
|
||||
{
|
||||
DebugConsole.Log("Authentication failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static void StopAuthSession(ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return;
|
||||
|
||||
DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID);
|
||||
instance.server.Auth.EndSession(clientSteamID);
|
||||
}
|
||||
|
||||
public static bool CloseServer()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return false;
|
||||
|
||||
instance.server.Dispose();
|
||||
instance.server = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static bool UnlockAchievement(string achievementName)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
@@ -173,7 +255,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
public static bool IncrementStat(string statName, int increment)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized) { return false; }
|
||||
if (instance == null || !instance.isInitialized || instance.client == null) { return false; }
|
||||
DebugConsole.Log("Incremented stat \"" + statName + "\" by " + increment);
|
||||
bool success = instance.client.Stats.Add(statName, increment);
|
||||
if (!success)
|
||||
@@ -187,7 +269,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
public static bool IncrementStat(string statName, float increment)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized) { return false; }
|
||||
if (instance == null || !instance.isInitialized || instance.client == null) { return false; }
|
||||
DebugConsole.Log("Incremented stat \"" + statName + "\" by " + increment);
|
||||
bool success = instance.client.Stats.Add(statName, increment);
|
||||
if (!success)
|
||||
@@ -199,7 +281,35 @@ namespace Barotrauma.Steam
|
||||
return success;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public static ulong GetSteamID()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return instance.client.SteamId;
|
||||
}
|
||||
|
||||
public static ulong GetWorkshopItemIDFromUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(url);
|
||||
string idStr = HttpUtility.ParseQueryString(uri.Query).Get("id");
|
||||
if (ulong.TryParse(idStr, out ulong id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to get Workshop item ID from the url \""+url+"\"!", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#region Connecting to servers
|
||||
|
||||
public static bool GetServers(Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, Action onFinished)
|
||||
@@ -326,106 +436,6 @@ namespace Barotrauma.Steam
|
||||
return instance.client.Auth.GetAuthSessionTicket();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server
|
||||
|
||||
public static bool CreateServer(Networking.GameServer server, bool isPublic)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerInit options = new ServerInit("Barotrauma", "Barotrauma")
|
||||
{
|
||||
GamePort = (ushort)server.Port,
|
||||
QueryPort = (ushort)server.QueryPort
|
||||
};
|
||||
//options.QueryShareGamePort();
|
||||
|
||||
instance.server = new Server(AppID, options, isPublic);
|
||||
if (!instance.server.IsValid)
|
||||
{
|
||||
instance.server.Dispose();
|
||||
instance.server = null;
|
||||
DebugConsole.ThrowError("Initializing Steam server failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshServerDetails(server);
|
||||
|
||||
instance.server.Auth.OnAuthChange = server.OnAuthChange;
|
||||
Instance.server.LogOnAnonymous();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RefreshServerDetails(Networking.GameServer server)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// These server state variables may be changed at any time. Note that there is no lnoger a mechanism
|
||||
// to send the player count. The player count is maintained by steam and you should use the player
|
||||
// creation/authentication functions to maintain your player count.
|
||||
instance.server.ServerName = server.Name;
|
||||
instance.server.MaxPlayers = server.MaxPlayers;
|
||||
instance.server.Passworded = server.HasPassword;
|
||||
Instance.server.SetKey("message", GameMain.NetLobbyScreen.ServerMessageText);
|
||||
Instance.server.SetKey("version", GameMain.Version.ToString());
|
||||
Instance.server.SetKey("contentpackage", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name)));
|
||||
Instance.server.SetKey("contentpackagehash", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.MD5hash.Hash)));
|
||||
Instance.server.SetKey("contentpackageurl", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
|
||||
Instance.server.SetKey("usingwhitelist", (server.WhiteList != null && server.WhiteList.Enabled).ToString());
|
||||
Instance.server.SetKey("modeselectionmode", server.ModeSelectionMode.ToString());
|
||||
Instance.server.SetKey("subselectionmode", server.SubSelectionMode.ToString());
|
||||
Instance.server.SetKey("allowspectating", server.AllowSpectating.ToString());
|
||||
Instance.server.SetKey("allowrespawn", server.AllowRespawn.ToString());
|
||||
Instance.server.SetKey("traitors", server.TraitorsEnabled.ToString());
|
||||
Instance.server.SetKey("gamestarted", server.GameStarted.ToString());
|
||||
Instance.server.SetKey("gamemode", server.GameModeIdentifier);
|
||||
|
||||
#if SERVER
|
||||
instance.server.DedicatedServer = true;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return false;
|
||||
|
||||
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
|
||||
if (!instance.server.Auth.StartSession(authTicketData, clientSteamID))
|
||||
{
|
||||
DebugConsole.Log("Authentication failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void StopAuthSession(ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return;
|
||||
|
||||
DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID);
|
||||
instance.server.Auth.EndSession(clientSteamID);
|
||||
}
|
||||
|
||||
public static bool CloseServer()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.server == null) return false;
|
||||
|
||||
instance.server.Dispose();
|
||||
instance.server = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Workshop
|
||||
@@ -1028,6 +1038,8 @@ namespace Barotrauma.Steam
|
||||
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
|
||||
public static void Update(float deltaTime)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized) return;
|
||||
@@ -1040,15 +1052,11 @@ namespace Barotrauma.Steam
|
||||
|
||||
public static void ShutDown()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
instance.client?.Dispose();
|
||||
instance.client = null;
|
||||
instance.server?.Dispose();
|
||||
instance.server = null;
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadTextPacks()
|
||||
public static void LoadTextPacks(IEnumerable<ContentPackage> selectedContentPackages)
|
||||
{
|
||||
var textFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Text);
|
||||
var textFiles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.Text);
|
||||
|
||||
foreach (string file in textFiles)
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user