Track LocalMods as part of monolith

This commit is contained in:
2026-06-08 18:50:16 +03:00
parent 143f2fed7c
commit 1b214b44c2
1287 changed files with 139255 additions and 1 deletions
@@ -0,0 +1,36 @@
using Barotrauma;
using Microsoft.Xna.Framework.Graphics;
using MoreLevelContent.Shared.Generation;
using Microsoft.Xna.Framework;
using MoreLevelContent.Shared.Utils;
using Barotrauma.Items.Components;
using MoreLevelContent.Shared;
using System;
public static class ClientDebugDraw
{
internal static void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (Level.Loaded != null)
{
// spriteBatch.DrawCircle(new Vector2(Level.Loaded.StartPosition.X, -Level.Loaded.StartPosition.Y), CaveGenerationDirector.MIN_DIST_FROM_START, 16, Color.Red, thickness: 100);
// spriteBatch.DrawLine(new Vector2(0, -Level.Loaded.StartPosition.Y + (Sonar.DefaultSonarRange / 2)), new Vector2(int.MaxValue, -Level.Loaded.StartPosition.Y + (Sonar.DefaultSonarRange / 2)), Color.Yellow, thickness: 2 / Screen.Selected.Cam.Zoom * GUI.Scale);
}
foreach (var item in CaveGenerationDirector.Instance._InitialCaveCheckDebug)
{
GUI.DrawString(spriteBatch, new Vector2(item.Cell.Center.X, -item.Cell.Center.Y), "Cell", Color.Azure);
}
foreach (var (from, to) in MissionGenerationDirector.DebugPoints)
{
var from1 = new Vector2(from.X, -from.Y);
var to1 = new Vector2(to.X, -to.Y);
spriteBatch.DrawCircle(from1, 20, 8, Color.Aqua);
spriteBatch.DrawCircle(to1, 10, 8, Color.Yellow);
GUI.DrawLine(spriteBatch, from1, to1, Color.Red, width: 5);
}
if (CaveGenerationDirector.Instance.ActiveThalaCave != null) CaveGenerationDirector.Instance.ActiveThalaCave.DebugDraw(spriteBatch, cam);
}
}
+354
View File
@@ -0,0 +1,354 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using Barotrauma.MoreLevelContent.Shared.Config;
using Barotrauma.MoreLevelContent.Config;
using MoreLevelContent.Shared;
using OpenAL;
namespace Barotrauma.MoreLevelContent.Client.UI
{
public class ConfigMenu
{
public static ConfigMenu Instance { get; private set; }
private MLCConfig unsavedConfig;
private readonly GUIFrame mainFrame;
private readonly GUILayoutGroup tabber;
private readonly GUIFrame contentFrame;
private readonly GUILayoutGroup bottom;
private readonly Dictionary<Tab, (GUIButton Button, GUIFrame Content)> tabContents;
public ConfigMenu(RectTransform mainParent)
{
unsavedConfig = ConfigManager.Instance.Config;
mainFrame = new GUIFrame(new RectTransform(Vector2.One, mainParent));
var mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.95f, mainFrame.RectTransform, Anchor.Center, Pivot.Center),
isHorizontal: false, childAnchor: Anchor.TopRight);
_ = new GUITextBlock(new RectTransform((1.0f, 0.07f), mainLayout.RectTransform), TextManager.Get("mlc.config"),
font: GUIStyle.LargeFont);
var tabberAndContentLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.86f), mainLayout.RectTransform),
isHorizontal: true);
void tabberPadding()
=> new GUIFrame(new RectTransform((0.01f, 1.0f), tabberAndContentLayout.RectTransform), style: null);
tabberPadding();
tabber = new GUILayoutGroup(new RectTransform((0.06f, 1.0f), tabberAndContentLayout.RectTransform), isHorizontal: false) { AbsoluteSpacing = GUI.IntScale(5f) };
tabberPadding();
tabContents = new Dictionary<Tab, (GUIButton Button, GUIFrame Content)>();
contentFrame = new GUIFrame(new RectTransform((0.92f, 1.0f), tabberAndContentLayout.RectTransform),
style: "InnerFrame");
bottom = new GUILayoutGroup(new RectTransform((contentFrame.RectTransform.RelativeSize.X, 0.04f), mainLayout.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.01f };
var tabToSelect = Tab.Debug;
tabToSelect = MakePermissionLockedTabs(tabToSelect);
CreateDebugTab();
CreateBottomButtons();
SelectTab(tabToSelect);
}
private Tab MakePermissionLockedTabs(Tab defaultTab)
{
// If we're not in single player
if (!GameMain.IsSingleplayer)
{
// and we don't have perms
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings))
return defaultTab; // don't create perm locked tabs
}
CreateGeneralTab();
CreatePirateOutpostTab();
return Tab.General;
}
GUITextBlock moveRuinsChanceDisplay;
GUITextBlock maxDistressCountDisplay;
GUITextBlock distressSpawnChanceDisplay;
private void CreateGeneralTab()
{
GUIFrame content = CreateNewContentFrame(Tab.General);
var (left, right) = CreateSidebars(content);
Tickbox(left,
TextManager.Get("mlc.settings.enablethalamuscave"),
TextManager.Get("mlc.settings.enablethalamuscavetooltip"),
unsavedConfig.NetworkedConfig.GeneralConfig.EnableThalamusCaves,
(v) => unsavedConfig.NetworkedConfig.GeneralConfig.EnableThalamusCaves = v);
Tickbox(left,
TextManager.Get("mlc.settings.enabledistressmissions"),
TextManager.Get("mlc.settings.enabledistressmissionstooltip"),
unsavedConfig.NetworkedConfig.GeneralConfig.EnableDistressMissions,
(v) => unsavedConfig.NetworkedConfig.GeneralConfig.EnableDistressMissions = v);
Tickbox(left,
TextManager.Get("mlc.settings.enablemapfeature"),
TextManager.Get("mlc.settings.enablemapfeaturetooltip"),
unsavedConfig.NetworkedConfig.GeneralConfig.EnableMapFeatures,
(v) => unsavedConfig.NetworkedConfig.GeneralConfig.EnableMapFeatures = v);
Tickbox(left,
TextManager.Get("mlc.settings.enablerelaystation"),
TextManager.Get("mlc.settings.enablerelaystationtooltip"),
unsavedConfig.NetworkedConfig.GeneralConfig.EnableRelayStations,
(v) => unsavedConfig.NetworkedConfig.GeneralConfig.EnableRelayStations = v);
Tickbox(left,
TextManager.Get("mlc.settings.enableconstructionsites"),
TextManager.Get("mlc.settings.enableconstructionsitestooltip"),
unsavedConfig.NetworkedConfig.GeneralConfig.EnableConstructionSites,
(v) => unsavedConfig.NetworkedConfig.GeneralConfig.EnableConstructionSites = v);
var moveRuinsChance = Label(left, TextManager.Get("mlc.settings.moveruins"), GUIStyle.SubHeadingFont);
moveRuinsChanceDisplay = TextBlock(moveRuinsChance, TextManager.Get("mlc.settings.moveruinstooltip"));
Slider(left, (0, 100), 100, (v) => $"{Round(v)}%",
unsavedConfig.NetworkedConfig.GeneralConfig.RuinMoveChance,
(v) => UpdateRuinMoveChance(v));
var maxActiveDistress = Label(left, TextManager.Get("mlc.settings.maxdistresscount"), GUIStyle.SubHeadingFont);
maxDistressCountDisplay = TextBlock(maxActiveDistress, TextManager.Get("mlc.settings.maxdistresscounttooltip"));
Slider(left, (0, 100), 100, (v) => $"{Round(v)}",
unsavedConfig.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons,
(v) => UpdateMaxDistress(v));
var distressSpawnChance = Label(left, TextManager.Get("mlc.settings.spawndistresschance"), GUIStyle.SubHeadingFont);
distressSpawnChanceDisplay = TextBlock(distressSpawnChance, TextManager.Get("mlc.settings.spawndistresschancetooltip"));
Slider(left, (0, 100), 100, (v) => $"{Round(v)}",
unsavedConfig.NetworkedConfig.GeneralConfig.DistressSpawnChance,
(v) => UpdateDistressSpawnChance(v));
void UpdateRuinMoveChance(float v)
{
unsavedConfig.NetworkedConfig.GeneralConfig.RuinMoveChance = Round(v);
moveRuinsChanceDisplay.Text = TextManager.GetWithVariable("mlc.settings.spawnchance", "[chance]", Round(v).ToString()); ;
}
void UpdateMaxDistress(float v)
{
unsavedConfig.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons = Round(v);
maxDistressCountDisplay.Text = TextManager.GetWithVariable("mlc.settings.maxactive", "[max]", Round(v).ToString()); ;
}
void UpdateDistressSpawnChance(float v)
{
unsavedConfig.NetworkedConfig.GeneralConfig.DistressSpawnChance = Round(v);
distressSpawnChanceDisplay.Text = TextManager.GetWithVariable("mlc.settings.spawnchance", "[chance]", Round(v).ToString());
}
UpdateRuinMoveChance(unsavedConfig.NetworkedConfig.GeneralConfig.RuinMoveChance);
UpdateMaxDistress(unsavedConfig.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons);
UpdateDistressSpawnChance(unsavedConfig.NetworkedConfig.GeneralConfig.DistressSpawnChance);
GUITextBlock TextBlock(GUITextBlock container, RichString tooltip)
{
return new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), container.RectTransform), "", textAlignment: Alignment.CenterRight)
{
ToolTip = tooltip
};
}
}
GUITextBlock pirateSpawnChanceDisplay;
private void CreatePirateOutpostTab()
{
GUIFrame content = CreateNewContentFrame(Tab.PirateOutpost);
var (left, right) = CreateSidebars(content);
Tickbox(left,
TextManager.Get("mlc.settings.enablepiratebase"),
TextManager.Get("mlc.settings.enablepiratebasetooltip"),
unsavedConfig.NetworkedConfig.PirateConfig.EnablePirateBases,
(v) => unsavedConfig.NetworkedConfig.PirateConfig.EnablePirateBases = v);
// If the pirate outpost is displayed on sonar
Tickbox(left,
TextManager.Get("mlc.config.piratedisplaysonar"),
TextManager.Get("mlc.config.piratedisplaysonartooltip"),
unsavedConfig.NetworkedConfig.PirateConfig.DisplaySonarMarker,
(v) => unsavedConfig.NetworkedConfig.PirateConfig.DisplaySonarMarker = v);
// If the pirate difficulty should scale with server memebers
Tickbox(left,
TextManager.Get("mlc.config.piratescalediff"),
TextManager.Get("mlc.config.piratescaledifftooltip"),
unsavedConfig.NetworkedConfig.PirateConfig.AddDiffPerPlayer,
(v) => unsavedConfig.NetworkedConfig.PirateConfig.AddDiffPerPlayer = v);
}
private void CreateDebugTab()
{
GUIFrame content = CreateNewContentFrame(Tab.Debug);
var (left, right) = CreateSidebars(content);
Tickbox(left, TextManager.Get("mlc.config.debugverbose"), TextManager.Get("mlc.config.debugverbosetooltip"), unsavedConfig.Client.Verbose, (v) => unsavedConfig.Client.Verbose = v);
Tickbox(left, TextManager.Get("mlc.config.debuginternal"), TextManager.Get("mlc.config.debuginternaltooltip"), unsavedConfig.Client.Internal, (v) => unsavedConfig.Client.Internal = v);
GUIButton showPatchNotes = new GUIButton(NewItemRectT(left), text: "Patch Notes")
{
OnClicked = (btn, obj) =>
{
MoreLevelContent.Client.UI.PatchNotes.Open();
return false;
}
};
}
private void CreateBottomButtons()
{
GUIButton cancelButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Cancel")
{
OnClicked = (btn, obj) =>
{
Close();
return false;
}
};
GUIButton applyButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Apply")
{
OnClicked = (btn, obj) =>
{
ConfigManager.Instance.SetConfig(unsavedConfig);
mainFrame.Flash(color: GUIStyle.Green);
return false;
}
};
}
private void Tickbox(GUILayoutGroup parent, LocalizedString label, LocalizedString tooltip, bool currentValue, Action<bool> setter)
{
var tickbox = new GUITickBox(NewItemRectT(parent), label)
{
Selected = currentValue,
ToolTip = tooltip,
OnSelected = (tb) =>
{
setter(tb.Selected);
return true;
}
};
}
private int Round(float v) => (int)MathF.Round(v);
private void Slider(GUILayoutGroup parent, Vector2 range, int steps, Func<float, string> labelFunc, float currentValue, Action<float> setter, LocalizedString tooltip = null)
{
var layout = new GUILayoutGroup(NewItemRectT(parent), isHorizontal: true);
var slider = new GUIScrollBar(new RectTransform((0.82f, 1.0f), layout.RectTransform), style: "GUISlider")
{
Range = range,
BarScrollValue = currentValue,
Step = 1.0f / (steps - 1),
BarSize = 1.0f / steps
};
if (tooltip != null)
{
slider.ToolTip = tooltip;
}
var label = new GUITextBlock(new RectTransform((0.18f, 1.0f), layout.RectTransform),
labelFunc(currentValue), wrap: false, textAlignment: Alignment.Center);
slider.OnMoved = (sb, val) =>
{
label.Text = labelFunc(sb.BarScrollValue);
setter(sb.BarScrollValue);
return true;
};
}
private static GUITextBlock Label(GUILayoutGroup parent, LocalizedString str, GUIFont font) => new GUITextBlock(NewItemRectT(parent), str, font: font);
private static RectTransform NewItemRectT(GUILayoutGroup parent)
=> new RectTransform((1.0f, 0.06f), parent.RectTransform, Anchor.CenterLeft);
private static (GUILayoutGroup Left, GUILayoutGroup Right) CreateSidebars(GUIFrame parent, bool split = false)
{
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(Vector2.One, parent.RectTransform), isHorizontal: true);
GUILayoutGroup left = new GUILayoutGroup(new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal: false);
var centerFrame = new GUIFrame(new RectTransform((0.025f, 1.0f), layout.RectTransform), style: null);
if (split)
{
_ = new GUICustomComponent(new RectTransform(Vector2.One, centerFrame.RectTransform),
onDraw: (sb, c) => sb.DrawLine((c.Rect.Center.X, c.Rect.Top), (c.Rect.Center.X, c.Rect.Bottom), GUIStyle.TextColorDim, 2f));
}
GUILayoutGroup right = new GUILayoutGroup(new RectTransform((0.4875f, 1.0f), layout.RectTransform), isHorizontal: false);
return (left, right);
}
private GUIFrame CreateNewContentFrame(Tab tab)
{
var content = new GUIFrame(new RectTransform(Vector2.One * 0.95f, contentFrame.RectTransform, Anchor.Center, Pivot.Center), style: null);
AddButtonToTabber(tab, content);
return content;
}
private void AddButtonToTabber(Tab tab, GUIFrame content)
{
var button = new GUIButton(new RectTransform(Vector2.One, tabber.RectTransform, Anchor.TopLeft, Pivot.TopLeft, scaleBasis: ScaleBasis.Smallest), "", style: $"SettingsMenuTab.{tab}")
{
ToolTip = TextManager.Get($"SettingsTab.{tab}"),
OnClicked = (b, _) =>
{
SelectTab(tab);
return false;
}
};
button.RectTransform.MaxSize = RectTransform.MaxPoint;
button.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
tabContents.Add(tab, (button, content));
}
public void SelectTab(Tab tab)
{
SwitchContent(tabContents[tab].Content);
tabber.Children.ForEach(c =>
{
if (c is GUIButton btn) { btn.Selected = btn == tabContents[tab].Button; }
});
}
private void SwitchContent(GUIFrame newContent)
{
contentFrame.Children.ForEach(c => c.Visible = false);
newContent.Visible = true;
}
public static ConfigMenu Create(RectTransform mainParent)
{
Instance?.Close();
Instance = new ConfigMenu(mainParent);
return Instance;
}
public void Close()
{
mainFrame.Parent.RemoveChild(mainFrame);
Instance = null;
ConfigManager.Instance.SettingsOpen = false;
}
public enum Tab
{
General,
PirateOutpost,
Debug
}
}
}
+273
View File
@@ -0,0 +1,273 @@
using Barotrauma.MoreLevelContent.Shared.Utils;
using System.Reflection;
using MoreLevelContent;
using HarmonyLib;
using MoreLevelContent.Shared.Data;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MoreLevelContent.Shared;
using MoreLevelContent.Shared.Generation;
using System.Threading;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection.Emit;
using Barotrauma.MoreLevelContent.Config;
namespace Barotrauma.MoreLevelContent.Client.UI
{
public class MapUI : Singleton<MapUI>
{
static FieldInfo zoomLevel;
static FieldInfo tooltipField;
static FieldInfo pendingSubInfoField;
static MethodInfo isInFogOfWar;
static bool _DrawingConnections = false;
public override void Setup()
{
var drawConnection = typeof(Map).GetMethod("DrawConnection", BindingFlags.NonPublic | BindingFlags.Instance);
var draw = AccessTools.Method(typeof(Map), nameof(Map.Draw));
zoomLevel = typeof(Map).GetField("zoom", BindingFlags.Instance | BindingFlags.NonPublic);
tooltipField = typeof(Map).GetField("tooltip", BindingFlags.Instance | BindingFlags.NonPublic);
pendingSubInfoField = AccessTools.Field(typeof(Map), "pendingSubInfo");
isInFogOfWar = AccessTools.Method(typeof(Map), "IsInFogOfWar");
_ = Main.Harmony.Patch(draw, transpiler: new HarmonyMethod(AccessTools.Method(typeof(MapUI), nameof(TranspileMapDraw))));
_ = Main.Harmony.Patch(drawConnection, postfix: new HarmonyMethod(GetType().GetMethod(nameof(OnDrawConnection), BindingFlags.NonPublic | BindingFlags.Static)));
}
private static SubmarineInfo.PendingSubInfo pendingSubInfo;
private static IEnumerable<CodeInstruction> TranspileMapDraw(IEnumerable<CodeInstruction> instructions, ILGenerator il)
{
Log.Debug("Transpiling map draw...");
bool finished = false;
var code = new List<CodeInstruction>(instructions);
for (int i = 0; i < code.Count; i++)
{
if (finished == false && code[i].opcode == OpCodes.Stloc_S && code[i].operand.ToString() == "Barotrauma.LocationConnection (32)")
{
finished = true;
yield return code[i];
yield return new CodeInstruction(OpCodes.Ldloc_S, code[i].operand); // Location connection
yield return new CodeInstruction(OpCodes.Ldarg_0); // Map
yield return new CodeInstruction(OpCodes.Ldarg_2); // Sprite batch
yield return new CodeInstruction(OpCodes.Ldloc_1); // View area
yield return new CodeInstruction(OpCodes.Ldloc_S, (byte)4); // View Offset
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(MapUI), nameof(DrawRevealedFeatures)));
yield return new CodeInstruction(OpCodes.Ldloc_S, code[i].operand);
}
yield return code[i];
}
if (!finished) Log.Error("Failed to find map transpile injection point!");
}
private static void DrawRevealedFeatures(LocationConnection connection, Map map, SpriteBatch spriteBatch, Rectangle viewArea, Vector2 viewOffset)
{
// Skip if we don't have a feature or pirate base
if (!CheckValid()) return;
// Both sides are in fog of war
bool inFow = (bool)isInFogOfWar.Invoke(map, new object[] { connection.Locations[0] }) && (bool)isInFogOfWar.Invoke(map, new object[] { connection.Locations[1] });
if (inFow)
{
DrawCustomConnections(spriteBatch, connection, viewArea, viewOffset, map, true);
//Log.Debug("Drew custom connection");
}
bool CheckValid()
{
var feature = connection.LevelData.MLC().MapFeatureData;
var pirateBase = connection.LevelData.MLC().PirateData;
if (pirateBase.HasPirateBase && pirateBase.Revealed) return true;
// Not valid if we don't have a feature
if (!feature.HasFeature) return false;
// Not valid if the feature isn't revealed
if (!feature.Revealed) return false;
// Not valid if the feature starts revealed
if (!feature.Feature.Display.HideUntilRevealed) return false;
return true;
}
}
private static void OnDrawConnection(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Map __instance, bool __state)
{
if (__state) return;
DrawCustomConnections(spriteBatch, connection, viewArea, viewOffset, __instance, false);
}
private static void DrawCustomConnections(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Map __instance, bool drawInFOW)
{
_DrawingConnections = false;
if (connection == null || spriteBatch == null) return;
LevelData_MLCData data = connection.LevelData.MLC();
Vector2? connectionStart = null;
Vector2? connectionEnd = null;
Vector2 rectCenter = viewArea.Center.ToVector2();
int startIndex = connection.CrackSegments.Count > 2 ? 1 : 0;
int endIndex = connection.CrackSegments.Count > 2 ? connection.CrackSegments.Count - 1 : connection.CrackSegments.Count;
float zoom = (float)zoomLevel.GetValue(__instance);
int iconCount, iconIndex = GetIconIndex(connection);
for (int i = startIndex; i < endIndex; i++)
{
var segment = connection.CrackSegments[i];
Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom;
Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom;
connectionEnd = end;
if (!connectionStart.HasValue) { connectionStart = start; }
}
iconCount = GetIconCount(__instance, connection);
if (drawInFOW)
{
iconCount = 0;
DrawMapFeature(data);
DrawPirateBase();
return;
}
if (data.HasBeaconConstruction && ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableConstructionSites)
{
LocalizedString localizedString = TextManager.GetWithVariable("mlc.beaconconsttooltip", "[requestedsupplies]", data.GetRequestedSupplies());
DrawIcon("BeaconConst", (int)(28 * zoom), RichString.Rich(localizedString));
}
if (data.HasDistress && ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableDistressMissions)
{
string tooltip = "mlc.distresstooltip";
string iconStyle = "DistressBeacon";
if (data.DistressStepsLeft <= 3)
{
tooltip = "mlc.distresstooltipfaint";
iconStyle = "DistressBeaconFaint";
}
LocalizedString localizedString = TextManager.Get(tooltip);
DrawIcon(iconStyle, (int)(28 * zoom), RichString.Rich(localizedString));
}
if (data.HasLostCargo)
{
DrawIcon("LostCargo", (int)(28 * zoom), RichString.Rich(TextManager.Get("mlc.lostcargotooltip")));
}
if (data.HasRelayStation && ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableRelayStations)
{
var iconName = data.RelayStationStatus == RelayStationStatus.Active ? "RelayStationActive" : "RelayStationInactive";
var locString = data.RelayStationStatus == RelayStationStatus.Active ? "mlc.relaystationtooltip.active" : "mlc.relaystationtooltip.inactive";
LocalizedString localizedString = TextManager.Get(locString);
DrawIcon(iconName, (int)(28 * zoom), RichString.Rich(localizedString));
}
DrawPirateBase();
DrawMapFeature(data);
void DrawMapFeature(LevelData_MLCData data)
{
if (!ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableMapFeatures) return;
if (data.MapFeatureData.Name.IsEmpty) return;
if (!data.MapFeatureData.Revealed && !GameMain.DebugDraw && !Commands.DisplayAllMapLocations) return;
if (!MapFeatureModule.TryGetFeature(data.MapFeatureData.Name, out MapFeature feature))
{
Log.Error($"Failed to find map feature with identifier {data.MapFeatureData.Name}!!");
return;
}
var tooltip = TextManager.Get(feature.Display.Tooltip);
if (GameMain.DebugDraw)
{
tooltip = $"{tooltip.Value} + {data.MapFeatureData.Revealed}";
}
DrawIcon(feature.Display.Icon, (int)(28 * zoom), RichString.Rich(tooltip));
}
void DrawPirateBase()
{
if (ConfigManager.Instance.Config.NetworkedConfig.PirateConfig.EnablePirateBases &&
data.PirateData.HasPirateBase &&
(GameMain.DebugDraw || Commands.DisplayAllMapLocations || data.PirateData.Revealed))
{ } else { return; }
LocalizedString text = "";
switch (data.PirateData.Status)
{
case PirateOutpostStatus.Active:
text = TextManager.Get("piratebase.active");
break;
case PirateOutpostStatus.Destroyed:
text = TextManager.Get("piratebase.destroyed");
break;
case PirateOutpostStatus.Husked:
text = TextManager.Get("piratebase.husked");
break;
}
if (GameMain.DebugDraw)
{
text += $" Revealed: {data.PirateData.Revealed}";
}
DrawIcon(data.PirateData.Status == PirateOutpostStatus.Active ? "PirateBase" : "PirateBaseDestroyed", (int)(28 * zoom), RichString.Rich(text));
}
void DrawIcon(string iconStyle, int iconSize, RichString tooltipText)
{
Vector2 iconPos = (connectionStart.Value + connectionEnd.Value) / 2;
Vector2 iconDiff = Vector2.Normalize(connectionEnd.Value - connectionStart.Value) * iconSize;
iconPos += (iconDiff * -(iconCount - 1) / 2.0f) + iconDiff * iconIndex;
var style = GUIStyle.GetComponentStyle(iconStyle);
if (style == null)
{
Log.Error($"Unable to find icon style {style}");
return;
}
bool mouseOn = Vector2.DistanceSquared(iconPos, PlayerInput.MousePosition) < iconSize * iconSize && IsPreferredTooltip(iconPos, __instance);
Sprite iconSprite = style.GetDefaultSprite();
iconSprite.Draw(spriteBatch, iconPos, (mouseOn ? style.HoverColor : style.Color) * 0.7f,
scale: iconSize / iconSprite.size.X);
if (mouseOn)
{
tooltipField.SetValue(__instance, (new Rectangle((iconPos - Vector2.One * iconSize / 2).ToPoint(), new Point(iconSize)), tooltipText));
}
iconIndex++;
}
bool IsPreferredTooltip(Vector2 tooltipPos, Map map) => tooltipField.GetValue(map) == null || Vector2.DistanceSquared(tooltipPos, PlayerInput.MousePosition) < Vector2.DistanceSquared((tooltipField.GetValue(map) as (Rectangle targetArea, RichString tip)?).Value.targetArea.Center.ToVector2(), PlayerInput.MousePosition);
int GetIconCount(Map __instance, LocationConnection connection)
{
int iconCount = 0;
float subCrushDepth = SubmarineInfo.GetSubCrushDepth(SubmarineSelection.CurrentOrPendingSubmarine(), ref pendingSubInfo);
if (connection.LevelData.InitialDepth * Physics.DisplayToRealWorldRatio > subCrushDepth)
{
iconIndex++;
iconCount++;
}
else if ((connection.LevelData.InitialDepth + connection.LevelData.Size.Y) * Physics.DisplayToRealWorldRatio > subCrushDepth)
{
iconIndex++;
iconCount++;
}
return iconCount;
}
int GetIconIndex(LocationConnection connection)
{
int index = 0;
if (connection.LevelData.HasBeaconStation) index++;
if (connection.Locked) index++;
if (connection.LevelData.HasHuntingGrounds) index++;
return index;
}
}
}
}
@@ -0,0 +1,73 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using Barotrauma.MoreLevelContent.Config;
using MoreLevelContent;
namespace Barotrauma.MoreLevelContent.Client.UI
{
public class PatchNotes
{
private readonly GUIFrame mainFrame;
private readonly GUIFrame backgroundBlocker;
private readonly GUIFrame contentFrame;
private readonly GUILayoutGroup bottom;
public static PatchNotes Instance { get; private set; }
public PatchNotes()
{
backgroundBlocker = new GUIFrame(new RectTransform(Vector2.One, Screen.Selected.Frame.RectTransform, Anchor.Center), style: null);
_ = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, backgroundBlocker.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
var mainParent = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.55f), backgroundBlocker.RectTransform, Anchor.Center, scaleBasis: ScaleBasis.Smallest) { MinSize = new Point(640, 480) }).RectTransform;
mainFrame = new GUIFrame(new RectTransform(Vector2.One, mainParent));
var mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.95f, mainFrame.RectTransform, Anchor.Center, Pivot.Center),
isHorizontal: false, childAnchor: Anchor.TopRight);
_ = new GUITextBlock(new RectTransform((1.0f, 0.07f), mainLayout.RectTransform), TextManager.GetWithVariable("mlc.patchnote", "[version]", Main.Version),
font: GUIStyle.LargeFont);
// Padding
_ = new GUIFrame(new RectTransform((0.01f, 0.01f), mainLayout.RectTransform), style: null);
contentFrame = new GUIFrame(new RectTransform((1.0f, 0.8f), mainLayout.RectTransform),
style: "InnerFrame");
_ = new GUITextBlock(new RectTransform((1.0f, 1.0f), contentFrame.RectTransform), TextManager.Get("mlc.patchnotes").Value ?? "hot spicy meme action", textAlignment: Alignment.TopLeft);
// Padding
_ = new GUIFrame(new RectTransform((0.01f, 0.01f), mainLayout.RectTransform), style: null);
bottom = new GUILayoutGroup(new RectTransform((1.0f, 0.04f), mainLayout.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.01f };
CreateBottomButton();
}
private void CreateBottomButton()
{
GUIButton cancelButton =
new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), bottom.RectTransform), text: "close")
{
OnClicked = (btn, obj) =>
{
Close();
return false;
}
};
}
public static void Open()
{
Instance?.Close();
Instance = new PatchNotes();
ConfigManager.ShouldDisplayPatchNotes = false;
}
public void Close()
{
mainFrame.Parent.RemoveChild(mainFrame);
backgroundBlocker.Parent.RemoveChild(backgroundBlocker);
if (Instance == this) { Instance = null; }
}
}
}