Пример #1
0
        private Expr Dice()
        {
            Expr expr = Unary();

            // Match dice
            while (Match(TokenType.Identifier))
            {
                Token id = Previous();
                if ("d".Equals(id.Lexeme) || "D".Equals(id.Lexeme))
                {
                    Expr faces = Call(false);

                    // Check for modifiers
                    if (Match(TokenType.Identifier, TokenType.Bang, TokenType.BangBang))
                    {
                        GetDiceModifiers(faces, out var mod, out var modOp, out var modValue);
                        expr = new Expr.Dice(expr, faces, GetLabel(), mod, modOp, modValue);
                    }
                    else
                    {
                        expr = new Expr.Dice(expr, faces, GetLabel());
                    }
                }
            }

            return(expr);
        }
Пример #2
0
        public string VisitDiceExpr(Expr.Dice expr)
        {
            var label = string.IsNullOrEmpty(expr.Label) ? "" : $" [{expr.Label}]";

            if (expr.Mod == Expr.Dice.DiceMod.None)
            {
                return($"(d {expr.Num.Accept(this)} {expr.Faces.Accept(this)}{label})");
            }

            return($"(d {expr.Num.Accept(this)} {expr.Faces.Accept(this)} {expr.Mod} {expr.ModOp} {expr.ModValue.Accept(this)}{label})");
        }
Пример #3
0
        public string VisitDiceExpr(Expr.Dice dice)
        {
            var s = dice.Results.Aggregate("(", (s1, r) => s1 + (s1 == "(" ? $"{r}" : $" + {r}"));

            s += ")";
            if (dice.Mod != Expr.Dice.DiceMod.None)
            {
                s += $"{DiceModToString(dice.Mod)}{DiceModOpToString(dice.ModOp)}{dice.ModValue.Accept(this)}";
            }

            if (!string.IsNullOrEmpty(dice.Label))
            {
                s += $"[{dice.Label}]";
            }
            return(s);
        }
