public async Task AttackWithRangedWeapon(int range = 0, string weaponName = null) { if (range < 0) { await ReplyAsync($"Range can't be negative."); return; } var activeCharacter = _stewardContext.PlayerCharacters .Include(c => c.DefaultRangedWeapon) .Include(c => c.House) .Include(c => c.CharacterTraits) .ThenInclude(ct => ct.Trait) .SingleOrDefault(c => c.DiscordUserId == Context.User.Id.ToString() && c.YearOfDeath == null); ValkFinderWeapon valkFinderWeapon = null; valkFinderWeapon = activeCharacter.DefaultRangedWeapon ?? _stewardContext.ValkFinderWeapons.FirstOrDefault(w => w.WeaponName == weaponName); if (valkFinderWeapon == null) { await ReplyAsync($"Could not find weapon."); return; } if (!_inventoryService.CheckInv(activeCharacter, valkFinderWeapon.WeaponName, "weapon", 1)) { await ReplyAsync($"You do not have a {valkFinderWeapon.WeaponName} in your inventory"); return; } if (!valkFinderWeapon.IsRanged) { await ReplyAsync($"{weaponName} is not a ranged weapon."); return; } var message = _rollService.RollRangedAttack(activeCharacter, valkFinderWeapon, range); await ReplyAsync(embed : message.Build()); }
public EmbedBuilder RollMeleeAttack(PlayerCharacter character, ValkFinderWeapon weapon, string attackType) { var attackTypeHitBonus = 0; var attackTypeDamageBonus = 0; switch (attackType) { case "heavy": attackTypeHitBonus = 2; attackTypeDamageBonus = 1; break; case "light": attackTypeHitBonus = -4; attackTypeDamageBonus = -2; break; case "normal": break; default: var embedBuilderError = new EmbedBuilder().WithColor(Color.Purple); embedBuilderError.AddField("Error", "Unknown attack type"); return(embedBuilderError); } var rnd = new Random(); var strMod = GetStatAsModifier(CharacterAttribute.STR, character); var dexMod = 0; //GetStatAsModifier(CharacterAttribute.DEX, character); -- ditto as below if (weapon.WeaponTrait == WeaponTrait.Finesse) { strMod = 0; dexMod = GetStatAsModifier(CharacterAttribute.DEX, character); } var attackRollRaw = rnd.Next(1, 21); var attackRoll = attackRollRaw + strMod + dexMod + attackTypeHitBonus + weapon.HitBonus; if (attackRoll < 0) { attackRoll = 0; } var crit = attackRollRaw == 20; //are we crittin'? var damageRollsRaw = new List <int>(); for (var i = 0; i < weapon.DamageDieAmount; i++) { damageRollsRaw.Add(rnd.Next(1, weapon.DamageDieSize + 1)); } var critRolls = new List <int>(); if (crit) { for (var i = 0; i < weapon.DamageDieAmount; i++) { critRolls.Add(rnd.Next(1, weapon.DamageDieSize + 1)); } } strMod = GetStatAsModifier(CharacterAttribute.STR, character); dexMod = GetStatAsModifier(CharacterAttribute.DEX, character); var damage = damageRollsRaw.Sum() + weapon.DamageBonus + attackTypeDamageBonus + critRolls.Sum() + strMod + dexMod; //TODO: Clean this up into something modular, redefining the entire string each time just isn't maintainable. //Done: cleaned up into something modular var attackRollString = $"(1d20 = {attackRollRaw}) + {strMod + dexMod}"; if (attackTypeHitBonus != 0) { attackRollString += $" + {attackTypeHitBonus} from attack type"; } if (weapon.HitBonus != 0) { attackRollString += $" + {weapon.HitBonus} from weapon"; } attackRollString += $" = {attackRoll}"; if (crit) { attackRollString += " **!Critical Hit!**"; } var damageRollsRawString = string.Join(" + ", damageRollsRaw); var critRollsString = string.Join(" + ", critRolls); var damageRollString = $"({weapon.DamageDieAmount}d{weapon.DamageDieSize} = {damageRollsRawString})"; if (crit) { damageRollString += $" + ({weapon.DamageDieAmount}d{weapon.DamageDieSize} = {critRollsString}) from crit"; } if (attackTypeDamageBonus != 0) { damageRollString += $" + {attackTypeDamageBonus} from attack type"; } if (weapon.DamageBonus != 0) { damageRollString += $" + {weapon.DamageBonus} from weapon"; } damageRollString += $" + {strMod}(STR) + {dexMod}(DEX) = {damage}"; var embedBuilder = new EmbedBuilder().WithColor(Color.Purple).WithTitle($"Melee: {weapon.WeaponName} ({attackType}) by {character.CharacterName}"); embedBuilder.AddField("Attack Roll", attackRollString); embedBuilder.AddField("Damage Roll", damageRollString); return(embedBuilder); }
public EmbedBuilder RollRangedAttack(PlayerCharacter character, ValkFinderWeapon weapon, int range = 0) { var rnd = new Random(); var perMod = GetStatAsModifier(CharacterAttribute.PER, character); var dexMod = GetStatAsModifier(CharacterAttribute.DEX, character); var rangePenalty = 0; //-(range / 2); var attackRollRaw = rnd.Next(1, 21); var attackRoll = attackRollRaw + perMod + dexMod + rangePenalty + weapon.HitBonus; var crit = attackRollRaw == 20; /*if (attackRoll < 0) * { * attackRoll = 0; * } * * var damageRollBonus = 0; //GetStatAsModifier(weapon.DamageModifier, character); -- ―〃― * var rawDamageRoll = rnd.Next(1, weapon.DamageDieSize + 1); * var damageRoll = rawDamageRoll + damageRollBonus; * * if (crit) * damageRoll += rawDamageRoll; * * if (damageRoll < 0) * { * damageRoll = 0; * }*/ var damageRollsRaw = new List <int>(); for (int i = 0; i < weapon.DamageDieAmount; i++) { damageRollsRaw.Add(rnd.Next(1, weapon.DamageDieSize + 1)); } var damage = damageRollsRaw.Sum() + weapon.DamageBonus + dexMod; if (crit) { damage = damageRollsRaw.Sum() * 2 + weapon.DamageBonus; } var attackRollString = $"(1d20 = {attackRollRaw}) + {perMod + dexMod}"; if (weapon.HitBonus != 0) { attackRollString += $" + {weapon.HitBonus} from weapon"; } attackRollString += $" = {attackRoll}"; if (crit) { attackRollString += " **!Critical Hit!**"; } var damageRollsRawString = string.Join(" + ", damageRollsRaw); var damageRollString = $"({weapon.DamageDieAmount}d{weapon.DamageDieSize} = {damageRollsRawString})"; if (crit) { damageRollString += $" * 2 from crit"; } if (weapon.DamageBonus != 0) { damageRollString += $" + {weapon.DamageBonus} from weapon"; } damageRollString += $" + {dexMod}(DEX) = {damage}"; var embedBuilder = new EmbedBuilder().WithColor(Color.Purple).WithTitle($"Ranged: {weapon.WeaponName}"); embedBuilder.AddField("Attack Roll", attackRollString); embedBuilder.AddField("Damage Roll", damageRollString); return(embedBuilder); }
public async Task AddWeapon(string name, string rangedOrMelee, string damage, int hitBonus, string weaponTraitString = "None", bool unique = false) { if (name.Length > 100) { await ReplyAsync("Weapon name can't be longer than 100 characters."); return; } if (rangedOrMelee != "ranged" && rangedOrMelee != "melee") { await ReplyAsync("Weapon has to be either melee or ranged."); return; } var damageDieAmount = 0; var damageDieSize = 0; var damageBonus = 0; var pattern = @"(\d+)d(\d+)([+-])(\d+)"; if (Regex.IsMatch(damage, pattern)) { foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(damage, pattern)) { damageDieAmount = Int32.Parse(m.Groups[1].Value); damageDieSize = Int32.Parse(m.Groups[2].Value); damageBonus = Int32.Parse(m.Groups[3].Value + m.Groups[4].Value); } } else { await ReplyAsync($"{damage}: is not a valid damage die and modifier"); return; } if (!Enum.TryParse(weaponTraitString, true, out WeaponTrait weaponTrait)) { await ReplyAsync("Not a valid attribute."); return; } var doesWeaponAlreadyExist = _stewardContext.ValkFinderWeapons.SingleOrDefault(vfw => vfw.WeaponName == name); if (doesWeaponAlreadyExist != null) { await ReplyAsync("Weapon already exists."); return; } var newWeapon = new ValkFinderWeapon() { WeaponName = name, DamageDieAmount = damageDieAmount, DamageDieSize = damageDieSize, DamageBonus = damageBonus, HitBonus = hitBonus, IsRanged = rangedOrMelee == "ranged", IsUnique = unique, WeaponTrait = weaponTrait }; _stewardContext.ValkFinderWeapons.Add(newWeapon); await _stewardContext.SaveChangesAsync(); await ReplyAsync("Weapon added."); }