diff --git a/dice/ircplugin.py b/dice/ircplugin.py index 58599ce..2d836c9 100644 --- a/dice/ircplugin.py +++ b/dice/ircplugin.py @@ -7,11 +7,15 @@ from django.conf import settings from irc.client import NickMask +from dice.lib import cypher_roll from dice.roller import DiceRoller from ircbot.lib import Plugin logger = logging.getLogger(__name__) +CYPHER_ROLL_REGEX = r'(T(?P\d+))?(?P(?:\s*(-|\+)\d+)*)\s*(?P.*)?' +CYPHER_COMMAND_REGEX = r'^!cypher\s+(' + CYPHER_ROLL_REGEX + ')' + class Dice(Plugin): """Roll simple or complex dice strings.""" @@ -24,6 +28,8 @@ class Dice(Plugin): def start(self): """Set up the handlers.""" + self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], CYPHER_COMMAND_REGEX, + self.handle_cypher_roll, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!roll\s+(.*)$', self.handle_roll, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!random\s+(.*)$', @@ -38,6 +44,45 @@ class Dice(Plugin): super(Dice, self).stop() + def handle_cypher_roll(self, connection, event, match): + """Handle the !cypher roll.""" + nick = NickMask(event.source).nick + task = match.group(1) + + task_group = re.search(CYPHER_ROLL_REGEX, task) + difficulty = int(task_group.group('difficulty')) if task_group.group('difficulty') else None + mods = task_group.group('mods') + comment = task_group.group('comment') + result, beats, success, effect = cypher_roll(difficulty=difficulty, mods=mods) + + if success is not None: + if success: + if effect: + result_str = f"9succeeded, with {effect}!" + else: + result_str = "9succeeded!" + else: + if effect: + result_str = f"4failed, with {effect}!" + else: + result_str = "4failed." + else: + if effect: + result_str = f"beats a difficulty {beats} task, with {effect}!" + else: + result_str = f"beats a difficulty {beats} task." + + if success is not None: + # show the adjusted difficulty + detail_str = f"14(d20={result} vs. diff. {difficulty}{mods})" + else: + detail_str = f"14(d20={result} with {mods} levels)" + + if comment: + return self.bot.reply(event, f"{nick}: {comment} {result_str} {detail_str}") + else: + return self.bot.reply(event, f"{nick}: your check {result_str} {detail_str}") + def handle_random(self, connection, event, match): """Handle the !random command which picks an item from a list.""" nick = NickMask(event.source).nick diff --git a/tests/test_dice_ircplugin.py b/tests/test_dice_ircplugin.py new file mode 100644 index 0000000..92a656f --- /dev/null +++ b/tests/test_dice_ircplugin.py @@ -0,0 +1,48 @@ +"""Test IRC behavior of the dice plugin.""" +import re +from unittest import mock + +from django.test import TestCase + +import dice.ircplugin +from ircbot.models import IrcServer + + +class MarkovTestCase(TestCase): + """Test the markov plugin.""" + + fixtures = ['tests/fixtures/irc_server_fixture.json'] + + def setUp(self): + """Create common objects.""" + self.mock_bot = mock.MagicMock() + self.mock_connection = mock.MagicMock() + + self.mock_connection.get_nickname.return_value = 'test_bot' + self.mock_connection.server_config = IrcServer.objects.get(pk=1) + + self.plugin = dice.ircplugin.Dice(self.mock_bot, self.mock_connection, mock.MagicMock()) + + def test_cypher_roll_strings(self): + """Simulate incoming Cypher System requests.""" + mock_event = mock.MagicMock() + mock_event.arguments = ['!cypher T3'] + mock_event.source = 'test!test@test' + mock_event.target = '#test' + mock_event.recursing = False + + match = re.search(dice.ircplugin.CYPHER_COMMAND_REGEX, '!cypher T3') + with mock.patch('random.SystemRandom.randint', return_value=17): + self.plugin.handle_cypher_roll(self.mock_connection, mock_event, match) + self.mock_bot.reply.assert_called_with( + mock_event, + 'test: your check 9succeeded, with +1 damage! 14(d20=17 vs. diff. 3)' + ) + + match = re.search(dice.ircplugin.CYPHER_COMMAND_REGEX, '!cypher +1') + with mock.patch('random.SystemRandom.randint', return_value=17): + self.plugin.handle_cypher_roll(self.mock_connection, mock_event, match) + self.mock_bot.reply.assert_called_with( + mock_event, + 'test: your check beats a difficulty 4 task, with +1 damage! 14(d20=17 with +1 levels)' + )