Mercurial > parpg-source
diff dialogue.py @ 0:7a89ea5404b1
Initial commit of parpg-core.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Sat, 14 May 2011 01:12:35 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dialogue.py Sat May 14 01:12:35 2011 -0700 @@ -0,0 +1,192 @@ +# This file is part of PARPG. +# +# PARPG is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PARPG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PARPG. If not, see <http://www.gnu.org/licenses/>. +""" +Provides classes used to contain and organize dialogue data for use within +in-game dialogues between the player character and NPCs. +""" +try: + from collections import OrderedDict +except ImportError: + # Python version 2.4-2.6 doesn't have the OrderedDict + from parpg.common.ordereddict import OrderedDict + +class Dialogue(object): + """ + Represents a complete dialogue and acts as a container for the dialogue + data belonging to a particular NPC. + """ + __slots__ = ['npc_name', 'avatar_path', 'default_greeting', + 'greetings', 'sections'] + + def __init__(self, npc_name, avatar_path, default_greeting, greetings=None, + sections=None): + """ + Initialize a new L{Dialogue} instance. + + @param npc_name: name displayed for the NPC in the dialogue. + @type npc_name: basestring + @param avatar_path: path to the image that should be displayed as the + NPC's avatar. + @type avatar_path: basestring + @param default_greeting: section of dialogue that should be + displayed when the dialogue is first initiated and no other start + sections are available. + @type default_greeting: L{DialogueSection} + @param greetings: sections of dialogue defining the conditions + under which each should be displayed when the dialogue is first + initiated. + @type greetings: list of + L{RootDialogueSections<DialogueGreeting>} + @param sections: sections of dialogue that make up this + L{Dialogue} instance. + @type sections: list of L{DialogueSections<DialogueSection>} + """ + self.npc_name = npc_name + self.avatar_path = avatar_path + self.default_greeting = default_greeting + self.greetings = greetings if greetings is not None else [] + self.sections = OrderedDict() + all_sections = [default_greeting] + if (greetings is not None): + all_sections += greetings + if (sections is not None): + all_sections += sections + if (__debug__): + section_ids = [section.id for section in all_sections] + for section in all_sections: + # Sanity check: All DialogueResponses should have next_section_id + # attributes that refer to valid DialogueSections in the Dialogue. + if (__debug__): + for response in section.responses: + assert response.next_section_id in section_ids + \ + ['end', 'back'], ('"{0}" does not refer to a ' + 'DialogueSection in this Dialogue')\ + .format(response.next_section_id) + self.sections[section.id] = section + + def __str__(self): + """Return the string representation of a L{Dialogue} instance.""" + string_representation = 'Dialogue(npc_id={0.npc_name})'.format(self) + return string_representation + + +class DialogueNode(object): + """ + Abstract base class that represents a node or related group of attributes + within a Dialogue. + """ + def __init__(self, text, actions=None): + """ + Initialize a new L{DialogueNode} instance. + + @param text: textual content of the L{DialogueNode}. + @type text: basestring + @param actions: dialogue actions associated with the L{DialogueNode}. + @type actions: list of L{DialogueActions<DialogueAction>} + """ + self.text = text + self.actions = actions or [] + + +class DialogueSection(DialogueNode): + """DialogueNode that represents a distinct section of the dialogue.""" + __slots__ = ['id', 'text', 'responses', 'actions'] + + def __init__(self, id_, text, responses=None, actions=None): + """ + Initialize a new L{DialogueSection} instance. + + @param id_: named used to uniquely identify the L{DialogueSection} + within a L{Dialogue}. + @type id_: basestring + @param text: text displayed as the NPC's part of the L{Dialogue}. + @type text: basestring + @param responses: possible responses that the player can choose from. + @type responses: list of L{DialogueResponses<DialogueResponse>} + @param actions: dialogue actions that should be executed when the + L{DialogueSection} is reached. + @type actions: list of L{DialogueActions<DialogueAction>} + """ + DialogueNode.__init__(self, text=text, actions=actions) + self.id = id_ + if (responses is not None): + self.responses = list(responses) + + +class DialogueGreeting(DialogueSection): + """ + Represents a root section of dialogue in a L{Dialogue} along with the + conditional statement used to determine the whether this section should be + displayed first upon dialogue initiation. + + @ivar id: Name used to uniquely identify the L{DialogueSection} to which + the L{DialogueRootSectionReference} points. + @type id: basestring + @ivar condition: Boolean Python expression used to determine if the + L{DialogueSection} referenced is a valid starting section. + @type condition: basestring + """ + __slots__ = ['id', 'condition', 'text', 'actions', 'responses'] + + def __init__(self, id_, condition, text, responses=None, actions=None): + """ + Initialize a new L{DialogueGreeting} instance. + + @param id_: named used to uniquely identify the L{DialogueSection} + within a L{Dialogue}. + @type id_: basestring + @param condition: Boolean Python expression used to determine if this + root dialogue section should be displayed. + @type condition: basestring + @param text: text displayed as the NPC's part of the L{Dialogue}. + @type text: basestring + @param responses: possible responses that the player can choose from. + @type responses: list of L{DialogueResponses<DialogueResponse>} + @param actions: dialogue actions that should be executed when the + L{DialogueSection} is reached. + @type actions: list of L{DialogueActions<DialogueAction>} + """ + DialogueSection.__init__(self, id_=id_, text=text, responses=responses, + actions=actions) + self.condition = condition + + +class DialogueResponse(DialogueNode): + """ + L{DialogueNode} that represents one possible player response to a + particular L{DialogueSection}. + """ + __slots__ = ['text', 'actions', 'condition', 'next_section_id'] + + def __init__(self, text, next_section_id, actions=None, condition=None): + """ + Initialize a new L{DialogueResponse} instance. + + @param text: text displayed as the content of the player's response. + @type text: basestring + @param next_section_id: ID of the L{DialogueSection} that should be + jumped to if this response is chosen by the player. + @type next_section_id: basestring + @param actions: dialogue actions that should be executed if this + response is chosen by the player. + @type actions: list of L{DialogueActions<DialogueAction>} + @param condition: Python expression that when evaluated determines + whether the L{DialogueResponse} should be displayed to the player + as a valid response. + @type condition: basestring + """ + DialogueNode.__init__(self, text=text, actions=actions) + self.condition = condition + self.next_section_id = next_section_id