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

Revision 736, 6.7 KB checked in by aspidites, 9 years ago (diff)

Patch by Aspidites:

  • renamed scripts package to parpg
  • renamed parpg module to application
  • removed packaging and other related files (kept locally for reference, will reintroduce similar scripts to resolve bug #275
  • updated all import statements to respect changes above
  • 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 parpg.common.optionparser import OptionParser, OptionError
25from parpg.dialogueparsers import YamlDialogueParser
26from parpg.dialogueprocessor import DialogueProcessor
27from parpg.quest_engine import QuestEngine
28
29def setupLogging():
30    """Set various logging parameters for this module."""
31    logging.basicConfig(filename='dialogue_demo.log')
32setupLogging()
33
34PARPG_ROOT_DIR = os.path.dirname(__file__)
35"""Absolute path to the root of the PARPG installation."""
36DIALOGUE_DIR = os.path.join(PARPG_ROOT_DIR, 'dialogue')
37"""Absolute path to the dialogue directory of the PARPG installation."""
38USAGE_MESSAGE = '''\
39usage: dialogue_demo.py [-h] [dialogue_file]
40Script for testing dialogue files.
41
42-h, --help                  Show this help message.
43dialogue_file               YAML file containing a dialogue; if not specified,
44                                the user will be prompted to choose a dialogue
45                                file from the dialogue directory.
46'''
47
48class MockPlayerCharacter(object):
49    """
50    Mock object representing the player character.
51    """
52    def __init__(self):
53        """
54        Initialize a new L{MockPlayerCharacter} instance.
55       
56        @ivar inventory: set of items carried by the L{MockPlayerCharacter}.
57        @ivar known_npcs: set of IDs for the NPCs the player has met.
58        """
59        self.inventory = set(['beer'])
60        self.known_npcs = set()
61   
62    def meet(self, npc_id):
63        """
64        Add an NPC to the list of NPCs known by the player.
65       
66        @param npc: ID of the NPC to add.
67        @type npc: str
68        """
69        if npc_id in self.known_npcs:
70            raise RuntimeError("I already know {0}".format(npc_id))
71        self.known_npcs.add(npc_id)
72   
73    def met(self, npc):
74        return npc in self.known_npcs
75
76
77class MockBeer(object):
78    """Mock object representing a 'beer' item."""
79    quality = 3
80
81
82class MockBox(object):
83    """Mock box object than can be opened or closed."""
84    def __init__(self):
85        """
86        Initialize a new {MockBox} instance.
87       
88        @ivar opened: whether the L{MockBox} has been "opened".
89        """
90        self.opened = False
91   
92    def open(self):
93        """Set the opened state of the L{MockBox} to True."""
94        self.opened = True
95   
96    def close(self):
97        """Set the opened state of the L{MockBox} to False."""
98        self.opened = False
99
100
101def selectDialogueFile():
102    """
103    List all YAML dialogue files in the dialogue directory and prompt the user
104    to select one for testing.
105    """
106    dialogue_files = [file_name for file_name in os.listdir(DIALOGUE_DIR) 
107                      if file_name.endswith('.yaml')]
108    for index, file_name in enumerate(dialogue_files):
109        print('{0} - {1}'.format(index, file_name))
110    while True:
111        str_input = raw_input("> ")
112        try:
113            choice_n = int(str_input)
114            selected_file_name = dialogue_files[choice_n]
115        except (ValueError, IndexError):
116            print(('"{0}" is an invalid selection, please choose a number '
117                   'between 0 and {1}').format(str_input,
118                                               len(dialogue_files) - 1))
119            continue
120        else:
121            break
122   
123    selected_file_path = os.path.join(DIALOGUE_DIR, selected_file_name)
124    return selected_file_path
125
126def chooseReply(dialogue_responses):
127    """
128    Prompt the user to choose a L{DialogueResponse} from a list of valid
129    responses.
130   
131    @param dialogue_responses: valid responses to choose from
132    @type dialogue_responses: list of L{DialogueResponses}
133    """
134    while (True):
135        print('Available responses:')
136        for index, response in enumerate(dialogue_responses):
137            print('{0} - {1}'.format(index, response.text))
138        try:
139            chosen_response_n = int(raw_input('Choose a response number> '))
140            chosen_response = dialogue_responses[chosen_response_n]
141        except (ValueError, IndexError):
142            print(('\ninvalid response, please enter an integer between 0 '
143                   'and {0}').format(len(dialogue_responses) - 1))
144        else:
145            break
146   
147    return chosen_response
148
149def processDialogue(dialogue, game_state):
150    """
151    Process a L{Dialogue} until the user selects a response that ends it.
152   
153    @param dialogue: dialogue data to process.
154    @type dialogue: L{Dialogue}
155    @param game_state: objects that should be made available for response
156        conditional testing.
157    @type game_state: dict of objects
158    """
159    npc_name = dialogue.npc_name
160    dialogue_processor = DialogueProcessor(dialogue, game_state)
161    dialogue_processor.initiateDialogue()
162    while dialogue_processor.in_dialogue:
163        responses = dialogue_processor.continueDialogue()
164        current_dialogue_section = \
165            dialogue_processor.getCurrentDialogueSection()
166        dialogue_text = current_dialogue_section.text
167        # Indent dialogue text after the first line.
168        dialogue_text = dialogue_text.replace('\n', '\n    ')
169        print('\n{0}: {1}'.format(npc_name, dialogue_text))
170        chosen_reply = chooseReply(responses)
171        dialogue_processor.reply(chosen_reply)
172
173def main(argv=sys.argv):
174    option_parser = OptionParser(usage=USAGE_MESSAGE)
175    for option in option_parser:
176        if (option in ['-h', '--help']):
177            print(option_parser.usage)
178            sys.exit(0)
179        else:
180            option_parser.error('unrecognized option "{0}"'.format(option))
181    try:
182        dialogue_file_path = option_parser.get_next_prog_arg()
183    except OptionError:
184        dialogue_file_path = selectDialogueFile()
185    game_state = {
186        'quest': QuestEngine('quests'),
187        'pc': MockPlayerCharacter(),
188        'box': MockBox(),
189        'beer': MockBeer()
190    }
191    dialogue_parser = YamlDialogueParser()
192    with file(dialogue_file_path, 'r') as dialogue_file:
193        dialogue = dialogue_parser.load(dialogue_file)
194    processDialogue(dialogue, game_state)
195
196if __name__ == "__main__":
197    main()
Note: See TracBrowser for help on using the repository browser.