/* * Uses the CharacterBuildController to edit level plans * Refer MainMenu.StartChargen which sets up the state and then calls CharacterBuildController.HandleLevelUpStart * */ public static void EditLevelPlan(LevelPlanHolder levelPlanHolder, int level) { var unit = levelPlanHolder.CreateUnit(level); if (Main.settings.ShowDollRoom) { ShowDollRoom(unit); } CharacterBuildController characterBuildController = Game.Instance.UI.CharacterBuildController; var mode = level == 1 ? LevelUpState.CharBuildMode.CharGen : LevelUpState.CharBuildMode.LevelUp; CurrentLevelUpController = LevelUpController.Start( unit: unit.Descriptor, instantCommit: false, unitJson: null, onSuccess: null, mode: mode); CurrentLevelUpController.SelectPortrait(Game.Instance.BlueprintRoot.CharGen.Portraits[0]); CurrentLevelUpController.SelectGender(Gender.Male); CurrentLevelUpController.SelectRace(Game.Instance.BlueprintRoot.Progression.CharacterRaces[0]); CurrentLevelUpController.SelectAlignment(Kingmaker.Enums.Alignment.TrueNeutral); CurrentLevelUpController.SelectVoice(Game.Instance.BlueprintRoot.CharGen.MaleVoices[0]); CurrentLevelUpController.SelectName("LevelPlan"); Traverse.Create(characterBuildController).Property <LevelUpController>("LevelUpController").Value = CurrentLevelUpController; Traverse.Create(characterBuildController).Field("Mode").SetValue(CurrentLevelUpController.State.Mode); Traverse.Create(characterBuildController).Field("Unit").SetValue(unit.Descriptor); characterBuildController.Show(true); }
/* * Refer MainMenu.StartChargen which also calls CharacterBuildController.HandleLevelUpStart * */ internal static void TestLevelup() { var unit = CreateUnit(); var descriptorJson = UnitSerialization.Serialize(unit.Descriptor);; if (Main.settings.ShowDollRoom) { ShowDollRoom(unit); } CharacterBuildController characterBuildController = Game.Instance.UI.CharacterBuildController; LevelPlanManager.CurrentLevelUpController = LevelUpController.Start( unit: unit.Descriptor, instantCommit: false, unitJson: descriptorJson, onSuccess: null, mode: LevelUpState.CharBuildMode.CharGen); /*CurrentLevelUpController.SelectPortrait(Game.Instance.BlueprintRoot.CharGen.Portraits[0]); * CurrentLevelUpController.SelectGender(Gender.Male); * CurrentLevelUpController.SelectRace(Game.Instance.BlueprintRoot.Progression.CharacterRaces[0]); * CurrentLevelUpController.SelectAlignment(Kingmaker.Enums.Alignment.TrueNeutral); * CurrentLevelUpController.SelectVoice(Game.Instance.BlueprintRoot.CharGen.MaleVoices[0]); * CurrentLevelUpController.SelectName("LevelPlan");*/ Traverse.Create(characterBuildController).Property <LevelUpController>("LevelUpController").Value = LevelPlanManager.CurrentLevelUpController; characterBuildController.Unit = unit.Descriptor; characterBuildController.Show(true); }
private LevelUpController AddLevel(UnitDescriptor unit, Dictionary <SelectionEntry, HashSet <int> > selectionsHistory, HashSet <int> spellHistory) { LevelUpController levelUpController = LevelUpController.Start(unit, true, null, null, LevelUpState.CharBuildMode.LevelUp); if (levelUpController.State.CanSelectRace) { BlueprintRace race = unit.Progression.Race; DefaultBuildData data = ElementsContext.GetData <DefaultBuildData>(); if (data != null) { race = data.Race; } if (race != null) { levelUpController.SelectRace(race); } } if (levelUpController.State.CanSelectRaceStat) { levelUpController.SelectRaceStat(instance.RaceStat); } this.ApplyStatsDistributionPreset(levelUpController); if (unit.Progression.GetClassLevel(instance.CharacterClass) <= 0) { foreach (BlueprintArchetype archetype in instance.Archetypes) { levelUpController.AddArchetype(instance.CharacterClass, archetype); } } levelUpController.SelectClass(instance.CharacterClass, false); levelUpController.ApplyClassMechanics(); this.PerformSelections(levelUpController, selectionsHistory, new LevelUpActionPriority?(LevelUpActionPriority.ReplaceSpellbook)); levelUpController.ApplySpellbook(); while (levelUpController.State.AttributePoints > 0 && instance.LevelsStat.IsAttribute()) { levelUpController.SpendAttributePoint(instance.LevelsStat); } this.PerformSelections(levelUpController, selectionsHistory, new LevelUpActionPriority?(LevelUpActionPriority.ApplySkillPoints)); levelUpController.ApplySkillPoints(); while (levelUpController.State.SkillPointsRemaining > 0) { int skillPointsRemaining = levelUpController.State.SkillPointsRemaining; foreach (StatType skill in instance.Skills) { if (levelUpController.State.SkillPointsRemaining <= 0) { break; } levelUpController.SpendSkillPoint(skill); } if (skillPointsRemaining == levelUpController.State.SkillPointsRemaining) { break; } } this.PerformSelections(levelUpController, selectionsHistory, null); this.PerformSpellSelections(levelUpController, spellHistory); return(levelUpController); }
/* * Refer AddClassLevels.LevelUp and Player.CreateCustomCompanion */ public UnitEntityData CreateUnit(int level) { //var playerUnit = ResourcesLibrary.TryGetBlueprint<BlueprintUnit>("4391e8b9afbb0cf43aeba700c089f56d"); //var unit = new UnitDescriptor(playerUnit, null); var unit = Main.settings.DefaultPointBuy25 ? Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.DefaultPlayerCharacter) : Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.CustomCompanion); ApplyLevelPlan(unit.Descriptor); for (int i = 0; i < level; i++) { var levelUpController = LevelUpController.Start(unit.Descriptor, true); } return(unit); }
static void CreateLevelPlan() { var unit = Game.Instance.Player.MainCharacter.Value.Descriptor; var unitJson = UnitSerialization.Serialize(unit); CharacterBuildController characterBuildController = Game.Instance.UI.CharacterBuildController; CurrentLevelUpController = LevelUpController.Start( unit: unit, instantCommit: false, unitJson: unitJson, onSuccess: null, mode: LevelUpState.CharBuildMode.PreGen); Traverse.Create(characterBuildController).Property <LevelUpController>("LevelUpController").Value = CurrentLevelUpController; Traverse.Create(characterBuildController).Field("Mode").SetValue(CurrentLevelUpController.State.Mode); Traverse.Create(characterBuildController).Field("Unit").SetValue(unit); characterBuildController.Show(true); }
/* * Create a level plan from BlueprintCharacterClass' defaultBuild * Refer AddClassLevels.LevelUp and LevelController.ApplyStatsDistributionPreset * LevelUpController.SelectDefaultClassBuild and CharacterBuildController.LoadDefaultProgression * * AddClassLevels and StatsDistributionPreset are both components of * BlueprintCharacterClass.DefaultBuild */ public LevelPlanHolder(BlueprintCharacterClass defaultClass) { bool IsDefaultBuildPriority(LevelUpActionPriority priority) { return(priority != LevelUpActionPriority.Visual && priority != LevelUpActionPriority.Race && priority != LevelUpActionPriority.Class && priority != LevelUpActionPriority.ApplyClass && priority != LevelUpActionPriority.ApplySpellbook && priority != LevelUpActionPriority.ApplySkillPoints && priority != LevelUpActionPriority.Alignment); } using (new CodeTimer("Create default build")) { var defaultBuild = defaultClass.DefaultBuild; var addClassLevels = defaultBuild.GetComponent <AddClassLevels>(); var targetPoints = Main.settings.DefaultPointBuy25 ? 25 : 20; var stats = defaultBuild.GetComponents <StatsDistributionPreset>().FirstOrDefault(sd => sd.TargetPoints == targetPoints); //var race = Game.Instance.BlueprintRoot.Progression.CharacterRaces[0]; var race = ResourcesLibrary.TryGetBlueprint <BlueprintRace>("5c4e42124dc2b4647af6e36cf2590500"); UnitEntityData unit = Main.settings.DefaultPointBuy25 ? Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.DefaultPlayerCharacter) : Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.CustomCompanion); var levelUpController = LevelUpController.Start(unit.Descriptor, instantCommit: true, mode: LevelUpState.CharBuildMode.CharGen); if (!levelUpController.SelectPortrait(Game.Instance.BlueprintRoot.CharGen.Portraits[0])) { throw new Exception("Error selecting portrait"); } if (!levelUpController.SelectGender(Gender.Male)) { throw new Exception("Error selecting gender"); } if (!levelUpController.SelectRace(race)) { throw new Exception("Error selecting race"); } //Default build must be aquired after selecting race but before selecting class levelUpController.Unit.Ensure <LevelUpPlanUnitHolder>(); levelUpController.Unit.Progression.DropLevelPlans(); levelUpController.Unit.AddFact(defaultBuild, null, null); LevelPlanData levelPlan = levelUpController.Unit.Progression.GetLevelPlan(levelUpController.State.NextLevel); if (!levelUpController.SelectClass(defaultClass)) { throw new Exception("Error selecting class"); } levelUpController.LevelUpActions.RemoveAll((ILevelUpAction a) => IsDefaultBuildPriority(a.Priority)); levelUpController.LevelUpActions.AddRange(from a in levelPlan.Actions where IsDefaultBuildPriority(a.Priority) select a); levelUpController.LevelUpActions = (from a in levelUpController.LevelUpActions orderby a.Priority select a).ToList(); if (!levelUpController.SelectAlignment(Kingmaker.Enums.Alignment.TrueNeutral)) { throw new Exception("Error selecting alignment"); } if (!levelUpController.SelectName($"Default {defaultClass.Name} Build")) { throw new Exception("Error selecting name"); } for (int i = 0; i < 20; i++) { var plan = unit.Descriptor.Progression.GetLevelPlan(i + 1); LevelPlanData[i] = plan; } LevelPlanData[0] = new LevelPlanData(1, levelUpController.LevelUpActions.ToArray()); } using (new CodeTimer("Verify default build")) { VerifyLevelPlan(); } }
/* * Verify that a level plan is valid. We do this by creating a test unit and try to level it up with the leveling plan * Refer LevelUpController, LevelUpState.IsComplete CharacterBuildController.Next * CharBPhase.IsUnlocked */ void VerifyLevelPlan() { var unitEntityData = Main.settings.DefaultPointBuy25 ? Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.DefaultPlayerCharacter) : Game.Instance.CreateUnitVacuum(BlueprintRoot.Instance.CustomCompanion); for (int i = 0; i < 20; i++) { if (i > 0) { ValidLevels[i] = false; Message[i] = "TODO"; continue; } var levelUpLog = new List <string>(); var mode = i == 0 ? LevelUpState.CharBuildMode.CharGen : LevelUpState.CharBuildMode.LevelUp; var levelUpController = LevelUpController.Start(unitEntityData.Descriptor, instantCommit: false, mode: mode); if (LevelPlanData[i] == null) { throw new Exception($"Level plan is null for index {i}"); } if (LevelPlanData[i].Actions == null) { throw new Exception($"Actions not set for level plan {i}, level {LevelPlanData[i].Level}"); } foreach (var action in LevelPlanData[i].Actions) { if (!action.Check(levelUpController.State, unitEntityData.Descriptor)) { levelUpLog.Add($"Invalid action: {Util.MakeActionReadable(action)}"); } else { levelUpController.LevelUpActions.Add(action); action.Apply(levelUpController.State, unitEntityData.Descriptor); levelUpController.State.OnApplyAction(); } } unitEntityData.Descriptor.Progression.ReapplyFeaturesOnLevelUp(); ValidLevels[i] = levelUpController.State.IsComplete() && levelUpLog.Count == 0; if (!levelUpController.State.IsComplete()) { if (!levelUpController.State.StatsDistribution.IsComplete()) { levelUpLog.Add("Stat Distribution is incomplete"); } if (levelUpController.State.CanSelectAlignment) { levelUpLog.Add("Alignment not selected"); } if (levelUpController.State.CanSelectRace) { levelUpLog.Add("Race not selected"); } if (levelUpController.State.CanSelectRaceStat) { levelUpLog.Add("CanSelectRaceStat"); } if (levelUpController.State.CanSelectName) { levelUpLog.Add("CanSelectName"); } if (levelUpController.State.CanSelectPortrait) { levelUpLog.Add("CanSelectPortrait"); } if (levelUpController.State.CanSelectGender) { levelUpLog.Add("CanSelectGender"); } if (!levelUpController.State.CanSelectVoice) { levelUpLog.Add("CanSelectVoice"); } if (levelUpController.State.AttributePoints > 0) { levelUpLog.Add("Unassigned Attribute Points"); } if (levelUpController.State.SelectedClass == null) { levelUpLog.Add("Class is null"); } if (!levelUpController.State.IsSkillPointsComplete()) { levelUpLog.Add("Unassigned Skill Points"); } if (levelUpController.State.Selections.Any((FeatureSelectionState s) => !s.Selected && s.CanSelectAnything(levelUpController.State, unitEntityData.Descriptor))) { levelUpLog.Add("Unassinged Features"); } if (levelUpController.State.SpellSelections.Any((SpellSelectionData data) => data.CanSelectAnything(unitEntityData.Descriptor))) { levelUpLog.Add("Unassigned Spells"); } } if (ValidLevels[i]) { Message[i] = "Valid level plan"; } else { Message[i] = $"Invalid level plan:\n{string.Join("\n", levelUpLog)}"; } } }