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, {})