Unstable 0.1500.4.0 (Shrek edition)
This commit is contained in:
@@ -23,12 +23,30 @@ namespace Barotrauma
|
|||||||
private Sprite disguisedJobIcon;
|
private Sprite disguisedJobIcon;
|
||||||
private Color disguisedJobColor;
|
private Color disguisedJobColor;
|
||||||
|
|
||||||
|
private Sprite tintMask;
|
||||||
|
private float tintHighlightThreshold;
|
||||||
|
private float tintHighlightMultiplier;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.GetDefaultSprite();
|
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.GetDefaultSprite();
|
||||||
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void LoadHeadSpriteProjectSpecific(XElement limbElement)
|
||||||
|
{
|
||||||
|
XElement maskElement = limbElement.Element("tintmask");
|
||||||
|
if (maskElement != null)
|
||||||
|
{
|
||||||
|
string tintMaskPath = maskElement.GetAttributeString("texture", "");
|
||||||
|
if (!string.IsNullOrWhiteSpace(tintMaskPath))
|
||||||
|
{
|
||||||
|
tintMask = new Sprite(maskElement, file: Limb.GetSpritePath(tintMaskPath, this));
|
||||||
|
tintHighlightThreshold = maskElement.GetAttributeFloat("highlightthreshold", 0.6f);
|
||||||
|
tintHighlightMultiplier = maskElement.GetAttributeFloat("highlightmultiplier", 0.8f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null)
|
public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null)
|
||||||
{
|
{
|
||||||
@@ -458,6 +476,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//TODO: disguise skin and hair colors
|
||||||
sheetIndex = disguisedSheetIndex;
|
sheetIndex = disguisedSheetIndex;
|
||||||
portraitToDraw = disguisedPortrait;
|
portraitToDraw = disguisedPortrait;
|
||||||
attachmentsToDraw = disguisedAttachmentSprites;
|
attachmentsToDraw = disguisedAttachmentSprites;
|
||||||
@@ -465,22 +484,74 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (portraitToDraw != null)
|
if (portraitToDraw != null)
|
||||||
{
|
{
|
||||||
|
var currEffect = spriteBatch.GetCurrentEffect();
|
||||||
// Scale down the head sprite 10%
|
// Scale down the head sprite 10%
|
||||||
float scale = targetWidth * 0.9f / Portrait.size.X;
|
float scale = targetWidth * 0.9f / Portrait.size.X;
|
||||||
if (sheetIndex.HasValue)
|
if (sheetIndex.HasValue)
|
||||||
{
|
{
|
||||||
|
SetHeadEffect(spriteBatch);
|
||||||
portraitToDraw.SourceRect = new Rectangle(CalculateOffset(portraitToDraw, sheetIndex.Value.ToPoint()), portraitToDraw.SourceRect.Size);
|
portraitToDraw.SourceRect = new Rectangle(CalculateOffset(portraitToDraw, sheetIndex.Value.ToPoint()), portraitToDraw.SourceRect.Size);
|
||||||
}
|
}
|
||||||
portraitToDraw.Draw(spriteBatch, screenPos + offset, Color.White, 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)
|
if (attachmentsToDraw != null)
|
||||||
{
|
{
|
||||||
float depthStep = 0.000001f;
|
float depthStep = 0.000001f;
|
||||||
foreach (var attachment in attachmentsToDraw)
|
foreach (var attachment in attachmentsToDraw)
|
||||||
{
|
{
|
||||||
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
SetAttachmentEffect(spriteBatch, attachment);
|
||||||
|
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, GetAttachmentColor(attachment), flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||||
depthStep += depthStep;
|
depthStep += depthStep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spriteBatch.SwapEffect(currEffect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: I hate this so much :(
|
||||||
|
private SpriteBatch.EffectWithParams headEffectParameters;
|
||||||
|
private Dictionary<WearableType, SpriteBatch.EffectWithParams> attachmentEffectParameters
|
||||||
|
= new Dictionary<WearableType, SpriteBatch.EffectWithParams>();
|
||||||
|
|
||||||
|
private void SetHeadEffect(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
headEffectParameters.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||||
|
headEffectParameters.Params ??= new Dictionary<string, object>();
|
||||||
|
headEffectParameters.Params["xBaseTexture"] = headSprite.Texture;
|
||||||
|
headEffectParameters.Params["xTintMaskTexture"] = tintMask?.Texture ?? GUI.WhiteTexture;
|
||||||
|
headEffectParameters.Params["xCutoffTexture"] = GUI.WhiteTexture;
|
||||||
|
headEffectParameters.Params["baseToCutoffSizeRatio"] = 1.0f;
|
||||||
|
headEffectParameters.Params["highlightThreshold"] = tintHighlightThreshold;
|
||||||
|
headEffectParameters.Params["highlightMultiplier"] = tintHighlightMultiplier;
|
||||||
|
spriteBatch.SwapEffect(headEffectParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAttachmentEffect(SpriteBatch spriteBatch, WearableSprite attachment)
|
||||||
|
{
|
||||||
|
if (!attachmentEffectParameters.ContainsKey(attachment.Type))
|
||||||
|
{
|
||||||
|
attachmentEffectParameters.Add(attachment.Type, new SpriteBatch.EffectWithParams(GameMain.GameScreen.ThresholdTintEffect, new Dictionary<string, object>()));
|
||||||
|
}
|
||||||
|
var parameters = attachmentEffectParameters[attachment.Type].Params;
|
||||||
|
parameters["xBaseTexture"] = attachment.Sprite.Texture;
|
||||||
|
parameters["xTintMaskTexture"] = GUI.WhiteTexture;
|
||||||
|
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||||
|
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||||
|
parameters["highlightThreshold"] = tintHighlightThreshold;
|
||||||
|
parameters["highlightMultiplier"] = tintHighlightMultiplier;
|
||||||
|
spriteBatch.SwapEffect(attachmentEffectParameters[attachment.Type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color GetAttachmentColor(WearableSprite attachment)
|
||||||
|
{
|
||||||
|
switch (attachment.Type)
|
||||||
|
{
|
||||||
|
case WearableType.Hair:
|
||||||
|
return HairColor;
|
||||||
|
case WearableType.Beard:
|
||||||
|
case WearableType.Moustache:
|
||||||
|
return FacialHairColor;
|
||||||
|
default:
|
||||||
|
return Color.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,34 +560,28 @@ namespace Barotrauma
|
|||||||
var headSprite = HeadSprite;
|
var headSprite = HeadSprite;
|
||||||
if (headSprite != null)
|
if (headSprite != null)
|
||||||
{
|
{
|
||||||
|
var currEffect = spriteBatch.GetCurrentEffect();
|
||||||
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
|
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
|
||||||
if (Head.SheetIndex.HasValue)
|
if (Head.SheetIndex.HasValue)
|
||||||
{
|
{
|
||||||
headSprite.SourceRect = new Rectangle(CalculateOffset(headSprite, Head.SheetIndex.Value.ToPoint()), headSprite.SourceRect.Size);
|
headSprite.SourceRect = new Rectangle(CalculateOffset(headSprite, Head.SheetIndex.Value.ToPoint()), headSprite.SourceRect.Size);
|
||||||
}
|
}
|
||||||
headSprite.Draw(spriteBatch, screenPos, scale: scale);
|
SetHeadEffect(spriteBatch);
|
||||||
|
headSprite.Draw(spriteBatch, screenPos, scale: scale, color: SkinColor);
|
||||||
if (AttachmentSprites != null)
|
if (AttachmentSprites != null)
|
||||||
{
|
{
|
||||||
float depthStep = 0.000001f;
|
float depthStep = 0.000001f;
|
||||||
foreach (var attachment in AttachmentSprites)
|
foreach (var attachment in AttachmentSprites)
|
||||||
{
|
{
|
||||||
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep);
|
SetAttachmentEffect(spriteBatch, attachment);
|
||||||
|
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep, GetAttachmentColor(attachment));
|
||||||
depthStep += depthStep;
|
depthStep += depthStep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spriteBatch.SwapEffect(currEffect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawJobIcon(SpriteBatch spriteBatch, Vector2 pos, float scale = 1.0f, bool evaluateDisguise = false)
|
|
||||||
{
|
|
||||||
if (evaluateDisguise && IsDisguised) return;
|
|
||||||
var icon = !IsDisguisedAsAnother || !evaluateDisguise ? Job?.Prefab?.Icon : disguisedJobIcon;
|
|
||||||
if (icon == null) { return; }
|
|
||||||
Color iconColor = !IsDisguisedAsAnother || !evaluateDisguise ? Job.Prefab.UIColor : disguisedJobColor;
|
|
||||||
|
|
||||||
icon.Draw(spriteBatch, pos, iconColor, scale: scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area, bool evaluateDisguise = false)
|
public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area, bool evaluateDisguise = false)
|
||||||
{
|
{
|
||||||
if (evaluateDisguise && IsDisguised) return;
|
if (evaluateDisguise && IsDisguised) return;
|
||||||
@@ -527,7 +592,7 @@ namespace Barotrauma
|
|||||||
icon.Draw(spriteBatch, area.Center.ToVector2(), iconColor, scale: Math.Min(area.Width / (float)icon.SourceRect.Width, area.Height / (float)icon.SourceRect.Height));
|
icon.Draw(spriteBatch, area.Center.ToVector2(), iconColor, scale: Math.Min(area.Width / (float)icon.SourceRect.Width, area.Height / (float)icon.SourceRect.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2? sheetIndex, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
|
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2? sheetIndex, Vector2 drawPos, float scale, float depthStep, Color? color = null, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||||
{
|
{
|
||||||
if (attachment.InheritSourceRect)
|
if (attachment.InheritSourceRect)
|
||||||
{
|
{
|
||||||
@@ -544,7 +609,7 @@ namespace Barotrauma
|
|||||||
attachment.Sprite.SourceRect = head.SourceRect;
|
attachment.Sprite.SourceRect = head.SourceRect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vector2 origin = attachment.Sprite.Origin;
|
Vector2 origin;
|
||||||
if (attachment.InheritOrigin)
|
if (attachment.InheritOrigin)
|
||||||
{
|
{
|
||||||
origin = head.Origin;
|
origin = head.Origin;
|
||||||
@@ -559,7 +624,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
depth = head.Depth - depthStep;
|
depth = head.Depth - depthStep;
|
||||||
}
|
}
|
||||||
attachment.Sprite.Draw(spriteBatch, drawPos, Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
|
attachment.Sprite.Draw(spriteBatch, drawPos, color ?? Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc)
|
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc)
|
||||||
@@ -574,6 +639,9 @@ namespace Barotrauma
|
|||||||
int beardIndex = inc.ReadByte();
|
int beardIndex = inc.ReadByte();
|
||||||
int moustacheIndex = inc.ReadByte();
|
int moustacheIndex = inc.ReadByte();
|
||||||
int faceAttachmentIndex = inc.ReadByte();
|
int faceAttachmentIndex = inc.ReadByte();
|
||||||
|
Color skinColor = inc.ReadColorR8G8B8();
|
||||||
|
Color hairColor = inc.ReadColorR8G8B8();
|
||||||
|
Color facialHairColor = inc.ReadColorR8G8B8();
|
||||||
string ragdollFile = inc.ReadString();
|
string ragdollFile = inc.ReadString();
|
||||||
|
|
||||||
string jobIdentifier = inc.ReadString();
|
string jobIdentifier = inc.ReadString();
|
||||||
@@ -599,6 +667,9 @@ namespace Barotrauma
|
|||||||
ID = infoID,
|
ID = infoID,
|
||||||
};
|
};
|
||||||
ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||||
|
ch.SkinColor = skinColor;
|
||||||
|
ch.HairColor = hairColor;
|
||||||
|
ch.FacialHairColor = facialHairColor;
|
||||||
if (ch.Job != null)
|
if (ch.Job != null)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, float> skill in skillLevels)
|
foreach (KeyValuePair<string, float> skill in skillLevels)
|
||||||
@@ -627,5 +698,384 @@ namespace Barotrauma
|
|||||||
ch.AdditionalTalentPoints = inc.ReadUInt16();
|
ch.AdditionalTalentPoints = inc.ReadUInt16();
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateIcon(RectTransform rectT)
|
||||||
|
{
|
||||||
|
LoadHeadAttachments();
|
||||||
|
new GUICustomComponent(rectT,
|
||||||
|
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AppearanceCustomizationMenu : IDisposable
|
||||||
|
{
|
||||||
|
public readonly CharacterInfo CharacterInfo;
|
||||||
|
public GUIListBox HeadSelectionList = null;
|
||||||
|
public bool HasIcon = true;
|
||||||
|
|
||||||
|
public GUIScrollBar.OnMovedHandler OnSliderMoved = null;
|
||||||
|
public GUIScrollBar.OnMovedHandler OnSliderReleased = null;
|
||||||
|
public Action<AppearanceCustomizationMenu> OnHeadSwitch = null;
|
||||||
|
|
||||||
|
private readonly GUIComponent parentComponent;
|
||||||
|
private readonly List<Sprite> characterSprites = new List<Sprite>();
|
||||||
|
|
||||||
|
public AppearanceCustomizationMenu(CharacterInfo info, GUIComponent parent, bool hasIcon = true)
|
||||||
|
{
|
||||||
|
CharacterInfo = info;
|
||||||
|
parentComponent = parent;
|
||||||
|
HasIcon = hasIcon;
|
||||||
|
|
||||||
|
RecreateFrameContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecreateFrameContents()
|
||||||
|
{
|
||||||
|
var info = CharacterInfo;
|
||||||
|
|
||||||
|
HeadSelectionList = null;
|
||||||
|
parentComponent.ClearChildren();
|
||||||
|
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;
|
||||||
|
|
||||||
|
info.LoadHeadAttachments();
|
||||||
|
if (HasIcon)
|
||||||
|
{
|
||||||
|
info.CreateIcon(
|
||||||
|
new RectTransform(new Vector2(0.25f, 1.0f), parentComponent.RectTransform, Anchor.CenterRight)
|
||||||
|
{ RelativeOffset = new Vector2(-0.01f, 0.0f) });
|
||||||
|
}
|
||||||
|
|
||||||
|
RectTransform createItemRectTransform(string labelTag, float width = 0.6f)
|
||||||
|
{
|
||||||
|
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform));
|
||||||
|
|
||||||
|
var label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), layoutGroup.RectTransform),
|
||||||
|
TextManager.Get(labelTag), font: GUI.SubHeadingFont);
|
||||||
|
|
||||||
|
var bottomItem = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), layoutGroup.RectTransform),
|
||||||
|
style: null);
|
||||||
|
|
||||||
|
return new RectTransform(new Vector2(width, 1.0f), bottomItem.RectTransform, Anchor.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
RectTransform genderItemRT = createItemRectTransform("Gender", 1.0f);
|
||||||
|
|
||||||
|
GUILayoutGroup genderContainer =
|
||||||
|
new GUILayoutGroup(genderItemRT, isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
void createGenderButton(Gender gender)
|
||||||
|
{
|
||||||
|
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), genderContainer.RectTransform),
|
||||||
|
TextManager.Get(gender.ToString()), style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
UserData = gender,
|
||||||
|
OnClicked = OpenHeadSelection,
|
||||||
|
Selected = info.Gender == gender
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createGenderButton(Gender.Male);
|
||||||
|
createGenderButton(Gender.Female);
|
||||||
|
|
||||||
|
int countAttachmentsOfType(WearableType wearableType)
|
||||||
|
=> info.FilterByTypeAndHeadID(
|
||||||
|
info.FilterElementsByGenderAndRace(info.Wearables, info.Head.gender, info.Head.race),
|
||||||
|
wearableType, info.HeadSpriteId).Count();
|
||||||
|
|
||||||
|
void createAttachmentSlider(int initialValue, WearableType wearableType)
|
||||||
|
{
|
||||||
|
int attachmentCount = countAttachmentsOfType(wearableType);
|
||||||
|
if (attachmentCount > 0)
|
||||||
|
{
|
||||||
|
var labelTag = wearableType == WearableType.FaceAttachment
|
||||||
|
? "FaceAttachment.Accessories"
|
||||||
|
: $"FaceAttachment.{wearableType}";
|
||||||
|
var sliderItemRT = createItemRectTransform(labelTag);
|
||||||
|
var slider =
|
||||||
|
new GUIScrollBar(sliderItemRT, style: "GUISlider")
|
||||||
|
{
|
||||||
|
Range = new Vector2(0, attachmentCount),
|
||||||
|
StepValue = 1,
|
||||||
|
OnMoved = (bar, scroll) => SwitchAttachment(bar, wearableType),
|
||||||
|
OnReleased = OnSliderReleased,
|
||||||
|
BarSize = 1.0f / (float)(attachmentCount + 1)
|
||||||
|
};
|
||||||
|
slider.BarScrollValue = initialValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createAttachmentSlider(info.HairIndex, WearableType.Hair);
|
||||||
|
createAttachmentSlider(info.BeardIndex, WearableType.Beard);
|
||||||
|
createAttachmentSlider(info.MoustacheIndex, WearableType.Moustache);
|
||||||
|
createAttachmentSlider(info.FaceAttachmentIndex, WearableType.FaceAttachment);
|
||||||
|
|
||||||
|
void createColorSelector(string labelTag, IEnumerable<Color> options, Func<Color> getter,
|
||||||
|
Action<Color> setter)
|
||||||
|
{
|
||||||
|
var selectorItemRT = createItemRectTransform(labelTag, 0.4f);
|
||||||
|
var dropdown =
|
||||||
|
new GUIDropDown(selectorItemRT)
|
||||||
|
{ AllowNonText = true };
|
||||||
|
|
||||||
|
var listBoxSize = dropdown.ListBox.RectTransform.RelativeSize;
|
||||||
|
dropdown.ListBox.RectTransform.RelativeSize = new Vector2(listBoxSize.X * 1.75f, listBoxSize.Y);
|
||||||
|
var dropdownButton = dropdown.GetChild<GUIButton>();
|
||||||
|
var buttonFrame =
|
||||||
|
new GUIFrame(
|
||||||
|
new RectTransform(Vector2.One * 0.7f, dropdownButton.RectTransform, Anchor.CenterLeft)
|
||||||
|
{ RelativeOffset = new Vector2(0.05f, 0.0f) }, style: null);
|
||||||
|
dropdown.OnSelected = (component, color) =>
|
||||||
|
{
|
||||||
|
setter((Color)color);
|
||||||
|
buttonFrame.Color = getter();
|
||||||
|
buttonFrame.HoverColor = getter();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
buttonFrame.Color = getter();
|
||||||
|
buttonFrame.HoverColor = getter();
|
||||||
|
|
||||||
|
dropdown.ListBox.UseGridLayout = true;
|
||||||
|
foreach (var option in options)
|
||||||
|
{
|
||||||
|
var optionElement =
|
||||||
|
new GUIFrame(
|
||||||
|
new RectTransform(new Vector2(0.25f, 1.0f / 3.0f),
|
||||||
|
dropdown.ListBox.Content.RectTransform),
|
||||||
|
style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
UserData = option,
|
||||||
|
CanBeFocused = true
|
||||||
|
};
|
||||||
|
var colorElement =
|
||||||
|
new GUIFrame(
|
||||||
|
new RectTransform(Vector2.One * 0.75f, optionElement.RectTransform, Anchor.Center,
|
||||||
|
scaleBasis: ScaleBasis.Smallest),
|
||||||
|
style: null)
|
||||||
|
{
|
||||||
|
Color = option,
|
||||||
|
HoverColor = option,
|
||||||
|
OutlineColor = Color.Lerp(Color.Black, option, 0.5f),
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countAttachmentsOfType(WearableType.Hair) > 0)
|
||||||
|
{
|
||||||
|
createColorSelector($"Customization.{nameof(info.HairColor)}", info.HairColors,
|
||||||
|
() => info.HairColor, (color) => info.HairColor = color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countAttachmentsOfType(WearableType.Moustache) > 0 ||
|
||||||
|
countAttachmentsOfType(WearableType.Beard) > 0)
|
||||||
|
{
|
||||||
|
createColorSelector($"Customization.{nameof(info.FacialHairColor)}", info.FacialHairColors,
|
||||||
|
() => info.FacialHairColor, (color) => info.FacialHairColor = color);
|
||||||
|
}
|
||||||
|
|
||||||
|
createColorSelector($"Customization.{nameof(info.SkinColor)}", info.SkinColors, () => info.SkinColor,
|
||||||
|
(color) => info.SkinColor = color);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
new RectTransform(
|
||||||
|
new Point(parentComponent.Rect.Width,
|
||||||
|
(int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)), GUI.Canvas)
|
||||||
|
{
|
||||||
|
AbsoluteOffset = new Point(parentComponent.Rect.Right - parentComponent.Rect.Width,
|
||||||
|
button.Rect.Bottom)
|
||||||
|
});
|
||||||
|
|
||||||
|
parentComponent.RectTransform.SizeChanged += () =>
|
||||||
|
{
|
||||||
|
if (parentComponent == null || HeadSelectionList?.RectTransform == null || button == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeadSelectionList.RectTransform.Resize(new Point(parentComponent.Rect.Width,
|
||||||
|
(int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)));
|
||||||
|
HeadSelectionList.RectTransform.AbsoluteOffset =
|
||||||
|
new Point(parentComponent.Rect.Right - parentComponent.Rect.Width, button.Rect.Bottom);
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUIFrame(
|
||||||
|
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.RectTransform, Anchor.Center),
|
||||||
|
style: "OuterGlow", color: Color.Black)
|
||||||
|
{
|
||||||
|
UserData = "outerglow",
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
GUILayoutGroup row = null;
|
||||||
|
int itemsInRow = 0;
|
||||||
|
|
||||||
|
XElement headElement = info.Ragdoll.MainElement.Elements().FirstOrDefault(e =>
|
||||||
|
e.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase));
|
||||||
|
XElement headSpriteElement = headElement.Element("sprite");
|
||||||
|
string spritePathWithTags = headSpriteElement.Attribute("texture").Value;
|
||||||
|
|
||||||
|
var characterConfigElement = info.CharacterConfigElement;
|
||||||
|
|
||||||
|
var heads = info.Heads;
|
||||||
|
if (heads != null)
|
||||||
|
{
|
||||||
|
row = null;
|
||||||
|
itemsInRow = 0;
|
||||||
|
foreach (var head in heads)
|
||||||
|
{
|
||||||
|
var headPreset = head.Key;
|
||||||
|
Gender gender = headPreset.Gender;
|
||||||
|
Race race = headPreset.Race;
|
||||||
|
int headIndex = headPreset.ID;
|
||||||
|
|
||||||
|
string spritePath = spritePathWithTags
|
||||||
|
.Replace("[GENDER]", gender.ToString().ToLowerInvariant())
|
||||||
|
.Replace("[RACE]", race.ToString().ToLowerInvariant());
|
||||||
|
|
||||||
|
if (!File.Exists(spritePath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite headSprite = new Sprite(headSpriteElement, "", spritePath);
|
||||||
|
headSprite.SourceRect =
|
||||||
|
new Rectangle(CharacterInfo.CalculateOffset(headSprite, head.Value.ToPoint()),
|
||||||
|
headSprite.SourceRect.Size);
|
||||||
|
characterSprites.Add(headSprite);
|
||||||
|
|
||||||
|
if (itemsInRow >= 4 || row == null || gender != (Gender)row.UserData)
|
||||||
|
{
|
||||||
|
row = new GUILayoutGroup(
|
||||||
|
new RectTransform(new Vector2(1.0f, 0.333f), HeadSelectionList.Content.RectTransform),
|
||||||
|
true)
|
||||||
|
{
|
||||||
|
UserData = gender,
|
||||||
|
Visible = gender == selectedGender
|
||||||
|
};
|
||||||
|
itemsInRow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var btn = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), row.RectTransform),
|
||||||
|
style: "ListBoxElementSquare")
|
||||||
|
{
|
||||||
|
OutlineColor = Color.White * 0.5f,
|
||||||
|
PressedColor = Color.White * 0.5f,
|
||||||
|
UserData = new Tuple<Gender, Race, int>(gender, race, headIndex),
|
||||||
|
OnClicked = SwitchHead,
|
||||||
|
Selected = gender == info.Gender && race == info.Race && headIndex == info.HeadSpriteId,
|
||||||
|
Visible = gender == selectedGender
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), headSprite, scaleToFit: true);
|
||||||
|
itemsInRow++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SwitchHead(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
var info = CharacterInfo;
|
||||||
|
Gender gender = ((Tuple<Gender, Race, int>)obj).Item1;
|
||||||
|
Race race = ((Tuple<Gender, Race, int>)obj).Item2;
|
||||||
|
int id = ((Tuple<Gender, Race, int>)obj).Item3;
|
||||||
|
info.Gender = gender;
|
||||||
|
info.Race = race;
|
||||||
|
info.HeadSpriteId = id;
|
||||||
|
RecreateFrameContents();
|
||||||
|
OnHeadSwitch?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SwitchAttachment(GUIScrollBar scrollBar, WearableType type)
|
||||||
|
{
|
||||||
|
var info = CharacterInfo;
|
||||||
|
int index = (int)scrollBar.BarScrollValue;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case WearableType.Beard:
|
||||||
|
info.BeardIndex = index;
|
||||||
|
break;
|
||||||
|
case WearableType.FaceAttachment:
|
||||||
|
info.FaceAttachmentIndex = index;
|
||||||
|
break;
|
||||||
|
case WearableType.Hair:
|
||||||
|
info.HairIndex = index;
|
||||||
|
break;
|
||||||
|
case WearableType.Moustache:
|
||||||
|
info.MoustacheIndex = index;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DebugConsole.ThrowError($"Wearable type not implemented: {type}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.RefreshHead();
|
||||||
|
OnSliderMoved?.Invoke(scrollBar, scrollBar.BarScroll);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (HeadSelectionList != null && PlayerInput.PrimaryMouseButtonDown() &&
|
||||||
|
!GUI.IsMouseOn(HeadSelectionList))
|
||||||
|
{
|
||||||
|
HeadSelectionList.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
HeadSelectionList?.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearSprites()
|
||||||
|
{
|
||||||
|
foreach (Sprite sprite in characterSprites) { sprite.Remove(); }
|
||||||
|
characterSprites.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ClearSprites();
|
||||||
|
}
|
||||||
|
|
||||||
|
~AppearanceCustomizationMenu()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -601,8 +601,13 @@ namespace Barotrauma
|
|||||||
.FindAll(a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
|
.FindAll(a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
|
||||||
currentDisplayedAfflictions.Sort((a1, a2) =>
|
currentDisplayedAfflictions.Sort((a1, a2) =>
|
||||||
{
|
{
|
||||||
int dmgPerSecond = Math.Sign(a2.DamagePerSecond - a1.DamagePerSecond);
|
int dmgPerSecond = Math.Sign(a1.DamagePerSecond - a2.DamagePerSecond);
|
||||||
return dmgPerSecond != 0 ? dmgPerSecond : Math.Sign(a1.Strength - a1.Strength);
|
if (dmgPerSecond != 0) { return dmgPerSecond; }
|
||||||
|
return Math.Sign(GetStr(a1) - GetStr(a2));
|
||||||
|
static float GetStr(Affliction affliction)
|
||||||
|
{
|
||||||
|
return affliction.Strength / affliction.Prefab.MaxStrength * (affliction.Prefab.IsBuff ? 1.0f : 10.0f);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
HintManager.OnAfflictionDisplayed(Character, currentDisplayedAfflictions);
|
HintManager.OnAfflictionDisplayed(Character, currentDisplayedAfflictions);
|
||||||
updateDisplayedAfflictionsTimer = UpdateDisplayedAfflictionsInterval;
|
updateDisplayedAfflictionsTimer = UpdateDisplayedAfflictionsInterval;
|
||||||
@@ -1131,6 +1136,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static Color GetAfflictionIconColor(Affliction affliction) => GetAfflictionIconColor(affliction.Prefab, affliction);
|
public static Color GetAfflictionIconColor(Affliction affliction) => GetAfflictionIconColor(affliction.Prefab, affliction);
|
||||||
|
|
||||||
|
private readonly List<(Affliction affliction, float strength)> displayedAfflictions = new List<(Affliction affliction, float strength)>();
|
||||||
|
|
||||||
private void UpdateAfflictionContainer(LimbHealth selectedLimb)
|
private void UpdateAfflictionContainer(LimbHealth selectedLimb)
|
||||||
{
|
{
|
||||||
if (selectedLimb == null)
|
if (selectedLimb == null)
|
||||||
@@ -1139,45 +1146,33 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
|
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
|
||||||
var displayedAfflictions = afflictionIconContainer.Content.Children.Select(c => c.UserData as Affliction);
|
if (currentAfflictions.Any(a => !displayedAfflictions.Any(d => d.affliction == a)) ||
|
||||||
if (currentAfflictions.Any(a => !displayedAfflictions.Contains(a)) ||
|
displayedAfflictions.Any(a => !currentAfflictions.Contains(a.affliction)))
|
||||||
displayedAfflictions.Any(a => !currentAfflictions.Contains(a)))
|
|
||||||
{
|
{
|
||||||
CreateAfflictionInfos(currentAfflictions);
|
CreateAfflictionInfos(currentAfflictions);
|
||||||
|
CreateRecommendedTreatments();
|
||||||
|
}
|
||||||
|
//update recommended treatments if the strength of some displayed affliction has changed by > 1
|
||||||
|
else if (displayedAfflictions.Any(d => Math.Abs(d.strength - currentAfflictions.First(a => a == d.affliction).Strength) > 1.0f))
|
||||||
|
{
|
||||||
|
CreateRecommendedTreatments();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAfflictionInfos(displayedAfflictions);
|
UpdateAfflictionInfos(displayedAfflictions.Select(d => d.affliction));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
|
private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
|
||||||
{
|
{
|
||||||
afflictionIconContainer.ClearChildren();
|
afflictionIconContainer.ClearChildren();
|
||||||
recommendedTreatmentContainer.Content.ClearChildren();
|
displayedAfflictions.Clear();
|
||||||
|
|
||||||
float characterSkillLevel = Character.Controlled == null ? 0.0f : Character.Controlled.GetSkillLevel("medical");
|
|
||||||
|
|
||||||
//key = item identifier
|
|
||||||
//float = suitability
|
|
||||||
Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
|
|
||||||
GetSuitableTreatments(treatmentSuitability,
|
|
||||||
normalize: true,
|
|
||||||
ignoreHiddenAfflictions: true,
|
|
||||||
limb: selectedLimbIndex == -1 ? null : Character.AnimController.Limbs.Find(l => l.HealthIndex == selectedLimbIndex));
|
|
||||||
|
|
||||||
foreach (string treatment in treatmentSuitability.Keys.ToList())
|
|
||||||
{
|
|
||||||
//prefer suggestions for items the player has
|
|
||||||
if (Character.Controlled.Inventory.FindItemByIdentifier(treatment) != null)
|
|
||||||
{
|
|
||||||
treatmentSuitability[treatment] *= 10.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions).FirstOrDefault();
|
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions).FirstOrDefault();
|
||||||
GUIButton buttonToSelect = null;
|
GUIButton buttonToSelect = null;
|
||||||
|
|
||||||
foreach (Affliction affliction in afflictions)
|
foreach (Affliction affliction in afflictions)
|
||||||
{
|
{
|
||||||
|
displayedAfflictions.Add((affliction, affliction.Strength));
|
||||||
|
|
||||||
var child = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), afflictionIconContainer.Content.RectTransform, Anchor.TopCenter))
|
var child = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), afflictionIconContainer.Content.RectTransform, Anchor.TopCenter))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
@@ -1233,6 +1228,39 @@ namespace Barotrauma
|
|||||||
child.Recalculate();
|
child.Recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buttonToSelect?.OnClicked(buttonToSelect, "selectaffliction");
|
||||||
|
afflictionIconContainer.RecalculateChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateRecommendedTreatments()
|
||||||
|
{
|
||||||
|
ItemPrefab prevHighlightedItem = null;
|
||||||
|
if (GUI.MouseOn?.UserData is ItemPrefab && recommendedTreatmentContainer.Content.IsParentOf(GUI.MouseOn))
|
||||||
|
{
|
||||||
|
prevHighlightedItem = (ItemPrefab)GUI.MouseOn.UserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
recommendedTreatmentContainer.Content.ClearChildren();
|
||||||
|
|
||||||
|
float characterSkillLevel = Character.Controlled == null ? 0.0f : Character.Controlled.GetSkillLevel("medical");
|
||||||
|
|
||||||
|
//key = item identifier
|
||||||
|
//float = suitability
|
||||||
|
Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
|
||||||
|
GetSuitableTreatments(treatmentSuitability,
|
||||||
|
normalize: true,
|
||||||
|
ignoreHiddenAfflictions: true,
|
||||||
|
limb: selectedLimbIndex == -1 ? null : Character.AnimController.Limbs.Find(l => l.HealthIndex == selectedLimbIndex));
|
||||||
|
|
||||||
|
foreach (string treatment in treatmentSuitability.Keys.ToList())
|
||||||
|
{
|
||||||
|
//prefer suggestions for items the player has
|
||||||
|
if (Character.Controlled.Inventory.FindItemByIdentifier(treatment) != null)
|
||||||
|
{
|
||||||
|
treatmentSuitability[treatment] *= 10.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!treatmentSuitability.Any())
|
if (!treatmentSuitability.Any())
|
||||||
{
|
{
|
||||||
new GUITextBlock(new RectTransform(Vector2.One, recommendedTreatmentContainer.Content.RectTransform), TextManager.Get("none"), textAlignment: Alignment.Center)
|
new GUITextBlock(new RectTransform(Vector2.One, recommendedTreatmentContainer.Content.RectTransform), TextManager.Get("none"), textAlignment: Alignment.Center)
|
||||||
@@ -1248,10 +1276,6 @@ namespace Barotrauma
|
|||||||
recommendedTreatmentContainer.AutoHideScrollBar = true;
|
recommendedTreatmentContainer.AutoHideScrollBar = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonToSelect?.OnClicked(buttonToSelect, "selectaffliction");
|
|
||||||
|
|
||||||
afflictionIconContainer.RecalculateChildren();
|
|
||||||
|
|
||||||
List<KeyValuePair<string, float>> treatmentSuitabilities = treatmentSuitability.OrderByDescending(t => t.Value).ToList();
|
List<KeyValuePair<string, float>> treatmentSuitabilities = treatmentSuitability.OrderByDescending(t => t.Value).ToList();
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -1286,7 +1310,7 @@ namespace Barotrauma
|
|||||||
new GUIImage(new RectTransform(Vector2.One, innerFrame.RectTransform, Anchor.Center), style: "TalentBackgroundGlow")
|
new GUIImage(new RectTransform(Vector2.One, innerFrame.RectTransform, Anchor.Center), style: "TalentBackgroundGlow")
|
||||||
{
|
{
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
Color = Color.White * 0.7f,
|
Color = GUI.Style.Green,
|
||||||
HoverColor = Color.White,
|
HoverColor = Color.White,
|
||||||
PressedColor = Color.DarkGray,
|
PressedColor = Color.DarkGray,
|
||||||
SelectedColor = Color.Transparent,
|
SelectedColor = Color.Transparent,
|
||||||
@@ -1304,6 +1328,12 @@ namespace Barotrauma
|
|||||||
SelectedColor = itemColor,
|
SelectedColor = itemColor,
|
||||||
DisabledColor = itemColor * 0.8f
|
DisabledColor = itemColor * 0.8f
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (item == prevHighlightedItem)
|
||||||
|
{
|
||||||
|
innerFrame.State = GUIComponent.ComponentState.Hover;
|
||||||
|
innerFrame.Children.ForEach(c => c.State = GUIComponent.ComponentState.Hover);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recommendedTreatmentContainer.RecalculateChildren();
|
recommendedTreatmentContainer.RecalculateChildren();
|
||||||
@@ -1315,6 +1345,19 @@ namespace Barotrauma
|
|||||||
int dmgPerSecond = Math.Sign(second.DamagePerSecond - first.DamagePerSecond);
|
int dmgPerSecond = Math.Sign(second.DamagePerSecond - first.DamagePerSecond);
|
||||||
return dmgPerSecond != 0 ? dmgPerSecond : Math.Sign(second.Strength - first.Strength);
|
return dmgPerSecond != 0 ? dmgPerSecond : Math.Sign(second.Strength - first.Strength);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
var treatmentIconSize = recommendedTreatmentContainer.Content.Children.Sum(c => c.Rect.Width + recommendedTreatmentContainer.Spacing);
|
||||||
|
if (treatmentIconSize < recommendedTreatmentContainer.Content.Rect.Width)
|
||||||
|
{
|
||||||
|
var spacing = new GUIFrame(new RectTransform(new Point((recommendedTreatmentContainer.Content.Rect.Width - treatmentIconSize) / 2, 0), recommendedTreatmentContainer.Content.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
spacing.RectTransform.SetAsFirstChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateAfflictionInfoElements(GUIComponent parent, Affliction affliction)
|
private void CreateAfflictionInfoElements(GUIComponent parent, Affliction affliction)
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ namespace Barotrauma
|
|||||||
public List<SpriteDeformation> ActiveDeformations { get; set; } = new List<SpriteDeformation>();
|
public List<SpriteDeformation> ActiveDeformations { get; set; } = new List<SpriteDeformation>();
|
||||||
|
|
||||||
public Sprite Sprite { get; protected set; }
|
public Sprite Sprite { get; protected set; }
|
||||||
|
public Sprite TintMask { get; protected set; }
|
||||||
|
|
||||||
|
public Sprite HuskMask { get; protected set; }
|
||||||
|
public float TintHighlightThreshold { get; protected set; }
|
||||||
|
public float TintHighlightMultiplier { get; protected set; }
|
||||||
|
|
||||||
|
private SpriteBatch.EffectWithParams tintEffectParams;
|
||||||
|
private SpriteBatch.EffectWithParams huskSpriteParams;
|
||||||
|
|
||||||
|
|
||||||
protected DeformableSprite _deformSprite;
|
protected DeformableSprite _deformSprite;
|
||||||
|
|
||||||
@@ -273,6 +282,7 @@ namespace Barotrauma
|
|||||||
DecorativeSpriteGroups[groupID].Add(decorativeSprite);
|
DecorativeSpriteGroups[groupID].Add(decorativeSprite);
|
||||||
spriteAnimState.Add(decorativeSprite, new SpriteState());
|
spriteAnimState.Add(decorativeSprite, new SpriteState());
|
||||||
}
|
}
|
||||||
|
TintMask = null;
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
@@ -308,6 +318,22 @@ namespace Barotrauma
|
|||||||
InitialLightSourceColor = LightSource.Color;
|
InitialLightSourceColor = LightSource.Color;
|
||||||
InitialLightSpriteAlpha = LightSource.OverrideLightSpriteAlpha;
|
InitialLightSpriteAlpha = LightSource.OverrideLightSpriteAlpha;
|
||||||
break;
|
break;
|
||||||
|
case "tintmask":
|
||||||
|
string tintMaskPath = subElement.GetAttributeString("texture", "");
|
||||||
|
if (!string.IsNullOrWhiteSpace(tintMaskPath))
|
||||||
|
{
|
||||||
|
TintMask = new Sprite(subElement, file: GetSpritePath(tintMaskPath));
|
||||||
|
TintHighlightThreshold = subElement.GetAttributeFloat("highlightthreshold", 0.6f);
|
||||||
|
TintHighlightMultiplier = subElement.GetAttributeFloat("highlightmultiplier", 0.8f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "huskmask":
|
||||||
|
string huskMaskPath = subElement.GetAttributeString("texture", "");
|
||||||
|
if (!string.IsNullOrWhiteSpace(huskMaskPath))
|
||||||
|
{
|
||||||
|
HuskMask = new Sprite(subElement, file: GetSpritePath(huskMaskPath));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISerializableEntity GetConditionalTarget()
|
ISerializableEntity GetConditionalTarget()
|
||||||
@@ -449,20 +475,20 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the full path of a limb sprite, taking into account tags, gender and head id
|
/// Get the full path of a limb sprite, taking into account tags, gender and head id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string GetSpritePath(string texturePath)
|
public static string GetSpritePath(string texturePath, CharacterInfo characterInfo)
|
||||||
{
|
{
|
||||||
string spritePath = texturePath;
|
string spritePath = texturePath;
|
||||||
string spritePathWithTags = spritePath;
|
string spritePathWithTags = spritePath;
|
||||||
if (character.Info != null && character.IsHumanoid)
|
if (characterInfo != null)
|
||||||
{
|
{
|
||||||
spritePath = spritePath.Replace("[GENDER]", (character.Info.Gender == Gender.Female) ? "female" : "male");
|
spritePath = spritePath.Replace("[GENDER]", (characterInfo.Gender == Gender.Female) ? "female" : "male");
|
||||||
spritePath = spritePath.Replace("[RACE]", character.Info.Race.ToString().ToLowerInvariant());
|
spritePath = spritePath.Replace("[RACE]", characterInfo.Race.ToString().ToLowerInvariant());
|
||||||
spritePath = spritePath.Replace("[HEADID]", character.Info.HeadSpriteId.ToString());
|
spritePath = spritePath.Replace("[HEADID]", characterInfo.HeadSpriteId.ToString());
|
||||||
|
|
||||||
if (character.Info.HeadSprite != null && character.Info.SpriteTags.Any())
|
if (characterInfo.HeadSprite != null && characterInfo.SpriteTags.Any())
|
||||||
{
|
{
|
||||||
string tags = "";
|
string tags = "";
|
||||||
character.Info.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
|
characterInfo.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
|
||||||
|
|
||||||
spritePathWithTags = Path.Combine(
|
spritePathWithTags = Path.Combine(
|
||||||
Path.GetDirectoryName(spritePath),
|
Path.GetDirectoryName(spritePath),
|
||||||
@@ -472,6 +498,13 @@ namespace Barotrauma
|
|||||||
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
|
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetSpritePath(string texturePath)
|
||||||
|
{
|
||||||
|
if (!character.IsHumanoid) { return texturePath; }
|
||||||
|
return GetSpritePath(texturePath, character?.Info);
|
||||||
|
}
|
||||||
|
|
||||||
partial void LoadParamsProjSpecific()
|
partial void LoadParamsProjSpecific()
|
||||||
{
|
{
|
||||||
bool isFlipped = dir == Direction.Left;
|
bool isFlipped = dir == Direction.Left;
|
||||||
@@ -638,13 +671,24 @@ namespace Barotrauma
|
|||||||
var spriteParams = Params.GetSprite();
|
var spriteParams = Params.GetSprite();
|
||||||
if (spriteParams == null) { return; }
|
if (spriteParams == null) { return; }
|
||||||
|
|
||||||
Color color = new Color(spriteParams.Color.R / 255f * brightness, spriteParams.Color.G / 255f * brightness, spriteParams.Color.B / 255f * brightness, spriteParams.Color.A / 255f);
|
Color clr = spriteParams.Color;
|
||||||
|
if (!spriteParams.IgnoreTint)
|
||||||
|
{
|
||||||
|
clr = clr.Multiply(ragdoll.RagdollParams.Color);
|
||||||
|
if (character.Info != null)
|
||||||
|
{
|
||||||
|
clr = clr.Multiply(character.Info.SkinColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
if (deadTimer > 0)
|
if (deadTimer > 0)
|
||||||
{
|
{
|
||||||
color = Color.Lerp(color, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
|
color = Color.Lerp(color, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
|
||||||
}
|
}
|
||||||
|
|
||||||
color = overrideColor ?? color;
|
color = overrideColor ?? color;
|
||||||
|
blankColor = overrideColor ?? blankColor;
|
||||||
|
|
||||||
if (isSevered)
|
if (isSevered)
|
||||||
{
|
{
|
||||||
@@ -667,6 +711,8 @@ namespace Barotrauma
|
|||||||
OtherWearables.Any(w => w.HideLimb) ||
|
OtherWearables.Any(w => w.HideLimb) ||
|
||||||
wearingItems.Any(w => w != null && w.HideLimb);
|
wearingItems.Any(w => w != null && w.HideLimb);
|
||||||
|
|
||||||
|
bool drawHuskSprite = HuskSprite != null && !wearableTypesToHide.Contains(WearableType.Husk);
|
||||||
|
|
||||||
var activeSprite = ActiveSprite;
|
var activeSprite = ActiveSprite;
|
||||||
if (type == LimbType.Head)
|
if (type == LimbType.Head)
|
||||||
{
|
{
|
||||||
@@ -698,7 +744,33 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool useTintMask = TintMask != null && spriteBatch.GetCurrentEffect() is null;
|
||||||
|
if (useTintMask)
|
||||||
|
{
|
||||||
|
tintEffectParams.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||||
|
tintEffectParams.Params ??= new Dictionary<string, object>();
|
||||||
|
var parameters = tintEffectParams.Params;
|
||||||
|
parameters["xBaseTexture"] = Sprite.Texture;
|
||||||
|
parameters["xTintMaskTexture"] = TintMask.Texture;
|
||||||
|
if (drawHuskSprite && HuskMask != null)
|
||||||
|
{
|
||||||
|
parameters["xCutoffTexture"] = HuskMask.Texture;
|
||||||
|
parameters["baseToCutoffSizeRatio"] = (float)Sprite.Texture.Width / (float)HuskMask.Texture.Width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||||
|
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||||
|
}
|
||||||
|
parameters["highlightThreshold"] = TintHighlightThreshold;
|
||||||
|
parameters["highlightMultiplier"] = TintHighlightMultiplier;
|
||||||
|
spriteBatch.SwapEffect(tintEffectParams);
|
||||||
|
}
|
||||||
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
|
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
|
||||||
|
if (useTintMask)
|
||||||
|
{
|
||||||
|
spriteBatch.SwapEffect(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Handle non-exlusive, i.e. additional conditional sprites
|
// Handle non-exlusive, i.e. additional conditional sprites
|
||||||
foreach (var conditionalSprite in ConditionalSprites)
|
foreach (var conditionalSprite in ConditionalSprites)
|
||||||
@@ -770,15 +842,36 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (onlyDrawable == null)
|
if (onlyDrawable == null)
|
||||||
{
|
{
|
||||||
if (HerpesSprite != null && !wearableTypesToHide.Contains(WearableType.Herpes))
|
if (HerpesSprite != null && !wearableTypesToHide.Contains(WearableType.Herpes) && herpesStrength > 0)
|
||||||
{
|
{
|
||||||
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
|
float alpha = Math.Min(herpesStrength * 2 / 100.0f, 1.0f);
|
||||||
|
DrawWearable(HerpesSprite, depthStep, spriteBatch, blankColor, alpha: alpha, spriteEffect);
|
||||||
|
depthStep += step;
|
||||||
|
}
|
||||||
|
if (drawHuskSprite)
|
||||||
|
{
|
||||||
|
bool useTintEffect = HuskMask != null && spriteBatch.GetCurrentEffect() is null;
|
||||||
|
if (useTintEffect)
|
||||||
|
{
|
||||||
|
huskSpriteParams.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||||
|
huskSpriteParams.Params ??= new Dictionary<string, object>();
|
||||||
|
var parameters = huskSpriteParams.Params;
|
||||||
|
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||||
|
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||||
|
spriteBatch.SwapEffect(huskSpriteParams);
|
||||||
|
}
|
||||||
|
DrawWearable(HuskSprite, depthStep, spriteBatch, color, alpha: color.A / 255f, spriteEffect);
|
||||||
|
if (useTintEffect)
|
||||||
|
{
|
||||||
|
spriteBatch.SwapEffect(null);
|
||||||
|
}
|
||||||
depthStep += step;
|
depthStep += step;
|
||||||
}
|
}
|
||||||
foreach (WearableSprite wearable in OtherWearables)
|
foreach (WearableSprite wearable in OtherWearables)
|
||||||
{
|
{
|
||||||
|
if (wearable.Type == WearableType.Husk) { continue; }
|
||||||
if (wearableTypesToHide.Contains(wearable.Type)) { continue; }
|
if (wearableTypesToHide.Contains(wearable.Type)) { continue; }
|
||||||
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||||
depthStep += step;
|
depthStep += step;
|
||||||
}
|
}
|
||||||
@@ -786,7 +879,7 @@ namespace Barotrauma
|
|||||||
foreach (WearableSprite wearable in WearingItems)
|
foreach (WearableSprite wearable in WearingItems)
|
||||||
{
|
{
|
||||||
if (onlyDrawable != null && onlyDrawable != wearable) continue;
|
if (onlyDrawable != null && onlyDrawable != wearable) continue;
|
||||||
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||||
depthStep += step;
|
depthStep += step;
|
||||||
}
|
}
|
||||||
@@ -936,7 +1029,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, SpriteEffects spriteEffect)
|
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, float alpha, SpriteEffects spriteEffect)
|
||||||
{
|
{
|
||||||
var sprite = ActiveSprite;
|
var sprite = ActiveSprite;
|
||||||
if (wearable.InheritSourceRect)
|
if (wearable.InheritSourceRect)
|
||||||
@@ -955,7 +1048,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 origin = wearable.Sprite.Origin;
|
Vector2 origin;
|
||||||
if (wearable.InheritOrigin)
|
if (wearable.InheritOrigin)
|
||||||
{
|
{
|
||||||
origin = sprite.Origin;
|
origin = sprite.Origin;
|
||||||
@@ -986,7 +1079,7 @@ namespace Barotrauma
|
|||||||
Color wearableColor = Color.White;
|
Color wearableColor = Color.White;
|
||||||
if (wearableItemComponent != null)
|
if (wearableItemComponent != null)
|
||||||
{
|
{
|
||||||
// Draw outer cloths on top of inner cloths.
|
// Draw outer clothes on top of inner clothes.
|
||||||
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.OuterClothes))
|
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.OuterClothes))
|
||||||
{
|
{
|
||||||
depth -= depthStep;
|
depth -= depthStep;
|
||||||
@@ -997,15 +1090,38 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
||||||
}
|
}
|
||||||
float textureScale = wearable.InheritTextureScale ? TextureScale : wearable.Scale;
|
else if (character.Info != null)
|
||||||
|
{
|
||||||
|
if (wearable.Type == WearableType.Hair)
|
||||||
|
{
|
||||||
|
wearableColor = character.Info.HairColor;
|
||||||
|
}
|
||||||
|
else if (wearable.Type == WearableType.Beard || wearable.Type == WearableType.Moustache)
|
||||||
|
{
|
||||||
|
wearableColor = character.Info.FacialHairColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float scale = wearable.Scale;
|
||||||
|
if (wearable.InheritScale)
|
||||||
|
{
|
||||||
|
if (!wearable.IgnoreTextureScale)
|
||||||
|
{
|
||||||
|
scale *= TextureScale;
|
||||||
|
}
|
||||||
|
if (!wearable.IgnoreLimbScale)
|
||||||
|
{
|
||||||
|
scale *= Params.Scale;
|
||||||
|
}
|
||||||
|
if (!wearable.IgnoreRagdollScale)
|
||||||
|
{
|
||||||
|
scale *= ragdoll.RagdollParams.LimbScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
float rotation = -body.DrawRotation - wearable.Rotation * Dir;
|
float rotation = -body.DrawRotation - wearable.Rotation * Dir;
|
||||||
|
float finalAlpha = alpha * wearableColor.A;
|
||||||
wearable.Sprite.Draw(spriteBatch,
|
Color finalColor = color.Multiply(wearableColor);
|
||||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
finalColor = new Color(finalColor.R, finalColor.G, finalColor.B, (byte)finalAlpha);
|
||||||
new Color((color.R * wearableColor.R) / (255.0f * 255.0f), (color.G * wearableColor.G) / (255.0f * 255.0f), (color.B * wearableColor.B) / (255.0f * 255.0f)) * ((color.A * wearableColor.A) / (255.0f * 255.0f)),
|
wearable.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), finalColor, origin, rotation, scale, spriteEffect, depth);
|
||||||
origin, rotation,
|
|
||||||
Scale * textureScale, spriteEffect, depth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WearableSprite GetWearableSprite(WearableType type, bool random = false)
|
private WearableSprite GetWearableSprite(WearableType type, bool random = false)
|
||||||
@@ -1056,6 +1172,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
HerpesSprite?.Sprite.Remove();
|
HerpesSprite?.Sprite.Remove();
|
||||||
HerpesSprite = null;
|
HerpesSprite = null;
|
||||||
|
|
||||||
|
TintMask?.Remove();
|
||||||
|
TintMask = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ResourceClusters.Count; i++)
|
for (int i = 0; i < resourceClusters.Count; i++)
|
||||||
{
|
{
|
||||||
var amount = msg.ReadByte();
|
var amount = msg.ReadByte();
|
||||||
var rotation = msg.ReadSingle();
|
var rotation = msg.ReadSingle();
|
||||||
@@ -41,20 +41,20 @@ namespace Barotrauma
|
|||||||
h.AttachToWall();
|
h.AttachToWall();
|
||||||
item.Rotation = rotation;
|
item.Rotation = rotation;
|
||||||
}
|
}
|
||||||
if (SpawnedResources.TryGetValue(item.Prefab.Identifier, out var resources))
|
if (spawnedResources.TryGetValue(item.Prefab.Identifier, out var resources))
|
||||||
{
|
{
|
||||||
resources.Add(item);
|
resources.Add(item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SpawnedResources.Add(item.Prefab.Identifier, new List<Item>() { item });
|
spawnedResources.Add(item.Prefab.Identifier, new List<Item>() { item });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CalculateMissionClusterPositions();
|
CalculateMissionClusterPositions();
|
||||||
|
|
||||||
for(int i = 0; i < ResourceClusters.Count; i++)
|
for(int i = 0; i < resourceClusters.Count; i++)
|
||||||
{
|
{
|
||||||
var identifier = msg.ReadString();
|
var identifier = msg.ReadString();
|
||||||
var count = msg.ReadByte();
|
var count = msg.ReadByte();
|
||||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
|||||||
if (!(entity is Item item)) { continue; }
|
if (!(entity is Item item)) { continue; }
|
||||||
resources[j] = item;
|
resources[j] = item;
|
||||||
}
|
}
|
||||||
RelevantLevelResources.Add(identifier, resources);
|
relevantLevelResources.Add(identifier, resources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ namespace Barotrauma
|
|||||||
public static GUIStyle Style;
|
public static GUIStyle Style;
|
||||||
|
|
||||||
private static Texture2D t;
|
private static Texture2D t;
|
||||||
|
public static Texture2D WhiteTexture => t;
|
||||||
private static Sprite[] MouseCursorSprites => Style.CursorSprite;
|
private static Sprite[] MouseCursorSprites => Style.CursorSprite;
|
||||||
|
|
||||||
private static bool debugDrawSounds, debugDrawEvents, debugDrawMetadata;
|
private static bool debugDrawSounds, debugDrawEvents, debugDrawMetadata;
|
||||||
@@ -862,11 +863,10 @@ namespace Barotrauma
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
if (updateList.Count > 0)
|
if (updateList.Count > 0)
|
||||||
{
|
{
|
||||||
index = updateList.Count - 1;
|
index = updateList.Count;
|
||||||
while (updateList[index].UpdateOrder > item.UpdateOrder)
|
while (index > 0 && updateList[index-1].UpdateOrder > item.UpdateOrder)
|
||||||
{
|
{
|
||||||
index--;
|
index--;
|
||||||
if (index == 0) { break; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!updateListSet.Contains(item))
|
if (!updateListSet.Contains(item))
|
||||||
@@ -1057,12 +1057,15 @@ namespace Barotrauma
|
|||||||
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
|
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
|
||||||
if (listBox.CanDragElements) { return CursorState.Move; }
|
if (listBox.CanDragElements) { return CursorState.Move; }
|
||||||
|
|
||||||
var hoverParent = c;
|
if (listBox.HoverCursor != CursorState.Default)
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
if (hoverParent == parent || hoverParent == null) { break; }
|
var hoverParent = c;
|
||||||
if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; }
|
while (true)
|
||||||
hoverParent = hoverParent.Parent;
|
{
|
||||||
|
if (hoverParent == parent || hoverParent == null) { break; }
|
||||||
|
if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; }
|
||||||
|
hoverParent = hoverParent.Parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ namespace Barotrauma
|
|||||||
private bool selectMultiple;
|
private bool selectMultiple;
|
||||||
|
|
||||||
public bool Dropped { get; set; }
|
public bool Dropped { get; set; }
|
||||||
|
|
||||||
|
public bool AllowNonText { get; set; }
|
||||||
|
|
||||||
public object SelectedItemData
|
public object SelectedItemData
|
||||||
{
|
{
|
||||||
@@ -318,9 +320,9 @@ namespace Barotrauma
|
|||||||
if (textBlock == null)
|
if (textBlock == null)
|
||||||
{
|
{
|
||||||
textBlock = component.GetChild<GUITextBlock>();
|
textBlock = component.GetChild<GUITextBlock>();
|
||||||
if (textBlock == null) return false;
|
if (textBlock is null && !AllowNonText) { return false; }
|
||||||
}
|
}
|
||||||
button.Text = textBlock.Text;
|
button.Text = textBlock?.Text ?? "";
|
||||||
}
|
}
|
||||||
Dropped = false;
|
Dropped = false;
|
||||||
// TODO: OnSelected can be called multiple times and when it shouldn't be called -> turn into an event so that nobody else can call it.
|
// TODO: OnSelected can be called multiple times and when it shouldn't be called -> turn into an event so that nobody else can call it.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
private Dictionary<string, GUIComponentStyle> componentStyles;
|
private Dictionary<string, GUIComponentStyle> componentStyles;
|
||||||
|
|
||||||
private XElement configElement;
|
private readonly XElement configElement;
|
||||||
|
|
||||||
private GraphicsDevice graphicsDevice;
|
private GraphicsDevice graphicsDevice;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Barotrauma
|
|||||||
private static UISprite spectateIcon, disconnectedIcon;
|
private static UISprite spectateIcon, disconnectedIcon;
|
||||||
private static Sprite ownerIcon, moderatorIcon;
|
private static Sprite ownerIcon, moderatorIcon;
|
||||||
|
|
||||||
public enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine, Talents };
|
public enum InfoFrameTab { Crew, Mission, Reputation, Traitor, Submarine, Talents };
|
||||||
public static InfoFrameTab selectedTab;
|
public static InfoFrameTab selectedTab;
|
||||||
private GUIFrame infoFrame, contentFrame;
|
private GUIFrame infoFrame, contentFrame;
|
||||||
|
|
||||||
@@ -34,6 +34,8 @@ namespace Barotrauma
|
|||||||
private List<CharacterTeamType> teamIDs;
|
private List<CharacterTeamType> teamIDs;
|
||||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||||
|
|
||||||
|
private GUIFrame pendingChangesFrame = null;
|
||||||
|
|
||||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||||
|
|
||||||
private class LinkedGUI
|
private class LinkedGUI
|
||||||
@@ -134,6 +136,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
GameSession.UpdateTalentNotificationIndicator(talentPointNotification);
|
||||||
|
if (Character.Controlled is { } controlled && talentResetButton != null && talentApplyButton != null)
|
||||||
|
{
|
||||||
|
int talentCount = selectedTalents.Count - controlled.Info.UnlockedTalents.Count;
|
||||||
|
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedTab != InfoFrameTab.Crew) return;
|
if (selectedTab != InfoFrameTab.Crew) return;
|
||||||
if (linkedGUIList == null) return;
|
if (linkedGUIList == null) return;
|
||||||
|
|
||||||
@@ -183,16 +192,8 @@ namespace Barotrauma
|
|||||||
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, infoFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, infoFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
||||||
|
|
||||||
//this used to be a switch expression but i changed it because it killed enc :(
|
//this used to be a switch expression but i changed it because it killed enc :(
|
||||||
Vector2 contentFrameSize;
|
//now it's not even a switch statement anymore :(
|
||||||
switch (selectedTab)
|
Vector2 contentFrameSize = new Vector2(0.45f, 0.667f);
|
||||||
{
|
|
||||||
case InfoFrameTab.MyCharacter:
|
|
||||||
contentFrameSize = new Vector2(0.45f, 0.5f);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
contentFrameSize = new Vector2(0.45f, 0.667f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
contentFrame = new GUIFrame(new RectTransform(contentFrameSize, infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.12f) });
|
contentFrame = new GUIFrame(new RectTransform(contentFrameSize, infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.12f) });
|
||||||
|
|
||||||
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.958f, 0.943f), contentFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(25f)) }, isHorizontal: true)
|
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.958f, 0.943f), contentFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(25f)) }, isHorizontal: true)
|
||||||
@@ -243,6 +244,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
TextGetter = () => TextManager.GetWithVariable("campaignmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", campaignMode.Money))
|
TextGetter = () => TextManager.GetWithVariable("campaignmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", campaignMode.Money))
|
||||||
};
|
};
|
||||||
|
GUIFrame bottomDisclaimerFrame = new GUIFrame(new RectTransform(new Vector2(contentFrameSize.X, 0.1f), infoFrame.RectTransform)
|
||||||
|
{
|
||||||
|
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
||||||
|
}, style: null);
|
||||||
|
|
||||||
|
pendingChangesFrame = new GUIFrame(new RectTransform(Vector2.One, bottomDisclaimerFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
|
if (GameMain.NetLobbyScreen?.CampaignCharacterDiscarded ?? false)
|
||||||
|
{
|
||||||
|
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -255,20 +267,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine");
|
var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine");
|
||||||
|
|
||||||
if (GameMain.NetworkMember != null)
|
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
||||||
|
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
||||||
{
|
{
|
||||||
var myCharacterButton = createTabButton(InfoFrameTab.MyCharacter, "tabmenu.character");
|
talentsButton.Enabled = Character.Controlled?.Info != null;
|
||||||
}
|
|
||||||
|
|
||||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.talents");
|
|
||||||
talentsButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
|
|
||||||
{
|
|
||||||
talentsButton.Enabled = Character.Controlled?.Info != null && (GameMain.GameSession?.Campaign != null || Screen.Selected == GameMain.TestScreen || GameMain.GameSession.GameMode is TestGameMode);
|
|
||||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||||
{
|
{
|
||||||
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
talentPointNotification = GameSession.CreateTalentIconNotification(talentsButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
||||||
@@ -300,10 +309,6 @@ namespace Barotrauma
|
|||||||
if (traitor == null || traitorMission == null) return false;
|
if (traitor == null || traitorMission == null) return false;
|
||||||
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
|
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
|
||||||
break;
|
break;
|
||||||
case InfoFrameTab.MyCharacter:
|
|
||||||
if (GameMain.NetworkMember == null) { return false; }
|
|
||||||
GameMain.NetLobbyScreen.CreatePlayerFrame(infoFrameHolder);
|
|
||||||
break;
|
|
||||||
case InfoFrameTab.Submarine:
|
case InfoFrameTab.Submarine:
|
||||||
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
||||||
break;
|
break;
|
||||||
@@ -1188,6 +1193,11 @@ namespace Barotrauma
|
|||||||
private GUITextBlock talentPointText;
|
private GUITextBlock talentPointText;
|
||||||
private GUIListBox skillListBox;
|
private GUIListBox skillListBox;
|
||||||
|
|
||||||
|
private GUIButton talentApplyButton,
|
||||||
|
talentResetButton;
|
||||||
|
|
||||||
|
private GUIImage talentPointNotification;
|
||||||
|
|
||||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, GUIComponentStyle> talentStageStyles = new Dictionary<TalentTree.TalentTreeStageState, GUIComponentStyle>
|
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, GUIComponentStyle> talentStageStyles = new Dictionary<TalentTree.TalentTreeStageState, GUIComponentStyle>
|
||||||
{
|
{
|
||||||
{ TalentTree.TalentTreeStageState.Invalid, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
{ TalentTree.TalentTreeStageState.Invalid, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
||||||
@@ -1219,9 +1229,22 @@ namespace Barotrauma
|
|||||||
int padding = GUI.IntScale(15);
|
int padding = GUI.IntScale(15);
|
||||||
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
GUIFrame paddedTalentFrame = new GUIFrame(new RectTransform(new Vector2(0.9f), talentFrameContent.RectTransform, Anchor.Center), style: null);
|
GUIFrame paddedTalentFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), talentFrameContent.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
if (controlledCharacter.Info == null)
|
GUIFrame talentFrameMain = new GUIFrame(new RectTransform(Vector2.One, paddedTalentFrame.RectTransform), style: null);
|
||||||
|
|
||||||
|
GUIFrame characterSettingsFrame = null;
|
||||||
|
GUILayoutGroup characterLayout = null;
|
||||||
|
if (!(GameMain.NetworkMember is null))
|
||||||
|
{
|
||||||
|
characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrameContent.RectTransform), style: null) { Visible = false };
|
||||||
|
characterLayout = new GUILayoutGroup(new RectTransform(Vector2.One, characterSettingsFrame.RectTransform));
|
||||||
|
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
|
||||||
|
GUIFrame playerFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), containerFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlledCharacter.Info is null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No character info found for talent UI");
|
DebugConsole.ThrowError("No character info found for talent UI");
|
||||||
return;
|
return;
|
||||||
@@ -1229,7 +1252,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
||||||
|
|
||||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), paddedTalentFrame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
AbsoluteSpacing = GUI.IntScale(5)
|
AbsoluteSpacing = GUI.IntScale(5)
|
||||||
};
|
};
|
||||||
@@ -1241,11 +1264,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
||||||
{
|
{
|
||||||
float posY = component.Rect.Bottom - component.Rect.Width;
|
float posY = component.Rect.Center.Y - component.Rect.Width / 2;
|
||||||
info.DrawPortrait(batch, new Vector2(component.Rect.X, posY), Vector2.Zero, component.Rect.Width, false, false);
|
info.DrawPortrait(batch, new Vector2(component.Rect.X, posY), Vector2.Zero, component.Rect.Width, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.375f, 1f), talentInfoLayoutGroup.RectTransform));
|
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), talentInfoLayoutGroup.RectTransform)) { RelativeSpacing = 0.05f };
|
||||||
|
|
||||||
Vector2 nameSize = GUI.SubHeadingFont.MeasureString(info.Name);
|
Vector2 nameSize = GUI.SubHeadingFont.MeasureString(info.Name);
|
||||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUI.SubHeadingFont) { TextColor = job.Prefab.UIColor };
|
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUI.SubHeadingFont) { TextColor = job.Prefab.UIColor };
|
||||||
@@ -1260,7 +1283,56 @@ namespace Barotrauma
|
|||||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUI.SmallFont);
|
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUI.SmallFont);
|
||||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||||
|
|
||||||
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.375f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true };
|
if (!(GameMain.NetworkMember is null))
|
||||||
|
{
|
||||||
|
GUIButton newCharacterBox = new GUIButton(new RectTransform(Vector2.One, nameLayout.RectTransform, Anchor.BottomCenter), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true
|
||||||
|
};
|
||||||
|
|
||||||
|
newCharacterBox.OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
|
||||||
|
{
|
||||||
|
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
|
||||||
|
{
|
||||||
|
newCharacterBox.Text = TextManager.Get("settings");
|
||||||
|
|
||||||
|
if (pendingChangesFrame != null)
|
||||||
|
{
|
||||||
|
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||||
|
}
|
||||||
|
OpenMenu();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenMenu();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
void OpenMenu()
|
||||||
|
{
|
||||||
|
characterSettingsFrame!.Visible = true;
|
||||||
|
talentFrameMain.Visible = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
characterSettingsFrame!.Visible = false;
|
||||||
|
talentFrameMain.Visible = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true };
|
||||||
|
|
||||||
string skillString = TextManager.Get("skills");
|
string skillString = TextManager.Get("skills");
|
||||||
Vector2 skillSize = GUI.SubHeadingFont.MeasureString(skillString);
|
Vector2 skillSize = GUI.SubHeadingFont.MeasureString(skillString);
|
||||||
@@ -1276,6 +1348,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||||
|
|
||||||
|
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||||
foreach (var subTree in talentTree.TalentSubTrees)
|
foreach (var subTree in talentTree.TalentSubTrees)
|
||||||
{
|
{
|
||||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||||
@@ -1285,7 +1358,7 @@ namespace Barotrauma
|
|||||||
int elementPadding = GUI.IntScale(8);
|
int elementPadding = GUI.IntScale(8);
|
||||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||||
new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUI.SubHeadingFont, textAlignment: Alignment.Center));
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -1296,7 +1369,7 @@ namespace Barotrauma
|
|||||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground");
|
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground");
|
||||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||||
|
|
||||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.25f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight), style: null)
|
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
@@ -1316,10 +1389,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentOptionLayoutGroup.RectTransform), style: null)
|
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentOptionLayoutGroup.RectTransform), style: null)
|
||||||
{
|
{
|
||||||
CanBeFocused = false,
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
GUIFrame croppedTalentFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), style: null);
|
||||||
|
|
||||||
|
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, croppedTalentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||||
{
|
{
|
||||||
ToolTip = $"{talent.DisplayName}\n\n{talent.Description}",
|
ToolTip = $"{talent.DisplayName}\n\n{talent.Description}",
|
||||||
UserData = talent.Identifier,
|
UserData = talent.Identifier,
|
||||||
@@ -1361,7 +1436,7 @@ namespace Barotrauma
|
|||||||
GUIComponent iconImage;
|
GUIComponent iconImage;
|
||||||
if (talent.Icon is null)
|
if (talent.Icon is null)
|
||||||
{
|
{
|
||||||
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), text: "???", font: GUI.LargeFont, textAlignment: Alignment.Center, style: null)
|
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), text: "???", font: GUI.LargeFont, textAlignment: Alignment.Center, style: null)
|
||||||
{
|
{
|
||||||
OutlineColor = GUI.Style.Red,
|
OutlineColor = GUI.Style.Red,
|
||||||
TextColor = GUI.Style.Red,
|
TextColor = GUI.Style.Red,
|
||||||
@@ -1387,10 +1462,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||||
|
|
||||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||||
|
|
||||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.775f, 1f), talentBottomFrame.RectTransform));
|
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
||||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||||
|
|
||||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||||
@@ -1399,19 +1475,22 @@ namespace Barotrauma
|
|||||||
IsHorizontal = true
|
IsHorizontal = true
|
||||||
};
|
};
|
||||||
|
|
||||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textAlignment: Alignment.CenterRight);
|
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||||
|
|
||||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUI.SubHeadingFont, parseRichText: true, textAlignment: Alignment.CenterRight);
|
|
||||||
|
|
||||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUICharacterInfoButton")
|
|
||||||
{
|
{
|
||||||
OnClicked = ResetTalentSelection,
|
Shadow = true
|
||||||
};
|
};
|
||||||
|
|
||||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUICharacterInfoButton")
|
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUI.SubHeadingFont, parseRichText: true, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||||
|
|
||||||
|
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||||
|
{
|
||||||
|
OnClicked = ResetTalentSelection
|
||||||
|
};
|
||||||
|
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||||
{
|
{
|
||||||
OnClicked = ApplyTalentSelection,
|
OnClicked = ApplyTalentSelection,
|
||||||
};
|
};
|
||||||
|
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||||
|
|
||||||
UpdateTalentButtons();
|
UpdateTalentButtons();
|
||||||
}
|
}
|
||||||
@@ -1419,11 +1498,12 @@ namespace Barotrauma
|
|||||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
||||||
{
|
{
|
||||||
parent.Content.ClearChildren();
|
parent.Content.ClearChildren();
|
||||||
|
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||||
foreach (Skill skill in character.Info.Job.Skills)
|
foreach (Skill skill in character.Info.Job.Skills)
|
||||||
{
|
{
|
||||||
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}", returnNull: true) ?? skill.Identifier);
|
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}", returnNull: true) ?? skill.Identifier));
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
||||||
|
|
||||||
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
||||||
@@ -1444,6 +1524,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
parent.RecalculateChildren();
|
parent.RecalculateChildren();
|
||||||
|
GUITextBlock.AutoScaleAndNormalize(skillNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTalentButtons()
|
private void UpdateTalentButtons()
|
||||||
|
|||||||
@@ -1068,7 +1068,6 @@ namespace Barotrauma
|
|||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
|
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
|
||||||
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ namespace Barotrauma
|
|||||||
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||||
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.CampaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||||
|
|
||||||
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
|
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
|
||||||
TextManager.Get("NewCampaign"), style: "GUITabButton")
|
TextManager.Get("NewCampaign"), style: "GUITabButton")
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
|
if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
|
||||||
{
|
{
|
||||||
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
|
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu?.Dispose();
|
||||||
|
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu = null;
|
||||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
||||||
}
|
}
|
||||||
if (tabMenu == null && !(GameMode is TutorialMode) && !ConversationAction.IsDialogOpen)
|
if (tabMenu == null && !(GameMode is TutorialMode) && !ConversationAction.IsDialogOpen)
|
||||||
@@ -39,6 +40,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private GUILayoutGroup topLeftButtonGroup;
|
private GUILayoutGroup topLeftButtonGroup;
|
||||||
private GUIButton crewListButton, commandButton, tabMenuButton;
|
private GUIButton crewListButton, commandButton, tabMenuButton;
|
||||||
|
private GUIImage talentPointNotification;
|
||||||
|
|
||||||
private GUIComponent respawnInfoFrame, respawnButtonContainer;
|
private GUIComponent respawnInfoFrame, respawnButtonContainer;
|
||||||
private GUITextBlock respawnInfoText;
|
private GUITextBlock respawnInfoText;
|
||||||
@@ -88,11 +90,11 @@ namespace Barotrauma
|
|||||||
tabMenuButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "TabMenuButton")
|
tabMenuButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "TabMenuButton")
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.GetWithVariable("hudbutton.tabmenu", "[key]", GameMain.Config.KeyBindText(InputType.InfoTab)),
|
ToolTip = TextManager.GetWithVariable("hudbutton.tabmenu", "[key]", GameMain.Config.KeyBindText(InputType.InfoTab)),
|
||||||
OnClicked = (button, userData) =>
|
OnClicked = (button, userData) => ToggleTabMenu()
|
||||||
{
|
|
||||||
return ToggleTabMenu();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
talentPointNotification = CreateTalentIconNotification(tabMenuButton);
|
||||||
|
|
||||||
GameMain.Instance.ResolutionChanged += CreateTopLeftButtons;
|
GameMain.Instance.ResolutionChanged += CreateTopLeftButtons;
|
||||||
|
|
||||||
respawnInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), parent: topLeftButtonGroup.RectTransform)
|
respawnInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), parent: topLeftButtonGroup.RectTransform)
|
||||||
@@ -139,11 +141,41 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (GameMain.NetworkMember != null)
|
if (GameMain.NetworkMember != null)
|
||||||
{
|
{
|
||||||
GameMain.NetLobbyScreen?.HeadSelectionList?.AddToGUIUpdateList();
|
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu?.AddToGUIUpdateList();
|
||||||
GameMain.NetLobbyScreen?.JobSelectionFrame?.AddToGUIUpdateList();
|
GameMain.NetLobbyScreen?.JobSelectionFrame?.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GUIImage CreateTalentIconNotification(GUIComponent parent, bool offset = true)
|
||||||
|
{
|
||||||
|
GUIImage indicator = new GUIImage(new RectTransform(new Vector2(0.45f), parent.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.BothWidth), style: "TalentPointNotification")
|
||||||
|
{
|
||||||
|
Visible = false,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
Point notificationSize = indicator.RectTransform.NonScaledSize;
|
||||||
|
if (offset)
|
||||||
|
{
|
||||||
|
indicator.RectTransform.AbsoluteOffset = new Point(-(notificationSize.X / 2), -(notificationSize.Y / 2));
|
||||||
|
}
|
||||||
|
return indicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateTalentNotificationIndicator(GUIImage indicator)
|
||||||
|
{
|
||||||
|
if (indicator != null)
|
||||||
|
{
|
||||||
|
if (Character.Controlled?.Info == null)
|
||||||
|
{
|
||||||
|
indicator.Visible = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
partial void UpdateProjSpecific(float deltaTime)
|
partial void UpdateProjSpecific(float deltaTime)
|
||||||
{
|
{
|
||||||
if (GUI.DisableHUD) { return; }
|
if (GUI.DisableHUD) { return; }
|
||||||
@@ -158,28 +190,24 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tabMenu.Update();
|
tabMenu.Update();
|
||||||
if ((PlayerInput.KeyHit(InputType.InfoTab) || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) &&
|
if ((PlayerInput.KeyHit(InputType.InfoTab) || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) &&
|
||||||
!(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
|
!(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
|
||||||
{
|
{
|
||||||
ToggleTabMenu();
|
ToggleTabMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateTalentNotificationIndicator(talentPointNotification);
|
||||||
|
|
||||||
if (GameMain.NetworkMember != null)
|
if (GameMain.NetworkMember != null)
|
||||||
{
|
{
|
||||||
if (GameMain.NetLobbyScreen?.HeadSelectionList != null)
|
GameMain.NetLobbyScreen?.CharacterAppearanceCustomizationMenu?.Update();
|
||||||
{
|
|
||||||
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.HeadSelectionList))
|
|
||||||
{
|
|
||||||
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GameMain.NetLobbyScreen?.JobSelectionFrame != null)
|
if (GameMain.NetLobbyScreen?.JobSelectionFrame != null)
|
||||||
{
|
{
|
||||||
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
|
if (GameMain.NetLobbyScreen.JobSelectionFrame != null && PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
|
||||||
{
|
{
|
||||||
GameMain.NetLobbyScreen.JobList.Deselect();
|
GameMain.NetLobbyScreen.JobList.Deselect();
|
||||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ namespace Barotrauma
|
|||||||
case Layout.Default:
|
case Layout.Default:
|
||||||
{
|
{
|
||||||
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
|
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
|
||||||
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
|
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s) && s != InvSlotType.HealthInterface);
|
||||||
|
|
||||||
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
|
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
|
||||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
|
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override void AddTooltipInfo(ref string name, ref string description)
|
public override void AddTooltipInfo(ref string name, ref string description)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(materialName))
|
if (!string.IsNullOrEmpty(materialName) && item.ContainedItems.Count() > 0)
|
||||||
{
|
{
|
||||||
string mergedMaterialName = materialName;
|
string mergedMaterialName = materialName;
|
||||||
foreach (Item containedItem in item.ContainedItems)
|
foreach (Item containedItem in item.ContainedItems)
|
||||||
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (containedMaterial == null) { continue; }
|
if (containedMaterial == null) { continue; }
|
||||||
mergedMaterialName += ", " + containedMaterial.materialName;
|
mergedMaterialName += ", " + containedMaterial.materialName;
|
||||||
}
|
}
|
||||||
name = TextManager.GetWithVariable("entityname.geneticmaterial", "[type]", mergedMaterialName);
|
name = name.Replace(materialName, mergedMaterialName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Tainted)
|
if (Tainted)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activateButton.Enabled = inputContainer.Inventory.AllItems.Any();
|
activateButton.Enabled = outputsFound;
|
||||||
activateButton.Text = TextManager.Get(ActivateButtonText);
|
activateButton.Text = TextManager.Get(ActivateButtonText);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,11 +516,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
string name = GetRecipeNameAndAmount(selectedItem);
|
string name = GetRecipeNameAndAmount(selectedItem);
|
||||||
|
|
||||||
float quality = 0;
|
float quality = GetFabricatedItemQuality(selectedItem, user);
|
||||||
foreach (string tag in selectedItem.TargetItem.Tags)
|
|
||||||
{
|
|
||||||
quality += user?.Info?.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag) ?? 0;
|
|
||||||
}
|
|
||||||
if (quality > 0)
|
if (quality > 0)
|
||||||
{
|
{
|
||||||
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", name+'\n', fallBackTag: "itemname.quality3");
|
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", name+'\n', fallBackTag: "itemname.quality3");
|
||||||
|
|||||||
@@ -246,25 +246,26 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
protected override void CreateGUI()
|
protected override void CreateGUI()
|
||||||
{
|
{
|
||||||
|
GuiFrame.ClearChildren();
|
||||||
|
|
||||||
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.05f, 0.0f);
|
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.05f, 0.0f);
|
||||||
GuiFrame.CanBeFocused = true;
|
GuiFrame.CanBeFocused = true;
|
||||||
new GUICustomComponent(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset }, DrawHUDBack, null);
|
var submarineBack = new GUICustomComponent(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset }, DrawHUDBack, null);
|
||||||
GUIFrame paddedContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center), style: null);
|
GUIFrame paddedContainer = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center), style: null);
|
||||||
submarineContainer = new GUIFrame(new RectTransform(Vector2.One, paddedContainer.RectTransform, Anchor.Center), style: null);
|
submarineContainer = new GUIFrame(new RectTransform(Vector2.One, paddedContainer.RectTransform, Anchor.Center), style: null);
|
||||||
|
var submarineFront = new GUICustomComponent(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset }, DrawHUDFront, null)
|
||||||
new GUICustomComponent(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset }, DrawHUDFront, null)
|
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.2f), paddedContainer.RectTransform), isHorizontal: true);
|
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.15f), paddedContainer.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(40)) }, isHorizontal: true) { CanBeFocused = true };
|
||||||
|
|
||||||
modeSwitchButtons = ImmutableArray.Create
|
modeSwitchButtons = ImmutableArray.Create
|
||||||
(
|
(
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 0.5f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.HullStatus") { UserData = MiniMapMode.HullStatus, Enabled = EnableHullStatus, ToolTip = TextManager.Get("StatusMonitorButton.HullStatus.Tooltip") },
|
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.HullStatus") { UserData = MiniMapMode.HullStatus, Enabled = EnableHullStatus, ToolTip = TextManager.Get("StatusMonitorButton.HullStatus.Tooltip") },
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 0.5f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.ElectricalView") { UserData = MiniMapMode.ElectricalView, Enabled = EnableHullCondition, ToolTip = TextManager.Get("StatusMonitorButton.ElectricalView.Tooltip") },
|
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.ElectricalView") { UserData = MiniMapMode.ElectricalView, Enabled = EnableHullCondition, ToolTip = TextManager.Get("StatusMonitorButton.ElectricalView.Tooltip") },
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 0.5f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.HullCondition") { UserData = MiniMapMode.HullCondition, Enabled = EnableHullCondition, ToolTip = TextManager.Get("StatusMonitorButton.HullCondition.Tooltip") },
|
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.HullCondition") { UserData = MiniMapMode.HullCondition, Enabled = EnableHullCondition, ToolTip = TextManager.Get("StatusMonitorButton.HullCondition.Tooltip") },
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 0.5f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.ItemFinder") { UserData = MiniMapMode.ItemFinder, Enabled = EnableItemFinder, ToolTip = TextManager.Get("StatusMonitorButton.ItemFinder.Tooltip") }
|
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonLayout.RectTransform), string.Empty, style: "StatusMonitorButton.ItemFinder") { UserData = MiniMapMode.ItemFinder, Enabled = EnableItemFinder, ToolTip = TextManager.Get("StatusMonitorButton.ItemFinder.Tooltip") }
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach (GUIButton button in modeSwitchButtons)
|
foreach (GUIButton button in modeSwitchButtons)
|
||||||
@@ -295,14 +296,15 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
List<Order> reports = Order.PrefabList.FindAll(o => o.IsReport && o.SymbolSprite != null && !o.Hidden);
|
List<Order> reports = Order.PrefabList.FindAll(o => o.IsReport && o.SymbolSprite != null && !o.Hidden);
|
||||||
|
|
||||||
GUIFrame bottomFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.15f), paddedContainer.RectTransform, Anchor.BottomCenter), style: null)
|
GUIFrame bottomFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.15f), paddedContainer.RectTransform, Anchor.BottomCenter) { MaxSize = new Point(int.MaxValue, GUI.IntScale(40)) }, style: null)
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
reportFrame = new GUILayoutGroup(new RectTransform(new Vector2(1), bottomFrame.RectTransform), isHorizontal: true)
|
reportFrame = new GUILayoutGroup(new RectTransform(new Vector2(1), bottomFrame.RectTransform), isHorizontal: true)
|
||||||
{
|
{
|
||||||
AbsoluteSpacing = (int)(5 * GUI.Scale)
|
Stretch = true,
|
||||||
|
AbsoluteSpacing = GUI.IntScale(5)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (reports.Any())
|
if (reports.Any())
|
||||||
@@ -359,10 +361,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
searchBar.OnSelected += (sender, key) =>
|
searchBar.OnSelected += (sender, key) =>
|
||||||
{
|
{
|
||||||
itemsFoundOnSub = Item.ItemList.Where(it =>
|
itemsFoundOnSub = Item.ItemList.Where(it => VisibleOnItemFinder(it)).Select(it => it.Prefab).ToImmutableHashSet();
|
||||||
it.Submarine == item.Submarine &&
|
|
||||||
!it.NonInteractable && !it.HiddenInGame &&
|
|
||||||
(it.GetComponent<Holdable>() != null || it.GetComponent<Wearable>() != null)).Select(it => it.Prefab).ToImmutableHashSet();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
searchBar.OnKeyHit += ControlSearchTooltip;
|
searchBar.OnKeyHit += ControlSearchTooltip;
|
||||||
@@ -390,6 +389,28 @@ namespace Barotrauma.Items.Components
|
|||||||
c.CanBeFocused = false;
|
c.CanBeFocused = false;
|
||||||
c.Children.ForEach(c2 => c2.CanBeFocused = false);
|
c.Children.ForEach(c2 => c2.CanBeFocused = false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
submarineBack.RectTransform.MaxSize =
|
||||||
|
submarineFront.RectTransform.MaxSize =
|
||||||
|
submarineContainer.RectTransform.MaxSize =
|
||||||
|
new Point(int.MaxValue, paddedContainer.Rect.Height - bottomFrame.Rect.Height - buttonLayout.Rect.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool VisibleOnItemFinder(Item it)
|
||||||
|
{
|
||||||
|
if (it.Submarine != item.Submarine) { return false; }
|
||||||
|
if (it.NonInteractable || it.HiddenInGame) { return false; }
|
||||||
|
if (it.GetComponent<Pickable>() == null) { return false; }
|
||||||
|
|
||||||
|
var holdable = it.GetComponent<Holdable>();
|
||||||
|
if (holdable != null && holdable.Attached) { return false; }
|
||||||
|
|
||||||
|
var wire = it.GetComponent<Wire>();
|
||||||
|
if (wire != null && wire.Connections.Any(c => c != null)) { return false; }
|
||||||
|
|
||||||
|
if (it.HasTag("traitormissionitem")) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddToGUIUpdateList()
|
public override void AddToGUIUpdateList()
|
||||||
@@ -546,10 +567,7 @@ namespace Barotrauma.Items.Components
|
|||||||
// is there a better way to do this?
|
// is there a better way to do this?
|
||||||
if (GuiFrame.Rect.Size != elementSize)
|
if (GuiFrame.Rect.Size != elementSize)
|
||||||
{
|
{
|
||||||
if (item.Submarine is { } sub)
|
CreateGUI();
|
||||||
{
|
|
||||||
BakeSubmarine(sub, miniMapFrame.Rect);
|
|
||||||
}
|
|
||||||
elementSize = GuiFrame.Rect.Size;
|
elementSize = GuiFrame.Rect.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,10 +800,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
foreach (Item it in Item.ItemList)
|
foreach (Item it in Item.ItemList)
|
||||||
{
|
{
|
||||||
if (it.Submarine != item.Submarine) { continue; }
|
if (!VisibleOnItemFinder(it)) { continue; }
|
||||||
if (it.HiddenInGame || it.NonInteractable) { continue; }
|
|
||||||
if (it.GetComponent<Wire>() is { Connections: { } conn} && conn.Any()) { continue; }
|
|
||||||
if (it.HasTag("traitormissionitem")) { continue; }
|
|
||||||
|
|
||||||
if (it.Prefab == searchedPrefab)
|
if (it.Prefab == searchedPrefab)
|
||||||
{
|
{
|
||||||
@@ -794,7 +809,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (it.FindParentInventory(inventory => inventory is ItemInventory { Owner: Item { ParentInventory: null } }) is ItemInventory parent)
|
if (it.FindParentInventory(inventory => inventory is ItemInventory { Owner: Item { ParentInventory: null } }) is ItemInventory parent)
|
||||||
{
|
{
|
||||||
foundItems.Add((Item) parent.Owner);
|
foundItems.Add((Item)parent.Owner);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1165,7 +1180,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (entity is Item it)
|
if (entity is Item it)
|
||||||
{
|
{
|
||||||
if (it.GetComponent<Holdable>() != null || it.ParentInventory != null) { continue; }
|
if (it.GetComponent<Pickable>() != null || it.ParentInventory != null) { continue; }
|
||||||
DrawItem(spriteBatch, it, parentRect, worldBorders, inflate);
|
DrawItem(spriteBatch, it, parentRect, worldBorders, inflate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class Quality : ItemComponent
|
||||||
|
{
|
||||||
|
public override void AddTooltipInfo(ref string name, ref string description)
|
||||||
|
{
|
||||||
|
foreach (var statValue in statValues)
|
||||||
|
{
|
||||||
|
int roundedValue = (int)Math.Round(statValue.Value * qualityLevel * 100);
|
||||||
|
if (roundedValue == 0) { return; }
|
||||||
|
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||||
|
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}%‖color:end‖ {TextManager.Get("qualitystattypenames." + statValue.Key.ToString(), true) ?? statValue.Key.ToString()}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ namespace Barotrauma.Items.Components
|
|||||||
public override bool ShouldDrawHUD(Character character)
|
public override bool ShouldDrawHUD(Character character)
|
||||||
{
|
{
|
||||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
|
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
|
||||||
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition))) || CanTinker(character);
|
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition))) || IsTinkerable(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific(XElement element)
|
partial void InitProjSpecific(XElement element)
|
||||||
@@ -162,7 +162,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
tinkerButtonText = "Tinker";
|
tinkerButtonText = "Tinker";
|
||||||
tinkeringText = "Tinkering";
|
tinkeringText = "Tinkering";
|
||||||
TinkerButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), tinkerButtonText, style: "GUIButtonSmall")
|
TinkerButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), tinkerButtonText)
|
||||||
{
|
{
|
||||||
IgnoreLayoutGroups = true,
|
IgnoreLayoutGroups = true,
|
||||||
Visible = false,
|
Visible = false,
|
||||||
@@ -254,7 +254,7 @@ namespace Barotrauma.Items.Components
|
|||||||
progressBarOverlayText.Visible = false;
|
progressBarOverlayText.Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition;
|
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && item.ConditionPercentage < RepairThreshold;
|
||||||
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
|
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
|
||||||
repairButtonText :
|
repairButtonText :
|
||||||
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||||
@@ -269,7 +269,7 @@ namespace Barotrauma.Items.Components
|
|||||||
TinkerButton.Visible = IsTinkerable(character);
|
TinkerButton.Visible = IsTinkerable(character);
|
||||||
TinkerButton.IgnoreLayoutGroups = !TinkerButton.Visible;
|
TinkerButton.IgnoreLayoutGroups = !TinkerButton.Visible;
|
||||||
TinkerButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Tinker)) && CanTinker(character);
|
TinkerButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Tinker)) && CanTinker(character);
|
||||||
TinkerButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Tinker && CanTinker(character)) ?
|
TinkerButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Tinker) ?
|
||||||
tinkerButtonText :
|
tinkerButtonText :
|
||||||
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||||
|
|
||||||
@@ -326,6 +326,7 @@ namespace Barotrauma.Items.Components
|
|||||||
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
||||||
DeteriorateAlways = msg.ReadBoolean();
|
DeteriorateAlways = msg.ReadBoolean();
|
||||||
tinkeringDuration = msg.ReadSingle();
|
tinkeringDuration = msg.ReadSingle();
|
||||||
|
tinkeringStrength = msg.ReadSingle();
|
||||||
ushort currentFixerID = msg.ReadUInt16();
|
ushort currentFixerID = msg.ReadUInt16();
|
||||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||||
|
|||||||
@@ -316,11 +316,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||||
|
|
||||||
|
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
||||||
if (item.Quality > 0)
|
if (item.Quality > 0)
|
||||||
{
|
{
|
||||||
name = TextManager.GetWithVariable("itemname.quality" + item.Quality, "[itemname]", name, fallBackTag: "itemname.quality3");
|
// substring by to get rid of the empty space at start, text file should be adjusted
|
||||||
|
toolTip += $"\n{TextManager.GetWithVariable("itemname.quality" + item.Quality, "[itemname]", "", fallBackTag: "itemname.quality3")?.Substring(1)}";
|
||||||
}
|
}
|
||||||
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
|
||||||
|
|
||||||
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
|
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
|
||||||
{
|
{
|
||||||
@@ -1653,9 +1654,9 @@ namespace Barotrauma
|
|||||||
scale: iconSize.X / stealIcon.size.X);
|
scale: iconSize.X / stealIcon.size.X);
|
||||||
}
|
}
|
||||||
int maxStackSize = item.Prefab.MaxStackSize;
|
int maxStackSize = item.Prefab.MaxStackSize;
|
||||||
if (item.Container != null)
|
if (inventory is ItemInventory itemInventory)
|
||||||
{
|
{
|
||||||
maxStackSize = Math.Min(maxStackSize, item.Container.GetComponent<ItemContainer>()?.GetMaxStackSize(slotIndex) ?? maxStackSize);
|
maxStackSize = Math.Min(maxStackSize, itemInventory.Container.GetMaxStackSize(slotIndex));
|
||||||
}
|
}
|
||||||
if (maxStackSize > 1 && inventory != null)
|
if (maxStackSize > 1 && inventory != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace Barotrauma
|
|||||||
if (!currentDisplayLocation.Discovered)
|
if (!currentDisplayLocation.Discovered)
|
||||||
{
|
{
|
||||||
RemoveFogOfWar(currentDisplayLocation);
|
RemoveFogOfWar(currentDisplayLocation);
|
||||||
currentDisplayLocation.Discovered = true;
|
currentDisplayLocation.Discover();
|
||||||
if (currentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X)
|
if (currentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X)
|
||||||
{
|
{
|
||||||
furthestDiscoveredLocation = currentDisplayLocation;
|
furthestDiscoveredLocation = currentDisplayLocation;
|
||||||
@@ -426,7 +426,7 @@ namespace Barotrauma
|
|||||||
Level.Loaded.DebugSetStartLocation(CurrentLocation);
|
Level.Loaded.DebugSetStartLocation(CurrentLocation);
|
||||||
Level.Loaded.DebugSetEndLocation(null);
|
Level.Loaded.DebugSetEndLocation(null);
|
||||||
|
|
||||||
CurrentLocation.Discovered = true;
|
CurrentLocation.Discover();
|
||||||
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
||||||
SelectLocation(-1);
|
SelectLocation(-1);
|
||||||
if (GameMain.Client == null)
|
if (GameMain.Client == null)
|
||||||
|
|||||||
@@ -2755,6 +2755,9 @@ namespace Barotrauma.Networking
|
|||||||
msg.Write((byte)characterInfo.BeardIndex);
|
msg.Write((byte)characterInfo.BeardIndex);
|
||||||
msg.Write((byte)characterInfo.MoustacheIndex);
|
msg.Write((byte)characterInfo.MoustacheIndex);
|
||||||
msg.Write((byte)characterInfo.FaceAttachmentIndex);
|
msg.Write((byte)characterInfo.FaceAttachmentIndex);
|
||||||
|
msg.WriteColorR8G8B8(characterInfo.SkinColor);
|
||||||
|
msg.WriteColorR8G8B8(characterInfo.HairColor);
|
||||||
|
msg.WriteColorR8G8B8(characterInfo.FacialHairColor);
|
||||||
|
|
||||||
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
|
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
|
||||||
int count = Math.Min(jobPreferences.Count, 3);
|
int count = Math.Min(jobPreferences.Count, 3);
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
abstract class CampaignSetupUI
|
||||||
|
{
|
||||||
|
protected readonly GUIComponent newGameContainer, loadGameContainer;
|
||||||
|
|
||||||
|
protected GUIListBox subList;
|
||||||
|
protected GUIListBox saveList;
|
||||||
|
protected List<GUITickBox> subTickBoxes;
|
||||||
|
|
||||||
|
protected GUITextBox saveNameBox, seedBox;
|
||||||
|
|
||||||
|
protected GUILayoutGroup subPreviewContainer;
|
||||||
|
|
||||||
|
protected GUIButton loadGameButton;
|
||||||
|
|
||||||
|
public Action<SubmarineInfo, string, string, CampaignSettings> StartNewGame;
|
||||||
|
public Action<string> LoadGame;
|
||||||
|
|
||||||
|
protected enum CategoryFilter { All = 0, Vanilla = 1, Custom = 2 };
|
||||||
|
protected CategoryFilter subFilter = CategoryFilter.All;
|
||||||
|
|
||||||
|
public GUIButton StartButton
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUITextBlock InitialMoneyText
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUITickBox EnableRadiationToggle { get; set; }
|
||||||
|
public GUILayoutGroup CampaignSettingsContent { get; set; }
|
||||||
|
|
||||||
|
public GUIButton CampaignCustomizeButton { get; set; }
|
||||||
|
public GUIMessageBox CampaignCustomizeSettings { get; set; }
|
||||||
|
|
||||||
|
public GUITextBlock MaxMissionCountText;
|
||||||
|
|
||||||
|
public CampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer)
|
||||||
|
{
|
||||||
|
this.newGameContainer = newGameContainer;
|
||||||
|
this.loadGameContainer = loadGameContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+521
@@ -0,0 +1,521 @@
|
|||||||
|
using Barotrauma.Tutorials;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Barotrauma.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using System.Globalization;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class MultiPlayerCampaignSetupUI : CampaignSetupUI
|
||||||
|
{
|
||||||
|
private GUIButton deleteMpSaveButton;
|
||||||
|
|
||||||
|
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
|
||||||
|
: base(newGameContainer, loadGameContainer)
|
||||||
|
{
|
||||||
|
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.015f
|
||||||
|
};
|
||||||
|
|
||||||
|
var rightColumn = new GUILayoutGroup(new RectTransform(Vector2.Zero, columnContainer.RectTransform))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.015f
|
||||||
|
};
|
||||||
|
|
||||||
|
columnContainer.Recalculate();
|
||||||
|
|
||||||
|
// New game left side
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont);
|
||||||
|
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
|
||||||
|
{
|
||||||
|
textFilterFunction = (string str) => { return ToolBox.RemoveInvalidFileNameChars(str); }
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
|
||||||
|
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
||||||
|
|
||||||
|
// Spacing to fix the multiplayer campaign setup layout
|
||||||
|
CreateMultiplayerCampaignSubList(leftColumn.RectTransform);
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
//new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform), style: null);
|
||||||
|
|
||||||
|
// New game right side
|
||||||
|
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
|
||||||
|
{
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
|
||||||
|
leftColumn.RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
|
||||||
|
|
||||||
|
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
|
||||||
|
{
|
||||||
|
OnClicked = (GUIButton btn, object userData) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
|
||||||
|
{
|
||||||
|
saveNameBox.Flash(GUI.Style.Red);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubmarineInfo selectedSub = null;
|
||||||
|
|
||||||
|
if (GameMain.NetLobbyScreen.SelectedSub == null) { return false; }
|
||||||
|
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||||
|
|
||||||
|
if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
|
||||||
|
{
|
||||||
|
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("undefinedsubmarineselected"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
||||||
|
{
|
||||||
|
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
||||||
|
subList.SelectedComponent.CanBeFocused = false;
|
||||||
|
subList.Deselect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveNameBox.Text);
|
||||||
|
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
|
||||||
|
|
||||||
|
CampaignSettings settings = new CampaignSettings();
|
||||||
|
|
||||||
|
settings.RadiationEnabled = GameMain.NetLobbyScreen.IsRadiationEnabled();
|
||||||
|
settings.MaxMissionCount = GameMain.NetLobbyScreen.GetMaxMissionCount();
|
||||||
|
|
||||||
|
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
|
||||||
|
{
|
||||||
|
if (!hasRequiredContentPackages)
|
||||||
|
{
|
||||||
|
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
|
||||||
|
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
|
||||||
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
|
|
||||||
|
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
||||||
|
msgBox.Buttons[0].OnClicked += (button, obj) =>
|
||||||
|
{
|
||||||
|
if (GUIMessageBox.MessageBoxes.Count == 0)
|
||||||
|
{
|
||||||
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
|
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSub.HasTag(SubmarineTag.Shuttle))
|
||||||
|
{
|
||||||
|
var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
|
||||||
|
TextManager.Get("ShuttleWarning"),
|
||||||
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
|
|
||||||
|
msgBox.Buttons[0].OnClicked = (button, obj) =>
|
||||||
|
{
|
||||||
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
|
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
|
|
||||||
|
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
|
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "", font: GUI.Style.SmallFont, textColor: GUI.Style.Green)
|
||||||
|
{
|
||||||
|
TextGetter = () =>
|
||||||
|
{
|
||||||
|
int initialMoney = CampaignMode.InitialMoney;
|
||||||
|
if (GameMain.NetLobbyScreen.SelectedSub != null)
|
||||||
|
{
|
||||||
|
initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
|
||||||
|
}
|
||||||
|
initialMoney = Math.Max(initialMoney, MultiPlayerCampaign.MinimumInitialMoney);
|
||||||
|
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
columnContainer.Recalculate();
|
||||||
|
leftColumn.Recalculate();
|
||||||
|
rightColumn.Recalculate();
|
||||||
|
|
||||||
|
if (submarines != null) { UpdateSubList(submarines); }
|
||||||
|
UpdateLoadMenu(saveFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateMultiplayerCampaignSubList(RectTransform parent)
|
||||||
|
{
|
||||||
|
GUILayoutGroup subHolder = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.725f), parent))
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.005f,
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("purchasablesubmarines", fallBackTag: "workshoplabelsubmarines"), font: GUI.SubHeadingFont);
|
||||||
|
|
||||||
|
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), subHolder.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true
|
||||||
|
};
|
||||||
|
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||||
|
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
|
||||||
|
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
|
||||||
|
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||||
|
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||||
|
searchBox.OnTextChanged += (textBox, text) =>
|
||||||
|
{
|
||||||
|
foreach (GUIComponent child in subList.Content.Children)
|
||||||
|
{
|
||||||
|
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
||||||
|
child.Visible = string.IsNullOrEmpty(text) ? true : sub.DisplayName.ToLower().Contains(text.ToLower());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
subList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform));
|
||||||
|
subTickBoxes = new List<GUITickBox>();
|
||||||
|
|
||||||
|
for (int i = 0; i < GameMain.Client.ServerSubmarines.Count; i++)
|
||||||
|
{
|
||||||
|
SubmarineInfo sub = GameMain.Client.ServerSubmarines[i];
|
||||||
|
|
||||||
|
if (!sub.IsCampaignCompatible) continue;
|
||||||
|
|
||||||
|
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), subList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||||
|
style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
ToolTip = sub.Description,
|
||||||
|
UserData = sub
|
||||||
|
};
|
||||||
|
|
||||||
|
int buttonSize = (int)(frame.Rect.Height * 0.8f);
|
||||||
|
|
||||||
|
GUITickBox tickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 1.0f), frame.RectTransform, Anchor.CenterLeft), ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Content.Rect.Width - 65))
|
||||||
|
{
|
||||||
|
UserData = sub,
|
||||||
|
OnSelected = (GUITickBox box) =>
|
||||||
|
{
|
||||||
|
GameMain.Client.RequestCampaignSub(box.UserData as SubmarineInfo, box.Selected);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
subTickBoxes.Add(tickBox);
|
||||||
|
tickBox.Selected = GameMain.NetLobbyScreen.CampaignSubmarines.Contains(sub);
|
||||||
|
|
||||||
|
frame.RectTransform.MinSize = new Point(0, tickBox.RectTransform.MinSize.Y);
|
||||||
|
|
||||||
|
var subTextBlock = tickBox.TextBlock;
|
||||||
|
|
||||||
|
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
|
||||||
|
if (matchingSub == null) matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
|
||||||
|
|
||||||
|
if (matchingSub == null)
|
||||||
|
{
|
||||||
|
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||||
|
frame.ToolTip = TextManager.Get("SubNotFound");
|
||||||
|
}
|
||||||
|
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
|
||||||
|
{
|
||||||
|
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||||
|
frame.ToolTip = TextManager.Get("SubDoesntMatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sub.RequiredContentPackagesInstalled)
|
||||||
|
{
|
||||||
|
subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
|
||||||
|
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.RawToolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
||||||
|
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
TextColor = subTextBlock.TextColor * 0.8f,
|
||||||
|
ToolTip = subTextBlock.RawToolTip
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshMultiplayerCampaignSubUI(List<SubmarineInfo> campaignSubs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < subTickBoxes.Count; i++)
|
||||||
|
{
|
||||||
|
subTickBoxes[i].Selected = campaignSubs.Contains(subTickBoxes[i].UserData as SubmarineInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> WaitForCampaignSetup()
|
||||||
|
{
|
||||||
|
GUI.SetCursorWaiting();
|
||||||
|
string headerText = TextManager.Get("CampaignStartingPleaseWait");
|
||||||
|
var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new string[] { TextManager.Get("Cancel") });
|
||||||
|
|
||||||
|
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||||
|
{
|
||||||
|
GameMain.NetLobbyScreen.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||||
|
GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||||
|
GUI.ClearCursorWait();
|
||||||
|
CoroutineManager.StopCoroutines("WaitForCampaignSetup");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
|
|
||||||
|
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 20);
|
||||||
|
while (Screen.Selected != GameMain.GameScreen && DateTime.Now < timeOut)
|
||||||
|
{
|
||||||
|
msgBox.Header.Text = headerText + new string('.', (int)Timing.TotalTime % 3 + 1);
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
|
}
|
||||||
|
msgBox.Close();
|
||||||
|
GUI.ClearCursorWait();
|
||||||
|
yield return CoroutineStatus.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
|
||||||
|
{
|
||||||
|
List<SubmarineInfo> subsToShow;
|
||||||
|
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
|
||||||
|
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
|
||||||
|
|
||||||
|
subsToShow.Sort((s1, s2) =>
|
||||||
|
{
|
||||||
|
int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0;
|
||||||
|
int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0;
|
||||||
|
return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
subList.ClearChildren();
|
||||||
|
|
||||||
|
foreach (SubmarineInfo sub in subsToShow)
|
||||||
|
{
|
||||||
|
var textBlock = new GUITextBlock(
|
||||||
|
new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
|
||||||
|
ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
ToolTip = sub.Description,
|
||||||
|
UserData = sub
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!sub.RequiredContentPackagesInstalled)
|
||||||
|
{
|
||||||
|
textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f);
|
||||||
|
textBlock.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + textBlock.RawToolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
|
||||||
|
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f,
|
||||||
|
ToolTip = textBlock.ToolTip
|
||||||
|
};
|
||||||
|
#if !DEBUG
|
||||||
|
if (!GameMain.DebugDraw)
|
||||||
|
{
|
||||||
|
if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible)
|
||||||
|
{
|
||||||
|
textBlock.CanBeFocused = false;
|
||||||
|
textBlock.TextColor *= 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (SubmarineInfo.SavedSubmarines.Any())
|
||||||
|
{
|
||||||
|
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList();
|
||||||
|
if (validSubs.Count > 0)
|
||||||
|
{
|
||||||
|
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> prevSaveFiles;
|
||||||
|
public void UpdateLoadMenu(IEnumerable<string> saveFiles = null)
|
||||||
|
{
|
||||||
|
prevSaveFiles?.Clear();
|
||||||
|
prevSaveFiles = null;
|
||||||
|
loadGameContainer.ClearChildren();
|
||||||
|
|
||||||
|
if (saveFiles == null)
|
||||||
|
{
|
||||||
|
saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.85f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.03f
|
||||||
|
};
|
||||||
|
|
||||||
|
saveList = new GUIListBox(new RectTransform(Vector2.One, leftColumn.RectTransform))
|
||||||
|
{
|
||||||
|
OnSelected = SelectSaveFile
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string saveFile in saveFiles)
|
||||||
|
{
|
||||||
|
string fileName = saveFile;
|
||||||
|
string subName = "";
|
||||||
|
string saveTime = "";
|
||||||
|
string contentPackageStr = "";
|
||||||
|
var saveFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), saveList.Content.RectTransform) { MinSize = new Point(0, 45) }, style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
UserData = saveFile
|
||||||
|
};
|
||||||
|
|
||||||
|
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform), "")
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isCompatible = true;
|
||||||
|
prevSaveFiles ??= new List<string>();
|
||||||
|
|
||||||
|
prevSaveFiles?.Add(saveFile);
|
||||||
|
string[] splitSaveFile = saveFile.Split(';');
|
||||||
|
saveFrame.UserData = splitSaveFile[0];
|
||||||
|
fileName = nameText.Text = Path.GetFileNameWithoutExtension(splitSaveFile[0]);
|
||||||
|
if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; }
|
||||||
|
if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; }
|
||||||
|
if (splitSaveFile.Length > 3) { contentPackageStr = splitSaveFile[3]; }
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(saveTime) && long.TryParse(saveTime, out long unixTime))
|
||||||
|
{
|
||||||
|
DateTime time = ToolBox.Epoch.ToDateTime(unixTime);
|
||||||
|
saveTime = time.ToString();
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(contentPackageStr))
|
||||||
|
{
|
||||||
|
List<string> contentPackagePaths = contentPackageStr.Split('|').ToList();
|
||||||
|
if (!GameSession.IsCompatibleWithEnabledContentPackages(contentPackagePaths, out string errorMsg))
|
||||||
|
{
|
||||||
|
nameText.TextColor = GUI.Style.Red;
|
||||||
|
saveFrame.ToolTip = string.Join("\n", errorMsg, TextManager.Get("campaignmode.contentpackagemismatchwarning"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isCompatible)
|
||||||
|
{
|
||||||
|
nameText.TextColor = GUI.Style.Red;
|
||||||
|
saveFrame.ToolTip = TextManager.Get("campaignmode.incompatiblesave");
|
||||||
|
}
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform, Anchor.BottomLeft),
|
||||||
|
text: subName, font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
UserData = fileName
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
|
||||||
|
text: saveTime, textAlignment: Alignment.Right, font: GUI.SmallFont)
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
UserData = fileName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
saveList.Content.RectTransform.SortChildren((c1, c2) =>
|
||||||
|
{
|
||||||
|
string file1 = c1.GUIComponent.UserData as string;
|
||||||
|
string file2 = c2.GUIComponent.UserData as string;
|
||||||
|
DateTime file1WriteTime = DateTime.MinValue;
|
||||||
|
DateTime file2WriteTime = DateTime.MinValue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file1WriteTime = File.GetLastWriteTime(file1);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file2WriteTime = File.GetLastWriteTime(file2);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
||||||
|
};
|
||||||
|
return file2WriteTime.CompareTo(file1WriteTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
||||||
|
{
|
||||||
|
OnClicked = (btn, obj) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
||||||
|
LoadGame?.Invoke(saveList.SelectedData as string);
|
||||||
|
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomLeft),
|
||||||
|
TextManager.Get("Delete"), style: "GUIButtonSmall")
|
||||||
|
{
|
||||||
|
OnClicked = DeleteSave,
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SelectSaveFile(GUIComponent component, object obj)
|
||||||
|
{
|
||||||
|
string fileName = (string)obj;
|
||||||
|
|
||||||
|
loadGameButton.Enabled = true;
|
||||||
|
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
|
||||||
|
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
|
||||||
|
if (deleteMpSaveButton.Visible)
|
||||||
|
{
|
||||||
|
deleteMpSaveButton.UserData = obj as string;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DeleteSave(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
string saveFile = obj as string;
|
||||||
|
if (obj == null) { return false; }
|
||||||
|
|
||||||
|
string header = TextManager.Get("deletedialoglabel");
|
||||||
|
string body = TextManager.GetWithVariable("deletedialogquestion", "[file]", Path.GetFileNameWithoutExtension(saveFile));
|
||||||
|
|
||||||
|
EventEditorScreen.AskForConfirmation(header, body, () =>
|
||||||
|
{
|
||||||
|
SaveUtil.DeleteSave(saveFile);
|
||||||
|
prevSaveFiles?.RemoveAll(s => s.StartsWith(saveFile));
|
||||||
|
UpdateLoadMenu(prevSaveFiles.ToList());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+353
-404
@@ -10,58 +10,108 @@ using Barotrauma.Extensions;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class CampaignSetupUI
|
class SinglePlayerCampaignSetupUI : CampaignSetupUI
|
||||||
{
|
{
|
||||||
private readonly GUIComponent newGameContainer, loadGameContainer;
|
public CharacterInfo.AppearanceCustomizationMenu[] CharacterMenus { get; private set; }
|
||||||
|
|
||||||
private GUIListBox subList;
|
private GUIButton nextButton;
|
||||||
private GUIListBox saveList;
|
private GUILayoutGroup characterInfoColumns;
|
||||||
private List<GUITickBox> subTickBoxes;
|
|
||||||
|
public SinglePlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
|
||||||
private readonly GUITextBox saveNameBox, seedBox;
|
: base(newGameContainer, loadGameContainer)
|
||||||
|
|
||||||
private readonly GUILayoutGroup subPreviewContainer;
|
|
||||||
|
|
||||||
private GUIButton loadGameButton, deleteMpSaveButton;
|
|
||||||
|
|
||||||
public Action<SubmarineInfo, string, string, CampaignSettings> StartNewGame;
|
|
||||||
public Action<string> LoadGame;
|
|
||||||
|
|
||||||
private enum CategoryFilter { All = 0, Vanilla = 1, Custom = 2 };
|
|
||||||
private CategoryFilter subFilter = CategoryFilter.All;
|
|
||||||
|
|
||||||
public GUIButton StartButton
|
|
||||||
{
|
{
|
||||||
get;
|
UpdateNewGameMenu(submarines);
|
||||||
private set;
|
UpdateLoadMenu(saveFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITextBlock InitialMoneyText
|
private int currentPage = 0;
|
||||||
|
private GUIListBox pageContainer;
|
||||||
|
|
||||||
|
public void Update()
|
||||||
{
|
{
|
||||||
get;
|
float targetScroll =
|
||||||
private set;
|
(float)currentPage / ((float)pageContainer.Content.CountChildren - 1);
|
||||||
|
|
||||||
|
pageContainer.BarScroll = MathHelper.Lerp(pageContainer.BarScroll, targetScroll, 0.2f);
|
||||||
|
if (MathUtils.NearlyEqual(pageContainer.BarScroll, targetScroll, 0.001f))
|
||||||
|
{
|
||||||
|
pageContainer.BarScroll = targetScroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<CharacterMenus.Length; i++)
|
||||||
|
{
|
||||||
|
CharacterMenus[i]?.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
pageContainer.HoverCursor = CursorState.Default;
|
||||||
|
pageContainer.Content.HoverCursor = CursorState.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPage(int pageIndex)
|
||||||
|
{
|
||||||
|
currentPage = pageIndex;
|
||||||
|
for (int i = 0; i < pageContainer.Content.CountChildren; i++)
|
||||||
|
{
|
||||||
|
var child = pageContainer.Content.GetChild(i);
|
||||||
|
child.CanBeFocused = (i == currentPage);
|
||||||
|
child.GetAllChildren().ForEach(c =>
|
||||||
|
{
|
||||||
|
if (c is GUIDropDown dd)
|
||||||
|
{
|
||||||
|
dd.Dropped = false;
|
||||||
|
}
|
||||||
|
c.CanBeFocused = (i == currentPage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var previewListBox = subPreviewContainer.GetAllChildren<GUIListBox>().FirstOrDefault();
|
||||||
|
previewListBox?.GetAllChildren()?.ForEach(c =>
|
||||||
|
{
|
||||||
|
c.CanBeFocused = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUITickBox EnableRadiationToggle { get; set; }
|
private void UpdateNewGameMenu(IEnumerable<SubmarineInfo> submarines)
|
||||||
public GUILayoutGroup CampaignSettingsContent { get; set; }
|
|
||||||
|
|
||||||
public GUIButton CampaignCustomizeButton { get; set; }
|
|
||||||
public GUIMessageBox CampaignCustomizeSettings { get; set; }
|
|
||||||
|
|
||||||
public GUITextBlock MaxMissionCountText;
|
|
||||||
|
|
||||||
private readonly bool isMultiplayer;
|
|
||||||
|
|
||||||
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
|
|
||||||
{
|
{
|
||||||
this.isMultiplayer = isMultiplayer;
|
pageContainer =
|
||||||
this.newGameContainer = newGameContainer;
|
new GUIListBox(new RectTransform(Vector2.One, newGameContainer.RectTransform), style: null, isHorizontal: true)
|
||||||
this.loadGameContainer = loadGameContainer;
|
{
|
||||||
|
ScrollBarEnabled = false,
|
||||||
|
ScrollBarVisible = false,
|
||||||
|
HoverCursor = CursorState.Default
|
||||||
|
};
|
||||||
|
|
||||||
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
|
GUILayoutGroup createPageLayout()
|
||||||
|
{
|
||||||
|
var containerItem =
|
||||||
|
new GUIFrame(new RectTransform(Vector2.One, pageContainer.Content.RectTransform), style: null);
|
||||||
|
return new GUILayoutGroup(new RectTransform(Vector2.One * 0.95f, containerItem.RectTransform,
|
||||||
|
Anchor.Center));
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFirstPage(createPageLayout(), submarines);
|
||||||
|
CreateSecondPage(createPageLayout());
|
||||||
|
|
||||||
|
pageContainer.RecalculateChildren();
|
||||||
|
pageContainer.GetAllChildren().ForEach(c =>
|
||||||
|
{
|
||||||
|
c.ClampMouseRectToParent = true;
|
||||||
|
});
|
||||||
|
pageContainer.GetAllChildren<GUIDropDown>().ForEach(dd =>
|
||||||
|
{
|
||||||
|
dd.ListBox.ClampMouseRectToParent = false;
|
||||||
|
dd.ListBox.Content.ClampMouseRectToParent = false;
|
||||||
|
});
|
||||||
|
SetPage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateFirstPage(GUILayoutGroup firstPageLayout, IEnumerable<SubmarineInfo> submarines)
|
||||||
|
{
|
||||||
|
firstPageLayout.RelativeSpacing = 0.02f;
|
||||||
|
|
||||||
|
var columnContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), firstPageLayout.RectTransform), isHorizontal: true)
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = isMultiplayer ? 0.0f : 0.02f
|
RelativeSpacing = 0.02f
|
||||||
};
|
};
|
||||||
|
|
||||||
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
||||||
@@ -70,7 +120,7 @@ namespace Barotrauma
|
|||||||
RelativeSpacing = 0.015f
|
RelativeSpacing = 0.015f
|
||||||
};
|
};
|
||||||
|
|
||||||
var rightColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? Vector2.Zero : new Vector2(1.5f, 1.0f), columnContainer.RectTransform))
|
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.5f, 1.0f), columnContainer.RectTransform))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.015f
|
RelativeSpacing = 0.015f
|
||||||
@@ -88,47 +138,37 @@ namespace Barotrauma
|
|||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
|
||||||
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
||||||
|
|
||||||
if (!isMultiplayer)
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub"), font: GUI.SubHeadingFont);
|
||||||
|
|
||||||
|
var moddedDropdown = new GUIDropDown(new RectTransform(new Vector2(1f, 0.02f), leftColumn.RectTransform), "", 3);
|
||||||
|
moddedDropdown.AddItem(TextManager.Get("clientpermission.all"), CategoryFilter.All);
|
||||||
|
moddedDropdown.AddItem(TextManager.Get("servertag.modded.false"), CategoryFilter.Vanilla);
|
||||||
|
moddedDropdown.AddItem(TextManager.Get("customrank"), CategoryFilter.Custom);
|
||||||
|
moddedDropdown.Select(0);
|
||||||
|
|
||||||
|
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub"), font: GUI.SubHeadingFont);
|
Stretch = true
|
||||||
|
};
|
||||||
|
|
||||||
var moddedDropdown = new GUIDropDown(new RectTransform(new Vector2(1f, 0.02f), leftColumn.RectTransform), "", 3);
|
subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true };
|
||||||
moddedDropdown.AddItem(TextManager.Get("clientpermission.all"), CategoryFilter.All);
|
|
||||||
moddedDropdown.AddItem(TextManager.Get("servertag.modded.false"), CategoryFilter.Vanilla);
|
|
||||||
moddedDropdown.AddItem(TextManager.Get("customrank"), CategoryFilter.Custom);
|
|
||||||
moddedDropdown.Select(0);
|
|
||||||
|
|
||||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
|
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||||
{
|
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
|
||||||
Stretch = true
|
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
|
||||||
};
|
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||||
|
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||||
|
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
|
||||||
|
|
||||||
subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true };
|
moddedDropdown.OnSelected = (component, data) =>
|
||||||
|
|
||||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
|
||||||
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
|
|
||||||
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
|
|
||||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
|
||||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
|
||||||
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
|
|
||||||
|
|
||||||
moddedDropdown.OnSelected = (component, data) =>
|
|
||||||
{
|
|
||||||
searchBox.Text = string.Empty;
|
|
||||||
subFilter = (CategoryFilter)data;
|
|
||||||
UpdateSubList(SubmarineInfo.SavedSubmarines);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
subList.OnSelected = OnSubSelected;
|
|
||||||
}
|
|
||||||
else // Spacing to fix the multiplayer campaign setup layout
|
|
||||||
{
|
{
|
||||||
CreateMultiplayerCampaignSubList(leftColumn.RectTransform);
|
searchBox.Text = string.Empty;
|
||||||
|
subFilter = (CategoryFilter)data;
|
||||||
|
UpdateSubList(SubmarineInfo.SavedSubmarines);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
//spacing
|
subList.OnSelected = OnSubSelected;
|
||||||
//new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform), style: null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// New game right side
|
// New game right side
|
||||||
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
|
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
|
||||||
@@ -136,176 +176,162 @@ namespace Barotrauma
|
|||||||
Stretch = true
|
Stretch = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
|
var firstPageButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f),
|
||||||
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
|
firstPageLayout.RectTransform), childAnchor: Anchor.BottomLeft, isHorizontal: true)
|
||||||
if (!isMultiplayer) { buttonContainer.IgnoreLayoutGroups = true; }
|
|
||||||
|
|
||||||
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
|
|
||||||
{
|
{
|
||||||
OnClicked = (GUIButton btn, object userData) =>
|
RelativeSpacing = 0.025f
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
|
|
||||||
{
|
|
||||||
saveNameBox.Flash(GUI.Style.Red);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubmarineInfo selectedSub = null;
|
|
||||||
|
|
||||||
if (!isMultiplayer)
|
|
||||||
{
|
|
||||||
if (!(subList.SelectedData is SubmarineInfo)) { return false; }
|
|
||||||
selectedSub = subList.SelectedData as SubmarineInfo;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GameMain.NetLobbyScreen.SelectedSub == null) { return false; }
|
|
||||||
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
|
|
||||||
{
|
|
||||||
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("undefinedsubmarineselected"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
|
||||||
{
|
|
||||||
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
|
||||||
subList.SelectedComponent.CanBeFocused = false;
|
|
||||||
subList.Deselect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
|
|
||||||
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
|
|
||||||
|
|
||||||
CampaignSettings settings = new CampaignSettings();
|
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
settings.RadiationEnabled = GameMain.NetLobbyScreen.IsRadiationEnabled();
|
|
||||||
settings.MaxMissionCount = GameMain.NetLobbyScreen.GetMaxMissionCount();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
settings.RadiationEnabled = EnableRadiationToggle?.Selected ?? false;
|
|
||||||
if (MaxMissionCountText != null && Int32.TryParse(MaxMissionCountText.Text, out int missionCount))
|
|
||||||
{
|
|
||||||
settings.MaxMissionCount = missionCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
settings.MaxMissionCount = CampaignSettings.DefaultMaxMissionCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
|
|
||||||
{
|
|
||||||
if (!hasRequiredContentPackages)
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
|
|
||||||
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
|
|
||||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
|
||||||
|
|
||||||
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
|
||||||
msgBox.Buttons[0].OnClicked += (button, obj) =>
|
|
||||||
{
|
|
||||||
if (GUIMessageBox.MessageBoxes.Count == 0)
|
|
||||||
{
|
|
||||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedSub.HasTag(SubmarineTag.Shuttle))
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
|
|
||||||
TextManager.Get("ShuttleWarning"),
|
|
||||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
|
||||||
|
|
||||||
msgBox.Buttons[0].OnClicked = (button, obj) =>
|
|
||||||
{
|
|
||||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
|
||||||
|
|
||||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(isMultiplayer ? 0.6f : 0.3f, 1f), buttonContainer.RectTransform), "", font: isMultiplayer ? GUI.Style.SmallFont : GUI.Style.Font, textColor: GUI.Style.Green)
|
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1f), firstPageButtonContainer.RectTransform), "", font: GUI.Style.Font, textColor: GUI.Style.Green, textAlignment: Alignment.CenterLeft)
|
||||||
{
|
{
|
||||||
TextGetter = () =>
|
TextGetter = () =>
|
||||||
{
|
{
|
||||||
int initialMoney = CampaignMode.InitialMoney;
|
int initialMoney = CampaignMode.InitialMoney;
|
||||||
if (isMultiplayer)
|
if (subList.SelectedData is SubmarineInfo subInfo)
|
||||||
{
|
|
||||||
if (GameMain.NetLobbyScreen.SelectedSub != null)
|
|
||||||
{
|
|
||||||
initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (subList.SelectedData is SubmarineInfo subInfo)
|
|
||||||
{
|
{
|
||||||
initialMoney -= subInfo.Price;
|
initialMoney -= subInfo.Price;
|
||||||
}
|
}
|
||||||
initialMoney = Math.Max(initialMoney, isMultiplayer ? MultiPlayerCampaign.MinimumInitialMoney : 0);
|
initialMoney = Math.Max(initialMoney, 0);
|
||||||
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
|
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isMultiplayer)
|
CampaignCustomizeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1f), firstPageButtonContainer.RectTransform, Anchor.CenterLeft), TextManager.Get("SettingsButton"))
|
||||||
{
|
{
|
||||||
CampaignCustomizeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1f), buttonContainer.RectTransform, Anchor.CenterLeft), TextManager.Get("SettingsButton"))
|
OnClicked = (tb, userdata) =>
|
||||||
{
|
{
|
||||||
OnClicked = (tb, userdata) =>
|
CreateCustomizeWindow();
|
||||||
{
|
return true;
|
||||||
CreateCustomizeWindow();
|
}
|
||||||
return true;
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(5) }, style: "GUINotificationButton")
|
nextButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), firstPageButtonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("Next"))
|
||||||
|
{
|
||||||
|
OnClicked = (GUIButton btn, object userData) =>
|
||||||
{
|
{
|
||||||
IgnoreLayoutGroups = true,
|
SetPage(1);
|
||||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowCampaignDisclaimer(); return true; }
|
return false;
|
||||||
};
|
}
|
||||||
disclaimerBtn.RectTransform.MaxSize = new Point((int)(30 * GUI.Scale));
|
};
|
||||||
}
|
|
||||||
|
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(5) }, style: "GUINotificationButton")
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
OnClicked = (btn, userdata) => { GameMain.Instance.ShowCampaignDisclaimer(); return true; }
|
||||||
|
};
|
||||||
|
disclaimerBtn.RectTransform.MaxSize = new Point((int)(30 * GUI.Scale));
|
||||||
|
|
||||||
columnContainer.Recalculate();
|
columnContainer.Recalculate();
|
||||||
leftColumn.Recalculate();
|
leftColumn.Recalculate();
|
||||||
rightColumn.Recalculate();
|
rightColumn.Recalculate();
|
||||||
|
|
||||||
if (submarines != null) { UpdateSubList(submarines); }
|
if (submarines != null) { UpdateSubList(submarines); }
|
||||||
UpdateLoadMenu(saveFiles);
|
}
|
||||||
|
|
||||||
|
private void CreateSecondPage(GUILayoutGroup secondPageLayout)
|
||||||
|
{
|
||||||
|
secondPageLayout.RelativeSpacing = 0.01f;
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.04f), secondPageLayout.RectTransform),
|
||||||
|
TextManager.Get("Crew"), font: GUI.Style.SubHeadingFont, textAlignment: Alignment.TopLeft);
|
||||||
|
|
||||||
|
characterInfoColumns = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.86f), secondPageLayout.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.01f
|
||||||
|
};
|
||||||
|
|
||||||
|
var secondPageButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f),
|
||||||
|
secondPageLayout.RectTransform), childAnchor: Anchor.BottomLeft, isHorizontal: true)
|
||||||
|
{
|
||||||
|
RelativeSpacing = 0.2f
|
||||||
|
};
|
||||||
|
|
||||||
|
var backButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), secondPageButtonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("Back"))
|
||||||
|
{
|
||||||
|
OnClicked = (GUIButton btn, object userData) =>
|
||||||
|
{
|
||||||
|
SetPage(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), secondPageButtonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("StartCampaignButton"))
|
||||||
|
{
|
||||||
|
OnClicked = FinishSetup
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RandomizeCrew()
|
||||||
|
{
|
||||||
|
var characterInfos = new List<(CharacterInfo Info, JobPrefab Job)>();
|
||||||
|
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < jobPrefab.InitialCount; i++)
|
||||||
|
{
|
||||||
|
var variant = Rand.Range(0, jobPrefab.Variants);
|
||||||
|
characterInfos.Add((new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant), jobPrefab));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
characterInfoColumns.ClearChildren();
|
||||||
|
CharacterMenus?.ForEach(m => m.Dispose());
|
||||||
|
CharacterMenus = new CharacterInfo.AppearanceCustomizationMenu[characterInfos.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < characterInfos.Count; i++)
|
||||||
|
{
|
||||||
|
var subLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f / characterInfos.Count, 1.0f),
|
||||||
|
characterInfoColumns.RectTransform));
|
||||||
|
|
||||||
|
var (characterInfo, job) = characterInfos[i];
|
||||||
|
|
||||||
|
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 characterName = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), subLayout.RectTransform))
|
||||||
|
{
|
||||||
|
Text = characterInfo.Name,
|
||||||
|
UserData = "random"
|
||||||
|
};
|
||||||
|
characterName.OnDeselected += (sender, key) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sender.Text))
|
||||||
|
{
|
||||||
|
characterInfo.Name = characterInfo.GetRandomName(Rand.RandSync.Unsynced);
|
||||||
|
sender.Text = characterInfo.Name;
|
||||||
|
sender.UserData = "random";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
characterInfo.Name = sender.Text;
|
||||||
|
sender.UserData = "user";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
characterName.OnEnterPressed += (sender, text) =>
|
||||||
|
{
|
||||||
|
sender.Deselect();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var customizationFrame =
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f), subLayout.RectTransform), style: null);
|
||||||
|
CharacterMenus[i] =
|
||||||
|
new CharacterInfo.AppearanceCustomizationMenu(characterInfo, customizationFrame, hasIcon: false)
|
||||||
|
{
|
||||||
|
OnHeadSwitch = menu =>
|
||||||
|
{
|
||||||
|
if (characterName.UserData is string ud && ud == "random")
|
||||||
|
{
|
||||||
|
characterInfo.Name = characterInfo.GetRandomName(Rand.RandSync.Unsynced);
|
||||||
|
characterName.Text = characterInfo.Name;
|
||||||
|
characterName.UserData = "random";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateCustomizeWindow()
|
private void CreateCustomizeWindow()
|
||||||
{
|
{
|
||||||
CampaignCustomizeSettings = new GUIMessageBox("", "", new string[] { TextManager.Get("OK") }, new Vector2(0.2f, 0.2f));
|
CampaignCustomizeSettings = new GUIMessageBox("", "", new string[] { TextManager.Get("OK") }, new Vector2(0.2f, 0.2f));
|
||||||
@@ -355,106 +381,93 @@ namespace Barotrauma
|
|||||||
maxMissionCountContainer.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
|
maxMissionCountContainer.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateMultiplayerCampaignSubList(RectTransform parent)
|
private bool FinishSetup(GUIButton btn, object userdata)
|
||||||
{
|
{
|
||||||
GUILayoutGroup subHolder = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.725f), parent))
|
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
|
||||||
{
|
{
|
||||||
RelativeSpacing = 0.005f,
|
saveNameBox.Flash(GUI.Style.Red);
|
||||||
Stretch = true
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("purchasablesubmarines", fallBackTag: "workshoplabelsubmarines"), font: GUI.SubHeadingFont);
|
SubmarineInfo selectedSub = null;
|
||||||
|
|
||||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), subHolder.RectTransform), isHorizontal: true)
|
if (!(subList.SelectedData is SubmarineInfo)) { return false; }
|
||||||
|
selectedSub = subList.SelectedData as SubmarineInfo;
|
||||||
|
|
||||||
|
if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
|
||||||
{
|
{
|
||||||
Stretch = true
|
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("undefinedsubmarineselected"));
|
||||||
};
|
return false;
|
||||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
}
|
||||||
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
|
|
||||||
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
|
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
||||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
|
||||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
|
||||||
searchBox.OnTextChanged += (textBox, text) =>
|
|
||||||
{
|
{
|
||||||
foreach (GUIComponent child in subList.Content.Children)
|
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
||||||
|
subList.SelectedComponent.CanBeFocused = false;
|
||||||
|
subList.Deselect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
|
||||||
|
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
|
||||||
|
|
||||||
|
CampaignSettings settings = new CampaignSettings();
|
||||||
|
settings.RadiationEnabled = EnableRadiationToggle?.Selected ?? false;
|
||||||
|
if (MaxMissionCountText != null && Int32.TryParse(MaxMissionCountText.Text, out int missionCount))
|
||||||
|
{
|
||||||
|
settings.MaxMissionCount = missionCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
settings.MaxMissionCount = CampaignSettings.DefaultMaxMissionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
|
||||||
|
{
|
||||||
|
if (!hasRequiredContentPackages)
|
||||||
{
|
{
|
||||||
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
|
||||||
child.Visible = string.IsNullOrEmpty(text) ? true : sub.DisplayName.ToLower().Contains(text.ToLower());
|
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
|
||||||
}
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
subList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform));
|
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
||||||
subTickBoxes = new List<GUITickBox>();
|
msgBox.Buttons[0].OnClicked += (button, obj) =>
|
||||||
|
|
||||||
for (int i = 0; i < GameMain.Client.ServerSubmarines.Count; i++)
|
|
||||||
{
|
|
||||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[i];
|
|
||||||
|
|
||||||
if (!sub.IsCampaignCompatible) continue;
|
|
||||||
|
|
||||||
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), subList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
|
||||||
style: "ListBoxElement")
|
|
||||||
{
|
|
||||||
ToolTip = sub.Description,
|
|
||||||
UserData = sub
|
|
||||||
};
|
|
||||||
|
|
||||||
int buttonSize = (int)(frame.Rect.Height * 0.8f);
|
|
||||||
|
|
||||||
GUITickBox tickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 1.0f), frame.RectTransform, Anchor.CenterLeft), ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Content.Rect.Width - 65))
|
|
||||||
{
|
|
||||||
UserData = sub,
|
|
||||||
OnSelected = (GUITickBox box) =>
|
|
||||||
{
|
{
|
||||||
GameMain.Client.RequestCampaignSub(box.UserData as SubmarineInfo, box.Selected);
|
if (GUIMessageBox.MessageBoxes.Count == 0)
|
||||||
|
{
|
||||||
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
};
|
|
||||||
subTickBoxes.Add(tickBox);
|
|
||||||
tickBox.Selected = GameMain.NetLobbyScreen.CampaignSubmarines.Contains(sub);
|
|
||||||
|
|
||||||
frame.RectTransform.MinSize = new Point(0, tickBox.RectTransform.MinSize.Y);
|
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||||
|
|
||||||
var subTextBlock = tickBox.TextBlock;
|
|
||||||
|
|
||||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
|
|
||||||
if (matchingSub == null) matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
|
|
||||||
|
|
||||||
if (matchingSub == null)
|
|
||||||
{
|
|
||||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
|
||||||
frame.ToolTip = TextManager.Get("SubNotFound");
|
|
||||||
}
|
|
||||||
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
|
|
||||||
{
|
|
||||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
|
||||||
frame.ToolTip = TextManager.Get("SubDoesntMatch");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sub.RequiredContentPackagesInstalled)
|
if (selectedSub.HasTag(SubmarineTag.Shuttle))
|
||||||
{
|
{
|
||||||
subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
|
var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
|
||||||
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.RawToolTip;
|
TextManager.Get("ShuttleWarning"),
|
||||||
}
|
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
|
|
||||||
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
msgBox.Buttons[0].OnClicked = (button, obj) =>
|
||||||
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
{
|
||||||
{
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
TextColor = subTextBlock.TextColor * 0.8f,
|
return true;
|
||||||
ToolTip = subTextBlock.RawToolTip
|
};
|
||||||
};
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
|
|
||||||
|
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
public void RefreshMultiplayerCampaignSubUI(List<SubmarineInfo> campaignSubs)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < subTickBoxes.Count; i++)
|
|
||||||
{
|
{
|
||||||
subTickBoxes[i].Selected = campaignSubs.Contains(subTickBoxes[i].UserData as SubmarineInfo);
|
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void RandomizeSeed()
|
public void RandomizeSeed()
|
||||||
{
|
{
|
||||||
seedBox.Text = ToolBox.RandomSeed(8);
|
seedBox.Text = ToolBox.RandomSeed(8);
|
||||||
@@ -478,54 +491,28 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!(obj is SubmarineInfo sub)) { return true; }
|
if (!(obj is SubmarineInfo sub)) { return true; }
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (!isMultiplayer && sub.Price > CampaignMode.InitialMoney && !GameMain.DebugDraw)
|
if (sub.Price > CampaignMode.InitialMoney && !GameMain.DebugDraw)
|
||||||
{
|
{
|
||||||
StartButton.Enabled = false;
|
SetPage(0);
|
||||||
|
nextButton.Enabled = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
StartButton.Enabled = true;
|
nextButton.Enabled = true;
|
||||||
sub.CreatePreviewWindow(subPreviewContainer);
|
sub.CreatePreviewWindow(subPreviewContainer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<object> WaitForCampaignSetup()
|
|
||||||
{
|
|
||||||
GUI.SetCursorWaiting();
|
|
||||||
string headerText = TextManager.Get("CampaignStartingPleaseWait");
|
|
||||||
var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new string[] { TextManager.Get("Cancel") });
|
|
||||||
|
|
||||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
|
||||||
{
|
|
||||||
GameMain.NetLobbyScreen.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
|
||||||
GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
|
||||||
GUI.ClearCursorWait();
|
|
||||||
CoroutineManager.StopCoroutines("WaitForCampaignSetup");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
|
||||||
|
|
||||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 20);
|
|
||||||
while (Screen.Selected != GameMain.GameScreen && DateTime.Now < timeOut)
|
|
||||||
{
|
|
||||||
msgBox.Header.Text = headerText + new string('.', (int)Timing.TotalTime % 3 + 1);
|
|
||||||
yield return CoroutineStatus.Running;
|
|
||||||
}
|
|
||||||
msgBox.Close();
|
|
||||||
GUI.ClearCursorWait();
|
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateDefaultSaveName()
|
public void CreateDefaultSaveName()
|
||||||
{
|
{
|
||||||
string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer);
|
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Singleplayer);
|
||||||
saveNameBox.Text = Path.GetFileNameWithoutExtension(savePath);
|
saveNameBox.Text = Path.GetFileNameWithoutExtension(savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
|
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
|
||||||
{
|
{
|
||||||
List<SubmarineInfo> subsToShow;
|
List<SubmarineInfo> subsToShow;
|
||||||
if (!isMultiplayer && subFilter != CategoryFilter.All)
|
if (subFilter != CategoryFilter.All)
|
||||||
{
|
{
|
||||||
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && s.IsVanillaSubmarine() == (subFilter == CategoryFilter.Vanilla)).ToList();
|
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && s.IsVanillaSubmarine() == (subFilter == CategoryFilter.Vanilla)).ToList();
|
||||||
}
|
}
|
||||||
@@ -596,10 +583,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (saveFiles == null)
|
if (saveFiles == null)
|
||||||
{
|
{
|
||||||
saveFiles = SaveUtil.GetSaveFiles(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer);
|
saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Singleplayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
var leftColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? new Vector2(1.0f, 0.85f) : new Vector2(0.5f, 1.0f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
|
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.03f
|
RelativeSpacing = 0.03f
|
||||||
@@ -610,26 +597,23 @@ namespace Barotrauma
|
|||||||
OnSelected = SelectSaveFile
|
OnSelected = SelectSaveFile
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isMultiplayer)
|
new GUIButton(new RectTransform(new Vector2(0.6f, 0.08f), leftColumn.RectTransform), TextManager.Get("showinfolder"))
|
||||||
{
|
{
|
||||||
new GUIButton(new RectTransform(new Vector2(0.6f, 0.08f), leftColumn.RectTransform), TextManager.Get("showinfolder"))
|
OnClicked = (btn, userdata) =>
|
||||||
{
|
{
|
||||||
OnClicked = (btn, userdata) =>
|
try
|
||||||
{
|
{
|
||||||
try
|
ToolBox.OpenFileWithShell(SaveUtil.SaveFolder);
|
||||||
{
|
|
||||||
ToolBox.OpenFileWithShell(SaveUtil.SaveFolder);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
new GUIMessageBox(
|
|
||||||
TextManager.Get("error"),
|
|
||||||
TextManager.GetWithVariables("showinfoldererror", new string[] { "[folder]", "[errormessage]" }, new string[] { SaveUtil.SaveFolder, e.Message }));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
new GUIMessageBox(
|
||||||
|
TextManager.Get("error"),
|
||||||
|
TextManager.GetWithVariables("showinfoldererror", new string[] { "[folder]", "[errormessage]" }, new string[] { SaveUtil.SaveFolder, e.Message }));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
foreach (string saveFile in saveFiles)
|
foreach (string saveFile in saveFiles)
|
||||||
{
|
{
|
||||||
@@ -649,39 +633,27 @@ namespace Barotrauma
|
|||||||
|
|
||||||
bool isCompatible = true;
|
bool isCompatible = true;
|
||||||
prevSaveFiles ??= new List<string>();
|
prevSaveFiles ??= new List<string>();
|
||||||
if (!isMultiplayer)
|
|
||||||
{
|
|
||||||
nameText.Text = Path.GetFileNameWithoutExtension(saveFile);
|
|
||||||
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
|
|
||||||
|
|
||||||
if (doc?.Root == null)
|
nameText.Text = Path.GetFileNameWithoutExtension(saveFile);
|
||||||
{
|
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
|
||||||
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
|
|
||||||
nameText.TextColor = GUI.Style.Red;
|
if (doc?.Root == null)
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (doc.Root.GetChildElement("multiplayercampaign") != null)
|
|
||||||
{
|
|
||||||
//multiplayer campaign save in the wrong folder -> don't show the save
|
|
||||||
saveList.Content.RemoveChild(saveFrame);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
subName = doc.Root.GetAttributeString("submarine", "");
|
|
||||||
saveTime = doc.Root.GetAttributeString("savetime", "");
|
|
||||||
isCompatible = SaveUtil.IsSaveFileCompatible(doc);
|
|
||||||
contentPackageStr = doc.Root.GetAttributeString("selectedcontentpackages", "");
|
|
||||||
prevSaveFiles?.Add(saveFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
prevSaveFiles?.Add(saveFile);
|
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
|
||||||
string[] splitSaveFile = saveFile.Split(';');
|
nameText.TextColor = GUI.Style.Red;
|
||||||
saveFrame.UserData = splitSaveFile[0];
|
continue;
|
||||||
fileName = nameText.Text = Path.GetFileNameWithoutExtension(splitSaveFile[0]);
|
|
||||||
if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; }
|
|
||||||
if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; }
|
|
||||||
if (splitSaveFile.Length > 3) { contentPackageStr = splitSaveFile[3]; }
|
|
||||||
}
|
}
|
||||||
|
if (doc.Root.GetChildElement("multiplayercampaign") != null)
|
||||||
|
{
|
||||||
|
//multiplayer campaign save in the wrong folder -> don't show the save
|
||||||
|
saveList.Content.RemoveChild(saveFrame);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
subName = doc.Root.GetAttributeString("submarine", "");
|
||||||
|
saveTime = doc.Root.GetAttributeString("savetime", "");
|
||||||
|
isCompatible = SaveUtil.IsSaveFileCompatible(doc);
|
||||||
|
contentPackageStr = doc.Root.GetAttributeString("selectedcontentpackages", "");
|
||||||
|
prevSaveFiles?.Add(saveFile);
|
||||||
if (!string.IsNullOrEmpty(saveTime) && long.TryParse(saveTime, out long unixTime))
|
if (!string.IsNullOrEmpty(saveTime) && long.TryParse(saveTime, out long unixTime))
|
||||||
{
|
{
|
||||||
DateTime time = ToolBox.Epoch.ToDateTime(unixTime);
|
DateTime time = ToolBox.Epoch.ToDateTime(unixTime);
|
||||||
@@ -748,38 +720,16 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
||||||
LoadGame?.Invoke(saveList.SelectedData as string);
|
LoadGame?.Invoke(saveList.SelectedData as string);
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomLeft),
|
|
||||||
TextManager.Get("Delete"), style: "GUIButtonSmall")
|
|
||||||
{
|
|
||||||
OnClicked = DeleteSave,
|
|
||||||
Visible = false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectSaveFile(GUIComponent component, object obj)
|
private bool SelectSaveFile(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
string fileName = (string)obj;
|
string fileName = (string)obj;
|
||||||
|
|
||||||
if (isMultiplayer)
|
|
||||||
{
|
|
||||||
loadGameButton.Enabled = true;
|
|
||||||
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
|
|
||||||
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
|
|
||||||
if (deleteMpSaveButton.Visible)
|
|
||||||
{
|
|
||||||
deleteMpSaveButton.UserData = obj as string;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
||||||
if (doc?.Root == null)
|
if (doc?.Root == null)
|
||||||
{
|
{
|
||||||
@@ -868,6 +818,5 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
loadGameContainer.RemoveChild(prevFrame);
|
loadGameContainer.RemoveChild(prevFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+22
-25
@@ -182,7 +182,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
showSpritesheet = false;
|
showSpritesheet = false;
|
||||||
isFrozen = false;
|
isFrozen = false;
|
||||||
autoFreeze = false;
|
autoFreeze = false;
|
||||||
limbPairEditing = true;
|
limbPairEditing = false;
|
||||||
uniformScaling = true;
|
uniformScaling = true;
|
||||||
lockSpriteOrigin = true;
|
lockSpriteOrigin = true;
|
||||||
lockSpritePosition = false;
|
lockSpritePosition = false;
|
||||||
@@ -1581,7 +1581,6 @@ namespace Barotrauma.CharacterEditor
|
|||||||
Character.Controlled = character;
|
Character.Controlled = character;
|
||||||
SetWallCollisions(character.AnimController.forceStanding);
|
SetWallCollisions(character.AnimController.forceStanding);
|
||||||
CreateTextures();
|
CreateTextures();
|
||||||
limbPairEditing = character.IsHumanoid;
|
|
||||||
CreateGUI();
|
CreateGUI();
|
||||||
ClearWidgets();
|
ClearWidgets();
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
@@ -1803,6 +1802,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
case AnimationType.Walk:
|
case AnimationType.Walk:
|
||||||
case AnimationType.Run:
|
case AnimationType.Run:
|
||||||
|
case AnimationType.Crouch:
|
||||||
if (!ragdollParams.CanWalk) { continue; }
|
if (!ragdollParams.CanWalk) { continue; }
|
||||||
break;
|
break;
|
||||||
case AnimationType.SwimSlow:
|
case AnimationType.SwimSlow:
|
||||||
@@ -1819,8 +1819,8 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
AllFiles.Add(configFilePath);
|
AllFiles.Add(configFilePath);
|
||||||
}
|
}
|
||||||
limbPairEditing = false;
|
|
||||||
SpawnCharacter(configFilePath, ragdollParams);
|
SpawnCharacter(configFilePath, ragdollParams);
|
||||||
|
limbPairEditing = false;
|
||||||
limbsToggle.Selected = true;
|
limbsToggle.Selected = true;
|
||||||
recalculateColliderToggle.Selected = true;
|
recalculateColliderToggle.Selected = true;
|
||||||
lockSpriteOriginToggle.Selected = false;
|
lockSpriteOriginToggle.Selected = false;
|
||||||
@@ -2599,11 +2599,15 @@ namespace Barotrauma.CharacterEditor
|
|||||||
var layoutGroupAnimation = new GUILayoutGroup(new RectTransform(Vector2.One, animationControls.RectTransform), childAnchor: Anchor.TopLeft) { CanBeFocused = false };
|
var layoutGroupAnimation = new GUILayoutGroup(new RectTransform(Vector2.One, animationControls.RectTransform), childAnchor: Anchor.TopLeft) { CanBeFocused = false };
|
||||||
var animationSelectionElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2 - (int)(5 * GUI.xScale), elementSize.Y), layoutGroupAnimation.RectTransform), style: null);
|
var animationSelectionElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2 - (int)(5 * GUI.xScale), elementSize.Y), layoutGroupAnimation.RectTransform), style: null);
|
||||||
var animationSelectionText = new GUITextBlock(new RectTransform(new Point(elementSize.X, elementSize.Y), animationSelectionElement.RectTransform), GetCharacterEditorTranslation("SelectedAnimation") + ": ", Color.WhiteSmoke, textAlignment: Alignment.Center);
|
var animationSelectionText = new GUITextBlock(new RectTransform(new Point(elementSize.X, elementSize.Y), animationSelectionElement.RectTransform), GetCharacterEditorTranslation("SelectedAnimation") + ": ", Color.WhiteSmoke, textAlignment: Alignment.Center);
|
||||||
animSelection = new GUIDropDown(new RectTransform(new Point((int)(100 * GUI.xScale), elementSize.Y), animationSelectionElement.RectTransform, Anchor.TopRight), elementCount: 4);
|
animSelection = new GUIDropDown(new RectTransform(new Point((int)(100 * GUI.xScale), elementSize.Y), animationSelectionElement.RectTransform, Anchor.TopRight), elementCount: 5);
|
||||||
if (character.AnimController.CanWalk)
|
if (character.AnimController.CanWalk)
|
||||||
{
|
{
|
||||||
animSelection.AddItem(AnimationType.Walk.ToString(), AnimationType.Walk);
|
animSelection.AddItem(AnimationType.Walk.ToString(), AnimationType.Walk);
|
||||||
animSelection.AddItem(AnimationType.Run.ToString(), AnimationType.Run);
|
animSelection.AddItem(AnimationType.Run.ToString(), AnimationType.Run);
|
||||||
|
if (character.IsHumanoid)
|
||||||
|
{
|
||||||
|
animSelection.AddItem(AnimationType.Crouch.ToString(), AnimationType.Crouch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
animSelection.AddItem(AnimationType.SwimSlow.ToString(), AnimationType.SwimSlow);
|
animSelection.AddItem(AnimationType.SwimSlow.ToString(), AnimationType.SwimSlow);
|
||||||
animSelection.AddItem(AnimationType.SwimFast.ToString(), AnimationType.SwimFast);
|
animSelection.AddItem(AnimationType.SwimFast.ToString(), AnimationType.SwimFast);
|
||||||
@@ -2622,25 +2626,15 @@ namespace Barotrauma.CharacterEditor
|
|||||||
switch (character.AnimController.ForceSelectAnimationType)
|
switch (character.AnimController.ForceSelectAnimationType)
|
||||||
{
|
{
|
||||||
case AnimationType.Walk:
|
case AnimationType.Walk:
|
||||||
character.AnimController.forceStanding = true;
|
|
||||||
character.ForceRun = false;
|
|
||||||
if (!wallCollisionsEnabled)
|
|
||||||
{
|
|
||||||
SetWallCollisions(true);
|
|
||||||
}
|
|
||||||
if (previousAnim != AnimationType.Walk && previousAnim != AnimationType.Run)
|
|
||||||
{
|
|
||||||
TeleportTo(spawnPosition);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AnimationType.Run:
|
case AnimationType.Run:
|
||||||
|
case AnimationType.Crouch:
|
||||||
character.AnimController.forceStanding = true;
|
character.AnimController.forceStanding = true;
|
||||||
character.ForceRun = true;
|
character.ForceRun = character.AnimController.ForceSelectAnimationType == AnimationType.Run;
|
||||||
if (!wallCollisionsEnabled)
|
if (!wallCollisionsEnabled)
|
||||||
{
|
{
|
||||||
SetWallCollisions(true);
|
SetWallCollisions(true);
|
||||||
}
|
}
|
||||||
if (previousAnim != AnimationType.Walk && previousAnim != AnimationType.Run)
|
if (previousAnim != AnimationType.Walk && previousAnim != AnimationType.Run && previousAnim != AnimationType.Crouch)
|
||||||
{
|
{
|
||||||
TeleportTo(spawnPosition);
|
TeleportTo(spawnPosition);
|
||||||
}
|
}
|
||||||
@@ -3046,21 +3040,24 @@ namespace Barotrauma.CharacterEditor
|
|||||||
loadBox.Buttons[1].OnClicked += (btn, data) =>
|
loadBox.Buttons[1].OnClicked += (btn, data) =>
|
||||||
{
|
{
|
||||||
string fileName = Path.GetFileNameWithoutExtension(selectedFile);
|
string fileName = Path.GetFileNameWithoutExtension(selectedFile);
|
||||||
if (character.IsHumanoid)
|
if (character.IsHumanoid && character.AnimController is HumanoidAnimController humanAnimController)
|
||||||
{
|
{
|
||||||
switch (selectedType)
|
switch (selectedType)
|
||||||
{
|
{
|
||||||
case AnimationType.Walk:
|
case AnimationType.Walk:
|
||||||
character.AnimController.WalkParams = HumanWalkParams.GetAnimParams(character, fileName);
|
humanAnimController.WalkParams = HumanWalkParams.GetAnimParams(character, fileName);
|
||||||
break;
|
break;
|
||||||
case AnimationType.Run:
|
case AnimationType.Run:
|
||||||
character.AnimController.RunParams = HumanRunParams.GetAnimParams(character, fileName);
|
humanAnimController.RunParams = HumanRunParams.GetAnimParams(character, fileName);
|
||||||
|
break;
|
||||||
|
case AnimationType.Crouch:
|
||||||
|
humanAnimController.HumanCrouchParams = HumanCrouchParams.GetAnimParams(character, fileName);
|
||||||
break;
|
break;
|
||||||
case AnimationType.SwimSlow:
|
case AnimationType.SwimSlow:
|
||||||
character.AnimController.SwimSlowParams = HumanSwimSlowParams.GetAnimParams(character, fileName);
|
humanAnimController.SwimSlowParams = HumanSwimSlowParams.GetAnimParams(character, fileName);
|
||||||
break;
|
break;
|
||||||
case AnimationType.SwimFast:
|
case AnimationType.SwimFast:
|
||||||
character.AnimController.SwimFastParams = HumanSwimFastParams.GetAnimParams(character, fileName);
|
humanAnimController.SwimFastParams = HumanSwimFastParams.GetAnimParams(character, fileName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DebugConsole.ThrowError(GetCharacterEditorTranslation("AnimationTypeNotImplemented").Replace("[type]", selectedType.ToString()));
|
DebugConsole.ThrowError(GetCharacterEditorTranslation("AnimationTypeNotImplemented").Replace("[type]", selectedType.ToString()));
|
||||||
@@ -4152,7 +4149,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
float offset = 0.1f;
|
float offset = 0.1f;
|
||||||
w.refresh = () =>
|
w.refresh = () =>
|
||||||
{
|
{
|
||||||
var refPoint = SimToScreen(collider.SimPosition + GetSimSpaceForward() * offset);
|
var refPoint = SimToScreen(character.AnimController.Collider.SimPosition + GetSimSpaceForward() * offset);
|
||||||
var handMovement = ConvertUnits.ToDisplayUnits(humanGroundedParams.HandMoveAmount);
|
var handMovement = ConvertUnits.ToDisplayUnits(humanGroundedParams.HandMoveAmount);
|
||||||
w.DrawPos = refPoint + new Vector2(handMovement.X * character.AnimController.Dir, handMovement.Y) * Cam.Zoom;
|
w.DrawPos = refPoint + new Vector2(handMovement.X * character.AnimController.Dir, handMovement.Y) * Cam.Zoom;
|
||||||
};
|
};
|
||||||
@@ -4167,7 +4164,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
if (w.IsSelected)
|
if (w.IsSelected)
|
||||||
{
|
{
|
||||||
GUI.DrawLine(sp, w.DrawPos, SimToScreen(collider.SimPosition + GetSimSpaceForward() * offset), GUI.Style.Green);
|
GUI.DrawLine(sp, w.DrawPos, SimToScreen(character.AnimController.Collider.SimPosition + GetSimSpaceForward() * offset), GUI.Style.Green);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}).Draw(spriteBatch, deltaTime);
|
}).Draw(spriteBatch, deltaTime);
|
||||||
@@ -4731,7 +4728,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
rotation: 0,
|
rotation: 0,
|
||||||
origin: orig,
|
origin: orig,
|
||||||
sourceRectangle: wearable.InheritSourceRect ? limb.ActiveSprite.SourceRect : wearable.Sprite.SourceRect,
|
sourceRectangle: wearable.InheritSourceRect ? limb.ActiveSprite.SourceRect : wearable.Sprite.SourceRect,
|
||||||
scale: (wearable.InheritTextureScale ? 1 : wearable.Scale / RagdollParams.TextureScale) * spriteSheetZoom,
|
scale: (wearable.InheritScale ? 1 : wearable.Scale / RagdollParams.TextureScale) * spriteSheetZoom,
|
||||||
effects: SpriteEffects.None,
|
effects: SpriteEffects.None,
|
||||||
color: Color.White,
|
color: Color.White,
|
||||||
layerDepth: 0);
|
layerDepth: 0);
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
isTextureSelected = true;
|
isTextureSelected = true;
|
||||||
texturePathElement.Text = destinationPath;
|
texturePathElement.Text = destinationPath.CleanUpPath();
|
||||||
};
|
};
|
||||||
FileSelection.ClearFileTypeFilters();
|
FileSelection.ClearFileTypeFilters();
|
||||||
FileSelection.AddFileTypeFilter("PNG", "*.png");
|
FileSelection.AddFileTypeFilter("PNG", "*.png");
|
||||||
@@ -431,7 +431,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
box.Header.Font = GUI.LargeFont;
|
box.Header.Font = GUI.LargeFont;
|
||||||
box.Content.ChildAnchor = Anchor.TopCenter;
|
box.Content.ChildAnchor = Anchor.TopCenter;
|
||||||
box.Content.AbsoluteSpacing = (int)(20 * GUI.Scale);
|
box.Content.AbsoluteSpacing = (int)(20 * GUI.Scale);
|
||||||
int elementSize = (int)(30 * GUI.Scale);
|
int elementSize = (int)(40 * GUI.Scale);
|
||||||
var frame = new GUIFrame(new RectTransform(new Point(box.Content.Rect.Width - (int)(80 * GUI.xScale), box.Content.Rect.Height - (int)(200 * GUI.yScale)),
|
var frame = new GUIFrame(new RectTransform(new Point(box.Content.Rect.Width - (int)(80 * GUI.xScale), box.Content.Rect.Height - (int)(200 * GUI.yScale)),
|
||||||
box.Content.RectTransform, Anchor.Center), style: null, color: ParamsEditor.Color)
|
box.Content.RectTransform, Anchor.Center), style: null, color: ParamsEditor.Color)
|
||||||
{
|
{
|
||||||
@@ -625,8 +625,12 @@ namespace Barotrauma.CharacterEditor
|
|||||||
var jointsElement = new GUIFrame(new RectTransform(new Vector2(1, 0.05f), content.RectTransform), style: null) { CanBeFocused = false };
|
var jointsElement = new GUIFrame(new RectTransform(new Vector2(1, 0.05f), content.RectTransform), style: null) { CanBeFocused = false };
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), jointsElement.RectTransform), GetCharacterEditorTranslation("Joints"), font: GUI.SubHeadingFont);
|
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), jointsElement.RectTransform), GetCharacterEditorTranslation("Joints"), font: GUI.SubHeadingFont);
|
||||||
var jointButtonElement = new GUIFrame(new RectTransform(new Vector2(0.5f, 1f), jointsElement.RectTransform)
|
var jointButtonElement = new GUIFrame(new RectTransform(new Vector2(0.5f, 1f), jointsElement.RectTransform)
|
||||||
{ RelativeOffset = new Vector2(0.15f, 0) }, style: null)
|
{
|
||||||
{ CanBeFocused = false };
|
RelativeOffset = new Vector2(0.15f, 0)
|
||||||
|
}, style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
var jointsList = new GUIListBox(new RectTransform(new Vector2(1, 0.45f), content.RectTransform));
|
var jointsList = new GUIListBox(new RectTransform(new Vector2(1, 0.45f), content.RectTransform));
|
||||||
var removeJointButton = new GUIButton(new RectTransform(new Point(jointButtonElement.Rect.Height, jointButtonElement.Rect.Height), jointButtonElement.RectTransform), style: "GUIMinusButton")
|
var removeJointButton = new GUIButton(new RectTransform(new Point(jointButtonElement.Rect.Height, jointButtonElement.Rect.Height), jointButtonElement.RectTransform), style: "GUIMinusButton")
|
||||||
{
|
{
|
||||||
@@ -824,7 +828,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
var group = new GUILayoutGroup(new RectTransform(Vector2.One, limbElement.RectTransform)) { AbsoluteSpacing = 2 };
|
var group = new GUILayoutGroup(new RectTransform(Vector2.One, limbElement.RectTransform)) { AbsoluteSpacing = 16 };
|
||||||
var label = new GUITextBlock(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), name, font: GUI.SubHeadingFont);
|
var label = new GUITextBlock(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), name, font: GUI.SubHeadingFont);
|
||||||
var idField = new GUIFrame(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), style: null);
|
var idField = new GUIFrame(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), style: null);
|
||||||
var nameField = new GUIFrame(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), style: null);
|
var nameField = new GUIFrame(new RectTransform(new Point(group.Rect.Width, elementSize), group.RectTransform), style: null);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace Barotrauma
|
|||||||
public Effect PostProcessEffect { get; private set; }
|
public Effect PostProcessEffect { get; private set; }
|
||||||
public Effect GradientEffect { get; private set; }
|
public Effect GradientEffect { get; private set; }
|
||||||
public Effect GrainEffect { get; private set; }
|
public Effect GrainEffect { get; private set; }
|
||||||
|
public Effect ThresholdTintEffect { get; private set; }
|
||||||
public Effect BlueprintEffect { get; set; }
|
public Effect BlueprintEffect { get; set; }
|
||||||
|
|
||||||
public GameScreen(GraphicsDevice graphics, ContentManager content)
|
public GameScreen(GraphicsDevice graphics, ContentManager content)
|
||||||
@@ -38,21 +39,20 @@ namespace Barotrauma
|
|||||||
CreateRenderTargets(graphics);
|
CreateRenderTargets(graphics);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Effect LoadEffect(string path)
|
||||||
|
=> content.Load<Effect>(path
|
||||||
#if LINUX || OSX
|
#if LINUX || OSX
|
||||||
//var blurEffect = content.Load<Effect>("Effects/blurshader_opengl");
|
+"_opengl"
|
||||||
damageEffect = content.Load<Effect>("Effects/damageshader_opengl");
|
|
||||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess_opengl");
|
|
||||||
GradientEffect = content.Load<Effect>("Effects/gradientshader_opengl");
|
|
||||||
GrainEffect = content.Load<Effect>("Effects/grainshader_opengl");
|
|
||||||
BlueprintEffect = content.Load<Effect>("Effects/blueprintshader_opengl");
|
|
||||||
#else
|
|
||||||
//var blurEffect = content.Load<Effect>("Effects/blurshader");
|
|
||||||
damageEffect = content.Load<Effect>("Effects/damageshader");
|
|
||||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess");
|
|
||||||
GradientEffect = content.Load<Effect>("Effects/gradientshader");
|
|
||||||
GrainEffect = content.Load<Effect>("Effects/grainshader");
|
|
||||||
BlueprintEffect = content.Load<Effect>("Effects/blueprintshader");
|
|
||||||
#endif
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
//var blurEffect = LoadEffect("Effects/blurshader");
|
||||||
|
damageEffect = LoadEffect("Effects/damageshader");
|
||||||
|
PostProcessEffect = LoadEffect("Effects/postprocess");
|
||||||
|
GradientEffect = LoadEffect("Effects/gradientshader");
|
||||||
|
GrainEffect = LoadEffect("Effects/grainshader");
|
||||||
|
ThresholdTintEffect = LoadEffect("Effects/thresholdtint");
|
||||||
|
BlueprintEffect = LoadEffect("Effects/blueprintshader");
|
||||||
|
|
||||||
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
||||||
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
|
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly GUIFrame[] menuTabs;
|
private readonly GUIFrame[] menuTabs;
|
||||||
|
|
||||||
private CampaignSetupUI campaignSetupUI;
|
private SinglePlayerCampaignSetupUI campaignSetupUI;
|
||||||
|
|
||||||
private GUITextBox serverNameBox, /*portBox, queryPortBox,*/ passwordBox, maxPlayersBox;
|
private GUITextBox serverNameBox, /*portBox, queryPortBox,*/ passwordBox, maxPlayersBox;
|
||||||
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox;
|
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox;
|
||||||
@@ -594,6 +594,8 @@ namespace Barotrauma
|
|||||||
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.NewGame); });
|
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.NewGame); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
campaignSetupUI.RandomizeCrew();
|
||||||
|
campaignSetupUI.SetPage(0);
|
||||||
campaignSetupUI.CreateDefaultSaveName();
|
campaignSetupUI.CreateDefaultSaveName();
|
||||||
campaignSetupUI.RandomizeSeed();
|
campaignSetupUI.RandomizeSeed();
|
||||||
campaignSetupUI.UpdateSubList(SubmarineInfo.SavedSubmarines);
|
campaignSetupUI.UpdateSubList(SubmarineInfo.SavedSubmarines);
|
||||||
@@ -985,24 +987,32 @@ namespace Barotrauma
|
|||||||
if (selectedTab < Tab.Empty && menuTabs[(int)selectedTab] != null)
|
if (selectedTab < Tab.Empty && menuTabs[(int)selectedTab] != null)
|
||||||
{
|
{
|
||||||
menuTabs[(int)selectedTab].AddToGUIUpdateList();
|
menuTabs[(int)selectedTab].AddToGUIUpdateList();
|
||||||
|
switch (selectedTab)
|
||||||
|
{
|
||||||
|
case Tab.NewGame:
|
||||||
|
campaignSetupUI.CharacterMenus?.ForEach(m => m.AddToGUIUpdateList());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
#if !DEBUG && USE_STEAM
|
||||||
#if USE_STEAM
|
|
||||||
if (GameMain.Config.UseSteamMatchmaking)
|
if (GameMain.Config.UseSteamMatchmaking)
|
||||||
{
|
{
|
||||||
hostServerButton.Enabled = Steam.SteamManager.IsInitialized;
|
hostServerButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||||
}
|
}
|
||||||
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
|
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||||
#endif
|
#elif USE_STEAM
|
||||||
#else
|
|
||||||
#if USE_STEAM
|
|
||||||
steamWorkshopButton.Enabled = true;
|
steamWorkshopButton.Enabled = true;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
switch (selectedTab)
|
||||||
|
{
|
||||||
|
case Tab.NewGame:
|
||||||
|
campaignSetupUI.Update();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawBackground(GraphicsDevice graphics, SpriteBatch spriteBatch)
|
public void DrawBackground(GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||||
@@ -1119,6 +1129,11 @@ namespace Barotrauma
|
|||||||
selectedSub = new SubmarineInfo(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"));
|
selectedSub = new SubmarineInfo(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"));
|
||||||
|
|
||||||
GameMain.GameSession = new GameSession(selectedSub, saveName, GameModePreset.SinglePlayerCampaign, settings, mapSeed);
|
GameMain.GameSession = new GameSession(selectedSub, saveName, GameModePreset.SinglePlayerCampaign, settings, mapSeed);
|
||||||
|
GameMain.GameSession.CrewManager.CharacterInfos.Clear();
|
||||||
|
foreach (var characterInfo in campaignSetupUI.CharacterMenus.Select(m => m.CharacterInfo))
|
||||||
|
{
|
||||||
|
GameMain.GameSession.CrewManager.AddCharacterInfo(characterInfo);
|
||||||
|
}
|
||||||
((SinglePlayerCampaign)GameMain.GameSession.GameMode).LoadNewLevel();
|
((SinglePlayerCampaign)GameMain.GameSession.GameMode).LoadNewLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,7 +1161,7 @@ namespace Barotrauma
|
|||||||
menuTabs[(int)Tab.NewGame].ClearChildren();
|
menuTabs[(int)Tab.NewGame].ClearChildren();
|
||||||
menuTabs[(int)Tab.LoadGame].ClearChildren();
|
menuTabs[(int)Tab.LoadGame].ClearChildren();
|
||||||
|
|
||||||
var innerNewGame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.025f) })
|
var innerNewGame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f
|
||||||
@@ -1154,30 +1169,14 @@ namespace Barotrauma
|
|||||||
var newGameContent = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.95f), innerNewGame.RectTransform, Anchor.Center),
|
var newGameContent = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.95f), innerNewGame.RectTransform, Anchor.Center),
|
||||||
style: "InnerFrame");
|
style: "InnerFrame");
|
||||||
|
|
||||||
var paddedNewGame = new GUIFrame(new RectTransform(new Vector2(0.95f), newGameContent.RectTransform, Anchor.Center), style: null);
|
|
||||||
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center) { AbsoluteOffset = new Point(0, 10) },
|
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center) { AbsoluteOffset = new Point(0, 10) },
|
||||||
style: null);
|
style: null);
|
||||||
|
|
||||||
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, SubmarineInfo.SavedSubmarines)
|
campaignSetupUI = new SinglePlayerCampaignSetupUI(newGameContent, paddedLoadGame, SubmarineInfo.SavedSubmarines)
|
||||||
{
|
{
|
||||||
LoadGame = LoadGame,
|
LoadGame = LoadGame,
|
||||||
StartNewGame = StartGame
|
StartNewGame = StartGame
|
||||||
};
|
};
|
||||||
|
|
||||||
var startButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), innerNewGame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.BottomRight)
|
|
||||||
{
|
|
||||||
RelativeSpacing = 0.05f
|
|
||||||
};
|
|
||||||
campaignSetupUI.StartButton.RectTransform.Parent = startButtonContainer.RectTransform;
|
|
||||||
campaignSetupUI.StartButton.RectTransform.MinSize = new Point(
|
|
||||||
(int)(campaignSetupUI.StartButton.TextBlock.TextSize.X * 1.5f),
|
|
||||||
campaignSetupUI.StartButton.RectTransform.MinSize.Y);
|
|
||||||
startButtonContainer.RectTransform.MinSize = new Point(0, campaignSetupUI.StartButton.RectTransform.MinSize.Y);
|
|
||||||
if (campaignSetupUI.CampaignCustomizeButton != null)
|
|
||||||
{
|
|
||||||
campaignSetupUI.CampaignCustomizeButton.RectTransform.Parent = startButtonContainer.RectTransform;
|
|
||||||
}
|
|
||||||
campaignSetupUI.InitialMoneyText.RectTransform.Parent = startButtonContainer.RectTransform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateHostServerFields()
|
private void CreateHostServerFields()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,21 +41,13 @@ namespace Barotrauma
|
|||||||
public Sprite(Texture2D texture, Rectangle? sourceRectangle, Vector2? newOffset, float newRotation = 0.0f, string path = null)
|
public Sprite(Texture2D texture, Rectangle? sourceRectangle, Vector2? newOffset, float newRotation = 0.0f, string path = null)
|
||||||
{
|
{
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
|
|
||||||
sourceRect = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height);
|
sourceRect = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height);
|
||||||
|
|
||||||
offset = newOffset ?? Vector2.Zero;
|
offset = newOffset ?? Vector2.Zero;
|
||||||
|
|
||||||
size = new Vector2(sourceRect.Width, sourceRect.Height);
|
size = new Vector2(sourceRect.Width, sourceRect.Height);
|
||||||
|
|
||||||
origin = Vector2.Zero;
|
origin = Vector2.Zero;
|
||||||
|
|
||||||
effects = SpriteEffects.None;
|
effects = SpriteEffects.None;
|
||||||
|
|
||||||
rotation = newRotation;
|
rotation = newRotation;
|
||||||
|
|
||||||
FilePath = path;
|
FilePath = path;
|
||||||
|
|
||||||
AddToList(this);
|
AddToList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +77,7 @@ namespace Barotrauma
|
|||||||
EnsureLazyLoaded(isAsync: true);
|
EnsureLazyLoaded(isAsync: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureLazyLoaded(bool isAsync=false)
|
public void EnsureLazyLoaded(bool isAsync = false)
|
||||||
{
|
{
|
||||||
if (!LazyLoad || texture != null || cannotBeLoaded || loadingAsync) { return; }
|
if (!LazyLoad || texture != null || cannotBeLoaded || loadingAsync) { return; }
|
||||||
loadingAsync = isAsync;
|
loadingAsync = isAsync;
|
||||||
@@ -382,7 +374,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (Sprite s in LoadedSprites)
|
foreach (Sprite s in LoadedSprites)
|
||||||
{
|
{
|
||||||
if (s.FullPath == FullPath) return;
|
if (s.FullPath == FullPath) { return; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -67,6 +67,12 @@
|
|||||||
/processorParam:DebugMode=Auto
|
/processorParam:DebugMode=Auto
|
||||||
/build:grainshader.fx
|
/build:grainshader.fx
|
||||||
|
|
||||||
|
#begin thresholdtint.fx
|
||||||
|
/importer:EffectImporter
|
||||||
|
/processor:EffectProcessor
|
||||||
|
/processorParam:DebugMode=Auto
|
||||||
|
/build:thresholdtint.fx
|
||||||
|
|
||||||
#begin blueprintshader.fx
|
#begin blueprintshader.fx
|
||||||
/importer:EffectImporter
|
/importer:EffectImporter
|
||||||
/processor:EffectProcessor
|
/processor:EffectProcessor
|
||||||
|
|||||||
@@ -72,3 +72,9 @@
|
|||||||
/processor:EffectProcessor
|
/processor:EffectProcessor
|
||||||
/processorParam:DebugMode=Auto
|
/processorParam:DebugMode=Auto
|
||||||
/build:blueprintshader_opengl.fx
|
/build:blueprintshader_opengl.fx
|
||||||
|
|
||||||
|
#begin thresholdtint_opengl.fx
|
||||||
|
/importer:EffectImporter
|
||||||
|
/processor:EffectProcessor
|
||||||
|
/processorParam:DebugMode=Auto
|
||||||
|
/build:thresholdtint_opengl.fx
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Texture2D xBaseTexture;
|
||||||
|
sampler BaseTextureSampler = sampler_state { Texture = <xBaseTexture>; };
|
||||||
|
Texture2D xTintMaskTexture;
|
||||||
|
sampler TintMaskTextureSampler = sampler_state { Texture = <xTintMaskTexture>; };
|
||||||
|
Texture2D xCutoffTexture;
|
||||||
|
sampler CutoffTextureSampler = sampler_state { Texture = <xCutoffTexture>; };
|
||||||
|
|
||||||
|
float highlightThreshold;
|
||||||
|
float highlightMultiplier;
|
||||||
|
|
||||||
|
float baseToCutoffSizeRatio;
|
||||||
|
|
||||||
|
float4 mainPS(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
|
{
|
||||||
|
float4 baseSample = xBaseTexture.Sample(BaseTextureSampler, texCoord);
|
||||||
|
float3 tintMaskSample = xTintMaskTexture.Sample(TintMaskTextureSampler, texCoord).rgb;
|
||||||
|
float cutoffSample = xCutoffTexture.Sample(CutoffTextureSampler, texCoord * baseToCutoffSizeRatio).r;
|
||||||
|
|
||||||
|
float3 highlight = saturate((baseSample.rgb - (highlightThreshold * float3(1,1,1))) * highlightMultiplier);
|
||||||
|
float3 tinted = saturate(baseSample.rgb * clr.rgb + highlight);
|
||||||
|
return float4(
|
||||||
|
(tinted * tintMaskSample) + (baseSample.rgb * (float3(1,1,1) - tintMaskSample)),
|
||||||
|
baseSample.a * cutoffSample * clr.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
technique ThresholdTintShader
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
PixelShader = compile ps_4_0_level_9_1 mainPS();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Texture2D xBaseTexture;
|
||||||
|
sampler BaseTextureSampler = sampler_state { Texture = <xBaseTexture>; };
|
||||||
|
Texture2D xTintMaskTexture;
|
||||||
|
sampler TintMaskTextureSampler = sampler_state { Texture = <xTintMaskTexture>; };
|
||||||
|
Texture2D xCutoffTexture;
|
||||||
|
sampler CutoffTextureSampler = sampler_state { Texture = <xCutoffTexture>; };
|
||||||
|
|
||||||
|
float highlightThreshold;
|
||||||
|
float highlightMultiplier;
|
||||||
|
|
||||||
|
float baseToCutoffSizeRatio;
|
||||||
|
|
||||||
|
float4 mainPS(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
|
{
|
||||||
|
float4 baseSample = tex2D(BaseTextureSampler, texCoord);
|
||||||
|
float3 tintMaskSample = tex2D(TintMaskTextureSampler, texCoord).rgb;
|
||||||
|
float cutoffSample = tex2D(CutoffTextureSampler, texCoord * baseToCutoffSizeRatio).r;
|
||||||
|
|
||||||
|
float3 highlight = saturate((baseSample.rgb - (highlightThreshold * float3(1,1,1))) * highlightMultiplier);
|
||||||
|
float3 tinted = saturate(baseSample.rgb * clr.rgb + highlight);
|
||||||
|
return float4(
|
||||||
|
(tinted * tintMaskSample) + (baseSample.rgb * (float3(1,1,1) - tintMaskSample)),
|
||||||
|
baseSample.a * cutoffSample * clr.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
technique ThresholdTintShader
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
PixelShader = compile ps_2_0 mainPS();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -39,10 +39,13 @@ namespace Barotrauma
|
|||||||
msg.Write((byte)Gender);
|
msg.Write((byte)Gender);
|
||||||
msg.Write((byte)Race);
|
msg.Write((byte)Race);
|
||||||
msg.Write((byte)HeadSpriteId);
|
msg.Write((byte)HeadSpriteId);
|
||||||
msg.Write((byte)Head.HairIndex);
|
msg.Write((byte)HairIndex);
|
||||||
msg.Write((byte)Head.BeardIndex);
|
msg.Write((byte)BeardIndex);
|
||||||
msg.Write((byte)Head.MoustacheIndex);
|
msg.Write((byte)MoustacheIndex);
|
||||||
msg.Write((byte)Head.FaceAttachmentIndex);
|
msg.Write((byte)FaceAttachmentIndex);
|
||||||
|
msg.WriteColorR8G8B8(SkinColor);
|
||||||
|
msg.WriteColorR8G8B8(HairColor);
|
||||||
|
msg.WriteColorR8G8B8(FacialHairColor);
|
||||||
msg.Write(ragdollFileName);
|
msg.Write(ragdollFileName);
|
||||||
|
|
||||||
if (Job != null)
|
if (Job != null)
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ namespace Barotrauma
|
|||||||
msg.Write((byte)(Level.Loaded == null || !Level.Loaded.Caves.Contains(cave) ? 255 : Level.Loaded.Caves.IndexOf(cave)));
|
msg.Write((byte)(Level.Loaded == null || !Level.Loaded.Caves.Contains(cave) ? 255 : Level.Loaded.Caves.IndexOf(cave)));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kvp in SpawnedResources)
|
foreach (var kvp in spawnedResources)
|
||||||
{
|
{
|
||||||
msg.Write((byte)kvp.Value.Count);
|
msg.Write((byte)kvp.Value.Count);
|
||||||
var rotation = ResourceClusters[kvp.Key].Second;
|
var rotation = resourceClusters[kvp.Key].rotation;
|
||||||
msg.Write(rotation);
|
msg.Write(rotation);
|
||||||
foreach (var r in kvp.Value)
|
foreach (var r in kvp.Value)
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kvp in RelevantLevelResources)
|
foreach (var kvp in relevantLevelResources)
|
||||||
{
|
{
|
||||||
msg.Write(kvp.Key);
|
msg.Write(kvp.Key);
|
||||||
msg.Write((byte)kvp.Value.Length);
|
msg.Write((byte)kvp.Value.Length);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace Barotrauma.Items.Components
|
|||||||
msg.Write(deteriorateAlwaysResetTimer);
|
msg.Write(deteriorateAlwaysResetTimer);
|
||||||
msg.Write(DeteriorateAlways);
|
msg.Write(DeteriorateAlways);
|
||||||
msg.Write(tinkeringDuration);
|
msg.Write(tinkeringDuration);
|
||||||
|
msg.Write(tinkeringStrength);
|
||||||
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
|
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
|
||||||
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
|
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3464,15 +3464,15 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
//gender = Gender.Male;
|
|
||||||
//race = Race.White;
|
|
||||||
//headSpriteId = 0;
|
|
||||||
DebugConsole.Log("Received invalid characterinfo from \"" + sender.Name + "\"! { " + e.Message + " }");
|
DebugConsole.Log("Received invalid characterinfo from \"" + sender.Name + "\"! { " + e.Message + " }");
|
||||||
}
|
}
|
||||||
int hairIndex = message.ReadByte();
|
int hairIndex = message.ReadByte();
|
||||||
int beardIndex = message.ReadByte();
|
int beardIndex = message.ReadByte();
|
||||||
int moustacheIndex = message.ReadByte();
|
int moustacheIndex = message.ReadByte();
|
||||||
int faceAttachmentIndex = message.ReadByte();
|
int faceAttachmentIndex = message.ReadByte();
|
||||||
|
Color skinColor = message.ReadColorR8G8B8();
|
||||||
|
Color hairColor = message.ReadColorR8G8B8();
|
||||||
|
Color facialHairColor = message.ReadColorR8G8B8();
|
||||||
|
|
||||||
List<Pair<JobPrefab, int>> jobPreferences = new List<Pair<JobPrefab, int>>();
|
List<Pair<JobPrefab, int>> jobPreferences = new List<Pair<JobPrefab, int>>();
|
||||||
int count = message.ReadByte();
|
int count = message.ReadByte();
|
||||||
@@ -3489,6 +3489,9 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
|
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
|
||||||
sender.CharacterInfo.RecreateHead(headSpriteId, race, gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
sender.CharacterInfo.RecreateHead(headSpriteId, race, gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||||
|
sender.CharacterInfo.SkinColor = skinColor;
|
||||||
|
sender.CharacterInfo.HairColor = hairColor;
|
||||||
|
sender.CharacterInfo.FacialHairColor = facialHairColor;
|
||||||
|
|
||||||
if (jobPreferences.Count > 0)
|
if (jobPreferences.Count > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.3.0</Version>
|
<Version>0.1500.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -118,6 +118,7 @@
|
|||||||
<Character file="Content/Characters/Variants/Mudraptor_hatchling/Mudraptor_hatchling.xml" />
|
<Character file="Content/Characters/Variants/Mudraptor_hatchling/Mudraptor_hatchling.xml" />
|
||||||
<Character file="Content/Characters/Variants/Mudraptor_passive/Mudraptor_passive.xml" />
|
<Character file="Content/Characters/Variants/Mudraptor_passive/Mudraptor_passive.xml" />
|
||||||
<Character file="Content/Characters/Variants/Tigerthresher_hatchling/Tigerthresher_hatchling.xml" />
|
<Character file="Content/Characters/Variants/Tigerthresher_hatchling/Tigerthresher_hatchling.xml" />
|
||||||
|
<Character file="Content/Characters/TintTest/TintTest.xml" />
|
||||||
<MapCreature file="Content/Items/Gardening/ballastflora.xml" />
|
<MapCreature file="Content/Items/Gardening/ballastflora.xml" />
|
||||||
<Wreck file="Content/Map/Wrecks/Dugong_Wrecked.sub" />
|
<Wreck file="Content/Map/Wrecks/Dugong_Wrecked.sub" />
|
||||||
<Wreck file="Content/Map/Wrecks/Kastrull_Wrecked.sub" />
|
<Wreck file="Content/Map/Wrecks/Kastrull_Wrecked.sub" />
|
||||||
|
|||||||
+1
-1
@@ -464,7 +464,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "return":
|
case "return":
|
||||||
newObjective = new AIObjectiveReturn(character, this, priorityModifier: priorityModifier);
|
newObjective = new AIObjectiveReturn(character, orderGiver, this, priorityModifier: priorityModifier);
|
||||||
newObjective.Abandoned += () => DismissSelf(order, option);
|
newObjective.Abandoned += () => DismissSelf(order, option);
|
||||||
newObjective.Completed += () => DismissSelf(order, option);
|
newObjective.Completed += () => DismissSelf(order, option);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-1
@@ -408,7 +408,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
bool isCompleted =
|
bool isCompleted =
|
||||||
AIObjectiveRescueAll.GetVitalityFactor(targetCharacter) >= AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager, character, targetCharacter) ||
|
AIObjectiveRescueAll.GetVitalityFactor(targetCharacter) >= AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager, character, targetCharacter) ||
|
||||||
targetCharacter.CharacterHealth.GetAllAfflictions().All(a => a.Strength < a.Prefab.TreatmentThreshold);
|
targetCharacter.CharacterHealth.GetAllAfflictions().All(a => a.Strength <= a.Prefab.TreatmentThreshold);
|
||||||
|
|
||||||
if (isCompleted && targetCharacter != character && character.IsOnPlayerTeam)
|
if (isCompleted && targetCharacter != character && character.IsOnPlayerTeam)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ namespace Barotrauma
|
|||||||
if (character.AIController is HumanAIController humanAI)
|
if (character.AIController is HumanAIController humanAI)
|
||||||
{
|
{
|
||||||
if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target) ||
|
if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target) ||
|
||||||
target.CharacterHealth.GetAllAfflictions().All(a => a.Strength < a.Prefab.TreatmentThreshold))
|
target.CharacterHealth.GetAllAfflictions().All(a => a.Strength <= a.Prefab.TreatmentThreshold))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -12,7 +12,7 @@ namespace Barotrauma
|
|||||||
private bool usingEscapeBehavior;
|
private bool usingEscapeBehavior;
|
||||||
public Submarine ReturnTarget { get; }
|
public Submarine ReturnTarget { get; }
|
||||||
|
|
||||||
public AIObjectiveReturn(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1.0f) : base(character, objectiveManager, priorityModifier)
|
public AIObjectiveReturn(Character character, Character orderGiver, AIObjectiveManager objectiveManager, float priorityModifier = 1.0f) : base(character, objectiveManager, priorityModifier)
|
||||||
{
|
{
|
||||||
ReturnTarget = GetReturnTarget(Submarine.MainSubs) ?? GetReturnTarget(Submarine.Loaded);
|
ReturnTarget = GetReturnTarget(Submarine.MainSubs) ?? GetReturnTarget(Submarine.Loaded);
|
||||||
if (ReturnTarget == null)
|
if (ReturnTarget == null)
|
||||||
@@ -23,10 +23,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Submarine GetReturnTarget(IEnumerable<Submarine> subs)
|
Submarine GetReturnTarget(IEnumerable<Submarine> subs)
|
||||||
{
|
{
|
||||||
|
var requiredTeamID = orderGiver?.TeamID ?? character?.TeamID;
|
||||||
Submarine returnTarget = null;
|
Submarine returnTarget = null;
|
||||||
foreach (var sub in subs)
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
if (sub?.TeamID != character.TeamID) { continue; }
|
if (sub == null) { continue; }
|
||||||
|
if (sub.TeamID != requiredTeamID) { continue; }
|
||||||
returnTarget = sub;
|
returnTarget = sub;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -229,7 +231,7 @@ namespace Barotrauma
|
|||||||
protected override void OnAbandon()
|
protected override void OnAbandon()
|
||||||
{
|
{
|
||||||
base.OnAbandon();
|
base.OnAbandon();
|
||||||
SteeringManager.Reset();
|
SteeringManager?.Reset();
|
||||||
if (character.IsOnPlayerTeam && objectiveManager.CurrentOrder == objectiveManager.CurrentObjective)
|
if (character.IsOnPlayerTeam && objectiveManager.CurrentOrder == objectiveManager.CurrentObjective)
|
||||||
{
|
{
|
||||||
string msg = TextManager.Get("dialogcannotreturn", returnNull: true);
|
string msg = TextManager.Get("dialogcannotreturn", returnNull: true);
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ namespace Barotrauma
|
|||||||
public readonly Vector2 Position;
|
public readonly Vector2 Position;
|
||||||
public readonly int WayPointID;
|
public readonly int WayPointID;
|
||||||
|
|
||||||
public bool blocked;
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"PathNode {WayPointID}";
|
return $"PathNode {WayPointID}";
|
||||||
@@ -81,6 +79,31 @@ namespace Barotrauma
|
|||||||
|
|
||||||
return nodeList;
|
return nodeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool? blocked;
|
||||||
|
public bool IsBlocked()
|
||||||
|
{
|
||||||
|
if (blocked.HasValue) { return blocked.Value; }
|
||||||
|
|
||||||
|
blocked = false;
|
||||||
|
|
||||||
|
if (Waypoint.Submarine != null) { return blocked.Value; }
|
||||||
|
if (Waypoint.Tunnel?.Type != Level.TunnelType.Cave) { return blocked.Value; }
|
||||||
|
foreach (var w in Level.Loaded.ExtraWalls)
|
||||||
|
{
|
||||||
|
if (!(w is DestructibleLevelWall d)) { return blocked.Value; }
|
||||||
|
if (d.Destroyed) { return blocked.Value; }
|
||||||
|
if (!d.IsPointInside(Waypoint.Position)) { return blocked.Value; }
|
||||||
|
blocked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return blocked.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetBlocked()
|
||||||
|
{
|
||||||
|
blocked = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PathFinder
|
class PathFinder
|
||||||
@@ -146,7 +169,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
|
public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
|
||||||
{
|
{
|
||||||
UpdateBlockedNodes();
|
foreach (PathNode node in nodes)
|
||||||
|
{
|
||||||
|
node.ResetBlocked();
|
||||||
|
}
|
||||||
|
|
||||||
//sort nodes roughly according to distance
|
//sort nodes roughly according to distance
|
||||||
sortedNodes.Clear();
|
sortedNodes.Clear();
|
||||||
@@ -202,11 +228,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (startNode == null || node.TempDistance < startNode.TempDistance)
|
if (startNode == null || node.TempDistance < startNode.TempDistance)
|
||||||
{
|
{
|
||||||
if (node.blocked) { continue; }
|
|
||||||
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
||||||
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
|
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
|
||||||
// Always check the visibility for the start node
|
// Always check the visibility for the start node
|
||||||
if (!IsWaypointVisible(node, start)) { continue; }
|
if (!IsWaypointVisible(node, start)) { continue; }
|
||||||
|
if (node.IsBlocked()) { continue; }
|
||||||
startNode = node;
|
startNode = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,11 +277,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (endNode == null || node.TempDistance < endNode.TempDistance)
|
if (endNode == null || node.TempDistance < endNode.TempDistance)
|
||||||
{
|
{
|
||||||
if (node.blocked) { continue; }
|
|
||||||
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
||||||
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
|
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
|
||||||
// Only check the visibility for the end node when allowed (fix leaks)
|
// Only check the visibility for the end node when allowed (fix leaks)
|
||||||
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; }
|
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; }
|
||||||
|
if (node.IsBlocked()) { continue; }
|
||||||
endNode = node;
|
endNode = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,15 +352,13 @@ namespace Barotrauma
|
|||||||
float dist = float.MaxValue;
|
float dist = float.MaxValue;
|
||||||
foreach (PathNode node in nodes)
|
foreach (PathNode node in nodes)
|
||||||
{
|
{
|
||||||
if (node.state != 1) { continue; }
|
if (node.state != 1 || node.F > dist) { continue; }
|
||||||
if (isCharacter && node.Waypoint.isObstructed) { continue; }
|
if (isCharacter && node.Waypoint.isObstructed) { continue; }
|
||||||
if (node.blocked) { continue; }
|
|
||||||
if (filter != null && !filter(node)) { continue; }
|
if (filter != null && !filter(node)) { continue; }
|
||||||
if (node.F < dist)
|
if (node.IsBlocked()) { continue; }
|
||||||
{
|
|
||||||
dist = node.F;
|
dist = node.F;
|
||||||
currNode = node;
|
currNode = node;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currNode == null || currNode == end) { break; }
|
if (currNode == null || currNode == end) { break; }
|
||||||
@@ -436,25 +460,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateBlockedNodes()
|
|
||||||
{
|
|
||||||
if (!isCharacter) { return; }
|
|
||||||
foreach (var n in nodes)
|
|
||||||
{
|
|
||||||
n.blocked = false;
|
|
||||||
if (n.Waypoint.Submarine != null) { continue; }
|
|
||||||
if (n.Waypoint.Tunnel?.Type != Level.TunnelType.Cave) { continue; }
|
|
||||||
foreach (var w in Level.Loaded.ExtraWalls)
|
|
||||||
{
|
|
||||||
if (!(w is DestructibleLevelWall d)) { continue; }
|
|
||||||
if (d.Destroyed) { continue; }
|
|
||||||
if (!d.IsPointInside(n.Waypoint.Position)) { continue; }
|
|
||||||
n.blocked = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (this is HumanoidAnimController humanAnimController && humanAnimController.Crouching)
|
||||||
|
{
|
||||||
|
return humanAnimController.HumanCrouchParams;
|
||||||
|
}
|
||||||
return IsMovingFast ? RunParams : WalkParams;
|
return IsMovingFast ? RunParams : WalkParams;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +100,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (CanWalk)
|
if (CanWalk)
|
||||||
{
|
{
|
||||||
return new List<AnimationParams> { WalkParams, RunParams, SwimSlowParams, SwimFastParams };
|
var anims = new List<AnimationParams> { WalkParams, RunParams, SwimSlowParams, SwimFastParams };
|
||||||
|
if (this is HumanoidAnimController humanAnimController)
|
||||||
|
{
|
||||||
|
anims.Add(humanAnimController.HumanCrouchParams);
|
||||||
|
}
|
||||||
|
return anims;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -154,7 +163,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public virtual void UpdateUseItem(bool allowMovement, Vector2 handWorldPos) { }
|
public virtual void UpdateUseItem(bool allowMovement, Vector2 handWorldPos) { }
|
||||||
|
|
||||||
public float GetSpeed(AnimationType type)
|
public virtual float GetSpeed(AnimationType type)
|
||||||
{
|
{
|
||||||
GroundedMovementParams movementParams;
|
GroundedMovementParams movementParams;
|
||||||
switch (type)
|
switch (type)
|
||||||
@@ -207,7 +216,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
animType = AnimationType.Walk;
|
if (this is HumanoidAnimController humanAnimController && humanAnimController.Crouching)
|
||||||
|
{
|
||||||
|
animType = AnimationType.Crouch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
animType = AnimationType.Walk;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return GetSpeed(animType);
|
return GetSpeed(animType);
|
||||||
@@ -221,6 +237,12 @@ namespace Barotrauma
|
|||||||
return WalkParams;
|
return WalkParams;
|
||||||
case AnimationType.Run:
|
case AnimationType.Run:
|
||||||
return RunParams;
|
return RunParams;
|
||||||
|
case AnimationType.Crouch:
|
||||||
|
if (this is HumanoidAnimController humanAnimController)
|
||||||
|
{
|
||||||
|
return humanAnimController.HumanCrouchParams;
|
||||||
|
}
|
||||||
|
throw new NotImplementedException(type.ToString());
|
||||||
case AnimationType.SwimSlow:
|
case AnimationType.SwimSlow:
|
||||||
return SwimSlowParams;
|
return SwimSlowParams;
|
||||||
case AnimationType.SwimFast:
|
case AnimationType.SwimFast:
|
||||||
|
|||||||
@@ -97,9 +97,9 @@ namespace Barotrauma
|
|||||||
public new FishSwimParams CurrentSwimParams => base.CurrentSwimParams as FishSwimParams;
|
public new FishSwimParams CurrentSwimParams => base.CurrentSwimParams as FishSwimParams;
|
||||||
|
|
||||||
public float? TailAngle => GetValidOrNull(CurrentAnimationParams, CurrentFishAnimation?.TailAngleInRadians);
|
public float? TailAngle => GetValidOrNull(CurrentAnimationParams, CurrentFishAnimation?.TailAngleInRadians);
|
||||||
public float FootTorque => CurrentFishAnimation.FootTorque;
|
public float FootTorque => CurrentAnimationParams.FootTorque;
|
||||||
public float HeadTorque => CurrentFishAnimation.HeadTorque;
|
public float HeadTorque => CurrentAnimationParams.HeadTorque;
|
||||||
public float TorsoTorque => CurrentFishAnimation.TorsoTorque;
|
public float TorsoTorque => CurrentAnimationParams.TorsoTorque;
|
||||||
public float TailTorque => CurrentFishAnimation.TailTorque;
|
public float TailTorque => CurrentFishAnimation.TailTorque;
|
||||||
public float HeadMoveForce => CurrentGroundedParams.HeadMoveForce;
|
public float HeadMoveForce => CurrentGroundedParams.HeadMoveForce;
|
||||||
public float TorsoMoveForce => CurrentGroundedParams.TorsoMoveForce;
|
public float TorsoMoveForce => CurrentGroundedParams.TorsoMoveForce;
|
||||||
|
|||||||
+95
-87
@@ -2,7 +2,6 @@
|
|||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
@@ -73,6 +72,20 @@ namespace Barotrauma
|
|||||||
set { _humanRunParams = value; }
|
set { _humanRunParams = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HumanCrouchParams _humanCrouchParams;
|
||||||
|
public HumanCrouchParams HumanCrouchParams
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_humanCrouchParams == null)
|
||||||
|
{
|
||||||
|
_humanCrouchParams = HumanCrouchParams.GetDefaultAnimParams(character);
|
||||||
|
}
|
||||||
|
return _humanCrouchParams;
|
||||||
|
}
|
||||||
|
set { _humanCrouchParams = value; }
|
||||||
|
}
|
||||||
|
|
||||||
private HumanSwimSlowParams _humanSwimSlowParams;
|
private HumanSwimSlowParams _humanSwimSlowParams;
|
||||||
public HumanSwimSlowParams HumanSwimSlowParams
|
public HumanSwimSlowParams HumanSwimSlowParams
|
||||||
{
|
{
|
||||||
@@ -102,8 +115,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
public new HumanGroundedParams CurrentGroundedParams => base.CurrentGroundedParams as HumanGroundedParams;
|
public new HumanGroundedParams CurrentGroundedParams => base.CurrentGroundedParams as HumanGroundedParams;
|
||||||
|
|
||||||
public new HumanSwimParams CurrentSwimParams => base.CurrentSwimParams as HumanSwimParams;
|
public new HumanSwimParams CurrentSwimParams => base.CurrentSwimParams as HumanSwimParams;
|
||||||
|
|
||||||
|
public IHumanAnimation CurrentHumanAnimParams => CurrentAnimationParams as IHumanAnimation;
|
||||||
|
|
||||||
public override GroundedMovementParams WalkParams
|
public override GroundedMovementParams WalkParams
|
||||||
{
|
{
|
||||||
get { return HumanWalkParams; }
|
get { return HumanWalkParams; }
|
||||||
@@ -169,42 +185,9 @@ namespace Barotrauma
|
|||||||
private float swimmingStateLockTimer;
|
private float swimmingStateLockTimer;
|
||||||
|
|
||||||
private float useItemTimer;
|
private float useItemTimer;
|
||||||
|
|
||||||
public override float? TorsoPosition
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Crouching && !swimming ? CurrentGroundedParams.CrouchingTorsoPos * RagdollParams.JointScale : base.TorsoPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float? HeadPosition
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Crouching && !swimming ? CurrentGroundedParams.CrouchingHeadPos * RagdollParams.JointScale : base.HeadPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float? TorsoAngle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Crouching && !swimming ? MathHelper.ToRadians(CurrentGroundedParams.CrouchingTorsoAngle) : base.TorsoAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float? HeadAngle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Crouching && !swimming ? MathHelper.ToRadians(CurrentGroundedParams.CrouchingHeadAngle) : base.HeadAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float HeadLeanAmount => CurrentGroundedParams.HeadLeanAmount;
|
public float HeadLeanAmount => CurrentGroundedParams.HeadLeanAmount;
|
||||||
public float TorsoLeanAmount => CurrentGroundedParams.TorsoLeanAmount;
|
public float TorsoLeanAmount => CurrentGroundedParams.TorsoLeanAmount;
|
||||||
public Vector2 FootMoveOffset => (Crouching ? CurrentGroundedParams.CrouchingFootMoveOffset : CurrentGroundedParams.FootMoveOffset) * RagdollParams.JointScale;
|
public Vector2 FootMoveOffset => CurrentGroundedParams.FootMoveOffset * RagdollParams.JointScale;
|
||||||
public float LegBendTorque => CurrentGroundedParams.LegBendTorque * RagdollParams.JointScale;
|
public float LegBendTorque => CurrentGroundedParams.LegBendTorque * RagdollParams.JointScale;
|
||||||
public Vector2 HandMoveOffset => CurrentGroundedParams.HandMoveOffset * RagdollParams.JointScale;
|
public Vector2 HandMoveOffset => CurrentGroundedParams.HandMoveOffset * RagdollParams.JointScale;
|
||||||
|
|
||||||
@@ -298,7 +281,7 @@ namespace Barotrauma
|
|||||||
LimbType lowerLegType = LimbType.RightLeg;
|
LimbType lowerLegType = LimbType.RightLeg;
|
||||||
LimbType footType = LimbType.RightFoot;
|
LimbType footType = LimbType.RightFoot;
|
||||||
|
|
||||||
var waistJoint = GetJointBetweenLimbs(LimbType.Waist, upperLegType);
|
var waistJoint = GetJointBetweenLimbs(LimbType.Waist, upperLegType) ?? GetJointBetweenLimbs(LimbType.Torso, upperLegType);
|
||||||
Vector2 localAnchorWaist = Vector2.Zero;
|
Vector2 localAnchorWaist = Vector2.Zero;
|
||||||
Vector2 localAnchorKnee = Vector2.Zero;
|
Vector2 localAnchorKnee = Vector2.Zero;
|
||||||
if (waistJoint != null)
|
if (waistJoint != null)
|
||||||
@@ -336,7 +319,7 @@ namespace Barotrauma
|
|||||||
levitatingCollider = true;
|
levitatingCollider = true;
|
||||||
ColliderIndex = Crouching && !swimming ? 1 : 0;
|
ColliderIndex = Crouching && !swimming ? 1 : 0;
|
||||||
if (character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false ||
|
if (character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false ||
|
||||||
(ForceSelectAnimationType != AnimationType.Walk && ForceSelectAnimationType != AnimationType.NotDefined))
|
(ForceSelectAnimationType != AnimationType.Crouch && ForceSelectAnimationType != AnimationType.NotDefined))
|
||||||
{
|
{
|
||||||
Crouching = false;
|
Crouching = false;
|
||||||
ColliderIndex = 0;
|
ColliderIndex = 0;
|
||||||
@@ -439,9 +422,8 @@ namespace Barotrauma
|
|||||||
midPos += Vector2.Transform(new Vector2(-0.3f * Dir, -0.2f), torsoTransform);
|
midPos += Vector2.Transform(new Vector2(-0.3f * Dir, -0.2f), torsoTransform);
|
||||||
|
|
||||||
if (rightHand.PullJointEnabled) midPos = (midPos + rightHand.PullJointWorldAnchorB) / 2.0f;
|
if (rightHand.PullJointEnabled) midPos = (midPos + rightHand.PullJointWorldAnchorB) / 2.0f;
|
||||||
|
HandIK(rightHand, midPos, CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
|
||||||
HandIK(rightHand, midPos);
|
HandIK(leftHand, midPos, CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
|
||||||
HandIK(leftHand, midPos);
|
|
||||||
}
|
}
|
||||||
else if (character.AnimController.AnimationTestPose)
|
else if (character.AnimController.AnimationTestPose)
|
||||||
{
|
{
|
||||||
@@ -638,7 +620,7 @@ namespace Barotrauma
|
|||||||
Collider.LinearVelocity.Y > 0.0f ? Collider.LinearVelocity.Y * 0.5f : Collider.LinearVelocity.Y);
|
Collider.LinearVelocity.Y > 0.0f ? Collider.LinearVelocity.Y * 0.5f : Collider.LinearVelocity.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUpForce = getUpForce * Math.Max(head.SimPosition.Y - colliderPos.Y, 0.5f);
|
getUpForce *= Math.Max(head.SimPosition.Y - colliderPos.Y, 0.5f);
|
||||||
|
|
||||||
torso.PullJointEnabled = true;
|
torso.PullJointEnabled = true;
|
||||||
head.PullJointEnabled = true;
|
head.PullJointEnabled = true;
|
||||||
@@ -710,9 +692,12 @@ namespace Barotrauma
|
|||||||
float torsoAngle = TorsoAngle.Value;
|
float torsoAngle = TorsoAngle.Value;
|
||||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||||
torsoAngle -= herpesStrength / 150.0f;
|
torsoAngle -= herpesStrength / 150.0f;
|
||||||
torso.body.SmoothRotate(torsoAngle * Dir, 50.0f);
|
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
|
||||||
|
}
|
||||||
|
if (HeadAngle.HasValue)
|
||||||
|
{
|
||||||
|
head.body.SmoothRotate(HeadAngle.Value * Dir, CurrentGroundedParams.HeadTorque);
|
||||||
}
|
}
|
||||||
if (HeadAngle.HasValue) head.body.SmoothRotate(HeadAngle.Value * Dir, 50.0f);
|
|
||||||
|
|
||||||
if (!onGround)
|
if (!onGround)
|
||||||
{
|
{
|
||||||
@@ -743,12 +728,23 @@ namespace Barotrauma
|
|||||||
Vector2 footPos = stepSize * -i;
|
Vector2 footPos = stepSize * -i;
|
||||||
footPos += new Vector2(Math.Sign(movement.X) * FootMoveOffset.X, FootMoveOffset.Y);
|
footPos += new Vector2(Math.Sign(movement.X) * FootMoveOffset.X, FootMoveOffset.Y);
|
||||||
|
|
||||||
if (footPos.Y < 0.0f) footPos.Y = -0.15f;
|
if (footPos.Y < 0.0f) { footPos.Y = -0.15f; }
|
||||||
|
|
||||||
//make the character limp if the feet are damaged
|
//make the character limp if the feet are damaged
|
||||||
float footAfflictionStrength = character.CharacterHealth.GetAfflictionStrength("damage", foot, true);
|
float footAfflictionStrength = character.CharacterHealth.GetAfflictionStrength("damage", foot, true);
|
||||||
footPos.X *= MathHelper.Lerp(1.0f, 0.75f, MathHelper.Clamp(footAfflictionStrength / 50.0f, 0.0f, 1.0f));
|
footPos.X *= MathHelper.Lerp(1.0f, 0.75f, MathHelper.Clamp(footAfflictionStrength / 50.0f, 0.0f, 1.0f));
|
||||||
|
|
||||||
|
if (CurrentGroundedParams.FootLiftHorizontalFactor > 0)
|
||||||
|
{
|
||||||
|
// Calculate the foot y dynamically based on the foot position relative to the waist,
|
||||||
|
// so that the foot aims higher when it's behind the waist and lower when it's in the front.
|
||||||
|
float xDiff = (foot.SimPosition.X - waistPos.X + FootMoveOffset.X) * Dir;
|
||||||
|
float min = MathUtils.InverseLerp(1, 0, CurrentGroundedParams.FootLiftHorizontalFactor);
|
||||||
|
float max = 1 + MathUtils.InverseLerp(0, 1, CurrentGroundedParams.FootLiftHorizontalFactor);
|
||||||
|
float xFactor = MathHelper.Lerp(min, max, MathUtils.InverseLerp(RagdollParams.JointScale, -RagdollParams.JointScale, xDiff));
|
||||||
|
footPos.Y *= xFactor;
|
||||||
|
}
|
||||||
|
|
||||||
if (onSlope && Stairs == null)
|
if (onSlope && Stairs == null)
|
||||||
{
|
{
|
||||||
footPos.Y *= 2.0f;
|
footPos.Y *= 2.0f;
|
||||||
@@ -770,7 +766,7 @@ namespace Barotrauma
|
|||||||
foot.DebugTargetPos = colliderPos + footPos;
|
foot.DebugTargetPos = colliderPos + footPos;
|
||||||
MoveLimb(foot, colliderPos + footPos, CurrentGroundedParams.FootMoveStrength);
|
MoveLimb(foot, colliderPos + footPos, CurrentGroundedParams.FootMoveStrength);
|
||||||
FootIK(foot, colliderPos + footPos,
|
FootIK(foot, colliderPos + footPos,
|
||||||
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootRotateStrength, CurrentGroundedParams.FootAngleInRadians);
|
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +785,7 @@ namespace Barotrauma
|
|||||||
HandIK(rightHand, torso.SimPosition + posAddition +
|
HandIK(rightHand, torso.SimPosition + posAddition +
|
||||||
new Vector2(
|
new Vector2(
|
||||||
-handPos.X,
|
-handPos.X,
|
||||||
(Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.HandMoveStrength);
|
(Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftHand != null && !leftHand.Disabled)
|
if (leftHand != null && !leftHand.Disabled)
|
||||||
@@ -797,16 +793,14 @@ namespace Barotrauma
|
|||||||
HandIK(leftHand, torso.SimPosition + posAddition +
|
HandIK(leftHand, torso.SimPosition + posAddition +
|
||||||
new Vector2(
|
new Vector2(
|
||||||
handPos.X,
|
handPos.X,
|
||||||
(Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.HandMoveStrength);
|
(Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = -1; i < 2; i += 2)
|
for (int i = -1; i < 2; i += 2)
|
||||||
{
|
{
|
||||||
Vector2 footPos = colliderPos;
|
Vector2 footPos = colliderPos;
|
||||||
|
|
||||||
if (Crouching)
|
if (Crouching)
|
||||||
{
|
{
|
||||||
footPos = new Vector2(
|
footPos = new Vector2(
|
||||||
@@ -817,27 +811,24 @@ namespace Barotrauma
|
|||||||
//lift the foot at the back up a bit
|
//lift the foot at the back up a bit
|
||||||
footPos.Y += 0.15f;
|
footPos.Y += 0.15f;
|
||||||
}
|
}
|
||||||
footPos.X += torso.SimPosition.X;
|
footPos.X += colliderPos.X;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
footPos = new Vector2(colliderPos.X + stepSize.X * i * 0.2f, colliderPos.Y - 0.1f);
|
footPos = new Vector2(colliderPos.X + stepSize.X * i * 0.2f, colliderPos.Y - 0.1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Stairs == null)
|
if (Stairs == null)
|
||||||
{
|
{
|
||||||
footPos.Y = Math.Max(Math.Min(FloorY, footPos.Y + 0.5f), footPos.Y);
|
footPos.Y = Math.Max(Math.Min(FloorY, footPos.Y + 0.5f), footPos.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
var foot = i == -1 ? rightFoot : leftFoot;
|
var foot = i == -1 ? rightFoot : leftFoot;
|
||||||
|
|
||||||
if (foot != null && !foot.Disabled)
|
if (foot != null && !foot.Disabled)
|
||||||
{
|
{
|
||||||
foot.DebugRefPos = colliderPos;
|
foot.DebugRefPos = colliderPos;
|
||||||
foot.DebugTargetPos = footPos;
|
foot.DebugTargetPos = footPos;
|
||||||
MoveLimb(foot, footPos, CurrentGroundedParams.FootMoveStrength);
|
MoveLimb(foot, footPos, CurrentGroundedParams.FootMoveStrength);
|
||||||
FootIK(foot, footPos,
|
FootIK(foot, footPos,
|
||||||
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootRotateStrength, CurrentGroundedParams.FootAngleInRadians);
|
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,7 +961,7 @@ namespace Barotrauma
|
|||||||
if (!aiming)
|
if (!aiming)
|
||||||
{
|
{
|
||||||
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
|
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
|
||||||
Collider.SmoothRotate(newRotation, 5.0f * character.SpeedMultiplier);
|
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -981,7 +972,7 @@ namespace Barotrauma
|
|||||||
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
||||||
TargetMovement = new Vector2(0.0f, -0.1f);
|
TargetMovement = new Vector2(0.0f, -0.1f);
|
||||||
float newRotation = MathUtils.VectorToAngle(diff);
|
float newRotation = MathUtils.VectorToAngle(diff);
|
||||||
Collider.SmoothRotate(newRotation, 5.0f * character.SpeedMultiplier);
|
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,19 +982,19 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (TorsoAngle.HasValue)
|
if (TorsoAngle.HasValue)
|
||||||
{
|
{
|
||||||
torso.body.SmoothRotate(Collider.Rotation + TorsoAngle.Value * Dir, CurrentSwimParams.SteerTorque);
|
torso.body.SmoothRotate(Collider.Rotation + TorsoAngle.Value * Dir, CurrentSwimParams.TorsoTorque);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.SteerTorque);
|
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque);
|
||||||
}
|
}
|
||||||
if (HeadAngle.HasValue)
|
if (HeadAngle.HasValue)
|
||||||
{
|
{
|
||||||
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
|
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
head.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.SteerTorque);
|
head.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.HeadTorque);
|
||||||
}
|
}
|
||||||
|
|
||||||
//dont try to move upwards if head is already out of water
|
//dont try to move upwards if head is already out of water
|
||||||
@@ -1044,25 +1035,25 @@ namespace Barotrauma
|
|||||||
float legMoveMultiplier = 1.0f;
|
float legMoveMultiplier = 1.0f;
|
||||||
if (movement.LengthSquared() < 0.001f)
|
if (movement.LengthSquared() < 0.001f)
|
||||||
{
|
{
|
||||||
//TODO: expose these?
|
// Swimming in place (TODO: expose?)
|
||||||
legMoveMultiplier = 0.3f;
|
legMoveMultiplier = 0.3f;
|
||||||
legCyclePos += 0.4f;
|
legCyclePos += 0.4f;
|
||||||
handCyclePos += 0.1f;
|
handCyclePos += 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
var waist = GetLimb(LimbType.Waist);
|
var waist = GetLimb(LimbType.Waist) ?? GetLimb(LimbType.Torso);
|
||||||
footPos = waist == null ? Vector2.Zero : waist.SimPosition - new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * (upperLegLength + lowerLegLength);
|
footPos = waist == null ? Vector2.Zero : waist.SimPosition - new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * (upperLegLength + lowerLegLength);
|
||||||
Vector2 transformedFootPos = new Vector2((float)Math.Sin(legCyclePos / CurrentSwimParams.LegCycleLength) * CurrentSwimParams.LegMoveAmount * legMoveMultiplier, 0.0f);
|
Vector2 transformedFootPos = new Vector2((float)Math.Sin(legCyclePos / CurrentSwimParams.LegCycleLength) * CurrentSwimParams.LegMoveAmount * legMoveMultiplier, 0.0f);
|
||||||
transformedFootPos = Vector2.Transform(transformedFootPos, Matrix.CreateRotationZ(Collider.Rotation));
|
transformedFootPos = Vector2.Transform(transformedFootPos, Matrix.CreateRotationZ(Collider.Rotation));
|
||||||
|
|
||||||
float torque = CurrentSwimParams.FootRotateStrength * character.SpeedMultiplier * (1.2f - character.GetLegPenalty());
|
float legTorque = CurrentSwimParams.LegTorque * character.SpeedMultiplier * (1.2f - character.GetLegPenalty());
|
||||||
if (rightFoot != null && !rightFoot.Disabled)
|
if (rightFoot != null && !rightFoot.Disabled)
|
||||||
{
|
{
|
||||||
FootIK(rightFoot, footPos - transformedFootPos, torque, torque, CurrentSwimParams.FootAngleInRadians);
|
FootIK(rightFoot, footPos - transformedFootPos, legTorque, CurrentSwimParams.FootTorque, CurrentSwimParams.FootAngleInRadians);
|
||||||
}
|
}
|
||||||
if (leftFoot != null && !leftFoot.Disabled)
|
if (leftFoot != null && !leftFoot.Disabled)
|
||||||
{
|
{
|
||||||
FootIK(leftFoot, footPos + transformedFootPos, torque, torque, CurrentSwimParams.FootAngleInRadians);
|
FootIK(leftFoot, footPos + transformedFootPos, legTorque, CurrentSwimParams.FootTorque, CurrentSwimParams.FootAngleInRadians);
|
||||||
}
|
}
|
||||||
|
|
||||||
handPos = (torso.SimPosition + head.SimPosition) / 2.0f;
|
handPos = (torso.SimPosition + head.SimPosition) / 2.0f;
|
||||||
@@ -1071,7 +1062,7 @@ namespace Barotrauma
|
|||||||
// -> hands just float around
|
// -> hands just float around
|
||||||
if ((!headInWater && TargetMovement.X == 0.0f && TargetMovement.Y > 0) || TargetMovement.LengthSquared() < 0.001f)
|
if ((!headInWater && TargetMovement.X == 0.0f && TargetMovement.Y > 0) || TargetMovement.LengthSquared() < 0.001f)
|
||||||
{
|
{
|
||||||
handPos += MathUtils.RotatePoint(Vector2.UnitX * Dir * 0.6f, torso.Rotation);
|
handPos += MathUtils.RotatePoint(Vector2.UnitX * Dir * 0.2f, torso.Rotation);
|
||||||
|
|
||||||
float wobbleAmount = 0.1f;
|
float wobbleAmount = 0.1f;
|
||||||
|
|
||||||
@@ -1079,14 +1070,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
MoveLimb(rightHand, new Vector2(
|
MoveLimb(rightHand, new Vector2(
|
||||||
handPos.X + (float)Math.Sin(handCyclePos / 1.5f) * wobbleAmount,
|
handPos.X + (float)Math.Sin(handCyclePos / 1.5f) * wobbleAmount,
|
||||||
handPos.Y + (float)Math.Sin(handCyclePos / 3.5f) * wobbleAmount - 0.25f), 1.5f);
|
handPos.Y + (float)Math.Sin(handCyclePos / 3.5f) * wobbleAmount - 0.25f), CurrentSwimParams.ArmMoveStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftHand != null && !leftHand.Disabled)
|
if (leftHand != null && !leftHand.Disabled)
|
||||||
{
|
{
|
||||||
MoveLimb(leftHand, new Vector2(
|
MoveLimb(leftHand, new Vector2(
|
||||||
handPos.X + (float)Math.Sin(handCyclePos / 2.0f) * wobbleAmount,
|
handPos.X + (float)Math.Sin(handCyclePos / 2.0f) * wobbleAmount,
|
||||||
handPos.Y + (float)Math.Sin(handCyclePos / 3.0f) * wobbleAmount - 0.25f), 1.5f);
|
handPos.Y + (float)Math.Sin(handCyclePos / 3.0f) * wobbleAmount - 0.25f), CurrentSwimParams.ArmMoveStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -1107,8 +1098,8 @@ namespace Barotrauma
|
|||||||
Vector2 rightHandPos = new Vector2(-handPosX, -handPosY) + handMoveOffset;
|
Vector2 rightHandPos = new Vector2(-handPosX, -handPosY) + handMoveOffset;
|
||||||
rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
|
rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
|
||||||
rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix);
|
rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix);
|
||||||
|
float speedMultiplier = character.SpeedMultiplier * (1 - Character.GetRightHandPenalty());
|
||||||
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.HandMoveStrength * character.SpeedMultiplier * (1 - Character.GetRightHandPenalty()));
|
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftHand != null && !leftHand.Disabled)
|
if (leftHand != null && !leftHand.Disabled)
|
||||||
@@ -1116,8 +1107,8 @@ namespace Barotrauma
|
|||||||
Vector2 leftHandPos = new Vector2(handPosX, handPosY) + handMoveOffset;
|
Vector2 leftHandPos = new Vector2(handPosX, handPosY) + handMoveOffset;
|
||||||
leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X);
|
leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X);
|
||||||
leftHandPos = Vector2.Transform(leftHandPos, rotationMatrix);
|
leftHandPos = Vector2.Transform(leftHandPos, rotationMatrix);
|
||||||
|
float speedMultiplier = character.SpeedMultiplier * (1 - Character.GetLeftHandPenalty());
|
||||||
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.HandMoveStrength * character.SpeedMultiplier * (1 - Character.GetLeftHandPenalty()));
|
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1173,15 +1164,16 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
float bottomPos = Collider.SimPosition.Y - ColliderHeightFromFloor - Collider.radius - Collider.height / 2.0f;
|
float bottomPos = Collider.SimPosition.Y - ColliderHeightFromFloor - Collider.radius - Collider.height / 2.0f;
|
||||||
|
float headPos = HeadPosition ?? 0;
|
||||||
|
float torsoPos = TorsoPosition ?? 0;
|
||||||
|
MoveLimb(head, new Vector2(ladderSimPos.X - 0.2f * Dir, bottomPos + headPos), 10.5f);
|
||||||
|
MoveLimb(torso, new Vector2(ladderSimPos.X - 0.35f * Dir, bottomPos + torsoPos), 10.5f);
|
||||||
|
|
||||||
MoveLimb(head, new Vector2(ladderSimPos.X - 0.35f * Dir, bottomPos + WalkParams.HeadPosition), 10.5f);
|
Collider.MoveToPos(new Vector2(ladderSimPos.X - 0.1f * Dir, Collider.SimPosition.Y), 10.5f);
|
||||||
MoveLimb(torso, new Vector2(ladderSimPos.X - 0.35f * Dir, bottomPos + WalkParams.TorsoPosition), 10.5f);
|
|
||||||
|
|
||||||
Collider.MoveToPos(new Vector2(ladderSimPos.X - 0.1f * Dir, Collider.SimPosition.Y), 10.5f);
|
|
||||||
|
|
||||||
Vector2 handPos = new Vector2(
|
Vector2 handPos = new Vector2(
|
||||||
ladderSimPos.X,
|
ladderSimPos.X,
|
||||||
bottomPos + WalkParams.TorsoPosition + movement.Y * 0.1f - ladderSimPos.Y);
|
bottomPos + torsoPos + movement.Y * 0.1f - ladderSimPos.Y);
|
||||||
|
|
||||||
//prevent the hands from going above the top of the ladders
|
//prevent the hands from going above the top of the ladders
|
||||||
handPos.Y = Math.Min(-0.5f, handPos.Y);
|
handPos.Y = Math.Min(-0.5f, handPos.Y);
|
||||||
@@ -1258,7 +1250,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
//apply forces to the collider to move the Character up/down
|
//apply forces to the collider to move the Character up/down
|
||||||
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||||
head.body.SmoothRotate(0.0f);
|
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
|
||||||
|
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
|
||||||
|
|
||||||
if (!character.SelectedConstruction.Prefab.Triggers.Any())
|
if (!character.SelectedConstruction.Prefab.Triggers.Any())
|
||||||
{
|
{
|
||||||
@@ -1881,7 +1874,7 @@ namespace Barotrauma
|
|||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
if (!character.Inventory.IsInLimbSlot(item, i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand)) { continue; }
|
if (!character.Inventory.IsInLimbSlot(item, i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand)) { continue; }
|
||||||
HandIK(i == 0 ? rightHand : leftHand, transformedHoldPos + transformedHandlePos[i]);
|
HandIK(i == 0 ? rightHand : leftHand, transformedHoldPos + transformedHandlePos[i], CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1906,7 +1899,7 @@ namespace Barotrauma
|
|||||||
return (lowFreqNoise * 1.0f + highFreqNoise * 0.1f) * wobbleStrength;
|
return (lowFreqNoise * 1.0f + highFreqNoise * 0.1f) * wobbleStrength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandIK(Limb hand, Vector2 pos, float force = 1.0f)
|
private void HandIK(Limb hand, Vector2 pos, float armTorque = 1.0f, float handTorque = 1.0f)
|
||||||
{
|
{
|
||||||
Vector2 shoulderPos;
|
Vector2 shoulderPos;
|
||||||
|
|
||||||
@@ -1948,9 +1941,11 @@ namespace Barotrauma
|
|||||||
armAngle -= MathHelper.TwoPi;
|
armAngle -= MathHelper.TwoPi;
|
||||||
}
|
}
|
||||||
|
|
||||||
arm?.body.SmoothRotate((armAngle - upperArmAngle), 20.0f * force * arm.Mass, wrapAngle: false);
|
arm?.body.SmoothRotate(armAngle - upperArmAngle, 100.0f * armTorque * arm.Mass, wrapAngle: false);
|
||||||
forearm?.body.SmoothRotate((armAngle + lowerArmAngle), 20.0f * force * forearm.Mass, wrapAngle: false);
|
float forearmAngle = armAngle + lowerArmAngle;
|
||||||
hand?.body.SmoothRotate((armAngle + lowerArmAngle), 100.0f * force * hand.Mass, wrapAngle: false);
|
forearm?.body.SmoothRotate(forearmAngle, 100.0f * handTorque * forearm.Mass, wrapAngle: false);
|
||||||
|
float handAngle = forearm != null ? armAngle : forearmAngle;
|
||||||
|
hand?.body.SmoothRotate(handAngle, 100.0f * handTorque * hand.Mass, wrapAngle: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
|
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
|
||||||
@@ -1976,12 +1971,12 @@ namespace Barotrauma
|
|||||||
upperLeg = GetLimb(LimbType.RightThigh);
|
upperLeg = GetLimb(LimbType.RightThigh);
|
||||||
lowerLeg = GetLimb(LimbType.RightLeg);
|
lowerLeg = GetLimb(LimbType.RightLeg);
|
||||||
}
|
}
|
||||||
var torso = GetLimb(LimbType.Torso);
|
Limb torso = GetLimb(LimbType.Torso);
|
||||||
var waist = GetJointBetweenLimbs(LimbType.Waist, upperLeg.type);
|
LimbJoint waistJoint = GetJointBetweenLimbs(LimbType.Waist, upperLeg.type) ?? GetJointBetweenLimbs(LimbType.Torso, upperLeg.type);
|
||||||
Vector2 waistPos = Vector2.Zero;
|
Vector2 waistPos = Vector2.Zero;
|
||||||
if (waist != null)
|
if (waistJoint != null)
|
||||||
{
|
{
|
||||||
waistPos = waist.LimbA == upperLeg ? waist.WorldAnchorA : waist.WorldAnchorB;
|
waistPos = waistJoint.LimbA == upperLeg ? waistJoint.WorldAnchorA : waistJoint.WorldAnchorB;
|
||||||
}
|
}
|
||||||
|
|
||||||
//distance from waist joint to the target position
|
//distance from waist joint to the target position
|
||||||
@@ -2137,5 +2132,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override float GetSpeed(AnimationType type)
|
||||||
|
{
|
||||||
|
if (type == AnimationType.Crouch)
|
||||||
|
{
|
||||||
|
if (!CanWalk)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"{character.SpeciesName} cannot crouch!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return IsMovingBackwards ? HumanCrouchParams.MovementSpeed * HumanCrouchParams.BackwardsMovementMultiplier : HumanCrouchParams.MovementSpeed;
|
||||||
|
}
|
||||||
|
return base.GetSpeed(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,8 +309,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public string TraitorCurrentObjective = "";
|
public string TraitorCurrentObjective = "";
|
||||||
public bool IsHuman => SpeciesName.Equals(CharacterPrefab.HumanSpeciesName, StringComparison.OrdinalIgnoreCase);
|
public bool IsHuman => SpeciesName.Equals(CharacterPrefab.HumanSpeciesName, StringComparison.OrdinalIgnoreCase);
|
||||||
public bool IsMale => Info != null && Info.HasGenders && Info.Gender == Gender.Male;
|
|
||||||
public bool IsFemale => Info != null && Info.HasGenders && Info.Gender == Gender.Female;
|
|
||||||
|
|
||||||
private float attackCoolDown;
|
private float attackCoolDown;
|
||||||
|
|
||||||
@@ -1665,9 +1663,9 @@ namespace Barotrauma
|
|||||||
AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f;
|
AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AnimController is HumanoidAnimController)
|
if (AnimController is HumanoidAnimController humanAnimController)
|
||||||
{
|
{
|
||||||
((HumanoidAnimController)AnimController).Crouching = IsKeyDown(InputType.Crouch);
|
humanAnimController.Crouching = humanAnimController.ForceSelectAnimationType == AnimationType.Crouch || IsKeyDown(InputType.Crouch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aiControlled &&
|
if (!aiControlled &&
|
||||||
@@ -2760,9 +2758,9 @@ namespace Barotrauma
|
|||||||
//ragdoll button
|
//ragdoll button
|
||||||
if (IsRagdolled || !CanMove)
|
if (IsRagdolled || !CanMove)
|
||||||
{
|
{
|
||||||
if (AnimController is HumanoidAnimController)
|
if (AnimController is HumanoidAnimController humanAnimController)
|
||||||
{
|
{
|
||||||
((HumanoidAnimController)AnimController).Crouching = false;
|
humanAnimController.Crouching = false;
|
||||||
}
|
}
|
||||||
AnimController.ResetPullJoints();
|
AnimController.ResetPullJoints();
|
||||||
SelectedConstruction = null;
|
SelectedConstruction = null;
|
||||||
@@ -3505,9 +3503,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse = 0.0f, Character attacker = null)
|
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse = 0.0f, Character attacker = null, float damageMultiplier = 1f)
|
||||||
{
|
{
|
||||||
return AddDamage(worldPosition, afflictions, stun, playSound, attackImpulse, out _, attacker);
|
return AddDamage(worldPosition, afflictions, stun, playSound, attackImpulse, out _, attacker, damageMultiplier: damageMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse, out Limb hitLimb, Character attacker = null, float damageMultiplier = 1)
|
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse, out Limb hitLimb, Character attacker = null, float damageMultiplier = 1)
|
||||||
@@ -4351,7 +4349,7 @@ namespace Barotrauma
|
|||||||
return GiveTalent(talentPrefab, addingFirstTime);
|
return GiveTalent(talentPrefab, addingFirstTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GiveTalent(TalentPrefab talentPrefab, bool addingFirstTime = true)
|
public bool GiveTalent(TalentPrefab talentPrefab, bool addingFirstTime = true)
|
||||||
{
|
{
|
||||||
if (addingFirstTime)
|
if (addingFirstTime)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Barotrauma.Networking;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
@@ -14,7 +14,6 @@ namespace Barotrauma
|
|||||||
public enum Gender { None, Male, Female };
|
public enum Gender { None, Male, Female };
|
||||||
public enum Race { None, White, Black, Brown, Asian };
|
public enum Race { None, White, Black, Brown, Asian };
|
||||||
|
|
||||||
// TODO: Generating the HeadInfo could be simplified.
|
|
||||||
partial class CharacterInfo
|
partial class CharacterInfo
|
||||||
{
|
{
|
||||||
public class HeadInfo
|
public class HeadInfo
|
||||||
@@ -25,15 +24,7 @@ namespace Barotrauma
|
|||||||
get { return _headSpriteId; }
|
get { return _headSpriteId; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_headSpriteId = value;
|
_headSpriteId = Math.Max(Math.Clamp(value, (int)headSpriteRange.X, (int)headSpriteRange.Y), 1);
|
||||||
if (_headSpriteId < (int)headSpriteRange.X)
|
|
||||||
{
|
|
||||||
_headSpriteId = (int)headSpriteRange.Y;
|
|
||||||
}
|
|
||||||
if (_headSpriteId > (int)headSpriteRange.Y)
|
|
||||||
{
|
|
||||||
_headSpriteId = (int)headSpriteRange.X;
|
|
||||||
}
|
|
||||||
GetSpriteSheetIndex();
|
GetSpriteSheetIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +33,10 @@ namespace Barotrauma
|
|||||||
public Gender gender;
|
public Gender gender;
|
||||||
public Race race;
|
public Race race;
|
||||||
|
|
||||||
|
public Color HairColor;
|
||||||
|
public Color FacialHairColor;
|
||||||
|
public Color SkinColor;
|
||||||
|
|
||||||
public int HairIndex { get; set; } = -1;
|
public int HairIndex { get; set; } = -1;
|
||||||
public int BeardIndex { get; set; } = -1;
|
public int BeardIndex { get; set; } = -1;
|
||||||
public int MoustacheIndex { get; set; } = -1;
|
public int MoustacheIndex { get; set; } = -1;
|
||||||
@@ -74,11 +69,11 @@ namespace Barotrauma
|
|||||||
FaceAttachmentIndex = -1;
|
FaceAttachmentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetSpriteSheetIndex()
|
public void GetSpriteSheetIndex()
|
||||||
{
|
{
|
||||||
if (heads != null && heads.Any())
|
if (heads != null && heads.Any())
|
||||||
{
|
{
|
||||||
var matchingHead = heads.Keys.FirstOrDefault(h => h.Gender == gender && h.Race == race && h.ID == _headSpriteId);
|
var matchingHead = heads.Keys.FirstOrDefault(h => h.ID == HeadSpriteId && IsMatchingGender(h.Gender, gender) && IsMatchingRace(h.Race, race));
|
||||||
if (matchingHead != null)
|
if (matchingHead != null)
|
||||||
{
|
{
|
||||||
if (heads.TryGetValue(matchingHead, out Vector2 index))
|
if (heads.TryGetValue(matchingHead, out Vector2 index))
|
||||||
@@ -99,14 +94,13 @@ namespace Barotrauma
|
|||||||
if (head != value && value != null)
|
if (head != value && value != null)
|
||||||
{
|
{
|
||||||
head = value;
|
head = value;
|
||||||
if (head.race == Race.None)
|
if (!IsValidRace(head.race))
|
||||||
{
|
{
|
||||||
head.race = GetRandomRace(Rand.RandSync.Unsynced);
|
head.race = GetRandomRace(Rand.RandSync.Unsynced);
|
||||||
}
|
}
|
||||||
CalculateHeadSpriteRange();
|
CalculateHeadSpriteRange();
|
||||||
Head.HeadSpriteId = value.HeadSpriteId;
|
Head.HeadSpriteId = value.HeadSpriteId;
|
||||||
HeadSprite = null;
|
RefreshHeadSprites();
|
||||||
AttachmentSprites = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +151,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool HasNickname => Name != OriginalName;
|
public bool HasNickname => Name != OriginalName;
|
||||||
public string OriginalName { get; private set; }
|
public string OriginalName { get; private set; }
|
||||||
|
|
||||||
public string Name;
|
public string Name;
|
||||||
|
|
||||||
public string DisplayName
|
public string DisplayName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -387,29 +383,31 @@ namespace Barotrauma
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
Head.HeadSpriteId = value;
|
Head.HeadSpriteId = value;
|
||||||
HeadSprite = null;
|
|
||||||
AttachmentSprites = null;
|
|
||||||
ResetHeadAttachments();
|
ResetHeadAttachments();
|
||||||
|
RefreshHeadSprites();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly bool HasGenders;
|
public readonly bool HasGenders;
|
||||||
|
public readonly bool HasRaces;
|
||||||
|
|
||||||
public Gender Gender
|
public Gender Gender
|
||||||
{
|
{
|
||||||
get { return Head.gender; }
|
get { return Head.gender; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Head.gender == value) return;
|
Gender previousValue = Head.gender;
|
||||||
Head.gender = value;
|
Head.gender = value;
|
||||||
if (Head.gender == Gender.None)
|
if (!IsValidGender(Head.gender))
|
||||||
{
|
{
|
||||||
Head.gender = Gender.Male;
|
Head.gender = GetDefaultGender();
|
||||||
|
}
|
||||||
|
if (Head.gender != previousValue)
|
||||||
|
{
|
||||||
|
CalculateHeadSpriteRange();
|
||||||
|
ResetHeadAttachments();
|
||||||
|
RefreshHeadSprites();
|
||||||
}
|
}
|
||||||
CalculateHeadSpriteRange();
|
|
||||||
ResetHeadAttachments();
|
|
||||||
HeadSprite = null;
|
|
||||||
AttachmentSprites = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,28 +416,82 @@ namespace Barotrauma
|
|||||||
get { return Head.race; }
|
get { return Head.race; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Head.race == value) { return; }
|
Race previousValue = Head.race;
|
||||||
Head.race = value;
|
Head.race = value;
|
||||||
if (Head.race == Race.None)
|
if (!IsValidRace(Head.race))
|
||||||
{
|
{
|
||||||
Head.race = Race.White;
|
Head.race = GetDefaultRace();
|
||||||
|
}
|
||||||
|
if (Head.race != previousValue)
|
||||||
|
{
|
||||||
|
CalculateHeadSpriteRange();
|
||||||
|
ResetHeadAttachments();
|
||||||
|
RefreshHeadSprites();
|
||||||
}
|
}
|
||||||
CalculateHeadSpriteRange();
|
|
||||||
ResetHeadAttachments();
|
|
||||||
HeadSprite = null;
|
|
||||||
AttachmentSprites = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int HairIndex { get => Head.HairIndex; set => Head.HairIndex = value; }
|
private bool IsValidRace(Race race) => HasRaces ? race != Race.None : race == Race.None;
|
||||||
public int BeardIndex { get => Head.BeardIndex; set => Head.BeardIndex = value; }
|
|
||||||
public int MoustacheIndex { get => Head.MoustacheIndex; set => Head.MoustacheIndex = value; }
|
|
||||||
public int FaceAttachmentIndex { get => Head.FaceAttachmentIndex; set => Head.FaceAttachmentIndex = value; }
|
|
||||||
|
|
||||||
public XElement HairElement { get => Head.HairElement; set => Head.HairElement = value; }
|
private bool IsValidGender(Gender gender) => HasGenders ? gender != Gender.None : gender == Gender.None;
|
||||||
public XElement BeardElement { get => Head.BeardElement; set => Head.BeardElement = value; }
|
|
||||||
public XElement MoustacheElement { get => Head.MoustacheElement; set => Head.MoustacheElement = value; }
|
private Gender GetDefaultGender() => HasGenders ? Gender.Male : Gender.None;
|
||||||
public XElement FaceAttachment { get => Head.FaceAttachment; set => Head.FaceAttachment = value; }
|
|
||||||
|
private Race GetDefaultRace() => HasRaces ? Race.White : Race.None;
|
||||||
|
|
||||||
|
public int HairIndex
|
||||||
|
{
|
||||||
|
get => Head.HairIndex;
|
||||||
|
set => Head.HairIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int BeardIndex
|
||||||
|
{
|
||||||
|
get => Head.BeardIndex;
|
||||||
|
set => Head.BeardIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MoustacheIndex
|
||||||
|
{
|
||||||
|
get => Head.MoustacheIndex;
|
||||||
|
set => Head.MoustacheIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FaceAttachmentIndex
|
||||||
|
{
|
||||||
|
get => Head.FaceAttachmentIndex;
|
||||||
|
set => Head.FaceAttachmentIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ImmutableArray<Color> HairColors;
|
||||||
|
public readonly ImmutableArray<Color> FacialHairColors;
|
||||||
|
public readonly ImmutableArray<Color> SkinColors;
|
||||||
|
|
||||||
|
public Color HairColor
|
||||||
|
{
|
||||||
|
get => Head.HairColor;
|
||||||
|
set => Head.HairColor = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color FacialHairColor
|
||||||
|
{
|
||||||
|
get => Head.FacialHairColor;
|
||||||
|
set => Head.FacialHairColor = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color SkinColor
|
||||||
|
{
|
||||||
|
get => Head.SkinColor;
|
||||||
|
set => Head.SkinColor = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XElement HairElement => Head.HairElement;
|
||||||
|
|
||||||
|
public XElement BeardElement => Head.BeardElement;
|
||||||
|
|
||||||
|
public XElement MoustacheElement => Head.MoustacheElement;
|
||||||
|
|
||||||
|
public XElement FaceAttachment => Head.FaceAttachment;
|
||||||
|
|
||||||
private RagdollParams ragdoll;
|
private RagdollParams ragdoll;
|
||||||
public RagdollParams Ragdoll
|
public RagdollParams Ragdoll
|
||||||
@@ -480,16 +532,18 @@ namespace Barotrauma
|
|||||||
if (doc == null) { return; }
|
if (doc == null) { return; }
|
||||||
CharacterConfigElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root;
|
CharacterConfigElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root;
|
||||||
// TODO: support for variants
|
// TODO: support for variants
|
||||||
head = new HeadInfo();
|
Head = new HeadInfo();
|
||||||
HasGenders = CharacterConfigElement.GetAttributeBool("genders", false);
|
HasGenders = CharacterConfigElement.GetAttributeBool("genders", false);
|
||||||
if (HasGenders)
|
Head.gender = GetRandomGender(randSync);
|
||||||
{
|
HasRaces = CharacterConfigElement.GetAttributeBool("races", false);
|
||||||
Head.gender = GetRandomGender(randSync);
|
|
||||||
}
|
|
||||||
Head.race = GetRandomRace(randSync);
|
Head.race = GetRandomRace(randSync);
|
||||||
CalculateHeadSpriteRange();
|
CalculateHeadSpriteRange();
|
||||||
Head.HeadSpriteId = GetRandomHeadID(randSync);
|
HeadSpriteId = GetRandomHeadID(randSync);
|
||||||
Job = (jobPrefab == null) ? Job.Random(Rand.RandSync.Unsynced) : new Job(jobPrefab, variant);
|
Job = (jobPrefab == null) ? Job.Random(Rand.RandSync.Unsynced) : new Job(jobPrefab, variant);
|
||||||
|
HairColors = CharacterConfigElement.GetAttributeColorArray("haircolors", new Color[] { Color.WhiteSmoke }).ToImmutableArray();
|
||||||
|
FacialHairColors = CharacterConfigElement.GetAttributeColorArray("facialhaircolors", new Color[] { Color.WhiteSmoke }).ToImmutableArray();
|
||||||
|
SkinColors = CharacterConfigElement.GetAttributeColorArray("skincolors", new Color[] { new Color(255, 215, 200, 255) }).ToImmutableArray();
|
||||||
|
SetColors();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(name))
|
if (!string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
@@ -502,23 +556,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
name = "";
|
name = "";
|
||||||
if (CharacterConfigElement.Element("name") != null)
|
Name = GetRandomName(randSync);
|
||||||
{
|
|
||||||
string firstNamePath = CharacterConfigElement.Element("name").GetAttributeString("firstname", "");
|
|
||||||
if (firstNamePath != "")
|
|
||||||
{
|
|
||||||
firstNamePath = firstNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
|
||||||
Name = ToolBox.GetRandomLine(firstNamePath, randSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
string lastNamePath = CharacterConfigElement.Element("name").GetAttributeString("lastname", "");
|
|
||||||
if (lastNamePath != "")
|
|
||||||
{
|
|
||||||
lastNamePath = lastNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
|
||||||
if (Name != "") Name += " ";
|
|
||||||
Name += ToolBox.GetRandomLine(lastNamePath, randSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
OriginalName = !string.IsNullOrEmpty(originalName) ? originalName : Name;
|
OriginalName = !string.IsNullOrEmpty(originalName) ? originalName : Name;
|
||||||
personalityTrait = NPCPersonalityTrait.GetRandom(name + HeadSpriteId);
|
personalityTrait = NPCPersonalityTrait.GetRandom(name + HeadSpriteId);
|
||||||
@@ -530,6 +568,53 @@ namespace Barotrauma
|
|||||||
LoadHeadAttachments();
|
LoadHeadAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetRandomName(Rand.RandSync randSync)
|
||||||
|
{
|
||||||
|
string name = "";
|
||||||
|
if (CharacterConfigElement.Element("name") != null)
|
||||||
|
{
|
||||||
|
string firstNamePath = CharacterConfigElement.Element("name").GetAttributeString("firstname", "");
|
||||||
|
if (firstNamePath != "")
|
||||||
|
{
|
||||||
|
firstNamePath = firstNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||||
|
name = ToolBox.GetRandomLine(firstNamePath, randSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
string lastNamePath = CharacterConfigElement.Element("name").GetAttributeString("lastname", "");
|
||||||
|
if (lastNamePath != "")
|
||||||
|
{
|
||||||
|
lastNamePath = lastNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||||
|
if (name != "") { name += " "; }
|
||||||
|
name += ToolBox.GetRandomLine(lastNamePath, randSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetColors()
|
||||||
|
{
|
||||||
|
HairColor = HairColors.GetRandom();
|
||||||
|
FacialHairColor = FacialHairColors.GetRandom();
|
||||||
|
SkinColor = SkinColors.GetRandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckColors()
|
||||||
|
{
|
||||||
|
if (HairColor == Color.Black)
|
||||||
|
{
|
||||||
|
HairColor = HairColors.GetRandom();
|
||||||
|
}
|
||||||
|
if (FacialHairColor == Color.Black)
|
||||||
|
{
|
||||||
|
FacialHairColor = FacialHairColors.GetRandom();
|
||||||
|
}
|
||||||
|
if (SkinColor == Color.Black)
|
||||||
|
{
|
||||||
|
SkinColor = SkinColors.GetRandom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Used for loading the data
|
// Used for loading the data
|
||||||
public CharacterInfo(XElement infoElement)
|
public CharacterInfo(XElement infoElement)
|
||||||
{
|
{
|
||||||
@@ -542,7 +627,7 @@ namespace Barotrauma
|
|||||||
ExperiencePoints = infoElement.GetAttributeInt("experiencepoints", 0);
|
ExperiencePoints = infoElement.GetAttributeInt("experiencepoints", 0);
|
||||||
UnlockedTalents = new HashSet<string>(infoElement.GetAttributeStringArray("unlockedtalents", new string[0], convertToLowerInvariant: true));
|
UnlockedTalents = new HashSet<string>(infoElement.GetAttributeStringArray("unlockedtalents", new string[0], convertToLowerInvariant: true));
|
||||||
AdditionalTalentPoints = infoElement.GetAttributeInt("additionaltalentpoints", 0);
|
AdditionalTalentPoints = infoElement.GetAttributeInt("additionaltalentpoints", 0);
|
||||||
Enum.TryParse(infoElement.GetAttributeString("race", "White"), true, out Race race);
|
Enum.TryParse(infoElement.GetAttributeString("race", "None"), true, out Race race);
|
||||||
Enum.TryParse(infoElement.GetAttributeString("gender", "None"), true, out Gender gender);
|
Enum.TryParse(infoElement.GetAttributeString("gender", "None"), true, out Gender gender);
|
||||||
_speciesName = infoElement.GetAttributeString("speciesname", null);
|
_speciesName = infoElement.GetAttributeString("speciesname", null);
|
||||||
XDocument doc = null;
|
XDocument doc = null;
|
||||||
@@ -560,14 +645,19 @@ namespace Barotrauma
|
|||||||
// TODO: support for variants
|
// TODO: support for variants
|
||||||
CharacterConfigElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root;
|
CharacterConfigElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root;
|
||||||
HasGenders = CharacterConfigElement.GetAttributeBool("genders", false);
|
HasGenders = CharacterConfigElement.GetAttributeBool("genders", false);
|
||||||
if (HasGenders && gender == Gender.None)
|
HasRaces = CharacterConfigElement.GetAttributeBool("hasraces", false);
|
||||||
|
if (!IsValidGender(gender))
|
||||||
{
|
{
|
||||||
gender = GetRandomGender(Rand.RandSync.Unsynced);
|
gender = GetRandomGender(Rand.RandSync.Unsynced);
|
||||||
}
|
}
|
||||||
else if (!HasGenders)
|
if (!IsValidRace(race))
|
||||||
{
|
{
|
||||||
gender = Gender.None;
|
race = GetRandomRace(Rand.RandSync.Unsynced);
|
||||||
}
|
}
|
||||||
|
HairColors = CharacterConfigElement.GetAttributeColorArray("haircolors", new Color[] { Color.WhiteSmoke }).ToImmutableArray();
|
||||||
|
FacialHairColors = CharacterConfigElement.GetAttributeColorArray("facialhaircolors", new Color[] { Color.WhiteSmoke }).ToImmutableArray();
|
||||||
|
SkinColors = CharacterConfigElement.GetAttributeColorArray("skincolors", new Color[] { new Color(255, 215, 200, 255) }).ToImmutableArray();
|
||||||
|
|
||||||
RecreateHead(
|
RecreateHead(
|
||||||
infoElement.GetAttributeInt("headspriteid", 1),
|
infoElement.GetAttributeInt("headspriteid", 1),
|
||||||
race,
|
race,
|
||||||
@@ -577,6 +667,11 @@ namespace Barotrauma
|
|||||||
infoElement.GetAttributeInt("moustacheindex", -1),
|
infoElement.GetAttributeInt("moustacheindex", -1),
|
||||||
infoElement.GetAttributeInt("faceattachmentindex", -1));
|
infoElement.GetAttributeInt("faceattachmentindex", -1));
|
||||||
|
|
||||||
|
SkinColor = infoElement.GetAttributeColor("skincolor", Color.White);
|
||||||
|
HairColor = infoElement.GetAttributeColor("haircolor", Color.White);
|
||||||
|
FacialHairColor = infoElement.GetAttributeColor("facialhaircolor", Color.White);
|
||||||
|
CheckColors();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Name))
|
if (string.IsNullOrEmpty(Name))
|
||||||
{
|
{
|
||||||
if (CharacterConfigElement.Element("name") != null)
|
if (CharacterConfigElement.Element("name") != null)
|
||||||
@@ -652,8 +747,25 @@ namespace Barotrauma
|
|||||||
LoadHeadAttachments();
|
LoadHeadAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gender GetRandomGender(Rand.RandSync randSync) => (Rand.Range(0.0f, 1.0f, randSync) < CharacterConfigElement.GetAttributeFloat("femaleratio", 0.5f)) ? Gender.Female : Gender.Male;
|
public Gender GetRandomGender(Rand.RandSync randSync)
|
||||||
public Race GetRandomRace(Rand.RandSync randSync) => new Race[] { Race.White, Race.Black, Race.Asian }.GetRandom(randSync);
|
{
|
||||||
|
if (HasGenders)
|
||||||
|
{
|
||||||
|
return (Rand.Range(0.0f, 1.0f, randSync) < CharacterConfigElement.GetAttributeFloat("femaleratio", 0.5f)) ? Gender.Female : Gender.Male;
|
||||||
|
}
|
||||||
|
return Gender.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Race GetRandomRace(Rand.RandSync randSync)
|
||||||
|
{
|
||||||
|
if (HasRaces)
|
||||||
|
{
|
||||||
|
return new Race[] { Race.White, Race.Black, Race.Asian }.GetRandom(randSync);
|
||||||
|
}
|
||||||
|
return Race.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public int GetRandomHeadID(Rand.RandSync randSync) => Head.headSpriteRange != Vector2.Zero ? Rand.Range((int)Head.headSpriteRange.X, (int)Head.headSpriteRange.Y + 1, randSync) : 0;
|
public int GetRandomHeadID(Rand.RandSync randSync) => Head.headSpriteRange != Vector2.Zero ? Rand.Range((int)Head.headSpriteRange.X, (int)Head.headSpriteRange.Y + 1, randSync) : 0;
|
||||||
|
|
||||||
private List<XElement> hairs;
|
private List<XElement> hairs;
|
||||||
@@ -720,10 +832,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (elements == null) { return elements; }
|
if (elements == null) { return elements; }
|
||||||
return elements.Where(w =>
|
return elements.Where(w =>
|
||||||
Enum.TryParse(w.GetAttributeString("gender", "None"), true, out Gender g) && g == gender &&
|
IsMatchingGender(Enum.Parse<Gender>(w.GetAttributeString("gender", "None"), ignoreCase: true), gender) &&
|
||||||
Enum.TryParse(w.GetAttributeString("race", "None"), true, out Race r) && r == race);
|
IsMatchingRace(Enum.Parse<Race>(w.GetAttributeString("race", "None"), ignoreCase: true), race));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsMatchingGender(Gender gender, Gender myGender) => gender == Gender.None || gender == myGender;
|
||||||
|
public static bool IsMatchingRace(Race race, Race myRace) => race == Race.None || race == myRace;
|
||||||
|
|
||||||
private void LoadHeadPresets()
|
private void LoadHeadPresets()
|
||||||
{
|
{
|
||||||
if (CharacterConfigElement == null) { return; }
|
if (CharacterConfigElement == null) { return; }
|
||||||
@@ -752,9 +867,16 @@ namespace Barotrauma
|
|||||||
// If there are any head presets defined, use them.
|
// If there are any head presets defined, use them.
|
||||||
if (heads.Any())
|
if (heads.Any())
|
||||||
{
|
{
|
||||||
var ids = heads.Keys.Where(h => h.Race == Race && h.Gender == Gender).Select(w => w.ID);
|
var ids = heads.Keys.Where(h => IsMatchingRace(Race, h.Race) && IsMatchingGender(Gender, h.Gender)).Select(w => w.ID);
|
||||||
ids = ids.OrderBy(id => id);
|
ids = ids.OrderBy(id => id);
|
||||||
Head.headSpriteRange = new Vector2(ids.First(), ids.Last());
|
if (ids.Any())
|
||||||
|
{
|
||||||
|
Head.headSpriteRange = new Vector2(ids.First(), ids.Last());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"[CharacterInfo] Couldn't find a head definition that matches {Race} and {Gender}!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Else we calculate the range from the wearables.
|
// Else we calculate the range from the wearables.
|
||||||
if (Head.headSpriteRange == Vector2.Zero)
|
if (Head.headSpriteRange == Vector2.Zero)
|
||||||
@@ -787,26 +909,72 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RecreateHead(HeadInfo headInfo)
|
||||||
|
{
|
||||||
|
RecreateHead(
|
||||||
|
headInfo.HeadSpriteId,
|
||||||
|
headInfo.race,
|
||||||
|
headInfo.gender,
|
||||||
|
headInfo.HairIndex,
|
||||||
|
headInfo.BeardIndex,
|
||||||
|
headInfo.MoustacheIndex,
|
||||||
|
headInfo.FaceAttachmentIndex);
|
||||||
|
|
||||||
|
SkinColor = headInfo.SkinColor;
|
||||||
|
HairColor = headInfo.HairColor;
|
||||||
|
FacialHairColor = headInfo.FacialHairColor;
|
||||||
|
CheckColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recreates the head info and checks that everything is valid.
|
||||||
|
/// </summary>
|
||||||
public void RecreateHead(int headID, Race race, Gender gender, int hairIndex, int beardIndex, int moustacheIndex, int faceAttachmentIndex)
|
public void RecreateHead(int headID, Race race, Gender gender, int hairIndex, int beardIndex, int moustacheIndex, int faceAttachmentIndex)
|
||||||
{
|
{
|
||||||
if (HasGenders && gender == Gender.None)
|
if (!IsValidGender(gender))
|
||||||
{
|
{
|
||||||
gender = GetRandomGender(Rand.RandSync.Unsynced);
|
gender = GetRandomGender(Rand.RandSync.Unsynced);
|
||||||
}
|
}
|
||||||
else if (!HasGenders)
|
if (!IsValidRace(race))
|
||||||
{
|
{
|
||||||
gender = Gender.None;
|
race = GetRandomRace(Rand.RandSync.Unsynced);
|
||||||
}
|
}
|
||||||
if (heads == null)
|
if (heads == null)
|
||||||
{
|
{
|
||||||
LoadHeadPresets();
|
LoadHeadPresets();
|
||||||
}
|
}
|
||||||
head = new HeadInfo(headID, gender, race, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
Color skin = Color.Black;
|
||||||
|
Color hair = Color.Black;
|
||||||
|
Color facialHair = Color.Black;
|
||||||
|
if (head != null)
|
||||||
|
{
|
||||||
|
skin = head.SkinColor;
|
||||||
|
hair = head.HairColor;
|
||||||
|
facialHair = head.FacialHairColor;
|
||||||
|
}
|
||||||
|
head = new HeadInfo(headID, gender, race, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex)
|
||||||
|
{
|
||||||
|
SkinColor = skin,
|
||||||
|
HairColor = hair,
|
||||||
|
FacialHairColor = facialHair
|
||||||
|
};
|
||||||
CalculateHeadSpriteRange();
|
CalculateHeadSpriteRange();
|
||||||
ReloadHeadAttachments();
|
ReloadHeadAttachments();
|
||||||
|
RefreshHead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadHeadSprite()
|
/// <summary>
|
||||||
|
/// Reloads the head sprite and the attachment sprites.
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshHead()
|
||||||
|
{
|
||||||
|
ReloadHeadAttachments();
|
||||||
|
RefreshHeadSprites();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void LoadHeadSpriteProjectSpecific(XElement limbElement);
|
||||||
|
|
||||||
|
private void LoadHeadSprite()
|
||||||
{
|
{
|
||||||
foreach (XElement limbElement in Ragdoll.MainElement.Elements())
|
foreach (XElement limbElement in Ragdoll.MainElement.Elements())
|
||||||
{
|
{
|
||||||
@@ -816,6 +984,7 @@ namespace Barotrauma
|
|||||||
if (spriteElement == null) { continue; }
|
if (spriteElement == null) { continue; }
|
||||||
|
|
||||||
string spritePath = spriteElement.Attribute("texture").Value;
|
string spritePath = spriteElement.Attribute("texture").Value;
|
||||||
|
if (string.IsNullOrEmpty(spritePath)) { continue; }
|
||||||
|
|
||||||
spritePath = spritePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
spritePath = spritePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male");
|
||||||
spritePath = spritePath.Replace("[RACE]", Head.race.ToString().ToLowerInvariant());
|
spritePath = spritePath.Replace("[RACE]", Head.race.ToString().ToLowerInvariant());
|
||||||
@@ -823,6 +992,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
string fileName = Path.GetFileNameWithoutExtension(spritePath);
|
string fileName = Path.GetFileNameWithoutExtension(spritePath);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(fileName)) { continue; }
|
||||||
|
|
||||||
//go through the files in the directory to find a matching sprite
|
//go through the files in the directory to find a matching sprite
|
||||||
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
|
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
|
||||||
{
|
{
|
||||||
@@ -847,13 +1018,12 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadHeadSpriteProjectSpecific(limbElement);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads only the elements according to the indices, not the sprites.
|
|
||||||
/// </summary>
|
|
||||||
public void LoadHeadAttachments()
|
public void LoadHeadAttachments()
|
||||||
{
|
{
|
||||||
if (Wearables != null)
|
if (Wearables != null)
|
||||||
@@ -1138,7 +1308,7 @@ namespace Barotrauma
|
|||||||
new XAttribute("name", Name),
|
new XAttribute("name", Name),
|
||||||
new XAttribute("originalname", OriginalName),
|
new XAttribute("originalname", OriginalName),
|
||||||
new XAttribute("speciesname", SpeciesName),
|
new XAttribute("speciesname", SpeciesName),
|
||||||
new XAttribute("gender", Head.gender == Gender.Male ? "male" : "female"),
|
new XAttribute("gender", Head.gender.ToString()),
|
||||||
new XAttribute("race", Head.race.ToString()),
|
new XAttribute("race", Head.race.ToString()),
|
||||||
new XAttribute("salary", Salary),
|
new XAttribute("salary", Salary),
|
||||||
new XAttribute("experiencepoints", ExperiencePoints),
|
new XAttribute("experiencepoints", ExperiencePoints),
|
||||||
@@ -1149,6 +1319,9 @@ namespace Barotrauma
|
|||||||
new XAttribute("beardindex", BeardIndex),
|
new XAttribute("beardindex", BeardIndex),
|
||||||
new XAttribute("moustacheindex", MoustacheIndex),
|
new XAttribute("moustacheindex", MoustacheIndex),
|
||||||
new XAttribute("faceattachmentindex", FaceAttachmentIndex),
|
new XAttribute("faceattachmentindex", FaceAttachmentIndex),
|
||||||
|
new XAttribute("skincolor", XMLExtensions.ColorToString(SkinColor)),
|
||||||
|
new XAttribute("haircolor", XMLExtensions.ColorToString(HairColor)),
|
||||||
|
new XAttribute("facialhaircolor", XMLExtensions.ColorToString(FacialHairColor)),
|
||||||
new XAttribute("startitemsgiven", StartItemsGiven),
|
new XAttribute("startitemsgiven", StartItemsGiven),
|
||||||
new XAttribute("ragdoll", ragdollFileName),
|
new XAttribute("ragdoll", ragdollFileName),
|
||||||
new XAttribute("personality", personalityTrait == null ? "" : personalityTrait.Name));
|
new XAttribute("personality", personalityTrait == null ? "" : personalityTrait.Name));
|
||||||
@@ -1462,13 +1635,19 @@ namespace Barotrauma
|
|||||||
if (healthData != null) { character?.CharacterHealth.Load(healthData); }
|
if (healthData != null) { character?.CharacterHealth.Load(healthData); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadHeadAttachments()
|
/// <summary>
|
||||||
|
/// Reloads the attachment xml elements according to the indices. Doesn't reload the sprites.
|
||||||
|
/// </summary>
|
||||||
|
private void ReloadHeadAttachments()
|
||||||
{
|
{
|
||||||
ResetLoadedAttachments();
|
ResetLoadedAttachments();
|
||||||
LoadHeadAttachments();
|
LoadHeadAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetHeadAttachments()
|
/// <summary>
|
||||||
|
/// Loads only the elements according to the indices, not the sprites.
|
||||||
|
/// </summary>
|
||||||
|
private void ResetHeadAttachments()
|
||||||
{
|
{
|
||||||
ResetAttachmentIndices();
|
ResetAttachmentIndices();
|
||||||
ResetLoadedAttachments();
|
ResetLoadedAttachments();
|
||||||
@@ -1500,6 +1679,12 @@ namespace Barotrauma
|
|||||||
AttachmentSprites = null;
|
AttachmentSprites = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RefreshHeadSprites()
|
||||||
|
{
|
||||||
|
HeadSprite = null;
|
||||||
|
AttachmentSprites = null;
|
||||||
|
}
|
||||||
|
|
||||||
// This could maybe be a LookUp instead?
|
// This could maybe be a LookUp instead?
|
||||||
private readonly Dictionary<StatTypes, List<SavedStatValue>> savedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
|
private readonly Dictionary<StatTypes, List<SavedStatValue>> savedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
|
||||||
|
|
||||||
@@ -1541,7 +1726,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue)
|
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue, bool setValue = false)
|
||||||
{
|
{
|
||||||
if (!savedStatValues.ContainsKey(statType))
|
if (!savedStatValues.ContainsKey(statType))
|
||||||
{
|
{
|
||||||
@@ -1550,7 +1735,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (savedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
|
if (savedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
|
||||||
{
|
{
|
||||||
savedStat.StatValue = MathHelper.Min(savedStat.StatValue + value, maxValue);
|
savedStat.StatValue = setValue ? value : MathHelper.Min(savedStat.StatValue + value, maxValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+14
@@ -628,6 +628,11 @@ namespace Barotrauma
|
|||||||
Description = TextManager.Get("AfflictionDescription." + translationId, true) ?? element.GetAttributeString("description", "");
|
Description = TextManager.Get("AfflictionDescription." + translationId, true) ?? element.GetAttributeString("description", "");
|
||||||
IsBuff = element.GetAttributeBool("isbuff", false);
|
IsBuff = element.GetAttributeBool("isbuff", false);
|
||||||
|
|
||||||
|
if (element.Attribute("nameidentifier") != null)
|
||||||
|
{
|
||||||
|
Name = TextManager.Get(element.GetAttributeString("nameidentifier", string.Empty), returnNull: true) ?? Name;
|
||||||
|
}
|
||||||
|
|
||||||
LimbSpecific = element.GetAttributeBool("limbspecific", false);
|
LimbSpecific = element.GetAttributeBool("limbspecific", false);
|
||||||
if (!LimbSpecific)
|
if (!LimbSpecific)
|
||||||
{
|
{
|
||||||
@@ -669,6 +674,15 @@ namespace Barotrauma
|
|||||||
case "afflictionoverlay":
|
case "afflictionoverlay":
|
||||||
AfflictionOverlay = new Sprite(subElement);
|
AfflictionOverlay = new Sprite(subElement);
|
||||||
break;
|
break;
|
||||||
|
case "statvalue":
|
||||||
|
DebugConsole.ThrowError($"Error in affliction \"{Identifier}\" - stat values should be configured inside the affliction's effects.");
|
||||||
|
break;
|
||||||
|
case "effect":
|
||||||
|
case "periodiceffect":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DebugConsole.AddWarning($"Unrecognized element in affliction \"{Identifier}\" ({subElement.Name})");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -979,7 +979,7 @@ namespace Barotrauma
|
|||||||
float minSuitability = -10, maxSuitability = 10;
|
float minSuitability = -10, maxSuitability = 10;
|
||||||
foreach (Affliction affliction in getAfflictions(limb))
|
foreach (Affliction affliction in getAfflictions(limb))
|
||||||
{
|
{
|
||||||
if (affliction.Strength < affliction.Prefab.TreatmentThreshold) { continue; }
|
if (affliction.Strength <= affliction.Prefab.TreatmentThreshold) { continue; }
|
||||||
if (ignoreHiddenAfflictions && affliction.Strength < affliction.Prefab.ShowIconThreshold) { continue; }
|
if (ignoreHiddenAfflictions && affliction.Strength < affliction.Prefab.ShowIconThreshold) { continue; }
|
||||||
foreach (KeyValuePair<string, float> treatment in affliction.Prefab.TreatmentSuitability)
|
foreach (KeyValuePair<string, float> treatment in affliction.Prefab.TreatmentSuitability)
|
||||||
{
|
{
|
||||||
@@ -1088,7 +1088,7 @@ namespace Barotrauma
|
|||||||
/// Automatically filters out buffs.
|
/// Automatically filters out buffs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<Affliction> SortAfflictionsBySeverity(IEnumerable<Affliction> afflictions, bool excludeBuffs = true) =>
|
public static IEnumerable<Affliction> SortAfflictionsBySeverity(IEnumerable<Affliction> afflictions, bool excludeBuffs = true) =>
|
||||||
afflictions.Where(a => !excludeBuffs || !a.Prefab.IsBuff).OrderByDescending(a => a.DamagePerSecond).ThenByDescending(a => a.Strength);
|
afflictions.Where(a => !excludeBuffs || !a.Prefab.IsBuff).OrderByDescending(a => a.DamagePerSecond).ThenByDescending(a => a.Strength / a.Prefab.MaxStrength);
|
||||||
|
|
||||||
public void Save(XElement healthElement)
|
public void Save(XElement healthElement)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -275,7 +275,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Skills.Sort((x,y) => y.LevelRange.X.CompareTo(x.LevelRange.X));
|
Skills.Sort((x,y) => y.LevelRange.X.CompareTo(x.LevelRange.X));
|
||||||
|
|
||||||
ClothingElement = element.GetChildElement("PortraitClothing");
|
// Disabled on purpose, TODO: remove all references?
|
||||||
|
//ClothingElement = element.GetChildElement("PortraitClothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (attacker != null)
|
if (attacker != null)
|
||||||
{
|
{
|
||||||
var abilityAffliction = new AbilityAffliction(newAffliction);
|
var abilityAffliction = new AbilityAfflictionCharacter(newAffliction, character);
|
||||||
attacker.CheckTalents(AbilityEffectType.OnAddDamageAffliction, abilityAffliction);
|
attacker.CheckTalents(AbilityEffectType.OnAddDamageAffliction, abilityAffliction);
|
||||||
}
|
}
|
||||||
if (applyAffliction)
|
if (applyAffliction)
|
||||||
|
|||||||
+17
-1
@@ -14,6 +14,7 @@ namespace Barotrauma
|
|||||||
NotDefined,
|
NotDefined,
|
||||||
Walk,
|
Walk,
|
||||||
Run,
|
Run,
|
||||||
|
Crouch,
|
||||||
SwimSlow,
|
SwimSlow,
|
||||||
SwimFast
|
SwimFast
|
||||||
}
|
}
|
||||||
@@ -56,12 +57,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
[Serialize(25.0f, true, description: "Turning speed (or rather a force applied on the main collider to make it turn). Note that you can set a limb-specific steering forces too (additional)."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
[Serialize(25.0f, true, description: "Turning speed (or rather a force applied on the main collider to make it turn). Note that you can set a limb-specific steering forces too (additional)."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
public float SteerTorque { get; set; }
|
public float SteerTorque { get; set; }
|
||||||
|
|
||||||
|
[Serialize(25.0f, true, description: "How much torque is used to move the legs."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
|
public float LegTorque { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AnimationParams : EditableParams, IMemorizable<AnimationParams>
|
abstract class AnimationParams : EditableParams, IMemorizable<AnimationParams>
|
||||||
{
|
{
|
||||||
public string SpeciesName { get; private set; }
|
public string SpeciesName { get; private set; }
|
||||||
public bool IsGroundedAnimation => AnimationType == AnimationType.Walk || AnimationType == AnimationType.Run;
|
public bool IsGroundedAnimation => AnimationType == AnimationType.Walk || AnimationType == AnimationType.Run || AnimationType == AnimationType.Crouch;
|
||||||
public bool IsSwimAnimation => AnimationType == AnimationType.SwimSlow || AnimationType == AnimationType.SwimFast;
|
public bool IsSwimAnimation => AnimationType == AnimationType.SwimSlow || AnimationType == AnimationType.SwimFast;
|
||||||
|
|
||||||
protected static Dictionary<string, Dictionary<string, AnimationParams>> allAnimations = new Dictionary<string, Dictionary<string, AnimationParams>>();
|
protected static Dictionary<string, Dictionary<string, AnimationParams>> allAnimations = new Dictionary<string, Dictionary<string, AnimationParams>>();
|
||||||
@@ -110,8 +114,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float TorsoAngleInRadians { get; private set; } = float.NaN;
|
public float TorsoAngleInRadians { get; private set; } = float.NaN;
|
||||||
|
|
||||||
|
[Serialize(50.0f, true, description: "How much torque is used to rotate the head to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
|
public float HeadTorque { get; set; }
|
||||||
|
|
||||||
|
[Serialize(50.0f, true, description: "How much torque is used to rotate the torso to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
|
public float TorsoTorque { get; set; }
|
||||||
|
|
||||||
|
[Serialize(25.0f, true, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
|
public float FootTorque { get; set; }
|
||||||
|
|
||||||
[Serialize(AnimationType.NotDefined, true), Editable]
|
[Serialize(AnimationType.NotDefined, true), Editable]
|
||||||
public virtual AnimationType AnimationType { get; protected set; }
|
public virtual AnimationType AnimationType { get; protected set; }
|
||||||
|
|
||||||
@@ -402,6 +416,8 @@ namespace Barotrauma
|
|||||||
return typeof(HumanWalkParams);
|
return typeof(HumanWalkParams);
|
||||||
case AnimationType.Run:
|
case AnimationType.Run:
|
||||||
return typeof(HumanRunParams);
|
return typeof(HumanRunParams);
|
||||||
|
case AnimationType.Crouch:
|
||||||
|
return typeof(HumanCrouchParams);
|
||||||
case AnimationType.SwimSlow:
|
case AnimationType.SwimSlow:
|
||||||
return typeof(HumanSwimSlowParams);
|
return typeof(HumanSwimSlowParams);
|
||||||
case AnimationType.SwimFast:
|
case AnimationType.SwimFast:
|
||||||
|
|||||||
-20
@@ -87,18 +87,9 @@ namespace Barotrauma
|
|||||||
[Serialize(8.0f, true, description: "How much force is used to move the feet to the correct position."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
[Serialize(8.0f, true, description: "How much force is used to move the feet to the correct position."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||||
public float FootMoveForce { get; set; }
|
public float FootMoveForce { get; set; }
|
||||||
|
|
||||||
[Serialize(50.0f, true, description: "How much torque is used to rotate the head to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
|
||||||
public float HeadTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(50.0f, true, description: "How much torque is used to rotate the torso to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
|
||||||
public float TorsoTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(50.0f, true, description: "How much torque is used to rotate the tail to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
[Serialize(50.0f, true, description: "How much torque is used to rotate the tail to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
||||||
public float TailTorque { get; set; }
|
public float TailTorque { get; set; }
|
||||||
|
|
||||||
[Serialize(25.0f, true, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
|
||||||
public float FootTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(0.0f, true, description: "Optional torque that's constantly applied to legs."), Editable(MinValueFloat = 0, MaxValueFloat = 1000)]
|
[Serialize(0.0f, true, description: "Optional torque that's constantly applied to legs."), Editable(MinValueFloat = 0, MaxValueFloat = 1000)]
|
||||||
public float LegTorque { get; set; }
|
public float LegTorque { get; set; }
|
||||||
|
|
||||||
@@ -173,20 +164,12 @@ namespace Barotrauma
|
|||||||
[Editable, Serialize(true, true, description: "Should the character face towards the direction it's heading.")]
|
[Editable, Serialize(true, true, description: "Should the character face towards the direction it's heading.")]
|
||||||
public bool RotateTowardsMovement { get; set; }
|
public bool RotateTowardsMovement { get; set; }
|
||||||
|
|
||||||
[Serialize(25.0f, true, description: "How much torque is used to rotate the torso to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 2000, ValueStep = 1)]
|
|
||||||
public float TorsoTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(25.0f, true, description: "How much torque is used to rotate the head to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 2000, ValueStep = 1)]
|
|
||||||
public float HeadTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(50.0f, true, description: "How much torque is used to rotate the tail to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 2000, ValueStep = 1)]
|
[Serialize(50.0f, true, description: "How much torque is used to rotate the tail to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 2000, ValueStep = 1)]
|
||||||
public float TailTorque { get; set; }
|
public float TailTorque { get; set; }
|
||||||
|
|
||||||
[Serialize(1f, true, description: "Multiplier applied based on the angle difference between the tail and the main limb. Increasing the value prevents snake-like characters from getting tangled on themselves. Default = 1 (no boost)"), Editable(MinValueFloat = 1, MaxValueFloat = 100)]
|
[Serialize(1f, true, description: "Multiplier applied based on the angle difference between the tail and the main limb. Increasing the value prevents snake-like characters from getting tangled on themselves. Default = 1 (no boost)"), Editable(MinValueFloat = 1, MaxValueFloat = 100)]
|
||||||
public float TailTorqueMultiplier { get; set; }
|
public float TailTorqueMultiplier { get; set; }
|
||||||
|
|
||||||
[Serialize(25.0f, true, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
|
|
||||||
public float FootTorque { get; set; }
|
|
||||||
|
|
||||||
[Serialize(null, true), Editable]
|
[Serialize(null, true), Editable]
|
||||||
public string FootAngles
|
public string FootAngles
|
||||||
@@ -224,10 +207,7 @@ namespace Barotrauma
|
|||||||
Dictionary<int, float> FootAnglesInRadians { get; set; }
|
Dictionary<int, float> FootAnglesInRadians { get; set; }
|
||||||
float TailAngle { get; set; }
|
float TailAngle { get; set; }
|
||||||
float TailAngleInRadians { get; }
|
float TailAngleInRadians { get; }
|
||||||
float HeadTorque { get; set; }
|
|
||||||
float TorsoTorque { get; set; }
|
|
||||||
float TailTorque { get; set; }
|
float TailTorque { get; set; }
|
||||||
float FootTorque { get; set; }
|
|
||||||
bool Flip { get; set; }
|
bool Flip { get; set; }
|
||||||
float FlipCooldown { get; set; }
|
float FlipCooldown { get; set; }
|
||||||
float FlipDelay { get; set; }
|
float FlipDelay { get; set; }
|
||||||
|
|||||||
+45
-37
@@ -24,6 +24,17 @@ namespace Barotrauma
|
|||||||
public override void StoreSnapshot() => StoreSnapshot<HumanRunParams>();
|
public override void StoreSnapshot() => StoreSnapshot<HumanRunParams>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HumanCrouchParams : HumanGroundedParams
|
||||||
|
{
|
||||||
|
public static HumanCrouchParams GetDefaultAnimParams(Character character) => GetDefaultAnimParams<HumanCrouchParams>(character, AnimationType.Crouch);
|
||||||
|
public static HumanCrouchParams GetAnimParams(Character character, string fileName = null)
|
||||||
|
{
|
||||||
|
return GetAnimParams<HumanCrouchParams>(character.SpeciesName, AnimationType.Crouch, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void StoreSnapshot() => StoreSnapshot<HumanCrouchParams>();
|
||||||
|
}
|
||||||
|
|
||||||
class HumanSwimFastParams: HumanSwimParams
|
class HumanSwimFastParams: HumanSwimParams
|
||||||
{
|
{
|
||||||
public static HumanSwimFastParams GetDefaultAnimParams(Character character) => GetDefaultAnimParams<HumanSwimFastParams>(character, AnimationType.SwimFast);
|
public static HumanSwimFastParams GetDefaultAnimParams(Character character) => GetDefaultAnimParams<HumanSwimFastParams>(character, AnimationType.SwimFast);
|
||||||
@@ -58,9 +69,6 @@ namespace Barotrauma
|
|||||||
[Serialize("0.5, 0.1", true), Editable(DecimalCount = 2)]
|
[Serialize("0.5, 0.1", true), Editable(DecimalCount = 2)]
|
||||||
public Vector2 HandMoveAmount { get; set; }
|
public Vector2 HandMoveAmount { get; set; }
|
||||||
|
|
||||||
[Serialize(0.5f, true), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
|
||||||
public float HandMoveStrength { get; set; }
|
|
||||||
|
|
||||||
[Serialize(5.0f, true), Editable]
|
[Serialize(5.0f, true), Editable]
|
||||||
public float HandCycleSpeed { get; set; }
|
public float HandCycleSpeed { get; set; }
|
||||||
|
|
||||||
@@ -81,36 +89,23 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
public float FootAngleInRadians { get; private set; }
|
public float FootAngleInRadians { get; private set; }
|
||||||
|
|
||||||
[Serialize(25.0f, true, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
[Serialize(1f, true, description: "How much force is used to move the arms."), Editable(MinValueFloat = 0, MaxValueFloat = 20, DecimalCount = 2)]
|
||||||
public float FootRotateStrength { get; set; }
|
public float ArmMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to rotate the arms to the IK position."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float ArmIKStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to rotate the hands to the IK position."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float HandIKStrength { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class HumanGroundedParams : GroundedMovementParams, IHumanAnimation
|
abstract class HumanGroundedParams : GroundedMovementParams, IHumanAnimation
|
||||||
{
|
{
|
||||||
[Serialize(0.3f, true, description: "How much force is used to force the character upright."), Editable(MinValueFloat = 0, MaxValueFloat = 1, DecimalCount = 2)]
|
[Serialize(0.3f, true, description: "How much force is used to force the character upright."), Editable(MinValueFloat = 0, MaxValueFloat = 1, DecimalCount = 2)]
|
||||||
public float GetUpForce { get; set; }
|
public float GetUpForce { get; set; }
|
||||||
|
|
||||||
// -- TODO: use a separate clip for crawling -> replace these when implemented.
|
|
||||||
|
|
||||||
[Serialize(0.65f, true, description: "Height of the torso when crouching."), Editable(MinValueFloat = 0, MaxValueFloat = 5, DecimalCount = 2)]
|
|
||||||
public float CrouchingTorsoPos { get; set; }
|
|
||||||
|
|
||||||
[Serialize(0.65f, true, description: "Height of the head when crouching."), Editable(MinValueFloat = 0, MaxValueFloat = 5, DecimalCount = 2)]
|
|
||||||
public float CrouchingHeadPos { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// In degrees
|
|
||||||
/// </summary>
|
|
||||||
[Serialize(-10f, true, description: "Angle of the torso when crouching."), Editable(MinValueFloat = -360, MaxValueFloat = 360)]
|
|
||||||
public float CrouchingTorsoAngle { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// In degrees
|
|
||||||
/// </summary>
|
|
||||||
[Serialize(-10f, true, description: "Angle of the head when crouching."), Editable(MinValueFloat = -360, MaxValueFloat = 360)]
|
|
||||||
public float CrouchingHeadAngle { get; set; }
|
|
||||||
|
|
||||||
// --
|
|
||||||
|
|
||||||
[Serialize(0.25f, true, description: "How much the character's head leans forwards when moving."), Editable(DecimalCount = 2)]
|
[Serialize(0.25f, true, description: "How much the character's head leans forwards when moving."), Editable(DecimalCount = 2)]
|
||||||
public float HeadLeanAmount { get; set; }
|
public float HeadLeanAmount { get; set; }
|
||||||
@@ -121,6 +116,9 @@ namespace Barotrauma
|
|||||||
[Serialize(15.0f, true, description: "How much force is used to move the feet to the correct position."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
[Serialize(15.0f, true, description: "How much force is used to move the feet to the correct position."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||||
public float FootMoveStrength { get; set; }
|
public float FootMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(0f, true, description: "How much the horizontal difference of waist and the foot positions has an effect to lifting the foot."), Editable(DecimalCount = 2, ValueStep = 0.1f, MinValueFloat = 0f, MaxValueFloat = 1f)]
|
||||||
|
public float FootLiftHorizontalFactor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In degrees.
|
/// In degrees.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -135,15 +133,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
public float FootAngleInRadians { get; private set; }
|
public float FootAngleInRadians { get; private set; }
|
||||||
|
|
||||||
[Serialize(20.0f, true, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
|
||||||
public float FootRotateStrength { get; set; }
|
|
||||||
|
|
||||||
[Serialize("0.0, 0.0", true, description: "Added to the calculated foot positions, e.g. a value of {-1.0, 0.0f} would make the character \"drag\" their feet one unit behind them."), Editable(DecimalCount = 2)]
|
[Serialize("0.0, 0.0", true, description: "Added to the calculated foot positions, e.g. a value of {-1.0, 0.0f} would make the character \"drag\" their feet one unit behind them."), Editable(DecimalCount = 2)]
|
||||||
public Vector2 FootMoveOffset { get; set; }
|
public Vector2 FootMoveOffset { get; set; }
|
||||||
|
|
||||||
[Serialize("0.0, 0.0", true, description: "Added to the calculated foot positions, e.g. a value of {-1.0, 0.0f} would make the character \"drag\" their feet one unit behind them."), Editable(DecimalCount = 2)]
|
|
||||||
public Vector2 CrouchingFootMoveOffset { get; set; }
|
|
||||||
|
|
||||||
[Serialize(10.0f, true, description: "How much torque is used to bend the characters legs when taking a step."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
[Serialize(10.0f, true, description: "How much torque is used to bend the characters legs when taking a step."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||||
public float LegBendTorque { get; set; }
|
public float LegBendTorque { get; set; }
|
||||||
|
|
||||||
@@ -153,17 +145,33 @@ namespace Barotrauma
|
|||||||
[Serialize("-0.15, 0.0", true, description: "Added to the calculated hand positions, e.g. a value of {-1.0, 0.0f} would make the character \"drag\" their hands one unit behind them."), Editable(DecimalCount = 2)]
|
[Serialize("-0.15, 0.0", true, description: "Added to the calculated hand positions, e.g. a value of {-1.0, 0.0f} would make the character \"drag\" their hands one unit behind them."), Editable(DecimalCount = 2)]
|
||||||
public Vector2 HandMoveOffset { get; set; }
|
public Vector2 HandMoveOffset { get; set; }
|
||||||
|
|
||||||
[Serialize(0.7f, true, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 2, DecimalCount = 2)]
|
|
||||||
public float HandMoveStrength { get; set; }
|
|
||||||
|
|
||||||
[Serialize(-1.0f, true, description: "The position of the hands is clamped below this (relative to the position of the character's torso)."), Editable(DecimalCount = 2)]
|
[Serialize(-1.0f, true, description: "The position of the hands is clamped below this (relative to the position of the character's torso)."), Editable(DecimalCount = 2)]
|
||||||
public float HandClampY { get; set; }
|
public float HandClampY { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to move the arms."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float ArmMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to rotate the arms to the IK position."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float ArmIKStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(1f, true, description: "How much force is used to rotate the hands to the IK position."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
|
public float HandIKStrength { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHumanAnimation
|
public interface IHumanAnimation
|
||||||
{
|
{
|
||||||
float FootAngle { get; set; }
|
float FootAngle { get; set; }
|
||||||
float FootAngleInRadians { get; }
|
float FootAngleInRadians { get; }
|
||||||
float FootRotateStrength { get; set; }
|
|
||||||
|
float ArmMoveStrength { get; set; }
|
||||||
|
|
||||||
|
float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
float ArmIKStrength { get; set; }
|
||||||
|
|
||||||
|
float HandIKStrength { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ namespace Barotrauma
|
|||||||
[Serialize("", true, description: "Default path for the limb sprite textures. Used only if the limb specific path for the limb is not defined"), Editable]
|
[Serialize("", true, description: "Default path for the limb sprite textures. Used only if the limb specific path for the limb is not defined"), Editable]
|
||||||
public string Texture { get; set; }
|
public string Texture { get; set; }
|
||||||
|
|
||||||
|
[Serialize("1.0,1.0,1.0,1.0", true), Editable()]
|
||||||
|
public Color Color { get; set; }
|
||||||
|
|
||||||
[Serialize(0.0f, true, description: "The orientation of the sprites as drawn on the sprite sheet. Can be overridden by setting a value for Limb's 'Sprite Orientation'. Used mainly for animations and widgets."), Editable(-360, 360)]
|
[Serialize(0.0f, true, description: "The orientation of the sprites as drawn on the sprite sheet. Can be overridden by setting a value for Limb's 'Sprite Orientation'. Used mainly for animations and widgets."), Editable(-360, 360)]
|
||||||
public float SpritesheetOrientation { get; set; }
|
public float SpritesheetOrientation { get; set; }
|
||||||
|
|
||||||
@@ -556,7 +559,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GenerateName() => $"Limb {ID}";
|
public override string GenerateName() => Type != LimbType.None ? $"{Type} ({ID})" : $"Limb {ID}";
|
||||||
|
|
||||||
public SpriteParams GetSprite() => deformSpriteParams ?? normalSpriteParams;
|
public SpriteParams GetSprite() => deformSpriteParams ?? normalSpriteParams;
|
||||||
|
|
||||||
@@ -574,7 +577,7 @@ namespace Barotrauma
|
|||||||
[Serialize("", true), Editable]
|
[Serialize("", true), Editable]
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
|
||||||
[Serialize(1f, true), Editable]
|
[Serialize(1f, true), Editable(DecimalCount = 2)]
|
||||||
public float Scale { get; set; }
|
public float Scale { get; set; }
|
||||||
|
|
||||||
[Serialize(true, true, description: "Does the limb flip when the character flips?"), Editable()]
|
[Serialize(true, true, description: "Does the limb flip when the character flips?"), Editable()]
|
||||||
@@ -889,6 +892,9 @@ namespace Barotrauma
|
|||||||
[Serialize("", true), Editable()]
|
[Serialize("", true), Editable()]
|
||||||
public string Texture { get; set; }
|
public string Texture { get; set; }
|
||||||
|
|
||||||
|
[Serialize(false, true), Editable()]
|
||||||
|
public bool IgnoreTint { get; set; }
|
||||||
|
|
||||||
[Serialize("1.0,1.0,1.0,1.0", true), Editable()]
|
[Serialize("1.0,1.0,1.0,1.0", true), Editable()]
|
||||||
public Color Color { get; set; }
|
public Color Color { get; set; }
|
||||||
|
|
||||||
|
|||||||
+3
@@ -33,6 +33,7 @@ namespace Barotrauma.Abilities
|
|||||||
NotSelf = 3,
|
NotSelf = 3,
|
||||||
Alive = 4,
|
Alive = 4,
|
||||||
Monster = 5,
|
Monster = 5,
|
||||||
|
InFriendlySubmarine = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
protected List<TargetType> ParseTargetTypes(string[] targetTypeStrings)
|
protected List<TargetType> ParseTargetTypes(string[] targetTypeStrings)
|
||||||
@@ -80,6 +81,8 @@ namespace Barotrauma.Abilities
|
|||||||
return !targetCharacter.IsDead;
|
return !targetCharacter.IsDead;
|
||||||
case TargetType.Monster:
|
case TargetType.Monster:
|
||||||
return !targetCharacter.IsHuman;
|
return !targetCharacter.IsHuman;
|
||||||
|
case TargetType.InFriendlySubmarine:
|
||||||
|
return targetCharacter.Submarine != null && targetCharacter.Submarine.TeamID == character.TeamID;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
using Barotrauma.Items.Components;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Abilities
|
||||||
|
{
|
||||||
|
class AbilityConditionAffliction : AbilityConditionData
|
||||||
|
{
|
||||||
|
private readonly string[] afflictions;
|
||||||
|
public AbilityConditionAffliction(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||||
|
{
|
||||||
|
afflictions = conditionElement.GetAttributeStringArray("afflictions", new string[0], convertToLowerInvariant: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MatchesConditionSpecific(AbilityObject abilityObject)
|
||||||
|
{
|
||||||
|
if ((abilityObject as IAbilityAffliction)?.Affliction is Affliction affliction)
|
||||||
|
{
|
||||||
|
return afflictions.Any(a => a == affliction.Identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogAbilityConditionError(abilityObject, typeof(IAbilityAttackResult));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Abilities
|
||||||
|
{
|
||||||
|
class AbilityConditionLocation : AbilityConditionData
|
||||||
|
{
|
||||||
|
private readonly bool? hasOutpost;
|
||||||
|
private readonly string[] locationIdentifiers;
|
||||||
|
|
||||||
|
public AbilityConditionLocation(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||||
|
{
|
||||||
|
if (conditionElement.Attribute("hasoutpost") != null)
|
||||||
|
{
|
||||||
|
hasOutpost = conditionElement.GetAttributeBool("hasoutpost", false);
|
||||||
|
}
|
||||||
|
locationIdentifiers = conditionElement.GetAttributeStringArray("locationtype", new string[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MatchesConditionSpecific(AbilityObject abilityObject)
|
||||||
|
{
|
||||||
|
if (abilityObject is IAbilityLocation abilityLocation)
|
||||||
|
{
|
||||||
|
if (locationIdentifiers.Any())
|
||||||
|
{
|
||||||
|
if (!locationIdentifiers.Contains(abilityLocation.Location.Type.Identifier)) { return false; }
|
||||||
|
}
|
||||||
|
if (hasOutpost.HasValue)
|
||||||
|
{
|
||||||
|
if (hasOutpost.Value != abilityLocation.Location.HasOutpost()) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogAbilityConditionError(abilityObject, typeof(IAbilityItemPrefab));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -20,6 +20,11 @@
|
|||||||
public Mission Mission { get; set; }
|
public Mission Mission { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IAbilityLocation
|
||||||
|
{
|
||||||
|
public Location Location { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
interface IAbilityCharacter
|
interface IAbilityCharacter
|
||||||
{
|
{
|
||||||
public Character Character { get; set; }
|
public Character Character { get; set; }
|
||||||
|
|||||||
+33
-1
@@ -43,6 +43,17 @@ namespace Barotrauma.Abilities
|
|||||||
public Affliction Affliction { get; set; }
|
public Affliction Affliction { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AbilityAfflictionCharacter : AbilityObject, IAbilityAffliction, IAbilityCharacter
|
||||||
|
{
|
||||||
|
public AbilityAfflictionCharacter(Affliction affliction, Character character)
|
||||||
|
{
|
||||||
|
Affliction = affliction;
|
||||||
|
Character = character;
|
||||||
|
}
|
||||||
|
public Character Character { get; set; }
|
||||||
|
public Affliction Affliction { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
class AbilityValueItem : AbilityObject, IAbilityValue, IAbilityItemPrefab
|
class AbilityValueItem : AbilityObject, IAbilityValue, IAbilityItemPrefab
|
||||||
{
|
{
|
||||||
public AbilityValueItem(float value, ItemPrefab itemPrefab)
|
public AbilityValueItem(float value, ItemPrefab itemPrefab)
|
||||||
@@ -54,6 +65,17 @@ namespace Barotrauma.Abilities
|
|||||||
public ItemPrefab ItemPrefab { get; set; }
|
public ItemPrefab ItemPrefab { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AbilityItemPrefabItem : AbilityObject, IAbilityItem, IAbilityItemPrefab
|
||||||
|
{
|
||||||
|
public AbilityItemPrefabItem(Item item, ItemPrefab itemPrefab)
|
||||||
|
{
|
||||||
|
Item = item;
|
||||||
|
ItemPrefab = itemPrefab;
|
||||||
|
}
|
||||||
|
public Item Item { get; set; }
|
||||||
|
public ItemPrefab ItemPrefab { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
class AbilityValueString : AbilityObject, IAbilityValue, IAbilityString
|
class AbilityValueString : AbilityObject, IAbilityValue, IAbilityString
|
||||||
{
|
{
|
||||||
public AbilityValueString(float value, string abilityString)
|
public AbilityValueString(float value, string abilityString)
|
||||||
@@ -65,7 +87,7 @@ namespace Barotrauma.Abilities
|
|||||||
public string String { get; set; }
|
public string String { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AbilityValueStringCharacter : AbilityObject, IAbilityValue, IAbilityString
|
class AbilityValueStringCharacter : AbilityObject, IAbilityValue, IAbilityString, IAbilityCharacter
|
||||||
{
|
{
|
||||||
public AbilityValueStringCharacter(float value, string abilityString, Character character)
|
public AbilityValueStringCharacter(float value, string abilityString, Character character)
|
||||||
{
|
{
|
||||||
@@ -111,6 +133,16 @@ namespace Barotrauma.Abilities
|
|||||||
public Mission Mission { get; set; }
|
public Mission Mission { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AbilityLocation : AbilityObject, IAbilityLocation
|
||||||
|
{
|
||||||
|
public AbilityLocation(Location location)
|
||||||
|
{
|
||||||
|
Location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location Location { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
// this is an exception class that should only be passed in this form, so classes that use it should cast into it directly
|
// this is an exception class that should only be passed in this form, so classes that use it should cast into it directly
|
||||||
class AbilityAttackData : AbilityObject, IAbilityCharacter
|
class AbilityAttackData : AbilityObject, IAbilityCharacter
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,4 @@
|
|||||||
using Barotrauma.Extensions;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
@@ -9,10 +8,12 @@ namespace Barotrauma.Abilities
|
|||||||
class CharacterAbilityApplyStatusEffectsToAllies : CharacterAbilityApplyStatusEffects
|
class CharacterAbilityApplyStatusEffectsToAllies : CharacterAbilityApplyStatusEffects
|
||||||
{
|
{
|
||||||
private readonly bool allowSelf;
|
private readonly bool allowSelf;
|
||||||
|
private readonly float maxDistance = float.MaxValue;
|
||||||
|
|
||||||
public CharacterAbilityApplyStatusEffectsToAllies(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityApplyStatusEffectsToAllies(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
allowSelf = abilityElement.GetAttributeBool("allowself", true);
|
allowSelf = abilityElement.GetAttributeBool("allowself", true);
|
||||||
|
maxDistance = abilityElement.GetAttributeFloat("maxdistance", float.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +23,10 @@ namespace Barotrauma.Abilities
|
|||||||
|
|
||||||
foreach (Character character in chosenCharacters)
|
foreach (Character character in chosenCharacters)
|
||||||
{
|
{
|
||||||
|
if (maxDistance < float.MaxValue)
|
||||||
|
{
|
||||||
|
if (Vector2.DistanceSquared(character.WorldPosition, Character.WorldPosition) > maxDistance * maxDistance) { continue; }
|
||||||
|
}
|
||||||
ApplyEffectSpecific(character);
|
ApplyEffectSpecific(character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using System.Xml.Linq;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma.Abilities
|
namespace Barotrauma.Abilities
|
||||||
{
|
{
|
||||||
@@ -8,7 +7,7 @@ namespace Barotrauma.Abilities
|
|||||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||||
|
|
||||||
private readonly int amount;
|
private readonly int amount;
|
||||||
private StatTypes scalingStatType;
|
private readonly StatTypes scalingStatType;
|
||||||
|
|
||||||
public CharacterAbilityGiveMoney(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityGiveMoney(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-2
@@ -13,6 +13,7 @@ namespace Barotrauma.Abilities
|
|||||||
private readonly bool removeOnDeath;
|
private readonly bool removeOnDeath;
|
||||||
private readonly bool removeAfterRound;
|
private readonly bool removeAfterRound;
|
||||||
private readonly bool giveOnAddingFirstTime;
|
private readonly bool giveOnAddingFirstTime;
|
||||||
|
private readonly bool setValue;
|
||||||
|
|
||||||
//private readonly float maximumValue;
|
//private readonly float maximumValue;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ namespace Barotrauma.Abilities
|
|||||||
removeOnDeath = abilityElement.GetAttributeBool("removeondeath", true);
|
removeOnDeath = abilityElement.GetAttributeBool("removeondeath", true);
|
||||||
removeAfterRound = abilityElement.GetAttributeBool("removeafterround", false);
|
removeAfterRound = abilityElement.GetAttributeBool("removeafterround", false);
|
||||||
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", characterAbilityGroup.AbilityEffectType == AbilityEffectType.None);
|
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", characterAbilityGroup.AbilityEffectType == AbilityEffectType.None);
|
||||||
|
setValue = abilityElement.GetAttributeBool("setvalue", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void InitializeAbility(bool addingFirstTime)
|
public override void InitializeAbility(bool addingFirstTime)
|
||||||
@@ -52,11 +54,11 @@ namespace Barotrauma.Abilities
|
|||||||
{
|
{
|
||||||
if (targetAllies)
|
if (targetAllies)
|
||||||
{
|
{
|
||||||
Character.GetFriendlyCrew(Character).ForEach(c => c?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue));
|
Character.GetFriendlyCrew(Character).ForEach(c => c?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue, setValue));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Character?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue);
|
Character?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue, setValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma.Abilities
|
|||||||
|
|
||||||
public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
resistanceId = abilityElement.GetAttributeString("resistanceid", "");
|
resistanceId = abilityElement.GetAttributeString("resistanceid", abilityElement.GetAttributeString("resistance", string.Empty));
|
||||||
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
|
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(resistanceId))
|
if (string.IsNullOrEmpty(resistanceId))
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Abilities
|
||||||
|
{
|
||||||
|
class CharacterAbilityModifyStatToLevel : CharacterAbility
|
||||||
|
{
|
||||||
|
private readonly StatTypes statType;
|
||||||
|
private readonly float statPerLevel;
|
||||||
|
private readonly int maxLevel;
|
||||||
|
private float lastValue = 0f;
|
||||||
|
|
||||||
|
public CharacterAbilityModifyStatToLevel(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
|
{
|
||||||
|
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||||
|
statPerLevel = abilityElement.GetAttributeFloat("statperlevel", 0f);
|
||||||
|
maxLevel = abilityElement.GetAttributeInt("maxlevel", int.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
|
||||||
|
{
|
||||||
|
Character.ChangeStat(statType, -lastValue);
|
||||||
|
if (conditionsMatched)
|
||||||
|
{
|
||||||
|
int level = MathHelper.Min(Character?.Info.GetCurrentLevel() ?? 0, maxLevel);
|
||||||
|
lastValue = statPerLevel * level;
|
||||||
|
Character.ChangeStat(statType, lastValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastValue = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-2
@@ -10,19 +10,24 @@ namespace Barotrauma.Abilities
|
|||||||
private readonly List<StatusEffect> statusEffects;
|
private readonly List<StatusEffect> statusEffects;
|
||||||
private readonly List<Item> openedContainers = new List<Item>();
|
private readonly List<Item> openedContainers = new List<Item>();
|
||||||
private readonly float randomChance;
|
private readonly float randomChance;
|
||||||
|
private readonly bool oncePerContainer;
|
||||||
|
|
||||||
public CharacterAbilitySpawnItemsToContainer(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilitySpawnItemsToContainer(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||||
randomChance = abilityElement.GetAttributeFloat("randomchance", 1f);
|
randomChance = abilityElement.GetAttributeFloat("randomchance", 1f);
|
||||||
|
oncePerContainer = abilityElement.GetAttributeBool("oncepercontainer", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||||
{
|
{
|
||||||
if ((abilityObject as IAbilityItem)?.Item is Item item)
|
if ((abilityObject as IAbilityItem)?.Item is Item item)
|
||||||
{
|
{
|
||||||
if (openedContainers.Contains(item)) { return; }
|
if (oncePerContainer)
|
||||||
openedContainers.Add(item);
|
{
|
||||||
|
if (openedContainers.Contains(item)) { return; }
|
||||||
|
openedContainers.Add(item);
|
||||||
|
}
|
||||||
if (randomChance < Rand.Range(0f, 1f, Rand.RandSync.Unsynced)) { return; }
|
if (randomChance < Rand.Range(0f, 1f, Rand.RandSync.Unsynced)) { return; }
|
||||||
|
|
||||||
foreach (var statusEffect in statusEffects)
|
foreach (var statusEffect in statusEffects)
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Abilities
|
||||||
|
{
|
||||||
|
class CharacterAbilityUnlockTree : CharacterAbility
|
||||||
|
{
|
||||||
|
public CharacterAbilityUnlockTree(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void InitializeAbility(bool addingFirstTime)
|
||||||
|
{
|
||||||
|
if (!addingFirstTime) { return; }
|
||||||
|
if (!TalentTree.JobTalentTrees.TryGetValue(Character.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||||
|
|
||||||
|
var subTree = talentTree.TalentSubTrees.Find(t => t.TalentOptionStages.Any(ts => ts.Talents.Contains(CharacterTalent.Prefab)));
|
||||||
|
if (subTree != null)
|
||||||
|
{
|
||||||
|
foreach (var talentOption in subTree.TalentOptionStages)
|
||||||
|
{
|
||||||
|
foreach (var talent in talentOption.Talents)
|
||||||
|
{
|
||||||
|
Character.GiveTalent(talent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -4,14 +4,14 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Barotrauma.Abilities
|
namespace Barotrauma.Abilities
|
||||||
{
|
{
|
||||||
class CharacterAbilityEnigmaMachine : CharacterAbility
|
class CharacterAbilityAtmosMachine : CharacterAbility
|
||||||
{
|
{
|
||||||
private readonly float addedValue;
|
private readonly float addedValue;
|
||||||
private readonly float multiplyValue;
|
private readonly float multiplyValue;
|
||||||
private readonly string[] tags;
|
private readonly string[] tags;
|
||||||
private readonly int maxMultiplyCount;
|
private readonly int maxMultiplyCount;
|
||||||
|
|
||||||
public CharacterAbilityEnigmaMachine(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityAtmosMachine(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||||
-42
@@ -1,42 +0,0 @@
|
|||||||
using Microsoft.Xna.Framework;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma.Abilities
|
|
||||||
{
|
|
||||||
class CharacterAbilityStonewall : CharacterAbility
|
|
||||||
{
|
|
||||||
private readonly List<StatusEffect> statusEffects;
|
|
||||||
private readonly List<StatusEffect> statusEffectsReset;
|
|
||||||
private readonly int maxEnemyCount;
|
|
||||||
private readonly float squaredDistance;
|
|
||||||
|
|
||||||
public CharacterAbilityStonewall(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
|
||||||
{
|
|
||||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
|
||||||
statusEffectsReset = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffectsreset"));
|
|
||||||
maxEnemyCount = abilityElement.GetAttributeInt("maxenemycount", 0);
|
|
||||||
squaredDistance = MathF.Pow(abilityElement.GetAttributeFloat("distance", 0), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
|
|
||||||
{
|
|
||||||
int numberOfEnemiesInRange = Character.CharacterList.Count(c => !HumanAIController.IsFriendly(Character, c) && !c.IsDead && Vector2.DistanceSquared(Character.WorldPosition, c.WorldPosition) < squaredDistance);
|
|
||||||
|
|
||||||
foreach (var statusEffect in statusEffectsReset)
|
|
||||||
{
|
|
||||||
statusEffect.Apply(ActionType.OnAbility, 1f, Character, Character);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conditionsMatched && numberOfEnemiesInRange > 0)
|
|
||||||
{
|
|
||||||
foreach (var statusEffect in statusEffects)
|
|
||||||
{
|
|
||||||
statusEffect.Apply(ActionType.OnAbility, Math.Min(numberOfEnemiesInRange, maxEnemyCount), Character, Character);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -23,6 +23,7 @@ namespace Barotrauma.Abilities
|
|||||||
characterAbility.ApplyAbilityEffect(abilityObject);
|
characterAbility.ApplyAbilityEffect(abilityObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
timesTriggered++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
@@ -39,6 +39,10 @@ namespace Barotrauma.Abilities
|
|||||||
characterAbility.UpdateCharacterAbility(conditionsMatched, TimeSinceLastUpdate);
|
characterAbility.UpdateCharacterAbility(conditionsMatched, TimeSinceLastUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (conditionsMatched)
|
||||||
|
{
|
||||||
|
timesTriggered++;
|
||||||
|
}
|
||||||
TimeSinceLastUpdate = 0;
|
TimeSinceLastUpdate = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(jobIdentifier))
|
if (string.IsNullOrEmpty(jobIdentifier))
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No job defined for talent tree!");
|
DebugConsole.ThrowError($"No job defined for talent tree in \"{filePath}\"!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,10 @@
|
|||||||
OnAllyGainMissionExperience,
|
OnAllyGainMissionExperience,
|
||||||
OnGainMissionExperience,
|
OnGainMissionExperience,
|
||||||
OnGainMissionMoney,
|
OnGainMissionMoney,
|
||||||
|
OnLocationDiscovered,
|
||||||
OnItemDeconstructed,
|
OnItemDeconstructed,
|
||||||
OnItemDeconstructedMaterial,
|
OnItemDeconstructedMaterial,
|
||||||
OnItemDeconstructedRetainProbability,
|
OnItemDeconstructedInventory,
|
||||||
OnStopTinkering,
|
OnStopTinkering,
|
||||||
OnItemPicked,
|
OnItemPicked,
|
||||||
AfterSubmarineAttacked,
|
AfterSubmarineAttacked,
|
||||||
@@ -96,7 +97,6 @@
|
|||||||
// Utility
|
// Utility
|
||||||
RepairSpeed,
|
RepairSpeed,
|
||||||
DeconstructorSpeedMultiplier,
|
DeconstructorSpeedMultiplier,
|
||||||
TinkeringDuration,
|
|
||||||
RepairToolStructureRepairMultiplier,
|
RepairToolStructureRepairMultiplier,
|
||||||
RepairToolStructureDamageMultiplier,
|
RepairToolStructureDamageMultiplier,
|
||||||
RepairToolDeattachTimeMultiplier,
|
RepairToolDeattachTimeMultiplier,
|
||||||
@@ -105,6 +105,10 @@
|
|||||||
GeneticMaterialRefineBonus,
|
GeneticMaterialRefineBonus,
|
||||||
GeneticMaterialTaintedProbabilityReductionOnCombine,
|
GeneticMaterialTaintedProbabilityReductionOnCombine,
|
||||||
SkillGainSpeed,
|
SkillGainSpeed,
|
||||||
|
// Tinker
|
||||||
|
TinkeringDuration,
|
||||||
|
TinkeringStrength,
|
||||||
|
TinkeringDamage,
|
||||||
// Misc
|
// Misc
|
||||||
ReputationGainMultiplier,
|
ReputationGainMultiplier,
|
||||||
MissionMoneyGainMultiplier,
|
MissionMoneyGainMultiplier,
|
||||||
@@ -114,6 +118,7 @@
|
|||||||
Coauthor,
|
Coauthor,
|
||||||
WarriorPoetMissionRuns,
|
WarriorPoetMissionRuns,
|
||||||
WarriorPoetEnemiesKilled,
|
WarriorPoetEnemiesKilled,
|
||||||
|
QuickfixRepairCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AbilityFlags
|
public enum AbilityFlags
|
||||||
|
|||||||
@@ -868,6 +868,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (level == null) { return 0.0f; }
|
if (level == null) { return 0.0f; }
|
||||||
var refEntity = GetRefEntity();
|
var refEntity = GetRefEntity();
|
||||||
|
if (refEntity == null) { return 0.0f; }
|
||||||
Vector2 target = ConvertUnits.ToSimUnits(level.EndPosition);
|
Vector2 target = ConvertUnits.ToSimUnits(level.EndPosition);
|
||||||
var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(refEntity.WorldPosition), target);
|
var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(refEntity.WorldPosition), target);
|
||||||
if (steeringPath.Unreachable || float.IsPositiveInfinity(totalPathLength))
|
if (steeringPath.Unreachable || float.IsPositiveInfinity(totalPathLength))
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class MineralMission : Mission
|
partial class MineralMission : Mission
|
||||||
{
|
{
|
||||||
private Dictionary<string, Pair<int, float>> ResourceClusters { get; } = new Dictionary<string, Pair<int, float>>();
|
private readonly Dictionary<string, (int amount, float rotation)> resourceClusters = new Dictionary<string, (int amount, float rotation)>();
|
||||||
private Dictionary<string, List<Item>> SpawnedResources { get; } = new Dictionary<string, List<Item>>();
|
private readonly Dictionary<string, List<Item>> spawnedResources = new Dictionary<string, List<Item>>();
|
||||||
private Dictionary<string, Item[]> RelevantLevelResources { get; } = new Dictionary<string, Item[]>();
|
private readonly Dictionary<string, Item[]> relevantLevelResources = new Dictionary<string, Item[]>();
|
||||||
private List<Tuple<string, Vector2>> MissionClusterPositions { get; } = new List<Tuple<string, Vector2>>();
|
private readonly List<Tuple<string, Vector2>> missionClusterPositions = new List<Tuple<string, Vector2>>();
|
||||||
|
|
||||||
private readonly HashSet<Level.Cave> caves = new HashSet<Level.Cave>();
|
private readonly HashSet<Level.Cave> caves = new HashSet<Level.Cave>();
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return MissionClusterPositions
|
return missionClusterPositions
|
||||||
.Where(p => SpawnedResources.ContainsKey(p.Item1) && AnyAreUncollected(SpawnedResources[p.Item1]))
|
.Where(p => spawnedResources.ContainsKey(p.Item1) && AnyAreUncollected(spawnedResources[p.Item1]))
|
||||||
.Select(p => p.Item2);
|
.Select(p => p.Item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,53 +33,53 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
var identifier = c.GetAttributeString("identifier", null);
|
var identifier = c.GetAttributeString("identifier", null);
|
||||||
if (string.IsNullOrWhiteSpace(identifier)) { continue; }
|
if (string.IsNullOrWhiteSpace(identifier)) { continue; }
|
||||||
if (ResourceClusters.ContainsKey(identifier))
|
if (resourceClusters.ContainsKey(identifier))
|
||||||
{
|
{
|
||||||
ResourceClusters[identifier].First++;
|
resourceClusters[identifier] = (resourceClusters[identifier].amount + 1, resourceClusters[identifier].rotation);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ResourceClusters.Add(identifier, new Pair<int, float>(1, 0.0f));
|
resourceClusters.Add(identifier, (1, 0.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void StartMissionSpecific(Level level)
|
protected override void StartMissionSpecific(Level level)
|
||||||
{
|
{
|
||||||
if (SpawnedResources.Any())
|
if (spawnedResources.Any())
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
throw new Exception($"SpawnedResources.Count > 0 ({SpawnedResources.Count})");
|
throw new Exception($"SpawnedResources.Count > 0 ({spawnedResources.Count})");
|
||||||
#else
|
#else
|
||||||
DebugConsole.AddWarning("Spawned resources list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
DebugConsole.AddWarning("Spawned resources list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
||||||
SpawnedResources.Clear();
|
spawnedResources.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RelevantLevelResources.Any())
|
if (relevantLevelResources.Any())
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
throw new Exception($"RelevantLevelResources.Count > 0 ({RelevantLevelResources.Count})");
|
throw new Exception($"RelevantLevelResources.Count > 0 ({relevantLevelResources.Count})");
|
||||||
#else
|
#else
|
||||||
DebugConsole.AddWarning("Relevant level resources list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
DebugConsole.AddWarning("Relevant level resources list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
||||||
RelevantLevelResources.Clear();
|
relevantLevelResources.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MissionClusterPositions.Any())
|
if (missionClusterPositions.Any())
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
throw new Exception($"MissionClusterPositions.Count > 0 ({MissionClusterPositions.Count})");
|
throw new Exception($"MissionClusterPositions.Count > 0 ({missionClusterPositions.Count})");
|
||||||
#else
|
#else
|
||||||
DebugConsole.AddWarning("Mission cluster positions list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
DebugConsole.AddWarning("Mission cluster positions list was not empty at the start of a mineral mission. The mission instance may not have been ended correctly on previous rounds.");
|
||||||
MissionClusterPositions.Clear();
|
missionClusterPositions.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
caves.Clear();
|
caves.Clear();
|
||||||
|
|
||||||
if (IsClient) { return; }
|
if (IsClient) { return; }
|
||||||
foreach (var kvp in ResourceClusters)
|
foreach (var kvp in resourceClusters)
|
||||||
{
|
{
|
||||||
var prefab = ItemPrefab.Find(null, kvp.Key);
|
var prefab = ItemPrefab.Find(null, kvp.Key);
|
||||||
if (prefab == null)
|
if (prefab == null)
|
||||||
@@ -88,15 +88,14 @@ namespace Barotrauma
|
|||||||
"couldn't find an item prefab with the identifier " + kvp.Key);
|
"couldn't find an item prefab with the identifier " + kvp.Key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var spawnedResources = level.GenerateMissionResources(prefab, kvp.Value.First, out float rotation);
|
var spawnedResources = level.GenerateMissionResources(prefab, kvp.Value.amount, out float rotation);
|
||||||
if (spawnedResources.Count < kvp.Value.First)
|
if (spawnedResources.Count < kvp.Value.amount)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in MineralMission - " +
|
DebugConsole.ThrowError("Error in MineralMission - " +
|
||||||
"spawned " + spawnedResources.Count + "/" + kvp.Value.First + " of " + prefab.Name);
|
"spawned " + spawnedResources.Count + "/" + kvp.Value.amount + " of " + prefab.Name);
|
||||||
}
|
}
|
||||||
if (spawnedResources.None()) { continue; }
|
if (spawnedResources.None()) { continue; }
|
||||||
SpawnedResources.Add(kvp.Key, spawnedResources);
|
this.spawnedResources.Add(kvp.Key, spawnedResources);
|
||||||
kvp.Value.Second = rotation;
|
|
||||||
|
|
||||||
foreach (Level.Cave cave in Level.Loaded.Caves)
|
foreach (Level.Cave cave in Level.Loaded.Caves)
|
||||||
{
|
{
|
||||||
@@ -142,7 +141,7 @@ namespace Barotrauma
|
|||||||
GiveReward();
|
GiveReward();
|
||||||
completed = true;
|
completed = true;
|
||||||
}
|
}
|
||||||
foreach (var kvp in SpawnedResources)
|
foreach (var kvp in spawnedResources)
|
||||||
{
|
{
|
||||||
foreach (var i in kvp.Value)
|
foreach (var i in kvp.Value)
|
||||||
{
|
{
|
||||||
@@ -152,33 +151,33 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpawnedResources.Clear();
|
spawnedResources.Clear();
|
||||||
RelevantLevelResources.Clear();
|
relevantLevelResources.Clear();
|
||||||
MissionClusterPositions.Clear();
|
missionClusterPositions.Clear();
|
||||||
failed = !completed && state > 0;
|
failed = !completed && state > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FindRelevantLevelResources()
|
private void FindRelevantLevelResources()
|
||||||
{
|
{
|
||||||
RelevantLevelResources.Clear();
|
relevantLevelResources.Clear();
|
||||||
foreach (var identifier in ResourceClusters.Keys)
|
foreach (var identifier in resourceClusters.Keys)
|
||||||
{
|
{
|
||||||
var items = Item.ItemList.Where(i => i.Prefab.Identifier == identifier &&
|
var items = Item.ItemList.Where(i => i.Prefab.Identifier == identifier &&
|
||||||
i.Submarine == null && i.ParentInventory == null &&
|
i.Submarine == null && i.ParentInventory == null &&
|
||||||
(!(i.GetComponent<Holdable>() is Holdable h) || (h.Attachable && h.Attached)))
|
(!(i.GetComponent<Holdable>() is Holdable h) || (h.Attachable && h.Attached)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
RelevantLevelResources.Add(identifier, items);
|
relevantLevelResources.Add(identifier, items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool EnoughHaveBeenCollected()
|
private bool EnoughHaveBeenCollected()
|
||||||
{
|
{
|
||||||
foreach (var kvp in ResourceClusters)
|
foreach (var kvp in resourceClusters)
|
||||||
{
|
{
|
||||||
if (RelevantLevelResources.TryGetValue(kvp.Key, out var availableResources))
|
if (relevantLevelResources.TryGetValue(kvp.Key, out var availableResources))
|
||||||
{
|
{
|
||||||
var collected = availableResources.Count(r => HasBeenCollected(r));
|
var collected = availableResources.Count(r => HasBeenCollected(r));
|
||||||
var needed = kvp.Value.First;
|
var needed = kvp.Value.amount;
|
||||||
if (collected < needed) { return false; }
|
if (collected < needed) { return false; }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -210,8 +209,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CalculateMissionClusterPositions()
|
private void CalculateMissionClusterPositions()
|
||||||
{
|
{
|
||||||
MissionClusterPositions.Clear();
|
missionClusterPositions.Clear();
|
||||||
foreach (var kvp in SpawnedResources)
|
foreach (var kvp in spawnedResources)
|
||||||
{
|
{
|
||||||
if (kvp.Value.None()) { continue; }
|
if (kvp.Value.None()) { continue; }
|
||||||
var pos = Vector2.Zero;
|
var pos = Vector2.Zero;
|
||||||
@@ -222,7 +221,7 @@ namespace Barotrauma
|
|||||||
itemCount++;
|
itemCount++;
|
||||||
}
|
}
|
||||||
pos /= itemCount;
|
pos /= itemCount;
|
||||||
MissionClusterPositions.Add(new Tuple<string, Vector2>(kvp.Key, pos));
|
missionClusterPositions.Add(new Tuple<string, Vector2>(kvp.Key, pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,11 @@ namespace Barotrauma
|
|||||||
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(patrolPos), ConvertUnits.ToSimUnits(preferredSpawnPos));
|
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(patrolPos), ConvertUnits.ToSimUnits(preferredSpawnPos));
|
||||||
if (!path.Unreachable)
|
if (!path.Unreachable)
|
||||||
{
|
{
|
||||||
preferredSpawnPos = path.Nodes[Rand.Range(0, path.Nodes.Count - 1)].WorldPosition; // spawn the sub in a random point in the path if possible
|
var validNodes = path.Nodes.FindAll(n => !Level.Loaded.ExtraWalls.Any(w => w.Cells.Any(c => c.IsPointInside(n.WorldPosition))));
|
||||||
|
if (validNodes.Any())
|
||||||
|
{
|
||||||
|
preferredSpawnPos = validNodes.GetRandom().WorldPosition; // spawn the sub in a random point in the path if possible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int graceDistance = 500; // the sub still spawns awkwardly close to walls, so this helps. could also be given as a parameter instead
|
int graceDistance = 500; // the sub still spawns awkwardly close to walls, so this helps. could also be given as a parameter instead
|
||||||
|
|||||||
+5
-1
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Barotrauma.Extensions
|
namespace Barotrauma.Extensions
|
||||||
{
|
{
|
||||||
@@ -12,6 +11,11 @@ namespace Barotrauma.Extensions
|
|||||||
new Color((byte)(color.R * value), (byte)(color.G * value), (byte)(color.B * value), (byte)(color.A * value));
|
new Color((byte)(color.R * value), (byte)(color.G * value), (byte)(color.B * value), (byte)(color.A * value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Color Multiply(this Color thisColor, Color color)
|
||||||
|
{
|
||||||
|
return new Color((byte)(thisColor.R * color.R / 255f), (byte)(thisColor.G * color.G / 255f), (byte)(thisColor.B * color.B / 255f), (byte)(thisColor.A * color.A / 255f));
|
||||||
|
}
|
||||||
|
|
||||||
public static Color Opaque(this Color color)
|
public static Color Opaque(this Color color)
|
||||||
{
|
{
|
||||||
return new Color(color.R, color.G, color.B, (byte)255);
|
return new Color(color.R, color.G, color.B, (byte)255);
|
||||||
@@ -659,16 +659,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
foreach (Location location in Map.Locations)
|
foreach (Location location in Map.Locations)
|
||||||
{
|
{
|
||||||
if (location.Type != location.OriginalType)
|
location.Reset();
|
||||||
{
|
|
||||||
location.ChangeType(location.OriginalType);
|
|
||||||
location.PendingLocationTypeChange = null;
|
|
||||||
}
|
|
||||||
location.CreateStore(force: true);
|
|
||||||
location.ClearMissions();
|
|
||||||
location.Discovered = false;
|
|
||||||
location.LevelData?.EventHistory?.Clear();
|
|
||||||
location.UnlockInitialMissions();
|
|
||||||
}
|
}
|
||||||
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
|
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
|
||||||
Map.SelectLocation(-1);
|
Map.SelectLocation(-1);
|
||||||
|
|||||||
@@ -452,9 +452,11 @@ namespace Barotrauma
|
|||||||
StatusEffect.StopAll();
|
StatusEffect.StopAll();
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
|
#if !DEBUG
|
||||||
GameMain.LightManager.LosEnabled = GameMain.Client == null || GameMain.Client.CharacterInfo != null;
|
GameMain.LightManager.LosEnabled = GameMain.Client == null || GameMain.Client.CharacterInfo != null;
|
||||||
|
#endif
|
||||||
if (GameMain.LightManager.LosEnabled) { GameMain.LightManager.LosAlpha = 1f; }
|
if (GameMain.LightManager.LosEnabled) { GameMain.LightManager.LosAlpha = 1f; }
|
||||||
if (GameMain.Client == null) GameMain.LightManager.LosMode = GameMain.Config.LosMode;
|
if (GameMain.Client == null) { GameMain.LightManager.LosMode = GameMain.Config.LosMode; }
|
||||||
#endif
|
#endif
|
||||||
LevelData = level?.LevelData;
|
LevelData = level?.LevelData;
|
||||||
Level = level;
|
Level = level;
|
||||||
@@ -661,6 +663,7 @@ namespace Barotrauma
|
|||||||
#if SERVER
|
#if SERVER
|
||||||
return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null);
|
return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null);
|
||||||
#else
|
#else
|
||||||
|
if (GameMain.GameSession == null) { return Enumerable.Empty<Character>(); }
|
||||||
return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null);
|
return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,14 +143,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CharacterHeadIndex { get; set; }
|
internal CharacterInfo.HeadInfo PlayerCharacterCustomization { get; set; }
|
||||||
public int CharacterHairIndex { get; set; }
|
|
||||||
public int CharacterBeardIndex { get; set; }
|
|
||||||
public int CharacterMoustacheIndex { get; set; }
|
|
||||||
public int CharacterFaceAttachmentIndex { get; set; }
|
|
||||||
|
|
||||||
public Gender CharacterGender { get; set; }
|
|
||||||
public Race CharacterRace { get; set; }
|
|
||||||
|
|
||||||
private float aimAssistAmount;
|
private float aimAssistAmount;
|
||||||
public float AimAssistAmount
|
public float AimAssistAmount
|
||||||
@@ -855,171 +848,6 @@ namespace Barotrauma
|
|||||||
UnsavedSettings = false;
|
UnsavedSettings = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveNewDefaultConfig()
|
|
||||||
{
|
|
||||||
XDocument doc = new XDocument();
|
|
||||||
|
|
||||||
if (doc.Root == null)
|
|
||||||
{
|
|
||||||
doc.Add(new XElement("config"));
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.Root.Add(
|
|
||||||
new XAttribute("language", TextManager.Language),
|
|
||||||
new XAttribute("masterserverurl", MasterServerUrl),
|
|
||||||
new XAttribute("remotecontenturl", RemoteContentUrl),
|
|
||||||
new XAttribute("autocheckupdates", AutoCheckUpdates),
|
|
||||||
new XAttribute("musicvolume", musicVolume),
|
|
||||||
new XAttribute("soundvolume", soundVolume),
|
|
||||||
new XAttribute("microphonevolume", microphoneVolume),
|
|
||||||
new XAttribute("voicechatvolume", voiceChatVolume),
|
|
||||||
new XAttribute("voicechatcutoffprevention", VoiceChatCutoffPrevention),
|
|
||||||
new XAttribute("verboselogging", VerboseLogging),
|
|
||||||
new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs),
|
|
||||||
new XAttribute("submarineautosave", EnableSubmarineAutoSave),
|
|
||||||
new XAttribute("maxautosaves", MaximumAutoSaves),
|
|
||||||
new XAttribute("autosaveintervalseconds", AutoSaveIntervalSeconds),
|
|
||||||
new XAttribute("subeditorbackground", XMLExtensions.ColorToString(SubEditorBackgroundColor)),
|
|
||||||
new XAttribute("subeditorundobuffer", SubEditorMaxUndoBuffer),
|
|
||||||
new XAttribute("enablesplashscreen", EnableSplashScreen),
|
|
||||||
new XAttribute("usesteammatchmaking", UseSteamMatchmaking),
|
|
||||||
new XAttribute("quickstartsub", QuickStartSubmarineName),
|
|
||||||
new XAttribute("requiresteamauthentication", RequireSteamAuthentication),
|
|
||||||
new XAttribute("aimassistamount", aimAssistAmount),
|
|
||||||
new XAttribute("tutorialskipwarning", ShowTutorialSkipWarning));
|
|
||||||
|
|
||||||
if (!ShowUserStatisticsPrompt)
|
|
||||||
{
|
|
||||||
doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics));
|
|
||||||
}
|
|
||||||
|
|
||||||
XElement gMode = doc.Root.Element("graphicsmode");
|
|
||||||
if (gMode == null)
|
|
||||||
{
|
|
||||||
gMode = new XElement("graphicsmode");
|
|
||||||
doc.Root.Add(gMode);
|
|
||||||
}
|
|
||||||
if (GraphicsWidth == 0 || GraphicsHeight == 0)
|
|
||||||
{
|
|
||||||
gMode.ReplaceAttributes(new XAttribute("displaymode", windowMode));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gMode.ReplaceAttributes(
|
|
||||||
new XAttribute("width", GraphicsWidth),
|
|
||||||
new XAttribute("height", GraphicsHeight),
|
|
||||||
new XAttribute("vsync", VSyncEnabled),
|
|
||||||
new XAttribute("framelimit", Timing.FrameLimit),
|
|
||||||
new XAttribute("displaymode", windowMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
XElement gSettings = doc.Root.Element("graphicssettings");
|
|
||||||
if (gSettings == null)
|
|
||||||
{
|
|
||||||
gSettings = new XElement("graphicssettings");
|
|
||||||
doc.Root.Add(gSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
gSettings.ReplaceAttributes(
|
|
||||||
new XAttribute("particlelimit", ParticleLimit),
|
|
||||||
new XAttribute("lightmapscale", LightMapScale),
|
|
||||||
new XAttribute("chromaticaberration", ChromaticAberrationEnabled),
|
|
||||||
new XAttribute("losmode", LosMode),
|
|
||||||
new XAttribute("hudscale", HUDScale),
|
|
||||||
new XAttribute("inventoryscale", InventoryScale));
|
|
||||||
|
|
||||||
foreach (ContentPackage contentPackage in ContentPackage.CorePackages)
|
|
||||||
{
|
|
||||||
if (contentPackage.Path.Contains(VanillaContentPackagePath))
|
|
||||||
{
|
|
||||||
doc.Root.Add(new XElement("contentpackages", new XElement("core", new XAttribute("name", contentPackage.Name))));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CLIENT
|
|
||||||
var keyMappingElement = new XElement("keymapping");
|
|
||||||
doc.Root.Add(keyMappingElement);
|
|
||||||
for (int i = 0; i < keyMapping.Length; i++)
|
|
||||||
{
|
|
||||||
KeyOrMouse bind = keyMapping[i];
|
|
||||||
if (bind.MouseButton == MouseButton.None)
|
|
||||||
{
|
|
||||||
keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), bind.Key));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
keyMappingElement.Add(new XAttribute(((InputType)i).ToString(), bind.MouseButton));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var inventoryKeyMappingElement = new XElement("inventorykeymapping");
|
|
||||||
doc.Root.Add(inventoryKeyMappingElement);
|
|
||||||
for (int i = 0; i < inventoryKeyMapping.Length; i++)
|
|
||||||
{
|
|
||||||
KeyOrMouse bind = inventoryKeyMapping[i];
|
|
||||||
if (bind.MouseButton == MouseButton.None)
|
|
||||||
{
|
|
||||||
inventoryKeyMappingElement.Add(new XAttribute($"slot{i}", bind.Key));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
inventoryKeyMappingElement.Add(new XAttribute($"slot{i}", bind.MouseButton));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var gameplay = new XElement("gameplay");
|
|
||||||
var jobPreferences = new XElement("jobpreferences");
|
|
||||||
foreach (Pair<string, int> job in JobPreferences)
|
|
||||||
{
|
|
||||||
XElement jobElement = new XElement("job");
|
|
||||||
jobElement.Add(new XAttribute("identifier", job.First));
|
|
||||||
jobElement.Add(new XAttribute("variant", job.Second));
|
|
||||||
jobPreferences.Add(jobElement);
|
|
||||||
}
|
|
||||||
gameplay.Add(jobPreferences);
|
|
||||||
|
|
||||||
var teamPreference = new XElement("teampreference");
|
|
||||||
teamPreference.Add(new XAttribute("team", TeamPreference.ToString()));
|
|
||||||
gameplay.Add(teamPreference);
|
|
||||||
|
|
||||||
doc.Root.Add(gameplay);
|
|
||||||
|
|
||||||
var playerElement = new XElement("player",
|
|
||||||
new XAttribute("name", playerName ?? ""),
|
|
||||||
new XAttribute("headindex", CharacterHeadIndex),
|
|
||||||
new XAttribute("gender", CharacterGender),
|
|
||||||
new XAttribute("race", CharacterRace),
|
|
||||||
new XAttribute("hairindex", CharacterHairIndex),
|
|
||||||
new XAttribute("beardindex", CharacterBeardIndex),
|
|
||||||
new XAttribute("moustacheindex", CharacterMoustacheIndex),
|
|
||||||
new XAttribute("faceattachmentindex", CharacterFaceAttachmentIndex));
|
|
||||||
doc.Root.Add(playerElement);
|
|
||||||
|
|
||||||
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
|
||||||
{
|
|
||||||
Indent = true,
|
|
||||||
OmitXmlDeclaration = true,
|
|
||||||
NewLineOnAttributes = true
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var writer = XmlWriter.Create(SavePath, settings))
|
|
||||||
{
|
|
||||||
doc.WriteTo(writer);
|
|
||||||
writer.Flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Saving game settings failed.", e);
|
|
||||||
GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
|
||||||
"Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Load PlayerConfig
|
#region Load PlayerConfig
|
||||||
public void LoadPlayerConfig()
|
public void LoadPlayerConfig()
|
||||||
{
|
{
|
||||||
@@ -1307,15 +1135,20 @@ namespace Barotrauma
|
|||||||
gameplay.Add(jobPreferences);
|
gameplay.Add(jobPreferences);
|
||||||
doc.Root.Add(gameplay);
|
doc.Root.Add(gameplay);
|
||||||
|
|
||||||
var playerElement = new XElement("player",
|
var playerElement = new XElement("player", new XAttribute("name", playerName ?? ""));
|
||||||
new XAttribute("name", playerName ?? ""),
|
if (PlayerCharacterCustomization != null)
|
||||||
new XAttribute("headindex", CharacterHeadIndex),
|
{
|
||||||
new XAttribute("gender", CharacterGender),
|
playerElement.SetAttributeValue("headindex", PlayerCharacterCustomization.HeadSpriteId);
|
||||||
new XAttribute("race", CharacterRace),
|
playerElement.SetAttributeValue("gender", PlayerCharacterCustomization.gender);
|
||||||
new XAttribute("hairindex", CharacterHairIndex),
|
playerElement.SetAttributeValue("race", PlayerCharacterCustomization.race);
|
||||||
new XAttribute("beardindex", CharacterBeardIndex),
|
playerElement.SetAttributeValue("hairindex", PlayerCharacterCustomization.HairIndex);
|
||||||
new XAttribute("moustacheindex", CharacterMoustacheIndex),
|
playerElement.SetAttributeValue("beardindex", PlayerCharacterCustomization.BeardIndex);
|
||||||
new XAttribute("faceattachmentindex", CharacterFaceAttachmentIndex));
|
playerElement.SetAttributeValue("moustacheindex", PlayerCharacterCustomization.MoustacheIndex);
|
||||||
|
playerElement.SetAttributeValue("faceattachmentindex", PlayerCharacterCustomization.FaceAttachmentIndex);
|
||||||
|
playerElement.SetAttributeValue("skincolor", XMLExtensions.ColorToString(PlayerCharacterCustomization.SkinColor));
|
||||||
|
playerElement.SetAttributeValue("haircolor", XMLExtensions.ColorToString(PlayerCharacterCustomization.HairColor));
|
||||||
|
playerElement.SetAttributeValue("facialhaircolor", XMLExtensions.ColorToString(PlayerCharacterCustomization.FacialHairColor));
|
||||||
|
}
|
||||||
doc.Root.Add(playerElement);
|
doc.Root.Add(playerElement);
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
@@ -1434,23 +1267,22 @@ namespace Barotrauma
|
|||||||
if (playerElement != null)
|
if (playerElement != null)
|
||||||
{
|
{
|
||||||
playerName = playerElement.GetAttributeString("name", playerName);
|
playerName = playerElement.GetAttributeString("name", playerName);
|
||||||
CharacterHeadIndex = playerElement.GetAttributeInt("headindex", CharacterHeadIndex);
|
int head = playerElement.GetAttributeInt("headindex", -1);
|
||||||
if (Enum.TryParse(playerElement.GetAttributeString("gender", "none"), true, out Gender g))
|
Enum.TryParse(playerElement.GetAttributeString("gender", "none"), true, out Gender gender);
|
||||||
|
Enum.TryParse(playerElement.GetAttributeString("race", "white"), true, out Race race);
|
||||||
|
int hair = playerElement.GetAttributeInt("hairindex", -1);
|
||||||
|
int beard = playerElement.GetAttributeInt("beardindex", -1);
|
||||||
|
int moustache = playerElement.GetAttributeInt("moustacheindex", -1);
|
||||||
|
int faceAttachment = playerElement.GetAttributeInt("faceattachmentindex", -1);
|
||||||
|
Color skinColor = playerElement.GetAttributeColor("skincolor", Color.Black);
|
||||||
|
Color hairColor = playerElement.GetAttributeColor("haircolor", Color.Black);
|
||||||
|
Color facialHairColor = playerElement.GetAttributeColor("facialhaircolor", Color.Black);
|
||||||
|
PlayerCharacterCustomization = new CharacterInfo.HeadInfo(head, gender, race, hair, beard, moustache, faceAttachment)
|
||||||
{
|
{
|
||||||
CharacterGender = g;
|
SkinColor = skinColor,
|
||||||
}
|
HairColor = hairColor,
|
||||||
if (Enum.TryParse(playerElement.GetAttributeString("race", "white"), true, out Race r))
|
FacialHairColor = facialHairColor
|
||||||
{
|
};
|
||||||
CharacterRace = r;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CharacterRace = Race.White;
|
|
||||||
}
|
|
||||||
CharacterHairIndex = playerElement.GetAttributeInt("hairindex", CharacterHairIndex);
|
|
||||||
CharacterBeardIndex = playerElement.GetAttributeInt("beardindex", CharacterBeardIndex);
|
|
||||||
CharacterMoustacheIndex = playerElement.GetAttributeInt("moustacheindex", CharacterMoustacheIndex);
|
|
||||||
CharacterFaceAttachmentIndex = playerElement.GetAttributeInt("faceattachmentindex", CharacterFaceAttachmentIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1656,13 +1488,7 @@ namespace Barotrauma
|
|||||||
UseSteamMatchmaking = true;
|
UseSteamMatchmaking = true;
|
||||||
RequireSteamAuthentication = true;
|
RequireSteamAuthentication = true;
|
||||||
QuickStartSubmarineName = string.Empty;
|
QuickStartSubmarineName = string.Empty;
|
||||||
CharacterHeadIndex = 1;
|
PlayerCharacterCustomization = null;
|
||||||
CharacterHairIndex = -1;
|
|
||||||
CharacterBeardIndex = -1;
|
|
||||||
CharacterMoustacheIndex = -1;
|
|
||||||
CharacterFaceAttachmentIndex = -1;
|
|
||||||
CharacterGender = Gender.None;
|
|
||||||
CharacterRace = Race.White;
|
|
||||||
aimAssistAmount = 0.5f;
|
aimAssistAmount = 0.5f;
|
||||||
EnableMouseLook = true;
|
EnableMouseLook = true;
|
||||||
EnableRadialDistortion = true;
|
EnableRadialDistortion = true;
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ namespace Barotrauma.Items.Components
|
|||||||
private Character targetCharacter;
|
private Character targetCharacter;
|
||||||
private AfflictionPrefab selectedEffect, selectedTaintedEffect;
|
private AfflictionPrefab selectedEffect, selectedTaintedEffect;
|
||||||
|
|
||||||
[Serialize("", false)]
|
[Serialize("", true)]
|
||||||
public string Effect
|
public string Effect
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize("geneticmaterialdebuff", false)]
|
[Serialize("geneticmaterialdebuff", true)]
|
||||||
public string TaintedEffect
|
public string TaintedEffect
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool tainted;
|
private bool tainted;
|
||||||
[Serialize(false, false)]
|
[Serialize(false, true)]
|
||||||
public bool Tainted
|
public bool Tainted
|
||||||
{
|
{
|
||||||
get { return tainted; }
|
get { return tainted; }
|
||||||
@@ -49,7 +49,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
//only for saving the selected tainted effect
|
//only for saving the selected tainted effect
|
||||||
[Serialize("", false)]
|
[Serialize("", true)]
|
||||||
public string SelectedTaintedEffect
|
public string SelectedTaintedEffect
|
||||||
{
|
{
|
||||||
get { return selectedTaintedEffect?.Identifier ?? string.Empty; }
|
get { return selectedTaintedEffect?.Identifier ?? string.Empty; }
|
||||||
@@ -100,6 +100,11 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
float selectedTaintedEffectStrength = item.ConditionPercentage / 100.0f * selectedTaintedEffect.MaxStrength;
|
float selectedTaintedEffectStrength = item.ConditionPercentage / 100.0f * selectedTaintedEffect.MaxStrength;
|
||||||
character.CharacterHealth.ApplyAffliction(null, selectedTaintedEffect.Instantiate(selectedTaintedEffectStrength));
|
character.CharacterHealth.ApplyAffliction(null, selectedTaintedEffect.Instantiate(selectedTaintedEffectStrength));
|
||||||
|
var existingAffliction = character.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedTaintedEffect);
|
||||||
|
if (existingAffliction != null)
|
||||||
|
{
|
||||||
|
existingAffliction.Strength = selectedTaintedEffectStrength;
|
||||||
|
}
|
||||||
targetCharacter = character;
|
targetCharacter = character;
|
||||||
#if SERVER
|
#if SERVER
|
||||||
item.CreateServerEvent(this);
|
item.CreateServerEvent(this);
|
||||||
@@ -111,6 +116,11 @@ namespace Barotrauma.Items.Components
|
|||||||
ApplyStatusEffects(ActionType.OnWearing, 1.0f);
|
ApplyStatusEffects(ActionType.OnWearing, 1.0f);
|
||||||
float selectedEffectStrength = item.ConditionPercentage / 100.0f * selectedEffect.MaxStrength;
|
float selectedEffectStrength = item.ConditionPercentage / 100.0f * selectedEffect.MaxStrength;
|
||||||
character.CharacterHealth.ApplyAffliction(null, selectedEffect.Instantiate(selectedEffectStrength));
|
character.CharacterHealth.ApplyAffliction(null, selectedEffect.Instantiate(selectedEffectStrength));
|
||||||
|
var existingAffliction = character.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedEffect);
|
||||||
|
if (existingAffliction != null)
|
||||||
|
{
|
||||||
|
existingAffliction.Strength = selectedEffectStrength;
|
||||||
|
}
|
||||||
targetCharacter = character;
|
targetCharacter = character;
|
||||||
#if SERVER
|
#if SERVER
|
||||||
item.CreateServerEvent(this);
|
item.CreateServerEvent(this);
|
||||||
@@ -197,5 +207,21 @@ namespace Barotrauma.Items.Components
|
|||||||
item.CreateServerEvent(this);
|
item.CreateServerEvent(this);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string TryCreateName(ItemPrefab prefab, XElement element)
|
||||||
|
{
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
if (subElement.Name.ToString().Equals(nameof(GeneticMaterial), StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string nameId = subElement.GetAttributeString("nameidentifier", "");
|
||||||
|
if (!string.IsNullOrEmpty(nameId))
|
||||||
|
{
|
||||||
|
return prefab.Name.Replace("[type]", TextManager.Get(nameId, returnNull: true) ?? nameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prefab.Name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -603,6 +603,11 @@ namespace Barotrauma.Items.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool SecondaryUse(float deltaTime, Character character = null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private Vector2 GetAttachPosition(Character user, bool useWorldCoordinates = false)
|
private Vector2 GetAttachPosition(Character user, bool useWorldCoordinates = false)
|
||||||
{
|
{
|
||||||
if (user == null) { return useWorldCoordinates ? item.WorldPosition : item.Position; }
|
if (user == null) { return useWorldCoordinates ? item.WorldPosition : item.Position; }
|
||||||
|
|||||||
@@ -61,8 +61,10 @@ namespace Barotrauma.Items.Components
|
|||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
if (!subElement.Name.ToString().Equals("attack", StringComparison.OrdinalIgnoreCase)) { continue; }
|
if (!subElement.Name.ToString().Equals("attack", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||||
Attack = new Attack(subElement, item.Name + ", MeleeWeapon", item);
|
Attack = new Attack(subElement, item.Name + ", MeleeWeapon", item)
|
||||||
Attack.DamageRange = item.body == null ? 10.0f : ConvertUnits.ToDisplayUnits(item.body.GetMaxExtent());
|
{
|
||||||
|
DamageRange = item.body == null ? 10.0f : ConvertUnits.ToDisplayUnits(item.body.GetMaxExtent())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
item.IsShootable = true;
|
item.IsShootable = true;
|
||||||
// TODO: should define this in xml if we have melee weapons that don't require aim to use
|
// TODO: should define this in xml if we have melee weapons that don't require aim to use
|
||||||
@@ -266,16 +268,10 @@ namespace Barotrauma.Items.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Character targetCharacter = null;
|
if (f2.Body.UserData is Limb targetLimb)
|
||||||
Limb targetLimb = null;
|
|
||||||
Structure targetStructure = null;
|
|
||||||
Item targetItem = null;
|
|
||||||
|
|
||||||
if (f2.Body.UserData is Limb)
|
|
||||||
{
|
{
|
||||||
targetLimb = (Limb)f2.Body.UserData;
|
|
||||||
if (targetLimb.IsSevered || targetLimb.character == null || targetLimb.character == User) { return false; }
|
if (targetLimb.IsSevered || targetLimb.character == null || targetLimb.character == User) { return false; }
|
||||||
targetCharacter = targetLimb.character;
|
var targetCharacter = targetLimb.character;
|
||||||
if (targetCharacter == picker) { return false; }
|
if (targetCharacter == picker) { return false; }
|
||||||
if (AllowHitMultiple)
|
if (AllowHitMultiple)
|
||||||
{
|
{
|
||||||
@@ -287,9 +283,8 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
hitTargets.Add(targetCharacter);
|
hitTargets.Add(targetCharacter);
|
||||||
}
|
}
|
||||||
else if (f2.Body.UserData is Character)
|
else if (f2.Body.UserData is Character targetCharacter)
|
||||||
{
|
{
|
||||||
targetCharacter = (Character)f2.Body.UserData;
|
|
||||||
if (targetCharacter == picker || targetCharacter == User) { return false; }
|
if (targetCharacter == picker || targetCharacter == User) { return false; }
|
||||||
targetLimb = targetCharacter.AnimController.GetLimb(LimbType.Torso); //Otherwise armor can be bypassed in strange ways
|
targetLimb = targetCharacter.AnimController.GetLimb(LimbType.Torso); //Otherwise armor can be bypassed in strange ways
|
||||||
if (AllowHitMultiple)
|
if (AllowHitMultiple)
|
||||||
@@ -302,9 +297,8 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
hitTargets.Add(targetCharacter);
|
hitTargets.Add(targetCharacter);
|
||||||
}
|
}
|
||||||
else if (f2.Body.UserData is Structure)
|
else if (f2.Body.UserData is Structure targetStructure)
|
||||||
{
|
{
|
||||||
targetStructure = (Structure)f2.Body.UserData;
|
|
||||||
if (AllowHitMultiple)
|
if (AllowHitMultiple)
|
||||||
{
|
{
|
||||||
if (hitTargets.Contains(targetStructure)) { return true; }
|
if (hitTargets.Contains(targetStructure)) { return true; }
|
||||||
@@ -315,9 +309,8 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
hitTargets.Add(targetStructure);
|
hitTargets.Add(targetStructure);
|
||||||
}
|
}
|
||||||
else if (f2.Body.UserData is Item)
|
else if (f2.Body.UserData is Item targetItem)
|
||||||
{
|
{
|
||||||
targetItem = (Item)f2.Body.UserData;
|
|
||||||
if (AllowHitMultiple)
|
if (AllowHitMultiple)
|
||||||
{
|
{
|
||||||
if (hitTargets.Contains(targetItem)) { return true; }
|
if (hitTargets.Contains(targetItem)) { return true; }
|
||||||
@@ -350,13 +343,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
Limb targetLimb = target.UserData as Limb;
|
Limb targetLimb = target.UserData as Limb;
|
||||||
Character targetCharacter = targetLimb?.character ?? target.UserData as Character;
|
Character targetCharacter = targetLimb?.character ?? target.UserData as Character;
|
||||||
Structure targetStructure = target.UserData as Structure;
|
|
||||||
Item targetItem = target.UserData as Item;
|
|
||||||
|
|
||||||
if (Attack != null)
|
if (Attack != null)
|
||||||
{
|
{
|
||||||
Attack.SetUser(User);
|
Attack.SetUser(User);
|
||||||
Attack.DamageMultiplier = 1 + User.GetStatValue(StatTypes.MeleeAttackMultiplier);
|
Attack.DamageMultiplier = 1 + User.GetStatValue(StatTypes.MeleeAttackMultiplier);
|
||||||
|
Attack.DamageMultiplier *= 1.0f + item.GetQualityModifier(Quality.StatType.AttackMultiplier);
|
||||||
|
|
||||||
if (targetLimb != null)
|
if (targetLimb != null)
|
||||||
{
|
{
|
||||||
@@ -370,12 +361,12 @@ namespace Barotrauma.Items.Components
|
|||||||
targetCharacter.LastDamageSource = item;
|
targetCharacter.LastDamageSource = item;
|
||||||
Attack.DoDamage(User, targetCharacter, item.WorldPosition, 1.0f);
|
Attack.DoDamage(User, targetCharacter, item.WorldPosition, 1.0f);
|
||||||
}
|
}
|
||||||
else if (targetStructure != null)
|
else if (target.UserData is Structure targetStructure)
|
||||||
{
|
{
|
||||||
if (targetStructure.Removed) { return; }
|
if (targetStructure.Removed) { return; }
|
||||||
Attack.DoDamage(User, targetStructure, item.WorldPosition, 1.0f);
|
Attack.DoDamage(User, targetStructure, item.WorldPosition, 1.0f);
|
||||||
}
|
}
|
||||||
else if (targetItem != null && targetItem.Prefab.DamagedByMeleeWeapons && targetItem.Condition > 0)
|
else if (target.UserData is Item targetItem && targetItem.Prefab.DamagedByMeleeWeapons && targetItem.Condition > 0)
|
||||||
{
|
{
|
||||||
if (targetItem.Removed) { return; }
|
if (targetItem.Removed) { return; }
|
||||||
Attack.DoDamage(User, targetItem, item.WorldPosition, 1.0f);
|
Attack.DoDamage(User, targetItem, item.WorldPosition, 1.0f);
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 barrelPos = TransformedBarrelPos + item.body.SimPosition;
|
Vector2 barrelPos = TransformedBarrelPos + item.body.SimPosition;
|
||||||
float rotation = (Item.body.Dir == 1.0f) ? Item.body.Rotation : Item.body.Rotation - MathHelper.Pi;
|
float rotation = (Item.body.Dir == 1.0f) ? Item.body.Rotation : Item.body.Rotation - MathHelper.Pi;
|
||||||
float spread = GetSpread(character) * Rand.Range(-0.5f, 0.5f);
|
float spread = GetSpread(character) * Rand.Range(-0.5f, 0.5f);
|
||||||
projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: limbBodies.ToList(), createNetworkEvent: false);
|
float damageMultiplier = 1f + item.GetQualityModifier(Quality.StatType.AttackMultiplier);
|
||||||
|
projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: limbBodies.ToList(), createNetworkEvent: false, damageMultiplier);
|
||||||
projectile.Item.GetComponent<Rope>()?.Attach(Item, projectile.Item);
|
projectile.Item.GetComponent<Rope>()?.Attach(Item, projectile.Item);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -619,7 +619,7 @@ namespace Barotrauma.Items.Components
|
|||||||
levelResource.requiredItems.Any() &&
|
levelResource.requiredItems.Any() &&
|
||||||
levelResource.HasRequiredItems(user, addMessage: false))
|
levelResource.HasRequiredItems(user, addMessage: false))
|
||||||
{
|
{
|
||||||
float addedDetachTime = deltaTime * (1f + user.GetStatValue(StatTypes.RepairToolDeattachTimeMultiplier)) * item.GetQualityModifier(Quality.StatType.RepairToolDeattachTimeMultiplier);
|
float addedDetachTime = deltaTime * (1f + user.GetStatValue(StatTypes.RepairToolDeattachTimeMultiplier)) * (1f + item.GetQualityModifier(Quality.StatType.RepairToolDeattachTimeMultiplier));
|
||||||
levelResource.DeattachTimer += addedDetachTime;
|
levelResource.DeattachTimer += addedDetachTime;
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
Character.Controlled?.UpdateHUDProgressBar(
|
Character.Controlled?.UpdateHUDProgressBar(
|
||||||
|
|||||||
+17
-14
@@ -19,6 +19,8 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private float userDeconstructorSpeedMultiplier = 1.0f;
|
private float userDeconstructorSpeedMultiplier = 1.0f;
|
||||||
|
|
||||||
|
private const float TinkeringSpeedIncrease = 1.5f;
|
||||||
|
|
||||||
private ItemContainer inputContainer, outputContainer;
|
private ItemContainer inputContainer, outputContainer;
|
||||||
|
|
||||||
public ItemContainer InputContainer
|
public ItemContainer InputContainer
|
||||||
@@ -89,12 +91,20 @@ namespace Barotrauma.Items.Components
|
|||||||
if (powerConsumption <= 0.0f) { Voltage = 1.0f; }
|
if (powerConsumption <= 0.0f) { Voltage = 1.0f; }
|
||||||
progressTimer += deltaTime * Math.Min(Voltage, 1.0f);
|
progressTimer += deltaTime * Math.Min(Voltage, 1.0f);
|
||||||
|
|
||||||
|
float tinkeringStrength = 0f;
|
||||||
|
if (repairable.IsTinkering)
|
||||||
|
{
|
||||||
|
tinkeringStrength = repairable.TinkeringStrength;
|
||||||
|
}
|
||||||
|
// doesn't quite work properly, remaining time changes if tinkering stops
|
||||||
|
float deconstructionSpeedModifier = userDeconstructorSpeedMultiplier * (1f + tinkeringStrength * TinkeringSpeedIncrease);
|
||||||
|
|
||||||
if (DeconstructItemsSimultaneously)
|
if (DeconstructItemsSimultaneously)
|
||||||
{
|
{
|
||||||
float deconstructTime = 0.0f;
|
float deconstructTime = 0.0f;
|
||||||
foreach (Item targetItem in inputContainer.Inventory.AllItems)
|
foreach (Item targetItem in inputContainer.Inventory.AllItems)
|
||||||
{
|
{
|
||||||
deconstructTime += targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * userDeconstructorSpeedMultiplier);
|
deconstructTime += targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * deconstructionSpeedModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
||||||
@@ -126,7 +136,7 @@ namespace Barotrauma.Items.Components
|
|||||||
var validDeconstructItems = targetItem.Prefab.DeconstructItems.FindAll(it =>
|
var validDeconstructItems = targetItem.Prefab.DeconstructItems.FindAll(it =>
|
||||||
it.RequiredDeconstructor.Length == 0 || it.RequiredDeconstructor.Any(r => item.HasTag(r) || item.Prefab.Identifier.Equals(r, StringComparison.OrdinalIgnoreCase)));
|
it.RequiredDeconstructor.Length == 0 || it.RequiredDeconstructor.Any(r => item.HasTag(r) || item.Prefab.Identifier.Equals(r, StringComparison.OrdinalIgnoreCase)));
|
||||||
|
|
||||||
float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / DeconstructionSpeed : 1.0f;
|
float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * deconstructionSpeedModifier) : 1.0f;
|
||||||
|
|
||||||
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
||||||
if (progressTimer > deconstructTime)
|
if (progressTimer > deconstructTime)
|
||||||
@@ -234,9 +244,13 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (user != null && !user.Removed)
|
if (user != null && !user.Removed)
|
||||||
{
|
{
|
||||||
var itemsCreated = new AbilityValueItem(1f, targetItem.Prefab);
|
var itemsCreated = new AbilityValueItem(amount, targetItem.Prefab);
|
||||||
user.CheckTalents(AbilityEffectType.OnItemDeconstructedMaterial, itemsCreated);
|
user.CheckTalents(AbilityEffectType.OnItemDeconstructedMaterial, itemsCreated);
|
||||||
amount = (int)itemsCreated.Value;
|
amount = (int)itemsCreated.Value;
|
||||||
|
|
||||||
|
// used to spawn items directly into the deconstructor
|
||||||
|
var itemContainer = new AbilityItemPrefabItem(item, targetItem.Prefab);
|
||||||
|
user.CheckTalents(AbilityEffectType.OnItemDeconstructedInventory, itemContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < amount; i++)
|
for (int i = 0; i < amount; i++)
|
||||||
@@ -256,17 +270,6 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user != null && !user.Removed)
|
|
||||||
{
|
|
||||||
var deconstructItemRetainProbability = new AbilityValueItem(0f, targetItem.Prefab);
|
|
||||||
user.CheckTalents(AbilityEffectType.OnItemDeconstructedRetainProbability, deconstructItemRetainProbability);
|
|
||||||
|
|
||||||
if (deconstructItemRetainProbability.Value > Rand.Range(0f, 1f, Rand.RandSync.Unsynced))
|
|
||||||
{
|
|
||||||
allowRemove = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetItem.AllowDeconstruct && allowRemove)
|
if (targetItem.AllowDeconstruct && allowRemove)
|
||||||
{
|
{
|
||||||
//drop all items that are inside the deconstructed item
|
//drop all items that are inside the deconstructed item
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const float TinkeringForceIncrease = 1.5f;
|
||||||
|
|
||||||
public Engine(Item item, XElement element)
|
public Engine(Item item, XElement element)
|
||||||
: base(item, element)
|
: base(item, element)
|
||||||
{
|
{
|
||||||
@@ -128,7 +130,7 @@ namespace Barotrauma.Items.Components
|
|||||||
currForce *= maxForce * forceMultiplier;
|
currForce *= maxForce * forceMultiplier;
|
||||||
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
||||||
{
|
{
|
||||||
currForce *= 2.5f;
|
currForce *= 1f + repairable.TinkeringStrength * TinkeringForceIncrease;
|
||||||
}
|
}
|
||||||
|
|
||||||
//less effective when in a bad condition
|
//less effective when in a bad condition
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ namespace Barotrauma.Items.Components
|
|||||||
[Serialize(1.0f, true)]
|
[Serialize(1.0f, true)]
|
||||||
public float SkillRequirementMultiplier { get; set; }
|
public float SkillRequirementMultiplier { get; set; }
|
||||||
|
|
||||||
|
private const float TinkeringSpeedIncrease = 1.5f;
|
||||||
|
|
||||||
private enum FabricatorState
|
private enum FabricatorState
|
||||||
{
|
{
|
||||||
Active = 1,
|
Active = 1,
|
||||||
@@ -279,7 +281,14 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (powerConsumption <= 0) { Voltage = 1.0f; }
|
if (powerConsumption <= 0) { Voltage = 1.0f; }
|
||||||
|
|
||||||
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f);
|
float tinkeringStrength = 0f;
|
||||||
|
if (repairable.IsTinkering)
|
||||||
|
{
|
||||||
|
tinkeringStrength = repairable.TinkeringStrength;
|
||||||
|
}
|
||||||
|
float fabricationSpeedIncrease = 1f + tinkeringStrength * TinkeringSpeedIncrease;
|
||||||
|
|
||||||
|
timeUntilReady -= deltaTime * fabricationSpeedIncrease * Math.Min(Voltage, 1.0f);
|
||||||
|
|
||||||
UpdateRequiredTimeProjSpecific();
|
UpdateRequiredTimeProjSpecific();
|
||||||
|
|
||||||
@@ -329,12 +338,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationValueItem);
|
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationValueItem);
|
||||||
|
|
||||||
float floatQuality = 0.0f;
|
quality = GetFabricatedItemQuality(fabricatedItem, user);
|
||||||
foreach (string tag in fabricatedItem.TargetItem.Tags)
|
|
||||||
{
|
|
||||||
floatQuality += user.Info.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag);
|
|
||||||
}
|
|
||||||
quality = (int)floatQuality;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var tempUser = user;
|
var tempUser = user;
|
||||||
@@ -404,6 +408,25 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetFabricatedItemQuality(FabricationRecipe fabricatedItem, Character user)
|
||||||
|
{
|
||||||
|
if (user == null) { return 0; }
|
||||||
|
if (fabricatedItem.TargetItem.ConfigElement.GetChildElement("Quality") == null) { return 0; }
|
||||||
|
int quality = 0;
|
||||||
|
float floatQuality = 0.0f;
|
||||||
|
foreach (string tag in fabricatedItem.TargetItem.Tags)
|
||||||
|
{
|
||||||
|
floatQuality += user.Info.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag);
|
||||||
|
}
|
||||||
|
quality = (int)floatQuality;
|
||||||
|
|
||||||
|
const int MaxCraftingSkill = 100;
|
||||||
|
|
||||||
|
quality += fabricatedItem.RequiredSkills.All(s => user.GetSkillLevel(s.Identifier) >= MaxCraftingSkill) ? 1 : 0;
|
||||||
|
quality += FabricationDegreeOfSuccess(user, fabricatedItem.RequiredSkills) >= 0.5f ? 1 : 0;
|
||||||
|
return quality;
|
||||||
|
}
|
||||||
|
|
||||||
partial void UpdateRequiredTimeProjSpecific();
|
partial void UpdateRequiredTimeProjSpecific();
|
||||||
|
|
||||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, Dictionary<string, List<Item>> availableIngredients, Character character)
|
private bool CanBeFabricated(FabricationRecipe fabricableItem, Dictionary<string, List<Item>> availableIngredients, Character character)
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ namespace Barotrauma.Items.Components
|
|||||||
public bool HasPower => IsActive && Voltage >= MinVoltage;
|
public bool HasPower => IsActive && Voltage >= MinVoltage;
|
||||||
public bool IsAutoControlled => pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
|
public bool IsAutoControlled => pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
|
||||||
|
|
||||||
|
private const float TinkeringSpeedIncrease = 1.5f;
|
||||||
|
|
||||||
public Pump(Item item, XElement element)
|
public Pump(Item item, XElement element)
|
||||||
: base(item, element)
|
: base(item, element)
|
||||||
{
|
{
|
||||||
@@ -108,7 +110,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
||||||
{
|
{
|
||||||
currFlow *= 2.5f;
|
currFlow *= 1f + repairable.TinkeringStrength * TinkeringSpeedIncrease;
|
||||||
}
|
}
|
||||||
|
|
||||||
//less effective when in a bad condition
|
//less effective when in a bad condition
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ namespace Barotrauma.Items.Components
|
|||||||
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.X * Physics.DisplayToRealWorldRatio) * 3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_x");
|
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.X * Physics.DisplayToRealWorldRatio) * 3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_x");
|
||||||
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.Y * Physics.DisplayToRealWorldRatio) * -3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_y");
|
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.Y * Physics.DisplayToRealWorldRatio) * -3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_y");
|
||||||
|
|
||||||
item.SendSignal(new Signal(sub.WorldPosition.X.ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_position_x");
|
item.SendSignal(new Signal((sub.WorldPosition.X * Physics.DisplayToRealWorldRatio).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_position_x");
|
||||||
item.SendSignal(new Signal(sub.RealWorldDepth.ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_position_y");
|
item.SendSignal(new Signal(sub.RealWorldDepth.ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_position_y");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user