Esempio n. 1
0
        public async Task Attack([Remainder] string args = "")
        {
            Character c;

            args = args.ToLower();

            if (args.Contains("-c"))
            {
                c    = GetCompanion();
                args = args.Replace("-c", "");
                if (c == null)
                {
                    await ReplyAsync("You have no active companion.");

                    return;
                }
            }
            else
            {
                c = GetCharacter();
                if (c == null)
                {
                    await ReplyAsync("You have no active character.");

                    return;
                }
            }
            if (args.NullorEmpty())
            {
                var strikes = await SheetService.Get(c, "strikes");

                var embed = new EmbedBuilder()
                            .WithTitle(c.Name + "'s strikes")
                            .WithThumbnailUrl(c.ImageUrl);

                if (strikes.Count() == 0)
                {
                    await ReplyAsync(c.Name + " has no strikes.");

                    return;
                }

                var sb = new StringBuilder();
                foreach (var s in strikes)
                {
                    string act = Icons.Actions["1"];
                    if (!((string)s["actions"]).NullorEmpty())
                    {
                        if (Icons.Actions.TryGetValue((string)s["actions"], out string ic))
                        {
                            act = ic;
                        }
                        else
                        {
                            act = "[" + s["actions"] + "]";
                        }
                    }
                    sb.AppendLine(Icons.Strike[(string)s["attack"]] + " " + (((string)s["name"]).NullorEmpty() ? "Unnamed Strike" : (string)s["name"]) + " " + act);
                }
                embed.WithDescription(sb.ToString());

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }
                else
                {
                    Random randonGen   = new Random();
                    Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                                   randonGen.Next(255));
                    embed.WithColor(randomColor);
                }

                await ReplyAsync("", embed.Build());

                return;
            }
            else
            {
                string[] Bonuses = new string[0];

                if (BonusRegex.IsMatch(args))
                {
                    Bonuses = BonusRegex.Matches(args).Select(x => x.Value).ToArray();
                    foreach (var b in Bonuses)
                    {
                        args = args.Replace(b, "");
                    }
                    args = args.Trim();
                }

                var Jstrikes = await SheetService.Get(c, "strikes");

                var values = await SheetService.GetValues(c);

                if (values == null || Jstrikes == null)
                {
                    var err = new EmbedBuilder()
                              .WithTitle("Click here")
                              .WithUrl("https://character.pf2.tools/?" + c.RemoteId)
                              .WithDescription("Seems like we cannot fetch " + c.Name + "'s values. This is due to the fact values are only updated when you open the sheet in pf2.tools. To fix this, click the link above to generate those values.");
                    await ReplyAsync("", err.Build());

                    return;
                }

                var strikes = from sk in Jstrikes
                              where ((string)sk["name"]).ToLower().StartsWith(args)
                              orderby sk["name"]
                              select sk;

                if (strikes.Count() == 0)
                {
                    await ReplyAsync("You have no strikes whose name starts with '" + args + "'.");

                    return;
                }

                var s     = strikes.FirstOrDefault();
                var embed = new EmbedBuilder()
                            .WithTitle(c.Name + " strikes with a " + (((string)s["name"]).NullorEmpty() ? "Unnamed Strike" : (string)s["name"]) + "!")
                            .WithThumbnailUrl(c.ImageUrl);

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }
                else
                {
                    Random randonGen   = new Random();
                    Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                                   randonGen.Next(255));
                    embed.WithColor(randomColor);
                }

                await ReplyAsync("Rolling...");

                string hit         = "";
                string dmg         = "";
                string penalties   = "";
                string damagebonus = "";
                string dmgtype     = "Untyped";

                if ((string)s["attack"] == "spell")
                {
                    dmgtype = "Spell";
                    var classes = await SheetService.Get(c, "classes");

                    JToken cl = null;
                    if (((string)s["class"]).NullorEmpty())
                    {
                        cl = classes.FirstOrDefault();
                    }
                    else
                    {
                        cl = classes.First(x => (string)x["id"] == (string)s["class"]);
                    }
                    if (classes == null || classes.Count == 0)
                    {
                        await ReplyAsync("You don't seem to have a class. Without one you can't make spell attacks.");

                        return;
                    }

                    if (!values.ContainsKey(((string)cl["name"]).ToLower()))
                    {
                        await ReplyAsync("Sorry! It seems we cannot retrieve the data for this strike! This issue is outside of the bot's control and will likely be solved later.");

                        return;
                    }

                    hit = (string)values[((string)cl["name"]).ToLower()]["bonus"];

                    int dc = int.Parse(hit ?? "0") + 10;

                    dmg = (string)s["overridedamage"];

                    if (!dmg.NullorEmpty() && AttributeRegex.IsMatch(dmg))
                    {
                        dmg = await ParseValues(dmg, c, values);
                    }

                    string summary = "";

                    var result = Roller.Roll("d20 + " + hit + (Bonuses.Length > 0?string.Join(" ", Bonuses):""));

                    summary += "Spell Attack roll: " + result.ParseResult() + " = `" + result.Value + "`" +
                               "\nDC: `" + dc + "`";

                    if (!((string)s["spell"]).NullorEmpty())
                    {
                        var spells = await SheetService.Get(c, "spells");

                        var sp = spells.First(x => (string)x["id"] == (string)s["spell"]);
                        if (!((string)sp["body"]).NullorEmpty())
                        {
                            embed.AddField("Spell description", sp["body"]);
                        }
                        if (!((string)sp["savingthrow"]).NullorEmpty())
                        {
                            summary += "\nSaving Throw: " + sp["savingthrow"];
                        }
                        embed.WithTitle(c.Name + " casts " + (sp["name"] ?? "Unnamed Spell") + "!");
                    }
                    if (!dmg.NullorEmpty())
                    {
                        try
                        {
                            RollResult result2 = Roller.Roll(dmg + damagebonus);

                            summary += "\n" + dmgtype.Uppercase() + " damage: " + result2.ParseResult() + " = `" + result2.Value + "` ";

                            if (!((string)s["extradamage"]).NullorEmpty())
                            {
                                RollResult result3 = Roller.Roll((string)s["extradamage"]);
                                summary += "\n" + ((string)s["overridedamage"]).Uppercase() + " damage: " + result3.ParseResult() + " = `" + result3.Value + "`";
                            }
                        }
                        catch
                        {
                            await ReplyAsync("It seems like this strike doesn't have a valid dice roll on its damage or additional damage fields. If this is a spell make sure you have a valid dice expression on the damage fields.");

                            return;
                        }
                    }


                    embed.WithDescription(summary)
                    .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));



                    await ReplyAsync(" ", embed.Build());
                }
                else
                {
                    if (!((string)s["weapon"]).NullorEmpty())
                    {
                        var items = await SheetService.Get(c, "items");

                        var i = items.First(x => (string)x["id"] == (string)s["weapon"]);
                        dmgtype = (string)i["damagetype"] ?? "Untyped";
                    }
                    else
                    {
                        dmgtype = "Bludgeoning";
                    }

                    if ((string)s["attack"] == "melee" || ((string)s["attack"]).NullorEmpty())
                    {
                        hit       = (string)values["melee " + (string)s["name"]]["bonus"];
                        penalties = (string)values["melee " + (string)s["name"]]["penalty"];
                    }
                    else
                    {
                        hit       = (string)values["ranged " + (string)s["name"]]["bonus"];
                        penalties = (string)values["ranged " + (string)s["name"]]["penalty"];
                    }

                    damagebonus = (string)values["damage " + (string)s["name"]]["value"];

                    dmg = (string)values["damagedice " + (string)s["name"]]["value"] + GetDie((int)values["damagedie " + (string)s["name"]]["value"]);

                    string summary = "";

                    var result = Roller.Roll("d20 + " + hit + (penalties != "0"? "-" + penalties:"") + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));

                    summary += "Attack roll: " + result.ParseResult() + " = `" + result.Value + "`";

                    if (!dmg.NullorEmpty())
                    {
                        try
                        {
                            RollResult result2 = Roller.Roll(dmg + "+" + damagebonus);
                            summary += "\n" + dmgtype.Uppercase() + " damage: " + result2.ParseResult() + " = `" + result2.Value + "` ";

                            if (!((string)s["extradamage"]).NullorEmpty())
                            {
                                RollResult result3 = Roller.Roll((string)s["extradamage"]);
                                summary += "\n" + ((string)s["overridedamage"]).Uppercase() + " damage: " + result3.ParseResult() + " = `" + result3.Value + "`";
                            }
                        }
                        catch
                        {
                            await ReplyAsync("It seems like this strike doesn't have a valid dice roll on its damage or additional damage fields. If this is a spell make sure you have a valid dice expression on the damage fields.");

                            return;
                        }
                    }


                    embed.WithDescription(summary)
                    .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));



                    await ReplyAsync(" ", embed.Build());
                }
            }
        }
