public Race GenerateWith(Alignment alignment, CharacterClass characterClass, RaceRandomizer baseRaceRandomizer, RaceRandomizer metaraceRandomizer) { var race = new Race(); race.BaseRace = baseRaceRandomizer.Randomize(alignment, characterClass); race.Metarace = metaraceRandomizer.Randomize(alignment, characterClass); race.MetaraceSpecies = DetermineMetaraceSpecies(alignment, race.Metarace); race.IsMale = DetermineIfMale(race.BaseRace, characterClass.Name); race.Size = DetermineSize(race.BaseRace); race.HasWings = DetermineIfRaceHasWings(race); race.LandSpeed = DetermineLandSpeed(race); race.AerialSpeed = DetermineAerialSpeed(race); race.Age = DetermineAge(race, characterClass); var tableName = string.Format(TableNameConstants.Formattable.Adjustments.GENDERHeights, race.Gender); var baseHeights = adjustmentsSelector.SelectFrom(tableName); var heightModifier = GetModifier(race, TableNameConstants.Set.Collection.HeightRolls); race.HeightInInches = baseHeights[race.BaseRace] + heightModifier; tableName = string.Format(TableNameConstants.Formattable.Adjustments.GENDERWeights, race.Gender); var baseWeights = adjustmentsSelector.SelectFrom(tableName); var weightModifier = GetModifier(race, TableNameConstants.Set.Collection.WeightRolls); race.WeightInPounds = baseWeights[race.BaseRace] + heightModifier * weightModifier; return race; }
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; }
private string GetStatToIncrease(Dictionary<string, Stat> stats, Race race, CharacterClass characterClass) { var statPriorities = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.StatPriorities, characterClass.Name); var undead = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.MetaraceGroups, GroupConstants.Undead); if (undead.Contains(race.Metarace)) statPriorities = statPriorities.Except(new[] { StatConstants.Constitution }); if (statPriorities.Any() == false) { var stat = collectionsSelector.SelectRandomFrom(stats.Keys); while (undead.Contains(race.Metarace) && stat == StatConstants.Constitution) stat = collectionsSelector.SelectRandomFrom(stats.Keys); return stat; } var secondPriorityStats = statPriorities.Skip(1); if (secondPriorityStats.Any() == false) return statPriorities.First(); var increaseFirst = booleanPercentileSelector.SelectFrom(TableNameConstants.Set.TrueOrFalse.IncreaseFirstPriorityStat); if (increaseFirst) return statPriorities.First(); return collectionsSelector.SelectRandomFrom(secondPriorityStats); }
public IEnumerable<Feat> GenerateWith(Race race, Dictionary<string, Skill> skills, Dictionary<string, Stat> stats) { var baseRacialFeatSelections = featsSelector.SelectRacial(race.BaseRace); var metaracialFeatSelections = featsSelector.SelectRacial(race.Metarace); var featToIncreasePower = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.FeatGroups, GroupConstants.AddMonsterHitDiceToPower); foreach (var selection in metaracialFeatSelections) if (featToIncreasePower.Contains(selection.Feat)) selection.Power += GetMonsterHitDice(race.BaseRace); var metaraceSpeciesFeatSelections = featsSelector.SelectRacial(race.MetaraceSpecies); var allRacialFeatSelections = baseRacialFeatSelections.Union(metaracialFeatSelections).Union(metaraceSpeciesFeatSelections); var monsterHitDice = GetMonsterHitDice(race.BaseRace); var applicableRacialFeatSelections = allRacialFeatSelections.Where(s => s.RequirementsMet(race, monsterHitDice, stats)); var feats = new List<Feat>(); foreach (var racialFeatSelection in applicableRacialFeatSelections) { var feat = new Feat(); feat.Name = racialFeatSelection.Feat; var focus = featFocusGenerator.GenerateAllowingFocusOfAllFrom(racialFeatSelection.Feat, racialFeatSelection.FocusType, skills); if (string.IsNullOrEmpty(focus) == false) feat.Foci = feat.Foci.Union(new[] { focus }); feat.Frequency = racialFeatSelection.Frequency; feat.Power = racialFeatSelection.Power; feats.Add(feat); } return feats; }
private Dictionary<string, Skill> AddMonsterSkillRanks(Race race, Dictionary<string, Stat> stats, Dictionary<string, Skill> skills) { var monsterSkills = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ClassSkills, race.BaseRace); var monsterHitDice = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.MonsterHitDice); foreach (var monsterSkill in monsterSkills) { if (skills.ContainsKey(monsterSkill) == false) { var selection = skillSelector.SelectFor(monsterSkill); if (stats.ContainsKey(selection.BaseStatName) == false) continue; skills[monsterSkill] = new Skill(monsterSkill, stats[selection.BaseStatName], 0); } skills[monsterSkill].RankCap += monsterHitDice[race.BaseRace] + 3; skills[monsterSkill].ClassSkill = true; } var intelligenceSkillBonus = Math.Max(1, 2 + stats[StatConstants.Intelligence].Bonus); var points = (monsterHitDice[race.BaseRace] + 3) * intelligenceSkillBonus; var validMonsterSkills = FilterOutInvalidSkills(monsterSkills, skills); while (points-- > 0 && validMonsterSkills.Any()) { var skill = collectionsSelector.SelectRandomFrom(validMonsterSkills); skills[skill].Ranks++; validMonsterSkills = FilterOutInvalidSkills(monsterSkills, skills); } return skills; }
public Dictionary<string, Skill> GenerateWith(CharacterClass characterClass, Race race, Dictionary<string, Stat> stats) { var classSkills = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ClassSkills, characterClass.Name); var crossClassSkills = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.CrossClassSkills, characterClass.Name); var specialistSkills = Enumerable.Empty<string>(); foreach (var specialistField in characterClass.SpecialistFields) { var newSpecialistSkills = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.SkillGroups, specialistField); specialistSkills = specialistSkills.Union(newSpecialistSkills); } classSkills = classSkills.Union(specialistSkills); if (characterClass.Name == CharacterClassConstants.Expert) classSkills = GetRandomClassSkills(); var skills = InitializeSkills(stats, classSkills, crossClassSkills, characterClass); skills = AddRanks(characterClass, race, stats, classSkills, crossClassSkills, skills); var monsters = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.BaseRaceGroups, GroupConstants.Monsters); if (monsters.Contains(race.BaseRace)) skills = AddMonsterSkillRanks(race, stats, skills); skills = ApplySkillSynergies(skills); return skills; }
public IEnumerable<string> GenerateWith(Race race, string className, int intelligenceBonus) { var languages = new List<string>(); var automaticLanguages = languagesSelector.SelectAutomaticLanguagesFor(race, className); languages.AddRange(automaticLanguages); var bonusLanguages = languagesSelector.SelectBonusLanguagesFor(race.BaseRace, className); var remainingBonusLanguages = bonusLanguages.Except(languages).ToList(); var numberOfBonusLanguages = intelligenceBonus; if (numberOfBonusLanguages >= remainingBonusLanguages.Count) { languages.AddRange(remainingBonusLanguages); return languages; } while (numberOfBonusLanguages-- > 0 && remainingBonusLanguages.Any()) { var language = collectionsSelector.SelectRandomFrom(remainingBonusLanguages); languages.Add(language); remainingBonusLanguages.Remove(language); } return languages; }
public Item GenerateMeleeFrom(IEnumerable<Feat> feats, CharacterClass characterClass, Race race) { var meleeWeapons = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ItemGroups, AttributeConstants.Melee); var weapon = GenerateFiltered(feats, characterClass, race, meleeWeapons); return weapon; }
public IEnumerable<string> SelectAutomaticLanguagesFor(Race race, string className) { var baseRaceLanguages = innerSelector.SelectFrom(TableNameConstants.Set.Collection.AutomaticLanguages, race.BaseRace); var metaraceLanguages = innerSelector.SelectFrom(TableNameConstants.Set.Collection.AutomaticLanguages, race.Metarace); var classLanguages = innerSelector.SelectFrom(TableNameConstants.Set.Collection.AutomaticLanguages, className); return baseRaceLanguages.Union(metaraceLanguages).Union(classLanguages); }
public bool VerifyRaceCompatibility(Race race, CharacterClass characterClass, ILevelRandomizer levelRandomizer) { if (levelRandomizer is ISetLevelRandomizer && (levelRandomizer as ISetLevelRandomizer).AllowAdjustments == false) return true; var levelAdjustments = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.LevelAdjustments); return characterClass.Level + levelAdjustments[race.BaseRace] + levelAdjustments[race.Metarace] > 0; }
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 Item GenerateFrom(IEnumerable<Feat> feats, CharacterClass characterClass, Race race) { var weapons = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ItemGroups, FeatConstants.Foci.Weapons); var ammunition = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ItemGroups, AttributeConstants.Ammunition); var nonAmmunitionWeapons = weapons.Except(ammunition); var weapon = GenerateFiltered(feats, characterClass, race, nonAmmunitionWeapons); return weapon; }
private int GetClassHitPoints(CharacterClass characterClass, int constitutionBonus, Race race) { var undead = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.MetaraceGroups, GroupConstants.Undead); if (undead.Contains(race.Metarace)) return RollHitPoints(characterClass.Level, 12, constitutionBonus); var hitDice = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.ClassHitDice); return RollHitPoints(characterClass.Level, hitDice[characterClass.Name], constitutionBonus); }
private Dictionary<string, Stat> AdjustStats(Race race, Dictionary<string, Stat> stats) { var statAdjustments = statAdjustmentsSelector.SelectFor(race); foreach (var stat in stats.Keys) stats[stat].Value += statAdjustments[stat]; return stats; }
private bool ArmorIsValid(Item armor, IEnumerable<string> proficientArmors, CharacterClass characterClass, Race race) { if (armor == null) return true; if (armor.Attributes.Contains(AttributeConstants.Shield)) return false; return IsValid(armor, proficientArmors, characterClass, race); }
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 Character() { Alignment = new Alignment(); Class = new CharacterClass(); Race = new Race(); InterestingTrait = string.Empty; Combat = new Combat(); Ability = new Ability(); Equipment = new Equipment(); Magic = new Magic(); }
private Age DetermineAge(Race race, CharacterClass characterClass) { var tableName = string.Format(TableNameConstants.Formattable.Adjustments.RACEAges, race.BaseRace); var ages = adjustmentsSelector.SelectFrom(tableName); var age = new Age(); age.Maximum = GetMaximumAge(race, ages); age.Years = GetAgeInYears(race, characterClass, ages, age.Maximum); age.Stage = GetAgeStage(age.Years, ages); return age; }
private int DetermineAerialSpeed(Race race) { if (race.Metarace == RaceConstants.Metaraces.Ghost) return 30; if (race.HasWings == false) return 0; if (race.Metarace == RaceConstants.Metaraces.HalfFiend) return race.LandSpeed; return race.LandSpeed * 2; }
public bool RequirementsMet(Race race, int monsterHitDice, Dictionary<string, Stat> stats) { if (string.IsNullOrEmpty(SizeRequirement) == false && SizeRequirement != race.Size) return false; if (MaximumHitDieRequirement > 0 && monsterHitDice > MaximumHitDieRequirement) return false; if (MinimumStatMet(stats) == false) return false; return monsterHitDice >= MinimumHitDieRequirement; }
public Item GenerateShieldFrom(IEnumerable<Feat> feats, CharacterClass characterClass, Race race) { var effectiveLevel = GetEffectiveLevel(characterClass); var tableName = string.Format(TableNameConstants.Formattable.Percentile.LevelXPower, effectiveLevel); var power = percentileSelector.SelectFrom(tableName); var proficientShields = GetProficientArmors(feats, AttributeConstants.Shield); if (proficientShields.Any() == false) return null; return generator.Generate(() => GenerateArmor(power), s => ShieldIsValid(s, proficientShields, characterClass, race)); }
private int GetAdditionalMonsterHitDice(Race race, int constitutionBonus) { var hitDice = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.MonsterHitDice); if (race.Metarace == RaceConstants.Metaraces.HalfDragon) return RollHitPoints(hitDice[race.BaseRace], 10, constitutionBonus); var undead = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.MetaraceGroups, GroupConstants.Undead); if (undead.Contains(race.Metarace)) return RollHitPoints(hitDice[race.BaseRace], 12, constitutionBonus); return RollHitPoints(hitDice[race.BaseRace], 8, constitutionBonus); }
public int GenerateWith(CharacterClass characterClass, int constitutionBonus, Race race, IEnumerable<Feat> feats) { var hitPoints = GetClassHitPoints(characterClass, constitutionBonus, race); var toughness = feats.Where(f => f.Name == FeatConstants.Toughness); hitPoints += toughness.Sum(f => f.Power); var monsters = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.BaseRaceGroups, GroupConstants.Monsters); if (monsters.Contains(race.BaseRace) == false) return hitPoints; var monsterHitPoints = GetAdditionalMonsterHitDice(race, constitutionBonus); return hitPoints + monsterHitPoints; }
private IEnumerable<string> AnimalsForCharacter(CharacterClass characterClass, Race race, Dictionary<string, int> levelAdjustments) { var animals = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.Animals, characterClass.Name); var animalsForSize = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.Animals, race.Size); var animalsWithinLevel = animals.Where(a => characterClass.Level + levelAdjustments[a] > 0); var filteredAnimals = animals.Intersect(animalsForSize).Intersect(animalsWithinLevel); var mages = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ClassNameGroups, GroupConstants.Mages); if (mages.Contains(characterClass.Name) == false) return filteredAnimals; var animalsForMetarace = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.Animals, race.Metarace); return filteredAnimals.Intersect(animalsForMetarace); }
public Dictionary<string, int> SelectFor(Race race) { var adjustments = new Dictionary<string, int>(); var stats = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.StatGroups, GroupConstants.All); foreach (var stat in stats) { var tableName = string.Format(TableNameConstants.Formattable.Adjustments.STATStatAdjustments, stat); var statAdjustments = innerSelector.SelectFrom(tableName); adjustments[stat] = statAdjustments[race.BaseRace] + statAdjustments[race.Metarace]; } return adjustments; }
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 IEnumerable<string> RegenerateSpecialistFields(Alignment alignment, CharacterClass characterClass, Race race) { if (characterClass.SpecialistFields.Any() == false || race.Metarace == RaceConstants.Metaraces.None) return characterClass.SpecialistFields; var allClassSpecialistFields = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.SpecialistFields, characterClass.Name); var allMetaraceSpecialistFields = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.SpecialistFields, race.Metarace); var applicableFields = allClassSpecialistFields.Intersect(allMetaraceSpecialistFields); if (applicableFields.Any() == false) return characterClass.SpecialistFields; var nonAlignmentFields = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.ProhibitedFields, alignment.ToString()); var possibleSpecialistFields = applicableFields.Except(nonAlignmentFields); return PopulateFields(characterClass.SpecialistFields.Count(), possibleSpecialistFields); }
public ArmorClass GenerateWith(Equipment equipment, int adjustedDexterityBonus, IEnumerable<Feat> feats, Race race) { var armorClass = new ArmorClass(); armorClass.AdjustedDexterityBonus = adjustedDexterityBonus; armorClass.ArmorBonus = GetArmorBonus(equipment); armorClass.DeflectionBonus = GetDeflectionBonus(equipment.Treasure.Items); armorClass.DodgeBonus = GetDodgeBonus(feats); armorClass.NaturalArmorBonus = GetNaturalArmorBonus(equipment.Treasure.Items, feats, race); armorClass.ShieldBonus = GetShieldBonus(equipment); armorClass.SizeModifier = GetSizeModifier(race); var circumstantialDodgeBonus = IsDodgeBonusCircumstantial(feats); var circumstantialNaturalArmorBonus = IsNaturalArmorBonusCircumstantial(feats); armorClass.CircumstantialBonus = circumstantialDodgeBonus || circumstantialNaturalArmorBonus; return armorClass; }
public void Setup() { mockInnerSelector = new Mock<IAdjustmentsSelector>(); mockCollectionsSelector = new Mock<ICollectionsSelector>(); selector = new StatAdjustmentsSelector(mockInnerSelector.Object, mockCollectionsSelector.Object); race = new Race(); defaultAdjustments = new Dictionary<String, Int32>(); statNames = new List<String>(); race.BaseRace = "base race"; race.Metarace = "metarace"; defaultAdjustments[race.BaseRace] = 0; defaultAdjustments[race.Metarace] = 0; mockInnerSelector.Setup(s => s.SelectFrom(It.IsAny<String>())).Returns(defaultAdjustments); mockCollectionsSelector.Setup(s => s.SelectFrom(TableNameConstants.Set.Collection.StatGroups, GroupConstants.All)).Returns(statNames); statNames.Add("first stat"); statNames.Add("second stat"); }
public string GenerateFrom(Alignment alignment, CharacterClass characterClass, Race race, IEnumerable<Feat> feats) { if (characterClass.Name == CharacterClassConstants.Adept && characterClass.Level == 1) return string.Empty; var levelAdjustments = adjustmentsSelector.SelectFrom(TableNameConstants.Set.Adjustments.LevelAdjustments); var effectiveCharacterClass = GetEffectiveCharacterClass(characterClass); var animals = AnimalsForCharacter(effectiveCharacterClass, race, levelAdjustments); if (animals.Any() == false) return string.Empty; var improvedFamiliars = collectionsSelector.SelectFrom(TableNameConstants.Set.Collection.Animals, FeatConstants.ImprovedFamiliar); var characterHasImprovedFamiliarFeat = feats.Any(f => f.Name == FeatConstants.ImprovedFamiliar); var animal = generator.Generate(() => collectionsSelector.SelectRandomFrom(animals), a => characterHasImprovedFamiliarFeat || improvedFamiliars.Contains(a) == false); return animal; }