source: branches/active/character_customization/game/dialogue_demo.py @ 833

Revision 813, 6.8 KB checked in by aspidites, 7 years ago (diff)

Patch by Aspidites:

-updated all calls to settings.paths to the more readable settings.system_path and settings.user_path properties

  • renamed sys_path to system_path for consistency
  • 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
23from optparse import OptionParser
24
25from parpg.dialogueparsers import YamlDialogueParser
26from parpg.dialogueprocessor import DialogueProcessor
27from parpg.quest_engine import QuestEngine
28from parpg.settings import Settings
29
30class MockPlayerCharacter(object):
31    """
32    Mock object representing the player character.
33    """
34    def __init__(self):
35        """
36        Initialize a new L{MockPlayerCharacter} instance.
37       
38        @ivar inventory: set of items carried by the L{MockPlayerCharacter}.
39        @ivar known_npcs: set of IDs for the NPCs the player has met.
40        """
41        self.inventory = set(['beer'])
42        self.known_npcs = set()
43   
44    def meet(self, npc_id):
45        """
46        Add an NPC to the list of NPCs known by the player.
47       
48        @param npc: ID of the NPC to add.
49        @type npc: str
50        """
51        if npc_id in self.known_npcs:
52            raise RuntimeError("I already know {0}".format(npc_id))
53        self.known_npcs.add(npc_id)
54   
55    def met(self, npc):
56        return npc in self.known_npcs
57
58
59class MockBeer(object):
60    """Mock object representing a 'beer' item."""
61    quality = 3
62
63
64class MockBox(object):
65    """Mock box object than can be opened or closed."""
66    def __init__(self):
67        """
68        Initialize a new {MockBox} instance.
69       
70        @ivar opened: whether the L{MockBox} has been "opened".
71        """
72        self.opened = False
73   
74    def open(self):
75        """Set the opened state of the L{MockBox} to True."""
76        self.opened = True
77   
78    def close(self):
79        """Set the opened state of the L{MockBox} to False."""
80        self.opened = False
81
82
83def selectDialogueFile(settings):
84    """
85    List all YAML dialogue files in the dialogue directory and prompt the user
86    to select one for testing.
87    """
88    dialogue_dir = os.path.join(settings.system_path, 
89                                settings.parpg.DialoguesDirectory)
90    dialogue_files = [file_name for file_name in os.listdir(dialogue_dir) 
91                      if file_name.endswith('.yaml')]
92    for index, file_name in enumerate(dialogue_files):
93        print('{0} - {1}'.format(index, file_name))
94    while True:
95        str_input = raw_input("> ")
96        try:
97            choice_n = int(str_input)
98            selected_file_name = dialogue_files[choice_n]
99        except (ValueError, IndexError):
100            print(('"{0}" is an invalid selection, please choose a number '
101                   'between 0 and {1}').format(str_input,
102                                               len(dialogue_files) - 1))
103            continue
104        else:
105            break
106   
107    selected_file_path = os.path.join(dialogue_dir, selected_file_name)
108    return selected_file_path
109
110def chooseReply(dialogue_responses):
111    """
112    Prompt the user to choose a L{DialogueResponse} from a list of valid
113    responses.
114   
115    @param dialogue_responses: valid responses to choose from
116    @type dialogue_responses: list of L{DialogueResponses}
117    """
118    while (True):
119        print('Available responses:')
120        for index, response in enumerate(dialogue_responses):
121            print('{0} - {1}'.format(index, response.text))
122        try:
123            chosen_response_n = int(raw_input('Choose a response number> '))
124            chosen_response = dialogue_responses[chosen_response_n]
125        except (ValueError, IndexError):
126            print(('\ninvalid response, please enter an integer between 0 '
127                   'and {0}').format(len(dialogue_responses) - 1))
128        else:
129            break
130   
131    return chosen_response
132
133def processDialogue(dialogue, game_state):
134    """
135    Process a L{Dialogue} until the user selects a response that ends it.
136   
137    @param dialogue: dialogue data to process.
138    @type dialogue: L{Dialogue}
139    @param game_state: objects that should be made available for response
140        conditional testing.
141    @type game_state: dict of objects
142    """
143    npc_name = dialogue.npc_name
144    dialogue_processor = DialogueProcessor(dialogue, game_state)
145    dialogue_processor.initiateDialogue()
146    while dialogue_processor.in_dialogue:
147        responses = dialogue_processor.continueDialogue()
148        current_dialogue_section = \
149            dialogue_processor.getCurrentDialogueSection()
150        dialogue_text = current_dialogue_section.text
151        # Indent dialogue text after the first line.
152        dialogue_text = dialogue_text.replace('\n', '\n    ')
153        print('\n{0}: {1}'.format(npc_name, dialogue_text))
154        chosen_reply = chooseReply(responses)
155        dialogue_processor.reply(chosen_reply)
156
157def main():
158    parser = OptionParser(description='Script for testing dialogue files')
159    parser.add_option('-s', '--settings', nargs=2,
160                      dest='paths', default=['.'],
161                      help='One or more paths to load settings from')
162    parser.add_option('-f', '--logfile',
163                        help='Name of log file to save to')
164    parser.add_option('-l', '--loglevel', default='critical',
165                    help='desired output level for log file')
166   
167    opts, args = parser.parse_args()
168
169    settings = Settings(*opts.paths)
170
171    levels = {'debug': logging.DEBUG,
172              'info': logging.INFO,
173              'warning': logging.WARNING,
174              'error': logging.ERROR,
175              'critical': logging.CRITICAL}
176
177    #TODO: setup formating
178    logging.basicConfig(filename=opts.logfile, level=levels[opts.loglevel])
179    logger = logging.getLogger('dialogue_demo')
180
181    try:
182        dialogue_file_path = args[0]
183    except IndexError:
184        logger.info('No dialogue file provided, generating a list..')
185        dialogue_file_path = selectDialogueFile(settings)
186
187    game_state = {
188        'quest': QuestEngine('quests'),
189        'pc': MockPlayerCharacter(),
190        'box': MockBox(),
191        'beer': MockBeer()
192    }
193    dialogue_parser = YamlDialogueParser()
194    with file(dialogue_file_path, 'r') as dialogue_file:
195        dialogue = dialogue_parser.load(dialogue_file)
196    processDialogue(dialogue, game_state)
197
198if __name__ == "__main__":
199    main()
Note: See TracBrowser for help on using the repository browser.