Unstable 0.1500.5.0 (almost forgor edition 💀)

This commit is contained in:
Markus Isberg
2021-10-01 23:56:14 +09:00
parent 3043a9a7bc
commit 08bdfc6cea
150 changed files with 5669 additions and 4403 deletions
@@ -81,10 +81,10 @@ namespace Barotrauma
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), GUI.Style.Green, 0, 4);
}
if (LatchOntoAI.WallAttachPos.HasValue)
if (LatchOntoAI.AttachPos.HasValue)
{
//GUI.DrawLine(spriteBatch, pos,
// ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.WallAttachPos.Value.X, -LatchOntoAI.WallAttachPos.Value.Y)), GUI.Style.Green, 0, 3);
GUI.DrawLine(spriteBatch, pos,
ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.AttachPos.Value.X, -LatchOntoAI.AttachPos.Value.Y)), GUI.Style.Green, 0, 3);
}
}
@@ -562,8 +562,10 @@ namespace Barotrauma
if (this is HumanoidAnimController humanoid)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(humanoid.RightHandIKPos);
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
pos = ConvertUnits.ToDisplayUnits(humanoid.LeftHandIKPos);
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
}
@@ -100,7 +100,7 @@ namespace Barotrauma
}
}
private static bool shouldRecreateHudTexts = true;
public static bool ShouldRecreateHudTexts { get; set; } = true;
private static bool heldDownShiftWhenGotHudTexts;
public static bool IsCampaignInterfaceOpen =>
@@ -150,7 +150,7 @@ namespace Barotrauma
}
}
if (character.IsHumanoid && character.SelectedCharacter != null)
if (character.Params.CanInteract && character.SelectedCharacter != null)
{
character.SelectedCharacter.CharacterHealth.AddToGUIUpdateList();
}
@@ -195,7 +195,7 @@ namespace Barotrauma
}
}
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
if (character.Params.CanInteract && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{
if (character.SelectedCharacter.CanInventoryBeAccessed)
{
@@ -219,7 +219,7 @@ namespace Barotrauma
if (focusedItemOverlayTimer <= 0.0f)
{
focusedItem = null;
shouldRecreateHudTexts = true;
ShouldRecreateHudTexts = true;
}
}
}
@@ -285,6 +285,21 @@ namespace Barotrauma
i.GetRootInventoryOwner() == i);
}
if (GameMain.GameSession != null)
{
foreach (var mission in GameMain.GameSession.Missions)
{
if (!mission.DisplayTargetHudIcons) { continue; }
foreach (var target in mission.HudIconTargets)
{
if (target.Submarine != character.Submarine) { continue; }
float alpha = GetDistanceBasedIconAlpha(target, maxDistance: mission.Prefab.HudIconMaxDistance);
if (alpha <= 0.0f) { continue; }
GUI.DrawIndicator(spriteBatch, target.DrawPosition, cam, 100.0f, mission.Prefab.HudIcon, mission.Prefab.HudIconColor * alpha);
}
}
}
foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities)
{
DrawObjectiveIndicator(spriteBatch, cam, character, objectiveEntity, 1.0f);
@@ -317,7 +332,7 @@ namespace Barotrauma
if (focusedItem != character.FocusedItem)
{
focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer);
shouldRecreateHudTexts = true;
ShouldRecreateHudTexts = true;
}
focusedItem = character.FocusedItem;
}
@@ -342,13 +357,13 @@ namespace Barotrauma
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
{
bool shiftDown = PlayerInput.IsShiftDown();
if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
if (ShouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
{
shouldRecreateHudTexts = true;
ShouldRecreateHudTexts = true;
heldDownShiftWhenGotHudTexts = shiftDown;
}
var hudTexts = focusedItem.GetHUDTexts(character, shouldRecreateHudTexts);
shouldRecreateHudTexts = false;
var hudTexts = focusedItem.GetHUDTexts(character, ShouldRecreateHudTexts);
ShouldRecreateHudTexts = false;
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
@@ -490,7 +505,7 @@ namespace Barotrauma
if (!character.IsIncapacitated && character.Stun <= 0.0f)
{
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
if (character.Params.CanInteract && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{
if (character.SelectedCharacter.CanInventoryBeAccessed)
{
@@ -17,11 +17,15 @@ namespace Barotrauma
public bool LastControlled;
#warning TODO: Refactor
private Sprite disguisedPortrait;
private List<WearableSprite> disguisedAttachmentSprites;
private Vector2? disguisedSheetIndex;
private Sprite disguisedJobIcon;
private Color disguisedJobColor;
private Color disguisedHairColor;
private Color disguisedFacialHairColor;
private Color disguisedSkinColor;
private Sprite tintMask;
private float tintHighlightThreshold;
@@ -161,10 +165,10 @@ namespace Barotrauma
private void DrawInfoFrameCharacterIcon(SpriteBatch sb, Rectangle componentRect)
{
if (headSprite == null) { return; }
if (_headSprite == null) { return; }
Vector2 targetAreaSize = componentRect.Size.ToVector2();
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
DrawIcon(sb, componentRect.Location.ToVector2() + headSprite.size / 2 * scale, targetAreaSize);
float scale = Math.Min(targetAreaSize.X / _headSprite.size.X, targetAreaSize.Y / _headSprite.size.Y);
DrawIcon(sb, componentRect.Location.ToVector2() + _headSprite.size / 2 * scale, targetAreaSize);
}
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
@@ -227,193 +231,36 @@ namespace Barotrauma
{
if (idCard.Item.Tags == string.Empty) return;
if (idCard.StoredJobPrefab == null || idCard.StoredPortrait == null)
if (idCard.StoredOwnerAppearance.JobPrefab == null || idCard.StoredOwnerAppearance.Portrait == null)
{
string[] readTags = idCard.Item.Tags.Split(',');
if (readTags.Length == 0) return;
if (readTags.Length == 0) { return; }
if (idCard.StoredJobPrefab == null)
if (idCard.StoredOwnerAppearance.JobPrefab == null)
{
string jobIdTag = readTags.FirstOrDefault(s => s.StartsWith("jobid:"));
if (jobIdTag != null && jobIdTag.Length > 6)
{
string jobId = jobIdTag.Substring(6);
if (jobId != string.Empty)
{
idCard.StoredJobPrefab = JobPrefab.Get(jobId);
}
}
idCard.StoredOwnerAppearance.ExtractJobPrefab(readTags);
}
if (idCard.StoredPortrait == null)
if (idCard.StoredOwnerAppearance.Portrait == null)
{
string disguisedGender = string.Empty;
string disguisedRace = string.Empty;
string disguisedHeadSpriteId = string.Empty;
int disguisedHairIndex = -1;
int disguisedBeardIndex = -1;
int disguisedMoustacheIndex = -1;
int disguisedFaceAttachmentIndex = -1;
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
switch (s[0])
{
case "gender":
disguisedGender = s[1];
break;
case "race":
disguisedRace = s[1];
break;
case "headspriteid":
disguisedHeadSpriteId = s[1];
break;
case "hairindex":
disguisedHairIndex = int.Parse(s[1]);
break;
case "beardindex":
disguisedBeardIndex = int.Parse(s[1]);
break;
case "moustacheindex":
disguisedMoustacheIndex = int.Parse(s[1]);
break;
case "faceattachmentindex":
disguisedFaceAttachmentIndex = int.Parse(s[1]);
break;
case "sheetindex":
string[] vectorValues = s[1].Split(";");
idCard.StoredSheetIndex = new Vector2(float.Parse(vectorValues[0]), float.Parse(vectorValues[1]));
break;
}
}
if (disguisedGender == string.Empty || disguisedRace == string.Empty || disguisedHeadSpriteId == string.Empty)
{
idCard.StoredPortrait = null;
idCard.StoredAttachments = null;
return;
}
foreach (XElement limbElement in Ragdoll.MainElement.Elements())
{
if (!limbElement.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)) { continue; }
XElement spriteElement = limbElement.Element("sprite");
if (spriteElement == null) { continue; }
string spritePath = spriteElement.Attribute("texture").Value;
spritePath = spritePath.Replace("[GENDER]", disguisedGender);
spritePath = spritePath.Replace("[RACE]", disguisedRace.ToLowerInvariant());
spritePath = spritePath.Replace("[HEADID]", disguisedHeadSpriteId);
string fileName = Path.GetFileNameWithoutExtension(spritePath);
//go through the files in the directory to find a matching sprite
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
{
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string fileWithoutTags = Path.GetFileNameWithoutExtension(file);
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
if (fileWithoutTags != fileName) { continue; }
idCard.StoredPortrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
break;
}
break;
}
if (Wearables != null)
{
XElement disguisedHairElement, disguisedBeardElement, disguisedMoustacheElement, disguisedFaceAttachmentElement;
List<XElement> disguisedHairs, disguisedBeards, disguisedMoustaches, disguisedFaceAttachments;
Gender disguisedGenderEnum = disguisedGender == "female" ? Gender.Female : Gender.Male;
Race disguisedRaceEnum = (Race)Enum.Parse(typeof(Race), disguisedRace);
int headSpriteId = int.Parse(disguisedHeadSpriteId);
float commonness = disguisedGenderEnum == Gender.Female ? 0.05f : 0.2f;
disguisedHairs = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Hair, headSpriteId), WearableType.Hair, commonness);
disguisedBeards = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Beard, headSpriteId), WearableType.Beard);
disguisedMoustaches = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Moustache, headSpriteId), WearableType.Moustache);
disguisedFaceAttachments = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.FaceAttachment, headSpriteId), WearableType.FaceAttachment);
if (IsValidIndex(disguisedHairIndex, disguisedHairs))
{
disguisedHairElement = disguisedHairs[disguisedHairIndex];
}
else
{
disguisedHairElement = GetRandomElement(disguisedHairs);
}
if (IsValidIndex(disguisedBeardIndex, disguisedBeards))
{
disguisedBeardElement = disguisedBeards[disguisedBeardIndex];
}
else
{
disguisedBeardElement = GetRandomElement(disguisedBeards);
}
if (IsValidIndex(disguisedMoustacheIndex, disguisedMoustaches))
{
disguisedMoustacheElement = disguisedMoustaches[disguisedMoustacheIndex];
}
else
{
disguisedMoustacheElement = GetRandomElement(disguisedMoustaches);
}
if (IsValidIndex(disguisedFaceAttachmentIndex, disguisedFaceAttachments))
{
disguisedFaceAttachmentElement = disguisedFaceAttachments[disguisedFaceAttachmentIndex];
}
else
{
disguisedFaceAttachmentElement = GetRandomElement(disguisedFaceAttachments);
}
idCard.StoredAttachments = new List<WearableSprite>();
disguisedFaceAttachmentElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.FaceAttachment)));
disguisedBeardElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Beard)));
disguisedMoustacheElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Moustache)));
disguisedHairElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Hair)));
if (OmitJobInPortraitClothing)
{
JobPrefab.NoJobElement?.Element("PortraitClothing")?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.JobIndicator)));
}
else
{
idCard.StoredJobPrefab?.ClothingElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.JobIndicator)));
}
}
idCard.StoredOwnerAppearance.ExtractAppearance(this, readTags);
}
}
if (idCard.StoredJobPrefab != null)
if (idCard.StoredOwnerAppearance.JobPrefab != null)
{
disguisedJobIcon = idCard.StoredJobPrefab.Icon;
disguisedJobColor = idCard.StoredJobPrefab.UIColor;
disguisedJobIcon = idCard.StoredOwnerAppearance.JobPrefab.Icon;
disguisedJobColor = idCard.StoredOwnerAppearance.JobPrefab.UIColor;
}
disguisedPortrait = idCard.StoredPortrait;
disguisedSheetIndex = idCard.StoredSheetIndex;
disguisedAttachmentSprites = idCard.StoredAttachments;
disguisedPortrait = idCard.StoredOwnerAppearance.Portrait;
disguisedSheetIndex = idCard.StoredOwnerAppearance.SheetIndex;
disguisedAttachmentSprites = idCard.StoredOwnerAppearance.Attachments;
disguisedHairColor = idCard.StoredOwnerAppearance.HairColor;
disguisedFacialHairColor = idCard.StoredOwnerAppearance.FacialHairColor;
disguisedSkinColor = idCard.StoredOwnerAppearance.SkinColor;
}
partial void LoadAttachmentSprites(bool omitJob)
@@ -462,24 +309,35 @@ namespace Barotrauma
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 offset, float targetWidth, bool flip = false, bool evaluateDisguise = false)
{
if (evaluateDisguise && IsDisguised) return;
if (evaluateDisguise && IsDisguised) { return; }
Vector2? sheetIndex;
Sprite portraitToDraw;
List<WearableSprite> attachmentsToDraw;
Color hairColor;
Color facialHairColor;
Color skinColor;
if (!IsDisguisedAsAnother || !evaluateDisguise)
{
sheetIndex = Head.SheetIndex;
portraitToDraw = Portrait;
attachmentsToDraw = AttachmentSprites;
hairColor = Head.HairColor;
facialHairColor = Head.FacialHairColor;
skinColor = Head.SkinColor;
}
else
{
//TODO: disguise skin and hair colors
sheetIndex = disguisedSheetIndex;
portraitToDraw = disguisedPortrait;
attachmentsToDraw = disguisedAttachmentSprites;
hairColor = disguisedHairColor;
facialHairColor = disguisedFacialHairColor;
skinColor = disguisedSkinColor;
}
if (portraitToDraw != null)
@@ -492,14 +350,14 @@ namespace Barotrauma
SetHeadEffect(spriteBatch);
portraitToDraw.SourceRect = new Rectangle(CalculateOffset(portraitToDraw, sheetIndex.Value.ToPoint()), portraitToDraw.SourceRect.Size);
}
portraitToDraw.Draw(spriteBatch, screenPos + offset, SkinColor, portraitToDraw.Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
portraitToDraw.Draw(spriteBatch, screenPos + offset, skinColor, portraitToDraw.Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
if (attachmentsToDraw != null)
{
float depthStep = 0.000001f;
foreach (var attachment in attachmentsToDraw)
{
SetAttachmentEffect(spriteBatch, attachment);
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, GetAttachmentColor(attachment), flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, GetAttachmentColor(attachment, hairColor, facialHairColor), flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
depthStep += depthStep;
}
}
@@ -516,7 +374,7 @@ namespace Barotrauma
{
headEffectParameters.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
headEffectParameters.Params ??= new Dictionary<string, object>();
headEffectParameters.Params["xBaseTexture"] = headSprite.Texture;
headEffectParameters.Params["xBaseTexture"] = HeadSprite.Texture;
headEffectParameters.Params["xTintMaskTexture"] = tintMask?.Texture ?? GUI.WhiteTexture;
headEffectParameters.Params["xCutoffTexture"] = GUI.WhiteTexture;
headEffectParameters.Params["baseToCutoffSizeRatio"] = 1.0f;
@@ -541,15 +399,15 @@ namespace Barotrauma
spriteBatch.SwapEffect(attachmentEffectParameters[attachment.Type]);
}
private Color GetAttachmentColor(WearableSprite attachment)
private Color GetAttachmentColor(WearableSprite attachment, Color hairColor, Color facialHairColor)
{
switch (attachment.Type)
{
case WearableType.Hair:
return HairColor;
return hairColor;
case WearableType.Beard:
case WearableType.Moustache:
return FacialHairColor;
return facialHairColor;
default:
return Color.White;
}
@@ -574,7 +432,7 @@ namespace Barotrauma
foreach (var attachment in AttachmentSprites)
{
SetAttachmentEffect(spriteBatch, attachment);
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep, GetAttachmentColor(attachment));
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep, GetAttachmentColor(attachment, HairColor, FacialHairColor));
depthStep += depthStep;
}
}
@@ -718,6 +576,7 @@ namespace Barotrauma
private readonly GUIComponent parentComponent;
private readonly List<Sprite> characterSprites = new List<Sprite>();
public GUIButton RandomizeButton;
public AppearanceCustomizationMenu(CharacterInfo info, GUIComponent parent, bool hasIcon = true)
{
@@ -737,13 +596,12 @@ namespace Barotrauma
ClearSprites();
float contentWidth = HasIcon ? 0.75f : 1.0f;
var content =
new GUIListBox(
new RectTransform(new Vector2(contentWidth, 1.0f), parentComponent.RectTransform,
Anchor.CenterLeft))
{ CanBeFocused = false, CanTakeKeyBoardFocus = false }
.Content;
var listBox = new GUIListBox(
new RectTransform(new Vector2(contentWidth, 1.0f), parentComponent.RectTransform,
Anchor.CenterLeft))
{ CanBeFocused = false, CanTakeKeyBoardFocus = false };
var content = listBox.Content;
info.LoadHeadAttachments();
if (HasIcon)
{
@@ -754,7 +612,7 @@ namespace Barotrauma
RectTransform createItemRectTransform(string labelTag, float width = 0.6f)
{
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform));
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.166f), content.RectTransform));
var label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), layoutGroup.RectTransform),
TextManager.Get(labelTag), font: GUI.SubHeadingFont);
@@ -793,6 +651,7 @@ namespace Barotrauma
info.FilterElementsByGenderAndRace(info.Wearables, info.Head.gender, info.Head.race),
wearableType, info.HeadSpriteId).Count();
List<GUIScrollBar> attachmentSliders = new List<GUIScrollBar>();
void createAttachmentSlider(int initialValue, WearableType wearableType)
{
int attachmentCount = countAttachmentsOfType(wearableType);
@@ -812,6 +671,7 @@ namespace Barotrauma
BarSize = 1.0f / (float)(attachmentCount + 1)
};
slider.BarScrollValue = initialValue;
attachmentSliders.Add(slider);
}
}
@@ -869,6 +729,36 @@ namespace Barotrauma
CanBeFocused = false
};
}
var childToSelect = dropdown.ListBox.Content.FindChild(c => (Color)c.UserData == getter());
dropdown.Select(dropdown.ListBox.Content.GetChildIndex(childToSelect));
//The following exists to track mouseover to preview colors before selecting them
bool previewingColor = false;
new GUICustomComponent(new RectTransform(Vector2.One, buttonFrame.RectTransform),
onUpdate: (deltaTime, component) =>
{
if (GUI.MouseOn is GUIFrame { Parent: { } p } hoveredFrame && dropdown.ListBox.Content.IsParentOf(hoveredFrame))
{
previewingColor = true;
Color color = (Color)(dropdown.ListBox.Content.FindChild(c =>
c == hoveredFrame || c.IsParentOf(hoveredFrame))?.UserData ?? dropdown.SelectedData);
setter(color);
buttonFrame.Color = getter();
buttonFrame.HoverColor = getter();
}
else if (previewingColor)
{
setter((Color)dropdown.SelectedData);
buttonFrame.Color = getter();
buttonFrame.HoverColor = getter();
previewingColor = false;
}
}, onDraw: null)
{
CanBeFocused = false,
Visible = true
};
}
if (countAttachmentsOfType(WearableType.Hair) > 0)
@@ -886,28 +776,54 @@ namespace Barotrauma
createColorSelector($"Customization.{nameof(info.SkinColor)}", info.SkinColors, () => info.SkinColor,
(color) => info.SkinColor = color);
RandomizeButton = new GUIButton(new RectTransform(Vector2.One * 0.12f,
parentComponent.RectTransform,
anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
{ RelativeOffset = new Vector2(0.01f, 0.005f) }, style: "RandomizeButton")
{
OnClicked = (button, o) =>
{
var headPreset = info.Heads.Keys.GetRandom(Rand.RandSync.Unsynced);
info.Head.gender = headPreset.Gender;
info.Head.race = headPreset.Race;
info.Head.HeadSpriteId = headPreset.ID;
info.Head.HairIndex = Rand.Int(countAttachmentsOfType(WearableType.Hair), Rand.RandSync.Unsynced);
info.Head.BeardIndex = Rand.Int(countAttachmentsOfType(WearableType.Beard), Rand.RandSync.Unsynced);
info.Head.MoustacheIndex = Rand.Int(countAttachmentsOfType(WearableType.Moustache), Rand.RandSync.Unsynced);
info.Head.FaceAttachmentIndex = Rand.Int(countAttachmentsOfType(WearableType.FaceAttachment), Rand.RandSync.Unsynced);
info.Head.HairColor = info.HairColors.GetRandom(Rand.RandSync.Unsynced);
info.Head.FacialHairColor = info.FacialHairColors.GetRandom(Rand.RandSync.Unsynced);
info.Head.SkinColor = info.SkinColors.GetRandom(Rand.RandSync.Unsynced);
RecreateFrameContents();
info.RefreshHead();
OnHeadSwitch?.Invoke(this);
attachmentSliders.ForEach(s => OnSliderMoved?.Invoke(s, s.BarScroll));
return false;
}
};
//force update twice because the listbox is insanely janky
//TODO: fix all of the UI :)
listBox.ForceUpdate();
listBox.ForceUpdate();
foreach (var childLayoutGroup in listBox.Content.GetAllChildren<GUILayoutGroup>())
{
childLayoutGroup.Recalculate();
}
}
private bool OpenHeadSelection(GUIButton button, object userData)
{
Gender selectedGender = (Gender)userData;
if (HeadSelectionList != null)
{
HeadSelectionList.Visible = true;
foreach (GUIComponent child in HeadSelectionList.Content.Children)
{
child.Visible = (Gender)child.UserData == selectedGender;
child.Children.ForEach(c =>
c.Visible = ((Tuple<Gender, Race, int>)c.UserData).Item1 == selectedGender);
}
return true;
}
var info = CharacterInfo;
float characterHeightWidthRatio = info.HeadSprite.size.Y / info.HeadSprite.size.X;
HeadSelectionList = new GUIListBox(
HeadSelectionList ??= new GUIListBox(
new RectTransform(
new Point(parentComponent.Rect.Width,
(int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)), GUI.Canvas)
@@ -915,6 +831,9 @@ namespace Barotrauma
AbsoluteOffset = new Point(parentComponent.Rect.Right - parentComponent.Rect.Width,
button.Rect.Bottom)
});
HeadSelectionList.Visible = true;
HeadSelectionList.Content.ClearChildren();
ClearSprites();
parentComponent.RectTransform.SizeChanged += () =>
{
@@ -952,15 +871,14 @@ namespace Barotrauma
{
row = null;
itemsInRow = 0;
foreach (var head in heads)
foreach (var kvp in heads.Where(kv => kv.Key.Gender == selectedGender))
{
var headPreset = head.Key;
Gender gender = headPreset.Gender;
var headPreset = kvp.Key;
Race race = headPreset.Race;
int headIndex = headPreset.ID;
string spritePath = spritePathWithTags
.Replace("[GENDER]", gender.ToString().ToLowerInvariant())
.Replace("[GENDER]", selectedGender.ToString().ToLowerInvariant())
.Replace("[RACE]", race.ToString().ToLowerInvariant());
if (!File.Exists(spritePath))
@@ -970,18 +888,18 @@ namespace Barotrauma
Sprite headSprite = new Sprite(headSpriteElement, "", spritePath);
headSprite.SourceRect =
new Rectangle(CharacterInfo.CalculateOffset(headSprite, head.Value.ToPoint()),
new Rectangle(CalculateOffset(headSprite, kvp.Value.ToPoint()),
headSprite.SourceRect.Size);
characterSprites.Add(headSprite);
if (itemsInRow >= 4 || row == null || gender != (Gender)row.UserData)
if (itemsInRow >= 4 || row == null)
{
row = new GUILayoutGroup(
new RectTransform(new Vector2(1.0f, 0.333f), HeadSelectionList.Content.RectTransform),
true)
{
UserData = gender,
Visible = gender == selectedGender
UserData = selectedGender,
Visible = true
};
itemsInRow = 0;
}
@@ -991,10 +909,10 @@ namespace Barotrauma
{
OutlineColor = Color.White * 0.5f,
PressedColor = Color.White * 0.5f,
UserData = new Tuple<Gender, Race, int>(gender, race, headIndex),
UserData = new Tuple<Gender, Race, int>(selectedGender, race, headIndex),
OnClicked = SwitchHead,
Selected = gender == info.Gender && race == info.Race && headIndex == info.HeadSpriteId,
Visible = gender == selectedGender
Selected = selectedGender == info.Gender && race == info.Race && headIndex == info.HeadSpriteId,
Visible = true
};
new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), headSprite, scaleToFit: true);
@@ -1013,7 +931,7 @@ namespace Barotrauma
int id = ((Tuple<Gender, Race, int>)obj).Item3;
info.Gender = gender;
info.Race = race;
info.HeadSpriteId = id;
info.Head.HeadSpriteId = id;
RecreateFrameContents();
OnHeadSwitch?.Invoke(this);
return true;
@@ -66,8 +66,6 @@ namespace Barotrauma
private SpriteSheet medUIExtra;
private float medUIExtraAnimState;
private GUIComponent draggingMed;
private int highlightedLimbIndex = -1;
private int selectedLimbIndex = -1;
private LimbHealth currentDisplayedLimb;
@@ -118,7 +116,6 @@ namespace Barotrauma
if (prevOpenHealthWindow != null)
{
prevOpenHealthWindow.selectedLimbIndex = -1;
prevOpenHealthWindow.highlightedLimbIndex = -1;
}
@@ -207,7 +204,7 @@ namespace Barotrauma
new GUICustomComponent(new RectTransform(new Vector2(0.2f, 1.0f), nameContainer.RectTransform, Anchor.CenterLeft),
onDraw: (spriteBatch, component) =>
{
character.Info?.DrawPortrait(spriteBatch, new Vector2(component.Rect.X, component.Rect.Center.Y - component.Rect.Width / 2), Vector2.Zero, component.Rect.Width, false, openHealthWindow?.Character != Character.Controlled);
character.Info?.DrawPortrait(spriteBatch, new Vector2(component.Rect.X, component.Rect.Center.Y - component.Rect.Width / 2), Vector2.Zero, component.Rect.Width, false, character != Character.Controlled);
});
characterName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), nameContainer.RectTransform), "", textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont)
{
@@ -216,7 +213,7 @@ namespace Barotrauma
new GUICustomComponent(new RectTransform(new Vector2(0.2f, 1.0f), nameContainer.RectTransform),
onDraw: (spriteBatch, component) =>
{
character.Info?.DrawJobIcon(spriteBatch, component.Rect, openHealthWindow?.Character != Character.Controlled);
character.Info?.DrawJobIcon(spriteBatch, component.Rect, character != Character.Controlled);
});
@@ -275,6 +272,34 @@ namespace Barotrauma
}
});
cprButton = new GUIButton(new RectTransform(new Vector2(0.17f, 0.17f), characterIndicatorArea.RectTransform, Anchor.BottomLeft, scaleBasis: ScaleBasis.Smallest), text: "", style: "CPRButton")
{
OnClicked = (button, userData) =>
{
Character selectedCharacter = Character.Controlled?.SelectedCharacter;
if (selectedCharacter == null || (!selectedCharacter.IsUnconscious && selectedCharacter.Stun <= 0.0f))
{
return false;
}
Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ?
AnimController.Animation.None : AnimController.Animation.CPR;
selectedCharacter.AnimController.ResetPullJoints();
if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Treatment });
}
return true;
},
ToolTip = TextManager.Get("doctor.cprobjective"),
IgnoreLayoutGroups = true,
Visible = false
};
var limbSelection = new GUICustomComponent(new RectTransform(new Vector2(0.4f, 1.0f), characterIndicatorArea.RectTransform),
(spriteBatch, component) =>
{
@@ -300,7 +325,7 @@ namespace Barotrauma
deadIndicator.AutoScaleHorizontal = true;
}
afflictionIconContainer = new GUIListBox(new RectTransform(new Vector2(0.25f, 0.7f), characterIndicatorArea.RectTransform), style: null);
afflictionIconContainer = new GUIListBox(new RectTransform(new Vector2(0.25f, 1.0f), characterIndicatorArea.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), healthWindowVerticalLayout.RectTransform),
TextManager.Get("SuitableTreatments"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomCenter);
@@ -324,33 +349,6 @@ namespace Barotrauma
characterIndicatorArea.Recalculate();
cprButton = new GUIButton(new RectTransform(new Vector2(afflictionIconContainer.RectTransform.RelativeSize.X, 0.3f), characterIndicatorArea.RectTransform, Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest), text: "", style: "CPRButton")
{
OnClicked = (button, userData) =>
{
Character selectedCharacter = Character.Controlled?.SelectedCharacter;
if (selectedCharacter == null || (!selectedCharacter.IsUnconscious && selectedCharacter.Stun <= 0.0f))
{
return false;
}
Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ?
AnimController.Animation.None : AnimController.Animation.CPR;
selectedCharacter.AnimController.ResetPullJoints();
if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Treatment });
}
return true;
},
ToolTip = TextManager.Get("doctor.cprobjective"),
IgnoreLayoutGroups = true,
Visible = false
};
healthBarHolder = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas), style: null)
{
HoverCursor = CursorState.Hand
@@ -721,20 +719,19 @@ namespace Barotrauma
foreach (GUIComponent afflictionIcon in afflictionIconContainer.Content.Children)
{
if (!(afflictionIcon.UserData is Affliction affliction)) { continue; }
var btn = afflictionIcon.GetChild<GUIButton>();
if (affliction.AppliedAsFailedTreatmentTime > Timing.TotalTime - 1.0 && btn.FlashTimer <= 0.0f)
if (affliction.AppliedAsFailedTreatmentTime > Timing.TotalTime - 1.0 && afflictionIcon.FlashTimer <= 0.0f)
{
btn.Flash(GUI.Style.Red);
afflictionIcon.Flash(GUI.Style.Red);
}
else if (affliction.AppliedAsSuccessfulTreatmentTime > Timing.TotalTime - 1.0 && btn.FlashTimer <= 0.0f)
else if (affliction.AppliedAsSuccessfulTreatmentTime > Timing.TotalTime - 1.0 && afflictionIcon.FlashTimer <= 0.0f)
{
btn.Flash(GUI.Style.Green);
afflictionIcon.Flash(GUI.Style.Green);
}
}
if (GUI.MouseOn != null && GUI.MouseOn.UserData is string str && str == "selectaffliction")
if (GUI.MouseOn?.UserData is Affliction)
{
Affliction affliction = GUI.MouseOn.Parent.UserData as Affliction;
Affliction affliction = GUI.MouseOn?.UserData as Affliction;
if (afflictionTooltip == null || afflictionTooltip.UserData != affliction)
{
@@ -802,6 +799,8 @@ namespace Barotrauma
currentDisplayedLimb = selectedLimb;
}
UpdateAfflictionInfos(displayedAfflictions.Select(d => d.affliction));
foreach (GUIComponent component in recommendedTreatmentContainer.Content.Children)
{
var treatmentButton = component.GetChild<GUIButton>();
@@ -857,15 +856,6 @@ namespace Barotrauma
selectedLimbIndex = highlightedLimbIndex;
}
}
if (draggingMed != null)
{
if (!PlayerInput.PrimaryMouseButtonHeld())
{
OnItemDropped(draggingMed.UserData as Item, ignoreMousePos: false);
draggingMed = null;
}
}
}
else
{
@@ -1157,8 +1147,6 @@ namespace Barotrauma
{
CreateRecommendedTreatments();
}
UpdateAfflictionInfos(displayedAfflictions.Select(d => d.affliction));
}
private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
@@ -1173,28 +1161,40 @@ namespace Barotrauma
{
displayedAfflictions.Add((affliction, affliction.Strength));
var child = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), afflictionIconContainer.Content.RectTransform, Anchor.TopCenter))
var frame = new GUIButton(new RectTransform(new Vector2(1.0f, 0.25f), afflictionIconContainer.Content.RectTransform), style: "ListBoxElement")
{
Stretch = true,
UserData = affliction
};
var button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.9f), child.RectTransform), style: null)
{
Color = Color.Gray.Multiply(0.1f).Opaque(),
HoverColor = Color.Gray.Multiply(0.4f).Opaque(),
SelectedColor = Color.Gray.Multiply(0.25f).Opaque(),
PressedColor = Color.Gray.Multiply(0.2f).Opaque(),
UserData = "selectaffliction",
UserData = affliction,
OnClicked = SelectAffliction
};
new GUIFrame(new RectTransform(Vector2.One, frame.RectTransform), style: "GUIFrameListBox") { CanBeFocused = false };
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), frame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
CanBeFocused = false
};
var progressbarBg = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.18f), content.RectTransform), 0.0f, GUI.Style.Green, style: "GUIAfflictionBar")
{
UserData = "afflictionstrengthprediction",
CanBeFocused = false
};
new GUIProgressBar(new RectTransform(Vector2.One, progressbarBg.RectTransform), 0.0f, Color.Transparent, showFrame: false, style: "GUIAfflictionBar")
{
UserData = "afflictionstrength",
CanBeFocused = false
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.15f), content.RectTransform), style: null) { CanBeFocused = false };
if (affliction == mostSevereAffliction)
{
buttonToSelect = button;
buttonToSelect = frame;
}
var afflictionIcon = new GUIImage(new RectTransform(Vector2.One * 0.8f, button.RectTransform, Anchor.Center), affliction.Prefab.Icon, scaleToFit: true)
var afflictionIcon = new GUIImage(new RectTransform(Vector2.One * 0.8f, content.RectTransform), affliction.Prefab.Icon, scaleToFit: true)
{
Color = GetAfflictionIconColor(affliction),
CanBeFocused = false
@@ -1203,32 +1203,22 @@ namespace Barotrauma
afflictionIcon.HoverColor = Color.Lerp(afflictionIcon.Color, Color.White, 0.6f);
afflictionIcon.SelectedColor = Color.Lerp(afflictionIcon.Color, Color.White, 0.5f);
float afflictionVitalityDecrease = affliction.GetVitalityDecrease(this);
Color afflictionEffectColor = Color.White;
if (afflictionVitalityDecrease > 0.0f)
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.1f, 0.0f), content.RectTransform),
affliction.Prefab.Name, font: GUI.SmallFont, textAlignment: Alignment.BottomCenter)
{
afflictionEffectColor = GUI.Style.Red;
}
else if (afflictionVitalityDecrease < 0.0f)
{
afflictionEffectColor = GUI.Style.Green;
}
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), child.RectTransform),
affliction.Prefab.Name, font: GUI.SmallFont, textAlignment: Alignment.Center, style: "GUIToolTip");
CanBeFocused = false
};
nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, nameText.Rect.Width);
nameText.RectTransform.MinSize = new Point(0, (int)(nameText.TextSize.Y * 1.25f));
new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.15f), child.RectTransform), 0.0f, afflictionEffectColor, style: "GUIAfflictionBar")
nameText.RectTransform.MinSize = new Point(0, (int)(nameText.TextSize.Y));
nameText.RectTransform.SizeChanged += () =>
{
UserData = "afflictionstrength"
nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, nameText.Rect.Width);
};
child.Recalculate();
content.Recalculate();
}
buttonToSelect?.OnClicked(buttonToSelect, "selectaffliction");
buttonToSelect?.OnClicked(buttonToSelect, buttonToSelect.UserData);
afflictionIconContainer.RecalculateChildren();
}
@@ -1448,11 +1438,52 @@ namespace Barotrauma
private void UpdateAfflictionInfos(IEnumerable<Affliction> afflictions)
{
var potentialTreatment = Inventory.DraggingItems.FirstOrDefault();
if (potentialTreatment == null && GUI.MouseOn?.UserData is ItemPrefab itemPrefab)
{
potentialTreatment = Character.Controlled.Inventory.AllItems.FirstOrDefault(it => it.prefab == itemPrefab);
}
potentialTreatment ??= Inventory.SelectedSlot?.Item;
foreach (Affliction affliction in afflictions)
{
float afflictionVitalityDecrease = affliction.GetVitalityDecrease(this);
Color afflictionEffectColor = Color.White;
if (afflictionVitalityDecrease > 0.0f)
{
afflictionEffectColor = GUI.Style.Red;
}
else if (afflictionVitalityDecrease < 0.0f)
{
afflictionEffectColor = GUI.Style.Green;
}
var child = afflictionIconContainer.Content.FindChild(affliction);
var afflictionStrengthBar = child.GetChildByUserData("afflictionstrength") as GUIProgressBar;
var afflictionStrengthPredictionBar = child.GetChild<GUILayoutGroup>().GetChildByUserData("afflictionstrengthprediction") as GUIProgressBar;
afflictionStrengthPredictionBar.BarSize = 0.0f;
var afflictionStrengthBar = afflictionStrengthPredictionBar.GetChildByUserData("afflictionstrength") as GUIProgressBar;
afflictionStrengthBar.BarSize = affliction.Strength / affliction.Prefab.MaxStrength;
afflictionStrengthBar.Color = afflictionEffectColor;
float afflictionStrengthPrediction = GetAfflictionStrengthPrediction(potentialTreatment, affliction);
if (!MathUtils.NearlyEqual(afflictionStrengthPrediction, affliction.Strength))
{
float t = (float)Math.Max(0.5f, (Math.Sin(Timing.TotalTime * 5) + 1.0f) / 2.0f);
if (afflictionStrengthPrediction < affliction.Strength)
{
afflictionStrengthBar.Color = afflictionEffectColor;
afflictionStrengthPredictionBar.Color = GUI.Style.Blue * t;
afflictionStrengthPredictionBar.BarSize = afflictionStrengthBar.BarSize;
afflictionStrengthBar.BarSize = afflictionStrengthPrediction / affliction.Prefab.MaxStrength;
}
else
{
afflictionStrengthPredictionBar.Color = Color.Red * t;
afflictionStrengthPredictionBar.BarSize = afflictionStrengthPrediction / affliction.Prefab.MaxStrength;
}
}
if (afflictionTooltip != null && afflictionTooltip.UserData == affliction)
{
UpdateAfflictionInfo(afflictionTooltip.Content, affliction);
@@ -1460,6 +1491,32 @@ namespace Barotrauma
}
}
private float GetAfflictionStrengthPrediction(Item item, Affliction affliction)
{
float strength = affliction.Strength;
if (item == null) { return strength; }
foreach (ItemComponent ic in item.Components)
{
if (ic.statusEffectLists == null) { continue; }
if (!ic.statusEffectLists.TryGetValue(ActionType.OnUse, out List<StatusEffect> statusEffects)) { continue; }
foreach (StatusEffect effect in statusEffects)
{
foreach (var reduceAffliction in effect.ReduceAffliction)
{
if (reduceAffliction.affliction != affliction.Identifier && reduceAffliction.affliction != affliction.Prefab.AfflictionType) { continue; }
strength -= reduceAffliction.amount * (effect.Duration > 0 ? effect.Duration : 1.0f);
}
foreach (var addAffliction in effect.Afflictions)
{
if (addAffliction.Prefab != affliction.Prefab) { continue; }
strength += addAffliction.Strength * (effect.Duration > 0 ? effect.Duration : 1.0f);
}
}
}
return strength;
}
private void UpdateAfflictionInfo(GUIComponent parent, Affliction affliction)
{
var labelContainer = parent.GetChildByUserData("label");
@@ -1722,13 +1779,6 @@ namespace Barotrauma
Color.LightGray * 0.5f, width: 4);
}
}
if (draggingMed != null)
{
GUIImage itemImage = draggingMed.GetChild<GUIImage>();
float scale = Math.Min(40.0f / itemImage.Sprite.size.X, 40.0f / itemImage.Sprite.size.Y);
itemImage.Sprite.Draw(spriteBatch, PlayerInput.MousePosition, itemImage.Color, 0, scale);
}
}
private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction, float iconScale, ref Vector2 iconPos)
@@ -679,6 +679,14 @@ namespace Barotrauma
{
clr = clr.Multiply(character.Info.SkinColor);
}
if (character.CharacterHealth.FaceTint.A > 0 && type == LimbType.Head)
{
clr = Color.Lerp(clr, character.CharacterHealth.FaceTint.Opaque(), character.CharacterHealth.FaceTint.A / 255.0f);
}
if (character.CharacterHealth.BodyTint.A > 0)
{
clr = Color.Lerp(clr, character.CharacterHealth.BodyTint.Opaque(), character.CharacterHealth.BodyTint.A / 255.0f);
}
}
Color color = new Color((byte)(clr.R * brightness), (byte)(clr.G * brightness), (byte)(clr.B * brightness), clr.A);
Color blankColor = new Color(brightness, brightness, brightness, 1);
@@ -720,6 +728,7 @@ namespace Barotrauma
}
body.UpdateDrawPosition();
float depthStep = 0.000001f;
if (!hideLimb)
{
@@ -794,7 +803,7 @@ namespace Barotrauma
}
else
{
body.Draw(spriteBatch, conditionalSprite.Sprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
body.Draw(spriteBatch, conditionalSprite.Sprite, color, depth: activeSprite.Depth - (depthStep * 50), Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
}
}
}
@@ -809,7 +818,7 @@ namespace Barotrauma
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
color * Math.Min(damageOverlayStrength, 1.0f), activeSprite.Origin,
-body.DrawRotation,
Scale, spriteEffect, activeSprite.Depth - 0.0000015f);
Scale, spriteEffect, activeSprite.Depth - (depthStep * 90));
}
foreach (var decorativeSprite in DecorativeSprites)
{
@@ -827,9 +836,8 @@ namespace Barotrauma
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
depth: decorativeSprite.Sprite.Depth);
depth: activeSprite.Depth - (depthStep * 100));
}
float depthStep = 0.000001f;
float step = depthStep;
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
if (Params.MirrorHorizontally)
@@ -690,6 +690,7 @@ namespace Barotrauma
AssignRelayToServer("readycheck", true);
AssignRelayToServer("givetalent", true);
AssignRelayToServer("unlocktalents", true);
AssignRelayToServer("giveexperience", true);
AssignOnExecute("control", (string[] args) =>
@@ -1099,9 +1100,35 @@ namespace Barotrauma
commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
{
if (args.Length == 0) return;
SubmarineInfo subInfo = new SubmarineInfo(string.Join(" ", args));
if (args.Length == 0) { return; }
if (GameMain.GameSession != null)
{
ThrowError("The loadsub command cannot be used when a round is running. You should probably be using spawnsub instead.");
return;
}
string name = string.Join(" ", args);
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => name.Equals(s.Name, StringComparison.OrdinalIgnoreCase));
if (subInfo == null)
{
string path = Path.Combine(SubmarineInfo.SavePath, name);
if (!File.Exists(path))
{
ThrowError($"Could not find a submarine with the name \"{name}\" or in the path {path}.");
return;
}
subInfo = new SubmarineInfo(path);
}
Submarine.Load(subInfo, true);
},
() =>
{
return new string[][]
{
SubmarineInfo.SavedSubmarines.Select(s => s.Name).ToArray()
};
}));
commands.Add(new Command("cleansub", "", (string[] args) =>
@@ -0,0 +1,31 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class AlienRuinMission : Mission
{
public override void ClientReadInitial(IReadMessage msg)
{
existingTargets.Clear();
spawnedTargets.Clear();
allTargets.Clear();
ushort existingTargetsCount = msg.ReadUInt16();
for (int i = 0; i < existingTargetsCount; i++)
{
ushort targetId = msg.ReadUInt16();
if (targetId == Entity.NullEntityID) { continue; }
Entity target = Entity.FindEntityByID(targetId);
if (target == null) { continue; }
existingTargets.Add(target);
allTargets.Add(target);
}
ushort spawnedTargetsCount = msg.ReadUInt16();
for (int i = 0; i < spawnedTargetsCount; i++)
{
var enemy = Character.ReadSpawnData(msg);
existingTargets.Add(enemy);
allTargets.Add(enemy);
}
}
}
}
@@ -3,6 +3,7 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace Barotrauma
{
@@ -14,6 +15,10 @@ namespace Barotrauma
get { return shownMessages; }
}
public bool DisplayTargetHudIcons => Prefab.DisplayTargetHudIcons;
public virtual IEnumerable<Entity> HudIconTargets => Enumerable.Empty<Entity>();
public Color GetDifficultyColor()
{
int v = Difficulty ?? MissionPrefab.MinDifficulty;
@@ -92,7 +97,7 @@ namespace Barotrauma
};
}
public void ClientRead(IReadMessage msg)
public virtual void ClientRead(IReadMessage msg)
{
State = msg.ReadInt16();
}
@@ -18,13 +18,54 @@ namespace Barotrauma
private set;
}
public bool DisplayTargetHudIcons
{
get;
private set;
}
public float HudIconMaxDistance
{
get;
private set;
}
public Sprite HudIcon
{
get
{
return hudIcon ?? Icon;
}
}
public Color HudIconColor
{
get
{
return hudIconColor ?? IconColor;
}
}
private Sprite hudIcon;
private Color? hudIconColor;
partial void InitProjSpecific(XElement element)
{
DisplayTargetHudIcons = element.GetAttributeBool("displaytargethudicons", false);
HudIconMaxDistance = element.GetAttributeFloat("hudiconmaxdistance", 1000.0f);
foreach (XElement subElement in element.Elements())
{
if (!subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase)) { continue; }
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
string name = subElement.Name.ToString();
if (name.Equals("icon", StringComparison.OrdinalIgnoreCase))
{
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
}
else if (name.Equals("hudicon", StringComparison.OrdinalIgnoreCase))
{
hudIcon = new Sprite(subElement);
hudIconColor = subElement.GetAttributeColor("color");
}
}
}
}
@@ -0,0 +1,66 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class ScanMission : Mission
{
public override IEnumerable<Entity> HudIconTargets
{
get
{
if (State == 0)
{
return scanTargets.Where(kvp => !kvp.Value).Select(kvp => kvp.Key);
}
else
{
return Enumerable.Empty<Entity>();
}
}
}
public override void ClientReadInitial(IReadMessage msg)
{
startingItems.Clear();
ushort itemCount = msg.ReadUInt16();
for (int i = 0; i < itemCount; i++)
{
startingItems.Add(Item.ReadSpawnData(msg));
}
if (startingItems.Contains(null))
{
throw new Exception($"Error in ScanMission.ClientReadInitial: item list contains null (mission: {Prefab.Identifier})");
}
if (startingItems.Count != itemCount)
{
throw new Exception($"Error in ScanMission.ClientReadInitial: item count does not match the server count ({itemCount} != {startingItems.Count}, mission: {Prefab.Identifier})");
}
scanners.Clear();
GetScanners();
ClientReadScanTargetStatus(msg);
}
public override void ClientRead(IReadMessage msg)
{
base.ClientRead(msg);
ClientReadScanTargetStatus(msg);
}
private void ClientReadScanTargetStatus(IReadMessage msg)
{
scanTargets.Clear();
byte targetsToScan = msg.ReadByte();
for (int i = 0; i < targetsToScan; i++)
{
ushort id = msg.ReadUInt16();
bool scanned = msg.ReadBoolean();
Entity entity = Entity.FindEntityByID(id);
scanTargets.Add(entity as WayPoint, scanned);
}
}
}
}
@@ -627,7 +627,7 @@ namespace Barotrauma
{
if (child == Content || child == ScrollBar || child == ContentBackground) { continue; }
child.AddToGUIUpdateList(ignoreChildren, order);
}
}
}
foreach (GUIComponent child in Content.Children)
@@ -656,7 +656,7 @@ namespace Barotrauma
OnAddedToGUIUpdateList?.Invoke(this);
return;
}
int lastVisible = 0;
for (int i = 0; i < Content.CountChildren; i++)
{
@@ -700,6 +700,8 @@ namespace Barotrauma
}
}
public void ForceUpdate() => Update((float)Timing.Step);
protected override void Update(float deltaTime)
{
if (!Visible) { return; }
@@ -595,10 +595,10 @@ namespace Barotrauma
private string GetPlayerBalanceText() => GetCurrencyFormatted(PlayerMoney);
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList)
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount = 4)
{
var elementHeight = (int)(GUI.yScale * 80);
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, 4 * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, elementCount * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
frame.UserData = "deals";
var dealsGroup = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter);
var dealsHeader = new GUILayoutGroup(new RectTransform(new Point((int)(0.95f * parentList.Content.Rect.Width), elementHeight), parent: dealsGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
@@ -726,6 +726,8 @@ namespace Barotrauma
FilterStoreItems(category, searchBox.Text);
}
int prevDailySpecialCount;
private void RefreshStoreBuyList()
{
float prevBuyListScroll = storeBuyList.BarScroll;
@@ -734,11 +736,14 @@ namespace Barotrauma
bool hasPermissions = HasPermissions;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any())
int dailySpecialCount = CurrentLocation?.DailySpecials.Count() ?? 3;
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any() || dailySpecialCount != prevDailySpecialCount)
{
if (storeDailySpecialsGroup == null)
if (storeDailySpecialsGroup == null || dailySpecialCount != prevDailySpecialCount)
{
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
storeBuyList.RemoveChild(storeDailySpecialsGroup?.Parent);
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList, 1 + dailySpecialCount);
storeDailySpecialsGroup.Parent.SetAsFirstChild();
}
else
@@ -747,6 +752,7 @@ namespace Barotrauma
storeDailySpecialsGroup = null;
}
storeBuyList.RecalculateChildren();
prevDailySpecialCount = dailySpecialCount;
}
foreach (PurchasedItem item in CurrentLocation.StoreStock)
@@ -1320,7 +1320,7 @@ namespace Barotrauma
if (!(characterLayout is null))
{
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomRight);
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("close"))
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
{
OnClicked = (button, o) =>
{
@@ -922,8 +922,7 @@ namespace Barotrauma
}
//open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC
else if ((Character.Controlled == null || !itemHudActive())
//TODO: do we need to check Inventory.SelectedSlot?
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null
&& CharacterHealth.OpenHealthWindow == null
&& !CrewManager.IsCommandInterfaceOpen
&& !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null))
{
@@ -1837,6 +1837,7 @@ namespace Barotrauma
ic.ParseMsg();
}
}
CharacterHUD.ShouldRecreateHudTexts = true;
}
private void ApplySettings()
@@ -1,13 +1,201 @@
using Microsoft.Xna.Framework;
using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.IO;
namespace Barotrauma.Items.Components
{
partial class IdCard
{
public Sprite StoredPortrait;
public Vector2 StoredSheetIndex;
public JobPrefab StoredJobPrefab;
public List<WearableSprite> StoredAttachments;
public struct OwnerAppearance
{
public Sprite Portrait;
public Vector2 SheetIndex;
public JobPrefab JobPrefab;
public List<WearableSprite> Attachments;
public Color HairColor;
public Color FacialHairColor;
public Color SkinColor;
public void ExtractJobPrefab(string[] tags)
{
string jobIdTag = tags.FirstOrDefault(s => s.StartsWith("jobid:"));
if (jobIdTag != null && jobIdTag.Length > 6)
{
string jobId = jobIdTag.Substring(6);
if (jobId != string.Empty)
{
JobPrefab = JobPrefab.Get(jobId);
}
}
}
public void ExtractAppearance(CharacterInfo characterInfo, string[] tags)
{
Gender disguisedGender = Gender.None;
Race disguisedRace = Race.None;
int disguisedHeadSpriteId = -1;
int disguisedHairIndex = -1;
int disguisedBeardIndex = -1;
int disguisedMoustacheIndex = -1;
int disguisedFaceAttachmentIndex = -1;
Color hairColor = Color.Black;
Color facialHairColor = Color.Black;
Color skinColor = Color.Black;
foreach (string tag in tags)
{
string[] s = tag.Split(':');
switch (s[0].ToLowerInvariant())
{
case "haircolor":
hairColor = XMLExtensions.ParseColor(s[1]);
break;
case "facialhaircolor":
facialHairColor = XMLExtensions.ParseColor(s[1]);
break;
case "skincolor":
skinColor = XMLExtensions.ParseColor(s[1]);
break;
case "gender":
Enum.TryParse(s[1], ignoreCase: true, out disguisedGender);
break;
case "race":
Enum.TryParse(s[1], ignoreCase: true, out disguisedRace);
break;
case "headspriteid":
int.TryParse(s[1], NumberStyles.Any, CultureInfo.InvariantCulture, out disguisedHeadSpriteId);
break;
case "hairindex":
disguisedHairIndex = int.Parse(s[1]);
break;
case "beardindex":
disguisedBeardIndex = int.Parse(s[1]);
break;
case "moustacheindex":
disguisedMoustacheIndex = int.Parse(s[1]);
break;
case "faceattachmentindex":
disguisedFaceAttachmentIndex = int.Parse(s[1]);
break;
case "sheetindex":
string[] vectorValues = s[1].Split(";");
SheetIndex = new Vector2(float.Parse(vectorValues[0]), float.Parse(vectorValues[1]));
break;
}
}
if ((characterInfo.HasGenders && disguisedGender == Gender.None)
|| (characterInfo.HasRaces && disguisedRace == Race.None)
|| disguisedHeadSpriteId <= 0)
{
Portrait = null;
Attachments = null;
return;
}
foreach (XElement limbElement in characterInfo.Ragdoll.MainElement.Elements())
{
if (!limbElement.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)) { continue; }
XElement spriteElement = limbElement.Element("sprite");
if (spriteElement == null) { continue; }
string spritePath = spriteElement.Attribute("texture").Value;
spritePath = spritePath.Replace("[GENDER]", disguisedGender.ToString().ToLowerInvariant());
spritePath = spritePath.Replace("[RACE]", disguisedRace.ToString().ToLowerInvariant());
spritePath = spritePath.Replace("[HEADID]", disguisedHeadSpriteId.ToString());
string fileName = Path.GetFileNameWithoutExtension(spritePath);
//go through the files in the directory to find a matching sprite
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
{
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string fileWithoutTags = Path.GetFileNameWithoutExtension(file);
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
if (fileWithoutTags != fileName) { continue; }
Portrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
break;
}
break;
}
if (characterInfo.Wearables != null)
{
float baldnessChance = disguisedGender == Gender.Female ? 0.05f : 0.2f;
List<XElement> createElementList(WearableType wearableType, float emptyCommonness = 1.0f)
=> CharacterInfo.AddEmpty(
characterInfo.FilterByTypeAndHeadID(
characterInfo.FilterElementsByGenderAndRace(characterInfo.Wearables, disguisedGender, disguisedRace),
wearableType, disguisedHeadSpriteId),
wearableType, emptyCommonness);
var disguisedHairs = createElementList(WearableType.Hair, baldnessChance);
var disguisedBeards = createElementList(WearableType.Beard);
var disguisedMoustaches = createElementList(WearableType.Moustache);
var disguisedFaceAttachments = createElementList(WearableType.FaceAttachment);
XElement getElementFromList(List<XElement> list, int index)
=> CharacterInfo.IsValidIndex(index, list)
? list[index]
: characterInfo.GetRandomElement(list);
var disguisedHairElement = getElementFromList(disguisedHairs, disguisedHairIndex);
var disguisedBeardElement = getElementFromList(disguisedBeards, disguisedBeardIndex);
var disguisedMoustacheElement = getElementFromList(disguisedMoustaches, disguisedMoustacheIndex);
var disguisedFaceAttachmentElement = getElementFromList(disguisedFaceAttachments, disguisedFaceAttachmentIndex);
Attachments = new List<WearableSprite>();
void loadAttachments(List<WearableSprite> attachments, XElement element, WearableType wearableType)
{
foreach (var s in element?.Elements("sprite") ?? Enumerable.Empty<XElement>())
{
attachments.Add(new WearableSprite(s, wearableType));
}
}
loadAttachments(Attachments, disguisedFaceAttachmentElement, WearableType.FaceAttachment);
loadAttachments(Attachments, disguisedBeardElement, WearableType.Beard);
loadAttachments(Attachments, disguisedMoustacheElement, WearableType.Moustache);
loadAttachments(Attachments, disguisedHairElement, WearableType.Hair);
loadAttachments(Attachments,
characterInfo.OmitJobInPortraitClothing
? JobPrefab.NoJobElement?.Element("PortraitClothing")
: JobPrefab?.ClothingElement,
WearableType.JobIndicator);
}
HairColor = hairColor;
FacialHairColor = facialHairColor;
SkinColor = skinColor;
}
}
public OwnerAppearance StoredOwnerAppearance = default;
}
}
@@ -289,7 +289,7 @@ namespace Barotrauma.Items.Components
}
else
{
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
Matrix transform = Matrix.CreateRotationZ(item.body.DrawRotation);
if (item.body.Dir == -1.0f)
{
transformedItemPos.X = -transformedItemPos.X;
@@ -300,7 +300,7 @@ namespace Barotrauma.Items.Components
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
transformedItemPos += item.DrawPosition;
transformedItemPos += item.body.DrawPosition;
}
Vector2 currentItemPos = transformedItemPos;
@@ -380,9 +380,20 @@ namespace Barotrauma.Items.Components
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X, slotRect.Bottom - 8, slotRect.Width, 8), Color.Black * 0.8f, true);
DrawConditionBar(spriteBatch, requiredItem.MinCondition);
}
else if (requiredItem.MaxCondition < 1.0f)
{
DrawConditionBar(spriteBatch, requiredItem.MaxCondition);
}
void DrawConditionBar(SpriteBatch sb, float condition)
{
int spacing = GUI.IntScale(4);
int height = GUI.IntScale(10);
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, slotRect.Width - spacing * 2, height), Color.Black * 0.8f, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(slotRect.X, slotRect.Bottom - 8, (int)(slotRect.Width * requiredItem.MinCondition), 8),
new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, (int)((slotRect.Width - spacing * 2) * condition), height),
GUI.Style.Green * 0.8f, true);
}
@@ -395,6 +406,10 @@ namespace Barotrauma.Items.Components
{
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
}
else if(requiredItem.MaxCondition < 1.0f)
{
toolTipText += " 0-" + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
}
else if (requiredItem.MaxCondition <= 0.0f)
{
toolTipText = TextManager.GetWithVariable("displayname.emptyitem", "[itemname]", toolTipText);
@@ -649,8 +664,13 @@ namespace Barotrauma.Items.Components
{
foreach (GUIComponent child in itemList.Content.Children)
{
var itemPrefab = child.UserData as FabricationRecipe;
if (itemPrefab == null) continue;
if (!(child.UserData is FabricationRecipe itemPrefab)) { continue; }
if (itemPrefab != selectedItem &&
(child.Rect.Y > itemList.Rect.Bottom || child.Rect.Bottom < itemList.Rect.Y))
{
continue;
}
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients, character);
if (itemPrefab == selectedItem)
@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
private bool isConnectedToSteering;
private static string caveLabel;
private static string caveLabel, ruinLabel;
private bool AllowUsingMineralScanner =>
HasMineralScanner && !isConnectedToSteering;
@@ -880,7 +880,7 @@ namespace Barotrauma.Items.Components
foreach (AITarget aiTarget in AITarget.List)
{
if (!aiTarget.Enabled) { continue; }
if (aiTarget.InDetectable) { continue; }
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) { continue; }
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
@@ -1234,7 +1234,7 @@ namespace Barotrauma.Items.Components
foreach (AITarget aiTarget in AITarget.List)
{
float disruption = aiTarget.Entity is Character c ? c.Params.SonarDisruption : aiTarget.SonarDisruption;
if (disruption <= 0.0f || !aiTarget.Enabled) { continue; }
if (disruption <= 0.0f || aiTarget.InDetectable) { continue; }
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
if (distSqr > worldPingRadiusSqr) { continue; }
float disruptionDist = (float)Math.Sqrt(distSqr);
@@ -1359,28 +1359,6 @@ namespace Barotrauma.Items.Components
blipType : cell.IsDestructible ? BlipType.Destructible : BlipType.Default);
}
}
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
{
if (!MathUtils.CircleIntersectsRectangle(pingSource, range, ruin.Area)) continue;
foreach (var ruinShape in ruin.RuinShapes)
{
foreach (RuinGeneration.Line wall in ruinShape.Walls)
{
float cellDot = Vector2.Dot(
Vector2.Normalize(ruinShape.Center - pingSource),
Vector2.Normalize((wall.A + wall.B) / 2.0f - ruinShape.Center));
if (cellDot > 0) continue;
CreateBlipsForLine(
wall.A, wall.B,
pingSource, transducerPos,
pingRadius, prevPingRadius,
100.0f, 1000.0f, range, pingStrength, passive);
}
}
}
}
foreach (Item item in Item.ItemList)
@@ -21,6 +21,8 @@ namespace Barotrauma.Items.Components
private GUITextBlock progressBarOverlayText;
private GUILayoutGroup extraButtonContainer;
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
//the corresponding particle emitter is active when the condition is within this range
private readonly List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
@@ -145,10 +147,16 @@ namespace Barotrauma.Items.Components
progressBarHolder.RectTransform.MinSize = RepairButton.RectTransform.MinSize;
RepairButton.RectTransform.MinSize = new Point((int)(RepairButton.TextBlock.TextSize.X * 1.2f), RepairButton.RectTransform.MinSize.Y);
extraButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), isHorizontal: true)
{
IgnoreLayoutGroups = true,
Stretch = true,
AbsoluteSpacing = GUI.IntScale(5)
};
sabotageButtonText = TextManager.Get("SabotageButton");
sabotagingText = TextManager.Get("Sabotaging");
SabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText, style: "GUIButtonSmall")
SabotageButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), sabotageButtonText, style: "GUIButtonSmall")
{
IgnoreLayoutGroups = true,
Visible = false,
@@ -160,9 +168,9 @@ namespace Barotrauma.Items.Components
}
};
tinkerButtonText = "Tinker";
tinkeringText = "Tinkering";
TinkerButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), tinkerButtonText)
tinkerButtonText = TextManager.Get("TinkerButton", returnNull: true) ?? "Tinker";
tinkeringText = TextManager.Get("Tinkering", returnNull: true) ?? "Tinkering";
TinkerButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), tinkerButtonText, style: "GUIButtonSmall")
{
IgnoreLayoutGroups = true,
Visible = false,
@@ -173,6 +181,8 @@ namespace Barotrauma.Items.Components
return true;
}
};
extraButtonContainer.RectTransform.MinSize = new Point(0, SabotageButton.RectTransform.MinSize.Y);
}
partial void UpdateProjSpecific(float deltaTime)
@@ -274,6 +284,10 @@ namespace Barotrauma.Items.Components
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
extraButtonContainer.Visible = SabotageButton.Visible || TinkerButton.Visible;
extraButtonContainer.IgnoreLayoutGroups = !extraButtonContainer.Visible;
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
{
if (!(c.UserData is Skill skill)) continue;
@@ -31,6 +31,9 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize("0.5,0.5)", false)]
public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
public Vector2 DrawSize
{
get
@@ -57,7 +60,6 @@ namespace Barotrauma.Items.Components
sourcePos = sourceLimb.body.DrawPosition;
}
return sourcePos;
}
partial void InitProjSpecific(XElement element)
@@ -87,7 +89,8 @@ namespace Barotrauma.Items.Components
startPos.Y = -startPos.Y;
if (source is Item sourceItem)
{
var turret = sourceItem?.GetComponent<Turret>();
var turret = sourceItem.GetComponent<Turret>();
var weapon = sourceItem.GetComponent<RangedWeapon>();
if (turret != null)
{
startPos = new Vector2(sourceItem.WorldRect.X + turret.TransformedBarrelPos.X, -(sourceItem.WorldRect.Y - turret.TransformedBarrelPos.Y));
@@ -96,8 +99,21 @@ namespace Barotrauma.Items.Components
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
}
}
else if (weapon != null)
{
Vector2 barrelPos = FarseerPhysics.ConvertUnits.ToDisplayUnits(weapon.TransformedBarrelPos);
barrelPos.Y = -barrelPos.Y;
startPos += barrelPos * item.Scale;
}
}
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
Vector2 endPos = new Vector2(target.DrawPosition.X, target.DrawPosition.Y);
Vector2 flippedPos = target.Sprite.size * target.Scale * (Origin - new Vector2(0.5f));
if (target.body.Dir < 0.0f)
{
flippedPos.X = -flippedPos.X;
}
endPos += Vector2.Transform(flippedPos, Matrix.CreateRotationZ(target.body.Rotation));
endPos.Y = -endPos.Y;
if (Snapped)
{
@@ -0,0 +1,29 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class Scanner : ItemComponent, IServerSerializable
{
partial void UpdateProjSpecific()
{
if (Holdable != null && Holdable.Attached && (AlwaysDisplayProgressBar || DisplayProgressBar) && !IsScanCompleted)
{
Character.Controlled?.UpdateHUDProgressBar(this,
item.WorldPosition,
ScanTimer / ScanDuration,
GUI.Style.Red, GUI.Style.Green,
textTag: "progressbar.scanning");
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool wasScanCompletedPreviously = IsScanCompleted;
scanTimer = msg.ReadSingle();
if (!wasScanCompletedPreviously && IsScanCompleted)
{
OnScanCompleted?.Invoke(this);
}
}
}
}
@@ -0,0 +1,114 @@
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class ButtonTerminal : ItemComponent, IClientSerializable, IServerSerializable
{
private string[] terminalButtonStyles;
private GUIFrame containerHolder;
private GUIImage containerIndicator;
private GUIComponentStyle indicatorStyleRed, indicatorStyleGreen;
partial void InitProjSpecific(XElement element)
{
terminalButtonStyles = new string[RequiredSignalCount];
int i = 0;
foreach (var childElement in element.GetChildElements("TerminalButton"))
{
string style = childElement.GetAttributeString("style", null);
if (style == null) { continue; }
terminalButtonStyles[i++] = style;
}
indicatorStyleRed = GUI.Style.GetComponentStyle("IndicatorLightRed");
indicatorStyleGreen = GUI.Style.GetComponentStyle("IndicatorLightGreen");
CreateGUI();
}
protected override void CreateGUI()
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
RelativeSpacing = 0.08f
};
paddedFrame.OnAddedToGUIUpdateList += (component) =>
{
bool buttonsEnabled = AllowUsingButtons;
foreach (var child in component.Children)
{
if (!(child is GUIButton)) { continue; }
if (!(child.UserData is int)) { continue; }
child.Enabled = buttonsEnabled;
child.Children.ForEach(c => c.Enabled = buttonsEnabled);
}
bool itemsContained = Container.Inventory.AllItems.Any();
if (itemsContained)
{
var indicatorStyle = buttonsEnabled ? indicatorStyleGreen : indicatorStyleRed;
if (containerIndicator.Style != indicatorStyle)
{
containerIndicator.ApplyStyle(indicatorStyle);
}
}
containerIndicator.OverrideState = itemsContained ? GUIComponent.ComponentState.Selected : GUIComponent.ComponentState.None;
};
float x = 1.0f / (1 + RequiredSignalCount);
float y = (x * paddedFrame.Rect.Width) / paddedFrame.Rect.Height;
Vector2 relativeSize = new Vector2(x, y);
var containerSection = new GUIFrame(new RectTransform(new Vector2(x, 1.0f), paddedFrame.RectTransform), style: null);
var containerSlot = new GUIFrame(new RectTransform(new Vector2(1.0f, y), containerSection.RectTransform, anchor: Anchor.Center), style: null);
containerHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.2f), containerSlot.RectTransform, Anchor.BottomCenter), style: null);
containerIndicator = new GUIImage(new RectTransform(new Vector2(0.5f, 0.5f * y), containerSection.RectTransform, anchor: Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.05f + 0.5f * y) },
style: "IndicatorLightRed", scaleToFit: true);
for (int i = 0; i < RequiredSignalCount; i++)
{
var button = new GUIButton(new RectTransform(relativeSize, paddedFrame.RectTransform), style: null)
{
UserData = i,
OnClicked = (button, userData) =>
{
if (GameMain.IsSingleplayer)
{
SendSignal((int)userData);
}
else
{
item.CreateClientEvent(this, new object[] { userData });
}
return true;
}
};
var image = new GUIImage(new RectTransform(Vector2.One, button.RectTransform), terminalButtonStyles[i], scaleToFit: true);
}
}
protected override void OnResolutionChanged()
{
base.OnResolutionChanged();
OnItemLoadedProjSpecific();
}
partial void OnItemLoadedProjSpecific()
{
Container.AllowUIOverlap = true;
Container.Inventory.RectTransform = containerHolder.RectTransform;
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
Write(msg, extraData);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), isServerMessage: true);
}
}
}
@@ -276,7 +276,7 @@ namespace Barotrauma
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
float displayCondition = FakeBroken ? 0.0f : condition;
float displayCondition = FakeBroken ? 0.0f : ConditionPercentage;
Vector2 drawOffset = Vector2.Zero;
if (displayCondition < MaxCondition)
{
@@ -326,9 +326,14 @@ namespace Barotrauma
size, color: color,
textureScale: Vector2.One * Scale,
depth: depth);
fadeInBrokenSprite?.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
textureScale: Vector2.One * Scale,
depth: depth - 0.000001f);
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
fadeInBrokenSprite.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
textureScale: Vector2.One * Scale,
depth: d);
}
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
@@ -357,7 +362,11 @@ namespace Barotrauma
if (color.A > 0)
{
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, d);
}
}
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
{
@@ -410,8 +419,11 @@ namespace Barotrauma
}
}
body.Draw(spriteBatch, activeSprite, color, depth, Scale);
if (fadeInBrokenSprite != null) { body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, depth - 0.000001f, Scale); }
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, d, Scale);
}
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
@@ -464,6 +476,11 @@ namespace Barotrauma
if (GameMain.DebugDraw)
{
body?.DebugDraw(spriteBatch, Color.White);
if (GetComponent<TriggerComponent>()?.PhysicsBody is PhysicsBody triggerBody)
{
triggerBody.UpdateDrawPosition();
triggerBody.DebugDraw(spriteBatch, Color.White);
}
}
if (editing && IsSelected && PlayerInput.KeyDown(Keys.Space))
@@ -7,14 +7,9 @@ namespace Barotrauma.RuinGeneration
{
public void DebugDraw(SpriteBatch spriteBatch)
{
foreach (RuinShape shape in allShapes)
{
GUI.DrawString(spriteBatch, new Vector2(shape.Center.X, -shape.Center.Y - 50), shape.DistanceFromEntrance.ToString(), Color.White, Color.Black * 0.5f, font: GUI.LargeFont);
}
foreach (Line line in walls)
{
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), GUI.Style.Red, 0.0f, 10);
}
Rectangle drawRect = Area;
drawRect.Y = -drawRect.Y - Area.Height;
GUI.DrawRectangle(spriteBatch, drawRect, Color.Cyan, false, 0, 6);
}
}
}
@@ -846,16 +846,15 @@ namespace Barotrauma.Lights
if (chList.Submarine == null)
{
list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)));
}
//light is outside, convexhull inside a sub
else
{
Rectangle subBorders = chList.Submarine.Borders;
subBorders.Y -= chList.Submarine.Borders.Height;
if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, subBorders)) continue;
if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, subBorders)) { continue; }
lightPos -= (chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition);
lightPos -= chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition;
list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)));
}
@@ -865,14 +864,6 @@ namespace Barotrauma.Lights
//light is inside, convexhull outside
if (chList.Submarine == null)
{
lightPos += (ParentSub.WorldPosition - ParentSub.HiddenSubPosition);
HashSet<RuinGeneration.Ruin> visibleRuins = new HashSet<RuinGeneration.Ruin>();
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
{
if (!MathUtils.CircleIntersectsRectangle(lightPos, range, ruin.Area)) { continue; }
visibleRuins.Add(ruin);
}
list.AddRange(chList.List.FindAll(ch => ch.ParentEntity?.ParentRuin != null && visibleRuins.Contains(ch.ParentEntity.ParentRuin)));
continue;
}
//light and convexhull are both inside the same sub
@@ -1291,7 +1291,7 @@ namespace Barotrauma.Lights
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
drawPos.Y = -drawPos.Y;
spriteBatch.Draw(currentTexture, drawPos, null, Color.Multiply(CurrentBrightness), -rotation, center, scale, SpriteEffects.None, 1);
spriteBatch.Draw(currentTexture, drawPos, null, Color.Multiply(CurrentBrightness), -rotation + MathHelper.ToRadians(LightSourceParams.Rotation), center, scale, SpriteEffects.None, 1);
return;
}
@@ -178,7 +178,6 @@ namespace Barotrauma
//drawing ----------------------------------------------------
private static readonly HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
private static readonly HashSet<Ruin> visibleRuins = new HashSet<Ruin>();
public static void CullEntities(Camera cam)
{
visibleSubs.Clear();
@@ -198,24 +197,6 @@ namespace Barotrauma
}
}
visibleRuins.Clear();
if (Level.Loaded != null)
{
foreach (Ruin ruin in Level.Loaded.Ruins)
{
Rectangle worldBorders = new Rectangle(
ruin.Area.X - 500,
ruin.Area.Y + ruin.Area.Height + 500,
ruin.Area.Width + 1000,
ruin.Area.Height + 1000);
if (RectsOverlap(worldBorders, cam.WorldView))
{
visibleRuins.Add(ruin);
}
}
}
if (visibleEntities == null)
{
visibleEntities = new List<MapEntity>(MapEntity.mapEntityList.Count);
@@ -232,10 +213,6 @@ namespace Barotrauma
{
if (!visibleSubs.Contains(entity.Submarine)) { continue; }
}
else if (entity.ParentRuin != null)
{
if (!visibleRuins.Contains(entity.ParentRuin)) { continue; }
}
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
}
@@ -600,6 +600,8 @@ namespace Barotrauma
var prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle;
GameMain.Instance.GraphicsDevice.ScissorRectangle = scissorRectangle;
var prevRasterizerState = GameMain.Instance.GraphicsDevice.RasterizerState;
GameMain.Instance.GraphicsDevice.RasterizerState = GameMain.ScissorTestEnable;
spriteRecorder.Render(camera);
@@ -643,6 +645,7 @@ namespace Barotrauma
spriteBatch.End();
GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect;
GameMain.Instance.GraphicsDevice.RasterizerState = prevRasterizerState;
spriteBatch.Begin(SpriteSortMode.Deferred);
}
@@ -171,10 +171,7 @@ namespace Barotrauma
{
foreach (MapEntity e in mapEntityList)
{
if (e.GetType() != typeof(WayPoint)) continue;
if (e == this) continue;
if (!Submarine.RectContains(e.Rect, position)) continue;
if (!(e is WayPoint) || e == this || !e.IsHighlighted) { continue; }
if (linkedTo.Contains(e))
{
@@ -287,7 +287,9 @@ namespace Barotrauma
characterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.275f), subLayout.RectTransform));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), subLayout.RectTransform), job.Name, job.UIColor);
var jobTextContainer =
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), subLayout.RectTransform), style: null);
var jobText = new GUITextBlock(new RectTransform(Vector2.One, jobTextContainer.RectTransform), job.Name, job.UIColor);
var characterName = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), subLayout.RectTransform))
{
@@ -327,8 +329,11 @@ namespace Barotrauma
characterName.Text = characterInfo.Name;
characterName.UserData = "random";
}
StealRandomizeButton(menu, jobTextContainer);
}
};
StealRandomizeButton(CharacterMenus[i], jobTextContainer);
}
}
@@ -381,6 +386,16 @@ namespace Barotrauma
maxMissionCountContainer.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
}
private static void StealRandomizeButton(CharacterInfo.AppearanceCustomizationMenu menu, GUIComponent parent)
{
//This is just stupid
var randomizeButton = menu.RandomizeButton;
var oldButton = parent.GetChild<GUIButton>();
parent.RemoveChild(oldButton);
randomizeButton.RectTransform.Parent = parent.RectTransform;
randomizeButton.RectTransform.RelativeSize = Vector2.One * 1.3f;
}
private bool FinishSetup(GUIButton btn, object userdata)
{
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
@@ -483,21 +483,18 @@ namespace Barotrauma.CharacterEditor
// It's possible that the physics are disabled, because the angle widgets handle input logic in the draw method (which they shouldn't)
character.AnimController.Collider.PhysEnabled = true;
}
if (character.IsHumanoid)
animTestPoseToggle.Enabled = CurrentAnimation.IsGroundedAnimation;
if (animTestPoseToggle.Enabled)
{
animTestPoseToggle.Enabled = CurrentAnimation.IsGroundedAnimation;
if (animTestPoseToggle.Enabled)
if (PlayerInput.KeyHit(Keys.X))
{
if (PlayerInput.KeyHit(Keys.X))
{
SetToggle(animTestPoseToggle, !animTestPoseToggle.Selected);
}
}
else
{
animTestPoseToggle.Selected = false;
SetToggle(animTestPoseToggle, !animTestPoseToggle.Selected);
}
}
else
{
animTestPoseToggle.Selected = false;
}
if (PlayerInput.KeyHit(InputType.Run))
{
// TODO: refactor this horrible hacky index manipulation mess
@@ -1072,7 +1069,7 @@ namespace Barotrauma.CharacterEditor
{
if (jointCreationMode == JointCreationMode.Create)
{
jointEndLimb = GetClosestLimbOnSpritesheet(PlayerInput.MousePosition, l => l != null && l != jointStartLimb && l.ActiveSprite != null);
jointEndLimb = GetClosestLimbOnSpritesheet(PlayerInput.MousePosition, l => l != null && l != jointStartLimb && l.ActiveSprite != null && !l.Hidden);
if (jointEndLimb != null && PlayerInput.PrimaryMouseButtonClicked())
{
Vector2 anchor1 = anchor1Pos.HasValue ? anchor1Pos.Value / spriteSheetZoom : Vector2.Zero;
@@ -1085,7 +1082,7 @@ namespace Barotrauma.CharacterEditor
}
else if (PlayerInput.PrimaryMouseButtonClicked())
{
jointStartLimb = GetClosestLimbOnSpritesheet(PlayerInput.MousePosition, l => selectedLimbs.Contains(l));
jointStartLimb = GetClosestLimbOnSpritesheet(PlayerInput.MousePosition, l => selectedLimbs.Contains(l) && !l.Hidden);
anchor1Pos = GetLimbSpritesheetRect(jointStartLimb).Center.ToVector2() - PlayerInput.MousePosition;
jointCreationMode = JointCreationMode.Create;
}
@@ -1094,7 +1091,7 @@ namespace Barotrauma.CharacterEditor
{
if (jointCreationMode == JointCreationMode.Create)
{
jointEndLimb = GetClosestLimbOnRagdoll(PlayerInput.MousePosition, l => l != null && l != jointStartLimb && l.ActiveSprite != null);
jointEndLimb = GetClosestLimbOnRagdoll(PlayerInput.MousePosition, l => l != null && l != jointStartLimb && l.ActiveSprite != null && !l.Hidden);
if (jointEndLimb != null && PlayerInput.PrimaryMouseButtonClicked())
{
Vector2 anchor1 = anchor1Pos ?? Vector2.Zero;
@@ -1105,7 +1102,7 @@ namespace Barotrauma.CharacterEditor
}
else if (PlayerInput.PrimaryMouseButtonClicked())
{
jointStartLimb = GetClosestLimbOnRagdoll(PlayerInput.MousePosition, l => selectedLimbs.Contains(l));
jointStartLimb = GetClosestLimbOnRagdoll(PlayerInput.MousePosition, l => selectedLimbs.Contains(l) && !l.Hidden);
anchor1Pos = ConvertUnits.ToDisplayUnits(jointStartLimb.body.FarseerBody.GetLocalPoint(ScreenToSim(PlayerInput.MousePosition)));
jointCreationMode = JointCreationMode.Create;
}
@@ -1185,8 +1182,15 @@ namespace Barotrauma.CharacterEditor
private void CreateLimb(XElement newElement)
{
var lastLimbElement = RagdollParams.MainElement.Elements("limb").Last();
lastLimbElement.AddAfterSelf(newElement);
var lastElement = RagdollParams.MainElement.GetChildElements("limb").LastOrDefault();
if (lastElement != null)
{
lastElement.AddAfterSelf(newElement);
}
else
{
RagdollParams.MainElement.AddFirst(newElement);
}
var newLimbParams = new RagdollParams.LimbParams(newElement, RagdollParams);
RagdollParams.Limbs.Add(newLimbParams);
character.AnimController.Recreate();
@@ -1217,12 +1221,7 @@ namespace Barotrauma.CharacterEditor
new XAttribute("limb1anchor", $"{a1.X.Format(2)}, {a1.Y.Format(2)}"),
new XAttribute("limb2anchor", $"{a2.X.Format(2)}, {a2.Y.Format(2)}")
);
var lastJointElement = RagdollParams.MainElement.Elements("joint").LastOrDefault();
if (lastJointElement == null)
{
// If no joints exist, use the last limb element.
lastJointElement = RagdollParams.MainElement.Elements("limb").LastOrDefault();
}
var lastJointElement = RagdollParams.MainElement.GetChildElements("joint").LastOrDefault() ?? RagdollParams.MainElement.GetChildElements("limb").LastOrDefault();
if (lastJointElement == null)
{
DebugConsole.ThrowError(GetCharacterEditorTranslation("CantAddJointsNoLimbElements"));
@@ -2196,7 +2195,7 @@ namespace Barotrauma.CharacterEditor
animTestPoseToggle = new GUITickBox(new RectTransform(toggleSize, layoutGroup.RectTransform), GetCharacterEditorTranslation("AnimationTestPose"))
{
Selected = character.AnimController.AnimationTestPose,
Enabled = character.IsHumanoid,
Enabled = true,
OnSelected = box =>
{
character.AnimController.AnimationTestPose = box.Selected;
@@ -2760,7 +2759,7 @@ namespace Barotrauma.CharacterEditor
return false;
}
#endif
if (!string.IsNullOrEmpty(RagdollParams.Texture) && !File.Exists(RagdollParams.Texture))
if (!character.IsHuman && !string.IsNullOrEmpty(RagdollParams.Texture) && !File.Exists(RagdollParams.Texture))
{
DebugConsole.ThrowError($"Invalid texture path: {RagdollParams.Texture}");
return false;
@@ -3863,7 +3862,7 @@ namespace Barotrauma.CharacterEditor
{
// Head angle
DrawRadialWidget(spriteBatch, SimToScreen(head.SimPosition), animParams.HeadAngle, GetCharacterEditorTranslation("HeadAngle"), Color.White,
angle => TryUpdateAnimParam("headangle", angle), circleRadius: 25, rotationOffset: collider.Rotation + MathHelper.Pi, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
angle => TryUpdateAnimParam("headangle", angle), circleRadius: 25, rotationOffset: -collider.Rotation + head.Params.GetSpriteOrientation() * dir, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
// Head position and leaning
Color color = GUI.Style.Red;
if (animParams.IsGroundedAnimation)
@@ -3972,7 +3971,7 @@ namespace Barotrauma.CharacterEditor
}
// Torso angle
DrawRadialWidget(spriteBatch, SimToScreen(referencePoint), animParams.TorsoAngle, GetCharacterEditorTranslation("TorsoAngle"), Color.White,
angle => TryUpdateAnimParam("torsoangle", angle), rotationOffset: collider.Rotation + MathHelper.Pi, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
angle => TryUpdateAnimParam("torsoangle", angle), rotationOffset: -collider.Rotation + torso.Params.GetSpriteOrientation() * dir, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
Color color = Color.DodgerBlue;
if (animParams.IsGroundedAnimation)
{
@@ -4075,7 +4074,7 @@ namespace Barotrauma.CharacterEditor
if (tail != null && fishParams != null)
{
DrawRadialWidget(spriteBatch, SimToScreen(tail.SimPosition), fishParams.TailAngle, GetCharacterEditorTranslation("TailAngle"), Color.White,
angle => TryUpdateAnimParam("tailangle", angle), circleRadius: 25, rotationOffset: collider.Rotation + MathHelper.Pi, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
angle => TryUpdateAnimParam("tailangle", angle), circleRadius: 25, rotationOffset: -collider.Rotation + tail.Params.GetSpriteOrientation() * dir, clockWise: dir < 0, wrapAnglePi: true, holdPosition: true);
}
// Foot angle
if (foot != null)
@@ -4101,13 +4100,13 @@ namespace Barotrauma.CharacterEditor
fishParams.FootAnglesInRadians[limb.Params.ID] = MathHelper.ToRadians(angle);
TryUpdateAnimParam("footangles", fishParams.FootAngles);
},
circleRadius: 25, rotationOffset: collider.Rotation, clockWise: dir < 0, wrapAnglePi: true, autoFreeze: true);
circleRadius: 25, rotationOffset: -collider.Rotation + limb.Params.GetSpriteOrientation() * dir, clockWise: dir < 0, wrapAnglePi: true, autoFreeze: true);
}
}
else if (humanParams != null)
{
DrawRadialWidget(spriteBatch, SimToScreen(foot.SimPosition), humanParams.FootAngle, GetCharacterEditorTranslation("FootAngle"), Color.White,
angle => TryUpdateAnimParam("footangle", angle), circleRadius: 25, rotationOffset: collider.Rotation + MathHelper.Pi, clockWise: dir < 0, wrapAnglePi: true);
angle => TryUpdateAnimParam("footangle", angle), circleRadius: 25, rotationOffset: -collider.Rotation + foot.Params.GetSpriteOrientation() * dir, clockWise: dir > 0, wrapAnglePi: true);
}
// Grounded only
if (groundedParams != null)
@@ -36,7 +36,7 @@ namespace Barotrauma
private readonly GUITextBox seedBox;
private readonly GUITickBox lightingEnabled, cursorLightEnabled;
private readonly GUITickBox lightingEnabled, cursorLightEnabled, mirrorLevel;
private Sprite editingSprite;
@@ -74,9 +74,7 @@ namespace Barotrauma
ruinParamsList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.1f), paddedLeftPanel.RectTransform));
ruinParamsList.OnSelected += (GUIComponent component, object obj) =>
{
var ruinGenerationParams = obj as RuinGenerationParams;
editorContainer.ClearChildren();
new SerializableEntityEditor(editorContainer.Content.RectTransform, ruinGenerationParams, false, true, elementHeight: 20);
CreateOutpostGenerationParamsEditor(obj as OutpostGenerationParams);
return true;
};
@@ -95,101 +93,7 @@ namespace Barotrauma
outpostParamsList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform));
outpostParamsList.OnSelected += (GUIComponent component, object obj) =>
{
var outpostGenerationParams = obj as OutpostGenerationParams;
editorContainer.ClearChildren();
var outpostParamsEditor = new SerializableEntityEditor(editorContainer.Content.RectTransform, outpostGenerationParams, false, true, elementHeight: 20);
// location type -------------------------
var locationTypeGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, 20)), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform), TextManager.Get("outpostmoduleallowedlocationtypes"), textAlignment: Alignment.CenterLeft);
HashSet<string> availableLocationTypes = new HashSet<string> { "any" };
foreach (LocationType locationType in LocationType.List) { availableLocationTypes.Add(locationType.Identifier); }
var locationTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform),
text: string.Join(", ", outpostGenerationParams.AllowedLocationTypes.Select(lt => TextManager.Capitalize(lt)) ?? "any".ToEnumerable()), selectMultiple: true);
foreach (string locationType in availableLocationTypes)
{
locationTypeDropDown.AddItem(TextManager.Capitalize(locationType), locationType);
if (outpostGenerationParams.AllowedLocationTypes.Contains(locationType))
{
locationTypeDropDown.SelectItem(locationType);
}
}
if (!outpostGenerationParams.AllowedLocationTypes.Any())
{
locationTypeDropDown.SelectItem("any");
}
locationTypeDropDown.OnSelected += (_, __) =>
{
outpostGenerationParams.SetAllowedLocationTypes(locationTypeDropDown.SelectedDataMultiple.Cast<string>());
locationTypeDropDown.Text = ToolBox.LimitString(locationTypeDropDown.Text, locationTypeDropDown.Font, locationTypeDropDown.Rect.Width);
return true;
};
locationTypeGroup.RectTransform.MinSize = new Point(locationTypeGroup.Rect.Width, locationTypeGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(locationTypeGroup, 100);
// module count -------------------------
var moduleLabel = new GUITextBlock(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(70 * GUI.Scale))), TextManager.Get("submarinetype.outpostmodules"), font: GUI.SubHeadingFont);
outpostParamsEditor.AddCustomContent(moduleLabel, 100);
foreach (KeyValuePair<string, int> moduleCount in outpostGenerationParams.ModuleCounts)
{
var moduleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(25 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Key), textAlignment: Alignment.CenterLeft);
new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), GUINumberInput.NumberType.Int)
{
MinValueInt = 0,
MaxValueInt = 100,
IntValue = moduleCount.Value,
OnValueChanged = (numInput) =>
{
outpostGenerationParams.SetModuleCount(moduleCount.Key, numInput.IntValue);
if (numInput.IntValue == 0)
{
outpostParamsList.Select(outpostParamsList.SelectedData);
}
}
};
moduleCountGroup.RectTransform.MinSize = new Point(moduleCountGroup.Rect.Width, moduleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(moduleCountGroup, 100);
}
// add module count -------------------------
var addModuleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(40 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.Center);
HashSet<string> availableFlags = new HashSet<string>();
foreach (string flag in OutpostGenerationParams.Params.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); }
foreach (var sub in SubmarineInfo.SavedSubmarines)
{
if (sub.OutpostModuleInfo == null) { continue; }
foreach (string flag in sub.OutpostModuleInfo.ModuleFlags) { availableFlags.Add(flag); }
}
var moduleTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.8f, 0.8f), addModuleCountGroup.RectTransform),
text: TextManager.Get("leveleditor.addmoduletype"));
foreach (string flag in availableFlags)
{
if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Key.Equals(flag, StringComparison.OrdinalIgnoreCase))) { continue; }
moduleTypeDropDown.AddItem(TextManager.Capitalize(flag), flag);
}
moduleTypeDropDown.OnSelected += (_, userdata) =>
{
outpostGenerationParams.SetModuleCount(userdata as string, 1);
outpostParamsList.Select(outpostParamsList.SelectedData);
return true;
};
addModuleCountGroup.RectTransform.MinSize = new Point(addModuleCountGroup.Rect.Width, addModuleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(addModuleCountGroup, 100);
CreateOutpostGenerationParamsEditor(obj as OutpostGenerationParams);
return true;
};
@@ -239,10 +143,12 @@ namespace Barotrauma
editorContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));
var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform), isHorizontal: true);
var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal: true);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), TextManager.Get("leveleditor.levelseed"));
seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), ToolBox.RandomSeed(8));
mirrorLevel = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), TextManager.Get("mirrorentityx"));
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
TextManager.Get("leveleditor.generate"))
{
@@ -253,7 +159,7 @@ namespace Barotrauma
GameMain.LightManager.ClearLights();
LevelData levelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams);
levelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams;
Level.Generate(levelData, mirror: false);
Level.Generate(levelData, mirror: mirrorLevel.Selected);
GameMain.LightManager.AddLight(pointerLightSource);
if (!wasLevelLoaded || cam.Position.X < 0 || cam.Position.Y < 0 || cam.Position.Y > Level.Loaded.Size.X || cam.Position.Y > Level.Loaded.Size.Y)
{
@@ -408,7 +314,7 @@ namespace Barotrauma
editorContainer.ClearChildren();
ruinParamsList.Content.ClearChildren();
foreach (RuinGenerationParams genParams in RuinGenerationParams.List)
foreach (RuinGenerationParams genParams in RuinGenerationParams.RuinParams)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), ruinParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
genParams.Name)
@@ -500,6 +406,104 @@ namespace Barotrauma
}
}
private void CreateOutpostGenerationParamsEditor(OutpostGenerationParams outpostGenerationParams)
{
editorContainer.ClearChildren();
var outpostParamsEditor = new SerializableEntityEditor(editorContainer.Content.RectTransform, outpostGenerationParams, false, true, elementHeight: 20);
// location type -------------------------
var locationTypeGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, 20)), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform), TextManager.Get("outpostmoduleallowedlocationtypes"), textAlignment: Alignment.CenterLeft);
HashSet<string> availableLocationTypes = new HashSet<string> { "any" };
foreach (LocationType locationType in LocationType.List) { availableLocationTypes.Add(locationType.Identifier); }
var locationTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform),
text: string.Join(", ", outpostGenerationParams.AllowedLocationTypes.Select(lt => TextManager.Capitalize(lt)) ?? "any".ToEnumerable()), selectMultiple: true);
foreach (string locationType in availableLocationTypes)
{
locationTypeDropDown.AddItem(TextManager.Capitalize(locationType), locationType);
if (outpostGenerationParams.AllowedLocationTypes.Contains(locationType))
{
locationTypeDropDown.SelectItem(locationType);
}
}
if (!outpostGenerationParams.AllowedLocationTypes.Any())
{
locationTypeDropDown.SelectItem("any");
}
locationTypeDropDown.OnSelected += (_, __) =>
{
outpostGenerationParams.SetAllowedLocationTypes(locationTypeDropDown.SelectedDataMultiple.Cast<string>());
locationTypeDropDown.Text = ToolBox.LimitString(locationTypeDropDown.Text, locationTypeDropDown.Font, locationTypeDropDown.Rect.Width);
return true;
};
locationTypeGroup.RectTransform.MinSize = new Point(locationTypeGroup.Rect.Width, locationTypeGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(locationTypeGroup, 100);
// module count -------------------------
var moduleLabel = new GUITextBlock(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(70 * GUI.Scale))), TextManager.Get("submarinetype.outpostmodules"), font: GUI.SubHeadingFont);
outpostParamsEditor.AddCustomContent(moduleLabel, 100);
foreach (KeyValuePair<string, int> moduleCount in outpostGenerationParams.ModuleCounts)
{
var moduleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(25 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Key), textAlignment: Alignment.CenterLeft);
new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), GUINumberInput.NumberType.Int)
{
MinValueInt = 0,
MaxValueInt = 100,
IntValue = moduleCount.Value,
OnValueChanged = (numInput) =>
{
outpostGenerationParams.SetModuleCount(moduleCount.Key, numInput.IntValue);
if (numInput.IntValue == 0)
{
outpostParamsList.Select(outpostParamsList.SelectedData);
}
}
};
moduleCountGroup.RectTransform.MinSize = new Point(moduleCountGroup.Rect.Width, moduleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(moduleCountGroup, 100);
}
// add module count -------------------------
var addModuleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(40 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.Center);
HashSet<string> availableFlags = new HashSet<string>();
foreach (string flag in OutpostGenerationParams.Params.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); }
foreach (var sub in SubmarineInfo.SavedSubmarines)
{
if (sub.OutpostModuleInfo == null) { continue; }
foreach (string flag in sub.OutpostModuleInfo.ModuleFlags) { availableFlags.Add(flag); }
}
var moduleTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.8f, 0.8f), addModuleCountGroup.RectTransform),
text: TextManager.Get("leveleditor.addmoduletype"));
foreach (string flag in availableFlags)
{
if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Key.Equals(flag, StringComparison.OrdinalIgnoreCase))) { continue; }
moduleTypeDropDown.AddItem(TextManager.Capitalize(flag), flag);
}
moduleTypeDropDown.OnSelected += (_, userdata) =>
{
outpostGenerationParams.SetModuleCount(userdata as string, 1);
outpostParamsList.Select(outpostParamsList.SelectedData);
return true;
};
addModuleCountGroup.RectTransform.MinSize = new Point(addModuleCountGroup.Rect.Width, addModuleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
outpostParamsEditor.AddCustomContent(addModuleCountGroup, 100);
}
private void CreateLevelObjectEditor(LevelObjectPrefab levelObjectPrefab)
{
editorContainer.ClearChildren();
@@ -435,7 +435,7 @@ namespace Barotrauma
menuTabs[(int)Tab.Settings] = new GUIFrame(new RectTransform(new Vector2(relativeSize.X, 0.8f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing },
style: null);
menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize * new Vector2(1.0f, 1.15f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
CreateCampaignSetupUI();
@@ -982,22 +982,24 @@ namespace Barotrauma
Visible = false,
CanBeFocused = false
};
continue;
}
missionTypeTickBoxes[index] = new GUITickBox(new RectTransform(Vector2.One, frame.RectTransform),
TextManager.Get("MissionType." + missionType.ToString()))
else
{
UserData = (int)missionType,
ToolTip = TextManager.Get("MissionTypeDescription." + missionType.ToString(), returnNull: true),
OnSelected = (tickbox) =>
missionTypeTickBoxes[index] = new GUITickBox(new RectTransform(Vector2.One, frame.RectTransform),
TextManager.Get("MissionType." + missionType.ToString()))
{
int missionTypeOr = tickbox.Selected ? (int)tickbox.UserData : (int)MissionType.None;
int missionTypeAnd = (int)MissionType.All & (!tickbox.Selected ? (~(int)tickbox.UserData) : (int)MissionType.All);
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, (int)missionTypeOr, (int)missionTypeAnd);
return true;
}
};
frame.RectTransform.MinSize = missionTypeTickBoxes[index].RectTransform.MinSize;
UserData = (int)missionType,
ToolTip = TextManager.Get("MissionTypeDescription." + missionType.ToString(), returnNull: true),
OnSelected = (tickbox) =>
{
int missionTypeOr = tickbox.Selected ? (int)tickbox.UserData : (int)MissionType.None;
int missionTypeAnd = (int)MissionType.All & (!tickbox.Selected ? (~(int)tickbox.UserData) : (int)MissionType.All);
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, (int)missionTypeOr, (int)missionTypeAnd);
return true;
}
};
frame.RectTransform.MinSize = missionTypeTickBoxes[index].RectTransform.MinSize;
}
index++;
}
clientDisabledElements.AddRange(missionTypeTickBoxes);
@@ -1428,9 +1430,9 @@ namespace Barotrauma
bool isGameRunning = GameMain.GameSession?.IsRunning ?? false;
infoContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, isGameRunning ? 0.95f : 0.9f), parent.RectTransform, Anchor.BottomCenter), childAnchor: Anchor.TopCenter)
infoContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, isGameRunning ? 0.97f : 0.92f), parent.RectTransform, Anchor.BottomCenter), childAnchor: Anchor.TopCenter)
{
RelativeSpacing = 0.015f,
RelativeSpacing = 0.0f,
Stretch = true,
UserData = characterInfo
};
@@ -1486,21 +1488,24 @@ namespace Barotrauma
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.006f), infoContainer.RectTransform), style: null);
if (allowEditing)
{
GUILayoutGroup characterInfoTabs = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.02f), infoContainer.RectTransform), isHorizontal: true)
GUILayoutGroup characterInfoTabs = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.016f), infoContainer.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.02f
};
jobPreferencesButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.33f), characterInfoTabs.RectTransform),
jobPreferencesButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), characterInfoTabs.RectTransform),
TextManager.Get("JobPreferences"), style: "GUITabButton")
{
Selected = true,
OnClicked = SelectJobPreferencesTab
};
appearanceButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.33f), characterInfoTabs.RectTransform),
appearanceButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), characterInfoTabs.RectTransform),
TextManager.Get("CharacterAppearance"), style: "GUITabButton")
{
OnClicked = SelectAppearanceTab
@@ -1515,7 +1520,7 @@ namespace Barotrauma
JobPreferenceContainer = new GUIFrame(new RectTransform(Vector2.One, characterInfoFrame.RectTransform),
style: "GUIFrameListBox");
characterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter));
characterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0f, 0.025f) });
JobList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.6f), JobPreferenceContainer.RectTransform, Anchor.BottomCenter), true)
{
Enabled = true,
@@ -3191,7 +3196,7 @@ namespace Barotrauma
{
GUICustomComponent characterIcon = JobPreferenceContainer.GetChild<GUICustomComponent>();
JobPreferenceContainer.RemoveChild(characterIcon);
GameMain.Client.CharacterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter));
GameMain.Client.CharacterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.025f) });
GUIListBox listBox = JobPreferenceContainer.GetChild<GUIListBox>();
/*foreach (Sprite sprite in jobPreferenceSprites) { sprite.Remove(); }
@@ -3297,10 +3302,10 @@ namespace Barotrauma
private GUIButton CreateJobVariantButton(Pair<JobPrefab, int> jobPrefab, int variantIndex, int variantCount, GUIComponent slot)
{
float relativeSize = 0.2f;
float relativeSize = 0.15f;
var btn = new GUIButton(new RectTransform(new Vector2(relativeSize), slot.RectTransform, Anchor.TopCenter, scaleBasis: ScaleBasis.BothHeight)
{ RelativeOffset = new Vector2(relativeSize * 1.05f * (variantIndex - (variantCount - 1) / 2.0f), 0.02f) },
{ RelativeOffset = new Vector2(relativeSize * 1.3f * (variantIndex - (variantCount - 1) / 2.0f), 0.02f) },
(variantIndex + 1).ToString(), style: "JobVariantButton")
{
Selected = jobPrefab.Second == variantIndex,
File diff suppressed because it is too large Load Diff
@@ -271,6 +271,21 @@ namespace Barotrauma
}
}
}
else if (newValue is string[] a)
{
for (int i = 0; i < fields.Length; i++)
{
if (i >= a.Length) { break; }
if (fields[i] is GUITextBox textBox)
{
textBox.Text = a[i];
if (flash)
{
textBox.Flash(GUI.Style.Green);
}
}
}
}
}
public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, bool inGame, bool showName, string style = "", int elementHeight = 24, ScalableFont titleFont = null)
@@ -423,6 +438,10 @@ namespace Barotrauma
{
propertyField = CreateRectangleField(entity, property, r, displayName, toolTip);
}
else if(value is string[] a)
{
propertyField = CreateStringArrayField(entity, property, a, displayName, toolTip);
}
return propertyField;
}
@@ -1164,6 +1183,75 @@ namespace Barotrauma
return frame;
}
public GUIComponent CreateStringArrayField(ISerializableEntity entity, SerializableProperty property, string[] value, string displayName, string toolTip)
{
int elementCount = (value.Length + 1);
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, elementCount * elementHeight), layoutGroup.RectTransform, isFixedSize: true), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f / elementCount), frame.RectTransform), displayName, font: GUI.SmallFont)
{
ToolTip = toolTip
};
var editableAttribute = property.GetAttribute<Editable>();
var fields = new GUIComponent[value.Length];
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, (float)(elementCount - 1) / elementCount), frame.RectTransform, anchor: Anchor.BottomLeft))
{
RelativeSpacing = 0.01f
};
elementCount -= 1;
for (int i = 0; i < value.Length; i++)
{
var element = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f / elementCount), inputArea.RectTransform) { MinSize = new Point(50, 0), MaxSize = new Point((int)(0.9f * inputArea.Rect.Width), 50) }, style: null);
var elementLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, element.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
// Set the label to be (i + 1) so it's easier to understand for non-programmers
string componentLabel = (i + 1).ToString();
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), elementLayoutGroup.RectTransform) { MaxSize = new Point(25, elementLayoutGroup.Rect.Height) }, componentLabel, font: GUI.SmallFont, textAlignment: Alignment.Center);
GUITextBox textBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1), elementLayoutGroup.RectTransform), text: value[i]) { Font = GUI.SmallFont };
int comp = i;
textBox.OnEnterPressed += (textBox, text) => OnApply(textBox);
textBox.OnDeselected += (textBox, keys) => OnApply(textBox);
fields[i] = textBox;
bool OnApply(GUITextBox textBox)
{
// Reserve the semicolon for serializing the value
bool containsForbiddenCharacters = textBox.Text.Contains(';');
string[] newValue = (string[])property.GetValue(entity);
if (!containsForbiddenCharacters)
{
newValue[comp] = textBox.Text;
if (SetPropertyValue(property, entity, newValue))
{
TrySendNetworkUpdate(entity, property);
textBox.Flash(color: GUI.Style.Green, flashDuration: 1f);
}
}
else
{
textBox.Text = newValue[comp];
textBox.Flash(color: GUI.Style.Red, flashDuration: 1f);
}
return true;
}
}
refresh += () =>
{
if (fields.None(f => ((GUITextBox)f).Selected))
{
string[] value = (string[])property.GetValue(entity);
for (int i = 0; i < fields.Length; i++)
{
((GUITextBox)fields[i]).Text = value[i];
}
}
};
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Sum(c => c.MinSize.Y));
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
public void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox)
{
var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel") }, new Vector2(0.2f, 0.5f), new Point(300, 400));
@@ -829,7 +829,6 @@ namespace Barotrauma
GameMain.GameSession.EventManager.CurrentIntensity * 100.0f : 0.0f;
IEnumerable<BackgroundMusic> suitableMusic = GetSuitableMusicClips(currentMusicType, currentIntensity);
int mainTrackIndex = 0;
if (suitableMusic.Count() == 0)
{
@@ -861,7 +860,6 @@ namespace Barotrauma
IEnumerable<BackgroundMusic> suitableNoiseLoops = Screen.Selected == GameMain.GameScreen ?
GetSuitableMusicClips(Level.Loaded.LevelData?.Biome?.Identifier, currentIntensity) :
Enumerable.Empty<BackgroundMusic>();
if (suitableNoiseLoops.Count() == 0)
{
targetMusic[noiseLoopIndex] = null;
@@ -877,12 +875,23 @@ namespace Barotrauma
targetMusic[noiseLoopIndex] = null;
}
IEnumerable<BackgroundMusic> suitableTypeAmbiences = GetSuitableMusicClips($"{currentMusicType}ambience", currentIntensity);
int typeAmbienceTrackIndex = 2;
if (suitableTypeAmbiences.None())
{
targetMusic[typeAmbienceTrackIndex] = null;
}
// Switch the type ambience if nothing playing atm or the currently playing clip is not suitable anymore
else if (targetMusic[typeAmbienceTrackIndex] == null || currentMusic[typeAmbienceTrackIndex] == null || !currentMusic[typeAmbienceTrackIndex].IsPlaying() || suitableTypeAmbiences.None(m => m.File == currentMusic[typeAmbienceTrackIndex].Filename))
{
targetMusic[mainTrackIndex] = suitableMusic.GetRandom();
}
//get the appropriate intensity layers for current situation
IEnumerable<BackgroundMusic> suitableIntensityMusic = Screen.Selected == GameMain.GameScreen ?
GetSuitableMusicClips("intensity", currentIntensity) :
Enumerable.Empty<BackgroundMusic>();
int intensityTrackStartIndex = 2;
int intensityTrackStartIndex = 3;
for (int i = intensityTrackStartIndex; i < MaxMusicChannels; i++)
{
//disable targetmusics that aren't suitable anymore
@@ -891,7 +900,6 @@ namespace Barotrauma
targetMusic[i] = null;
}
}
foreach (BackgroundMusic intensityMusic in suitableIntensityMusic)
{
//already playing, do nothing