Пример #4
0
        public object VisitDiceExpr(Expr.Dice dice)
        {
            if (dice.Results.Count > 0)
            {
                // dice were already rolled.
                return(dice.Result);
            }

            var oNum = Evaluate(dice.Num);

            if (!(oNum is double))
            {
                throw new InterpreterError($"Dice number must be a number but is a {oNum.GetType()}!");
            }
            var num = (int)Math.Round((double)oNum);

            var oFaces = Evaluate(dice.Faces);

            if (!(oFaces is double))
            {
                throw new InterpreterError($"Dice faces must be a number but is a {oFaces.GetType()}!");
            }
            var faces = (int)Math.Round((double)oFaces);

            if (dice.Mod != Expr.Dice.DiceMod.None)
            {
                var oModValue = Evaluate(dice.ModValue);
                if (!(oModValue is double))
                {
                    throw new InterpreterError($"Dice mod value must be a number but is a {oModValue.GetType()}!");
                }

                var modValue = (double)oModValue;

                switch (dice.Mod)
                {
                case Expr.Dice.DiceMod.CountSuccesses:
                {
                    for (var i = 0; i < num; ++i)
                    {
                        dice.Results.Add(RollDie(faces));
                    }

                    switch (dice.ModOp)
                    {
                    case Expr.Dice.ModOperator.Equal:
                        return(dice.Result = dice.Results.Count(d => Math.Abs(d - modValue) < 0.00001));

                    case Expr.Dice.ModOperator.Less:
                        return(dice.Result = dice.Results.Count(d => d < modValue));

                    case Expr.Dice.ModOperator.LessEqual:
                        return(dice.Result = dice.Results.Count(d => d <= modValue));

                    case Expr.Dice.ModOperator.Greater:
                        return(dice.Result = dice.Results.Count(d => d > modValue));

                    case Expr.Dice.ModOperator.GreaterEqual:
                        return(dice.Result = dice.Results.Count(d => d >= modValue));

                    default:
                        throw new InterpreterError($"Unknown dice mod operator: '{dice.ModOp}'");
                    }
                }

                case Expr.Dice.DiceMod.MarginOfSuccess:
                {
                    var result = 0.0d;
                    for (var i = 0; i < num; ++i)
                    {
                        var tmp = RollDie(faces);
                        dice.Results.Add(tmp);
                        result += tmp;
                    }

                    switch (dice.ModOp)
                    {
                    case Expr.Dice.ModOperator.Equal:
                    case Expr.Dice.ModOperator.Greater:
                    case Expr.Dice.ModOperator.GreaterEqual:
                        result -= modValue;
                        break;

                    case Expr.Dice.ModOperator.Less:
                    case Expr.Dice.ModOperator.LessEqual:
                        result = modValue - result;
                        break;

                    default:
                        throw new InterpreterError($"Unknown dice mod operator: '{dice.ModOp}'");
                    }

                    return(dice.Result = result);
                }

                case Expr.Dice.DiceMod.ReRoll:
                {
                    var result = 0.0d;
                    for (var i = 0; i < num; ++i)
                    {
                        var tmp = RollDie(faces);
                        switch (dice.ModOp)
                        {
                        case Expr.Dice.ModOperator.Equal:
                            while (Math.Abs(tmp - modValue) < 0.00001)
                            {
                                tmp = RollDie(faces);
                            }
                            break;

                        case Expr.Dice.ModOperator.Greater:
                            while (tmp > modValue)
                            {
                                tmp = RollDie(faces);
                            }
                            break;

                        case Expr.Dice.ModOperator.GreaterEqual:
                            while (tmp >= modValue)
                            {
                                tmp = RollDie(faces);
                            }
                            break;

                        case Expr.Dice.ModOperator.Less:
                            while (tmp < modValue)
                            {
                                tmp = RollDie(faces);
                            }
                            break;

                        case Expr.Dice.ModOperator.LessEqual:
                            while (tmp <= modValue)
                            {
                                tmp = RollDie(faces);
                            }
                            break;
                        }

                        dice.Results.Add(tmp);
                        result += tmp;
                    }

                    return(dice.Result = result);
                }

                case Expr.Dice.DiceMod.Explode:
                {
                    var result = 0.0d;
                    for (var i = 0; i < num; ++i)
                    {
                        var tmp = RollDie(faces);
                        switch (dice.ModOp)
                        {
                        case Expr.Dice.ModOperator.Equal:
                            if (Math.Abs(tmp - modValue) < 0.00001)
                            {
                                num++;
                            }

                            break;

                        case Expr.Dice.ModOperator.Greater:
                            if (tmp > modValue)
                            {
                                num++;
                            }

                            break;

                        case Expr.Dice.ModOperator.GreaterEqual:
                            if (tmp >= modValue)
                            {
                                num++;
                            }

                            break;

                        case Expr.Dice.ModOperator.Less:
                            if (tmp < modValue)
                            {
                                num++;
                            }

                            break;

                        case Expr.Dice.ModOperator.LessEqual:
                            if (tmp <= modValue)
                            {
                                num++;
                            }

                            break;
                        }

                        dice.Results.Add(tmp);
                        result += tmp;
                    }

                    return(dice.Result = result);
                }

                case Expr.Dice.DiceMod.CompoundExplode:
                {
                    var result = 0.0d;
                    for (var i = 0; i < num; ++i)
                    {
                        var compundSum = 0.0d;
                        var tmp        = RollDie(faces);
                        compundSum += tmp;
                        switch (dice.ModOp)
                        {
                        case Expr.Dice.ModOperator.Equal:
                            while (Math.Abs(tmp - modValue) < 0.00001)
                            {
                                tmp         = RollDie(faces);
                                compundSum += tmp;
                            }
                            break;

                        case Expr.Dice.ModOperator.Greater:
                            while (tmp > modValue)
                            {
                                tmp         = RollDie(faces);
                                compundSum += tmp;
                            }
                            break;

                        case Expr.Dice.ModOperator.GreaterEqual:
                            while (tmp >= modValue)
                            {
                                tmp         = RollDie(faces);
                                compundSum += tmp;
                            }
                            break;

                        case Expr.Dice.ModOperator.Less:
                            while (tmp < modValue)
                            {
                                tmp         = RollDie(faces);
                                compundSum += tmp;
                            }
                            break;

                        case Expr.Dice.ModOperator.LessEqual:
                            while (tmp <= modValue)
                            {
                                tmp         = RollDie(faces);
                                compundSum += tmp;
                            }
                            break;
                        }

                        dice.Results.Add(compundSum);
                        result += compundSum;
                    }

                    return(dice.Result = result);
                }

                case Expr.Dice.DiceMod.KeepHighest:
                {
                    for (var i = 0; i < num; ++i)
                    {
                        dice.Results.Add(RollDie(faces));
                    }
                    return(dice.Result = dice.Results.OrderByDescending(d => d).Take(Convert.ToInt32(modValue)).Sum());
                }

                case Expr.Dice.DiceMod.KeepLowest:
                {
                    for (var i = 0; i < num; ++i)
                    {
                        dice.Results.Add(RollDie(faces));
                    }
                    return(dice.Result = dice.Results.OrderBy(d => d).Take(Convert.ToInt32(modValue)).Sum());
                }

                case Expr.Dice.DiceMod.DropHighest:
                {
                    for (var i = 0; i < num; ++i)
                    {
                        dice.Results.Add(RollDie(faces));
                    }
                    return(dice.Result = dice.Results.OrderByDescending(d => d).Skip(Convert.ToInt32(modValue)).Sum());
                }

                case Expr.Dice.DiceMod.DropLowest:
                {
                    for (var i = 0; i < num; ++i)
                    {
                        dice.Results.Add(RollDie(faces));
                    }
                    return(dice.Result = dice.Results.OrderBy(d => d).Skip(Convert.ToInt32(modValue)).Sum());
                }

                default:
                    throw new InterpreterError($"Unknown dice modifier '{dice.Mod}'");
                }
            }

            var rollingSum = 0;

            for (var i = 0; i < num; ++i)
            {
                var tmp = RollDie(faces);
                dice.Results.Add(tmp);
                rollingSum += tmp;
            }

            return(dice.Result = rollingSum);
        }