Esempio n. 2
0
        public async Task SkillCheck([Remainder] string Skill)
        {
            Character c;

            Skill = Skill.ToLower();
            bool familiar = false;

            if (Skill.Contains("-c"))
            {
                c = GetCompanion();
                if (c == null)
                {
                    await ReplyAsync("You have no active companion.");

                    return;
                }
                Skill = Skill.Replace("-c", "").Trim();
            }
            else
            {
                c = GetCharacter();
                if (c == null)
                {
                    await ReplyAsync("You have no active character.");

                    return;
                }
            }
            if (Skill.Contains("-f"))
            {
                familiar = true;
                Skill    = Skill.Replace("-f", "".Trim());
            }
            string[] Bonuses = new string[0];
            if (BonusRegex.IsMatch(Skill))
            {
                Bonuses = BonusRegex.Matches(Skill).Select(x => x.Value).ToArray();
                foreach (var b in Bonuses)
                {
                    Skill = Skill.Replace(b, "");
                }
                Skill = Skill.Trim();
            }

            var sheet = await SheetService.GetFullSheet(c);

            var values = await SheetService.GetValues(c);

            ;
            if (values == null || sheet == null)
            {
                var embed = new EmbedBuilder()
                            .WithTitle("Click here")
                            .WithUrl("https://character.pf2.tools/?" + c.RemoteId)
                            .WithDescription("Seems like we cannot fetch " + c.Name + "'s values. This is due to the fact values are only updated when you open the sheet in pf2.tools. To fix this, click the link above to generate those values.");
                await ReplyAsync("", embed.Build());

                return;
            }


            if (Skill == "perception" || Skill == "per" || Skill == "perc")
            {
                var    embed = new EmbedBuilder();
                JToken bonus;
                string message = "";
                if (familiar)
                {
                    if (c.Familiar.NullorEmpty())
                    {
                        await ReplyAsync("You have no named familiars.");

                        return;
                    }
                    bonus   = (int)values["famperception " + c.Familiar]["bonus"] - (int)values["famperception " + c.Familiar]["penalty"];;
                    message = c.Name + "'s familiar makes a Perception check!";
                    embed.WithThumbnailUrl(c.FamImg);
                }
                else
                {
                    bonus   = values["perception"]["bonus"] ?? 0;
                    message = c.Name + " makes a Perception check!";
                    embed.WithThumbnailUrl(c.ImageUrl);
                }
                var result = Roller.Roll("d20 + " + bonus + (Bonuses.Length > 0?string.Join(" ", Bonuses):""));


                embed.WithTitle(message)
                .WithDescription(result.ParseResult() + "\nTotal = `" + result.Value + "`")
                .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));;
                Random randonGen   = new Random();
                Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                               randonGen.Next(255));
                embed.WithColor(randomColor);

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }

                await ReplyAsync("", embed.Build());

                return;
            }
            else
            {
                var    embed = new EmbedBuilder();
                JToken bonus;
                string message = "";
                if (familiar)
                {
                    if (c.Familiar.NullorEmpty())
                    {
                        await ReplyAsync("You have no named familiars.");

                        return;
                    }
                    switch (Skill.ToLower())
                    {
                    case "acrobatics":
                        bonus   = (int)values["famacrobatics " + c.Familiar]["bonus"] - (int)values["famacrobatics " + c.Familiar]["penalty"];
                        message = c.Name + "'s familiar makes an Acrobatics check!";
                        break;

                    case "stealth":
                        bonus   = (int)values["famstealth " + c.Familiar]["bonus"] - (int)values["feamstealth " + c.Familiar]["penalty"];
                        message = c.Name + "'s familiar makes a Stealth check!";
                        break;

                    default:
                        bonus   = (int)values["famother " + c.Familiar]["bonus"] - (int)values["famother " + c.Familiar]["penalty"];
                        message = c.Name + "'s familiar makes a skill check!";
                        break;
                    }
                    embed.WithThumbnailUrl(c.FamImg);
                }
                else
                {
                    var skill = from sk in sheet["skills"].Children()
                                where ((string)sk["name"]).ToLower().StartsWith(Skill.ToLower()) ||
                                (sk["lore"] != null && ((string)sk["lore"]).ToLower().StartsWith(Skill.ToLower()))
                                orderby sk["name"]
                                select sk;

                    if (skill.Count() == 0)
                    {
                        await ReplyAsync("You have no skill whose name starts with that.");

                        return;
                    }

                    var    s    = skill.FirstOrDefault();
                    string name = (string)s["lore"] ?? (string)s["name"];
                    message = c.Name + " makes " + (name.StartsWithVowel() ? "an " : "a ") + name.Uppercase() + " check!";
                    bonus   = values[name.ToLower()]["bonus"] ?? 0;
                    embed.WithThumbnailUrl(c.ImageUrl);
                }

                var result = Roller.Roll("d20 + " + bonus + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));


                embed.WithTitle(message)
                .WithDescription(result.ParseResult() + "\nTotal = `" + result.Value + "`")
                .WithFooter((c.ValuesLastUpdated.Outdated()? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));

                Random randonGen   = new Random();
                Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                               randonGen.Next(255));
                embed.WithColor(randomColor);

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }

                await ReplyAsync(" ", embed.Build());
            }
        }
