source: trunk/game/scripts/dialogue.py @ 684

Revision 684, 5.6 KB checked in by technomage, 9 years ago (diff)

Patch by Technomage

  • Refactored the DialogueEngine? singleton into the DialogueProcessor? instance factory, eliminating some of the problems the singleton pattern caused with encapsulation and unit testing.
  • Renamed the dialogueengine.py module to dialogueprocessor.py for clarity.
  • Added type-checking code to the instance variables defined by the DialogueProcessor? and Dialogue classes using assert statements that are removed when the optimization '-O' flag is passed to the Python interpreter.
  • Moved the 'main' logic in dialogue_demo.py script into a 'main' method to avoid cluttering the module namespace with runtime variables.
  • Fixed a few code documentation issues pointed out by aspidites.
  • Property svn:eol-style set to native
Line 
1#!/usr/bin/env python
2#
3#   This file is part of PARPG.
4#
5#   PARPG is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9#
10#   PARPG is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14#
15#   You should have received a copy of the GNU General Public License
16#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
17"""
18Provides classes used to contain and organize dialogue data for use within
19in-game dialogues between the player character and NPCs.
20"""
21try:
22    from collections import OrderedDict
23except ImportError:
24    # Python version 2.4-2.6 doesn't have the OrderedDict
25    from scripts.common.ordereddict import OrderedDict
26
27class Dialogue(object):
28    """
29    Represents a complete dialogue and acts as a container for the dialogue
30    data belonging to a particular NPC.
31    """
32    __slots__ = ['npc_name', 'avatar_path', 'start_section_id', 'sections']
33   
34    def __init__(self, npc_name, avatar_path, start_section_id,
35                 dialogue_sections=None):
36        """
37        Initialize a new L{Dialogue} instance.
38       
39        @param npc_name: name displayed for the NPC in the dialogue.
40        @type npc_name: basestring
41        @param avatar_path: path to the image that should be displayed as the
42            NPC's avatar.
43        @type avatar_path: basestring
44        @param start_section_id: ID of the L{DialogueSection} that should be
45            displayed when the dialogue is first initiated.
46        @type start_section_id: basestring
47        @param dialogue_sections: sections of dialogue that make up this
48            L{Dialogue} instance.
49        @type dialogue_sections: list of L{DialogueSections<DialogueSection>}
50        """
51        self.npc_name = npc_name
52        self.avatar_path = avatar_path
53        self.sections = OrderedDict()
54        if (dialogue_sections is not None):
55            for section in dialogue_sections:
56                self.sections[section.id] = section
57        assert start_section_id in self.sections.keys(), \
58            'start_section_id "{0}" not found in specified sections'\
59            .format(start_section_id)
60        self.start_section_id = start_section_id
61   
62    def __str__(self):
63        """Return the string representation of a L{Dialogue} instance."""
64        string_representation = (
65            ('Dialogue(npc_id={0.npc_name}, avatar_path={0.avatar_path}, '
66             'start_section_id={0.start_section_id}, ...)').format(self)
67        )
68        return string_representation
69
70
71class DialogueNode(object):
72    """
73    Abstract base class that represents a node or related group of attributes
74    within a Dialogue.
75    """
76    def __init__(self, text, actions=None):
77        """
78        Initialize a new L{DialogueNode} instance.
79       
80        @param text: textual content of the L{DialogueNode}.
81        @type text: basestring
82        @param actions: dialogue actions associated with the L{DialogueNode}.
83        @type actions: list of L{DialogueActions<DialogueAction>}
84        """
85        self.text = text
86        self.actions = actions or []
87
88
89class DialogueSection(DialogueNode):
90    """DialogueNode that represents a distinct section of the dialogue."""
91    __slots__ = ['id', 'text', 'actions', 'responses']
92   
93    def __init__(self, id, text, responses=None, actions=None):
94        """
95        Initialize a new L{DialogueSection} instance.
96       
97        @param id: named used to uniquely identify the L{DialogueSection}
98            within a L{Dialogue}.
99        @type id: basestring
100        @param text: text displayed as the NPC's part of the L{Dialogue}.
101        @type text: basestring
102        @param responses: possible responses that the player can choose from.
103        @type responses: list of L{DialogueResponses<DialogueResponse>}
104        @param actions: dialogue actions that should be executed when the
105            L{DialogueSection} is reached.
106        @type actions: list of L{DialogueActions<DialogueAction>}
107        """
108        DialogueNode.__init__(self, text=text, actions=actions)
109        self.id = id
110        if (responses is not None):
111            self.responses = list(responses)
112
113
114class DialogueResponse(DialogueNode):
115    """
116    L{DialogueNode} that represents one possible player response to a
117    particular L{DialogueSection}.
118    """
119    __slots__ = ['text', 'actions', 'condition', 'next_section_id']
120   
121    def __init__(self, text, next_section_id, actions=None,
122                 condition=None):
123        """
124        Initialize a new L{DialogueResponse} instance.
125       
126        @param text: text displayed as the content of the player's response.
127        @type text: basestring
128        @param next_section_id: ID of the L{DialogueSection} that should be
129            jumped to if this response is chosen by the player.
130        @type next_section_id: basestring
131        @param actions: dialogue actions that should be executed if this
132            response is chosen by the player.
133        @type actions: list of L{DialogueActions<DialogueAction>}
134        @param condition: Python expression that when evaluated determines
135            whether the L{DialogueResponse} should be displayed to the player
136            as a valid response.
137        @type condition: basestring
138        """
139        DialogueNode.__init__(self, text=text, actions=actions)
140        self.condition = condition
141        self.next_section_id = next_section_id
Note: See TracBrowser for help on using the repository browser.