95 lines
2.6 KiB
Python
95 lines
2.6 KiB
Python
from typing import Literal
|
|
|
|
import click
|
|
|
|
from roll.__about__ import __version__
|
|
from roll.cli.roll_param import ROLL
|
|
from roll.roll import Roll
|
|
from roll.throw import Throw
|
|
|
|
CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
|
|
|
|
|
|
@click.group(context_settings=CONTEXT_SETTINGS, invoke_without_command=True)
|
|
@click.version_option(version=__version__, prog_name="roll")
|
|
@click.argument("roll", type=ROLL, default="1d20")
|
|
def cli(roll: Roll | Literal["advantage"] | Literal["disadvantage"]) -> None:
|
|
"""throw a ROLL and print the results
|
|
|
|
ROLL is specified as
|
|
|
|
DdS[(+|-)M]
|
|
|
|
where D = # of dice, S = sides per die, and M = optional modifier
|
|
|
|
if no ROLL is provided, a 1d20 is thrown
|
|
|
|
instead of a ROLL specifier, you can use a substring of "advantage"
|
|
or "disadvantage" to throw 2d20 and take the appropriate result
|
|
|
|
example usage:
|
|
|
|
\b
|
|
$ roll 2d20+3
|
|
rolling 2d20+3:
|
|
1: | 2
|
|
2: | 13
|
|
mod: +3
|
|
total: 18
|
|
\b
|
|
$ roll
|
|
rolling 1d20:
|
|
1: | 11
|
|
total: 11
|
|
\b
|
|
$ roll advantage
|
|
rolling 2d20 with advantage:
|
|
1: | 13
|
|
1: | 2
|
|
total: 13
|
|
\b
|
|
$ roll dis
|
|
rolling 2d20 with disadvantage:
|
|
1: | 1
|
|
2: | 19
|
|
total: 1
|
|
critical miss!
|
|
"""
|
|
if isinstance(roll, str):
|
|
throw = _advantage(roll)
|
|
else:
|
|
throw = _throw(roll)
|
|
total = f" {throw.total}"
|
|
click.secho(f"total:\t╰{total:╶>5}", bold=True)
|
|
if throw.is_critical_hit: # pragma: no cover (random)
|
|
click.secho("critical hit!", fg="green", bold=True)
|
|
elif throw.is_critical_miss: # pragma: no cover (random)
|
|
click.secho("critical miss!", fg="red", bold=True)
|
|
|
|
|
|
def _advantage(advantage: str) -> Throw:
|
|
"""print the results of an advantage or disadvantage roll"""
|
|
click.echo(f"throwing 2d20 with {advantage}:")
|
|
roll = Roll()
|
|
fst = roll.throw()
|
|
snd = roll.throw()
|
|
click.echo(f"1:\t┆{fst.total: >5}")
|
|
click.echo(f"2:\t┆{snd.total: >5}")
|
|
if advantage == "advantage":
|
|
throw = fst if fst.total > snd.total else snd
|
|
else:
|
|
throw = fst if fst.total < snd.total else snd
|
|
return throw
|
|
|
|
|
|
def _throw(roll: Roll) -> Throw:
|
|
"""print the results of a roll"""
|
|
click.echo(f"throwing {roll.to_str()}:")
|
|
throw = roll.throw()
|
|
for i, result in enumerate(throw.results, start=1):
|
|
click.echo(f"{i}:\t┆{result: >5}")
|
|
if roll.modifier:
|
|
color = "green" if roll.modifier > 0 else "red"
|
|
click.secho(f"mod:\t┆{roll.modifier_str(): >5}", fg=color)
|
|
return throw
|