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 *
RevLine 
[674]1#!/usr/bin/env python2
[343]2#   This file is part of PARPG.
[679]3#
[343]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.
[679]8#
[343]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.
[679]13#
[343]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/>.
[679]16"""
17A very simple demonstration of the dialogue engine used for testing dialogue
18files.
19"""
[668]20import logging
[679]21import os
[668]22import sys
[343]23
[679]24from scripts.common.optionparser import OptionParser, OptionError
[672]25from scripts.dialogueparsers import YamlDialogueParser
[668]26from scripts.dialogueengine import DialogueEngine
27from scripts.quest_engine import QuestEngine
28
[682]29PARPG_ROOT_DIR = os.path.dirname(__file__)
[679]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
[668]34def setup_logging():
[679]35    """Set various logging parameters for this module."""
[668]36    logging.basicConfig(filename='dialogue_demo.log')
37setup_logging()
38
[679]39class MockPlayerCharacter(object):
[343]40    """
[679]41    Mock object representing the player character.
[343]42    """
43    def __init__(self):
[679]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        """
[350]50        self.inventory = set(['beer'])
[679]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
[343]66
[350]67
[679]68class MockBeer(object):
69    """Mock object representing a 'beer' item."""
70    quality = 3
[350]71
72
[679]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
[350]90
91
[679]92def selectDialogueFile():
[343]93    """
[679]94    List all YAML dialogue files in the dialogue directory and prompt the user
95    to select one for testing.
[343]96    """
[682]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))
[679]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
[674]113   
[679]114    selected_file_path = os.path.join(DIALOGUE_DIR, selected_file_name)
115    return selected_file_path
[350]116
[668]117def getReply(dialogue_responses):
[679]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    """
[668]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]
[679]132        except (ValueError, IndexError):
133            print(('\ninvalid response, please enter an integer between 0 '
134                   'and {0}').format(len(dialogue_responses) - 1))
[668]135        else:
[350]136            break
[668]137   
138    return chosen_response
[350]139
[679]140def processDialogue(dialogue, game_state):
141    """
142    Process a L{Dialogue} until the user selects a response that ends it.
[673]143   
[679]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    """
[668]150    DialogueEngine.initiateDialogue(dialogue, game_state)
[673]151    npc_name = dialogue.npc_name
[668]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    ')
[679]156        print('\n{0}: {1}'.format(npc_name, dialogue_text))
[668]157        chosen_reply = getReply(responses)
158        DialogueEngine.reply(chosen_reply)
[343]159
[679]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
[343]170if __name__ == "__main__":
[679]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'),
[681]184        'pc': MockPlayerCharacter(),
[679]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.