source: trunk/game/dialogue_demo.py @ 683

Revision 682, 6.5 KB checked in by technomage, 9 years ago (diff)

Patch by aspidites

  • Clarified the PARPG path constants in the dialogue_demo.py script.
  • Significantly simplified the selectDialogueFile method in the dialogue_demo.py script.
  • Property svn:executable set to *
Line 
1#!/usr/bin/env python2
2#   This file is part of PARPG.
3#
4#   PARPG is free software: you can redistribute it and/or modify
5#   it under the terms of the GNU General Public License as published by
6#   the Free Software Foundation, either version 3 of the License, or
7#   (at your option) any later version.
8#
9#   PARPG is distributed in the hope that it will be useful,
10#   but WITHOUT ANY WARRANTY; without even the implied warranty of
11#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12#   GNU General Public License for more details.
13#
14#   You should have received a copy of the GNU General Public License
15#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
16"""
17A very simple demonstration of the dialogue engine used for testing dialogue
18files.
19"""
20import logging
21import os
22import sys
23
24from scripts.common.optionparser import OptionParser, OptionError
25from scripts.dialogueparsers import YamlDialogueParser
26from scripts.dialogueengine import DialogueEngine
27from scripts.quest_engine import QuestEngine
28
29PARPG_ROOT_DIR = os.path.dirname(__file__)
30"""Absolute path to the root of the PARPG installation."""
31DIALOGUE_DIR = os.path.join(PARPG_ROOT_DIR, 'dialogue')
32"""Absolute path to the dialogue directory of the PARPG installation."""
33
34def setup_logging():
35    """Set various logging parameters for this module."""
36    logging.basicConfig(filename='dialogue_demo.log')
37setup_logging()
38
39class MockPlayerCharacter(object):
40    """
41    Mock object representing the player character.
42    """
43    def __init__(self):
44        """
45        Initialize a new L{MockPlayerCharacter} instance.
46       
47        @ivar inventory: set of items carried by the L{MockPlayerCharacter}.
48        @ivar known_npcs: set of IDs for the NPCs the player has met.
49        """
50        self.inventory = set(['beer'])
51        self.known_npcs = set()
52   
53    def meet(self, npc_id):
54        """
55        Add an NPC to the list of NPCs known by the player.
56       
57        @param npc: ID of the NPC to add.
58        @type npc: str
59        """
60        if npc_id in self.known_npcs:
61            raise RuntimeError("I already know {0}".format(npc_id))
62        self.known_npcs.add(npc_id)
63   
64    def met(self, npc):
65        return npc in self.known_npcs
66
67
68class MockBeer(object):
69    """Mock object representing a 'beer' item."""
70    quality = 3
71
72
73class MockBox(object):
74    """Mock box object than can be opened or closed."""
75    def __init__(self):
76        """
77        Initialize a new {MockBox} instance.
78       
79        @ivar opened: whether the L{MockBox} has been "opened".
80        """
81        self.opened = False
82   
83    def open(self):
84        """Set the opened state of the L{MockBox} to True."""
85        self.opened = True
86   
87    def close(self):
88        """Set the opened state of the L{MockBox} to False."""
89        self.opened = False
90
91
92def selectDialogueFile():
93    """
94    List all YAML dialogue files in the dialogue directory and prompt the user
95    to select one for testing.
96    """
97    dialogue_files = [file_name for file_name in os.listdir(DIALOGUE_DIR) 
98                      if file_name.endswith('.yaml')]
99    for index, file_name in enumerate(dialogue_files):
100        print('{0} - {1}'.format(index, file_name))
101    while True:
102        str_input = raw_input("> ")
103        try:
104            choice_n = int(str_input)
105            selected_file_name = dialogue_files[choice_n]
106        except (ValueError, IndexError):
107            print(('"{0}" is an invalid selection, please choose a number '
108                   'between 0 and {1}').format(str_input,
109                                               len(dialogue_files) - 1))
110            continue
111        else:
112            break
113   
114    selected_file_path = os.path.join(DIALOGUE_DIR, selected_file_name)
115    return selected_file_path
116
117def getReply(dialogue_responses):
118    """
119    Prompt the user to choose a L{DialogueResponse} from a list of valid
120    responses.
121   
122    @param dialogue_responses: valid responses to choose from
123    @type dialogue_responses: list of L{DialogueResponses}
124    """
125    while (True):
126        print('Available responses:')
127        for index, response in enumerate(dialogue_responses):
128            print('{0} - {1}'.format(index, response.text))
129        try:
130            chosen_response_n = int(raw_input('Choose a response number> '))
131            chosen_response = dialogue_responses[chosen_response_n]
132        except (ValueError, IndexError):
133            print(('\ninvalid response, please enter an integer between 0 '
134                   'and {0}').format(len(dialogue_responses) - 1))
135        else:
136            break
137   
138    return chosen_response
139
140def processDialogue(dialogue, game_state):
141    """
142    Process a L{Dialogue} until the user selects a response that ends it.
143   
144    @param dialogue: dialogue data to process.
145    @type dialogue: L{Dialogue}
146    @param game_state: objects that should be made available for response
147        conditional testing.
148    @type game_state: dict of objects
149    """
150    DialogueEngine.initiateDialogue(dialogue, game_state)
151    npc_name = dialogue.npc_name
152    while DialogueEngine.in_dialogue:
153        responses = DialogueEngine.continueDialogue()
154        current_dialogue_section = DialogueEngine.getCurrentDialogueSection()
155        dialogue_text = current_dialogue_section.text.replace('\n', '\n    ')
156        print('\n{0}: {1}'.format(npc_name, dialogue_text))
157        chosen_reply = getReply(responses)
158        DialogueEngine.reply(chosen_reply)
159
160usage_message='''\
161usage: dialogue_demo.py [-h] [dialogue_file]
162Script for testing dialogue files.
163
164-h, --help                  Show this help message.
165dialogue_file               YAML file containing a dialogue; if not specified,
166                                the user will be prompted to choose a dialogue
167                                file from the dialogue directory.
168'''
169
170if __name__ == "__main__":
171    option_parser = OptionParser(usage=usage_message)
172    for option in option_parser:
173        if (option in ['-h', '--help']):
174            print(option_parser.usage)
175            sys.exit(0)
176        else:
177            option_parser.error('unrecognized option "{0}"'.format(option))
178    try:
179        dialogue_file_path = option_parser.get_next_prog_arg()
180    except OptionError:
181        dialogue_file_path = selectDialogueFile()
182    game_state = {
183        'quest': QuestEngine('quests'),
184        'pc': MockPlayerCharacter(),
185        'box': MockBox(),
186        'beer': MockBeer()
187    }
188    dialogue_parser = YamlDialogueParser()
189    with file(dialogue_file_path, 'r') as dialogue_file:
190        dialogue = dialogue_parser.load(dialogue_file)
191    processDialogue(dialogue, game_state)
Note: See TracBrowser for help on using the repository browser.