public void SelectWithQuantityOf0_Thrown(string weapon) { var thrown = WeaponConstants.GetAllThrown(false, false); var simple = WeaponConstants.GetAllSimple(false, false); var melee = WeaponConstants.GetAllMelee(false, false); var thrownRanged = thrown.Except(melee).Intersect(simple); Assert.That(thrownRanged, Contains.Item(weapon) .And.EquivalentTo(new[] { WeaponConstants.Javelin, WeaponConstants.Dart, })); var item = itemSelector.SelectFrom($"{weapon}[{ItemTypeConstants.Weapon}]"); Assert.That(item.Name, Is.EqualTo(weapon), weapon); Assert.That(item.ItemType, Is.EqualTo(ItemTypeConstants.Weapon), weapon); Assert.That(item.Traits, Is.Empty, weapon); Assert.That(item.Magic.SpecialAbilities, Is.Empty, weapon); Assert.That(item.Magic.Bonus, Is.Zero, weapon); Assert.That(item.IsMagical, Is.False, weapon); Assert.That(item.Quantity, Is.Zero, weapon); }
public Item SelectFrom(string source) { var template = new Item(); template.Name = source; template.Name = itemTypeRegex.Replace(template.Name, string.Empty); template.Name = itemBonusRegex.Replace(template.Name, string.Empty); template.Name = specialAbilityRegex.Replace(template.Name, string.Empty); template.Name = traitRegex.Replace(template.Name, string.Empty); template.Name = isMagicRegex.Replace(template.Name, string.Empty); template.ItemType = GetMatchValue(itemTypeRegex, source, "[", "]"); if (isMagicRegex.IsMatch(source)) { var rawIsMagic = GetMatchValue(isMagicRegex, source, "@", "@"); template.IsMagical = Convert.ToBoolean(rawIsMagic); } if (itemBonusRegex.IsMatch(source)) { var rawBonus = GetMatchValue(itemBonusRegex, source, "(", ")"); template.Magic.Bonus = Convert.ToInt32(rawBonus); } if (specialAbilityRegex.IsMatch(source)) { var rawSpecialAbilities = GetMatchValue(specialAbilityRegex, source, "{", "}"); var specialAbilities = rawSpecialAbilities.Split(','); template.Magic.SpecialAbilities = GetSpecialAbilities(specialAbilities); } if (traitRegex.IsMatch(source)) { var rawTraits = GetMatchValue(traitRegex, source, "#"); var traits = rawTraits.Split(','); foreach (var trait in traits) { template.Traits.Add(trait); } } var ammunition = WeaponConstants.GetAllAmmunition(false, false); var thrown = WeaponConstants.GetAllThrown(false, false); var simple = WeaponConstants.GetAllSimple(false, false); var melee = WeaponConstants.GetAllMelee(false, false); var thrownRanged = thrown.Except(melee).Intersect(simple); var needRandomQuantity = ammunition.Union(thrownRanged); if (needRandomQuantity.Contains(template.Name)) { template.Quantity = 0; } return(template); }
public void SelectWithQuantityOf1_AllOtherWeapons() { var allWeapons = WeaponConstants.GetAllWeapons(false, false); var ammos = WeaponConstants.GetAllAmmunition(false, false); var thrown = WeaponConstants.GetAllThrown(false, false); var simple = WeaponConstants.GetAllSimple(false, false); var melee = WeaponConstants.GetAllMelee(false, false); var thrownRanged = thrown.Except(melee).Intersect(simple); var weapons = allWeapons.Except(ammos).Except(thrownRanged); foreach (var weapon in weapons) { var item = itemSelector.SelectFrom($"{weapon}[{ItemTypeConstants.Weapon}]"); Assert.That(item.Name, Is.EqualTo(weapon), weapon); Assert.That(item.ItemType, Is.EqualTo(ItemTypeConstants.Weapon), weapon); Assert.That(item.Traits, Is.Empty, weapon); Assert.That(item.Magic.SpecialAbilities, Is.Empty, weapon); Assert.That(item.Magic.Bonus, Is.Zero, weapon); Assert.That(item.IsMagical, Is.False, weapon); Assert.That(item.Quantity, Is.EqualTo(1), weapon); } }
public void MeleeWeaponsMatchConstants() { var melee = WeaponConstants.GetAllMelee(false, false); VerifyAttribute(melee, AttributeConstants.Melee); }
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); }
private Item GetWeapon(Item rod) { var weapons = WeaponConstants.GetAllMelee(false, false); var weaponBaseNames = weapons.Intersect(rod.BaseNames); if (!weaponBaseNames.Any()) { return(rod); } var weaponName = weaponBaseNames.First(); var mundaneWeaponGenerator = justInTimeFactory.Build <MundaneItemGenerator>(ItemTypeConstants.Weapon); var mundaneWeapon = mundaneWeaponGenerator.Generate(weaponName, rod.Traits.ToArray()) as Weapon; rod.Attributes = rod.Attributes.Union(mundaneWeapon.Attributes); rod.CloneInto(mundaneWeapon); if (mundaneWeapon.IsMagical) { mundaneWeapon.Traits.Add(TraitConstants.Masterwork); } if (mundaneWeapon.IsDoubleWeapon) { mundaneWeapon.SecondaryHasAbilities = true; mundaneWeapon.SecondaryMagicBonus = rod.Magic.Bonus; } foreach (var specialAbility in mundaneWeapon.Magic.SpecialAbilities) { if (specialAbility.Damages.Any()) { var damages = specialAbility.Damages.Select(d => d.Clone()).ToArray(); var damageType = mundaneWeapon.Damages[0].Type; foreach (var damage in damages) { if (string.IsNullOrEmpty(damage.Type)) { damage.Type = damageType; } } mundaneWeapon.Damages.AddRange(damages); if (mundaneWeapon.SecondaryHasAbilities) { var secondaryDamages = specialAbility.Damages.Select(d => d.Clone()).ToArray(); var secondaryDamageType = mundaneWeapon.SecondaryDamages[0].Type; foreach (var damage in secondaryDamages) { if (string.IsNullOrEmpty(damage.Type)) { damage.Type = secondaryDamageType; } } mundaneWeapon.SecondaryDamages.AddRange(secondaryDamages); } } if (specialAbility.CriticalDamages.Any()) { var damageType = mundaneWeapon.CriticalDamages[0].Type; foreach (var damage in specialAbility.CriticalDamages[mundaneWeapon.CriticalMultiplier]) { if (string.IsNullOrEmpty(damage.Type)) { damage.Type = damageType; } } mundaneWeapon.CriticalDamages.AddRange(specialAbility.CriticalDamages[mundaneWeapon.CriticalMultiplier]); if (mundaneWeapon.SecondaryHasAbilities) { foreach (var damage in specialAbility.CriticalDamages[mundaneWeapon.SecondaryCriticalMultiplier]) { if (string.IsNullOrEmpty(damage.Type)) { damage.Type = damageType; } } mundaneWeapon.SecondaryCriticalDamages.AddRange(specialAbility.CriticalDamages[mundaneWeapon.SecondaryCriticalMultiplier]); } } if (specialAbility.Name == SpecialAbilityConstants.Keen) { mundaneWeapon.ThreatRange *= 2; } } return(mundaneWeapon); }