Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update development branch #113

Closed
wants to merge 9 commits into from
107 changes: 70 additions & 37 deletions mvkroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def parse_dice(dicestr: str):
return dicecounts


def roll_dice(dicecounts, cheat=False):
def roll_dice(dicecounts):
"""Returns a dictionary of dieSize => rolls[]"""
dicerolls = {
20: [],
Expand All @@ -88,11 +88,7 @@ def roll_dice(dicecounts, cheat=False):
try:
for size, num in dicecounts.items():
if num > 0:
# pylint: disable=unused-variable
if cheat:
dicerolls[size] = [size for idx in range(0, num)]
else:
dicerolls[size] = [random.randint(1, size) for idx in range(0, num)]
dicerolls[size] = [random.randint(1, size) for idx in range(0, num)]
except Exception as exc:
raise RollError("Exception while rolling dice.") from exc

Expand Down Expand Up @@ -136,16 +132,71 @@ def adv_disadv(advantage, disadvantage, dicecounts, dicerolls):
except Exception as exc:
raise RollError("Coding error calculating advantage or disadvantage.") from exc

return answer, dicerolls[20]


def calc_action(fortunedicerolls, characterdicerolls):
"""Compute the action total, using up to one d20 and the highest character die roll."""
try:
action_dice = fortunedicerolls + characterdicerolls
action_dice.sort(reverse=True)
action_dice = action_dice[:2]
answer = f"**Action Total: {str(sum(action_dice))}** {str(action_dice)}\n"
except Exception as exc:
raise RollError(
"Coding error flattening dice rolls and creating total."
) from exc
return answer


def calc_impact(fortunedicerolls, characterdicerolls):
"""Calculate the impact total"""
try:
# die results of 10 or higher on a d10 or 12 give two impact. It doesn't happen on a d20.
fortuneimpact = 1 if fortunedicerolls[0] >= 4 else 0
doublecharacterimpact = sum(2 for p in characterdicerolls if p >= 10)
characterimpact = sum(1 for p in characterdicerolls if 4 <= p < 10)
impact = fortuneimpact + doublecharacterimpact + characterimpact
impact = max(impact, 1)
answer = f"**Impact: {impact}** "
answer += (
f"(fortune={fortuneimpact} 2x={doublecharacterimpact} 1x={characterimpact})"
)
except Exception as exc:
raise RollError("Coding error calculating Impact") from exc
return answer


def crit_fumble(fortunedicerolls, characterdicerolls):
"""Check if we had a critical fumble. If so, add output and discard lowest non-1 die"""
answer = ""
newdicerolls = characterdicerolls
if fortunedicerolls[0] == 1:
answer += "**Critical Fumble**\n"
characterdicerolls.sort()
newdicerolls = []
scratched = False
for i in characterdicerolls:
if scratched:
newdicerolls.append(i)
elif i == 1:
newdicerolls.append(i)
else:
scratched = True
answer += f"*Scratched {i}*\n"
# no append because scratching this die

answer += "**Gain 1 inspiration point**\n"
answer += f"New character dice: {newdicerolls}\n"
return answer, newdicerolls


def mvkroll(dicestr: str):
"""Implementation of dice roller that applies MvK rules."""

logger.debug("Roll %s", {dicestr})

answer = ""
cheat = False
advantage = False
disadvantage = False

Expand All @@ -154,9 +205,6 @@ def mvkroll(dicestr: str):
elif re.search(r"advantage", dicestr, flags=re.IGNORECASE):
advantage = True

if re.search(r"cheat", dicestr, flags=re.IGNORECASE):
cheat = True

dicecounts = parse_dice(dicestr)

# advantage and disadvantage need _at least_ 2d20
Expand All @@ -169,7 +217,7 @@ def mvkroll(dicestr: str):
dicecounts[20] = 1
answer += "_No advantage/disadvantage, setting 1d20_\n"

dicerolls = roll_dice(dicecounts, cheat)
dicerolls = roll_dice(dicecounts)

# the d20 is called the "Fortune Die"
fortunedicerolls = dicerolls[20]
Expand All @@ -187,35 +235,21 @@ def mvkroll(dicestr: str):
if len(characterdicerolls) + len(fortunedicerolls) < 1:
raise RollError("Not enough dice to roll")

answer += adv_disadv(advantage, disadvantage, dicecounts, dicerolls)
adv_disadv_answer, fortunedicerolls = adv_disadv(
advantage, disadvantage, dicecounts, dicerolls
)
answer += adv_disadv_answer

answer += print_dice(dicerolls)

# Compute the action total, using up to one d20 and the highest character die roll.
try:
action_dice = fortunedicerolls[:1] + characterdicerolls[:1]
answer += f"**Action Total: {str(sum(action_dice))}** {str(action_dice)}\n"
except Exception as exc:
raise RollError(
"Coding error flattening dice rolls and creating total."
) from exc
fumble_answer, characterdicerolls = crit_fumble(
fortunedicerolls, characterdicerolls
)
answer += fumble_answer

try:
# die results of 10 or higher on a d10 or 12 give two impact. It doesn't happen on a d20.
fortuneimpact = 1 if fortunedicerolls[0] >= 4 else 0
doublecharacterimpact = sum(2 for p in characterdicerolls if p >= 10)
characterimpact = sum(1 for p in characterdicerolls if 4 <= p < 10)
impact = fortuneimpact + doublecharacterimpact + characterimpact
impact = max(impact, 1)
answer += f"**Impact: {impact}** "
answer += (
f"(fortune={fortuneimpact} 2x={doublecharacterimpact} 1x={characterimpact})"
)
except Exception as exc:
raise RollError("Coding error calculating Impact") from exc
answer += calc_action(fortunedicerolls, characterdicerolls)

if cheat:
answer = "\n# Cheating" + answer + "\n# Cheating"
answer += calc_impact(fortunedicerolls, characterdicerolls)

return answer

Expand All @@ -226,10 +260,9 @@ def plainroll(dicestr: str):
logger.debug("Roll %s", {dicestr})

answer = ""
cheat = False

dicecounts = parse_dice(dicestr)
dicerolls = roll_dice(dicecounts, cheat)
dicerolls = roll_dice(dicecounts)

answer += print_dice(dicerolls)

Expand Down