[287] | 1 | # This file is part of PARPG. |
---|
| 2 | |
---|
| 3 | # PARPG is free software: you can redistribute it and/or modify |
---|
| 4 | # it under the terms of the GNU General Public License as published by |
---|
| 5 | # the Free Software Foundation, either version 3 of the License, or |
---|
| 6 | # (at your option) any later version. |
---|
| 7 | |
---|
| 8 | # PARPG is distributed in the hope that it will be useful, |
---|
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 11 | # GNU General Public License for more details. |
---|
| 12 | |
---|
| 13 | # You should have received a copy of the GNU General Public License |
---|
| 14 | # along with PARPG. If not, see <http://www.gnu.org/licenses/>. |
---|
[668] | 15 | import logging |
---|
[287] | 16 | |
---|
[473] | 17 | from fife import fife |
---|
| 18 | from fife.extensions import pychan |
---|
| 19 | from fife.extensions.pychan import widgets |
---|
| 20 | |
---|
[736] | 21 | from parpg.dialogueprocessor import DialogueProcessor |
---|
[287] | 22 | |
---|
[797] | 23 | logger = logging.getLogger('dialoguegui') |
---|
[668] | 24 | |
---|
[361] | 25 | class DialogueGUI(object): |
---|
[680] | 26 | """Window that handles the dialogues.""" |
---|
| 27 | _logger = logging.getLogger('dialoguegui.DialogueGUI') |
---|
[668] | 28 | |
---|
[575] | 29 | def __init__(self, controller, npc, quest_engine, player_character): |
---|
[632] | 30 | self.active = False |
---|
[668] | 31 | self.controller = controller |
---|
| 32 | self.dialogue_gui = pychan.loadXML("gui/dialogue.xml") |
---|
[287] | 33 | self.npc = npc |
---|
[668] | 34 | # TODO Technomage 2010-11-10: the QuestEngine should probably be |
---|
| 35 | # a singleton-like object, which would avoid all of this instance |
---|
| 36 | # handling. |
---|
| 37 | self.quest_engine = quest_engine |
---|
| 38 | self.player_character = player_character |
---|
| 39 | |
---|
[287] | 40 | def initiateDialogue(self): |
---|
| 41 | """Callback for starting a quest""" |
---|
[632] | 42 | self.active = True |
---|
[287] | 43 | stats_label = self.dialogue_gui.findChild(name='stats_label') |
---|
[415] | 44 | stats_label.text = u'Name: John Doe\nAn unnamed one' |
---|
[287] | 45 | events = { |
---|
| 46 | 'end_button': self.handleEnd |
---|
| 47 | } |
---|
| 48 | self.dialogue_gui.mapEvents(events) |
---|
| 49 | self.dialogue_gui.show() |
---|
[668] | 50 | self.setNpcName(self.npc.name) |
---|
[670] | 51 | self.setAvatarImage(self.npc.dialogue.avatar_path) |
---|
[668] | 52 | |
---|
| 53 | game_state = {'npc': self.npc, 'pc': self.player_character, |
---|
| 54 | 'quest': self.quest_engine} |
---|
[684] | 55 | try: |
---|
| 56 | self.dialogue_processor = DialogueProcessor(self.npc.dialogue, |
---|
| 57 | game_state) |
---|
| 58 | self.dialogue_processor.initiateDialogue() |
---|
| 59 | except (TypeError) as error: |
---|
| 60 | self._logger.error(str(error)) |
---|
| 61 | else: |
---|
| 62 | self.continueDialogue() |
---|
[668] | 63 | |
---|
| 64 | def setDialogueText(self, text): |
---|
| 65 | """Set the displayed dialogue text. |
---|
| 66 | @param text: text to display.""" |
---|
| 67 | text = unicode(text) |
---|
[287] | 68 | speech = self.dialogue_gui.findChild(name='speech') |
---|
| 69 | # to append text to npc speech box, uncomment the following line |
---|
| 70 | #speech.text = speech.text + "\n-----\n" + unicode(say) |
---|
[668] | 71 | speech.text = text |
---|
[680] | 72 | self._logger.debug('set dialogue text to "{0}"'.format(text)) |
---|
[668] | 73 | |
---|
| 74 | def continueDialogue(self): |
---|
| 75 | """Display the dialogue text and responses for the current |
---|
| 76 | L{DialogueSection}.""" |
---|
[684] | 77 | dialogue_processor = self.dialogue_processor |
---|
| 78 | dialogue_text = dialogue_processor.getCurrentDialogueSection().text |
---|
[668] | 79 | self.setDialogueText(dialogue_text) |
---|
[684] | 80 | self.responses = dialogue_processor.continueDialogue() |
---|
[668] | 81 | self.setResponses(self.responses) |
---|
| 82 | |
---|
[287] | 83 | def handleEntered(self, *args): |
---|
[668] | 84 | """Callback for when user hovers over response label.""" |
---|
[287] | 85 | pass |
---|
[668] | 86 | |
---|
[287] | 87 | def handleExited(self, *args): |
---|
[668] | 88 | """Callback for when user hovers out of response label.""" |
---|
[287] | 89 | pass |
---|
[668] | 90 | |
---|
[287] | 91 | def handleClicked(self, *args): |
---|
[668] | 92 | """Handle a response being clicked.""" |
---|
| 93 | response_n = int(args[0].name.replace('response', '')) |
---|
| 94 | response = self.responses[response_n] |
---|
[684] | 95 | dialogue_processor = self.dialogue_processor |
---|
| 96 | dialogue_processor.reply(response) |
---|
| 97 | if (not dialogue_processor.in_dialogue): |
---|
[287] | 98 | self.handleEnd() |
---|
[668] | 99 | else: |
---|
| 100 | self.continueDialogue() |
---|
| 101 | |
---|
[287] | 102 | def handleEnd(self): |
---|
[668] | 103 | """Handle the end of the conversation being reached, either from the |
---|
[287] | 104 | GUI or from within the conversation itself.""" |
---|
| 105 | self.dialogue_gui.hide() |
---|
[668] | 106 | self.responses = [] |
---|
[287] | 107 | self.npc.behaviour.state = 1 |
---|
| 108 | self.npc.behaviour.idle() |
---|
[632] | 109 | self.active = False |
---|
[668] | 110 | |
---|
| 111 | def setNpcName(self, name): |
---|
| 112 | """Set the NPC name to display on the dialogue GUI. |
---|
| 113 | @param name: name of the NPC to set |
---|
| 114 | @type name: basestring""" |
---|
| 115 | name = unicode(name) |
---|
[415] | 116 | stats_label = self.dialogue_gui.findChild(name='stats_label') |
---|
| 117 | try: |
---|
[575] | 118 | (first_name, desc) = name.split(" ", 1) |
---|
[415] | 119 | stats_label.text = u'Name: ' + first_name + "\n" + desc |
---|
[668] | 120 | except ValueError: |
---|
| 121 | stats_label.text = u'Name: ' + name |
---|
| 122 | |
---|
[415] | 123 | self.dialogue_gui.title = name |
---|
[680] | 124 | self._logger.debug('set NPC name to "{0}"'.format(name)) |
---|
[668] | 125 | |
---|
| 126 | def setAvatarImage(self, image_path): |
---|
| 127 | """Set the NPC avatar image to display on the dialogue GUI |
---|
| 128 | @param image_path: filepath to the avatar image |
---|
| 129 | @type image_path: basestring""" |
---|
[288] | 130 | avatar_image = self.dialogue_gui.findChild(name='npc_avatar') |
---|
[668] | 131 | avatar_image.image = image_path |
---|
| 132 | |
---|
| 133 | def setResponses(self, dialogue_responses): |
---|
[287] | 134 | """Creates the list of clickable response labels and sets their |
---|
[668] | 135 | respective on-click callbacks. |
---|
| 136 | @param responses: list of L{DialogueResponses} from the |
---|
[684] | 137 | L{DialogueProcessor} |
---|
[668] | 138 | @type responses: list of L{DialogueResponses}""" |
---|
[287] | 139 | choices_list = self.dialogue_gui.findChild(name='choices_list') |
---|
| 140 | choices_list.removeAllChildren() |
---|
[668] | 141 | for index, response in enumerate(dialogue_responses): |
---|
[287] | 142 | button = widgets.Label( |
---|
[668] | 143 | name="response{0}".format(index), |
---|
| 144 | text=unicode(response.text), |
---|
[287] | 145 | hexpand="1", |
---|
| 146 | min_size=(100,16), |
---|
| 147 | max_size=(490,48), |
---|
| 148 | position_technique='center:center' |
---|
| 149 | ) |
---|
[575] | 150 | button.margins = (5, 5) |
---|
| 151 | button.background_color = fife.Color(0, 0, 0) |
---|
| 152 | button.color = fife.Color(0, 255, 0) |
---|
[287] | 153 | button.border_size = 0 |
---|
| 154 | button.wrap_text = 1 |
---|
[668] | 155 | button.capture(lambda button=button: self.handleEntered(button), |
---|
[312] | 156 | event_name='mouseEntered') |
---|
[668] | 157 | button.capture(lambda button=button: self.handleExited(button), |
---|
[312] | 158 | event_name='mouseExited') |
---|
[668] | 159 | button.capture(lambda button=button: self.handleClicked(button), |
---|
[312] | 160 | event_name='mouseClicked') |
---|
[287] | 161 | choices_list.addChild(button) |
---|
| 162 | self.dialogue_gui.adaptLayout(True) |
---|
[680] | 163 | self._logger.debug( |
---|
[668] | 164 | 'added {0} to response choice list'.format(response) |
---|
| 165 | ) |
---|