move the generic roll result code into a common place

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
2026-05-17 12:28:50 -05:00
parent c41a2211d0
commit c14afe478a
3 changed files with 99 additions and 99 deletions
-1
View File
@@ -1,7 +1,6 @@
"""Roll dice when asked, intended for RPGs."""
import logging
import random
import re
from django.conf import settings
from irc.client import NickMask
+97
View File
@@ -126,6 +126,103 @@ def cypher_result(difficulty, modifier, is_attack, stat, comment, ircify=False):
return f"{comment} {result_str} {detail_str}"
def generic_roll(keep, dice, size):
"""Takes the parsed dice string for a single roll (eg 3/4d20) and performs
the actual roll. Returns a string representing the result.
"""
a = list(range(dice))
for i in range(dice):
a[i] = random.randint(1, size)
if keep != dice:
b = sorted(a, reverse=True)
b = b[0:keep]
else:
b = a
total = sum(b)
outstr = "[" + ",".join(str(i) for i in a) + "]"
return (total, outstr)
def generic_result(trials, mods, comment, ircify):
"""Processes rolls coming from the parser.
This generates the inputs for the generic_roll() command, and returns
the full string representing the whole current dice string (the part
up to a semicolon or end of line).
"""
rolls = mods[0][0][1] if mods[0][0][1] else 1
if trials:
assert trials <= 30, "Too many rolls (max: 30)."
assert rolls <= 50, "Too many dice (max: 50) in roll."
output = ""
repeat = 1
if trials is not None:
repeat = trials
for i in range(repeat):
mode = 1
total = 0
curr_str = ""
if i > 0:
output += ", "
for m in mods:
keep = 0
dice = 1
res = 0
# if m is a tuple, then it is a die roll
# m[0] = (keep, num dice)
# m[1] = num faces on the die
if type(m) == tuple:
if m[0] is not None:
if m[0][0] is not None:
keep = m[0][0]
dice = m[0][1]
size = m[1]
if keep > dice or keep == 0:
keep = dice
if size < 1:
output = "# of sides for die is incorrect: %d" % size
return output
if dice < 1:
output = "# of dice is incorrect: %d" % dice
return output
res = generic_roll(keep, dice, size)
curr_str += "%d%s" % (res[0], res[1])
res = res[0]
elif m == "+":
mode = 1
curr_str += "+"
elif m == "-":
mode = -1
curr_str += "-"
else:
res = m
curr_str += str(m)
total += mode * res
if repeat == 1:
if comment is not None:
if ircify:
output = "%d %s 14(%s)" % (total, comment.strip(), curr_str)
else:
output = "%d %s (%s)" % (total, comment.strip(), curr_str)
else:
if ircify:
output = "%d 14(%s)" % (total, curr_str)
else:
output = "%d (%s)" % (total, curr_str)
else:
if ircify:
output += "%d 14(%s)" % (total, curr_str)
else:
output += "%d (%s)" % (total, curr_str)
if i == repeat - 1:
if comment is not None:
output += " (%s)" % (comment.strip())
return output
def reaction_roll():
"""Make a reaction roll, which gives some oracle-like randomness to uncertain situations (for solo play or similar).
+2 -98
View File
@@ -1,6 +1,5 @@
"""Dice rollers used by the views, bots, etc."""
import logging
import random
import re
import ply.lex as lex
@@ -52,101 +51,6 @@ class DiceRoller(object):
output = ""
def roll_dice(self, keep, dice, size):
"""Takes the parsed dice string for a single roll (eg 3/4d20) and performs
the actual roll. Returns a string representing the result.
"""
a = list(range(dice))
for i in range(dice):
a[i] = random.randint(1, size)
if keep != dice:
b = sorted(a, reverse=True)
b = b[0:keep]
else:
b = a
total = sum(b)
outstr = "[" + ",".join(str(i) for i in a) + "]"
return (total, outstr)
def process_roll(self, trials, mods, comment):
"""Processes rolls coming from the parser.
This generates the inputs for the roll_dice() command, and returns
the full string representing the whole current dice string (the part
up to a semicolon or end of line).
"""
rolls = mods[0][0][1] if mods[0][0][1] else 1
if trials:
assert trials <= 30, "Too many rolls (max: 30)."
assert rolls <= 50, "Too many dice (max: 50) in roll."
output = ""
repeat = 1
if trials is not None:
repeat = trials
for i in range(repeat):
mode = 1
total = 0
curr_str = ""
if i > 0:
output += ", "
for m in mods:
keep = 0
dice = 1
res = 0
# if m is a tuple, then it is a die roll
# m[0] = (keep, num dice)
# m[1] = num faces on the die
if type(m) == tuple:
if m[0] is not None:
if m[0][0] is not None:
keep = m[0][0]
dice = m[0][1]
size = m[1]
if keep > dice or keep == 0:
keep = dice
if size < 1:
output = "# of sides for die is incorrect: %d" % size
return output
if dice < 1:
output = "# of dice is incorrect: %d" % dice
return output
res = self.roll_dice(keep, dice, size)
curr_str += "%d%s" % (res[0], res[1])
res = res[0]
elif m == "+":
mode = 1
curr_str += "+"
elif m == "-":
mode = -1
curr_str += "-"
else:
res = m
curr_str += str(m)
total += mode * res
if repeat == 1:
if comment is not None:
if self.ircify:
output = "%d %s 14(%s)" % (total, comment.strip(), curr_str)
else:
output = "%d %s (%s)" % (total, comment.strip(), curr_str)
else:
if self.ircify:
output = "%d 14(%s)" % (total, curr_str)
else:
output = "%d (%s)" % (total, curr_str)
else:
if self.ircify:
output += "%d 14(%s)" % (total, curr_str)
else:
output += "%d (%s)" % (total, curr_str)
if i == repeat - 1:
if comment is not None:
output += " (%s)" % (comment.strip())
return output
def p_roll_r(self, p):
# Chain rolls together.
@@ -170,7 +74,7 @@ class DiceRoller(object):
mods = p[2]
else:
mods = [p[2]]
p[0] = self.process_roll(p[1], mods, p[3])
p[0] = dice.lib.generic_result(p[1], mods, p[3], self.ircify)
output = p[0]
def p_roll_no_trials(self, p):
@@ -183,7 +87,7 @@ class DiceRoller(object):
mods = p[1]
else:
mods = [p[1]]
p[0] = self.process_roll(None, mods, p[2])
p[0] = dice.lib.generic_result(None, mods, p[2], self.ircify)
output = p[0]
def p_cypher_stat(self, p):