Esempio n. 3
0
        public async Task ability(Saves saves, params string[] args)
        {
            Character c;

            if (args.Length >= 1 && args.Contains("-c"))
            {
                c = GetCompanion();
                if (c == null)
                {
                    await ReplyAsync("You have no active companion.");

                    return;
                }
            }
            else
            {
                c = GetCharacter();
                if (c == null)
                {
                    await ReplyAsync("You have no active character.");

                    return;
                }
            }

            for (int i = 0; i < args.Length; i++)
            {
                if (!int.TryParse(args[i], out int a) && args[i].ToLower() != "-c" && args[i].ToLower() != "-f")
                {
                    args[i] = " ";
                }
            }

            string arguments = string.Join(" ", args).Replace("-c", "");

            var sheet = await SheetService.GetFullSheet(c);

            var values = await SheetService.GetValues(c);

            if (values == null || sheet == null)
            {
                var err = new EmbedBuilder()
                          .WithTitle("Click here")
                          .WithUrl("https://character.pf2.tools/?" + c.RemoteId)
                          .WithDescription("Seems like we cannot fetch " + c.Name + "'s values. This is due to the fact values are only updated when you open the sheet in pf2.tools. To fix this, click the link above to generate those values.");
                await ReplyAsync("", err.Build());

                return;
            }

            JToken bonus   = null;
            string message = "";

            switch ((int)saves)
            {
            case 1:
                bonus   = ((int)values["strength"]["values"]).GetModifier();
                message = c.Name + " makes a strength check!";
                break;

            case 2:
                bonus   = ((int)values["dexterity"]["values"]).GetModifier();
                message = c.Name + " makes a dexterity check!";
                break;

            case 3:
                bonus   = ((int)values["constitution"]["values"]).GetModifier();
                message = c.Name + " makes a constitution check!";
                break;

            case 4:
                bonus   = ((int)values["intelligence"]["values"]).GetModifier();
                message = c.Name + " makes a intelligence check!";
                break;

            case 5:
                bonus   = ((int)values["wisdom"]["values"]).GetModifier();
                message = c.Name + " makes a wisdom check!";
                break;

            case 6:
                bonus   = ((int)values["charisma"]["values"]).GetModifier();
                message = c.Name + " makes a charisma check!";
                break;
            }

            var result = Roller.Roll("d20 + " + bonus + arguments);

            var embed = new EmbedBuilder()
                        .WithTitle(message)
                        .WithThumbnailUrl(c.ImageUrl)
                        .WithDescription(result.ParseResult() + "\nTotal = `" + result.Value + "`")
                        .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));

            Random randonGen   = new Random();
            Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                           randonGen.Next(255));

            embed.WithColor(randomColor);

            if (c.Color != null)
            {
                embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
            }

            await ReplyAsync(" ", embed.Build());
        }
 public SheetsController(SheetService service)
 {
     sheetService = service;
 }
