add a !reaction dice roll for a very simple oracle-style vibe check
Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
parent
6d8ba18380
commit
3100efd4a9
@ -4,10 +4,9 @@ import random
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from irc.client import NickMask
|
||||
|
||||
from dice.lib import cypher_roll
|
||||
from dice.lib import cypher_roll, reaction_roll
|
||||
from dice.roller import DiceRoller
|
||||
from ircbot.lib import Plugin
|
||||
|
||||
@ -15,6 +14,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
CYPHER_ROLL_REGEX = r'((?P<type>A|T)(?P<difficulty>\d+))?(?P<mods>(?:\s*(-|\+)\d+)*)\s*(?P<comment>.*)?'
|
||||
CYPHER_COMMAND_REGEX = r'^!cypher\s+(' + CYPHER_ROLL_REGEX + ')'
|
||||
REACTION_COMMAND_REGEX = r'^!reaction$'
|
||||
|
||||
|
||||
class Dice(Plugin):
|
||||
@ -34,6 +34,8 @@ class Dice(Plugin):
|
||||
self.handle_roll, -20)
|
||||
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!random\s+(.*)$',
|
||||
self.handle_random, -20)
|
||||
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], REACTION_COMMAND_REGEX,
|
||||
self.handle_reaction_roll, -20)
|
||||
|
||||
super(Dice, self).start()
|
||||
|
||||
@ -41,6 +43,8 @@ class Dice(Plugin):
|
||||
"""Tear down handlers."""
|
||||
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_roll)
|
||||
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_random)
|
||||
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_cypher_roll)
|
||||
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_reaction_roll)
|
||||
|
||||
super(Dice, self).stop()
|
||||
|
||||
@ -102,6 +106,20 @@ class Dice(Plugin):
|
||||
reply = "{0:s}".format(choice)
|
||||
return self.bot.reply(event, reply)
|
||||
|
||||
def handle_reaction_roll(self, connection, event, match):
|
||||
"""Handle the !reaction roll."""
|
||||
nick = NickMask(event.source).nick
|
||||
|
||||
roll, label, summary = reaction_roll()
|
||||
if summary in ('--', '-'):
|
||||
result_str = f"4{label}"
|
||||
elif summary == '~':
|
||||
result_str = f"9{label}"
|
||||
else:
|
||||
result_str = f"9{label}"
|
||||
|
||||
return self.bot.reply(event, f"{nick}: the current disposition is: {result_str} 14({roll})")
|
||||
|
||||
def handle_roll(self, connection, event, match):
|
||||
"""Handle the !roll command which covers most common dice stuff."""
|
||||
nick = NickMask(event.source).nick
|
||||
|
29
dice/lib.py
29
dice/lib.py
@ -40,3 +40,32 @@ def cypher_roll(difficulty=None, mods=0, is_attack=False):
|
||||
beats = (roll // 3) - (numexpr.evaluate(mods).item() if mods else 0)
|
||||
beats = 0 if beats < 0 else beats
|
||||
return (roll, beats, difficulty <= beats if difficulty else None, effect)
|
||||
|
||||
|
||||
def reaction_roll():
|
||||
"""Make a reaction roll, which gives some oracle-like randomness to uncertain situations (for solo play or similar).
|
||||
|
||||
Returns:
|
||||
tuple of:
|
||||
- the result on the d20
|
||||
- the label for the result
|
||||
- a summary of the result ('++', '+', '~', '-', '--') (best to worst)
|
||||
"""
|
||||
roll = rand.randint(1, 20)
|
||||
if 1 == roll:
|
||||
label = 'VERY negative'
|
||||
summary = '--'
|
||||
elif 2 <= roll <= 6:
|
||||
label = 'negative'
|
||||
summary = '-'
|
||||
elif 7 <= roll <= 14:
|
||||
label = 'positive, with complications'
|
||||
summary = '~'
|
||||
elif 15 <= roll <= 19:
|
||||
label = 'positive'
|
||||
summary = '+'
|
||||
else:
|
||||
label = 'VERY positive'
|
||||
summary = '++'
|
||||
|
||||
return (roll, label, summary)
|
||||
|
@ -80,3 +80,56 @@ class MarkovTestCase(TestCase):
|
||||
mock_event,
|
||||
'test: unmodded attempt beats a difficulty 3 task. 14(d20=9)'
|
||||
)
|
||||
|
||||
def test_reaction_roll_strings(self):
|
||||
"""Simulate incoming reaction requests."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'test!test@test'
|
||||
mock_event.target = '#test'
|
||||
mock_event.recursing = False
|
||||
|
||||
# good and very good are bold green
|
||||
mock_event.arguments = ['!reaction']
|
||||
match = re.search(dice.ircplugin.REACTION_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=18):
|
||||
self.plugin.handle_reaction_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'test: the current disposition is: 9positive 14(18)'
|
||||
)
|
||||
mock_event.arguments = ['!reaction']
|
||||
match = re.search(dice.ircplugin.REACTION_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=20):
|
||||
self.plugin.handle_reaction_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'test: the current disposition is: 9VERY positive 14(20)'
|
||||
)
|
||||
|
||||
# decent is green
|
||||
mock_event.arguments = ['!reaction']
|
||||
match = re.search(dice.ircplugin.REACTION_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=10):
|
||||
self.plugin.handle_reaction_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'test: the current disposition is: 9positive, with complications 14(10)'
|
||||
)
|
||||
|
||||
# bad and very bad are bold red
|
||||
mock_event.arguments = ['!reaction']
|
||||
match = re.search(dice.ircplugin.REACTION_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=4):
|
||||
self.plugin.handle_reaction_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'test: the current disposition is: 4negative 14(4)'
|
||||
)
|
||||
mock_event.arguments = ['!reaction']
|
||||
match = re.search(dice.ircplugin.REACTION_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=1):
|
||||
self.plugin.handle_reaction_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'test: the current disposition is: 4VERY negative 14(1)'
|
||||
)
|
||||
|
@ -85,3 +85,22 @@ class DiceLibTestCase(TestCase):
|
||||
with mock.patch('random.SystemRandom.randint', return_value=10):
|
||||
result = dice.lib.cypher_roll(mods='2')
|
||||
self.assertEqual(result, (10, 1, None, None))
|
||||
|
||||
def test_reaction_roll(self):
|
||||
"""Roll possible reactions."""
|
||||
with mock.patch('random.SystemRandom.randint', return_value=1):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (1, 'VERY negative', '--'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=2):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (2, 'negative', '-'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=6):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (6, 'negative', '-'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=7):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (7, 'positive, with complications', '~'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=14):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (14, 'positive, with complications', '~'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=15):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (15, 'positive', '+'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=19):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (19, 'positive', '+'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=20):
|
||||
self.assertEqual(dice.lib.reaction_roll(), (20, 'VERY positive', '++'))
|
||||
|
Loading…
Reference in New Issue
Block a user