add a simple oracle to the dice roller
Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
+27
-2
@@ -6,11 +6,12 @@ from django.conf import settings
|
||||
from irc.client import NickMask
|
||||
|
||||
from dice import dice_roller
|
||||
from dice.lib import reaction_roll
|
||||
from dice.lib import oracle_roll, reaction_roll
|
||||
from ircbot.lib import Plugin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ORACLE_COMMAND_REGEX = r'^!oracle\s+(.*\?)$'
|
||||
REACTION_COMMAND_REGEX = r'^!reaction$'
|
||||
|
||||
|
||||
@@ -28,6 +29,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'], ORACLE_COMMAND_REGEX,
|
||||
self.handle_oracle_roll, -20)
|
||||
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], REACTION_COMMAND_REGEX,
|
||||
self.handle_reaction_roll, -20)
|
||||
|
||||
@@ -37,7 +40,7 @@ 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_oracle_roll)
|
||||
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_reaction_roll)
|
||||
|
||||
super(Dice, self).stop()
|
||||
@@ -59,6 +62,28 @@ class Dice(Plugin):
|
||||
reply = "{0:s}".format(choice)
|
||||
return self.bot.reply(event, reply)
|
||||
|
||||
def handle_oracle_roll(self, connection, event, match):
|
||||
"""Ask the oracle a question, get a yes/no/etc. answer."""
|
||||
inquiry = match.group(1)
|
||||
|
||||
roll, result = oracle_roll()
|
||||
result_str = result
|
||||
if result in ('YES', 'YES, AND'):
|
||||
result_str = f"9{result_str}"
|
||||
elif result in ('YES, BUT', ):
|
||||
result_str = f"3{result_str}"
|
||||
elif result in ('NO, BUT', ):
|
||||
result_str = f"14{result_str}"
|
||||
elif result in ('NO', 'NO, AND'):
|
||||
result_str = f"4{result_str}"
|
||||
|
||||
if result in ('YES, AND', 'NO, AND'):
|
||||
result_str = f"{result_str}"
|
||||
|
||||
result_str = f"{result_str} 14({roll})"
|
||||
|
||||
return self.bot.reply(event, f"{inquiry} {result_str}")
|
||||
|
||||
def handle_reaction_roll(self, connection, event, match):
|
||||
"""Handle the !reaction roll."""
|
||||
nick = NickMask(event.source).nick
|
||||
|
||||
+27
@@ -229,6 +229,33 @@ def generic_result(trials, mods, comment, ircify):
|
||||
return output
|
||||
|
||||
|
||||
def oracle_roll() -> Tuple[int, str]:
|
||||
"""Make a roll with some specific interpretations for simple yes/no/etc. renderings.
|
||||
|
||||
1: no, and (something terrible happens; 5% chance)
|
||||
2-4: no (shut down; 15% chance)
|
||||
5-10: no, but (not really, but maybe a compromise twist; 30% chance)
|
||||
11-16: yes, but (yes, but there's a complication; 30% chance)
|
||||
17-19: yes (yes, up to creativity to decide if it's simple or with a complication; 15% chance)
|
||||
20: yes, and (yes, and something cool happens; 5% chance)
|
||||
"""
|
||||
roll = rand.randint(1, 20)
|
||||
if roll == 1:
|
||||
result_str = 'NO, AND'
|
||||
elif 2 <= roll <= 4:
|
||||
result_str = 'NO'
|
||||
elif 5 <= roll <= 10:
|
||||
result_str = 'NO, BUT'
|
||||
elif 11 <= roll <= 16:
|
||||
result_str = 'YES, BUT'
|
||||
elif 17 <= roll <= 19:
|
||||
result_str = 'YES'
|
||||
elif roll == 20:
|
||||
result_str = 'YES, AND'
|
||||
|
||||
return roll, result_str
|
||||
|
||||
|
||||
def reaction_roll():
|
||||
"""Make a reaction roll, which gives some oracle-like randomness to uncertain situations (for solo play or similar).
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import dice.ircplugin
|
||||
from ircbot.models import IrcServer
|
||||
|
||||
|
||||
class MarkovTestCase(TestCase):
|
||||
class DiceTestCase(TestCase):
|
||||
"""Test the markov plugin."""
|
||||
|
||||
fixtures = ['tests/fixtures/irc_server_fixture.json']
|
||||
@@ -23,6 +23,73 @@ class MarkovTestCase(TestCase):
|
||||
|
||||
self.plugin = dice.ircplugin.Dice(self.mock_bot, self.mock_connection, mock.MagicMock())
|
||||
|
||||
def test_oracle_roll_strings(self):
|
||||
"""Simulate incoming oracle requests."""
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'test!test@test'
|
||||
mock_event.target = '#test'
|
||||
mock_event.recursing = False
|
||||
|
||||
# very good yes is bold green
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=20):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 9YES, AND 14(20)'
|
||||
)
|
||||
|
||||
# good yes is green
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=17):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 9YES 14(17)'
|
||||
)
|
||||
|
||||
# decent yes is dark green
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=11):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 3YES, BUT 14(11)'
|
||||
)
|
||||
|
||||
# decent no is dark gray
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=10):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 14NO, BUT 14(10)'
|
||||
)
|
||||
|
||||
# no is red
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=3):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 4NO 14(3)'
|
||||
)
|
||||
|
||||
# terrible no is bold red
|
||||
mock_event.arguments = ['!oracle is this a test?']
|
||||
match = re.search(dice.ircplugin.ORACLE_COMMAND_REGEX, mock_event.arguments[0])
|
||||
with mock.patch('random.SystemRandom.randint', return_value=1):
|
||||
self.plugin.handle_oracle_roll(self.mock_connection, mock_event, match)
|
||||
self.mock_bot.reply.assert_called_with(
|
||||
mock_event,
|
||||
'is this a test? 4NO, AND 14(1)'
|
||||
)
|
||||
|
||||
def test_reaction_roll_strings(self):
|
||||
"""Simulate incoming reaction requests."""
|
||||
mock_event = mock.MagicMock()
|
||||
|
||||
+50
-23
@@ -109,29 +109,6 @@ class CypherRollTestCase(TestCase):
|
||||
self.assertEqual(result, (1, 2, True, None, "a GM intrusion", 0, 0))
|
||||
|
||||
|
||||
class DiceLibTestCase(TestCase):
|
||||
"""Test that a variety of dice rolls work as expected."""
|
||||
|
||||
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', '++'))
|
||||
|
||||
|
||||
class CypherRollStringTestCase(TestCase):
|
||||
"""Test that Cypher System roll results are in the expected string representation."""
|
||||
|
||||
@@ -177,3 +154,53 @@ class CypherRollStringTestCase(TestCase):
|
||||
comment="Test")
|
||||
self.assertEqual(result,
|
||||
"Test Might roll succeeded, with a GM intrusion! (result 0 (d20=1) vs. difficulty 0 (2-2))")
|
||||
|
||||
|
||||
class OracleRollTestCase(TestCase):
|
||||
"""Test that a variety of oracle results are as expected."""
|
||||
|
||||
def test_oracle_results(self):
|
||||
"""Roll possible oracle reactions."""
|
||||
with mock.patch('random.SystemRandom.randint', return_value=1):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (1, 'NO, AND'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=2):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (2, 'NO'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=4):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (4, 'NO'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=5):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (5, 'NO, BUT'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=10):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (10, 'NO, BUT'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=11):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (11, 'YES, BUT'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=16):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (16, 'YES, BUT'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=17):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (17, 'YES'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=19):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (19, 'YES'))
|
||||
with mock.patch('random.SystemRandom.randint', return_value=20):
|
||||
self.assertEqual(dice.lib.oracle_roll(), (20, 'YES, AND'))
|
||||
|
||||
|
||||
class ReactionRollTestCase(TestCase):
|
||||
"""Test that a variety of dice rolls work as expected."""
|
||||
|
||||
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', '++'))
|
||||
|
||||
Reference in New Issue
Block a user