Esempio n. 5
0
        public async Task Save(Saves Throw, params string[] args)
        {
            Character c;

            if (args.Length >= 1 && args.Contains("-c"))
            {
                c = GetCompanion();
                if (c == null)
                {
                    await ReplyAsync("You have no active companion.");

                    return;
                }
            }
            else
            {
                c = GetCharacter();
                if (c == null)
                {
                    await ReplyAsync("You have no active character.");

                    return;
                }
            }

            for (int i = 0; i < args.Length; i++)
            {
                if (!int.TryParse(args[i], out int a) && args[i].ToLower() != "-c" && args[i].ToLower() != "-f")
                {
                    args[i] = " ";
                }
            }
            string arguments = string.Join(" ", args).Replace("-c", "");

            var sheet = await SheetService.GetFullSheet(c);

            var values = await SheetService.GetValues(c);

            if (values == null || sheet == null)
            {
                var err = new EmbedBuilder()
                          .WithTitle("Click here")
                          .WithUrl("https://character.pf2.tools/?" + c.RemoteId)
                          .WithDescription("Seems like we cannot fetch " + c.Name + "'s values. This is due to the fact values are only updated when you open the sheet in pf2.tools. To fix this, click the link above to generate those values.");
                await ReplyAsync("", err.Build());

                return;
            }
            var    embed   = new EmbedBuilder();
            int    bonus   = 0;
            string message = "";

            if (args.Contains("-f"))
            {
                if (c.Familiar.NullorEmpty())
                {
                    await ReplyAsync("You have no named familiars.");

                    return;
                }
                switch ((int)Throw)
                {
                case 1:
                    bonus   = (int)values["famfort " + c.Familiar]["bonus"] + (int)values["famfort " + c.Familiar]["penalty"];
                    message = c.Name + "'s familiar makes a fortitude check!";
                    break;

                case 2:
                    bonus   = (int)values["famref " + c.Familiar]["bonus"] + (int)values["famref " + c.Familiar]["penalty"];
                    message = c.Name + "'s familiar makes a reflex check!";
                    break;

                case 3:
                    bonus   = (int)values["famwill " + c.Familiar]["bonus"] + (int)values["famwill " + c.Familiar]["penalty"];
                    message = c.Name + "'s familiar makes a will check!";
                    break;
                }
                arguments = arguments.Replace("-f", "");
                embed.WithThumbnailUrl(c.FamImg);
            }
            else
            {
                switch ((int)Throw)
                {
                case 1:
                    bonus   = (int)values["fortitude"]["bonus"] + (int)values["fortitude"]["penalty"];
                    message = c.Name + " makes a fortitude check!";
                    break;

                case 2:
                    bonus   = (int)values["reflex"]["bonus"] + (int)values["reflex"]["penalty"];
                    message = c.Name + " makes a reflex check!";
                    break;

                case 3:
                    bonus   = (int)values["will"]["bonus"] + (int)values["will"]["penalty"];
                    message = c.Name + " makes a will check!";
                    break;
                }
                embed.WithThumbnailUrl(c.ImageUrl);
            }

            var result = Roller.Roll("d20 + " + bonus + arguments);

            embed.WithTitle(message)
            .WithDescription(result.ParseResult() + "\nTotal = `" + result.Value + "`")
            .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));

            Random randonGen   = new Random();
            Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                           randonGen.Next(255));

            embed.WithColor(randomColor);

            if (c.Color != null)
            {
                embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
            }

            await ReplyAsync(" ", embed.Build());
        }
