class TestContinueDialogue(TestDialogueProcessor): """Tests of the L{DialogueProcessor.continueDialogue} method.""" def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue_processor = DialogueProcessor(self.dialogue, self.game_state) self.dialogue_processor.initiateDialogue() self.dialogue_action = \ self.dialogue.default_greeting.actions[0] def testRunsDialogueActions(self): """continueDialogue executes all DialogueActions""" dialogue_processor = self.dialogue_processor dialogue_processor.continueDialogue() self.assertTrue(self.dialogue_action.was_called) expected_tuple = ((self.game_state,), {}) self.assertTupleEqual(expected_tuple, self.dialogue_action.call_arguments) def testReturnsValidResponses(self): """continueDialogue returns list of valid DialogueResponses""" dialogue_processor = self.dialogue_processor valid_responses = \ dialogue_processor.dialogue_section_stack[0].responses valid_responses.pop(2) # Sanity check, all "valid" responses should have a condition that # evaluates to True. for response in valid_responses: if (response.condition is not None): result = eval(response.condition, self.game_state, {}) self.assertTrue(result) responses = dialogue_processor.continueDialogue() self.assertItemsEqual(responses, valid_responses)
class TestGetCurrentDialogueSection(TestDialogueProcessor): """Tests of the L{DialogueProcessor.getCurrentDialogueSection} method.""" def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue_processor = DialogueProcessor(self.dialogue, self.game_state) self.dialogue_processor.initiateDialogue() def testReturnsCorrectDialogueSection(self): """getCurrentDialogueSection returns section at top of stack""" dialogue_processor = self.dialogue_processor expected_dialogue_section = self.dialogue.default_greeting actual_dialogue_section = \ dialogue_processor.getCurrentDialogueSection() self.assertEqual(expected_dialogue_section, actual_dialogue_section)
class TestGetRootDialogueSection(TestDialogueProcessor): """Tests of the L{DialogueProcessor.getDialogueGreeting} method.""" def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue_processor = DialogueProcessor( self.dialogue, {'use_alternative_root': True} ) self.dialogue_processor.initiateDialogue() def testReturnsCorrectDialogueSection(self): """getDialogueGreeting returns first section with true condition""" dialogue_processor = self.dialogue_processor dialogue = self.dialogue root_dialogue_section = dialogue_processor.getDialogueGreeting() expected_dialogue_section = dialogue.greetings[0] self.assertEqual(root_dialogue_section, expected_dialogue_section)
class TestGetValidResponses(TestDialogueProcessor): """Tests of the L{DialogueProcessor.getValidResponses} method.""" def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue_processor = DialogueProcessor(self.dialogue, self.game_state) self.dialogue_processor.initiateDialogue() def testReturnsValidResponses(self): """getValidResponses returns list of valid DialogueResponses""" dialogue_processor = self.dialogue_processor valid_responses = \ dialogue_processor.dialogue_section_stack[0].responses valid_responses.pop(2) # Sanity check, all "valid" responses should have a condition that # evaluates to True. for response in valid_responses: if (response.condition is not None): result = eval(response.condition, {}, {}) self.assertTrue(result) responses = dialogue_processor.continueDialogue() self.assertItemsEqual(responses, valid_responses)
class TestRunDialogueActions(TestDialogueProcessor): """Tests of the L{DialogueProcessor.runDialogueActions} method.""" def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue_processor = DialogueProcessor(self.dialogue, self.game_state) self.dialogue_processor.initiateDialogue() self.dialogue_section = DialogueSection( id_='some_section', text='Test dialogue section.', actions=[ MockDialogueAction('foo'), ], ) self.dialogue_response = DialogueResponse( text='A response.', actions=[ MockDialogueAction('foo'), ], next_section_id='end', ) def testExecutesDialogueActions(self): """runDialogueActions correctly executes DialogueActions""" dialogue_processor = self.dialogue_processor # Case: DialogueSection dialogue_processor.runDialogueActions(self.dialogue_section) dialogue_section_action = self.dialogue_section.actions[0] self.assertTrue(dialogue_section_action.was_called) expected_call_args = ((self.game_state,), {}) self.assertTupleEqual(expected_call_args, dialogue_section_action.call_arguments) # Case: DialogueResponse dialogue_processor.runDialogueActions(self.dialogue_response) dialogue_response_action = self.dialogue_response.actions[0] self.assertTrue(dialogue_response_action.was_called) self.assertTupleEqual(expected_call_args, dialogue_response_action.call_arguments)
def processDialogue(dialogue, game_state): """ Process a L{Dialogue} until the user selects a response that ends it. @param dialogue: dialogue data to process. @type dialogue: L{Dialogue} @param game_state: objects that should be made available for response conditional testing. @type game_state: dict of objects """ npc_name = dialogue.npc_name dialogue_processor = DialogueProcessor(dialogue, game_state) dialogue_processor.initiateDialogue() while dialogue_processor.in_dialogue: responses = dialogue_processor.continueDialogue() current_dialogue_section = \ dialogue_processor.getCurrentDialogueSection() dialogue_text = current_dialogue_section.text # Indent dialogue text after the first line. dialogue_text = dialogue_text.replace('\n', '\n ') print('\n{0}: {1}'.format(npc_name, dialogue_text)) chosen_reply = chooseReply(responses) dialogue_processor.reply(chosen_reply)
class DialogueGUI(object): """Window that handles the dialogues.""" _logger = logging.getLogger('dialoguegui.DialogueGUI') def __init__(self, controller, npc, quest_engine, player_character): self.active = False self.controller = controller self.dialogue_gui = pychan.loadXML("gui/dialogue.xml") self.npc = npc # TODO Technomage 2010-11-10: the QuestEngine should probably be # a singleton-like object, which would avoid all of this instance # handling. self.quest_engine = quest_engine self.player_character = player_character def initiateDialogue(self): """Callback for starting a quest""" self.active = True stats_label = self.dialogue_gui.findChild(name='stats_label') stats_label.text = u'Name: John Doe\nAn unnamed one' events = { 'end_button': self.handleEnd } self.dialogue_gui.mapEvents(events) self.dialogue_gui.show() self.setNpcName(self.npc.name) self.setAvatarImage(self.npc.dialogue.avatar_path) game_state = {'npc': self.npc, 'pc': self.player_character, 'quest': self.quest_engine} try: self.dialogue_processor = DialogueProcessor(self.npc.dialogue, game_state) self.dialogue_processor.initiateDialogue() except (TypeError) as error: self._logger.error(str(error)) else: self.continueDialogue() def setDialogueText(self, text): """Set the displayed dialogue text. @param text: text to display.""" text = unicode(text) speech = self.dialogue_gui.findChild(name='speech') # to append text to npc speech box, uncomment the following line #speech.text = speech.text + "\n-----\n" + unicode(say) speech.text = text self._logger.debug('set dialogue text to "{0}"'.format(text)) def continueDialogue(self): """Display the dialogue text and responses for the current L{DialogueSection}.""" dialogue_processor = self.dialogue_processor dialogue_text = dialogue_processor.getCurrentDialogueSection().text self.setDialogueText(dialogue_text) self.responses = dialogue_processor.continueDialogue() self.setResponses(self.responses) def handleEntered(self, *args): """Callback for when user hovers over response label.""" pass def handleExited(self, *args): """Callback for when user hovers out of response label.""" pass def handleClicked(self, *args): """Handle a response being clicked.""" response_n = int(args[0].name.replace('response', '')) response = self.responses[response_n] dialogue_processor = self.dialogue_processor dialogue_processor.reply(response) if (not dialogue_processor.in_dialogue): self.handleEnd() else: self.continueDialogue() def handleEnd(self): """Handle the end of the conversation being reached, either from the GUI or from within the conversation itself.""" self.dialogue_gui.hide() self.responses = [] self.npc.behaviour.state = 1 self.npc.behaviour.idle() self.active = False def setNpcName(self, name): """Set the NPC name to display on the dialogue GUI. @param name: name of the NPC to set @type name: basestring""" name = unicode(name) stats_label = self.dialogue_gui.findChild(name='stats_label') try: (first_name, desc) = name.split(" ", 1) stats_label.text = u'Name: ' + first_name + "\n" + desc except ValueError: stats_label.text = u'Name: ' + name self.dialogue_gui.title = name self._logger.debug('set NPC name to "{0}"'.format(name)) def setAvatarImage(self, image_path): """Set the NPC avatar image to display on the dialogue GUI @param image_path: filepath to the avatar image @type image_path: basestring""" avatar_image = self.dialogue_gui.findChild(name='npc_avatar') avatar_image.image = image_path def setResponses(self, dialogue_responses): """Creates the list of clickable response labels and sets their respective on-click callbacks. @param responses: list of L{DialogueResponses} from the L{DialogueProcessor} @type responses: list of L{DialogueResponses}""" choices_list = self.dialogue_gui.findChild(name='choices_list') choices_list.removeAllChildren() for index, response in enumerate(dialogue_responses): button = widgets.Label( name="response{0}".format(index), text=unicode(response.text), hexpand="1", min_size=(100,16), max_size=(490,48), position_technique='center:center' ) button.margins = (5, 5) button.background_color = fife.Color(0, 0, 0) button.color = fife.Color(0, 255, 0) button.border_size = 0 button.wrap_text = 1 button.capture(lambda button=button: self.handleEntered(button), event_name='mouseEntered') button.capture(lambda button=button: self.handleExited(button), event_name='mouseExited') button.capture(lambda button=button: self.handleClicked(button), event_name='mouseClicked') choices_list.addChild(button) self.dialogue_gui.adaptLayout(True) self._logger.debug( 'added {0} to response choice list'.format(response) )