public static void resetClassLevel(this UnitEntityData ch) { // TODO - this doesn't seem to work in BoT either... int level = 21; int xp = ch.Descriptor.Progression.Experience; BlueprintStatProgression xpTable = BlueprintRoot.Instance.Progression.XPTable; for (int i = 20; i >= 1; i--) { int xpBonus = xpTable.GetBonus(i); Logger.Log(i + ": " + xpBonus + " | " + xp); if ((xp - xpBonus) >= 0) { Logger.Log(i + ": " + (xp - xpBonus)); level = i; break; } } ch.Descriptor.Progression.CharacterLevel = level; }
public static void OnGUI() { var player = Game.Instance.Player; var filterChoices = GetPartyFilterChoices(); if (filterChoices == null) { return; } charToAdd = null; charToRemove = null; var characterListFunc = UI.TypePicker <List <UnitEntityData> >( null, ref Main.settings.selectedPartyFilter, filterChoices ); var characterList = characterListFunc.func(); var mainChar = GameHelper.GetPlayerCharacter(); if (characterListFunc.name == "Nearby") { UI.Slider("Nearby Distance", ref nearbyRange, 1f, 200, 25, 0, " meters", UI.Width(250)); characterList = characterList.OrderBy((ch) => ch.DistanceTo(mainChar)).ToList(); } UI.Space(20); int chIndex = 0; respecableCount = 0; var selectedCharacter = GetSelectedCharacter(); bool isWide = Main.IsWide; foreach (UnitEntityData ch in characterList) { var classData = ch.Progression.Classes; // TODO - understand the difference between ch.Progression and ch.Descriptor.Progression UnitProgressionData progression = ch.Descriptor.Progression; BlueprintStatProgression xpTable = BlueprintRoot.Instance.Progression.XPTable; int level = progression.CharacterLevel; int mythicLevel = progression.MythicExperience; var spellbooks = ch.Spellbooks; var spellCount = spellbooks.Sum((sb) => sb.GetAllKnownSpells().Count()); using (UI.HorizontalScope()) { UI.Label(ch.CharacterName.orange().bold(), UI.Width(200)); UI.Space(25); float distance = mainChar.DistanceTo(ch);; UI.Label(distance < 1 ? "" : distance.ToString("0") + "m", UI.Width(75)); UI.Space(25); UI.Label("lvl".green() + $": {level}", UI.Width(75)); // Level up code adapted from Bag of Tricks https://www.nexusmods.com/pathfinderkingmaker/mods/2 if (player.AllCharacters.Contains(ch)) { if (progression.Experience < xpTable.GetBonus(level + 1) && level < 20) { UI.ActionButton("+1", () => { progression.AdvanceExperienceTo(xpTable.GetBonus(level + 1), true); }, UI.Width(70)); } else if (progression.Experience >= xpTable.GetBonus(level + 1) && level < 20) { UI.Label("LvUp".cyan().italic(), UI.Width(70)); } else { UI.Space(74); } } else { UI.Space(74); } UI.Space(25); UI.Label($"my".green() + $": {mythicLevel}", UI.Width(100)); if (player.AllCharacters.Contains(ch)) { if (progression.MythicExperience < 10) { UI.ActionButton("+1", () => { progression.AdvanceMythicExperience(progression.MythicExperience + 1, true); }, UI.Width(70)); } else { UI.Label("max".cyan(), UI.Width(70)); } } else { UI.Space(74); } UI.Space(35); if (!isWide) { ActionsGUI(ch); } UI.Wrap(!Main.IsWide, 303, 0); bool showClasses = ch == selectedCharacter && selectedToggle == ToggleChoice.Classes; if (UI.DisclosureToggle($"{classData.Count} Classes", ref showClasses)) { if (showClasses) { selectedCharacter = ch; selectedToggle = ToggleChoice.Classes; Logger.Log($"selected {ch.CharacterName}"); } else { selectedToggle = ToggleChoice.None; } } bool showStats = ch == selectedCharacter && selectedToggle == ToggleChoice.Stats; if (UI.DisclosureToggle("Stats", ref showStats, true, isWide ? 150 : 200)) { if (showStats) { selectedCharacter = ch; selectedToggle = ToggleChoice.Stats; } else { selectedToggle = ToggleChoice.None; } } UI.Wrap(Main.IsNarrow, 279); bool showFacts = ch == selectedCharacter && selectedToggle == ToggleChoice.Facts; if (UI.DisclosureToggle("Facts", ref showFacts, true, isWide ? 150 : 200)) { if (showFacts) { selectedCharacter = ch; selectedToggle = ToggleChoice.Facts; } else { selectedToggle = ToggleChoice.None; } } bool showBuffs = ch == selectedCharacter && selectedToggle == ToggleChoice.Buffs; if (UI.DisclosureToggle("Buffs", ref showBuffs, true, isWide ? 150 : 200)) { if (showBuffs) { selectedCharacter = ch; selectedToggle = ToggleChoice.Buffs; } else { selectedToggle = ToggleChoice.None; } } UI.Wrap(Main.IsNarrow, 304); bool showAbilities = ch == selectedCharacter && selectedToggle == ToggleChoice.Abilities; if (UI.DisclosureToggle("Abilities", ref showAbilities, true)) { if (showAbilities) { selectedCharacter = ch; selectedToggle = ToggleChoice.Abilities; } else { selectedToggle = ToggleChoice.None; } } UI.Space(25); if (spellCount > 0) { bool showSpells = ch == selectedCharacter && selectedToggle == ToggleChoice.Spells; if (UI.DisclosureToggle($"{spellCount} Spells", ref showSpells, true)) { if (showSpells) { selectedCharacter = ch; selectedToggle = ToggleChoice.Spells; } else { selectedToggle = ToggleChoice.None; } } } else { UI.Space(180); } if (isWide) { ActionsGUI(ch); } } if (!Main.IsWide) { UI.Div(20, 20); } if (selectedCharacter != spellbookEditCharacter) { editSpellbooks = false; spellbookEditCharacter = null; } if (selectedCharacter != multiclassEditCharacter) { editMultiClass = false; multiclassEditCharacter = null; } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Classes) { #if DEBUG UI.Div(100, 20); using (UI.HorizontalScope()) { UI.Space(100); UI.Toggle("Multiple Classes On Level-Up", ref settings.toggleMulticlass, 0); if (settings.toggleMulticlass) { UI.Space(39); if (UI.DisclosureToggle("Config".orange().bold(), ref editMultiClass)) { multiclassEditCharacter = selectedCharacter; } UI.Space(25); UI.Label("Experimental Preview ".magenta() + "See 'Level Up + Multiclass' for more options".green()); } else { UI.Space(50); UI.Label("Experimental Preview ".magenta()); } } #endif UI.Div(100, 20); if (editMultiClass) { var multiclassSet = ch.GetMulticlassSet(); MulticlassPicker.OnGUI(multiclassSet); ch.SetMulticlassSet(multiclassSet); } else { var prog = ch.Descriptor.Progression; using (UI.HorizontalScope()) { UI.Space(100); UI.Label("Character Level".cyan(), UI.Width(250)); UI.ActionButton("<", () => prog.CharacterLevel = Math.Max(0, prog.CharacterLevel - 1), UI.AutoWidth()); UI.Space(25); UI.Label("level".green() + $": {prog.CharacterLevel}", UI.Width(100f)); UI.ActionButton(">", () => prog.CharacterLevel = Math.Min(20, prog.CharacterLevel + 1), UI.AutoWidth()); UI.Space(25); UI.ActionButton("Reset", () => ch.resetClassLevel(), UI.Width(125)); UI.Space(23); UI.Label("This directly changes your character level but will not change exp or adjust any features associated with your character. To do a normal level up use +1 Lvl above".green()); } UI.Div(0, 25); using (UI.HorizontalScope()) { UI.Space(100); UI.Label("Mythic Level".cyan(), UI.Width(250)); UI.ActionButton("<", () => prog.MythicLevel = Math.Max(0, prog.MythicLevel - 1), UI.AutoWidth()); UI.Space(25); UI.Label("my lvl".green() + $": {prog.MythicLevel}", UI.Width(100f)); UI.ActionButton(">", () => prog.MythicLevel = Math.Min(10, prog.MythicLevel + 1), UI.AutoWidth()); UI.Space(175); UI.Label("This directly changes your mythic level but will not adjust any features associated with your character. To do a normal mythic level up use +1 my above".green()); } foreach (var cd in classData) { UI.Div(100, 20); using (UI.HorizontalScope()) { UI.Space(100); UI.Label(cd.CharacterClass.Name.orange(), UI.Width(250)); UI.ActionButton("<", () => cd.Level = Math.Max(0, cd.Level - 1), UI.AutoWidth()); UI.Space(25); UI.Label("level".green() + $": {cd.Level}", UI.Width(100f)); var maxLevel = cd.CharacterClass.Progression.IsMythic ? 10 : 20; UI.ActionButton(">", () => cd.Level = Math.Min(maxLevel, cd.Level + 1), UI.AutoWidth()); UI.Space(175); UI.Label(cd.CharacterClass.Description.green(), UI.AutoWidth()); } } } } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Stats) { UI.Div(100, 20, 755); var alignment = ch.Descriptor.Alignment.Value; using (UI.HorizontalScope()) { UI.Space(100); UI.Label("Alignment", UI.Width(425)); UI.Label($"{alignment.Name()}".color(alignment.Color()).bold(), UI.Width(1250f)); } using (UI.HorizontalScope()) { UI.Space(528); int alignmentIndex = Array.IndexOf(alignments, alignment); var titles = alignments.Select( a => a.Acronym().color(a.Color()).bold()).ToArray(); if (UI.SelectionGrid(ref alignmentIndex, titles, 3, UI.Width(250f))) { ch.Descriptor.Alignment.Set(alignments[alignmentIndex]); } } UI.Div(100, 20, 755); using (UI.HorizontalScope()) { UI.Space(100); UI.Label("Size", UI.Width(425)); var size = ch.Descriptor.State.Size; UI.Label($"{size}".orange().bold(), UI.Width(175)); } using (UI.HorizontalScope()) { UI.Space(528); UI.EnumGrid( () => ch.Descriptor.State.Size, (s) => ch.Descriptor.State.Size = s, 3, UI.Width(600)); } using (UI.HorizontalScope()) { UI.Space(528); UI.ActionButton("Reset", () => { ch.Descriptor.State.Size = ch.Descriptor.OriginalSize; }, UI.Width(197)); } UI.Div(100, 20, 755); foreach (StatType obj in Enum.GetValues(typeof(StatType))) { StatType statType = (StatType)obj; ModifiableValue modifiableValue = ch.Stats.GetStat(statType); if (modifiableValue != null) { String key = $"{ch.CharacterName}-{statType.ToString()}"; var storedValue = statEditorStorage.ContainsKey(key) ? statEditorStorage[key] : modifiableValue.BaseValue; var statName = statType.ToString(); if (statName == "BaseAttackBonus" || statName == "SkillAthletics") { UI.Div(100, 20, 755); } using (UI.HorizontalScope()) { UI.Space(100); UI.Label(statName, UI.Width(400f)); UI.Space(25); UI.ActionButton(" < ", () => { modifiableValue.BaseValue -= 1; storedValue = modifiableValue.BaseValue; }, UI.AutoWidth()); UI.Space(20); UI.Label($"{modifiableValue.BaseValue}".orange().bold(), UI.Width(50f)); UI.ActionButton(" > ", () => { modifiableValue.BaseValue += 1; storedValue = modifiableValue.BaseValue; }, UI.AutoWidth()); UI.Space(25); UI.ActionIntTextField(ref storedValue, statType.ToString(), (v) => { modifiableValue.BaseValue = v; }, null, UI.Width(75)); statEditorStorage[key] = storedValue; } } } } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Facts) { FactsEditor.OnGUI(ch, ch.Progression.Features.Enumerable.ToList()); } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Buffs) { FactsEditor.OnGUI(ch, ch.Descriptor.Buffs.Enumerable.ToList()); } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Abilities) { FactsEditor.OnGUI(ch, ch.Descriptor.Abilities.Enumerable.ToList()); } if (ch == selectedCharacter && selectedToggle == ToggleChoice.Spells) { UI.Space(20); var names = spellbooks.Select((sb) => sb.Blueprint.GetDisplayName()).ToArray(); var titles = names.Select((name, i) => $"{name} ({spellbooks.ElementAt(i).CasterLevel})").ToArray(); if (spellbooks.Any()) { using (UI.HorizontalScope()) { UI.SelectionGrid(ref selectedSpellbook, titles, 7, UI.Width(1581)); if (selectedSpellbook > names.Count()) { selectedSpellbook = 0; } // UI.DisclosureToggle("Edit", ref editSpellbooks); } var spellbook = spellbooks.ElementAt(selectedSpellbook); if (editSpellbooks) { spellbookEditCharacter = ch; var blueprints = BlueprintExensions.GetBlueprints <BlueprintSpellbook>().OrderBy((bp) => bp.GetDisplayName()); BlueprintListUI.OnGUI(ch, blueprints, 100); } else { var maxLevel = spellbook.Blueprint.MaxSpellLevel; var casterLevel = spellbook.CasterLevel; using (UI.HorizontalScope()) { UI.EnumerablePicker <int>( "Spell Level".bold() + " (count)", ref selectedSpellbookLevel, Enumerable.Range(0, casterLevel + 1), 0, (lvl) => { var levelText = lvl <= casterLevel ? $"L{lvl}".bold() : $"L{lvl}".grey(); var knownCount = spellbook.GetKnownSpells(lvl).Count(); var countText = knownCount > 0 ? $" ({knownCount})".white() : ""; return(levelText + countText); }, UI.AutoWidth() ); if (casterLevel < maxLevel) { UI.ActionButton("+1 Caster Level", () => spellbook.AddBaseLevel()); } } FactsEditor.OnGUI(ch, spellbook, selectedSpellbookLevel); } } #if false else { spellbookEditCharacter = ch; editSpellbooks = true; var blueprints = BlueprintExensions.GetBlueprints <BlueprintSpellbook>().OrderBy((bp) => bp.GetDisplayName()); BlueprintListUI.OnGUI(ch, blueprints, 100); } #endif } if (selectedCharacter != GetSelectedCharacter()) { selectedCharacterIndex = characterList.IndexOf(selectedCharacter); } chIndex += 1; } UI.Space(25); if (respecableCount > 0) { UI.Label($"{respecableCount} characters".yellow().bold() + " can be respecced. Pressing Respec will close the mod window and take you to character level up".orange()); UI.Label("WARNING".yellow().bold() + " this feature is ".orange() + "EXPERIMENTAL".yellow().bold() + " and uses unreleased and likely buggy code.".orange()); UI.Label("BACK UP".yellow().bold() + " before playing with this feature.You will lose your mythic ranks but you can restore them in this Party Editor.".orange()); } UI.Space(25); if (charToAdd != null) { UnitEntityDataUtils.AddCompanion(charToAdd); } if (charToRemove != null) { UnitEntityDataUtils.RemoveCompanion(charToRemove); } }
public static void Render() { GL.BeginVertical("box"); GL.BeginHorizontal(); settings.showPartyStatisticsCategory = GL.Toggle(settings.showPartyStatisticsCategory, RichTextUtils.MainCategoryFormat(Strings.GetText("mainCategory_PartyStats")), GL.ExpandWidth(false)); if (!settings.showPartyStatisticsCategory) { GL.EndHorizontal(); } else { MenuTools.FlexibleSpaceCategoryMenuElementsEndHorizontal("PartyOptions"); GL.Space(10); MenuTools.ToggleButton(ref settings.toggleAccessRemoteCharacters, "buttonToggle_AccessRemoteCharacters", "tooltip_AccessRemoteCharacters", nameof(settings.toggleAccessRemoteCharacters)); MenuTools.ToggleButtonActions(ref settings.toggleShowAllPartyPortraits, GroupControllerUtils.NaviBlockShowAllPartyMembers, GroupControllerUtils.NaviBlockShowDefault, "buttonToggle_ShowAllPartyPortraits", "tooltip_ShowAllPartyPortraits", nameof(settings.toggleShowAllPartyPortraits)); GL.Space(10); GL.BeginHorizontal(); Storage.statsFilterUnitEntityDataIndex = GL.SelectionGrid(Storage.statsFilterUnitEntityDataIndex, unitEntityDataFiltersArray, 3); GL.EndHorizontal(); Player player = Game.Instance.Player; switch (Storage.statsFilterUnitEntityDataIndex) { case 0: Storage.statsUnitEntityData = player.Party; break; case 1: Storage.statsUnitEntityData = player.ControllableCharacters; break; case 2: Storage.statsUnitEntityData = player.ActiveCompanions; break; case 3: Storage.statsUnitEntityData = player.AllCharacters; break; case 4: Storage.statsUnitEntityData = PartyUtils.GetRemoteCompanions(); break; case 5: Storage.statsUnitEntityData = PartyUtils.GetCustomCompanions(); break; case 6: Storage.statsUnitEntityData = PartyUtils.GetPets(); break; } if (Storage.statsFilterUnitEntityDataIndex != Storage.statsFilterUnitEntityDataIndexOld) { Storage.reloadPartyStats = true; Storage.statsFilterUnitEntityDataIndexOld = Storage.statsFilterUnitEntityDataIndex; } GL.Space(10); if (Storage.statsUnitEntityData.Any()) { if (Storage.reloadPartyStats) { Storage.statsSelectedControllableCharacterIndex = 0; Storage.statsPartyMembers = Storage.statsUnitEntityData; Storage.statsControllableCharacterNamesList.Clear(); foreach (UnitEntityData controllableCharacter in Storage.statsUnitEntityData) { Storage.statsControllableCharacterNamesList.Add(controllableCharacter.CharacterName); } Storage.reloadPartyStats = false; } if (!Storage.reloadPartyStats) { GL.BeginHorizontal(); Storage.statsSelectedControllableCharacterIndex = GL.SelectionGrid(Storage.statsSelectedControllableCharacterIndex, Storage.statsControllableCharacterNamesList.ToArray(), 6); GL.EndHorizontal(); GL.Space(10); GL.BeginVertical("box"); if (Storage.statsFilterUnitEntityDataIndex != 4) { MenuTools.SingleLineLabelGt("warning_SelectRemoteCharacters"); } else { if (GL.Button(MenuTools.TextWithTooltip("button_AddRemoteCompanionToParty", "tooltip_AddRemoteCompanionToParty", false), GL.ExpandWidth(false))) { UnitEntityDataUtils.AddCompanion(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex]); } GL.Space(10); if (!StringUtils.ToToggleBool(settings.toggleShowAllPartyPortraits) && Game.Instance.Player.Party.Count > 6) { MenuTools.SingleLineLabelGt("warning_PartyLimitShowAllPartyPortraits"); } } GL.EndVertical(); GL.Space(10); MainMenu.CurrentHitPointsOptions(); GL.Space(10); MainMenu.ChangeName(); GL.Space(10); MainMenu.ChangeGender(); GL.Space(10); MainMenu.ClassData(); GL.Space(10); //Menu.RaceData(); //GL.Space(10); /* * if (GL.Button(MenuTools.TextWithTooltip("button_RemoveEquippedItems", "tooltip_RemoveEquippedItems", false), GL.ExpandWidth(false))) * { * foreach (ItemEntity itemEntity in Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Inventory.Items) * { * if (itemEntity.Owner == Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor) * { * itemEntity.HoldingSlot.RemoveItem(); * } * } * } * GL.Space(10);*/ GL.BeginVertical("box"); GL.BeginHorizontal(); if (GL.Button(MenuTools.TextWithTooltip("button_ResetCharacterLevel", "tooltip_ResetCharacterLevel", false), GL.ExpandWidth(false))) { int level = 21; int xp = Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression.Experience; BlueprintStatProgression xpTable = BlueprintRoot.Instance.Progression.XPTable; for (int i = 20; i >= 1; i--) { int xpBonus = xpTable.GetBonus(i); modLogger.Log(i + ": " + xpBonus + " | " + xp); if ((xp - xpBonus) >= 0) { modLogger.Log(i + ": " + (xp - xpBonus)); level = i; break; } } Type type = Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression.GetType(); PropertyInfo propertyInfo = type.GetProperty("CharacterLevel"); propertyInfo.SetValue(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression, level, null); } GL.EndHorizontal(); GL.Space(10); GL.BeginHorizontal(); Storage.setCharLevel = GL.HorizontalSlider(Storage.setCharLevel, 1f, 20f, GL.Width(250f)); GL.Label($" {Mathf.RoundToInt(Storage.setCharLevel)}", GL.ExpandWidth(false)); GL.EndHorizontal(); GL.BeginHorizontal(); if (GL.Button(MenuTools.TextWithTooltip("button_SetCharacterLevel", "tooltip_SetCharacterLevel", "", $" {Mathf.RoundToInt(Storage.setCharLevel)}" + " " + StringUtils.PutInParenthesis(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName)), GL.ExpandWidth(false))) { Type type = Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression.GetType(); PropertyInfo propertyInfoLvl = type.GetProperty("CharacterLevel"); propertyInfoLvl.SetValue(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression, Mathf.RoundToInt(Storage.setCharLevel), null); int newXp = BlueprintRoot.Instance.Progression.XPTable.GetBonus(Mathf.RoundToInt(Storage.setCharLevel)); PropertyInfo propertyInfoXp = type.GetProperty("Experience"); propertyInfoXp.SetValue(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Progression, newXp, null); } GL.EndHorizontal(); MenuTools.SingleLineLabel(Strings.GetText("warning_SetCharacterLevel")); GL.EndVertical(); GL.Space(10); MenuTools.UnitAlignment(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex]); GL.Space(10); GL.BeginVertical("box"); MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_Size"))); GL.BeginHorizontal(); Storage.partySelectedSizeIndex = GL.SelectionGrid(Storage.partySelectedSizeIndex, Storage.charSizeArray, 4); GL.EndHorizontal(); GL.Space(10); GL.BeginHorizontal(); if (GL.Button(MenuTools.TextWithTooltip("button_SetSizeTo", "tooltip_SetSize", "", $" {Storage.charSizeArray[Storage.partySelectedSizeIndex]}"), GL.ExpandWidth(false))) { Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.State.Size = (Size)Storage.partySelectedSizeIndex; } GL.EndHorizontal(); GL.BeginHorizontal(); if (GL.Button(MenuTools.TextWithTooltip("button_SetToOriginalSize", "tooltip_SetToOriginalSize", "", $" ({Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.OriginalSize})"), GL.ExpandWidth(false))) { Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.State.Size = Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.OriginalSize; } GL.EndHorizontal(); MenuTools.SingleLineLabel(Strings.GetText("label_CurrentSize") + ": " + Common.SizeToString(Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.State.Size)); GL.EndVertical(); GL.Space(10); GL.BeginHorizontal(); GL.Label(MenuTools.TextWithTooltip("header_Statistics", "tooltip_Statistics", true)); GL.EndHorizontal(); GL.BeginHorizontal(); settings.partyStatsAmount = GL.TextField(settings.partyStatsAmount, 10, GL.Width(85f)); MenuTools.SettingParse(ref settings.partyStatsAmount, ref settings.partyFinalStatsAmount); GL.EndHorizontal(); CharacterStats charStats = Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].Descriptor.Stats; MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_AttributesBaseValues"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsAttributesDict) { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_SkillsRanks"))); MenuTools.ToggleButton(ref settings.toggleShowOnlyClassSkills, "buttonToggle_ShowOnlyClassSkills", "tooltip_ShowOnlyClassSkills"); foreach (KeyValuePair <string, StatType> entry in Storage.statsSkillsDict) { if (StringUtils.ToToggleBool(settings.toggleShowOnlyClassSkills)) { ModifiableValueSkill stat = charStats.GetStat(entry.Value) as ModifiableValueSkill; if (stat.ClassSkill && stat.BaseValue > 0) { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount); } } else { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount, true); } } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_SocialSkillsBaseValues"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsSocialSkillsDict) { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_StatsSaves"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsSavesDict) { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_StatsCombat"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsCombatDict) { MenuTools.CreateStatInterface(entry.Key, charStats, entry.Value, settings.partyFinalStatsAmount); } GL.Space(10); GL.BeginHorizontal(); GL.Label(MenuTools.TextWithTooltip("header_PartyMultipliers", "tooltip_PartyMultipliers", true)); GL.EndHorizontal(); GL.BeginHorizontal(); settings.partyStatMultiplier = GL.HorizontalSlider(settings.partyStatMultiplier, 0.1f, 10f, GL.Width(300f)); GL.Label($" {Math.Round(settings.partyStatMultiplier, 1)}", GL.ExpandWidth(false)); GL.EndHorizontal(); MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_Attributes"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsAttributesDict) { MenuTools.CreateStatMultiplierInterface(entry.Key, charStats, entry.Value, Storage.statsPartyMembers, settings.partyStatMultiplier); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_Skills"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsSkillsDict) { MenuTools.CreateStatMultiplierInterface(entry.Key, charStats, entry.Value, Storage.statsPartyMembers, settings.partyStatMultiplier); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_SocialSkills"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsSocialSkillsDict) { MenuTools.CreateStatMultiplierInterface(entry.Key, charStats, entry.Value, Storage.statsPartyMembers, settings.partyStatMultiplier); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_Saves"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsSavesDict) { MenuTools.CreateStatMultiplierInterface(entry.Key, charStats, entry.Value, Storage.statsPartyMembers, settings.partyStatMultiplier); } MenuTools.SingleLineLabel(RichTextUtils.Bold(Strings.GetText("header_Combat"))); foreach (KeyValuePair <string, StatType> entry in Storage.statsCombatDict) { MenuTools.CreateStatMultiplierInterface(entry.Key, charStats, entry.Value, Storage.statsPartyMembers, settings.partyStatMultiplier); } GL.BeginHorizontal(); if (GL.Button(MenuTools.TextWithTooltip("button_ExportCharInfo", "tooltip_ExportCharInfo", false), GL.ExpandWidth(false))) { List <string> charInfoTxt = new List <string>(); charInfoTxt.Add($"{Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName}"); charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_AttributesBaseValues")); foreach (KeyValuePair <string, StatType> entry in Storage.statsAttributesDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_SkillsRanks")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSkillsDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_SocialSkillsBaseValues")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSocialSkillsDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_StatsSaves")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSavesDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_StatsCombat")); foreach (KeyValuePair <string, StatType> entry in Storage.statsCombatDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } File.WriteAllLines(Path.Combine(Common.ExportPath(), $"{Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName}.txt"), charInfoTxt.ToArray()); } GL.Label(" " + Strings.GetText("label_Location") + $": {Path.Combine(Common.ExportPath(), $"{Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName}.txt")}"); GL.EndHorizontal(); if (File.Exists(Storage.modEntryPath + Storage.charactersImportFolder + "\\" + Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName + ".txt")) { if (GL.Button(MenuTools.TextWithTooltip("button_ImportStatsFrom", "tooltip_ImportStatsFrom", "", $" { Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName}.txt"), GL.ExpandWidth(false))) { if (settings.settingCreateBackupBeforeImport) { List <string> charInfoTxt = new List <string>(); charInfoTxt.Add($"{Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName}"); charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_AttributesBaseValues")); foreach (KeyValuePair <string, StatType> entry in Storage.statsAttributesDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_SkillsRanks")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSkillsDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_SocialSkillsBaseValues")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSocialSkillsDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_StatsSaves")); foreach (KeyValuePair <string, StatType> entry in Storage.statsSavesDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } charInfoTxt.Add(""); charInfoTxt.Add(Strings.GetText("header_StatsCombat")); foreach (KeyValuePair <string, StatType> entry in Storage.statsCombatDict) { charInfoTxt.Add(($"{entry.Key}: {charStats.GetStat(entry.Value).BaseValue} ({charStats.GetStat(entry.Value).ModifiedValue})")); } File.WriteAllLines(Path.Combine(Storage.modEntryPath + Storage.charactersImportFolder + "\\" + Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName + "_Backup.txt"), charInfoTxt.ToArray()); } string[] lines = File.ReadAllLines(Storage.modEntryPath + Storage.charactersImportFolder + "\\" + Storage.statsPartyMembers[Storage.statsSelectedControllableCharacterIndex].CharacterName + ".txt"); lines = lines.Where(x => !string.IsNullOrEmpty(x)).ToArray(); lines = lines.Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); for (int i = 0; i < lines.Length; i++) { if (Regex.IsMatch(lines[i], @"[\x20A-Za-z()]+:\s*[0-9]+")) { Match match = Regex.Match(lines[i], @"[\x20A-Za-z()]+:\s*[0-9]+"); lines[i] = match.Value; string[] splitLine = lines[i].Split(':'); Dictionary <string, StatType> allStats = Storage.statsAttributesDict.Union(Storage.statsSkillsDict).Union(Storage.statsSocialSkillsDict).Union(Storage.statsSavesDict).Union(Storage.statsCombatDict).ToDictionary(k => k.Key, v => v.Value); if (allStats.TryGetValue(splitLine[0], out StatType statType) && int.TryParse(splitLine[1], out int baseValue)) { charStats.GetStat(statType).BaseValue = baseValue; } } else { } } } } } } else { MenuTools.SingleLineLabel(Strings.GetText("message_NoUnitFound")); } } GL.EndVertical(); }