Esempio n. 6
0
        public async Task Initiative([Remainder] string skill = null)
        {
            var b = GetBattle(Context.Channel.Id);

            if (!b.Active)
            {
                await ReplyAsync("There is no encounter happening on this channel. Start one with `!Encounter Start`");

                return;
            }
            Character c = GetCharacter();

            skill = skill?.ToLower() ?? "";

            if (c == null)
            {
                await ReplyAsync("You have no active character!");

                return;
            }

            string[] Bonuses = new string[0];
            if (BonusRegex.IsMatch(skill))
            {
                Bonuses = BonusRegex.Matches(skill).Select(x => x.Value).ToArray();
                foreach (var bo in Bonuses)
                {
                    skill = skill.Replace(bo, "");
                }
                skill = skill.Trim();
            }

            var embed = new EmbedBuilder()
                        .WithTitle(c.Name + " Rolled initiative!")
                        .WithThumbnailUrl(c.ImageUrl);
            var values = await SheetService.GetValues(c);

            if (skill.NullorEmpty() || skill.ToLower().Equals("perception"))
            {
                var bonus = ((int)values["perception"]["bonus"] - (int)values["perception"]["penalty"]);

                try
                {
                    var results = Roller.Roll("1d20 + " + bonus + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));
                    embed.WithDescription("Perception: " + results.ParseResult() + " = `" + results.Value + "`");

                    if (b.Participants.Any(x => x.Name.ToLower() == c.Name.ToLower()))
                    {
                        var i = b.Participants.FindIndex(x => x.Name.ToLower() == c.Name.ToLower());
                        b.Participants[i] = new Participant()
                        {
                            Initiative = (int)results.Value, Tiebreaker = bonus, Name = c.Name, Player = c.Owner
                        };
                        b.Participants = b.Participants.OrderBy(x => x.Initiative).ThenBy(x => x.Tiebreaker).Reverse().ToList();
                        UpdateBattle(b);
                    }
                    else
                    {
                        b.Participants.Add(new Participant()
                        {
                            Initiative = (int)results.Value, Tiebreaker = bonus, Name = c.Name, Player = c.Owner
                        });
                        b.Participants = b.Participants.OrderBy(x => x.Initiative).ThenBy(x => x.Tiebreaker).Reverse().ToList();
                        UpdateBattle(b);
                    }
                }
                catch
                {
                    await ReplyAsync("Something went wrong when rolling the dice, make sure you only added a bonus/penalty using +X or -X where x is an integer (No fractions or decimals).");

                    return;
                }
            }
            else
            {
                var sheet = await SheetService.GetFullSheet(c);

                var snk = from sk in sheet["skills"].Children()
                          where ((string)sk["name"]).ToLower().StartsWith(skill.ToLower()) ||
                          (sk["lore"] != null && ((string)sk["lore"]).ToLower().StartsWith(skill.ToLower()))
                          orderby sk["name"]
                          select sk;

                if (snk.Count() == 0)
                {
                    await ReplyAsync("You have no skill whose name starts with that.");

                    return;
                }

                var    s     = snk.FirstOrDefault();
                string name  = (string)s["lore"] ?? (string)s["name"];
                var    bonus = (int)values[name.ToLower()]["bonus"] - (int)values[name.ToLower()]["penalty"];

                try
                {
                    var results = Roller.Roll("1d20 + " + bonus + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));
                    embed.WithDescription(name.Uppercase() + ": " + results.ParseResult() + " = `" + results.Value + "`");

                    if (b.Participants.Any(x => x.Name.ToLower() == c.Name.ToLower()))
                    {
                        var i = b.Participants.FindIndex(x => x.Name.ToLower() == c.Name.ToLower());
                        b.Participants[i] = new Participant()
                        {
                            Initiative = (int)results.Value, Tiebreaker = bonus, Name = c.Name, Player = c.Owner
                        };
                        b.Participants = b.Participants.OrderBy(x => x.Initiative).ThenBy(x => x.Tiebreaker).Reverse().ToList();
                        UpdateBattle(b);
                    }
                    else
                    {
                        b.Participants.Add(new Participant()
                        {
                            Initiative = (int)results.Value, Tiebreaker = bonus, Name = c.Name, Player = c.Owner
                        });
                        b.Participants = b.Participants.OrderBy(x => x.Initiative).ThenBy(x => x.Tiebreaker).Reverse().ToList();
                        UpdateBattle(b);
                    }
                }
                catch
                {
                    await ReplyAsync("Something went wrong when rolling the dice, make sure you only added a bonus/penalty using +X or -X where x is an integer (No fractions or decimals).");

                    return;
                }
            }


            Random randonGen   = new Random();
            Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                           randonGen.Next(255));

            embed.WithColor(randomColor);

            if (c.Color != null)
            {
                embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
            }
            await ReplyAsync(" ", embed.Build());
        }
Esempio n. 7
0
 public SheetEndpoint(ILoggerService <SheetEndpoint> logger, SheetService service)
 {
     _logger  = logger;
     _service = service;
 }
 public CharacterController(SheetService sheets)
 {
     sheetService = sheets;
 }
Esempio n. 9
0
 public async Task TestRetrive()
 {
     var wb   = new SheetService();
     var list = wb.GetWorkouts();
 }
