private IEnumerable<Feat> GetAdditionalFeats(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, Dictionary<String, Skill> skills, BaseAttack baseAttack, IEnumerable<Feat> preselectedFeats) { var additionalFeatSelections = featsSelector.SelectAdditional(); var availableFeatSelections = additionalFeatSelections.Where(s => s.ImmutableRequirementsMet(baseAttack.RangedBonus, stats, skills, characterClass)); var numberOfAdditionalFeats = characterClass.Level / 3 + 1; if (race.BaseRace == RaceConstants.BaseRaces.Human) numberOfAdditionalFeats++; if (characterClass.Name == CharacterClassConstants.Rogue && characterClass.Level >= 10) numberOfAdditionalFeats += (characterClass.Level - 10) / 3 + 1; var monsters = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.BaseRaceGroups, GroupConstants.Monsters); if (monsters.Contains(race.BaseRace)) { var monsterHitDice = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.MonsterHitDice); numberOfAdditionalFeats += monsterHitDice[race.BaseRace] / 3 + 1; } var feats = PopulateFeatsFrom(characterClass, stats, skills, baseAttack, preselectedFeats, availableFeatSelections, numberOfAdditionalFeats); return feats; }
public IEnumerable<Feat> GenerateWith(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills, BaseAttack baseAttack, IEnumerable<Feat> preselectedFeats) { var additionalFeats = GetAdditionalFeats(characterClass, race, stats, skills, baseAttack, preselectedFeats); var allButBonusFeats = preselectedFeats.Union(additionalFeats); var bonusFeats = GetBonusFeats(characterClass, race, stats, skills, baseAttack, allButBonusFeats); return additionalFeats.Union(bonusFeats); }
public BaseAttack GenerateBaseAttackWith(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats) { var baseAttack = new BaseAttack(); baseAttack.BaseBonus = GetBaseAttackBonus(characterClass); baseAttack.SizeModifier = GetSizeAdjustments(race); baseAttack.StrengthBonus = stats[StatConstants.Strength].Bonus; baseAttack.DexterityBonus = stats[StatConstants.Dexterity].Bonus; baseAttack.RacialModifier = GetRacialBaseAttackAdjustments(race); return baseAttack; }
public Ability GenerateWith(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, BaseAttack baseAttack) { var ability = new Ability(); ability.Stats = stats; ability.Languages = languageGenerator.GenerateWith(race, characterClass.Name, ability.Stats[StatConstants.Intelligence].Bonus); ability.Skills = skillsGenerator.GenerateWith(characterClass, race, ability.Stats); ability.Feats = featsGenerator.GenerateWith(characterClass, race, ability.Stats, ability.Skills, baseAttack); var allFeatGrantingSkillBonuses = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, FeatConstants.SkillBonus); var featNames = ability.Feats.Select(f => f.Name); var featNamesGrantingSkillBonuses = allFeatGrantingSkillBonuses.Intersect(featNames); var featGrantingSkillBonuses = ability.Feats.Where(f => featNamesGrantingSkillBonuses.Contains(f.Name)); var allSkills = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.SkillGroups, GroupConstants.Skills); foreach (var feat in featGrantingSkillBonuses) { if (feat.Foci.Any()) { foreach (var focus in feat.Foci) { if (allSkills.Any(s => focus.StartsWith(s)) == false) continue; var skill = allSkills.First(s => focus.StartsWith(s)); if (ability.Skills.ContainsKey(skill) == false) continue; var circumstantial = allSkills.Contains(focus) == false; ability.Skills[skill].CircumstantialBonus |= circumstantial; if (circumstantial == false) ability.Skills[skill].Bonus += feat.Power; } } else { var skillsToReceiveBonus = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.SkillGroups, feat.Name); foreach (var skill in skillsToReceiveBonus) if (ability.Skills.ContainsKey(skill)) ability.Skills[skill].Bonus += feat.Power; } } return ability; }
public Combat GenerateWith(BaseAttack baseAttack, CharacterClass characterClass, Race race, IEnumerable<Feat> feats, Dictionary<String, Stat> stats, Equipment equipment) { var combat = new Combat(); combat.BaseAttack = baseAttack; combat.BaseAttack.BaseBonus += GetBonusFromFeats(feats); combat.BaseAttack.CircumstantialBonus = IsAttackBonusCircumstantial(feats); combat.AdjustedDexterityBonus = GetAdjustedDexterityBonus(stats, equipment); combat.ArmorClass = armorClassGenerator.GenerateWith(equipment, combat.AdjustedDexterityBonus, feats, race); if (stats.ContainsKey(StatConstants.Constitution)) combat.HitPoints = hitPointsGenerator.GenerateWith(characterClass, stats[StatConstants.Constitution].Bonus, race, feats); else combat.HitPoints = hitPointsGenerator.GenerateWith(characterClass, 0, race, feats); combat.SavingThrows = savingThrowsGenerator.GenerateWith(characterClass, feats, stats); combat.InitiativeBonus = GetInitiativeBonus(combat.AdjustedDexterityBonus, feats); return combat; }
public IEnumerable<Feat> GenerateWith(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills, BaseAttack baseAttack) { var racialFeats = racialFeatsGenerator.GenerateWith(race, skills, stats); var classFeats = classFeatsGenerator.GenerateWith(characterClass, race, stats, racialFeats, skills); var automaticFeats = racialFeats.Union(classFeats); var additionalFeats = additionalFeatsGenerator.GenerateWith(characterClass, race, stats, skills, baseAttack, automaticFeats); var allFeats = automaticFeats.Union(additionalFeats); var featsToCombine = allFeats.Where(f => CanCombine(f, allFeats)); var featsToRemove = new List<Feat>(); var combinedFeatNames = new List<string>(); foreach (var featToCombine in featsToCombine) { if (combinedFeatNames.Contains(featToCombine.Name)) continue; var combinableFeats = featsToCombine.Where(f => CanCombine(f, featsToCombine)); if (combinableFeats.Count() < 2) continue; var otherFeats = Enumerable.Empty<Feat>(); if (combinableFeats.Any(f => f.Frequency.TimePeriod == FeatConstants.Frequencies.Constant)) { var featToKeep = combinableFeats.First(f => f.Frequency.TimePeriod == FeatConstants.Frequencies.Constant); otherFeats = combinableFeats.Except(new[] { featToKeep }); } else if (combinableFeats.Any(f => f.Frequency.TimePeriod == FeatConstants.Frequencies.AtWill)) { var featToKeep = combinableFeats.First(f => f.Frequency.TimePeriod == FeatConstants.Frequencies.AtWill); otherFeats = combinableFeats.Except(new[] { featToKeep }); } else { otherFeats = combinableFeats.Except(new[] { featToCombine }); featToCombine.Frequency.Quantity = combinableFeats.Sum(f => f.Frequency.Quantity); } featsToRemove.AddRange(otherFeats); combinedFeatNames.Add(featToCombine.Name); } var featsWithRemovableStrengths = allFeats.Where(f => CanRemoveStrength(f, allFeats)); combinedFeatNames.Clear(); foreach (var featToRemove in featsWithRemovableStrengths) { if (combinedFeatNames.Contains(featToRemove.Name)) continue; var removableFeats = featsWithRemovableStrengths.Where(f => f.Name == featToRemove.Name); var maxPower = removableFeats.Max(f => f.Power); var featToKeep = removableFeats.First(f => f.Power == maxPower); var otherFeats = removableFeats.Except(new[] { featToKeep }); featsToRemove.AddRange(otherFeats); combinedFeatNames.Add(featToRemove.Name); } if (allFeats.Any(f => f.Foci.Contains(FeatConstants.Foci.All))) { var featsWithAllFocus = allFeats.Where(f => f.Foci.Contains(FeatConstants.Foci.All)); var featNamesAllowingMultipleTakes = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, GroupConstants.TakenMultipleTimes); var featNamesWithAllFocus = featsWithAllFocus.Select(f => f.Name).Except(featNamesAllowingMultipleTakes); var redundantFeats = allFeats.Where(f => featNamesWithAllFocus.Contains(f.Name) && f.Foci.Contains(FeatConstants.Foci.All) == false); featsToRemove.AddRange(redundantFeats); foreach (var feat in featsWithAllFocus) feat.Foci = new[] { FeatConstants.Foci.All }; } var remainingFeats = allFeats.Except(featsToRemove); var featsWithCombinableFoci = remainingFeats.Where(f => CanCombineFoci(f, remainingFeats)); var combinedFeatNamesAndPowers = new Dictionary<string, List<int>>(); foreach (var featToKeep in featsWithCombinableFoci) { if (combinedFeatNamesAndPowers.ContainsKey(featToKeep.Name) == false) combinedFeatNamesAndPowers[featToKeep.Name] = new List<int>(); if (combinedFeatNamesAndPowers[featToKeep.Name].Contains(featToKeep.Power)) continue; combinedFeatNamesAndPowers[featToKeep.Name].Add(featToKeep.Power); var removableFeats = featsWithCombinableFoci.Where(f => f.Name == featToKeep.Name && f.Power == featToKeep.Power); foreach (var featToRemove in removableFeats) { var matchingFoci = featToKeep.Foci.Intersect(featToRemove.Foci); if (matchingFoci.Any()) continue; featToKeep.Foci = featToKeep.Foci.Union(featToRemove.Foci); featsToRemove.Add(featToRemove); } } allFeats = allFeats.Except(featsToRemove); return allFeats; }
public void Setup() { baseAttack = new BaseAttack(); }
public void Setup() { mockStatsRandomizer = new Mock<IStatsRandomizer>(); mockStatsGenerator = new Mock<IStatsGenerator>(); mockLanguageGenerator = new Mock<ILanguageGenerator>(); mockSkillsGenerator = new Mock<ISkillsGenerator>(); mockFeatsGenerator = new Mock<IFeatsGenerator>(); mockCollectionsSelector = new Mock<ICollectionsSelector>(); abilitiesGenerator = new AbilitiesGenerator(mockStatsGenerator.Object, mockLanguageGenerator.Object, mockSkillsGenerator.Object, mockFeatsGenerator.Object, mockCollectionsSelector.Object); stats = new Dictionary<string, Stat>(); baseAttack = new BaseAttack(); characterClass = new CharacterClass(); race = new Race(); characterClass.Name = "class name"; stats[StatConstants.Intelligence] = new Stat(StatConstants.Intelligence); stats[StatConstants.Intelligence].Value = 9266; mockStatsGenerator.Setup(g => g.GenerateWith(mockStatsRandomizer.Object, characterClass, race)).Returns(stats); mockCollectionsSelector.Setup(s => s.SelectFrom(TableNameConstants.Set.Collection.SkillGroups, GroupConstants.Skills)).Returns(new[] { "skill 1", "skill 2", "skill 3", "skill 4", "skill 5" }); }
private void SetUpGenerators() { mockAlignmentGenerator = new Mock<IAlignmentGenerator>(); mockAbilitiesGenerator = new Mock<IAbilitiesGenerator>(); mockCombatGenerator = new Mock<ICombatGenerator>(); mockTreasureGenerator = new Mock<IEquipmentGenerator>(); mockCharacterClassGenerator = new Mock<ICharacterClassGenerator>(); mockRaceGenerator = new Mock<IRaceGenerator>(); mockMagicGenerator = new Mock<IMagicGenerator>(); generator = new ConfigurableIterationGenerator(4); alignment = new Alignment(); characterClass = new CharacterClass(); race = new Race(); ability = new Ability(); equipment = new Equipment(); combat = new Combat(); baseAttack = new BaseAttack(); feats = new List<Feat>(); magic = new Magic(); alignment.Goodness = "goodness"; alignment.Lawfulness = "lawfulness"; characterClass.Level = 1; characterClass.Name = "class name"; race.BaseRace = BaseRace; race.Metarace = RaceConstants.Metaraces.None; ability.Feats = feats; ability.Stats["stat"] = new Stat("stat"); mockCombatGenerator.Setup(g => g.GenerateBaseAttackWith(It.IsAny<CharacterClass>(), It.IsAny<Race>(), It.IsAny<Dictionary<string, Stat>>())).Returns(() => new BaseAttack()); mockTreasureGenerator.Setup(g => g.GenerateWith(It.IsAny<IEnumerable<Feat>>(), It.IsAny<CharacterClass>(), It.IsAny<Race>())).Returns(() => new Equipment()); mockCombatGenerator.Setup(g => g.GenerateWith(It.IsAny<BaseAttack>(), It.IsAny<CharacterClass>(), It.IsAny<Race>(), It.IsAny<IEnumerable<Feat>>(), It.IsAny<Dictionary<string, Stat>>(), It.IsAny<Equipment>())).Returns(() => new Combat()); mockMagicGenerator.Setup(g => g.GenerateWith(It.IsAny<Alignment>(), It.IsAny<CharacterClass>(), It.IsAny<Race>(), It.IsAny<Dictionary<string, Stat>>(), It.IsAny<IEnumerable<Feat>>(), It.IsAny<Equipment>())).Returns(() => new Magic()); mockAlignmentGenerator.Setup(g => g.GenerateWith(mockAlignmentRandomizer.Object)).Returns(alignment); mockCharacterClassGenerator.Setup(g => g.GenerateWith(alignment, mockLevelRandomizer.Object, mockClassNameRandomizer.Object)).Returns(characterClass); mockCharacterClassGenerator.Setup(g => g.GenerateWith(alignment, mockSetLevelRandomizer.Object, mockClassNameRandomizer.Object)).Returns(characterClass); mockRaceGenerator.Setup(g => g.GenerateWith(alignment, characterClass, mockBaseRaceRandomizer.Object, mockMetaraceRandomizer.Object)).Returns(race); mockAbilitiesGenerator.Setup(g => g.GenerateStats(characterClass, race, mockStatsRandomizer.Object)).Returns(ability.Stats); mockAbilitiesGenerator.Setup(g => g.GenerateWith(characterClass, race, ability.Stats, baseAttack)).Returns(ability); mockTreasureGenerator.Setup(g => g.GenerateWith(ability.Feats, characterClass, race)).Returns(equipment); mockCombatGenerator.Setup(g => g.GenerateWith(baseAttack, characterClass, race, ability.Feats, ability.Stats, equipment)).Returns(combat); mockCombatGenerator.Setup(g => g.GenerateBaseAttackWith(characterClass, race, ability.Stats)).Returns(baseAttack); mockMagicGenerator.Setup(g => g.GenerateWith(alignment, characterClass, race, ability.Stats, ability.Feats, equipment)).Returns(magic); }
private IEnumerable<Feat> GetBonusFeats(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills, BaseAttack baseAttack, IEnumerable<Feat> preselectedFeats) { if (characterClass.Name == CharacterClassConstants.Fighter) return GetFighterFeats(characterClass, race, stats, skills, baseAttack, preselectedFeats); else if (characterClass.Name == CharacterClassConstants.Wizard) return GetWizardBonusFeats(characterClass, race, stats, skills, baseAttack, preselectedFeats); return Enumerable.Empty<Feat>(); }
private List<Feat> PopulateFeatsFrom(CharacterClass characterClass, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills, BaseAttack baseAttack, IEnumerable<Feat> preselectedFeats, IEnumerable<AdditionalFeatSelection> sourceFeats, Int32 quantity) { var feats = new List<Feat>(); var chosenFeats = preselectedFeats; var availableFeats = GetAvailableFeats(sourceFeats, chosenFeats); while (quantity-- > 0 && availableFeats.Any()) { var featSelection = collectionsSelector.SelectRandomFrom(availableFeats); var preliminaryFocus = featFocusGenerator.GenerateFrom(featSelection.Feat, featSelection.FocusType, skills, featSelection.RequiredFeats, chosenFeats, characterClass); if (preliminaryFocus == FeatConstants.Foci.All) { quantity++; sourceFeats = sourceFeats.Except(new[] { featSelection }); availableFeats = GetAvailableFeats(sourceFeats, chosenFeats); continue; } var feat = new Feat(); var hasMatchingFeat = feats.Any(f => FeatsMatch(f, featSelection)); if (hasMatchingFeat) { feat = feats.First(f => FeatsMatch(f, featSelection)); } else { feat.Name = featSelection.Feat; feat.Frequency = featSelection.Frequency; feat.Power = featSelection.Power; if (featSelection.Feat == FeatConstants.SpellMastery) feat.Power = stats[StatConstants.Intelligence].Bonus; feats.Add(feat); } chosenFeats = preselectedFeats.Union(feats); availableFeats = GetAvailableFeats(sourceFeats, chosenFeats); if (string.IsNullOrEmpty(preliminaryFocus) == false) feat.Foci = feat.Foci.Union(new[] { preliminaryFocus }); var featFociQuantity = 0; if (featSelection.Feat == FeatConstants.SkillMastery) featFociQuantity = stats[StatConstants.Intelligence].Bonus + featSelection.Power - 1; while (featFociQuantity-- > 0 && preliminaryFocus != FeatConstants.Foci.All && string.IsNullOrEmpty(preliminaryFocus) == false) { preliminaryFocus = featFocusGenerator.GenerateFrom(featSelection.Feat, featSelection.FocusType, skills, featSelection.RequiredFeats, chosenFeats, characterClass); feat.Foci = feat.Foci.Union(new[] { preliminaryFocus }); } } return feats; }
private IEnumerable<Feat> GetWizardBonusFeats(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills, BaseAttack baseAttack, IEnumerable<Feat> selectedFeats) { var wizardFeatIds = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, GroupConstants.WizardBonusFeats); var wizardFeats = featsSelector.SelectAdditional().Where(f => wizardFeatIds.Contains(f.Feat)); var availableFeats = wizardFeats.Where(f => f.ImmutableRequirementsMet(baseAttack.RangedBonus, stats, skills, characterClass)); var numberOfWizardFeats = characterClass.Level / 5; var feats = PopulateFeatsFrom(characterClass, stats, skills, baseAttack, selectedFeats, availableFeats, numberOfWizardFeats); return feats; }
public void Setup() { mockCollectionsSelector = new Mock<ICollectionsSelector>(); mockFeatsSelector = new Mock<IFeatsSelector>(); mockFeatFocusGenerator = new Mock<IFeatFocusGenerator>(); mockAdjustmentsSelector = new Mock<IAdjustmentsSelector>(); additionalFeatsGenerator = new AdditionalFeatsGenerator(mockCollectionsSelector.Object, mockFeatsSelector.Object, mockFeatFocusGenerator.Object, mockAdjustmentsSelector.Object); characterClass = new CharacterClass(); race = new Race(); stats = new Dictionary<string, Stat>(); skills = new Dictionary<string, Skill>(); additionalFeatSelections = new List<AdditionalFeatSelection>(); baseAttack = new BaseAttack(); stats[StatConstants.Intelligence] = new Stat(StatConstants.Intelligence); preselectedFeats = new List<Feat>(); fighterBonusFeats = new List<string>(); wizardBonusFeats = new List<string>(); monsters = new List<string>(); monsters.Add("monster"); mockFeatsSelector.Setup(s => s.SelectAdditional()).Returns(additionalFeatSelections); mockCollectionsSelector.Setup(s => s.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, GroupConstants.FighterBonusFeats)).Returns(fighterBonusFeats); mockCollectionsSelector.Setup(s => s.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, GroupConstants.WizardBonusFeats)).Returns(wizardBonusFeats); mockCollectionsSelector.Setup(s => s.SelectRandomFrom(It.IsAny<IEnumerable<AdditionalFeatSelection>>())).Returns((IEnumerable<AdditionalFeatSelection> fs) => fs.First()); mockCollectionsSelector.Setup(s => s.SelectFrom(TableNameConstants.Set.Collection.BaseRaceGroups, GroupConstants.Monsters)).Returns(monsters); }
public void Setup() { mockRacialFeatsGenerator = new Mock<IRacialFeatsGenerator>(); mockClassFeatsGenerator = new Mock<IClassFeatsGenerator>(); mockAdditionalFeatsGenerator = new Mock<IAdditionalFeatsGenerator>(); mockCollectionsSelector = new Mock<ICollectionsSelector>(); featsGenerator = new FeatsGenerator(mockRacialFeatsGenerator.Object, mockClassFeatsGenerator.Object, mockAdditionalFeatsGenerator.Object, mockCollectionsSelector.Object); characterClass = new CharacterClass(); race = new Race(); stats = new Dictionary<string, Stat>(); skills = new Dictionary<string, Skill>(); baseAttack = new BaseAttack(); racialFeats = new List<Feat>(); mockRacialFeatsGenerator.Setup(g => g.GenerateWith(race, skills, stats)).Returns(racialFeats); }