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); }
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})"); }
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); }
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); }