def reply(self, dialogue_response): """ Reply with a L{DialogueResponse}, execute the L{DialogueActions<DialogueAction>} it contains and push the next L{DialogueSection} onto the L{dialogue_section_stack}. @param dialogue_response: response to reply with. @type dialogue_response: L{DialogueReponse} @raise RuntimeError: Any precondition is not met. @precondition: L{initiateDialogue} must be called before this method is used. """ if (not self.in_dialogue): error_message = dedent_chomp(''' reply cannot be called until the dialogue has been initiated via initiateDialogue ''') raise RuntimeError(error_message) self._logger.info('replied with {0}'.format(dialogue_response)) # FIXME: Technomage 2010-12-11: What happens if runDialogueActions # raises an error? self.runDialogueActions(dialogue_response) next_section_id = dialogue_response.next_section_id if (next_section_id == 'back'): if (len(self.dialogue_section_stack) == 1): error_message = dedent_chomp(''' attempted to run goto: back action but stack does not contain a previous DialogueSection ''') raise RuntimeError(error_message) else: try: self.dialogue_section_stack.pop() except (IndexError,): error_message = dedent_chomp(''' attempted to run goto: back action but the stack was empty ''') raise RuntimeError(error_message) else: self._logger.debug( 'ran goto: back action, restored last DialogueSection' ) elif (next_section_id == 'end'): self.endDialogue() self._logger.debug('ran goto: end action, ended dialogue') else: try: next_dialogue_section = \ self.dialogue.sections[next_section_id] except KeyError: error_message = dedent_chomp(''' {0} is not a recognized goto: action or DialogueSection identifier ''').format(next_section_id) raise RuntimeError(error_message) else: self.dialogue_section_stack.append(next_dialogue_section)
def getCurrentDialogueSection(self): """ Return the L{DialogueSection} at the top of the L{dialogue_section_stack}. @returns: section of dialogue currently being processed. @rtype: L{DialogueSection} @raise RuntimeError: Any preconditions are not met. @precondition: dialogue has been initiated via L{initiateDialogue} and L{dialogue_section_stack} contains at least one L{DialogueSection}. """ if (not self.in_dialogue): error_message = dedent_chomp(''' getCurrentDialogueSection called but the dialogue has not been initiated yet ''') raise RuntimeError(error_message) try: current_dialogue_section = self.dialogue_section_stack[-1] except IndexError: error_message = dedent_chomp(''' getCurrentDialogueSection called but no DialogueSections are in the stack ''') raise RuntimeError(error_message) return current_dialogue_section
def getValidResponses(self, dialogue_section): """ Evaluate all L{DialogueResponse} conditions for a L{DialogueSection} and return a list of valid responses. @param dialogue_section: section of dialogue containing the L{DialogueResponses<DialogueResponse>} to process. @type dialogue_section: L{DialogueSection} @return: responses whose conditions were met. @rtype: list of L{DialogueResponses<DialogueResponse>} """ valid_responses = [] for dialogue_response in dialogue_section.responses: condition = dialogue_response.condition try: condition_met = condition is None or \ eval(condition, self.game_state) except (Exception,) as exception: error_message = dedent_chomp(''' evaluation of condition {condition} for {response} failed with error: {exception} ''').format(condition=dialogue_response.condition, response=dialogue_response, exception=exception) self._logger.error(error_message) else: self._logger.debug( 'condition "{0}" for {1} evaluated to {2}' .format(dialogue_response.condition, dialogue_response, condition_met) ) if (condition_met): valid_responses.append(dialogue_response) return valid_responses
def continueDialogue(self): """ Process the L{DialogueSection} at the top of the L{dialogue_section_stack}, run any L{DialogueActions<DialogueActions>} it contains and return a list of valid L{DialogueResponses<DialogueResponses> after evaluating any response conditionals. @returns: valid responses. @rtype: list of L{DialogueResponses<DialogueResponse>} @raise RuntimeError: Any preconditions are not met. @precondition: dialogue has been initiated via L{initiateDialogue}. """ if (not self.in_dialogue): error_message = dedent_chomp(''' dialogue has not be initiated via initiateDialogue yet ''') raise RuntimeError(error_message) current_dialogue_section = self.getCurrentDialogueSection() self.runDialogueActions(current_dialogue_section) valid_responses = self.getValidResponses(current_dialogue_section) return valid_responses
def getDialogueGreeting(self): """ Evaluate the L{RootDialogueSections<RootDialogueSection>} conditions and return the valid L{DialogueSection} which should be displayed first. @return: Valid root dialogue section. @rtype: L{DialogueSection} @raise: RuntimeError - evaluation of a DialogueGreeting condition fails by raising an exception (e.g. due to a syntax error). """ dialogue = self.dialogue dialogue_greeting = None for greeting in dialogue.greetings: try: condition_met = eval(greeting.condition, self.game_state) except Exception as exception: error_message = dedent_chomp(''' exception raised in DialogueGreeting {id} condition: {exception} ''').format(id=greeting.id, exception=exception) self._logger.error(error_message) if (condition_met): dialogue_greeting = greeting if (dialogue_greeting is None): dialogue_greeting = dialogue.default_greeting return dialogue_greeting
def setUp(self): TestDialogueProcessor.setUp(self) self.dialogue = Dialogue( npc_name='Mr. NPC', avatar_path='/some/path', default_greeting=DialogueSection( id_='greeting', text='This is the one (and only) dialogue section.', responses=[ DialogueResponse( text=dedent_chomp(''' A response that moves the dialogue to another_section. '''), next_section_id='another_section' ), DialogueResponse( text='A response that ends the dialogue.', next_section_id='end', ), ], ), sections=[ DialogueSection( id_='another_section', text='This is another section.', responses=[ DialogueResponse( text='A response that ends the dialogue', next_section_id='end', ) ], ), ] ) self.dialogue_processor = DialogueProcessor(self.dialogue, {})