0.1500.3.0 (🗿 edition)
This commit is contained in:
@@ -801,7 +801,11 @@ namespace Barotrauma
|
||||
{
|
||||
var treatmentButton = component.GetChild<GUIButton>();
|
||||
if (!(treatmentButton?.UserData is ItemPrefab itemPrefab)) { continue; }
|
||||
treatmentButton.Enabled = Character.Controlled.Inventory.AllItems.Any(it => it.prefab == itemPrefab);
|
||||
treatmentButton.Enabled = Character.Controlled.Inventory.AllItems.Any(it => it.prefab == itemPrefab);
|
||||
foreach (GUIComponent child in treatmentButton.Children)
|
||||
{
|
||||
child.Enabled = treatmentButton.Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1155,7 +1159,10 @@ namespace Barotrauma
|
||||
//key = item identifier
|
||||
//float = suitability
|
||||
Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
|
||||
GetSuitableTreatments(treatmentSuitability, normalize: true, limb: selectedLimbIndex == -1 ? null : Character.AnimController.Limbs.Find(l => l.HealthIndex == selectedLimbIndex));
|
||||
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())
|
||||
{
|
||||
@@ -1260,10 +1267,11 @@ namespace Barotrauma
|
||||
UserData = item
|
||||
};
|
||||
|
||||
var innerFrame = new GUIButton(new RectTransform(Vector2.One, itemSlot.RectTransform, Anchor.Center, Pivot.Center, scaleBasis: ScaleBasis.Smallest), style: "GUIButtonRound")
|
||||
var innerFrame = new GUIButton(new RectTransform(Vector2.One, itemSlot.RectTransform, Anchor.Center, Pivot.Center, scaleBasis: ScaleBasis.Smallest), style: "SubtreeHeader")
|
||||
{
|
||||
UserData = item,
|
||||
ToolTip = $"‖color:255,255,255,255‖{item.Name}‖color:end‖" + '\n' + item.Description,
|
||||
DisabledColor = Color.White * 0.1f,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (!(userdata is ItemPrefab itemPrefab)) { return false; }
|
||||
@@ -1274,6 +1282,17 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
new GUIImage(new RectTransform(Vector2.One, innerFrame.RectTransform, Anchor.Center), style: "TalentBackgroundGlow")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = Color.White * 0.7f,
|
||||
HoverColor = Color.White,
|
||||
PressedColor = Color.DarkGray,
|
||||
SelectedColor = Color.Transparent,
|
||||
DisabledColor = Color.Transparent
|
||||
};
|
||||
|
||||
Sprite itemSprite = item.InventoryIcon ?? item.sprite;
|
||||
Color itemColor = itemSprite == item.sprite ? item.SpriteColor : item.InventoryIconColor;
|
||||
var itemIcon = new GUIImage(new RectTransform(new Vector2(0.8f, 0.8f), innerFrame.RectTransform, Anchor.Center),
|
||||
@@ -1283,7 +1302,7 @@ namespace Barotrauma
|
||||
Color = itemColor * 0.9f,
|
||||
HoverColor = itemColor,
|
||||
SelectedColor = itemColor,
|
||||
DisabledColor = itemColor * 0.7f
|
||||
DisabledColor = itemColor * 0.8f
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1697,13 +1697,14 @@ namespace Barotrauma
|
||||
//check missing mission texts
|
||||
foreach (var missionPrefab in MissionPrefab.List)
|
||||
{
|
||||
string nameIdentifier = "missionname." + missionPrefab.Identifier;
|
||||
string missionId = (missionPrefab.ConfigElement.Attribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeString("textidentifier", string.Empty));
|
||||
string nameIdentifier = "missionname." + missionId;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
string descriptionIdentifier = "missiondescription." + missionPrefab.Identifier;
|
||||
string descriptionIdentifier = "missiondescription." + missionId;
|
||||
if (!tags[language].Contains(descriptionIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
|
||||
@@ -1713,6 +1714,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
|
||||
{
|
||||
if (sub.Type != SubmarineType.Player) { continue; }
|
||||
string nameIdentifier = "submarine.name." + sub.Name.ToLowerInvariant();
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
@@ -1729,14 +1731,23 @@ namespace Barotrauma
|
||||
|
||||
foreach (AfflictionPrefab affliction in AfflictionPrefab.List)
|
||||
{
|
||||
string nameIdentifier = "afflictionname." + affliction.Identifier;
|
||||
if (affliction.ShowIconThreshold > affliction.MaxStrength &&
|
||||
affliction.ShowIconToOthersThreshold > affliction.MaxStrength &&
|
||||
affliction.ShowInHealthScannerThreshold > affliction.MaxStrength)
|
||||
{
|
||||
//hidden affliction, no need for localization
|
||||
continue;
|
||||
}
|
||||
|
||||
string afflictionId = affliction.TranslationOverride ?? affliction.Identifier;
|
||||
string nameIdentifier = "afflictionname." + afflictionId;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
|
||||
string descriptionIdentifier = "afflictiondescription." + affliction.Identifier;
|
||||
string descriptionIdentifier = "afflictiondescription." + afflictionId;
|
||||
if (!tags[language].Contains(descriptionIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
|
||||
@@ -1744,6 +1755,29 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var talentTree in TalentTree.JobTalentTrees)
|
||||
{
|
||||
foreach (var talentSubTree in talentTree.Value.TalentSubTrees)
|
||||
{
|
||||
string nameIdentifier = "talenttree." + talentSubTree.Identifier;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var talent in TalentPrefab.TalentPrefabs)
|
||||
{
|
||||
string nameIdentifier = "talentname." + talent.Identifier;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
}
|
||||
|
||||
//check missing entity names
|
||||
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||
{
|
||||
|
||||
@@ -41,11 +41,14 @@ namespace Barotrauma
|
||||
public SpriteSheet SavingIndicator { get; private set; }
|
||||
|
||||
public UISprite UIGlow { get; private set; }
|
||||
public UISprite TalentGlow { get; private set; }
|
||||
|
||||
public UISprite PingCircle { get; private set; }
|
||||
|
||||
public UISprite UIGlowCircular { get; private set; }
|
||||
|
||||
public UISprite UIGlowSolidCircular { get; private set; }
|
||||
|
||||
public UISprite ButtonPulse { get; private set; }
|
||||
|
||||
public SpriteSheet FocusIndicator { get; private set; }
|
||||
@@ -88,6 +91,12 @@ namespace Barotrauma
|
||||
public Color TextColorDark { get; private set; } = Color.Black * 0.9f;
|
||||
public Color TextColorDim { get; private set; } = Color.White * 0.6f;
|
||||
|
||||
public Color ItemQualityColorPoor { get; private set; } = Color.Gray;
|
||||
public Color ItemQualityColorNormal { get; private set; } = Color.White;
|
||||
public Color ItemQualityColorGood { get; private set; } = Color.LightGreen;
|
||||
public Color ItemQualityColorExcellent { get; private set; } = Color.LightBlue;
|
||||
public Color ItemQualityColorMasterwork { get; private set; } = Color.MediumPurple;
|
||||
|
||||
public Color ColorReputationVeryLow { get; private set; } = Color.Red;
|
||||
public Color ColorReputationLow { get; private set; } = Color.Orange;
|
||||
public Color ColorReputationNeutral { get; private set; } = Color.White * 0.8f;
|
||||
@@ -241,6 +250,9 @@ namespace Barotrauma
|
||||
case "uiglow":
|
||||
UIGlow = new UISprite(subElement);
|
||||
break;
|
||||
case "talentglow":
|
||||
TalentGlow = new UISprite(subElement);
|
||||
break;
|
||||
case "pingcircle":
|
||||
PingCircle = new UISprite(subElement);
|
||||
break;
|
||||
@@ -253,6 +265,9 @@ namespace Barotrauma
|
||||
case "uiglowcircular":
|
||||
UIGlowCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "uiglowsolidcircular":
|
||||
UIGlowSolidCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "endroundbuttonpulse":
|
||||
ButtonPulse = new UISprite(subElement);
|
||||
break;
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Barotrauma
|
||||
|
||||
private readonly object loadMutex = new object();
|
||||
private float? loadState;
|
||||
|
||||
|
||||
public float? LoadState
|
||||
{
|
||||
get
|
||||
@@ -90,8 +90,8 @@ namespace Barotrauma
|
||||
{
|
||||
return loadState;
|
||||
}
|
||||
}
|
||||
set
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (loadMutex)
|
||||
{
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma
|
||||
GameMain.Config.EnableSplashScreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var titleStyle = GUI.Style?.GetComponentStyle("TitleText");
|
||||
Sprite titleSprite = null;
|
||||
if (!WaitForLanguageSelection && titleStyle != null && titleStyle.Sprites.ContainsKey(GUIComponent.ComponentState.None))
|
||||
@@ -177,8 +177,8 @@ namespace Barotrauma
|
||||
color: Color.White * noiseStrength * 0.1f,
|
||||
textureScale: Vector2.One * noiseScale);
|
||||
|
||||
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
|
||||
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
|
||||
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
|
||||
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
|
||||
scale: GameMain.GraphicsHeight / 2000.0f);
|
||||
|
||||
if (WaitForLanguageSelection)
|
||||
@@ -211,6 +211,13 @@ namespace Barotrauma
|
||||
if (LoadState != null)
|
||||
{
|
||||
loadText += " " + (int)LoadState + " %";
|
||||
|
||||
#if DEBUG
|
||||
if (GameMain.FirstLoad && GameMain.CancelQuickStart)
|
||||
{
|
||||
loadText += " (Quickstart aborted)";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (GUI.LargeFont != null)
|
||||
@@ -265,7 +272,7 @@ namespace Barotrauma
|
||||
decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.001f, GameMain.GraphicsHeight * 0.24f),
|
||||
Color.White, Vector2.Zero, 0.0f, decorativeScale, SpriteEffects.FlipVertically);
|
||||
|
||||
|
||||
decorativeMap.Draw(spriteBatch, (int)(decorativeMap.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.66f),
|
||||
Color.White, decorativeMap.FrameSize.ToVector2(), 0.0f, decorativeScale);
|
||||
@@ -281,9 +288,9 @@ namespace Barotrauma
|
||||
}
|
||||
else if (noiseVal < 0.5f)
|
||||
{
|
||||
randText =
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
randText =
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0');
|
||||
}
|
||||
@@ -299,12 +306,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (languageSelectionFont == null)
|
||||
{
|
||||
languageSelectionFont = new ScalableFont("Content/Fonts/NotoSans/NotoSans-Bold.ttf",
|
||||
languageSelectionFont = new ScalableFont("Content/Fonts/NotoSans/NotoSans-Bold.ttf",
|
||||
(uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice);
|
||||
}
|
||||
if (languageSelectionFontCJK == null)
|
||||
{
|
||||
languageSelectionFontCJK = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
|
||||
languageSelectionFontCJK = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
|
||||
(uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice, dynamicLoading: true);
|
||||
}
|
||||
if (languageSelectionCursor == null)
|
||||
@@ -320,11 +327,11 @@ namespace Barotrauma
|
||||
var font = TextManager.IsCJK(localizedLanguageName) ? languageSelectionFontCJK : languageSelectionFont;
|
||||
|
||||
Vector2 textSize = font.MeasureString(localizedLanguageName);
|
||||
bool hover =
|
||||
Math.Abs(PlayerInput.MousePosition.X - textPos.X) < textSize.X / 2 &&
|
||||
bool hover =
|
||||
Math.Abs(PlayerInput.MousePosition.X - textPos.X) < textSize.X / 2 &&
|
||||
Math.Abs(PlayerInput.MousePosition.Y - textPos.Y) < textSpacing.Y / 2;
|
||||
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
|
||||
hover ? Color.White : Color.White * 0.6f);
|
||||
if (hover && PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
@@ -394,14 +401,14 @@ namespace Barotrauma
|
||||
LoadState = null;
|
||||
SetSelectedTip(TextManager.Get("LoadingScreenTip", true));
|
||||
currentBackgroundTexture = LocationType.List.GetRandom()?.GetPortrait(Rand.Int(int.MaxValue))?.Texture;
|
||||
|
||||
|
||||
while (!drawn)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
CoroutineManager.StartCoroutine(loader);
|
||||
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
while (CoroutineManager.IsCoroutineRunning(loader.ToString()))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
@@ -18,8 +19,8 @@ namespace Barotrauma
|
||||
private static UISprite spectateIcon, disconnectedIcon;
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
private enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine, Talents };
|
||||
private static InfoFrameTab selectedTab;
|
||||
public enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine, Talents };
|
||||
public static InfoFrameTab selectedTab;
|
||||
private GUIFrame infoFrame, contentFrame;
|
||||
|
||||
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
||||
@@ -48,7 +49,7 @@ namespace Barotrauma
|
||||
private readonly GUIFrame frame;
|
||||
|
||||
public LinkedGUI(Client client, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
|
||||
{
|
||||
{
|
||||
this.client = client;
|
||||
this.textBlock = textBlock;
|
||||
this.frame = frame;
|
||||
@@ -262,7 +263,11 @@ namespace Barotrauma
|
||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.talents");
|
||||
talentsButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
|
||||
{
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null && GameMain.GameSession?.Campaign != null;
|
||||
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)
|
||||
{
|
||||
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -417,7 +422,7 @@ namespace Barotrauma
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
CreateMultiPlayerList(false);
|
||||
CreateMultiPlayerLogContent(crewFrame);
|
||||
CreateMultiPlayerLogContent(crewFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -608,7 +613,7 @@ namespace Barotrauma
|
||||
AbsoluteSpacing = 2
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
@@ -837,7 +842,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static readonly List<Pair<string, PlayerConnectionChangeType>> storedMessages = new List<Pair<string, PlayerConnectionChangeType>>();
|
||||
|
||||
|
||||
public static void StorePlayerConnectionChangeMessage(ChatMessage message)
|
||||
{
|
||||
if (!GameMain.GameSession?.IsRunning ?? true) { return; }
|
||||
@@ -850,7 +855,7 @@ namespace Barotrauma
|
||||
TabMenu instance = GameSession.TabMenuInstance;
|
||||
instance.AddLineToLog(msg, message.ChangeType);
|
||||
instance.RemoveCurrentElements();
|
||||
instance.CreateMultiPlayerList(true);
|
||||
instance.CreateMultiPlayerList(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -969,7 +974,7 @@ namespace Barotrauma
|
||||
GUIFrame missionDescriptionHolder = new GUIFrame(new RectTransform(Vector2.One, missionList.Content.RectTransform), style: null);
|
||||
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(iconSize + spacing, 0) }, false, childAnchor: Anchor.TopLeft)
|
||||
{
|
||||
AbsoluteSpacing = spacing
|
||||
AbsoluteSpacing = spacing
|
||||
};
|
||||
string descriptionText = mission.Description;
|
||||
foreach (string missionMessage in mission.ShownMessages)
|
||||
@@ -997,7 +1002,7 @@ namespace Barotrauma
|
||||
float ySize = missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y + missionReputationSize.Y + missionTextGroup.AbsoluteSpacing * 4;
|
||||
bool displayDifficulty = mission.Difficulty.HasValue;
|
||||
if (displayDifficulty) { ySize += missionRewardSize.Y; }
|
||||
|
||||
|
||||
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)ySize);
|
||||
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
@@ -1008,8 +1013,8 @@ namespace Barotrauma
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);*/
|
||||
|
||||
new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
{
|
||||
new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
{
|
||||
Color = mission.Prefab.IconColor,
|
||||
HoverColor = mission.Prefab.IconColor,
|
||||
SelectedColor = mission.Prefab.IconColor,
|
||||
@@ -1174,19 +1179,38 @@ namespace Barotrauma
|
||||
private Color unselectableColor = new Color(100, 100, 100, 225);
|
||||
private Color pressedColor = new Color(60, 60, 60, 225);
|
||||
|
||||
private readonly List<(GUIButton button, GUIImage background, GUIImage icon)> talentButtons = new List<(GUIButton button, GUIImage background, GUIImage icon)>();
|
||||
private readonly List<(GUIButton button, GUIComponent icon, GUIImage glow)> talentButtons = new List<(GUIButton button, GUIComponent icon, GUIImage glow)>();
|
||||
private readonly List<(string talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)> talentCornerIcons = new List<(string talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)>();
|
||||
private List<string> selectedTalents = new List<string>();
|
||||
private GUITextBlock talentTitleText;
|
||||
private GUITextBlock talentDescriptionText;
|
||||
private GUITextBlock talentPointsText;
|
||||
|
||||
private GUITextBlock experienceText;
|
||||
private GUIProgressBar experienceBar;
|
||||
private GUITextBlock talentPointText;
|
||||
private GUIListBox skillListBox;
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, GUIComponentStyle> talentStageStyles = new Dictionary<TalentTree.TalentTreeStageState, GUIComponentStyle>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Locked, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, GUI.Style.GetComponentStyle("TalentTreePurchased") },
|
||||
{ TalentTree.TalentTreeStageState.Available, GUI.Style.GetComponentStyle("TalentTreeUnlocked") },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, GUI.Style.GetComponentStyle("TalentTreeAvailable") },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, Color> talentStageBackgroundColors = new Dictionary<TalentTree.TalentTreeStageState, Color>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Locked, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, new Color(24,37,31,255) },
|
||||
{ TalentTree.TalentTreeStageState.Available, new Color(50,47,33,255) },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, new Color(50,47,33,255) },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private void CreateTalentInfo(GUIFrame infoFrame)
|
||||
{
|
||||
infoFrame.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter == null) { return; }
|
||||
@@ -1195,6 +1219,8 @@ namespace Barotrauma
|
||||
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 paddedTalentFrame = new GUIFrame(new RectTransform(new Vector2(0.9f), talentFrameContent.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
if (controlledCharacter.Info == null)
|
||||
{
|
||||
DebugConsole.ThrowError("No character info found for talent UI");
|
||||
@@ -1203,87 +1229,103 @@ namespace Barotrauma
|
||||
|
||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
||||
|
||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameContent.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), paddedTalentFrame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
|
||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.325f), talentFrameLayoutGroup.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter);
|
||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
|
||||
|
||||
GUIFrame talentTitleFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), talentInfoLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
CharacterInfo info = controlledCharacter.Info;
|
||||
Job job = info.Job;
|
||||
|
||||
talentTitleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), talentTitleFrame.RectTransform, Anchor.TopLeft), "", font: GUI.LargeFont);
|
||||
talentPointsText = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), talentTitleFrame.RectTransform, Anchor.TopRight), "", font: GUI.Font, textAlignment: Alignment.Center);
|
||||
|
||||
GUIFrame talentDescriptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.4f), talentInfoLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
|
||||
talentDescriptionText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), talentDescriptionFrame.RectTransform, Anchor.TopLeft), "", font: GUI.Font, textAlignment: Alignment.TopLeft, wrap: true);
|
||||
|
||||
GUIFrame characterInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.3f), talentInfoLayoutGroup.RectTransform, Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup characterInfoColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), characterInfoFrame.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopLeft, isHorizontal: true);
|
||||
|
||||
// move to a different tab menu
|
||||
if (GameSettings.VerboseLogging)
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
||||
{
|
||||
CreateCharacterSheet(characterInfoColumn);
|
||||
}
|
||||
float posY = component.Rect.Bottom - component.Rect.Width;
|
||||
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));
|
||||
|
||||
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 };
|
||||
nameBlock.RectTransform.NonScaledSize = nameSize.Pad(nameBlock.Padding).ToPoint();
|
||||
|
||||
Vector2 jobSize = GUI.SmallFont.MeasureString(job.Name);
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUI.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
|
||||
|
||||
string traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + info.PersonalityTrait.Name.Replace(" ", "")));
|
||||
Vector2 traitSize = GUI.SmallFont.MeasureString(traitString);
|
||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUI.SmallFont);
|
||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||
|
||||
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.375f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true };
|
||||
|
||||
string skillString = TextManager.Get("skills");
|
||||
Vector2 skillSize = GUI.SubHeadingFont.MeasureString(skillString);
|
||||
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(Vector2.One, skillLayout.RectTransform), skillString, font: GUI.SubHeadingFont);
|
||||
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
|
||||
|
||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.6f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
||||
|
||||
int spacing = GUI.IntScale(5);
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
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);
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: "SubtreeHeader");
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), subtreeTitleFrame.RectTransform, anchor: Anchor.TopCenter), subTree.Identifier, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
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");
|
||||
new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: "TalentOptionFrame");
|
||||
GUIImage talentBackground = new GUIImage(new RectTransform(Vector2.One, talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground")
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
|
||||
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 };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.25f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight), style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = unselectableColor,
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
|
||||
if (subTree.TalentOptionStages.Count > i)
|
||||
{
|
||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), talentOptionFrame.RectTransform, Anchor.CenterLeft), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
};
|
||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
foreach (TalentPrefab talent in talentOption.Talents)
|
||||
{
|
||||
int optionPadding = GUI.IntScale(10);
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(new Point(talentOptionFrame.Rect.Width, talentOptionFrame.Rect.Height - optionPadding), talentOptionLayoutGroup.RectTransform), style: null)
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentOptionLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
new GUIImage(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: "TalentFrameBackground")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
GUIImage iconImage = null;
|
||||
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: "TalentFrame")
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||
{
|
||||
ToolTip = $"{talent.DisplayName}\n\n{talent.Description}",
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
talentTitleText.Text = talent.DisplayName;
|
||||
talentDescriptionText.Text = talent.Description;
|
||||
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (GUIButton guiButton in talentOptionLayoutGroup.GetAllChildren<GUIButton>())
|
||||
{
|
||||
@@ -1314,61 +1356,129 @@ namespace Barotrauma
|
||||
},
|
||||
};
|
||||
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = Color.Transparent;
|
||||
|
||||
int iconPadding = GUI.IntScale(15);
|
||||
iconImage = new GUIImage(new RectTransform(new Point(talentFrame.Rect.Width - iconPadding, talentFrame.Rect.Height - iconPadding), talentFrame.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
GUIComponent iconImage;
|
||||
if (talent.Icon is null)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), text: "???", font: GUI.LargeFont, textAlignment: Alignment.Center, style: null)
|
||||
{
|
||||
OutlineColor = GUI.Style.Red,
|
||||
TextColor = GUI.Style.Red,
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
|
||||
talentButtons.Add((talentButton, talentBackground, iconImage));
|
||||
GUIImage iconGlow = new GUIImage(new RectTransform(Vector2.One, iconImage.RectTransform, anchor: Anchor.Center), sprite: GUI.Style.TalentGlow.Sprite, scaleToFit: true) { Visible = false };
|
||||
|
||||
talentButtons.Add((talentButton, iconImage, iconGlow));
|
||||
}
|
||||
|
||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUIFrame talentBottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(0.775f, 0.75f), talentBottomFrame.RectTransform, Anchor.TopCenter), style: null);
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.775f, 1f), talentBottomFrame.RectTransform));
|
||||
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),
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: Color.White, style: "ExperienceBar")
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUI.Style.Green)
|
||||
{
|
||||
IsHorizontal = true
|
||||
};
|
||||
|
||||
GUIImage experienceTextBackground = new GUIImage(new RectTransform(new Vector2(0.2f, 0.475f), experienceBarFrame.RectTransform, anchor: Anchor.Center), style: "ExperienceTextBackground");
|
||||
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), experienceTextBackground.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textColor: Color.White, textAlignment: Alignment.Center);
|
||||
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, 0.3f), talentBottomFrame.RectTransform, anchor: Anchor.TopRight), text: TextManager.Get("applysettingsbutton"))
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 0.3f), talentBottomFrame.RectTransform, anchor: Anchor.TopLeft), text: TextManager.Get("reset"))
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUICharacterInfoButton")
|
||||
{
|
||||
OnClicked = ResetTalentSelection,
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUICharacterInfoButton")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
||||
{
|
||||
parent.Content.ClearChildren();
|
||||
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 };
|
||||
|
||||
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) };
|
||||
|
||||
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
||||
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
||||
{
|
||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
||||
string stringColor = true switch
|
||||
{
|
||||
true when skillChange > 0 => XMLExtensions.ColorToString(GUI.Style.Green),
|
||||
true when skillChange < 0 => XMLExtensions.ColorToString(GUI.Style.Red),
|
||||
_ => XMLExtensions.ColorToString(GUI.Style.TextColor)
|
||||
};
|
||||
|
||||
string changeText = $"(‖color:{stringColor}‖{(skillChange > 0 ? "+" : string.Empty) + skillChange}‖color:end‖)";
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), changeText, parseRichText: true) { Padding = Vector4.Zero };
|
||||
}
|
||||
skillContainer.Recalculate();
|
||||
}
|
||||
|
||||
parent.RecalculateChildren();
|
||||
}
|
||||
|
||||
private void UpdateTalentButtons()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
talentPointsText.Text = $"{TextManager.Get("talentpointsleft")}{controlledCharacter.Info.GetAvailableTalentPoints()}";
|
||||
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
|
||||
//experienceBar.ToolTip = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
string pointsLeft = controlledCharacter.Info.GetAvailableTalentPoints().ToString();
|
||||
|
||||
int talentCount = selectedTalents.Count - controlledCharacter.Info.UnlockedTalents.Count;
|
||||
|
||||
if (talentCount > 0)
|
||||
{
|
||||
talentButton.background.Color = unselectableColor;
|
||||
string pointsUsed = $"‖color:{XMLExtensions.ColorToString(GUI.Style.Red)}‖{-talentCount}‖color:end‖";
|
||||
string localizedString = TextManager.GetWithVariables("talentmenu.points.spending", new []{ "[amount]", "[used]" }, new []{ pointsLeft, pointsUsed});
|
||||
talentPointText.SetRichText(localizedString);
|
||||
}
|
||||
else
|
||||
{
|
||||
talentPointText.SetRichText(TextManager.GetWithVariable("talentmenu.points", "[amount]", pointsLeft));
|
||||
}
|
||||
|
||||
foreach (var (talentTree, index, icon, frame, glow) in talentCornerIcons)
|
||||
{
|
||||
TalentTree.TalentTreeStageState state = TalentTree.GetTalentOptionStageState(controlledCharacter, talentTree, index, selectedTalents);
|
||||
GUIComponentStyle newStyle = talentStageStyles[state];
|
||||
icon.ApplyStyle(newStyle);
|
||||
icon.Color = newStyle.Color;
|
||||
frame.Color = talentStageBackgroundColors[state];
|
||||
glow.Visible = state == TalentTree.TalentTreeStageState.Highlighted;
|
||||
}
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
@@ -1377,30 +1487,23 @@ namespace Barotrauma
|
||||
bool unselectable = !TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents) || controlledCharacter.HasTalent(talentIdentifier);
|
||||
Color newTalentColor = unselectable ? unselectableColor : unselectedColor;
|
||||
|
||||
talentButton.glow.Visible = false;
|
||||
|
||||
if (controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
newTalentColor = ownedColor;
|
||||
newTalentColor = new Color(140,225,140,255);
|
||||
}
|
||||
else if (selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
newTalentColor = selectedColor;
|
||||
newTalentColor = new Color(174,164,124,255);
|
||||
talentButton.glow.Visible = true;
|
||||
}
|
||||
|
||||
talentButton.button.Color = newTalentColor;
|
||||
talentButton.button.SelectedColor = newTalentColor;
|
||||
talentButton.button.HoverColor = newTalentColor;
|
||||
talentButton.button.DisabledColor = newTalentColor;
|
||||
|
||||
talentButton.icon.Color = newTalentColor;
|
||||
|
||||
// update background color as well, if not defined yet
|
||||
if (talentButton.background.Color == unselectableColor)
|
||||
{
|
||||
talentButton.background.Color = newTalentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
}
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
{
|
||||
|
||||
@@ -194,6 +194,8 @@ namespace Barotrauma
|
||||
|
||||
#if DEBUG
|
||||
public static bool FirstLoad = true;
|
||||
|
||||
public static bool CancelQuickStart;
|
||||
#endif
|
||||
|
||||
public GameMain(string[] args)
|
||||
@@ -309,7 +311,7 @@ namespace Barotrauma
|
||||
|
||||
GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth;
|
||||
GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight;
|
||||
|
||||
|
||||
GraphicsDeviceManager.ApplyChanges();
|
||||
|
||||
if (windowMode == WindowMode.BorderlessWindowed)
|
||||
@@ -588,7 +590,7 @@ namespace Barotrauma
|
||||
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
|
||||
TitleScreen.LoadState = 55.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
|
||||
UpgradePrefab.LoadAll(GetFilesOfType(ContentType.UpgradeModules));
|
||||
TitleScreen.LoadState = 56.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -601,7 +603,7 @@ namespace Barotrauma
|
||||
ItemAssemblyPrefab.LoadAll();
|
||||
TitleScreen.LoadState = 60.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
|
||||
GameModePreset.Init();
|
||||
|
||||
SaveUtil.DeleteDownloadedSubs();
|
||||
@@ -654,7 +656,7 @@ namespace Barotrauma
|
||||
ParticleManager.LoadPrefabs();
|
||||
TitleScreen.LoadState = 88.0f;
|
||||
LevelObjectPrefab.LoadAll();
|
||||
|
||||
|
||||
TitleScreen.LoadState = 90.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -804,7 +806,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled || Config.TestScreenEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift))
|
||||
CancelQuickStart |= PlayerInput.KeyDown(Keys.LeftShift);
|
||||
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled || Config.TestScreenEnabled) && FirstLoad && !CancelQuickStart)
|
||||
{
|
||||
loadingScreenOpen = false;
|
||||
FirstLoad = false;
|
||||
@@ -812,7 +816,7 @@ namespace Barotrauma
|
||||
if (Config.TestScreenEnabled)
|
||||
{
|
||||
TestScreen.Select();
|
||||
}
|
||||
}
|
||||
else if (Config.AutomaticQuickStartEnabled)
|
||||
{
|
||||
MainMenuScreen.QuickStart();
|
||||
@@ -930,8 +934,8 @@ namespace Barotrauma
|
||||
static bool itemHudActive()
|
||||
{
|
||||
if (Character.Controlled?.SelectedConstruction == null) { return false; }
|
||||
return
|
||||
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
|
||||
return
|
||||
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
|
||||
((Character.Controlled.ViewTarget as Item)?.Prefab?.FocusOnSelected ?? false);
|
||||
}
|
||||
}
|
||||
@@ -1095,7 +1099,7 @@ namespace Barotrauma
|
||||
if (save)
|
||||
{
|
||||
GUI.SetSavingIndicatorState(true);
|
||||
|
||||
|
||||
if (GameSession.Submarine != null && !GameSession.Submarine.Removed)
|
||||
{
|
||||
GameSession.SubmarineInfo = new SubmarineInfo(GameSession.Submarine);
|
||||
@@ -1267,7 +1271,7 @@ namespace Barotrauma
|
||||
string text = TextManager.GetWithVariable("openlinkinbrowserprompt", "[link]", url);
|
||||
string extensionText = TextManager.Get(promptExtensionTag, returnNull: true, useEnglishAsFallBack: false);
|
||||
if (!string.IsNullOrEmpty(extensionText))
|
||||
{
|
||||
{
|
||||
text += $"\n\n{extensionText}";
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Barotrauma
|
||||
|
||||
ReportButtonFrame.RectTransform.AbsoluteOffset = new Point(0, -chatBox.ToggleButton.Rect.Height);
|
||||
|
||||
CreateReports(this, ReportButtonFrame, reports, false);
|
||||
CreateReportButtons(this, ReportButtonFrame, reports, false);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Barotrauma
|
||||
dismissedOrderPrefab ??= Order.GetPrefab("dismissed");
|
||||
}
|
||||
|
||||
public static void CreateReports(CrewManager crewManager, GUIComponent parent, List<Order> reports, bool isHorizontal)
|
||||
public static void CreateReportButtons(CrewManager crewManager, GUIComponent parent, List<Order> reports, bool isHorizontal)
|
||||
{
|
||||
//report buttons
|
||||
foreach (Order order in reports)
|
||||
@@ -228,22 +228,21 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (!CanIssueOrders) { return false; }
|
||||
if (!CanIssueOrders || crewManager?.DraggedOrder != null) { return false; }
|
||||
var sub = Character.Controlled.Submarine;
|
||||
if (sub == null || sub.TeamID != Character.Controlled.TeamID || sub.Info.IsWreck) { return false; }
|
||||
|
||||
if (crewManager != null)
|
||||
{
|
||||
crewManager.SetCharacterOrder(null, order, null, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
|
||||
if (crewManager.IsSinglePlayer) { HumanAIController.ReportProblem(Character.Controlled, order); }
|
||||
}
|
||||
return true;
|
||||
},
|
||||
UserData = order,
|
||||
ToolTip = order.Name,
|
||||
ClampMouseRectToParent = false
|
||||
};
|
||||
btn.ToolTip = $"‖color:{XMLExtensions.ColorToString(order.Prefab.Color)}‖{order.Name}‖color:end‖\n{TextManager.Get("draganddropreports")}";
|
||||
|
||||
if (crewManager != null)
|
||||
{
|
||||
@@ -272,8 +271,9 @@ namespace Barotrauma
|
||||
{
|
||||
Color = order.Color,
|
||||
HoverColor = Color.Lerp(order.Color, Color.White, 0.5f),
|
||||
ToolTip = order.Name,
|
||||
SpriteEffects = SpriteEffects.FlipHorizontally
|
||||
ToolTip = btn.RawToolTip,
|
||||
SpriteEffects = SpriteEffects.FlipHorizontally,
|
||||
UserData = order
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -717,7 +717,7 @@ namespace Barotrauma
|
||||
hull ??= orderGiver.CurrentHull;
|
||||
AddOrder(new Order(order.Prefab ?? order, hull, null, orderGiver), order.FadeOutTime);
|
||||
}
|
||||
else if(order.IsIgnoreOrder)
|
||||
else if (order.IsIgnoreOrder)
|
||||
{
|
||||
WallSection ws = null;
|
||||
if (order.TargetType == Order.OrderTargetType.Entity && order.TargetEntity is IIgnorable ignorable)
|
||||
|
||||
@@ -1232,7 +1232,7 @@ namespace Barotrauma
|
||||
highlightedQuickUseSlot = visualSlots[i];
|
||||
}
|
||||
|
||||
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any) || SlotTypes[i] == InvSlotType.HealthInterface)
|
||||
if (slots[i].First().AllowedSlots.Count() == 1 || SlotTypes[i] == InvSlotType.HealthInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Barotrauma.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Sounds;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -145,7 +146,9 @@ namespace Barotrauma.Items.Components
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
|
||||
|
||||
//camera focused on some other item/device, don't draw the crosshair
|
||||
if (character.ViewTarget != null && (character.ViewTarget is Item item) && item.Prefab.FocusOnSelected) { return; }
|
||||
if (character.ViewTarget != null && (character.ViewTarget is Item viewTargetItem) && viewTargetItem.Prefab.FocusOnSelected) { return; }
|
||||
//don't draw the crosshair if the item is in some other type of equip slot than hands (e.g. assault rifle in the bag slot)
|
||||
if (!character.HeldItems.Contains(item)) { return; }
|
||||
|
||||
GUI.HideCursor = (crosshairSprite != null || crosshairPointerSprite != null) &&
|
||||
GUI.MouseOn == null && !Inventory.IsMouseOnInventory && !GameMain.Instance.Paused;
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace Barotrauma.Items.Components
|
||||
if (UILabel == string.Empty) { return string.Empty; }
|
||||
if (UILabel != null)
|
||||
{
|
||||
return TextManager.Get("UILabel." + UILabel);
|
||||
return TextManager.Get("UILabel." + UILabel, returnNull: true) ?? TextManager.Get(UILabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private FabricationRecipe pendingFabricatedItem;
|
||||
|
||||
private Pair<Rectangle, string> tooltip;
|
||||
private (Rectangle area, string text)? tooltip;
|
||||
|
||||
private GUITextBlock requiredTimeBlock;
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace Barotrauma.Items.Components
|
||||
});
|
||||
|
||||
var sufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorsufficientskills", returnNull: true) ?? "Sufficient skills to fabricate", textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
|
||||
TextManager.Get("fabricatorsufficientskills"), textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
@@ -278,7 +278,7 @@ namespace Barotrauma.Items.Components
|
||||
sufficientSkillsText.RectTransform.SetAsFirstChild();
|
||||
|
||||
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorinsufficientskills", returnNull: true) ?? "Insufficient skills to fabricate", textColor: Color.Orange, font: GUI.SubHeadingFont)
|
||||
TextManager.Get("fabricatorinsufficientskills"), textColor: Color.Orange, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
@@ -290,7 +290,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorrequiresrecipe", returnNull: true) ?? "Requires recipe to fabricate", textColor: Color.Red, font: GUI.SubHeadingFont)
|
||||
TextManager.Get("fabricatorrequiresrecipe"), textColor: Color.Red, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
@@ -403,7 +403,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
toolTipText += '\n' + requiredItem.ItemPrefabs.First().Description;
|
||||
}
|
||||
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
|
||||
tooltip = (slotRect, toolTipText);
|
||||
}
|
||||
|
||||
slotIndex++;
|
||||
@@ -443,7 +443,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Value.text, tooltip.Value.area);
|
||||
tooltip = null;
|
||||
}
|
||||
}
|
||||
@@ -463,6 +463,22 @@ namespace Barotrauma.Items.Components
|
||||
if (recipe?.DisplayName == null) { continue; }
|
||||
child.Visible = recipe.DisplayName.ToLower().Contains(filter);
|
||||
}
|
||||
|
||||
//go through the elements backwards, and disable the labels ("insufficient skills to fabricate", "recipe required...") if there's no items below them
|
||||
bool recipeVisible = false;
|
||||
foreach (GUIComponent child in itemList.Content.Children.Reverse())
|
||||
{
|
||||
if (!(child.UserData is FabricationRecipe recipe))
|
||||
{
|
||||
child.Visible = recipeVisible;
|
||||
recipeVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
recipeVisible = child.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
itemList.UpdateScrollBarSize();
|
||||
itemList.BarScroll = 0.0f;
|
||||
|
||||
@@ -498,9 +514,20 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
}*/
|
||||
|
||||
string name = GetRecipeNameAndAmount(selectedItem);
|
||||
|
||||
float quality = 0;
|
||||
foreach (string tag in selectedItem.TargetItem.Tags)
|
||||
{
|
||||
quality += user?.Info?.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag) ?? 0;
|
||||
}
|
||||
if (quality > 0)
|
||||
{
|
||||
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", name+'\n', fallBackTag: "itemname.quality3");
|
||||
}
|
||||
|
||||
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||
GetRecipeNameAndAmount(selectedItem), textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont)
|
||||
name, textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont, parseRichText: true)
|
||||
{
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
@@ -218,8 +218,8 @@ namespace Barotrauma.Items.Components
|
||||
DefaultNeutralColor = MiniMapBaseColor * 0.8f,
|
||||
HoverColor = Color.White,
|
||||
BlueprintBlue = new Color(23, 38, 33),
|
||||
HullWaterColor = new Color(17, 173, 179),
|
||||
HullWaterLineColor = Color.LightBlue,
|
||||
HullWaterColor = new Color(17, 173, 179) * 0.5f,
|
||||
HullWaterLineColor = Color.LightBlue * 0.5f,
|
||||
NoPowerColor = MiniMapBaseColor * 0.1f,
|
||||
ElectricalBaseColor = GUI.Style.Orange,
|
||||
NoPowerElectricalColor = ElectricalBaseColor * 0.1f;
|
||||
@@ -307,10 +307,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (reports.Any())
|
||||
{
|
||||
CrewManager.CreateReports(GameMain.GameSession?.CrewManager, reportFrame, reports, true);
|
||||
CrewManager.CreateReportButtons(GameMain.GameSession?.CrewManager, reportFrame, reports, true);
|
||||
}
|
||||
|
||||
searchBarFrame = new GUILayoutGroup(new RectTransform(new Vector2(1), bottomFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
||||
searchBarFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.5f, 1.0f), bottomFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.Center)
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
searchBar = new GUITextBox(new RectTransform(new Vector2(1), searchBarFrame.RectTransform), string.Empty, createClearButton: true, createPenIcon: true)
|
||||
{
|
||||
OnEnterPressed = (box, text) =>
|
||||
@@ -345,6 +348,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (ItemPrefab prefab in ItemPrefab.Prefabs.OrderBy(prefab => prefab.Name))
|
||||
{
|
||||
if (prefab.HideInMenus) { continue; }
|
||||
CreateItemFrame(prefab, listBox.Content.RectTransform);
|
||||
}
|
||||
|
||||
@@ -355,7 +359,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
searchBar.OnSelected += (sender, key) =>
|
||||
{
|
||||
itemsFoundOnSub = Item.ItemList.Where(it => it.Submarine == item.Submarine && !it.NonInteractable && !it.HiddenInGame && it.Components.OfType<Holdable>().Any()).Select(it => it.Prefab).ToImmutableHashSet();
|
||||
itemsFoundOnSub = Item.ItemList.Where(it =>
|
||||
it.Submarine == item.Submarine &&
|
||||
!it.NonInteractable && !it.HiddenInGame &&
|
||||
(it.GetComponent<Holdable>() != null || it.GetComponent<Wearable>() != null)).Select(it => it.Prefab).ToImmutableHashSet();
|
||||
};
|
||||
|
||||
searchBar.OnKeyHit += ControlSearchTooltip;
|
||||
@@ -487,21 +494,24 @@ namespace Barotrauma.Items.Components
|
||||
CreateHUD();
|
||||
}
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonDown() && currentMode != MiniMapMode.HullStatus)
|
||||
if (scissorComponent != null)
|
||||
{
|
||||
if (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn))
|
||||
if (PlayerInput.PrimaryMouseButtonDown() && currentMode != MiniMapMode.HullStatus)
|
||||
{
|
||||
dragMapStart = PlayerInput.MousePosition;
|
||||
if (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn))
|
||||
{
|
||||
dragMapStart = PlayerInput.MousePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMode != MiniMapMode.HullStatus && Math.Abs(PlayerInput.ScrollWheelSpeed) > 0 && (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn)))
|
||||
{
|
||||
float newZoom = Math.Clamp(Zoom + PlayerInput.ScrollWheelSpeed / 1000.0f * Zoom, minZoom, maxZoom);
|
||||
float distanceScale = newZoom / Zoom;
|
||||
mapOffset *= distanceScale;
|
||||
recalculate |= !MathUtils.NearlyEqual(Zoom, newZoom);
|
||||
Zoom = newZoom;
|
||||
if (currentMode != MiniMapMode.HullStatus && Math.Abs(PlayerInput.ScrollWheelSpeed) > 0 && (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn)))
|
||||
{
|
||||
float newZoom = Math.Clamp(Zoom + PlayerInput.ScrollWheelSpeed / 1000.0f * Zoom, minZoom, maxZoom);
|
||||
float distanceScale = newZoom / Zoom;
|
||||
mapOffset *= distanceScale;
|
||||
recalculate |= !MathUtils.NearlyEqual(Zoom, newZoom);
|
||||
Zoom = newZoom;
|
||||
}
|
||||
}
|
||||
|
||||
if (dragMapStart is { } dragStart)
|
||||
@@ -524,15 +534,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (recalculate)
|
||||
{
|
||||
miniMapContainer.RectTransform.LocalScale = new Vector2(Zoom);
|
||||
miniMapContainer.RectTransform.RecalculateChildren(true, true);
|
||||
miniMapContainer.RectTransform.AbsoluteOffset = mapOffset.ToPoint();
|
||||
if (miniMapContainer != null)
|
||||
{
|
||||
miniMapContainer.RectTransform.LocalScale = new Vector2(Zoom);
|
||||
miniMapContainer.RectTransform.RecalculateChildren(true, true);
|
||||
miniMapContainer.RectTransform.AbsoluteOffset = mapOffset.ToPoint();
|
||||
}
|
||||
recalculate = false;
|
||||
|
||||
// var (maxWidth, maxHeight) = miniMapContainer.Rect.Size.ToVector2() / 2f;
|
||||
//
|
||||
// mapOffset.X = Math.Clamp(mapOffset.X, -maxWidth, maxWidth);
|
||||
// mapOffset.Y = Math.Clamp(mapOffset.Y, -maxHeight, maxHeight);
|
||||
}
|
||||
|
||||
// is there a better way to do this?
|
||||
@@ -606,17 +614,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void DrawHUDFront(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
{
|
||||
// TODO remove
|
||||
#warning remove
|
||||
if (currentMode == MiniMapMode.HullCondition)
|
||||
{
|
||||
const string wipText = "work in progress";
|
||||
Vector2 textSize = GUI.LargeFont.MeasureString(wipText);
|
||||
Vector2 textPos = GuiFrame.Rect.Center.ToVector2();
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos - textSize / 2, wipText.ToUpper(), GUI.Style.Orange, Color.Black * 0.8f, backgroundPadding: 8, font: GUI.LargeFont);
|
||||
}
|
||||
|
||||
if (Voltage < MinVoltage)
|
||||
{
|
||||
Vector2 textSize = GUI.Font.MeasureString(noPowerTip);
|
||||
@@ -627,18 +624,45 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentMode == MiniMapMode.HullStatus)
|
||||
if (currentMode == MiniMapMode.HullStatus || currentMode == MiniMapMode.HullCondition)
|
||||
{
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = submarineContainer.Rect;
|
||||
|
||||
foreach (var (entity, component) in hullStatusComponents)
|
||||
if (currentMode == MiniMapMode.HullCondition && item.Submarine != null)
|
||||
{
|
||||
if (!(entity is Hull hull)) { continue; }
|
||||
if (!hullDatas.TryGetValue(hull, out HullData? hullData) || hullData is null) { continue; }
|
||||
DrawHullCards(spriteBatch, hull, hullData, component.RectComponent);
|
||||
var sprite = GUI.Style.UIGlowSolidCircular?.Sprite;
|
||||
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
|
||||
if (sprite != null)
|
||||
{
|
||||
Vector2 spriteSize = sprite.size;
|
||||
Rectangle worldBorders = item.Submarine.GetDockedBorders();
|
||||
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
if (gap.IsRoomToRoom || gap.Submarine != item.Submarine || gap.ConnectedDoor != null) { continue; }
|
||||
RectangleF entityRect = ScaleRectToUI(gap, miniMapFrame.Rect, worldBorders);
|
||||
|
||||
Vector2 scale = new Vector2(entityRect.Size.X / spriteSize.X, entityRect.Size.Y / spriteSize.Y) * 2.0f;
|
||||
|
||||
Color color = ToolBox.GradientLerp(gap.Open, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorLow) * alpha;
|
||||
sprite.Draw(spriteBatch,
|
||||
miniMapFrame.Rect.Location.ToVector2() + entityRect.Center,
|
||||
color, origin: sprite.Origin, rotate: 0.0f, scale: scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMode == MiniMapMode.HullStatus)
|
||||
{
|
||||
foreach (var (entity, component) in hullStatusComponents)
|
||||
{
|
||||
if (!(entity is Hull hull)) { continue; }
|
||||
if (!hullDatas.TryGetValue(hull, out HullData? hullData) || hullData is null) { continue; }
|
||||
DrawHullCards(spriteBatch, hull, hullData, component.RectComponent);
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
@@ -721,14 +745,21 @@ namespace Barotrauma.Items.Components
|
||||
UserData = prefab
|
||||
};
|
||||
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
new GUIImage(new RectTransform(Vector2.One, layout.RectTransform, scaleBasis: ScaleBasis.BothHeight), sprite)
|
||||
{
|
||||
Color = prefab.InventoryIconColor
|
||||
Color = prefab.InventoryIconColor,
|
||||
UserData = prefab
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(Vector2.One, layout.RectTransform), prefab.Name, font: GUI.SubHeadingFont);
|
||||
layout.UserData = prefab;
|
||||
var nameText = new GUITextBlock(new RectTransform(Vector2.One, layout.RectTransform), prefab.Name);
|
||||
nameText.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
nameText.Text = ToolBox.LimitString(prefab.Name, nameText.Font, nameText.Rect.Width);
|
||||
};
|
||||
}
|
||||
|
||||
private void SearchItems(string text)
|
||||
@@ -792,15 +823,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void UpdateHUDBack()
|
||||
{
|
||||
if (item.Submarine == null) { return; }
|
||||
|
||||
hullInfoFrame.Visible = false;
|
||||
electricalFrame.Visible = false;
|
||||
miniMapFrame.Visible = false;
|
||||
reportFrame.Visible = false;
|
||||
searchBarFrame.Visible = false;
|
||||
electricalFrame.Visible = false;
|
||||
miniMapFrame.Visible = false;
|
||||
|
||||
switch (currentMode)
|
||||
{
|
||||
case MiniMapMode.HullStatus:
|
||||
case MiniMapMode.HullCondition:
|
||||
UpdateHullStatus();
|
||||
miniMapFrame.Visible = true;
|
||||
reportFrame.Visible = true;
|
||||
@@ -937,16 +971,19 @@ namespace Barotrauma.Items.Components
|
||||
SetTooltip(borderComponent.Rect.Center, header, line1, line2, line3, line1Color, line2Color, line3Color);
|
||||
}
|
||||
|
||||
bool draggingReport = GameMain.GameSession?.CrewManager?.DraggedOrder != null;
|
||||
// When setting the colors we want to know the linked hulls too or else the linked hull will not realize its being hovered over and reset the border color
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
if (!hullStatusComponents.ContainsKey(linkedHull)) { continue; }
|
||||
|
||||
isHoveringOver |= canHoverOverHull && hullStatusComponents[linkedHull].RectComponent == GUI.MouseOn;
|
||||
isHoveringOver |=
|
||||
canHoverOverHull &&
|
||||
(hullStatusComponents[linkedHull].RectComponent == GUI.MouseOn || (draggingReport && hullStatusComponents[linkedHull].RectComponent.MouseRect.Contains(PlayerInput.MousePosition)));
|
||||
if (isHoveringOver) { break; }
|
||||
}
|
||||
|
||||
if (isHoveringOver)
|
||||
if (isHoveringOver || (draggingReport && component.MouseRect.Contains(PlayerInput.MousePosition)))
|
||||
{
|
||||
borderColor = Color.Lerp(borderColor, Color.White, 0.5f);
|
||||
componentColor = HoverColor;
|
||||
@@ -1037,7 +1074,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hullsVisible = currentMode == MiniMapMode.HullStatus;
|
||||
bool hullsVisible = currentMode == MiniMapMode.HullStatus || currentMode == MiniMapMode.HullCondition;
|
||||
|
||||
foreach (var (entity, component) in hullStatusComponents)
|
||||
{
|
||||
@@ -1150,7 +1187,7 @@ namespace Barotrauma.Items.Components
|
||||
GameMain.GameScreen.BlueprintEffect.Parameters["width"].SetValue((float)texture.Width);
|
||||
GameMain.GameScreen.BlueprintEffect.Parameters["height"].SetValue((float)texture.Height);
|
||||
|
||||
Color blueprintBlue = BlueprintBlue * currentMode switch { MiniMapMode.HullStatus => 0.1f, MiniMapMode.ElectricalView => 0.1f, _ => 0.5f };
|
||||
Color blueprintBlue = BlueprintBlue * currentMode switch { MiniMapMode.HullStatus => 0.1f, MiniMapMode.HullCondition => 0.1f, MiniMapMode.ElectricalView => 0.1f, _ => 0.5f };
|
||||
|
||||
Vector2 origin = new Vector2(texture.Width / 2f, texture.Height / 2f);
|
||||
float scale = currentMode == MiniMapMode.HullStatus ? 1.0f : Zoom;
|
||||
|
||||
@@ -19,9 +19,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private GUIProgressBar progressBar;
|
||||
|
||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private GUITextBlock progressBarOverlayText;
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
//the corresponding particle emitter is active when the condition is within this range
|
||||
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
private readonly List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
|
||||
private SoundChannel repairSoundChannel;
|
||||
|
||||
@@ -88,7 +90,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.75f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
@@ -123,6 +125,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
progressBar = new GUIProgressBar(new RectTransform(new Vector2(0.6f, 1.0f), progressBarHolder.RectTransform),
|
||||
color: GUI.Style.Green, barSize: 0.0f, style: "DeviceProgressBar");
|
||||
progressBarOverlayText = new GUITextBlock(new RectTransform(Vector2.One, progressBar.RectTransform), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
|
||||
repairButtonText = TextManager.Get("RepairButton");
|
||||
repairingText = TextManager.Get("Repairing");
|
||||
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
|
||||
@@ -138,6 +145,7 @@ namespace Barotrauma.Items.Components
|
||||
progressBarHolder.RectTransform.MinSize = RepairButton.RectTransform.MinSize;
|
||||
RepairButton.RectTransform.MinSize = new Point((int)(RepairButton.TextBlock.TextSize.X * 1.2f), RepairButton.RectTransform.MinSize.Y);
|
||||
|
||||
|
||||
sabotageButtonText = TextManager.Get("SabotageButton");
|
||||
sabotagingText = TextManager.Get("Sabotaging");
|
||||
SabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText, style: "GUIButtonSmall")
|
||||
@@ -229,9 +237,23 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
progressBar.BarSize = item.Condition / item.MaxCondition;
|
||||
float defaultMaxCondition = (item.MaxCondition / item.MaxRepairConditionMultiplier);
|
||||
|
||||
progressBar.BarSize = item.Condition / defaultMaxCondition;
|
||||
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green);
|
||||
|
||||
if (item.Condition > defaultMaxCondition)
|
||||
{
|
||||
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
|
||||
progressBar.Color = ToolBox.GradientLerp((item.Condition - defaultMaxCondition) / extraCondition, GUI.Style.ColorReputationHigh, GUI.Style.ColorReputationVeryHigh);
|
||||
progressBarOverlayText.Visible = true;
|
||||
progressBarOverlayText.Text = $"{(int)Math.Round((item.Condition / defaultMaxCondition) * 100)}%";
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBarOverlayText.Visible = false;
|
||||
}
|
||||
|
||||
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition;
|
||||
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
|
||||
repairButtonText :
|
||||
|
||||
@@ -316,12 +316,17 @@ namespace Barotrauma
|
||||
|
||||
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||
|
||||
if (item.Quality > 0)
|
||||
{
|
||||
name = TextManager.GetWithVariable("itemname.quality" + item.Quality, "[itemname]", name, fallBackTag: "itemname.quality3");
|
||||
}
|
||||
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
||||
|
||||
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
|
||||
{
|
||||
toolTip += " " + TextManager.Get("connectionlocked");
|
||||
}
|
||||
if (!item.IsFullCondition && !item.Prefab.HideConditionBar)
|
||||
if (!item.IsFullCondition && !item.Prefab.HideConditionInTooltip)
|
||||
{
|
||||
string conditionColorStr = XMLExtensions.ColorToString(ToolBox.GradientLerp(item.Condition / item.MaxCondition, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull));
|
||||
toolTip += $"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
|
||||
|
||||
@@ -1068,7 +1068,7 @@ namespace Barotrauma
|
||||
foreach (Character otherCharacter in Character.CharacterList)
|
||||
{
|
||||
if (otherCharacter != character &&
|
||||
otherCharacter.SelectedConstruction == character.SelectedConstruction)
|
||||
otherCharacter.SelectedConstruction == this)
|
||||
{
|
||||
ItemInUseWarning.Visible = true;
|
||||
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
|
||||
@@ -1194,7 +1194,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this)
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this && GetComponent<RemoteController>() == null)
|
||||
{
|
||||
if (Character.Controlled.SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem != this &&
|
||||
!Character.Controlled.HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == this))
|
||||
@@ -1537,6 +1537,7 @@ namespace Barotrauma
|
||||
byte bodyType = msg.ReadByte();
|
||||
bool spawnedInOutpost = msg.ReadBoolean();
|
||||
bool allowStealing = msg.ReadBoolean();
|
||||
int quality = msg.ReadRangedInteger(0, Items.Components.Quality.MaxQuality);
|
||||
byte teamID = msg.ReadByte();
|
||||
bool tagsChanged = msg.ReadBoolean();
|
||||
string tags = "";
|
||||
@@ -1612,7 +1613,8 @@ namespace Barotrauma
|
||||
item = new Item(itemPrefab, pos, sub, id: itemId)
|
||||
{
|
||||
SpawnedInOutpost = spawnedInOutpost,
|
||||
AllowStealing = allowStealing
|
||||
AllowStealing = allowStealing,
|
||||
Quality = quality
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1694,7 +1694,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateJobVariantTooltip(JobPrefab jobPrefab, int variant, GUIComponent parentSlot)
|
||||
{
|
||||
jobVariantTooltip = new GUIFrame(new RectTransform(new Point((int)(500 * GUI.Scale), (int)(200 * GUI.Scale)), GUI.Canvas, pivot: Pivot.BottomRight),
|
||||
jobVariantTooltip = new GUIFrame(new RectTransform(new Point((int)(400 * GUI.Scale), (int)(180 * GUI.Scale)), GUI.Canvas, pivot: Pivot.BottomRight),
|
||||
style: "GUIToolTip")
|
||||
{
|
||||
UserData = new Pair<JobPrefab, int>(jobPrefab, variant)
|
||||
@@ -1707,17 +1707,7 @@ namespace Barotrauma
|
||||
AbsoluteSpacing = (int)(15 * GUI.Scale)
|
||||
};
|
||||
|
||||
string name =
|
||||
TextManager.Get("jobname." + jobPrefab.Identifier + (variant + 1), returnNull: true, fallBackTag: "jobname." + jobPrefab.Identifier) ??
|
||||
"";
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), name, font: GUI.SubHeadingFont);
|
||||
|
||||
string description =
|
||||
TextManager.Get("jobdescription." + jobPrefab.Identifier + (variant + 1), returnNull: true, fallBackTag: "jobdescription." + jobPrefab.Identifier) ??
|
||||
"";
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), description, wrap: true, font: GUI.SmallFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.GetWithVariable("startingequipmentname", "[number]", (variant + 1).ToString()), font: GUI.SubHeadingFont, textAlignment: Alignment.Center);
|
||||
|
||||
var itemIdentifiers = jobPrefab.ItemIdentifiers[variant]
|
||||
.Distinct()
|
||||
@@ -1726,7 +1716,7 @@ namespace Barotrauma
|
||||
int itemsPerRow = 5;
|
||||
int rows = (int)Math.Max(Math.Ceiling(itemIdentifiers.Count() / (float)itemsPerRow), 1);
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.4f * rows), content.RectTransform, Anchor.BottomLeft),
|
||||
new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.4f * rows), content.RectTransform, Anchor.BottomCenter),
|
||||
onDraw: (sb, component) => { DrawJobVariantItems(sb, component, new Pair<JobPrefab, int>(jobPrefab, variant), itemsPerRow); });
|
||||
|
||||
jobVariantTooltip.RectTransform.MinSize = new Point(0, content.RectTransform.Children.Sum(c => c.Rect.Height + content.AbsoluteSpacing));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
@@ -23,6 +24,8 @@ namespace Barotrauma
|
||||
private Character? dummyCharacter;
|
||||
public static Effect BlueprintEffect;
|
||||
|
||||
private TabMenu tabMenu;
|
||||
|
||||
public TestScreen()
|
||||
{
|
||||
Cam = new Camera();
|
||||
@@ -50,18 +53,15 @@ namespace Barotrauma
|
||||
dummyCharacter?.Remove();
|
||||
}
|
||||
|
||||
// ????????
|
||||
submarine = new Submarine(SubmarineInfo.SavedSubmarines.FirstOrDefault(info => info.Name.Equals("Crescent", StringComparison.OrdinalIgnoreCase)));
|
||||
miniMapItem = new Item(ItemPrefab.Find(null, "statusmonitor"), Vector2.Zero, submarine);
|
||||
MiniMap miniMap = miniMapItem.GetComponent<MiniMap>();
|
||||
miniMap.PowerConsumption = 0;
|
||||
|
||||
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
|
||||
dummyCharacter.Info.Job = new Job(JobPrefab.Prefabs.Where(jp => TalentTree.JobTalentTrees.ContainsKey(jp.Identifier)).GetRandom());
|
||||
dummyCharacter.Info.Name = "Galldren";
|
||||
dummyCharacter.Inventory.CreateSlots();
|
||||
|
||||
Character.Controlled = dummyCharacter;
|
||||
GameMain.World.ProcessChanges();
|
||||
TabMenu.selectedTab = TabMenu.InfoFrameTab.Talents;
|
||||
tabMenu = new TabMenu();
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
@@ -69,34 +69,21 @@ namespace Barotrauma
|
||||
Frame.AddToGUIUpdateList();
|
||||
CharacterHUD.AddToGUIUpdateList(dummyCharacter);
|
||||
dummyCharacter?.SelectedConstruction?.AddToGUIUpdateList();
|
||||
tabMenu.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
tabMenu.Update();
|
||||
|
||||
if (dummyCharacter is { } dummy && miniMapItem is { } item)
|
||||
if (dummyCharacter is { } dummy)
|
||||
{
|
||||
if (dummy.SelectedConstruction != item)
|
||||
{
|
||||
dummy.SelectedConstruction = item;
|
||||
}
|
||||
dummy.SelectedConstruction?.UpdateHUD(Cam, dummy, (float)deltaTime);
|
||||
Vector2 pos = FarseerPhysics.ConvertUnits.ToSimUnits(item.Position);
|
||||
foreach (Limb limb in dummy.AnimController.Limbs)
|
||||
{
|
||||
limb.body.SetTransform(pos, 0.0f);
|
||||
}
|
||||
|
||||
if (dummy.AnimController?.Collider is { } collider)
|
||||
{
|
||||
collider.SetTransform(pos, 0);
|
||||
}
|
||||
|
||||
dummy.ControlLocalPlayer((float)deltaTime, Cam, false);
|
||||
dummy.Control((float)deltaTime, Cam);
|
||||
dummy.Submarine = submarine;
|
||||
}
|
||||
|
||||
GUI.Update((float)deltaTime);
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -282,6 +282,7 @@ namespace Barotrauma
|
||||
msg.Write(body == null ? (byte)0 : (byte)body.BodyType);
|
||||
msg.Write(SpawnedInOutpost);
|
||||
msg.Write(AllowStealing);
|
||||
msg.WriteRangedInteger(Quality, 0, Items.Components.Quality.MaxQuality);
|
||||
|
||||
byte teamID = 0;
|
||||
foreach (WifiComponent wifiComponent in GetComponents<WifiComponent>())
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Barotrauma.Networking
|
||||
"192-255",
|
||||
"384-591",
|
||||
"1024-1279",
|
||||
"19968-40959","13312-19903","131072-15043983","15043985-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
|
||||
"19968-21327","21329-40959","13312-19903","131072-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
|
||||
};
|
||||
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", defaultAllowedClientNameChars);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1500.2.0</Version>
|
||||
<Version>0.1500.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -161,8 +161,8 @@ namespace Barotrauma
|
||||
for (int i = 0; i < container.Inventory.Capacity; i++)
|
||||
{
|
||||
if (container.Inventory.GetItemAt(i) != null) { continue; }
|
||||
if (MapEntityPrefab.List.GetRandom(e => e is ItemPrefab i && container.CanBeContained(i) &&
|
||||
Config.ForbiddenAmmunition.None(id => id.Equals(i.Identifier, StringComparison.OrdinalIgnoreCase)), Rand.RandSync.Server) is ItemPrefab ammoPrefab)
|
||||
if (MapEntityPrefab.List.GetRandom(e => e is ItemPrefab ip && container.CanBeContained(ip, i) &&
|
||||
Config.ForbiddenAmmunition.None(id => id.Equals(ip.Identifier, StringComparison.OrdinalIgnoreCase)), Rand.RandSync.Server) is ItemPrefab ammoPrefab)
|
||||
{
|
||||
Item ammo = new Item(ammoPrefab, container.Item.WorldPosition, Wreck);
|
||||
if (!container.Inventory.TryPutItem(ammo, i, allowSwapping: false, allowCombine: false, user: null, createNetworkEvent: false))
|
||||
|
||||
@@ -1430,6 +1430,7 @@ namespace Barotrauma
|
||||
|
||||
//throwing conscious/moving characters around takes more force -> double the flow force
|
||||
if (character.CanMove) { flowForce *= 2.0f; }
|
||||
flowForce *= 1 - Math.Clamp(character.GetStatValue(StatTypes.FlowResistance), 0f, 1f);
|
||||
|
||||
float flowForceMagnitude = flowForce.Length();
|
||||
float limbMultipier = limbs.Count(l => l.inWater) / (float)limbs.Length;
|
||||
|
||||
@@ -251,6 +251,8 @@ namespace Barotrauma
|
||||
private readonly List<Attacker> lastAttackers = new List<Attacker>();
|
||||
public IEnumerable<Attacker> LastAttackers => lastAttackers;
|
||||
public Character LastAttacker => lastAttackers.LastOrDefault()?.Character;
|
||||
public Character LastOrderedCharacter { get; private set; }
|
||||
public Character SecondLastOrderedCharacter { get; private set; }
|
||||
|
||||
public Entity LastDamageSource;
|
||||
|
||||
@@ -2720,7 +2722,7 @@ namespace Barotrauma
|
||||
|
||||
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
|
||||
bool allowRagdoll = GameMain.NetworkMember?.ServerSettings?.AllowRagdollButton ?? true;
|
||||
bool tooFastToUnragdoll = AnimController.Collider.LinearVelocity.LengthSquared() > 5.0f * 5.0f;
|
||||
bool tooFastToUnragdoll = AnimController.Collider.LinearVelocity.LengthSquared() > 2.5f * 2.5f;
|
||||
bool wasRagdolled = false;
|
||||
bool selfRagdolled = false;
|
||||
|
||||
@@ -3131,6 +3133,12 @@ namespace Barotrauma
|
||||
{
|
||||
var abilityOrderedCharacter = new AbilityCharacter(this);
|
||||
orderGiver.CheckTalents(AbilityEffectType.OnGiveOrder, abilityOrderedCharacter);
|
||||
|
||||
if (orderGiver.LastOrderedCharacter != this)
|
||||
{
|
||||
orderGiver.SecondLastOrderedCharacter = orderGiver.LastOrderedCharacter;
|
||||
orderGiver.LastOrderedCharacter = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (AIController is HumanAIController humanAI)
|
||||
@@ -3406,6 +3414,13 @@ namespace Barotrauma
|
||||
AddDamage(worldPosition, attackAfflictions, attack.Stun, playSound, attackImpulse, out limbHit, attacker, attack.DamageMultiplier * attackData.DamageMultiplier) :
|
||||
DamageLimb(worldPosition, targetLimb, attackAfflictions, attack.Stun, playSound, attackImpulse, attacker, attack.DamageMultiplier * attackData.DamageMultiplier, penetration: penetration + attackData.AddedPenetration);
|
||||
|
||||
if (attacker != null)
|
||||
{
|
||||
var abilityAttackResult = new AbilityAttackResult(attackResult);
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttackResult, abilityAttackResult);
|
||||
CheckTalents(AbilityEffectType.OnAttackedResult, abilityAttackResult);
|
||||
}
|
||||
|
||||
if (limbHit == null) { return new AttackResult(); }
|
||||
Vector2 forceWorld = attack.TargetImpulseWorld + attack.TargetForceWorld;
|
||||
if (attacker != null)
|
||||
@@ -3623,11 +3638,6 @@ namespace Barotrauma
|
||||
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
|
||||
hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
|
||||
}
|
||||
if (attacker != null)
|
||||
{
|
||||
var abilityAttackResult = new AbilityAttackResult(attackResult);
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttackResult, abilityAttackResult);
|
||||
}
|
||||
|
||||
return attackResult;
|
||||
}
|
||||
|
||||
@@ -979,6 +979,8 @@ namespace Barotrauma
|
||||
increase *= SkillSettings.Current.AssistantSkillIncreaseMultiplier;
|
||||
}
|
||||
|
||||
increase *= 1f + Character.GetStatValue(StatTypes.SkillGainSpeed);
|
||||
|
||||
float prevLevel = Job.GetSkillLevel(skillIdentifier);
|
||||
Job.IncreaseSkillLevel(skillIdentifier, increase, Character.HasAbilityFlag(AbilityFlags.GainSkillPastMaximum));
|
||||
|
||||
@@ -1527,6 +1529,17 @@ namespace Barotrauma
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
public float GetSavedStatValue(StatTypes statType, string statIdentifier)
|
||||
{
|
||||
if (savedStatValues.TryGetValue(statType, out var statValues))
|
||||
{
|
||||
return statValues.Where(s => s.StatIdentifier.Equals(statIdentifier, StringComparison.OrdinalIgnoreCase)).Sum(v => v.StatValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue)
|
||||
{
|
||||
|
||||
@@ -971,7 +971,7 @@ namespace Barotrauma
|
||||
/// <param name="treatmentSuitability">A dictionary where the key is the identifier of the item and the value the suitability</param>
|
||||
/// <param name="normalize">If true, the suitability values are normalized between 0 and 1. If not, they're arbitrary values defined in the medical item XML, where negative values are unsuitable, and positive ones suitable.</param>
|
||||
/// <param name="randomization">Amount of randomization to apply to the values (0 = the values are accurate, 1 = the values are completely random)</param>
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, Limb limb = null, float randomization = 0.0f)
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, Limb limb = null, bool ignoreHiddenAfflictions = false, float randomization = 0.0f)
|
||||
{
|
||||
//key = item identifier
|
||||
//float = suitability
|
||||
@@ -980,6 +980,7 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in getAfflictions(limb))
|
||||
{
|
||||
if (affliction.Strength < affliction.Prefab.TreatmentThreshold) { continue; }
|
||||
if (ignoreHiddenAfflictions && affliction.Strength < affliction.Prefab.ShowIconThreshold) { continue; }
|
||||
foreach (KeyValuePair<string, float> treatment in affliction.Prefab.TreatmentSuitability)
|
||||
{
|
||||
if (!treatmentSuitability.ContainsKey(treatment.Key))
|
||||
|
||||
@@ -7,12 +7,12 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
private enum WeaponType
|
||||
{
|
||||
Any = 0,
|
||||
Melee = 1,
|
||||
Any = 0,
|
||||
Melee = 1,
|
||||
Ranged = 2
|
||||
};
|
||||
|
||||
private WeaponType weapontype;
|
||||
private readonly WeaponType weapontype;
|
||||
public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
switch (conditionElement.GetAttributeString("weapontype", ""))
|
||||
@@ -43,7 +43,7 @@ namespace Barotrauma.Abilities
|
||||
break;
|
||||
default:
|
||||
aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionItem : AbilityConditionData
|
||||
{
|
||||
private readonly string identifier;
|
||||
private readonly string[] identifiers;
|
||||
private readonly string[] tags;
|
||||
|
||||
public AbilityConditionItem(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
identifier = conditionElement.GetAttributeString("identifier", string.Empty).ToLowerInvariant();
|
||||
identifiers = conditionElement.GetAttributeStringArray("identifiers", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
tags = conditionElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ namespace Barotrauma.Abilities
|
||||
|
||||
if (itemPrefab != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
if (identifiers.Any())
|
||||
{
|
||||
if (itemPrefab.Identifier != identifier)
|
||||
if (!identifiers.Any(t => itemPrefab.Identifier == t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return tags.Any(t => itemPrefab.Tags.Any(p => t == p));
|
||||
return !tags.Any() || tags.Any(t => itemPrefab.Tags.Any(p => t == p));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionHasVelocity : AbilityConditionDataless
|
||||
{
|
||||
private readonly float velocity;
|
||||
|
||||
public AbilityConditionHasVelocity(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
velocity = conditionElement.GetAttributeFloat("velocity", 0f);
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
return character.AnimController.Collider.LinearVelocity.LengthSquared() > velocity * velocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
if (character.Submarine == null || character.Submarine.TeamID != character.TeamID) { return false; }
|
||||
if (!character.IsInFriendlySub) { return false; }
|
||||
float currentFloodPercentage = character.Submarine.GetHulls(false).Average(h => h.WaterPercentage);
|
||||
return currentFloodPercentage / 100 > floodPercentage;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected readonly List<StatusEffect> statusEffects;
|
||||
|
||||
private readonly bool nearbyCharactersAppliesToSelf;
|
||||
private readonly bool applyToSelected;
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
@@ -18,6 +19,7 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
||||
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
|
||||
}
|
||||
|
||||
protected void ApplyEffectSpecific(Character targetCharacter)
|
||||
@@ -26,7 +28,7 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.UseTarget))
|
||||
{
|
||||
// currently used this to spawn items on the targeted character
|
||||
// currently used to spawn items on the targeted character
|
||||
statusEffect.SetUser(targetCharacter);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targetCharacter);
|
||||
}
|
||||
@@ -34,6 +36,10 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
targets.Clear();
|
||||
targets.AddRange(statusEffect.GetNearbyTargets(targetCharacter.WorldPosition, targets));
|
||||
if (!nearbyCharactersAppliesToSelf)
|
||||
{
|
||||
targets.RemoveAll(c => c == Character);
|
||||
}
|
||||
statusEffect.SetUser(Character);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApplyStatusEffectsToLastOrderedCharacter : CharacterAbilityApplyStatusEffects
|
||||
{
|
||||
public CharacterAbilityApplyStatusEffectsToLastOrderedCharacter(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
if (IsViableTarget(Character.LastOrderedCharacter))
|
||||
{
|
||||
ApplyEffectSpecific(Character.LastOrderedCharacter);
|
||||
}
|
||||
if (Character.HasAbilityFlag(AbilityFlags.AllowSecondOrderedTarget) && IsViableTarget(Character.SecondLastOrderedCharacter))
|
||||
{
|
||||
ApplyEffectSpecific(Character.SecondLastOrderedCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsViableTarget(Character targetCharacter)
|
||||
{
|
||||
if (targetCharacter == null || targetCharacter.Removed) { return false; }
|
||||
if (targetCharacter == Character) { return false; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,7 @@ namespace Barotrauma.Abilities
|
||||
targetAllies = abilityElement.GetAttributeBool("targetallies", false);
|
||||
removeOnDeath = abilityElement.GetAttributeBool("removeondeath", true);
|
||||
removeAfterRound = abilityElement.GetAttributeBool("removeafterround", false);
|
||||
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", false);
|
||||
//maximumValue = abilityElement.GetAttributeFloat("maximumvalue", float.MaxValue);
|
||||
giveOnAddingFirstTime = abilityElement.GetAttributeBool("giveonaddingfirsttime", characterAbilityGroup.AbilityEffectType == AbilityEffectType.None);
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
@@ -7,13 +8,22 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
|
||||
private string skillIdentifier;
|
||||
private float skillIncrease;
|
||||
private readonly string skillIdentifier;
|
||||
private readonly float skillIncrease;
|
||||
|
||||
public CharacterAbilityIncreaseSkill(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
skillIdentifier = abilityElement.GetAttributeString("skillidentifier", "").ToLowerInvariant();
|
||||
skillIncrease = abilityElement.GetAttributeFloat("skillincrease", 0f);
|
||||
|
||||
if (string.IsNullOrEmpty(skillIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent \"{characterAbilityGroup.CharacterTalent.DebugIdentifier}\" - skill identifier not defined in CharacterAbilityIncreaseSkill.");
|
||||
}
|
||||
if (MathUtils.NearlyEqual(skillIncrease, 0))
|
||||
{
|
||||
DebugConsole.AddWarning($"Possible error in talent \"{characterAbilityGroup.CharacterTalent.DebugIdentifier}\" - skill increase set to 0.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
@@ -35,7 +45,17 @@ namespace Barotrauma.Abilities
|
||||
|
||||
private void ApplyEffectSpecific(Character character)
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
if (skillIdentifier.Equals("random"))
|
||||
{
|
||||
var skill = character.Info?.Job?.Skills?.GetRandom();
|
||||
if (skill == null) { return; }
|
||||
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyStatToFlooding : CharacterAbility
|
||||
{
|
||||
private readonly StatTypes statType;
|
||||
private readonly float maxValue;
|
||||
private float lastValue = 0f;
|
||||
|
||||
public CharacterAbilityModifyStatToFlooding(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
maxValue = abilityElement.GetAttributeFloat("maxvalue", 0f);
|
||||
}
|
||||
|
||||
protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
{
|
||||
Character.ChangeStat(statType, -lastValue);
|
||||
|
||||
if (conditionsMatched && Character.IsInFriendlySub)
|
||||
{
|
||||
float currentFloodPercentage = Character.Submarine.GetHulls(false).Average(h => h.WaterPercentage);
|
||||
lastValue = currentFloodPercentage / 100f * maxValue;
|
||||
Character.ChangeStat(statType, lastValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastValue = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyValue : CharacterAbility
|
||||
{
|
||||
private float addedValue;
|
||||
private float multiplyValue;
|
||||
private readonly float addedValue;
|
||||
private readonly float multiplyValue;
|
||||
|
||||
public CharacterAbilityModifyValue(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
|
||||
@@ -6,12 +6,14 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityByTheBook : CharacterAbility
|
||||
{
|
||||
private int moneyAmount;
|
||||
private int max;
|
||||
private readonly int moneyAmount;
|
||||
private readonly int experienceAmount;
|
||||
private readonly int max;
|
||||
|
||||
public CharacterAbilityByTheBook(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
moneyAmount = abilityElement.GetAttributeInt("moneyamount", 0);
|
||||
experienceAmount = abilityElement.GetAttributeInt("experienceamount", 0);
|
||||
max = abilityElement.GetAttributeInt("max", 0);
|
||||
}
|
||||
|
||||
@@ -28,6 +30,10 @@ namespace Barotrauma.Abilities
|
||||
if (!enemyCharacter.LockHands) { continue; }
|
||||
if (timesGiven > max) { continue; }
|
||||
Character.GiveMoney(moneyAmount);
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
character.Info?.GiveExperience(experienceAmount);
|
||||
}
|
||||
timesGiven++;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityEnigmaMachine : CharacterAbility
|
||||
{
|
||||
private readonly float addedValue;
|
||||
private readonly float multiplyValue;
|
||||
private readonly string[] tags;
|
||||
private readonly int maxMultiplyCount;
|
||||
|
||||
public CharacterAbilityEnigmaMachine(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||
tags = abilityElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
maxMultiplyCount = abilityElement.GetAttributeInt("maxmultiplycount", int.MaxValue);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if (abilityObject is IAbilityValue abilityValue)
|
||||
{
|
||||
int multiplyCount = 0;
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Prefab.Tags.Any(t => tags.Contains(t)))
|
||||
{
|
||||
multiplyCount++;
|
||||
if (multiplyCount == maxMultiplyCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abilityValue.Value += addedValue * multiplyCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityIndustrialRevolution : CharacterAbility
|
||||
{
|
||||
float addedFabricationSpeed;
|
||||
|
||||
public CharacterAbilityIndustrialRevolution(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedFabricationSpeed = abilityElement.GetAttributeFloat("addedfabricationspeed", 0f);
|
||||
}
|
||||
|
||||
public override void UpdateCharacterAbility(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
{
|
||||
if (conditionsMatched)
|
||||
{
|
||||
// not necessarily the cleanest or performant way, but at least this shouldn't break anything.
|
||||
// must be done every frame in order to work.
|
||||
if (Character.SelectedConstruction?.GetComponent<Fabricator>() is Fabricator fabricator && fabricator.IsActive)
|
||||
{
|
||||
fabricator.FabricationSpeedMultiplier += addedFabricationSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityTaskmaster : CharacterAbility
|
||||
{
|
||||
private readonly List<StatusEffect> statusEffects;
|
||||
private readonly List<StatusEffect> statusEffectsRemove;
|
||||
|
||||
private Character lastCharacter;
|
||||
|
||||
public CharacterAbilityTaskmaster(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
statusEffectsRemove = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffectsremove"));
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
|
||||
{
|
||||
if (targetCharacter == Character) { return; }
|
||||
|
||||
foreach (var statusEffect in statusEffectsRemove)
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, lastCharacter);
|
||||
}
|
||||
|
||||
foreach (var statusEffect in statusEffects)
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, targetCharacter);
|
||||
}
|
||||
|
||||
lastCharacter = targetCharacter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ namespace Barotrauma.Abilities
|
||||
// currently only used to turn off simulation if random conditions are in use
|
||||
public bool IsActive { get; private set; } = true;
|
||||
|
||||
public readonly AbilityEffectType AbilityEffectType;
|
||||
|
||||
protected int maxTriggerCount { get; }
|
||||
protected int timesTriggered = 0;
|
||||
|
||||
@@ -24,8 +26,9 @@ namespace Barotrauma.Abilities
|
||||
// separate dictionaries for each type of characterability?
|
||||
protected readonly List<CharacterAbility> characterAbilities = new List<CharacterAbility>();
|
||||
|
||||
public CharacterAbilityGroup(CharacterTalent characterTalent, XElement abilityElementGroup)
|
||||
public CharacterAbilityGroup(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup)
|
||||
{
|
||||
AbilityEffectType = abilityEffectType;
|
||||
CharacterTalent = characterTalent;
|
||||
Character = CharacterTalent.Character;
|
||||
maxTriggerCount = abilityElementGroup.GetAttributeInt("maxtriggercount", int.MaxValue);
|
||||
@@ -168,8 +171,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
public static StatTypes ParseStatType(string statTypeString, string debugIdentifier)
|
||||
{
|
||||
StatTypes statType;
|
||||
if (!Enum.TryParse(statTypeString, true, out statType))
|
||||
if (!Enum.TryParse(statTypeString, true, out StatTypes statType))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid stat type type \"" + statTypeString + "\" in CharacterTalent (" + debugIdentifier + ")");
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGroupEffect : CharacterAbilityGroup
|
||||
{
|
||||
public CharacterAbilityGroupEffect(CharacterTalent characterTalent, XElement abilityElementGroup) : base(characterTalent, abilityElementGroup) { }
|
||||
public CharacterAbilityGroupEffect(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup) :
|
||||
base(abilityEffectType, characterTalent, abilityElementGroup) { }
|
||||
|
||||
public void CheckAbilityGroup(AbilityObject abilityObject)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Barotrauma.Abilities
|
||||
private float effectDelayTimer;
|
||||
|
||||
|
||||
public CharacterAbilityGroupInterval(CharacterTalent characterTalent, XElement abilityElementGroup) : base(characterTalent, abilityElementGroup)
|
||||
public CharacterAbilityGroupInterval(AbilityEffectType abilityEffectType, CharacterTalent characterTalent, XElement abilityElementGroup) :
|
||||
base(abilityEffectType, characterTalent, abilityElementGroup)
|
||||
{
|
||||
// too many overlapping intervals could cause hitching? maybe randomize a little
|
||||
interval = abilityElementGroup.GetAttributeFloat("interval", 0f);
|
||||
|
||||
@@ -85,14 +85,13 @@ namespace Barotrauma
|
||||
// XML logic
|
||||
private void LoadAbilityGroupInterval(XElement abilityGroup)
|
||||
{
|
||||
string name = abilityGroup.Name.ToString().ToLowerInvariant();
|
||||
characterAbilityGroupIntervals.Add(new CharacterAbilityGroupInterval(this, abilityGroup));
|
||||
characterAbilityGroupIntervals.Add(new CharacterAbilityGroupInterval(AbilityEffectType.Undefined, this, abilityGroup));
|
||||
}
|
||||
|
||||
private void LoadAbilityGroupEffect(XElement abilityGroup)
|
||||
{
|
||||
AbilityEffectType abilityEffectType = ParseAbilityEffectType(this, abilityGroup.GetAttributeString("abilityeffecttype", "none"));
|
||||
AddAbilityGroupEffect(new CharacterAbilityGroupEffect(this, abilityGroup), abilityEffectType);
|
||||
AddAbilityGroupEffect(new CharacterAbilityGroupEffect(abilityEffectType, this, abilityGroup), abilityEffectType);
|
||||
}
|
||||
|
||||
public void AddAbilityGroupEffect(CharacterAbilityGroupEffect characterAbilityGroup, AbilityEffectType abilityEffectType = AbilityEffectType.None)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -8,13 +7,19 @@ namespace Barotrauma
|
||||
{
|
||||
class TalentTree
|
||||
{
|
||||
public enum TalentTreeStageState
|
||||
{
|
||||
Invalid,
|
||||
Locked,
|
||||
Unlocked,
|
||||
Available,
|
||||
Highlighted
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, TalentTree> JobTalentTrees = new Dictionary<string, TalentTree>();
|
||||
|
||||
public readonly List<TalentSubTree> TalentSubTrees = new List<TalentSubTree>();
|
||||
|
||||
private static HashSet<string> subtreeTalents = new HashSet<string>();
|
||||
|
||||
private const string PlaceholderTalent = "placeholder";
|
||||
public XElement ConfigElement
|
||||
{
|
||||
get;
|
||||
@@ -35,14 +40,13 @@ namespace Barotrauma
|
||||
|
||||
foreach (XElement subTreeElement in element.GetChildElements("subtree"))
|
||||
{
|
||||
TalentSubTrees.Add(new TalentSubTree(subTreeElement));
|
||||
TalentSubTrees.Add(new TalentSubTree(subTreeElement));
|
||||
}
|
||||
|
||||
// talents found and unlocked using the identifier wihin the talent tree, so no duplicates may occur
|
||||
HashSet<string> duplicateSet = new HashSet<string>();
|
||||
foreach (string talent in TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier))))
|
||||
{
|
||||
if (talent == PlaceholderTalent) { continue; }
|
||||
TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c => c.Identifier.Equals(talent, StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
@@ -97,7 +101,7 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}");
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -117,10 +121,63 @@ namespace Barotrauma
|
||||
return IsViableTalentForCharacter(character, talentIdentifier, character?.Info?.UnlockedTalents ?? Enumerable.Empty<string>());
|
||||
}
|
||||
|
||||
// i hate this function - markus
|
||||
public static TalentTreeStageState GetTalentOptionStageState(Character character, string subTreeIdentifier, int index, List<string> selectedTalents)
|
||||
{
|
||||
if (character?.Info?.Job.Prefab is null) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
if (!JobTalentTrees.TryGetValue(character.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
TalentSubTree subTree = talentTree.TalentSubTrees.FirstOrDefault(tst => tst.Identifier == subTreeIdentifier);
|
||||
|
||||
if (subTree == null) { return TalentTreeStageState.Invalid; }
|
||||
|
||||
TalentOption targetTalentOption = subTree.TalentOptionStages[index];
|
||||
|
||||
if (targetTalentOption.Talents.Any(t => character.HasTalent(t.Identifier)))
|
||||
{
|
||||
return TalentTreeStageState.Unlocked;
|
||||
}
|
||||
|
||||
if (targetTalentOption.Talents.Any(t => selectedTalents.Contains(t.Identifier)))
|
||||
{
|
||||
return TalentTreeStageState.Highlighted;
|
||||
}
|
||||
|
||||
bool hasTalentInLastTier = true;
|
||||
bool isLastTalentPurchased = true;
|
||||
|
||||
int lastindex = index - 1;
|
||||
if (lastindex >= 0)
|
||||
{
|
||||
TalentOption lastLatentOption = subTree.TalentOptionStages[lastindex];
|
||||
hasTalentInLastTier = lastLatentOption.Talents.Any(HasTalent);
|
||||
isLastTalentPurchased = lastLatentOption.Talents.Any(t => character.HasTalent(t.Identifier));
|
||||
}
|
||||
|
||||
if (!hasTalentInLastTier)
|
||||
{
|
||||
return TalentTreeStageState.Locked;
|
||||
}
|
||||
|
||||
bool hasPointsForNewTalent = character.Info.GetTotalTalentPoints() - selectedTalents.Count > 0;
|
||||
|
||||
if (hasPointsForNewTalent)
|
||||
{
|
||||
return isLastTalentPurchased ? TalentTreeStageState.Highlighted : TalentTreeStageState.Available;
|
||||
}
|
||||
|
||||
return TalentTreeStageState.Locked;
|
||||
|
||||
bool HasTalent(TalentPrefab t)
|
||||
{
|
||||
return selectedTalents.Contains(t.Identifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool IsViableTalentForCharacter(Character character, string talentIdentifier, IEnumerable<string> selectedTalents)
|
||||
{
|
||||
if (talentIdentifier == PlaceholderTalent) { return false; }
|
||||
if (character?.Info?.Job.Prefab == null) { return false; }
|
||||
if (character.Info.GetTotalTalentPoints() - selectedTalents.Count() <= 0) { return false; }
|
||||
|
||||
@@ -173,12 +230,16 @@ namespace Barotrauma
|
||||
{
|
||||
public string Identifier { get; }
|
||||
|
||||
public string DisplayName { get; }
|
||||
|
||||
public readonly List<TalentOption> TalentOptionStages = new List<TalentOption>();
|
||||
|
||||
public TalentSubTree(XElement subTreeElement)
|
||||
{
|
||||
Identifier = subTreeElement.GetAttributeString("identifier", "");
|
||||
|
||||
DisplayName = TextManager.Get("talenttree." + Identifier, returnNull: true) ?? Identifier;
|
||||
|
||||
foreach (XElement talentOptionsElement in subTreeElement.GetChildElements("talentoptions"))
|
||||
{
|
||||
TalentOptionStages.Add(new TalentOption(talentOptionsElement, Identifier));
|
||||
@@ -196,6 +257,7 @@ namespace Barotrauma
|
||||
foreach (XElement talentOptionElement in talentOptionsElement.GetChildElements("talentoption"))
|
||||
{
|
||||
string identifier = talentOptionElement.GetAttributeString("identifier", string.Empty);
|
||||
|
||||
if (!TalentPrefab.TalentPrefabs.ContainsKey(identifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in talent tree \"{debugIdentifier}\" - could not find a talent with the identifier \"{identifier}\".");
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
|
||||
public enum ActionType
|
||||
{
|
||||
Always, OnPicked, OnUse, OnSecondaryUse,
|
||||
OnWearing, OnContaining, OnContained, OnNotContained,
|
||||
OnActive, OnFailure, OnBroken,
|
||||
OnFire, InWater, NotInWater,
|
||||
OnImpact,
|
||||
OnEating,
|
||||
OnDamaged,
|
||||
OnSevered,
|
||||
OnProduceSpawned,
|
||||
OnOpen, OnClose,
|
||||
Always = 0, OnPicked = 1, OnUse = 2, OnSecondaryUse = 3,
|
||||
OnWearing = 4, OnContaining = 5, OnContained = 6, OnNotContained = 7,
|
||||
OnActive = 8, OnFailure = 9, OnBroken = 10,
|
||||
OnFire = 11, InWater = 12, NotInWater = 13,
|
||||
OnImpact = 14,
|
||||
OnEating = 15,
|
||||
OnDamaged = 16,
|
||||
OnSevered = 17,
|
||||
OnProduceSpawned = 18,
|
||||
OnOpen = 19, OnClose = 20,
|
||||
OnDeath = OnBroken,
|
||||
OnSuccess,
|
||||
OnAbility,
|
||||
@@ -34,6 +34,7 @@
|
||||
OnAttack,
|
||||
OnAttackResult,
|
||||
OnAttacked,
|
||||
OnAttackedResult,
|
||||
OnGainSkillPoint,
|
||||
OnAllyGainSkillPoint,
|
||||
OnRepairComplete,
|
||||
@@ -57,7 +58,9 @@
|
||||
OnGainMissionMoney,
|
||||
OnItemDeconstructed,
|
||||
OnItemDeconstructedMaterial,
|
||||
OnItemDeconstructedRetainProbability,
|
||||
OnStopTinkering,
|
||||
OnItemPicked,
|
||||
AfterSubmarineAttacked,
|
||||
}
|
||||
|
||||
@@ -78,26 +81,37 @@
|
||||
BuffDurationMultiplier,
|
||||
DebuffDurationMultiplier,
|
||||
MedicalItemEffectivenessMultiplier,
|
||||
FlowResistance,
|
||||
// Combat
|
||||
AttackMultiplier,
|
||||
TeamAttackMultiplier,
|
||||
RangedAttackSpeed,
|
||||
TurretAttackSpeed,
|
||||
TurretPowerCostReduction,
|
||||
TurretChargeSpeed,
|
||||
MeleeAttackSpeed,
|
||||
MeleeAttackMultiplier,
|
||||
RangedAttackMultiplier,
|
||||
RangedSpreadReduction,
|
||||
// Utility
|
||||
RepairSpeed,
|
||||
DeconstructorSpeedMultiplier,
|
||||
TinkeringDuration,
|
||||
RepairToolStructureRepairMultiplier,
|
||||
RepairToolStructureDamageMultiplier,
|
||||
RepairToolDeattachTimeMultiplier,
|
||||
MaxRepairConditionMultiplier,
|
||||
IncreaseFabricationQuality,
|
||||
GeneticMaterialRefineBonus,
|
||||
GeneticMaterialTaintedProbabilityReductionOnCombine,
|
||||
SkillGainSpeed,
|
||||
// Misc
|
||||
ReputationGainMultiplier,
|
||||
MissionMoneyGainMultiplier,
|
||||
ExperienceGainMultiplier,
|
||||
MissionExperienceGainMultiplier,
|
||||
// these should be deprecated and moved to their own implementation, no sense making them share space with stat values
|
||||
Coathor,
|
||||
Coauthor,
|
||||
WarriorPoetMissionRuns,
|
||||
WarriorPoetEnemiesKilled,
|
||||
}
|
||||
@@ -113,7 +127,8 @@
|
||||
CanTinkerFabricatorsAndDeconstructors,
|
||||
TinkeringPowersDevices,
|
||||
GainSkillPastMaximum,
|
||||
RetainExperienceForNewCharacter
|
||||
RetainExperienceForNewCharacter,
|
||||
AllowSecondOrderedTarget,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace Barotrauma
|
||||
case 0:
|
||||
|
||||
if (items.All(it => it.Removed || it.Condition <= 0.0f) &&
|
||||
requireKill.All(c => c.Removed || c.IsDead) &&
|
||||
requireKill.All(c => c.Removed || c.IsDead || (c.LockHands && c.Submarine == Submarine.MainSub)) &&
|
||||
requireRescue.All(c => c.Submarine?.Info.Type == SubmarineType.Player))
|
||||
{
|
||||
State = 1;
|
||||
|
||||
@@ -382,11 +382,11 @@ namespace Barotrauma
|
||||
State = newState;
|
||||
}
|
||||
|
||||
private bool CheckWinState() => !IsClient && (characters.All(m => !Survived(m)));
|
||||
private bool CheckWinState() => !IsClient && characters.All(m => DeadOrCaptured(m));
|
||||
|
||||
private bool Survived(Character character)
|
||||
private bool DeadOrCaptured(Character character)
|
||||
{
|
||||
return character != null && !character.Removed && !character.IsDead;
|
||||
return character != null && !character.Removed && (character.IsDead || (character.LockHands && character.Submarine == Submarine.MainSub));
|
||||
}
|
||||
|
||||
public override void End()
|
||||
|
||||
@@ -247,8 +247,8 @@ namespace Barotrauma
|
||||
|
||||
public override void End()
|
||||
{
|
||||
var root = item.GetRootContainer() ?? item;
|
||||
if (root.CurrentHull?.Submarine == null || (!root.CurrentHull.Submarine.AtEndExit && !root.CurrentHull.Submarine.AtStartExit) || item.Removed)
|
||||
var root = item?.GetRootContainer() ?? item;
|
||||
if (root?.CurrentHull?.Submarine == null || (!root.CurrentHull.Submarine.AtEndExit && !root.CurrentHull.Submarine.AtStartExit) || item.Removed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,5 +92,12 @@ namespace Barotrauma.Extensions
|
||||
{
|
||||
return MathUtils.NearlyEqual(v.X, other.X) && MathUtils.NearlyEqual(v.Y, other.Y);
|
||||
}
|
||||
|
||||
public static Vector2 Pad(this Vector2 v, Vector4 padding)
|
||||
{
|
||||
v.X += padding.X + padding.Z;
|
||||
v.Y += padding.Y + padding.W;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public GeneticMaterial(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -85,7 +84,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public bool CanBeCombinedWith(GeneticMaterial otherGeneticMaterial)
|
||||
{
|
||||
return !tainted && otherGeneticMaterial != null && !otherGeneticMaterial.tainted;
|
||||
return !tainted && otherGeneticMaterial != null && !otherGeneticMaterial.tainted && item.AllowDeconstruct && otherGeneticMaterial.item.AllowDeconstruct;
|
||||
}
|
||||
|
||||
public override void Equip(Character character)
|
||||
@@ -147,9 +146,12 @@ namespace Barotrauma.Items.Components
|
||||
public bool Combine(GeneticMaterial otherGeneticMaterial, Character user)
|
||||
{
|
||||
if (!CanBeCombinedWith(otherGeneticMaterial)) { return false; }
|
||||
|
||||
float conditionIncrease = Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax);
|
||||
conditionIncrease *= 1.0f + user.GetStatValue(StatTypes.GeneticMaterialRefineBonus);
|
||||
if (item.Prefab == otherGeneticMaterial.item.Prefab)
|
||||
{
|
||||
item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax);
|
||||
item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + conditionIncrease;
|
||||
float taintedProbability = GetTaintedProbabilityOnRefine(user);
|
||||
if (taintedProbability >= Rand.Range(0.0f, 1.0f))
|
||||
{
|
||||
@@ -160,9 +162,14 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
item.Condition = otherGeneticMaterial.Item.Condition =
|
||||
(item.Condition + otherGeneticMaterial.Item.Condition) / 2.0f + Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax);
|
||||
(item.Condition + otherGeneticMaterial.Item.Condition) / 2.0f + conditionIncrease;
|
||||
item.OwnInventory?.TryPutItem(otherGeneticMaterial.Item, user: null);
|
||||
MakeTainted();
|
||||
item.AllowDeconstruct = false;
|
||||
otherGeneticMaterial.Item.AllowDeconstruct = false;
|
||||
if (GetTaintedProbabilityOnCombine(user) >= Rand.Range(0.0f, 1.0f))
|
||||
{
|
||||
MakeTainted();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +179,14 @@ namespace Barotrauma.Items.Components
|
||||
if (user == null) { return 1.0f; }
|
||||
float probability = MathHelper.Lerp(0.0f, 0.99f, item.Condition / 100.0f);
|
||||
probability *= MathHelper.Lerp(1.0f, 0.25f, DegreeOfSuccess(user));
|
||||
return probability;
|
||||
return MathHelper.Clamp(probability, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
private float GetTaintedProbabilityOnCombine(Character user)
|
||||
{
|
||||
if (user == null) { return 1.0f; }
|
||||
float probability = 1.0f - user.GetStatValue(StatTypes.GeneticMaterialTaintedProbabilityReductionOnCombine);
|
||||
return MathHelper.Clamp(probability, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
private void MakeTainted()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Abilities;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -73,12 +74,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (PickingTime > 0.0f)
|
||||
{
|
||||
var abilityPickingTime = new AbilityValueItem(PickingTime, item.Prefab);
|
||||
picker.CheckTalents(AbilityEffectType.OnItemPicked, abilityPickingTime);
|
||||
|
||||
if ((picker.PickingItem == null || picker.PickingItem == item) && PickingTime <= float.MaxValue)
|
||||
{
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
pickingCoroutine = CoroutineManager.StartCoroutine(WaitForPick(picker, PickingTime));
|
||||
pickingCoroutine = CoroutineManager.StartCoroutine(WaitForPick(picker, abilityPickingTime.Value));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -523,7 +523,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new ISerializableEntity[] { targetStructure });
|
||||
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
|
||||
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
|
||||
|
||||
float structureFixAmount = StructureFixAmount;
|
||||
if (structureFixAmount >= 0f)
|
||||
{
|
||||
structureFixAmount *= 1 + user.GetStatValue(StatTypes.RepairToolStructureRepairMultiplier);
|
||||
structureFixAmount *= 1 + item.GetQualityModifier(Quality.StatType.RepairToolStructureRepairMultiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
structureFixAmount *= 1 + user.GetStatValue(StatTypes.RepairToolStructureDamageMultiplier);
|
||||
structureFixAmount *= 1 + item.GetQualityModifier(Quality.StatType.RepairToolStructureDamageMultiplier);
|
||||
}
|
||||
|
||||
targetStructure.AddDamage(sectionIndex, -structureFixAmount * degreeOfSuccess, user);
|
||||
|
||||
//if the next section is small enough, apply the effect to it as well
|
||||
//(to make it easier to fix a small "left-over" section)
|
||||
@@ -535,7 +548,7 @@ namespace Barotrauma.Items.Components
|
||||
(nextSectionLength > 0 && nextSectionLength < Structure.WallSectionSize * 0.3f))
|
||||
{
|
||||
//targetStructure.HighLightSection(sectionIndex + i);
|
||||
targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess);
|
||||
targetStructure.AddDamage(sectionIndex + i, -structureFixAmount * degreeOfSuccess);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -606,7 +619,8 @@ namespace Barotrauma.Items.Components
|
||||
levelResource.requiredItems.Any() &&
|
||||
levelResource.HasRequiredItems(user, addMessage: false))
|
||||
{
|
||||
levelResource.DeattachTimer += deltaTime;
|
||||
float addedDetachTime = deltaTime * (1f + user.GetStatValue(StatTypes.RepairToolDeattachTimeMultiplier)) * item.GetQualityModifier(Quality.StatType.RepairToolDeattachTimeMultiplier);
|
||||
levelResource.DeattachTimer += addedDetachTime;
|
||||
#if CLIENT
|
||||
Character.Controlled?.UpdateHUDProgressBar(
|
||||
this,
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Barotrauma.Items.Components
|
||||
public int Capacity
|
||||
{
|
||||
get { return capacity; }
|
||||
set { capacity = Math.Max(value, 1); }
|
||||
set { capacity = Math.Max(value, 0); }
|
||||
}
|
||||
|
||||
//how many items can be contained
|
||||
@@ -86,15 +86,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")]
|
||||
public Vector2 ItemPos { get; set; }
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The interval at which the contained items are spaced apart from each other (in pixels).")]
|
||||
public Vector2 ItemInterval { get; set; }
|
||||
|
||||
@@ -329,11 +323,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
return slotRestrictions.Any(s => s.MatchesItem(item));
|
||||
}
|
||||
|
||||
public bool CanBeContained(Item item, int index)
|
||||
{
|
||||
if (index < 0 || index >= capacity) { return false; }
|
||||
return slotRestrictions[index].MatchesItem(item);
|
||||
}
|
||||
|
||||
public bool CanBeContained(ItemPrefab itemPrefab)
|
||||
{
|
||||
return slotRestrictions.Any(s => s.MatchesItem(itemPrefab));
|
||||
}
|
||||
|
||||
public bool CanBeContained(ItemPrefab itemPrefab, int index)
|
||||
{
|
||||
if (index < 0 || index >= capacity) { return false; }
|
||||
return slotRestrictions[index].MatchesItem(itemPrefab);
|
||||
}
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
|
||||
@@ -256,6 +256,17 @@ 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)
|
||||
{
|
||||
//drop all items that are inside the deconstructed item
|
||||
|
||||
@@ -24,12 +24,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private Character user;
|
||||
|
||||
public float FabricationSpeedMultiplier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private ItemContainer inputContainer, outputContainer;
|
||||
|
||||
[Serialize(1.0f, true)]
|
||||
@@ -249,7 +243,6 @@ namespace Barotrauma.Items.Components
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
if (fabricatedItem == null || !CanBeFabricated(fabricatedItem, availableIngredients, user))
|
||||
{
|
||||
FabricationSpeedMultiplier = 1f;
|
||||
CancelFabricating();
|
||||
return;
|
||||
}
|
||||
@@ -286,8 +279,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (powerConsumption <= 0) { Voltage = 1.0f; }
|
||||
|
||||
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f) * FabricationSpeedMultiplier;
|
||||
FabricationSpeedMultiplier = 1f;
|
||||
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f);
|
||||
|
||||
UpdateRequiredTimeProjSpecific();
|
||||
|
||||
@@ -328,13 +320,21 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
var fabricationValueItem = new AbilityValueItem(fabricatedItem.Amount, fabricatedItem.TargetItem);
|
||||
|
||||
if (user != null)
|
||||
int quality = 0;
|
||||
if (user?.Info != null)
|
||||
{
|
||||
foreach (Character character in Character.CharacterList.Where(c => c.TeamID == user.TeamID))
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.OnAllyItemFabricatedAmount, fabricationValueItem);
|
||||
}
|
||||
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationValueItem);
|
||||
|
||||
float floatQuality = 0.0f;
|
||||
foreach (string tag in fabricatedItem.TargetItem.Tags)
|
||||
{
|
||||
floatQuality += user.Info.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag);
|
||||
}
|
||||
quality = (int)floatQuality;
|
||||
}
|
||||
|
||||
var tempUser = user;
|
||||
@@ -343,12 +343,20 @@ namespace Barotrauma.Items.Components
|
||||
if (i < amountFittingContainer)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition,
|
||||
onSpawned: (Item spawnedItem) => { onItemSpawned(spawnedItem, tempUser); });
|
||||
onSpawned: (Item spawnedItem) =>
|
||||
{
|
||||
onItemSpawned(spawnedItem, tempUser);
|
||||
spawnedItem.Quality = quality;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, item.Position, item.Submarine, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition,
|
||||
onSpawned: (Item spawnedItem) => { onItemSpawned(spawnedItem, tempUser); });
|
||||
onSpawned: (Item spawnedItem) =>
|
||||
{
|
||||
onItemSpawned(spawnedItem, tempUser);
|
||||
spawnedItem.Quality = quality;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
item.CurrentHull.WaterVolume += currFlow;
|
||||
if (item.CurrentHull.WaterVolume > item.CurrentHull.Volume) { item.CurrentHull.Pressure += 0.5f; }
|
||||
|
||||
Voltage -= deltaTime;
|
||||
}
|
||||
|
||||
public void InfectBallast(string identifier, bool allowMultiplePerShip = false)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Quality : ItemComponent
|
||||
{
|
||||
public const int MaxQuality = 3;
|
||||
|
||||
public enum StatType
|
||||
{
|
||||
Condition,
|
||||
ExplosionRadius,
|
||||
ExplosionDamage,
|
||||
RepairSpeed,
|
||||
RepairToolStructureRepairMultiplier,
|
||||
RepairToolStructureDamageMultiplier,
|
||||
RepairToolDeattachTimeMultiplier,
|
||||
// unused as of now
|
||||
AttackMultiplier,
|
||||
AttackSpeedMultiplier,
|
||||
ForceDoorsOpenSpeedMultiplier,
|
||||
RangedSpreadReduction,
|
||||
ChargeSpeedMultiplier,
|
||||
MovementSpeedMultiplier,
|
||||
// generic stats to be used for various needs, declared just in case (localization)
|
||||
EffectivenessMultiplier,
|
||||
PowerOutputMultiplier,
|
||||
ConsumptionReductionMultiplier,
|
||||
}
|
||||
|
||||
private readonly Dictionary<StatType, float> statValues = new Dictionary<StatType, float>();
|
||||
|
||||
private int qualityLevel;
|
||||
|
||||
[Serialize(0, false)]
|
||||
public int QualityLevel
|
||||
{
|
||||
get { return qualityLevel; }
|
||||
set { qualityLevel = MathHelper.Clamp(value, 0, MaxQuality); }
|
||||
}
|
||||
|
||||
public Quality(Item item, XElement element) : base(item, element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
{
|
||||
case "stattype":
|
||||
case "statvalue":
|
||||
case "qualitystat":
|
||||
string statTypeString = subElement.GetAttributeString("stattype", "");
|
||||
if (!Enum.TryParse(statTypeString, true, out StatType statType))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid stat type type \"" + statTypeString + "\" in item (" + item.prefab.Identifier + ")");
|
||||
}
|
||||
float statValue = subElement.GetAttributeFloat("value", 0f);
|
||||
statValues.TryAdd(statType, statValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetValue(StatType statType)
|
||||
{
|
||||
if (!statValues.ContainsKey(statType)) { return 0.0f; }
|
||||
return statValues[statType] * qualityLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ namespace Barotrauma.Items.Components
|
||||
public RemoteController(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
DrawHudWhenEquipped = false;
|
||||
}
|
||||
|
||||
public override bool Select(Character character)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Repairable : ItemComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private string header;
|
||||
private readonly string header;
|
||||
|
||||
private float deteriorationTimer;
|
||||
private float deteriorateAlwaysResetTimer;
|
||||
@@ -182,6 +182,10 @@ namespace Barotrauma.Items.Components
|
||||
if (Rand.Range(0.0f, 0.5f) < RepairDegreeOfSuccess(character, requiredSkills)) { return true; }
|
||||
|
||||
ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
|
||||
if (bestRepairItem != null && bestRepairItem.GetComponent<Holdable>() is Holdable h)
|
||||
{
|
||||
h.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -217,6 +221,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GameServer.Log($"{GameServer.CharacterLogName(character)} failed to {(action == FixActions.Sabotage ? "sabotage" : "repair")} {item.Name}", ServerLog.MessageType.ItemInteraction);
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, character.ID });
|
||||
if (bestRepairItem != null && bestRepairItem.GetComponent<Holdable>() is Holdable h)
|
||||
{
|
||||
GameMain.Server?.CreateEntityEvent(bestRepairItem, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, h, character.ID });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -243,7 +252,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
return true;
|
||||
|
||||
Item GetBestRepairItem(Character character)
|
||||
static Item GetBestRepairItem(Character character)
|
||||
{
|
||||
return character.HeldItems.OrderByDescending(i => i.Prefab.AddedRepairSpeedMultiplier).FirstOrDefault();
|
||||
}
|
||||
@@ -386,6 +395,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
|
||||
fixDuration /= 1 + CurrentFixer.GetStatValue(StatTypes.RepairSpeed) + currentRepairItem?.Prefab.AddedRepairSpeedMultiplier ?? 0f;
|
||||
fixDuration /= 1 + item.GetQualityModifier(Quality.StatType.RepairSpeed);
|
||||
|
||||
item.MaxRepairConditionMultiplier = 1 + CurrentFixer.GetStatValue(StatTypes.MaxRepairConditionMultiplier);
|
||||
|
||||
if (currentFixerAction == FixActions.Repair)
|
||||
{
|
||||
|
||||
@@ -383,6 +383,10 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
float chargeDeltaTime = tryingToCharge ? deltaTime : -deltaTime;
|
||||
if (chargeDeltaTime > 0f && user != null)
|
||||
{
|
||||
chargeDeltaTime *= 1f + user.GetStatValue(StatTypes.TurretChargeSpeed);
|
||||
}
|
||||
currentChargeTime = Math.Clamp(currentChargeTime + chargeDeltaTime, 0f, MaxChargeTime);
|
||||
}
|
||||
tryingToCharge = false;
|
||||
|
||||
@@ -285,7 +285,7 @@ namespace Barotrauma.Items.Components
|
||||
int i = 0;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
if (subElement.Attribute("texture") == null)
|
||||
|
||||
@@ -97,13 +97,15 @@ namespace Barotrauma
|
||||
|
||||
private Dictionary<string, Connection> connections;
|
||||
|
||||
private List<Repairable> repairables;
|
||||
private readonly List<Repairable> repairables;
|
||||
|
||||
private Queue<float> impactQueue = new Queue<float>();
|
||||
private Quality qualityComponent;
|
||||
|
||||
private readonly Queue<float> impactQueue = new Queue<float>();
|
||||
|
||||
//a dictionary containing lists of the status effects in all the components of the item
|
||||
private bool[] hasStatusEffectsOfType;
|
||||
private Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
private readonly bool[] hasStatusEffectsOfType;
|
||||
private readonly Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; protected set; }
|
||||
|
||||
@@ -447,7 +449,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public bool IsFullCondition => MathUtils.NearlyEqual(Condition, MaxCondition);
|
||||
public float MaxCondition => Prefab.Health * healthMultiplier;
|
||||
public float MaxCondition => Prefab.Health * healthMultiplier * maxRepairConditionMultiplier * (1.0f + GetQualityModifier(Items.Components.Quality.StatType.Condition));
|
||||
public float ConditionPercentage => MathUtils.Percentage(Condition, MaxCondition);
|
||||
|
||||
private float offsetOnSelectedMultiplier = 1.0f;
|
||||
@@ -465,12 +467,18 @@ namespace Barotrauma
|
||||
public float HealthMultiplier
|
||||
{
|
||||
get => healthMultiplier;
|
||||
set
|
||||
{
|
||||
healthMultiplier = value;
|
||||
}
|
||||
set { healthMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); }
|
||||
}
|
||||
|
||||
|
||||
private float maxRepairConditionMultiplier = 1.0f;
|
||||
|
||||
[Serialize(1.0f, true)]
|
||||
public float MaxRepairConditionMultiplier
|
||||
{
|
||||
get => maxRepairConditionMultiplier;
|
||||
set { maxRepairConditionMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); }
|
||||
}
|
||||
|
||||
//the default value should be Prefab.Health, but because we can't use it in the attribute,
|
||||
//we'll just use NaN (which does nothing) and set the default value in the constructor/load
|
||||
[Serialize(float.NaN, false), Editable]
|
||||
@@ -618,6 +626,21 @@ namespace Barotrauma
|
||||
get { return Prefab.UseInHealthInterface; }
|
||||
}
|
||||
|
||||
public int Quality
|
||||
{
|
||||
get
|
||||
{
|
||||
return qualityComponent?.QualityLevel ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (qualityComponent != null)
|
||||
{
|
||||
qualityComponent.QualityLevel = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool InWater
|
||||
{
|
||||
get
|
||||
@@ -933,6 +956,8 @@ namespace Barotrauma
|
||||
ownInventory = itemContainer.Inventory;
|
||||
}
|
||||
|
||||
qualityComponent = GetComponent<Quality>();
|
||||
|
||||
InitProjSpecific();
|
||||
|
||||
if (callOnItemLoaded)
|
||||
@@ -1122,6 +1147,11 @@ namespace Barotrauma
|
||||
if (!componentsByType.ContainsKey(typeof(T))) { return Enumerable.Empty<T>(); }
|
||||
return components.Where(c => c is T).Cast<T>();
|
||||
}
|
||||
|
||||
public float GetQualityModifier(Quality.StatType statType)
|
||||
{
|
||||
return GetComponent<Quality>()?.GetValue(statType) ?? 0.0f;
|
||||
}
|
||||
|
||||
public void RemoveContained(Item contained)
|
||||
{
|
||||
|
||||
@@ -47,14 +47,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (ItemOwnsSelf(item)) { return false; }
|
||||
if (i < 0 || i >= slots.Length) { return false; }
|
||||
if (!container.CanBeContained(item)) { return false; }
|
||||
if (!container.CanBeContained(item, i)) { return false; }
|
||||
return item != null && slots[i].CanBePut(item, ignoreCondition) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
||||
}
|
||||
|
||||
public override bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition)
|
||||
{
|
||||
if (i < 0 || i >= slots.Length) { return false; }
|
||||
if (!container.CanBeContained(itemPrefab)) { return false; }
|
||||
if (!container.CanBeContained(itemPrefab, i)) { return false; }
|
||||
return itemPrefab != null && slots[i].CanBePut(itemPrefab, condition) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (itemPrefab == null) { return 0; }
|
||||
if (i < 0 || i >= slots.Length) { return 0; }
|
||||
if (!container.CanBeContained(itemPrefab)) { return 0; }
|
||||
if (!container.CanBeContained(itemPrefab, i)) { return 0; }
|
||||
return slots[i].HowManyCanBePut(itemPrefab, maxStackSize: Math.Min(itemPrefab.MaxStackSize, container.GetMaxStackSize(i)), condition);
|
||||
}
|
||||
|
||||
|
||||
@@ -370,6 +370,9 @@ namespace Barotrauma
|
||||
[Serialize(false, false, description: "Hides the condition bar displayed at the bottom of the inventory slot the item is in.")]
|
||||
public bool HideConditionBar { get; set; }
|
||||
|
||||
[Serialize(false, false, description: "Hides the condition displayed in the item's tooltip.")]
|
||||
public bool HideConditionInTooltip { get; set; }
|
||||
|
||||
//if true and the item has trigger areas defined, characters need to be within the trigger to interact with the item
|
||||
//if false, trigger areas define areas that can be used to highlight the item
|
||||
[Serialize(true, false)]
|
||||
@@ -1164,6 +1167,8 @@ namespace Barotrauma
|
||||
DefaultPrice ??= new PriceInfo(GetMinPrice() ?? 0, false);
|
||||
}
|
||||
|
||||
HideConditionInTooltip = element.GetAttributeBool("hideconditionintooltip", HideConditionBar);
|
||||
|
||||
//backwards compatibility
|
||||
if (categoryStr.Equals("Thalamus", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
@@ -128,6 +128,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float displayRange = Attack.Range;
|
||||
if (damageSource is Item sourceItem)
|
||||
{
|
||||
displayRange *= 1.0f + sourceItem.GetQualityModifier(Quality.StatType.ExplosionRadius);
|
||||
Attack.DamageMultiplier *= 1.0f + sourceItem.GetQualityModifier(Quality.StatType.ExplosionDamage);
|
||||
}
|
||||
|
||||
Vector2 cameraPos = GameMain.GameScreen.Cam.Position;
|
||||
float cameraDist = Vector2.Distance(cameraPos, worldPosition) / 2.0f;
|
||||
@@ -142,7 +147,7 @@ namespace Barotrauma
|
||||
|
||||
if (displayRange < 0.1f) { return; }
|
||||
|
||||
if (Attack.GetStructureDamage(1.0f) > 0.0f || Attack.GetLevelWallDamage(1.0f) > 0.0f)
|
||||
if (!MathUtils.NearlyEqual(Attack.GetStructureDamage(1.0f), 0.0f) || !MathUtils.NearlyEqual(Attack.GetLevelWallDamage(1.0f), 0.0f))
|
||||
{
|
||||
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker);
|
||||
}
|
||||
@@ -211,9 +216,9 @@ namespace Barotrauma
|
||||
float dist = Vector2.Distance(item.WorldPosition, worldPosition);
|
||||
float itemRadius = item.body == null ? 0.0f : item.body.GetMaxExtent();
|
||||
dist = Math.Max(0.0f, dist - ConvertUnits.ToDisplayUnits(itemRadius));
|
||||
if (dist > Attack.Range) { continue; }
|
||||
if (dist > displayRange) { continue; }
|
||||
|
||||
if (dist < Attack.Range * 0.5f && applyFireEffects && !item.FireProof && ignoreFireEffectsForTags.None(t => item.HasTag(t)))
|
||||
if (dist < displayRange * 0.5f && applyFireEffects && !item.FireProof && ignoreFireEffectsForTags.None(t => item.HasTag(t)))
|
||||
{
|
||||
//don't apply OnFire effects if the item is inside a fireproof container
|
||||
//(or if it's inside a container that's inside a fireproof container, etc)
|
||||
@@ -240,7 +245,7 @@ namespace Barotrauma
|
||||
|
||||
if (item.Prefab.DamagedByExplosions && !item.Indestructible)
|
||||
{
|
||||
float distFactor = 1.0f - dist / Attack.Range;
|
||||
float distFactor = 1.0f - dist / displayRange;
|
||||
float damageAmount = Attack.GetItemDamage(1.0f) * item.Prefab.ExplosionDamageMultiplier;
|
||||
|
||||
Vector2 explosionPos = worldPosition;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
@@ -8,6 +9,7 @@ using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using File = Barotrauma.IO.File;
|
||||
using FileStream = Barotrauma.IO.FileStream;
|
||||
using Path = Barotrauma.IO.Path;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -18,11 +20,12 @@ namespace Barotrauma
|
||||
public static readonly XmlReaderSettings ReaderSettings = new XmlReaderSettings
|
||||
{
|
||||
DtdProcessing = DtdProcessing.Prohibit,
|
||||
XmlResolver = null
|
||||
XmlResolver = null,
|
||||
IgnoreWhitespace = true,
|
||||
};
|
||||
|
||||
public static XmlReader CreateReader(System.IO.Stream stream)
|
||||
=> XmlReader.Create(stream, ReaderSettings);
|
||||
|
||||
public static XmlReader CreateReader(System.IO.Stream stream, string baseUri = "")
|
||||
=> XmlReader.Create(stream, ReaderSettings, baseUri);
|
||||
|
||||
public static XDocument TryLoadXml(System.IO.Stream stream)
|
||||
{
|
||||
@@ -52,8 +55,8 @@ namespace Barotrauma
|
||||
{
|
||||
ToolBox.IsProperFilenameCase(filePath);
|
||||
using FileStream stream = File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
|
||||
using XmlReader reader = CreateReader(stream);
|
||||
doc = XDocument.Load(reader);
|
||||
using XmlReader reader = CreateReader(stream, Path.GetFullPath(filePath));
|
||||
doc = XDocument.Load(reader, LoadOptions.SetBaseUri);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -79,7 +82,7 @@ namespace Barotrauma
|
||||
try
|
||||
{
|
||||
using FileStream stream = File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
|
||||
using XmlReader reader = CreateReader(stream);
|
||||
using XmlReader reader = CreateReader(stream, Path.GetFullPath(filePath));
|
||||
doc = XDocument.Load(reader);
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace Barotrauma
|
||||
// Only used by conditionals targeting an item. By default, containers check the parent item. This allows you to check the grandparent instead.
|
||||
public readonly bool TargetGrandParent;
|
||||
|
||||
public readonly bool TargetContainedItem;
|
||||
|
||||
// Remove this after refactoring
|
||||
public static bool IsValid(XAttribute attribute)
|
||||
{
|
||||
@@ -112,6 +114,7 @@ namespace Barotrauma
|
||||
TargetContainer = attribute.Parent.GetAttributeBool("targetcontainer", false);
|
||||
TargetSelf = attribute.Parent.GetAttributeBool("targetself", false);
|
||||
TargetGrandParent = attribute.Parent.GetAttributeBool("targetgrandparent", false);
|
||||
TargetContainedItem = attribute.Parent.GetAttributeBool("targetcontaineditem", false);
|
||||
|
||||
if (!Enum.TryParse(AttributeName, true, out Type))
|
||||
{
|
||||
@@ -171,6 +174,22 @@ namespace Barotrauma
|
||||
|
||||
public bool Matches(ISerializableEntity target)
|
||||
{
|
||||
if (TargetContainedItem)
|
||||
{
|
||||
if (target is Item item)
|
||||
{
|
||||
return item.ContainedItems.Any(it => Matches(it));
|
||||
}
|
||||
else if (target is Items.Components.ItemComponent ic)
|
||||
{
|
||||
return ic.Item.ContainedItems.Any(it => Matches(it));
|
||||
}
|
||||
else if (target is Character character)
|
||||
{
|
||||
return character.Inventory != null && character.Inventory.AllItems.Any(it => Matches(it));
|
||||
}
|
||||
}
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ConditionType.PropertyValue:
|
||||
|
||||
@@ -315,7 +315,11 @@ namespace Barotrauma.IO
|
||||
return System.IO.File.GetLastWriteTime(path);
|
||||
}
|
||||
|
||||
public static FileStream Open(string path, System.IO.FileMode mode, System.IO.FileAccess access = System.IO.FileAccess.ReadWrite)
|
||||
public static FileStream Open(
|
||||
string path,
|
||||
System.IO.FileMode mode,
|
||||
System.IO.FileAccess access = System.IO.FileAccess.ReadWrite,
|
||||
System.IO.FileShare? share = null)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
@@ -331,10 +335,12 @@ namespace Barotrauma.IO
|
||||
}
|
||||
break;
|
||||
}
|
||||
return new FileStream(path, System.IO.File.Open(path, mode,
|
||||
access =
|
||||
!Validation.CanWrite(path, false) ?
|
||||
System.IO.FileAccess.Read :
|
||||
access));
|
||||
access;
|
||||
var shareVal = share ?? (access == System.IO.FileAccess.Read ? System.IO.FileShare.Read : System.IO.FileShare.None);
|
||||
return new FileStream(path, System.IO.File.Open(path, mode, access, shareVal));
|
||||
}
|
||||
|
||||
public static FileStream OpenRead(string path)
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.1500.3.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Additions and changes:
|
||||
- More talents and talent-related items (all talent trees now functional and most of the talents implemented).
|
||||
|
||||
Changes:
|
||||
- Ignore hidden afflictions when determining treatment suggestions to show in the health interface.
|
||||
- Visualize leaks on the status monitor's hull condition tab (unstable only).
|
||||
- Added "condition_out" output to outpost O2 generator (unstable only).
|
||||
|
||||
Fixes:
|
||||
- Fixed crashing when reloading sprites or resetting to prefab in the sub editor.
|
||||
- Fixed ability to combine unidentified genetic materials with other genetic materials (unstable only).
|
||||
- Organ damage doesn't cause concussions (unstable only).
|
||||
- Fixed talent menu being accessible if you leave it open and switch to a game mode where it shouldn't be accessible (unstable only).
|
||||
- Fixed ability to contain items other than batteries in cargo scooter's battery slot (unstable only).
|
||||
- Damaging the mudraptor beak given by mudraptor genes damages the head instead of torso, added damage protection to the beak (unstable only).
|
||||
- Items that are set to be hidden in menus aren't shown in the status monitor's item finder (unstable only).
|
||||
- Fixed status monitor's item finder not showing wearable items (unstable only).
|
||||
- Fixed "in use by xxxx" warning being always visible when using a Reactor PDA (unstable only).
|
||||
- Fixed Reactor PDA rendering over the command interface (unstable only).
|
||||
- Fixed assault rifle crosshair being drawn when it's in the bag slot (unstable only).
|
||||
- Fixed equip buttons not being drawn on equipped items that can only be put to other equip slots, but not on the non-limb slots (e.g. assault rifle).
|
||||
|
||||
Modding:
|
||||
- Option to make property conditionals target contained items using the attribute targetcontaineditem="true".
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.1500.2.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
autorestart="false"
|
||||
LevelDifficulty="20"
|
||||
AllowedRandomMissionTypes="Random,Salvage,Monster,Cargo,Combat"
|
||||
AllowedClientNameChars="32-33,38-46,48-57,65-90,91-91,93-93,95-122,192-255,384-591,1024-1279,19968-40959,13312-19903,131072-15043983,15043985-173791,173824-178207,178208-183983,63744-64255,194560-195103"
|
||||
AllowedClientNameChars="32-33,38-46,48-57,65-90,91-91,93-93,95-122,192-255,384-591,1024-1279,19968-21327,21329-40959,13312-19903,131072-173791,173824-178207,178208-183983,63744-64255,194560-195103"
|
||||
ServerMessage=""
|
||||
tickrate="20"
|
||||
randomizeseed="True"
|
||||
|
||||
Reference in New Issue
Block a user