Пример #1
0
def create_response(message: Message) -> Optional[Response]:
    regex_result = parse(message.content)
    if regex_result:
        try:
            result, rolls = calc(regex_result.group("calc") or "0")

            response = " {comment}\n{results}\nErgebnis: **{FP}**".format(
                comment=regex_result.group("comment").strip(),
                results=(" ").join([
                    f"{len(roll_list)}d{sides}: [{' + '.join([str(roll) for roll in roll_list])}]"
                    for sides, roll_list in rolls
                ]),
                FP=int(result),
            )

            for sides, roll_list in rolls:
                save_check(
                    message.author,
                    "DiceRoll",
                    [int(roll) for roll in roll_list],
                    sides,
                )

            return Response(message.channel.send,
                            message.author.mention + response)
        except:
            return None

    return None
Пример #2
0
 def test_calc(self):
     self.assertEqual(calc("1"), (1, []))
     self.assertEqual(calc("1+1"), (2, []))
     self.assertEqual(calc("1-1"), (0, []))
     self.assertEqual(calc("-1"), (-1, []))
     self.assertEqual(calc("(2 + 1 * 2) / 2"), (2, []))
     self.assertEqual(calc("+ ((4 + -1 * 2) / 2) * (1+-3/4) "), (0.25, []))
Пример #3
0
class SkillCheck(GenericCheck):
    matcher = re.compile(
        r"""
            ^!?\ ?                                  # Optional exclamation mark
            (?P<force>f(?:orce)?\ )?                # Check if force
            (?P<attributes>(?:[0-9]+,?\ ?){3})\ ?   # A non-zero amount of numbers divided by comma or space
            (?:@\ ?(?P<SR>[0-9]+))\ ?               # An @ followed by a number
            (?P<modifier>(\ *[\+\-]\ *[0-9]+)*)     # A modifier
            (?P<modifierFP>(\ *[\+\-]\ *[0-9]+FP)*) # FP modifier
            (\ (?P<comment>.*?))?$                  # Anything else is lazy-matched as a comment
        """,
        re.VERBOSE | re.I,
    )
    transform = {
        **GenericCheck.transform,
        "SR": int,
        "modifierFP": lambda x: int(calc(x.replace("FP", "") or "0")[0]),
        "force": lambda x: x is not None,
    }
    _response = " {comment}\n```py\nEEW:    {EAV}\nWürfel: {rolls}\nFW {SR_mod}{diffs} = {SP} FP\n{result}\n```"
    _routine = " {comment}\n```py\nRoutineprobe: {SP} FP = QS {QL}\n```"

    @property
    def diffs(self) -> List[int]:
        return [
            min([eav - roll, 0])
            for eav, roll in zip(self.data["EAV"], self.data["rolls"])
        ]

    @property
    def skill_points(self) -> int:
        return self.data["SR"] + sum(self.diffs) + self.data["modifierFP"]

    @property
    def routine(self) -> bool:
        attr_ge_13 = all([attr >= 13 for attr in self.data["attributes"]])
        sr_ge_10 = self.data["SR"] >= 10 + 3 * -self.data["modifier"]
        return attr_ge_13 and sr_ge_10

    def force(self) -> None:
        self._force = True

    def ql(self, skill_points: int) -> int:
        return min([max([skill_points - 1, 0]) // 3 + 1, 6])

    def __str__(self) -> str:
        if (self.routine and not getattr(self, "_force", False)
                and not self.data["force"]):
            self._force = False
            sp = self.data["SR"] - self.data["SR"] // 2  # Rounds up
            return self._routine.format(**self.data, SP=sp, QL=self.ql(sp))
        else:
            self.data["diffs"] = "".join("{:>4}".format(d or "")
                                         for d in self.diffs)
            self.data["SP"] = self.skill_points
            if self.data["modifierFP"]:
                mod = f"{self.data['modifierFP']:+d}"
                self.data["SR_mod"] = f"{self.data['SR']:<2}{mod:<3}"
            else:
                self.data["SR_mod"] = f"{self.data['SR']:<5}"
            return super().__str__()

    def _get_result(self) -> str:
        if self.skill_points < 0 and self.data["rolls"].critical_success:
            return "Kritischer Erfolg! - Automatisch bestanden"
        if self.skill_points < 0 and self.data["rolls"].botch:
            return "Patzer!"
        if self.skill_points < 0:
            return "Nicht bestanden"
        if self.skill_points >= 0 and self.data["rolls"].botch:
            return "Patzer! - Automatisch nicht bestanden"
        if self.skill_points >= 0 and self.data["rolls"].critical_success:
            return "Kritischer Erfolg! (QS {})".format(
                self.ql(self.skill_points))
        else:
            return "Bestanden mit QS {}".format(self.ql(self.skill_points))
Пример #4
0
    def test_with_dice(self, mock_randint: MagicMock):
        mock_randint.return_value = 1

        self.assertEqual(calc("1d6"), (1, [(6, [1])]))
        self.assertEqual(calc("14+1d6"), (15, [(6, [1])]))
        self.assertEqual(calc("1d6+14"), (15, [(6, [1])]))
        self.assertEqual(calc("5+1w6+2"), (8, [(6, [1])]))
        self.assertEqual(calc("3w20 + 1 - 4"), (0, [(20, [1, 1, 1])]))
        self.assertEqual(calc("1337d1337")[0], 1337)
        self.assertEqual(calc("4W20"), (4, [(20, [1, 1, 1, 1])]))
        self.assertEqual(calc("w3"), (1, [(3, [1])]))
        self.assertEqual(calc("-w6 "), (-1, [(6, [1])]))
        self.assertEqual(
            calc("1w6+2W6+3d6+4D6"),
            (
                10,
                [
                    (6, [1]),
                    (6, [1, 1]),
                    (6, [1, 1, 1]),
                    (6, [1, 1, 1, 1]),
                ],
            ),
        )

        mock_randint.return_value = 2
        self.assertEqual(
            calc("(3*2w6-4)d(1W6+2)"),
            (16, [(6, [2, 2]), (6, [2]), (4, [2, 2, 2, 2, 2, 2, 2, 2])]),
        )
Пример #5
0
class GenericCheck:
    matcher = re.compile(
        r"""
            ^!?\ ?                              # Optional exclamation mark
            (?P<attributes>(?:[0-9]+,?\ ?)+)\ ? # A non-zero amount of numbers divided by comma or space
            (?P<modifier>(\ *[\+\-]\ *[0-9]+)*) # A modifier
            (\ (?P<comment>.*?))?$              # Anything else is lazy-matched as a comment
        """,
        re.VERBOSE | re.I,
    )
    transform: dict[str, Any] = {
        "attributes":
        lambda x: Attributes(
            [int(attr) for attr in re.split(r"[, ]+", x.strip(", "))]),
        "modifier":
        lambda x: int(calc(x or "0")[0]),
        "comment":
        lambda x: (x or "").strip(),
    }
    _response = " {comment}\n```py\nEEW:   {EAV}\nWürfel:{rolls}\n{result}\n```"
    _impossible = " {comment}\n```py\nEEW:{EAV}\nProbe nicht möglich\n```"

    def impossible(self) -> bool:
        return any(int(eav) <= 0 for eav in self.data["EAV"])

    def recalculate(self) -> None:
        self.data["EAV"] = Attributes(
            [attr + self.data["modifier"] for attr in self.data["attributes"]])
        self.data["rolls"] = CheckRolls(len(self.data["attributes"]))

    def __init__(self, author: Member, message: str):
        parsed = self.matcher.search(message)
        self.author = author
        if parsed:
            self.data = {}
            for name, value in parsed.groupdict().items():
                self.data[name] = self.transform[name](value)
            self.recalculate()
        else:
            raise ValueError

    def __str__(self) -> str:
        if self.impossible():
            return self._impossible.format(**self.data)

        save_check(self.author, self.__class__.__name__, self.data["rolls"],
                   20)

        return self._response.format(
            **self.data,
            result=self._get_result(),
        )

    def _get_result(self) -> str:
        rolls: type[CheckRolls] = self.data["rolls"]
        if rolls.critical_success:
            return "Kritischer Erfolg!"
        if rolls.botch:
            return "Patzer!"
        if all(roll <= eav for roll, eav in zip(rolls, self.data["EAV"])):
            return "Bestanden"
        else:
            return "Nicht bestanden"