private static CalcValue CompUntil(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context) { int limit = int.MaxValue; DiceContext dc = null; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } CalcNumber numLeft = null; CalcList lstLeft = null; bool list = false; CalcNumber numRight = (CalcNumber)right; // Now figure out how many sides each die has... int sides = 0; // (Are we using a list or a number for the sides?) if (left is CalcNumber) { numLeft = (CalcNumber)left; sides = (int)(numLeft.Value); } else if (left is CalcList) { lstLeft = (CalcList)left; sides = lstLeft.Count; list = true; } // ... and ensure it's at least one. if (sides < 1) { throw new CLException("Dice must have at least one side."); } // Now we can roll the dice! List <CalcValue> lstRet = new List <CalcValue>(); Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } CalcList output = null; Type actual = null; for (int i = 0; i < limit; i++) { // First determine the value int choice = rand.Next(sides); CalcNumber value = null; if (list) { CalcValue val = lstLeft[choice]; if (val is CalcList valList) { value = new DiceDie(valList.Sum(), lstLeft); } else if (val is CalcNumber valNum) { value = new DiceDie(valNum.Value, lstLeft); } } else { value = new DiceDie(choice + 1, new CalcNumber(sides)); } // See if it satisfies the comparison if (comp.CompareFunction(value.Value, numRight.Value)) { vars["_u"] = value; output = new CalcList(lstRet.ToArray()); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output)); history.Add(($"Killed above roll:", ValToList(value))); } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += i + 1; } return(output); } else { lstRet.Add(value); } } vars["_u"] = new CalcNumber(0); output = new CalcList(lstRet.ToArray()); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output)); } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += limit; } return(output); }
private static CalcValue CompRerolls(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context, bool keep = false, bool recurse = false) { CalcList lstLeft = (CalcList)left; CalcNumber numRight = (CalcNumber)right; List <CalcValue> output = new List <CalcValue>(); DiceContext dc = null; int limit = 0; int limitUsed = 0; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } // Go through the list foreach (CalcValue val in lstLeft) { decimal value; if (val is CalcNumber valNum) { value = valNum.Value; } else if (val is CalcList valList) { value = valList.Sum(); } else { throw new CLException("Re-rolls only work with numeric values."); } // If it's a value we need to re-roll if (comp.CompareFunction(value, numRight.Value)) { // Keep the original value ("x" and "xr" operators) if (keep) { output.Add(val); } // Now make another value (or recurse) bool redo = true; // Now figure out how many sides each die has... int sides = 0; bool list = false; CalcValue dSides; CalcList lstSides = null; if (val is DiceDie die) { dSides = die.Sides; // (Are we using a list or a number for the sides?) if (dSides is CalcNumber nSides) { sides = (int)(nSides.Value); } else if (dSides is CalcList lSides) { lstSides = lSides; sides = lSides.Count; list = true; } } else { decimal valValue = 0; if (val is CalcNumber nVal) { valValue = nVal.Value; } else if (val is CalcList lVal) { valValue = lVal.Sum(); } else { throw new CLException("Reroll only works with numeric values."); } if (valValue < 0) { valValue *= -1; } sides = (valValue <= 6) ? 6 : (valValue <= 20) ? 20 : (valValue <= 100) ? 100 : (valValue <= 1000) ? 1000 : (valValue <= 10000) ? 10000 : (valValue <= 100000) ? 100000 : (valValue <= 1000000) ? 1000000 : (valValue <= 10000000) ? 10000000 : (valValue <= 100000000) ? 100000000 : (valValue <= 1000000000) ? 1000000000 : 2147483647; dSides = new CalcNumber(sides); } // Now we can roll the dice! Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } while (redo && limitUsed < limit) { int choice = rand.Next(sides); limitUsed++; decimal cValue = 0; if (list) { CalcValue cVal = lstSides[choice]; if (cVal is CalcNumber cNum) { cValue = cNum.Value; output.Add(new DiceDie(cValue, lstSides)); } else if (cVal is CalcList cList) { cValue = cList.Sum(); output.Add(new DiceDie(cValue, lstSides)); } } else { cValue = choice + 1; output.Add(new DiceDie(cValue, new CalcNumber(sides))); } // recursion? if (recurse) { redo = comp.CompareFunction(cValue, numRight.Value); } else { redo = false; } } } else { // The reroll comparison wasn't satisfied output.Add(val); } } return(new CalcList(output.ToArray())); }
private static CalcValue BinDice(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { int limit = int.MaxValue; DiceContext dc = null; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } CalcNumber numLeft = (CalcNumber)left; CalcNumber numRight = null; CalcList lstRight = null; bool list = false; // Now figure out how many dice to roll... int count = (int)(numLeft.Value); // ... and whether or not it's within limits (including the limitation that it must be positive) if (count <= 0) { throw new CLException("The number of dice to roll must be positive."); } else if (count > limit) { count = limit; } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += count; } // Now figure out how many sides each die has... int sides = 0; // (Are we using a list or a number for the sides?) if (right is CalcNumber) { numRight = (CalcNumber)right; sides = (int)(numRight.Value); } else if (right is CalcList) { lstRight = (CalcList)right; sides = lstRight.Count; list = true; } // ... and ensure it's at least one. if (sides < 1) { throw new CLException("Dice must have at least one side."); } // Now we can roll the dice! CalcValue[] ret = new CalcValue[count]; Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } for (int i = 0; i < count; i++) { int choice = rand.Next(sides); if (list) { CalcValue val = lstRight[choice]; if (val is CalcNumber valNum) { ret[i] = new DiceDie(valNum.Value, lstRight); } else if (val is CalcList valList) { ret[i] = new DiceDie(valList.Sum(), lstRight); } else { throw new CLException("Dice must be numeric values."); // maybe I'll change this one day } } else { ret[i] = new DiceDie(choice + 1, new CalcNumber(sides)); } } CalcList output = new CalcList(ret); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out Type actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}d{right.ToCode()}", output)); } return(output); }