3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
22 public Action<SubmarineInfo, string, string, CampaignSettings>
StartNewGame;
48 this.loadGameContainer = loadGameContainer;
54 if (
string.IsNullOrEmpty(saveInfo.FilePath))
56 DebugConsole.AddWarning(
"Error when updating campaign load menu: path to a save file was empty.\n" + Environment.StackTrace);
62 style:
"ListBoxElement")
68 new RectTransform(
new Vector2(1.0f, 0.5f), saveFrame.RectTransform),
69 Path.GetFileNameWithoutExtension(saveInfo.FilePath),
70 textColor: GUIStyle.TextColorBright)
75 if (saveInfo.EnabledContentPackageNames !=
null && saveInfo.EnabledContentPackageNames.Any())
80 saveFrame.ToolTip =
string.Join(
"\n", errorMsg, TextManager.Get(
"campaignmode.contentpackagemismatchwarning"));
89 text: saveInfo.SubmarineName,
90 font: GUIStyle.SmallFont)
93 UserData = saveInfo.FilePath
96 string saveTimeStr =
string.Empty;
97 if (saveInfo.SaveTime.TryUnwrap(out var time))
99 saveTimeStr = time.ToLocalUserString();
102 new RectTransform(
new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
104 textAlignment: Alignment.Right,
105 font: GUIStyle.SmallFont)
107 CanBeFocused =
false,
108 UserData = saveInfo.FilePath
118 if (c1.GUIComponent.UserData is not
CampaignMode.SaveInfo file1
119 || c2.GUIComponent.UserData is not
CampaignMode.SaveInfo file2)
124 if (!file1.SaveTime.TryUnwrap(out var file1WriteTime)
125 || !file2.SaveTime.TryUnwrap(out var file2WriteTime))
130 return file2WriteTime.CompareTo(file1WriteTime);
156 return new CampaignSettings(element:
null)
181 private readonly Func<T> getter;
182 private readonly Action<T> setter;
186 return getter.Invoke();
191 setter.Invoke(value);
201 private readonly
struct SettingCarouselElement<T>
204 public readonly T Value;
205 public readonly
bool IsHidden;
207 public SettingCarouselElement(T value,
string label,
bool isHidden =
false)
210 Label = TextManager.Get(label).Fallback(label);
217 const float verticalSize = 0.14f;
219 bool loadingPreset =
false;
224 childAnchor:
Anchor.CenterLeft);
227 TextManager.Get(
"campaignsettingpreset"));
230 elementCount: CampaignModePresets.List.Length + 1);
231 presetDropdown.
AddItem(TextManager.Get(
"karmapreset.custom"),
null);
236 foreach (CampaignSettings settings
in CampaignModePresets.List)
238 string name = settings.PresetName;
239 presetDropdown.AddItem(TextManager.Get($
"preset.{name}").Fallback(name), settings);
241 if (settings.PresetName.Equals(prevSettings.PresetName, StringComparison.OrdinalIgnoreCase))
243 presetDropdown.SelectItem(settings);
248 get: () => presetDropdown.SelectedData is CampaignSettings settings ? settings.PresetName :
string.Empty,
249 set:
static _ => { });
253 Spacing = GUI.IntScale(5)
264 TextManager.Get(
"CampaignOption.EnableTutorial"),
265 TextManager.Get(
"campaignoption.enabletutorial.tooltip"),
266 prevSettings.TutorialEnabled,
274 TextManager.Get(
"CampaignOption.EnableRadiation"),
275 TextManager.Get(
"campaignoption.enableradiation.tooltip"),
276 prevSettings.RadiationEnabled,
285 ImmutableArray<SettingCarouselElement<Identifier>> startingSetOptions =
287 .OrderBy(s => s.Order)
288 .Select(
set =>
new SettingCarouselElement<Identifier>(
290 $
"startitemset.{set.Identifier}"))
292 SettingCarouselElement<Identifier> prevStartingSet = startingSetOptions
293 .FirstOrNull(element => element.Value == prevSettings.StartItemSet)
294 ?? startingSetOptions[1];
297 TextManager.Get(
"startitemset"),
298 TextManager.Get(
"startitemsettooltip"),
305 ImmutableArray<SettingCarouselElement<StartingBalanceAmountOption>> fundOptions = ImmutableArray.Create(
310 SettingCarouselElement<StartingBalanceAmountOption> prevStartingFund = fundOptions
311 .FirstOrNull(element => element.Value == prevSettings.StartingBalanceAmount)
315 TextManager.Get(
"startingfundsdescription"),
316 TextManager.Get(
"startingfundstooltip"),
325 TextManager.Get(
"maxmissioncount"),
326 TextManager.Get(
"maxmissioncounttooltip"),
327 prevSettings.MaxMissionCount,
329 minValue: CampaignSettings.MinMissionCountLimit,
330 maxValue: CampaignSettings.MaxMissionCountLimit,
335 CampaignSettings.MultiplierSettings rewardMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"MissionRewardMultiplier");
338 TextManager.Get(
"campaignoption.missionrewardmultiplier"),
339 TextManager.Get(
"campaignoption.missionrewardmultiplier.tooltip"),
340 prevSettings.MissionRewardMultiplier,
341 valueStep: rewardMultiplierSettings.Step,
342 minValue: rewardMultiplierSettings.Min,
343 maxValue: rewardMultiplierSettings.Max,
348 CampaignSettings.MultiplierSettings shopPriceMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"ShopPriceMultiplier");
351 TextManager.Get(
"campaignoption.shoppricemultiplier"),
352 TextManager.Get(
"campaignoption.shoppricemultiplier.tooltip"),
353 prevSettings.ShopPriceMultiplier,
354 valueStep: shopPriceMultiplierSettings.Step,
355 minValue: shopPriceMultiplierSettings.Min,
356 maxValue: shopPriceMultiplierSettings.Max,
361 CampaignSettings.MultiplierSettings shipyardPriceMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"ShipyardPriceMultiplier");
364 TextManager.Get(
"campaignoption.shipyardpricemultiplier"),
365 TextManager.Get(
"campaignoption.shipyardpricemultiplier.tooltip"),
366 prevSettings.ShipyardPriceMultiplier,
367 valueStep: shipyardPriceMultiplierSettings.Step,
368 minValue: shipyardPriceMultiplierSettings.Min,
369 maxValue: shipyardPriceMultiplierSettings.Max,
378 ImmutableArray<SettingCarouselElement<WorldHostilityOption>> hostilityOptions = ImmutableArray.Create(
379 new SettingCarouselElement<WorldHostilityOption>(
WorldHostilityOption.Low,
"worldhostility.low"),
380 new SettingCarouselElement<WorldHostilityOption>(
WorldHostilityOption.Medium,
"worldhostility.medium"),
381 new SettingCarouselElement<WorldHostilityOption>(
WorldHostilityOption.High,
"worldhostility.high"),
382 new SettingCarouselElement<WorldHostilityOption>(
WorldHostilityOption.Hellish,
"worldhostility.hellish", isHidden:
true)
384 SettingCarouselElement<WorldHostilityOption> prevHostility = hostilityOptions
385 .FirstOrNull(element => element.Value == prevSettings.WorldHostility)
386 ?? hostilityOptions[1];
389 TextManager.Get(
"worldhostility"),
390 TextManager.Get(
"worldhostility.tooltip"),
397 CampaignSettings.MultiplierSettings crewVitalityMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"CrewVitalityMultiplier");
400 TextManager.Get(
"campaignoption.maxvitalitymultipliercrew"),
401 TextManager.Get(
"campaignoption.maxvitalitymultipliercrew.tooltip"),
402 prevSettings.CrewVitalityMultiplier,
403 valueStep: crewVitalityMultiplierSettings.Step,
404 minValue: crewVitalityMultiplierSettings.Min,
405 maxValue: crewVitalityMultiplierSettings.Max,
410 CampaignSettings.MultiplierSettings nonCrewVitalityMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"NonCrewVitalityMultiplier");
413 TextManager.Get(
"campaignoption.maxvitalitymultipliernoncrew"),
414 TextManager.Get(
"campaignoption.maxvitalitymultipliernoncrew.tooltip"),
415 prevSettings.NonCrewVitalityMultiplier,
416 valueStep: nonCrewVitalityMultiplierSettings.Step,
417 minValue: nonCrewVitalityMultiplierSettings.Min,
418 maxValue: nonCrewVitalityMultiplierSettings.Max,
423 CampaignSettings.MultiplierSettings oxygenSourceMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"OxygenMultiplier");
426 TextManager.Get(
"campaignoption.oxygensourcemultiplier"),
427 TextManager.Get(
"campaignoption.oxygensourcemultiplier.tooltip"),
428 prevSettings.OxygenMultiplier,
429 valueStep: oxygenSourceMultiplierSettings.Step,
430 minValue: oxygenSourceMultiplierSettings.Min,
431 maxValue: oxygenSourceMultiplierSettings.Max,
436 CampaignSettings.MultiplierSettings reactorFuelMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"FuelMultiplier");
439 TextManager.Get(
"campaignoption.reactorfuelmultiplier"),
440 TextManager.Get(
"campaignoption.reactorfuelmultiplier.tooltip"),
441 prevSettings.FuelMultiplier,
442 valueStep: reactorFuelMultiplierSettings.Step,
443 minValue: reactorFuelMultiplierSettings.Min,
444 maxValue: reactorFuelMultiplierSettings.Max,
449 CampaignSettings.MultiplierSettings repairFailMultiplierSettings = CampaignSettings.GetMultiplierSettings(
"RepairFailMultiplier");
452 TextManager.Get(
"campaignoption.repairfailmultiplier"),
453 TextManager.Get(
"campaignoption.repairfailmultiplier.tooltip"),
454 prevSettings.RepairFailMultiplier,
455 valueStep: repairFailMultiplierSettings.Step,
456 minValue: repairFailMultiplierSettings.Min,
457 maxValue: repairFailMultiplierSettings.Max,
461 ImmutableArray<SettingCarouselElement<PatdownProbabilityOption>> patdownProbabilityPresets = ImmutableArray.Create(
467 SettingCarouselElement<PatdownProbabilityOption> prevPatdownProbability = patdownProbabilityPresets
468 .FirstOrNull(element => element.Value == prevSettings.PatdownProbability)
469 ?? patdownProbabilityPresets[1];
472 TextManager.Get(
"campaignoption.patdownprobability"),
473 TextManager.Get(
"campaignoption.patdownprobability.tooltip"),
474 prevPatdownProbability,
476 patdownProbabilityPresets,
482 TextManager.Get(
"campaignoption.showhuskwarning"),
483 TextManager.Get(
"campaignoption.showhuskwarning.tooltip"),
484 prevSettings.ShowHuskWarning,
488 presetDropdown.OnSelected = (_, o) =>
490 if (o is not CampaignSettings settings) {
return false; }
492 loadingPreset =
true;
493 tutorialEnabled.
SetValue(isSinglePlayer && settings.TutorialEnabled);
494 radiationEnabled.
SetValue(settings.RadiationEnabled);
495 maxMissionCountInput.
SetValue(settings.MaxMissionCount);
496 startingFundsInput.
SetValue(settings.StartingBalanceAmount);
497 hostilityInput.
SetValue(settings.WorldHostility);
498 startingSetInput.
SetValue(settings.StartItemSet);
499 crewVitalityMultiplier.
SetValue(settings.CrewVitalityMultiplier);
500 nonCrewVitalityMultiplier.
SetValue(settings.NonCrewVitalityMultiplier);
501 oxygenMultiplier.
SetValue(settings.OxygenMultiplier);
502 fuelMultiplier.
SetValue(settings.FuelMultiplier);
503 rewardMultiplier.
SetValue(settings.MissionRewardMultiplier);
504 shopPriceMultiplier.
SetValue(settings.ShopPriceMultiplier);
505 shipyardPriceMultiplier.
SetValue(settings.ShipyardPriceMultiplier);
506 repairFailMultiplier.
SetValue(settings.RepairFailMultiplier);
507 patdownProbability.
SetValue(settings.PatdownProbability);
508 huskWarning.
SetValue(settings.ShowHuskWarning);
509 loadingPreset =
false;
513 void OnValuesChanged()
515 if (loadingPreset) {
return; }
516 presetDropdown.Select(0);
521 SelectedPreset = presetValue,
522 TutorialEnabled = tutorialEnabled,
523 RadiationEnabled = radiationEnabled,
524 MaxMissionCount = maxMissionCountInput,
525 StartingFunds = startingFundsInput,
526 WorldHostility = hostilityInput,
527 StartItemSet = startingSetInput,
528 CrewVitalityMultiplier = crewVitalityMultiplier,
529 NonCrewVitalityMultiplier = nonCrewVitalityMultiplier,
530 OxygenMultiplier = oxygenMultiplier,
531 FuelMultiplier = fuelMultiplier,
532 MissionRewardMultiplier = rewardMultiplier,
533 ShopPriceMultiplier = shopPriceMultiplier,
534 ShipyardPriceMultiplier = shipyardPriceMultiplier,
535 RepairFailMultiplier = repairFailMultiplier,
536 PatdownProbability = patdownProbability,
537 ShowHuskWarning = huskWarning,
557 horizontalSize: 0.55f,
558 verticalSize: verticalSize);
562 style:
"GUIMinusButton",
563 textAlignment: Alignment.Center);
567 style:
"GUIPlusButton",
568 textAlignment: Alignment.Center);
572 textAlignment: Alignment.Center,
575 customPlusMinusButtons: (plusButton, minusButton))
577 IntValue = defaultValue,
578 MinValueInt = minValue,
579 MaxValueInt = maxValue,
580 ValueStep = valueStep,
607 horizontalSize: 0.55f,
608 verticalSize: verticalSize);
612 style:
"GUIMinusButton",
613 textAlignment: Alignment.Center);
617 style:
"GUIPlusButton",
618 textAlignment: Alignment.Center);
622 textAlignment: Alignment.Center,
625 customPlusMinusButtons: (plusButton, minusButton))
627 FloatValue = defaultValue,
628 MinValueFloat = minValue,
629 MaxValueFloat = maxValue,
630 ValueStep = valueStep,
639 i => numberInput.
FloatValue = (
float)Math.Round(i, 1));
646 SettingCarouselElement<T> defaultValue,
648 ImmutableArray<SettingCarouselElement<T>> options,
655 horizontalSize: 0.55f,
656 verticalSize: verticalSize);
660 style:
"GUIButtonToggleLeft",
661 textAlignment: Alignment.Center)
671 textAlignment: Alignment.Center,
675 IntValue = options.IndexOf(defaultValue),
677 MaxValueInt = options.Length,
684 text: defaultValue.Label.Value,
685 textAlignment: Alignment.Center,
686 createPenIcon:
false)
693 style:
"GUIButtonToggleRight",
694 textAlignment: Alignment.Center)
701 bool ChangeValue(
GUIButton btn,
object userData)
703 if (userData is not
int change) {
return false; }
705 int hiddenOptions = 0;
707 for (
int i = options.Length - 1; i >= 0; i--)
709 if (options[i].IsHidden)
717 int limit = options.Length - hiddenOptions;
721 limit = options.Length;
724 int newValue = MathUtils.PositiveModulo(Math.Clamp(numberInput.
IntValue + change, min: -1, max: limit), limit);
731 void SetValue(
int value)
734 inputLabel.
Text = options[value].Label.Value;
738 () => options[numberInput.
IntValue].Value,
739 t => SetValue(options.IndexOf(e => Equals(e.Value, t)))
751 GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, 0.625f, verticalSize);
754 childAnchor:
Anchor.Center);
779 float horizontalSize,
785 childAnchor:
Anchor.CenterLeft);
789 font: parent.
Rect.Width < 320 ? GUIStyle.SmallFont : GUIStyle.Font,
797 childAnchor:
Anchor.CenterLeft)
799 RelativeSpacing = 0.05f,
804 return inputContainer;
808 public abstract void CreateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles =
null);
812 if (obj is not
CampaignMode.SaveInfo saveInfo) {
return false; }
814 var header = TextManager.Get(
"deletedialoglabel");
815 var body = TextManager.GetWithVariable(
"deletedialogquestion",
"[file]", Path.GetFileNameWithoutExtension(saveInfo.FilePath));
817 EventEditorScreen.AskForConfirmation(header, body, () =>
819 SaveUtil.DeleteSave(saveInfo.FilePath);
820 prevSaveFiles?.RemoveAll(s => s.FilePath == saveInfo.FilePath);
828 protected void CreateBackupMenu(IEnumerable<SaveUtil.BackupIndexData> indexData, Action<SaveUtil.BackupIndexData> loadBackup)
830 var backupPopup =
new GUIMessageBox(
"",
"",
new[] { TextManager.Get(
"Load"), TextManager.Get(
"Cancel") },
new Vector2(0.3f, 0.5f), minSize:
new Point(500, 500));
838 if (!indexData.Any() || isIronman)
841 ? TextManager.Get(
"ironmanmodebackupdisclaimer")
842 : TextManager.Get(
"nobackups");
843 var errorBlock =
new GUITextBlock(
new RectTransform(Vector2.One, campaignSettingContent.RectTransform), errorMsg, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center)
845 TextColor = GUIStyle.Red,
846 IgnoreLayoutGroups =
true
849 if (errorBlock.Font.MeasureString(errorMsg).X > campaignSettingContent.Rect.Width)
851 errorBlock.
Wrap =
true;
852 errorBlock.SetTextPos();
858 foreach (var data
in indexData.OrderByDescending(
static i => i.SaveTime))
869 childAnchor:
Anchor.CenterLeft)
871 RelativeSpacing = 0.05f,
877 RelativeSpacing = 0.05f,
881 LocalizedString locationName = data.LocationType.IsEmpty || data.LocationNameIdentifier.IsEmpty ?
882 TextManager.Get(
"unknown") :
883 Location.
GetName(data.LocationType, data.LocationNameFormatIndex, data.LocationNameIdentifier);
887 TextColor = Color.White
895 RelativeSpacing = 0.05f,
901 double totalMinutes = difference.TotalMinutes;
905 < 1 => TextManager.Get(
"subeditor.savedjustnow"),
906 > 60 => TextManager.GetWithVariable(
"saveagehours",
"[hours]", ((
int)Math.Floor(difference.TotalHours)).ToString()),
907 _ => TextManager.GetWithVariable(
"subeditor.saveageminutes",
"[minutes]", difference.Minutes.ToString())
912 locationNameBlock.Text = ToolBox.LimitString(locationName, locationNameBlock.Font, locationNameBlock.Rect.Width);
920 backupPopup.Buttons[0].Enabled =
true;
924 backupPopup.Buttons[1].OnClicked += (button, o) =>
930 backupPopup.Buttons[0].Enabled =
false;
931 backupPopup.Buttons[0].OnClicked += (button, o) =>
937 loadBackup?.Invoke(selectedIndexData);
delegate void LoadGameDelegate(string loadPath, Option< uint > backupIndex)
readonly GUIComponent newGameContainer
CampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer)
GUITextBlock InitialMoneyText
LoadGameDelegate LoadGame
GUIComponent CreateSaveElement(CampaignMode.SaveInfo saveInfo)
Action< SubmarineInfo, string, string, CampaignSettings > StartNewGame
static CampaignSettingElements CreateCampaignSettingList(GUIComponent parent, CampaignSettings prevSettings, bool isSinglePlayer)
List< CampaignMode.SaveInfo > prevSaveFiles
GUIButton CampaignCustomizeButton
GUIMessageBox CampaignCustomizeSettings
abstract void CreateLoadMenu(IEnumerable< CampaignMode.SaveInfo > saveFiles=null)
void CreateBackupMenu(IEnumerable< SaveUtil.BackupIndexData > indexData, Action< SaveUtil.BackupIndexData > loadBackup)
bool DeleteSave(GUIButton button, object obj)
RectTransform RectTransform
GUIComponent AddItem(LocalizedString text, object userData=null, LocalizedString toolTip=null, Color? color=null, Color? textColor=null)
OnSelectedHandler AfterSelected
Triggers after some element has been selected from the listbox.
GUIComponent SelectedComponent
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
OnSelectedHandler OnSelected
static NetworkMember NetworkMember
static bool IsCompatibleWithEnabledContentPackages(IList< string > contentPackageNames, out LocalizedString errorMsg)
Defines a point in the event that GoTo actions can jump to.
static LocalizedString GetName(Identifier locationTypeIdentifier, int nameFormatIndex, Identifier nameId)
StartingBalanceAmountOption
SettingValue< float > OxygenMultiplier
SettingValue< float > CrewVitalityMultiplier
SettingValue< float > RepairFailMultiplier
SettingValue< int > MaxMissionCount
SettingValue< float > MissionRewardMultiplier
SettingValue< bool > RadiationEnabled
SettingValue< PatdownProbabilityOption > PatdownProbability
SettingValue< Identifier > StartItemSet
SettingValue< bool > TutorialEnabled
SettingValue< float > ShipyardPriceMultiplier
SettingValue< float > NonCrewVitalityMultiplier
SettingValue< WorldHostilityOption > WorldHostility
SettingValue< StartingBalanceAmountOption > StartingFunds
readonly CampaignSettings CreateSettings()
SettingValue< string > SelectedPreset
SettingValue< bool > ShowHuskWarning
SettingValue< float > FuelMultiplier
SettingValue< float > ShopPriceMultiplier
SettingValue(Func< T > get, Action< T > set)
static GUITextBlock CreateSubHeader(string textTag, GUIComponent parent, string toolTipTag=null)
DateTime wrapper that tries to offer a reliable string representation that's also human-friendly
static SerializableDateTime UtcNow