Esempio n. 1
0
        public void LightWeaponsMatchConstants()
        {
            var light = WeaponConstants.GetAllLightMelee(false, false);

            VerifyAttribute(light, AttributeConstants.Light);
        }
Esempio n. 2
0
        public Equipment Generate(string creatureName, bool canUseEquipment, IEnumerable <Feat> feats, int level, IEnumerable <Attack> attacks, Dictionary <string, Ability> abilities, string size)
        {
            var equipment = new Equipment();

            var weaponSize = GetWeaponSize(feats, size);

            //Get predetermined items
            var allPredeterminedItems = GetPredeterminedItems(creatureName, size, weaponSize);
            var predeterminedWeapons  = allPredeterminedItems
                                        .Where(i => i is Weapon)
                                        .Select(i => i as Weapon)
                                        .ToList();
            var predeterminedArmors = allPredeterminedItems
                                      .Where(i => i is Armor)
                                      .Select(i => i as Armor)
                                      .ToList();

            equipment.Items = allPredeterminedItems.Except(predeterminedWeapons).Except(predeterminedArmors);

            if (predeterminedArmors.Any())
            {
                equipment.Shield = predeterminedArmors.FirstOrDefault(a => a.Attributes.Contains(AttributeConstants.Shield));
                equipment.Armor  = predeterminedArmors.FirstOrDefault(a => !a.Attributes.Contains(AttributeConstants.Shield));
            }

            //INFO: If there are equipment attacks, but the level is 0, then this is a humanoid character
            //These attacks will be updated when the character is generated
            if (!canUseEquipment || level < 1)
            {
                return(equipment);
            }

            //Generate weapons and attacks
            var unnaturalAttacks = attacks.Where(a => !a.IsNatural);

            var weaponProficiencyFeatNames = collectionSelector.SelectFrom(TableNameConstants.Collection.FeatGroups, GroupConstants.WeaponProficiency);
            var weaponProficiencyFeats     = feats.Where(f => weaponProficiencyFeatNames.Contains(f.Name));

            var weapons = new List <Weapon>();
            var hasMultipleEquippedMeleeAttacks = unnaturalAttacks.Count(a => a.Name == AttributeConstants.Melee) >= 2;

            if (weaponProficiencyFeats.Any() && unnaturalAttacks.Any())
            {
                //Generate melee weapons
                var weaponNames = WeaponConstants.GetAllWeapons(false, false);

                var equipmentMeleeAttacks = unnaturalAttacks.Where(a => a.Name == AttributeConstants.Melee);
                if (equipmentMeleeAttacks.Any())
                {
                    var meleeWeaponNames = WeaponConstants.GetAllMelee(false, false);

                    var nonProficiencyFeats = feats.Except(weaponProficiencyFeats);
                    var hasWeaponFinesse    = feats.Any(f => f.Name == FeatConstants.WeaponFinesse);
                    var light = WeaponConstants.GetAllLightMelee(true, false);

                    var proficientMeleeWeaponNames    = GetProficientWeaponNames(feats, weaponProficiencyFeats, meleeWeaponNames, !hasMultipleEquippedMeleeAttacks);
                    var nonProficientMeleeWeaponNames = meleeWeaponNames
                                                        .Except(proficientMeleeWeaponNames.Common)
                                                        .Except(proficientMeleeWeaponNames.Uncommon);

                    if (hasMultipleEquippedMeleeAttacks)
                    {
                        var twoHandedWeapons = WeaponConstants.GetAllTwoHandedMelee(false, false);
                        nonProficientMeleeWeaponNames = nonProficientMeleeWeaponNames.Except(twoHandedWeapons);
                    }

                    var primaryMeleeAttacks    = equipmentMeleeAttacks.Where(a => a.IsPrimary).ToArray();
                    var primaryLightBonusAdded = false;

                    foreach (var attack in equipmentMeleeAttacks)
                    {
                        Weapon weapon = null;

                        if (predeterminedWeapons.Any(i => i.Attributes.Contains(AttributeConstants.Melee)))
                        {
                            weapon = predeterminedWeapons.First(i => i.Attributes.Contains(AttributeConstants.Melee));

                            predeterminedWeapons.Remove(weapon);
                        }
                        else
                        {
                            var weaponName = collectionSelector.SelectRandomFrom(
                                proficientMeleeWeaponNames.Common,
                                proficientMeleeWeaponNames.Uncommon,
                                null,
                                nonProficientMeleeWeaponNames);
                            weapon = itemGenerator.GenerateAtLevel(level, ItemTypeConstants.Weapon, weaponName, weaponSize) as Weapon;
                        }

                        weapons.Add(weapon);

                        attack.Name = weapon.Description;
                        attack.Damages.AddRange(weapon.Damages);

                        //Is not proficient with the weapon
                        if (!proficientMeleeWeaponNames.Common.Any(weapon.NameMatches) &&
                            !proficientMeleeWeaponNames.Uncommon.Any(weapon.NameMatches))
                        {
                            attack.AttackBonuses.Add(-4);
                        }

                        if (weapon.Magic.Bonus != 0)
                        {
                            attack.AttackBonuses.Add(weapon.Magic.Bonus);
                        }
                        else if (weapon.Traits.Contains(TraitConstants.Masterwork))
                        {
                            attack.AttackBonuses.Add(1);
                        }

                        var bonusFeats = nonProficiencyFeats.Where(f => f.Foci.Any(weapon.NameMatches));
                        foreach (var feat in bonusFeats)
                        {
                            if (feat.Power != 0)
                            {
                                attack.AttackBonuses.Add(feat.Power);
                            }
                        }

                        var isLight = light.Any(weapon.NameMatches);
                        if (hasWeaponFinesse && isLight)
                        {
                            attack.BaseAbility = abilities[AbilityConstants.Dexterity];
                        }

                        if (hasMultipleEquippedMeleeAttacks && !attack.IsPrimary && isLight)
                        {
                            attack.AttackBonuses.Add(2);

                            if (!primaryLightBonusAdded)
                            {
                                foreach (var primaryAttack in primaryMeleeAttacks)
                                {
                                    primaryAttack.AttackBonuses.Add(2);
                                }
                            }

                            primaryLightBonusAdded = true;
                        }
                    }
                }

                //Generate ranged weapons
                var equipmentRangedAttacks = unnaturalAttacks.Where(a => a.Name == AttributeConstants.Ranged);
                if (equipmentRangedAttacks.Any())
                {
                    var rangedWeaponNames = GetRangedWithBowTemplates();

                    var proficientRangedWeaponNames    = GetProficientWeaponNames(feats, weaponProficiencyFeats, rangedWeaponNames, !hasMultipleEquippedMeleeAttacks);
                    var nonProficientRangedWeaponNames = rangedWeaponNames
                                                         .Except(proficientRangedWeaponNames.Common)
                                                         .Except(proficientRangedWeaponNames.Uncommon);

                    var nonProficiencyFeats = feats.Except(weaponProficiencyFeats);
                    var crossbows           = new[]
                    {
                        WeaponConstants.HandCrossbow,
                        WeaponConstants.HeavyCrossbow,
                        WeaponConstants.LightCrossbow,
                    };

                    var rapidReload = feats.FirstOrDefault(f => f.Name == FeatConstants.RapidReload);

                    foreach (var attack in equipmentRangedAttacks)
                    {
                        Weapon weapon = null;

                        if (predeterminedWeapons.Any(i =>
                                                     i.Attributes.Contains(AttributeConstants.Ranged) &&
                                                     !i.Attributes.Contains(AttributeConstants.Melee)))
                        {
                            weapon = predeterminedWeapons.First(i =>
                                                                i.Attributes.Contains(AttributeConstants.Ranged) &&
                                                                !i.Attributes.Contains(AttributeConstants.Melee));

                            predeterminedWeapons.Remove(weapon);
                        }
                        else
                        {
                            var weaponName = collectionSelector.SelectRandomFrom(
                                proficientRangedWeaponNames.Common,
                                proficientRangedWeaponNames.Uncommon,
                                null,
                                nonProficientRangedWeaponNames);
                            weapon = itemGenerator.GenerateAtLevel(level, ItemTypeConstants.Weapon, weaponName, weaponSize) as Weapon;
                        }

                        weapons.Add(weapon);

                        //Get ammunition
                        if (!string.IsNullOrEmpty(weapon.Ammunition))
                        {
                            Weapon ammo = null;

                            if (predeterminedWeapons.Any(i => i.NameMatches(weapon.Ammunition)))
                            {
                                ammo = predeterminedWeapons.First(i => i.NameMatches(weapon.Ammunition));

                                predeterminedWeapons.Remove(ammo);
                            }
                            else
                            {
                                ammo = itemGenerator.GenerateAtLevel(level, ItemTypeConstants.Weapon, weapon.Ammunition, weaponSize) as Weapon;
                            }

                            weapons.Add(ammo);
                        }

                        //Set up the attack
                        attack.Name = weapon.Description;
                        attack.Damages.AddRange(weapon.Damages);

                        if (!proficientRangedWeaponNames.Common.Any(weapon.NameMatches) &&
                            !proficientRangedWeaponNames.Uncommon.Any(weapon.NameMatches))
                        {
                            attack.AttackBonuses.Add(-4);
                        }

                        if (weapon.Magic.Bonus != 0)
                        {
                            attack.AttackBonuses.Add(weapon.Magic.Bonus);
                        }
                        else if (weapon.Traits.Contains(TraitConstants.Masterwork))
                        {
                            attack.AttackBonuses.Add(1);
                        }

                        var bonusFeats = nonProficiencyFeats.Where(f => f.Foci.Any(weapon.NameMatches));
                        foreach (var feat in bonusFeats)
                        {
                            if (feat.Power != 0)
                            {
                                attack.AttackBonuses.Add(feat.Power);
                            }
                        }

                        if (!weapon.Attributes.Contains(AttributeConstants.Thrown) &&
                            !weapon.Attributes.Contains(AttributeConstants.Projectile))
                        {
                            attack.MaxNumberOfAttacks = 1;
                        }

                        if (crossbows.Any(weapon.NameMatches))
                        {
                            attack.MaxNumberOfAttacks = 1;

                            if (rapidReload?.Foci?.Any(weapon.NameMatches) == true &&
                                (weapon.NameMatches(WeaponConstants.LightCrossbow) ||
                                 weapon.NameMatches(WeaponConstants.HandCrossbow)))
                            {
                                attack.MaxNumberOfAttacks = 4;
                            }
                        }
                    }
                }

                equipment.Weapons = weapons;
            }

            var armorProficiencyFeatNames = collectionSelector.SelectFrom(TableNameConstants.Collection.FeatGroups, GroupConstants.ArmorProficiency);
            var armorProficiencyFeats     = feats.Where(f => armorProficiencyFeatNames.Contains(f.Name));

            if (armorProficiencyFeats.Any())
            {
                var armorNames           = ArmorConstants.GetAllArmors(false);
                var proficientArmorNames = GetProficientArmorNames(armorProficiencyFeats);

                if (proficientArmorNames.Any() && equipment.Armor == null)
                {
                    var nonProficientArmorNames = armorNames.Except(proficientArmorNames);
                    var armorName = collectionSelector.SelectRandomFrom(proficientArmorNames, null, null, nonProficientArmorNames);

                    equipment.Armor = itemGenerator.GenerateAtLevel(level, ItemTypeConstants.Armor, armorName, size) as Armor;
                }

                var shieldNames           = ArmorConstants.GetAllShields(false);
                var proficientShieldNames = GetProficientShieldNames(armorProficiencyFeats);
                var hasTwoHandedWeapon    = weapons.Any(w => w.Attributes.Contains(AttributeConstants.Melee) && w.Attributes.Contains(AttributeConstants.TwoHanded));

                if (proficientShieldNames.Any() &&
                    !hasTwoHandedWeapon &&
                    !hasMultipleEquippedMeleeAttacks &&
                    equipment.Shield == null)
                {
                    var nonProficientShieldNames = shieldNames.Except(proficientShieldNames);
                    var shieldName = collectionSelector.SelectRandomFrom(proficientShieldNames, null, null, nonProficientShieldNames);

                    equipment.Shield = itemGenerator.GenerateAtLevel(level, ItemTypeConstants.Armor, shieldName, size) as Armor;
                }
            }

            return(equipment);
        }