Esempio n. 10
0
        public async Task Attack([Remainder] string args = "")
        {
            Character c;

            args = args.ToLower();

            if (args.Contains("-c"))
            {
                c    = GetCompanion();
                args = args.Replace("-c", "").Trim();
                if (c == null)
                {
                    await ReplyAsync("You have no active companion.");

                    return;
                }
            }
            else
            {
                c = GetCharacter();
                if (c == null)
                {
                    await ReplyAsync("You have no active character.");

                    return;
                }
            }
            if (args.NullorEmpty())
            {
                var strikes = await SheetService.Get(c, "strikes");

                var embed = new EmbedBuilder()
                            .WithTitle(c.Name + "'s strikes")
                            .WithThumbnailUrl(c.ImageUrl);

                if (strikes.Count() == 0)
                {
                    await ReplyAsync(c.Name + " has no strikes.");

                    return;
                }

                var sb = new StringBuilder();
                foreach (var s in strikes)
                {
                    string act = Icons.Actions["1"];
                    if (!((string)s["actions"]).NullorEmpty())
                    {
                        if (Icons.Actions.TryGetValue((string)s["actions"], out string ic))
                        {
                            act = ic;
                        }
                        else
                        {
                            act = "[" + s["actions"] + "]";
                        }
                    }
                    sb.AppendLine(Icons.Strike[(string)s["attack"]] + " " + (((string)s["name"]).NullorEmpty() ? "Unnamed Strike" : (string)s["name"]) + " " + act);
                }
                embed.WithDescription(sb.ToString());

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }
                else
                {
                    Random randonGen   = new Random();
                    Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                                   randonGen.Next(255));
                    embed.WithColor(randomColor);
                }

                await ReplyAsync("", embed.Build());

                return;
            }
            else
            {
                string[] Bonuses = new string[0];

                if (BonusRegex.IsMatch(args))
                {
                    Bonuses = BonusRegex.Matches(args).Select(x => x.Value).ToArray();
                    foreach (var b in Bonuses)
                    {
                        args = args.Replace(b, "");
                    }
                    args = args.Trim();
                }

                List <string> Toggles = new List <string>();
                if (ToggleableRegex.IsMatch(args))
                {
                    MatchCollection RawToggles = ToggleableRegex.Matches(args);
                    foreach (Match m in RawToggles)
                    {
                        args = args.Replace(m.Value, "");
                        Toggles.Add(m.Groups[2].Value.Trim());
                    }
                    args = args.Trim();
                }

                var Jstrikes = await SheetService.Get(c, "strikes");

                var values = await SheetService.GetValues(c);

                if (values == null || Jstrikes == null)
                {
                    var err = new EmbedBuilder()
                              .WithTitle("Click here")
                              .WithUrl("https://character.pf2.tools/?" + c.RemoteId)
                              .WithDescription("Seems like we cannot fetch " + c.Name + "'s values. This is due to the fact values are only updated when you open the sheet in pf2.tools. To fix this, click the link above to generate those values.");
                    await ReplyAsync("", err.Build());

                    return;
                }

                var strikes = from sk in Jstrikes
                              where ((string)sk["name"]).ToLower().StartsWith(args)
                              orderby sk["name"]
                              select sk;

                if (strikes.Count() == 0)
                {
                    await ReplyAsync("You have no strikes whose name starts with '" + args + "'.");

                    return;
                }
                string strikename = "";
                var    s          = strikes.FirstOrDefault();
                var    embed      = new EmbedBuilder()
                                    .WithTitle(c.Name + " strikes with a " + (((string)s["name"]).NullorEmpty() ? "Unnamed Strike" : (string)s["name"]) + "!")
                                    .WithThumbnailUrl(c.ImageUrl);

                if (c.Color != null)
                {
                    embed.WithColor(new Color(c.Color[0], c.Color[1], c.Color[2]));
                }
                else
                {
                    Random randonGen   = new Random();
                    Color  randomColor = new Color(randonGen.Next(255), randonGen.Next(255),
                                                   randonGen.Next(255));
                    embed.WithColor(randomColor);
                }

                await ReplyAsync("Rolling...");

                string hit         = "";
                string dmg         = "";
                string penalties   = "";
                string damagebonus = "";
                string dmgtype     = "Untyped";

                if ((string)s["attack"] == "spell")
                {
                    JToken cl = null;

                    var classes = await SheetService.Get(c, "classes");

                    var traditions = await SheetService.Get(c, "traditions");

                    classes.Merge(traditions);
                    if (classes == null || classes.Count == 0)
                    {
                        await ReplyAsync("You don't seem to have a class. Without one you can't make spell attacks.");

                        return;
                    }
                    if (((string)s["class"]).NullorEmpty())
                    {
                        cl = classes.FirstOrDefault();
                    }
                    else
                    {
                        cl = classes.First(x => (string)x["id"] == (string)s["class"]);
                    }



                    if (!values.ContainsKey(((string)cl["name"]).ToLower()))
                    {
                        await ReplyAsync("Sorry! It seems we cannot retrieve the data for this strike! This issue is outside of the bot's control and will likely be solved later.");

                        return;
                    }

                    hit = (string)values[((string)cl["name"]).ToLower()]["bonus"];

                    int dc = int.Parse(hit ?? "0") + 10;


                    string summary = "";



                    if (!((string)s["spell"]).NullorEmpty())
                    {
                        var spells = await SheetService.Get(c, "spells");

                        var sp = spells.First(x => (string)x["id"] == (string)s["spell"]);
                        if (!((string)sp["body"]).NullorEmpty())
                        {
                            var sb = new StringBuilder();
                            sb.AppendLine((string)sp["body"]);
                            if (sb.Length <= 1024)
                            {
                                embed.AddField("Spell Description", sb.ToString());
                            }
                            else
                            {
                                var segments = sb.ToString().Split(1000).ToArray();
                                for (int i = 0; i < segments.Length; i++)
                                {
                                    embed.AddField("Spell Description (" + (i + 1) + "/" + (segments.Length) + ")", segments[i]);
                                }
                            }
                        }
                        if (!((string)sp["attackroll"]).NullorEmpty() && (bool)sp["attackroll"])
                        {
                            var result = Roller.Roll("d20 + " + hit + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));

                            summary += "**Spell Attack roll**: " + result.ParseResult() + " = `" + result.Value + "`";
                        }
                        if (!((string)sp["savingthrow"]).NullorEmpty())
                        {
                            summary += "\n**Saving Throw**: " + sp["savingthrow"] + " (DC: `" + dc + "`)";
                        }
                        embed.WithTitle(c.Name + " casts " + (sp["name"] ?? "Unnamed Spell") + "!");
                    }

                    dmg = (string)s["extradamage"];
                    if (!dmg.NullorEmpty() && AttributeRegex.IsMatch(dmg))
                    {
                        dmg = await ParseValues(dmg, c, values);
                    }

                    if (DmgRegex.IsMatch(dmg))
                    {
                        foreach (var m in DmgRegex.Matches(dmg).ToList())
                        {
                            try
                            {
                                RollResult dmgroll = Roller.Roll(m.Groups[2].Value.ToLower());
                                summary += "\n**" + m.Groups[1].Value + " damage**: " + dmgroll.ParseResult() + " = `" + dmgroll.Value + "` ";
                            }
                            catch
                            {
                                continue;
                            }
                        }
                    }

                    JToken details = s["details"];

                    if (details != null && details.HasValues)
                    {
                        foreach (var value in details.Where(x => (bool)x["active"] == true || Toggles.Contains(((string)x["name"]).ToLower())))
                        {
                            try
                            {
                                RollResult Eresult = Roller.Roll(((string)value["comment"]).ToLower());
                                summary += "\n**" + (((string)value["name"]).NullorEmpty() ? "Extra Damage (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") " : (string)value["name"] + " (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") ") + "**: " + Eresult.ParseResult() + " = `" + Eresult.Value + "`";
                            }
                            catch
                            {
                                continue;
                            }
                        }
                    }

                    embed.WithDescription(summary)
                    .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));



                    await ReplyAsync(" ", embed.Build());
                }
                else if ((string)s["attack"] == "custom")
                {
                    string summary = "";
                    if (!((string)s["weaponcustom"]).NullorEmpty())
                    {
                        embed.WithTitle(c.Name + " strikes with a " + s["weaponcustom"]);
                    }
                    if (!((string)s["damagetypecustom"]).NullorEmpty())
                    {
                        dmgtype = (string)s["damagetypecustom"];
                    }
                    if (!((string)s["traitscustom"]).NullorEmpty())
                    {
                        string[] traits = ((string)s["traitscustom"]).Split(',');
                        foreach (var x in traits)
                        {
                            summary += "[" + x.ToUpper() + "] ";
                        }
                        summary += "\n";
                    }
                    int range = 0;
                    if (!((string)s["range"]).NullorEmpty())
                    {
                        range += int.Parse((string)s["range"]);
                    }
                    if (!((string)s["modrange"]).NullorEmpty())
                    {
                        range += int.Parse((string)s["modrange"]);
                    }
                    summary += "**Range** " + range + "ft.\n";


                    if ((string)s["attackcustom"] == "ranged" || ((string)s["attack"]).NullorEmpty())
                    {
                        hit       = (string)values["ranged " + (string)s["name"]]["bonus"];
                        penalties = (string)values["ranged " + (string)s["name"]]["penalty"];
                        var result = Roller.Roll("d20 + " + hit + (penalties != "0" ? "-" + penalties : "") + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));

                        summary += "**Attack roll**: " + result.ParseResult() + " = `" + result.Value + "`";
                    }
                    else if ((string)s["attackcustom"] == "melee" || ((string)s["attack"]).NullorEmpty())
                    {
                        hit       = (string)values["melee " + (string)s["name"]]["bonus"];
                        penalties = (string)values["melee " + (string)s["name"]]["penalty"];
                        var result = Roller.Roll("d20 + " + hit + (penalties != "0" ? "-" + penalties : "") + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));

                        summary += "**Attack roll**: " + result.ParseResult() + " = `" + result.Value + "`";
                    }

                    damagebonus = (string)values["damage " + (string)s["name"]]["value"];

                    dmg = (string)values["damagedice " + (string)s["name"]]["value"] + GetDie((int)values["damagedie " + (string)s["name"]]["value"]);


                    if (!dmg.NullorEmpty())
                    {
                        try
                        {
                            RollResult result2 = Roller.Roll(dmg + "+" + damagebonus);
                            summary += "\n**" + dmgtype.Uppercase() + " damage**: " + result2.ParseResult() + " = `" + result2.Value + "` ";

                            if (!((string)s["extradamage"]).NullorEmpty())
                            {
                                string extradmg = (string)s["extradamage"];
                                if (!extradmg.NullorEmpty() && AttributeRegex.IsMatch(extradmg))
                                {
                                    extradmg = await ParseValues(extradmg, c, values);
                                }

                                if (DmgRegex.IsMatch(extradmg))
                                {
                                    foreach (var m in DmgRegex.Matches(extradmg).ToList())
                                    {
                                        try
                                        {
                                            RollResult dmgroll = Roller.Roll(m.Groups[2].Value);
                                            summary += "\n**" + m.Groups[1].Value + " damage**: " + dmgroll.ParseResult() + " = `" + dmgroll.Value + "` ";
                                        }
                                        catch
                                        {
                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                        catch
                        {
                            await ReplyAsync("It seems like this strike doesn't have a valid dice roll on its damage or additional damage fields. If this is a spell make sure you have a valid dice expression on the damage fields.");

                            return;
                        }
                    }
                    JToken details = s["details"];

                    if (details != null && details.HasValues)
                    {
                        foreach (var value in details.Where(x => (bool)x["active"] == true || Toggles.Contains(((string)x["name"]).ToLower())))
                        {
                            try
                            {
                                RollResult Eresult = Roller.Roll((string)value["comment"]);
                                summary += "\n**" + (((string)value["name"]).NullorEmpty() ? "Extra Damage (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") " : (string)value["name"] + " (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") ") + "**: " + Eresult.ParseResult() + " = `" + Eresult.Value + "`";
                            }
                            catch
                            {
                                continue;
                            }
                        }
                    }

                    embed.WithDescription(summary)
                    .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));



                    await ReplyAsync(" ", embed.Build());
                }
                else
                {
                    string summary = "";
                    if (!((string)s["weapon"]).NullorEmpty())
                    {
                        var items = await SheetService.Get(c, "items");

                        var i = items.First(x => (string)x["id"] == (string)s["weapon"]);
                        dmgtype = (string)i["damagetype"] ?? "Untyped";

                        if (!((string)i["traits"]).NullorEmpty())
                        {
                            string[] traits = ((string)i["traits"]).Split(',');
                            foreach (var x in traits)
                            {
                                summary += "[" + x.ToUpper() + "] ";
                            }
                            summary += "\n";
                        }


                        int range = 0;
                        if (!((string)i["range"]).NullorEmpty() && int.TryParse((string)i["range"], out int r))
                        {
                            range += r;
                        }
                        if (!((string)s["modrange"]).NullorEmpty() && int.TryParse((string)s["modrange"], out int r2))
                        {
                            range += r2;
                        }
                        summary += "**Range**: " + range + "ft.\n";

                        if ((string)i["attack"] == "melee")
                        {
                            hit       = (string)values["melee " + (string)s["name"]]["bonus"];
                            penalties = (string)values["melee " + (string)s["name"]]["penalty"];
                        }
                        else if ((string)i["attack"] == "ranged")
                        {
                            hit       = (string)values["ranged " + (string)s["name"]]["bonus"];
                            penalties = (string)values["ranged " + (string)s["name"]]["penalty"];
                        }
                        if (!((string)i["name"]).NullorEmpty())
                        {
                            embed.WithTitle(c.Name + " strikes with a " + (string)i["name"] + "!");
                        }
                    }

                    if ((string)s["attack"] == "melee")
                    {
                        hit       = (string)values["melee " + (string)s["name"]]["bonus"];
                        penalties = (string)values["melee " + (string)s["name"]]["penalty"];
                    }
                    else if ((string)s["attack"] == "ranged")
                    {
                        hit       = (string)values["ranged " + (string)s["name"]]["bonus"];
                        penalties = (string)values["ranged " + (string)s["name"]]["penalty"];
                    }

                    damagebonus = (string)values["damage " + (string)s["name"]]["value"];

                    dmg = (string)values["damagedice " + (string)s["name"]]["value"] + GetDie((int)values["damagedie " + (string)s["name"]]["value"]);



                    var result = Roller.Roll("d20 + " + hit + (penalties != "0"? "-" + penalties:"") + (Bonuses.Length > 0 ? string.Join(" ", Bonuses) : ""));

                    summary += "**Attack roll**: " + result.ParseResult() + " = `" + result.Value + "`";

                    if (!dmg.NullorEmpty())
                    {
                        try
                        {
                            RollResult result2 = Roller.Roll(dmg + "+" + damagebonus);
                            summary += "\n**" + dmgtype.Uppercase() + " damage**: " + result2.ParseResult() + " = `" + result2.Value + "` ";

                            if (!((string)s["extradamage"]).NullorEmpty())
                            {
                                string extradmg = (string)s["extradamage"];
                                if (!extradmg.NullorEmpty() && AttributeRegex.IsMatch(extradmg))
                                {
                                    extradmg = await ParseValues(extradmg, c, values);
                                }

                                if (DmgRegex.IsMatch(extradmg))
                                {
                                    foreach (var m in DmgRegex.Matches(extradmg).ToList())
                                    {
                                        try
                                        {
                                            RollResult dmgroll = Roller.Roll(m.Groups[2].Value);
                                            summary += "\n**" + m.Groups[1].Value + " damage**: " + dmgroll.ParseResult() + " = `" + dmgroll.Value + "` ";
                                        }
                                        catch
                                        {
                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                        catch
                        {
                            await ReplyAsync("It seems like this strike doesn't have a valid dice roll on its damage or additional damage fields. If this is a spell make sure you have a valid dice expression on the damage fields.");

                            return;
                        }
                    }
                    JToken details = s["details"];

                    if (details != null && details.HasValues)
                    {
                        foreach (var value in details.Where(x => (bool)x["active"] == true || Toggles.Contains(((string)x["name"]).ToLower())))
                        {
                            try
                            {
                                RollResult Eresult = Roller.Roll((string)value["comment"]);
                                summary += "\n**" + (((string)value["name"]).NullorEmpty() ? "Extra Damage (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") " : (string)value["name"] + " (" + (((string)value["type"]).NullorEmpty() ? "Untyped" : (string)value["type"]) + ") ") + "**: " + Eresult.ParseResult() + " = `" + Eresult.Value + "`";
                            }
                            catch
                            {
                                continue;
                            }
                        }
                    }

                    embed.WithDescription(summary)
                    .WithFooter((c.ValuesLastUpdated.Outdated() ? "⚠️ Couldn't retrieve updated values. Roll might not be accurate" : DateTime.Now.ToString()));



                    await ReplyAsync(" ", embed.Build());
                }
            }
        }