source: trunk/game/scripts/gui/hud.py @ 600

Revision 600, 16.8 KB checked in by beliar, 9 years ago (diff)

Patch by Beliar.

  • Dropping items menu action now only shows when right-clicking on an item in the players inventory
  • Actions that are supposed to happen when a key is pressed now work again.
  • Property svn:eol-style set to native
Line 
1#!/usr/bin/env python
2
3#   This file is part of PARPG.
4
5#   PARPG is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9
10#   PARPG is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14
15#   You should have received a copy of the GNU General Public License
16#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
17
18from fife.extensions import pychan
19from fife.extensions.pychan.tools import callbackWithArguments as cbwa
20
21from scripts.gui.filebrowser import FileBrowser
22from scripts.gui.context_menu import ContextMenu
23from scripts.gui import inventorygui
24from scripts.gui.popups import ExaminePopup
25from scripts.gui.containergui import ContainerGUI
26from scripts.gui.dialoguegui import DialogueGUI
27
28class Hud(object):
29    """Main Hud class"""
30    def __init__(self, controller, settings, callbacks):
31        """Initialise the instance.
32           @type controller: Class derived from ControllerBase
33           @param controller: The current controller
34           @type settings: settings.Setting
35           @param settings: The settings
36           @type inv_model: dict
37           @type callbacks: dict
38           @param callbacks: a dict of callbacks
39               saveGame: called when the user clicks on Save
40               loadGame: called when the user clicks on Load
41               quitGame: called when the user clicks on Quit
42           @return: None"""
43        pychan.init(controller.engine, debug = True)
44
45        # TODO: perhaps this should not be hard-coded here
46        self.hud = pychan.loadXML("gui/hud.xml")
47        self.controller = controller
48        self.engine = controller.engine
49        self.model = controller.model
50        self.settings = settings
51        self.inventory = None
52
53        self.save_game_callback = callbacks['saveGame']
54        self.load_game_callback = callbacks['loadGame']
55        self.quit_callback      = callbacks['quitGame']
56
57        self.box_container = None
58        self.examine_box = None
59        self.context_menu = None
60        self.help_dialog = None
61        self.events_to_map = None
62        self.main_menu = None
63        self.menu_events = None
64        self.quit_window = None
65       
66        self.actions_box = self.hud.findChild(name="actionsBox")
67        #self.actions_text = ""
68        self.menu_displayed = False
69        self.inventory_storage = None
70        self.initializeHud()
71        self.initializeMainMenu()
72        self.initializeContextMenu()
73        self.initializeHelpMenu()
74        self.initializeEvents()
75        self.initializeQuitDialog()
76
77    def initializeHud(self):
78        """Initialize and show the main HUD
79           @return: None"""
80        self.events_to_map = {"menuButton":self.displayMenu, }
81        self.hud.mapEvents(self.events_to_map) 
82        # set HUD size according to screen size
83        screen_width = self.engine.getSettings().getScreenWidth()
84        self.hud.findChild(name="mainHudWindow").size = (screen_width, 65)
85        self.hud.findChild(name="inventoryButton").position = \
86                                                    (screen_width-59, 7)
87        # add ready slots
88        ready1 = self.hud.findChild(name='hudReady1')
89        ready2 = self.hud.findChild(name='hudReady2')
90        ready3 = self.hud.findChild(name='hudReady3')
91        ready4 = self.hud.findChild(name='hudReady4')
92        actions_scroll_area = self.hud.findChild(name='actionsScrollArea')
93
94        if (screen_width <=800) :
95            gap = 0
96        else :
97            gap = 40
98        ready1.position = (160+gap, 7)
99        ready2.position = (220+gap, 7)
100        ready3.position = (screen_width-180-gap, 7)
101        ready4.position = (screen_width-120-gap, 7)
102        actions_scroll_area.position = (280+gap, 5)
103        actions_width = screen_width - 470 - 2*gap
104
105        self.actions_box.min_width = actions_width
106        self.actions_box.max_width = actions_width
107       
108        # and finally add an actions box
109        actions_scroll_area.min_size = (actions_width, 55)
110        actions_scroll_area.max_size = (actions_width, 55)
111        # now it should be OK to display it all
112        self.hud.show()
113
114    def refreshActionsBox(self):
115        """Refresh the actions box so that it displays the contents of
116           self.actions_text
117           @return: None"""
118        self.actions_box.adaptLayout()
119        self.actions_box.parent.adaptLayout()
120
121    def addAction(self, action):
122        """Add an action to the actions box.
123           @type action: (unicode) string
124           @param action: The text that you want to display in the actions box
125           @return: None"""       
126        if not type(action) is unicode:
127            action = unicode(action)
128        action_label = pychan.widgets.Label(text = action, wrap_text = True)
129        action_label.max_width = self.actions_box.width
130        self.actions_box.insertChild(action_label, 0)
131        self.refreshActionsBox()
132
133    def showHUD(self):
134        """Show the HUD.
135           @return: None"""
136        self.hud.show()
137
138    def hideHUD(self):
139        """Hide the HUD.
140           @return: None"""
141        self.hud.hide()
142
143    def initializeInventory(self):
144        """Initialize the inventory"""
145        inv_callbacks = {
146            'refreshReadyImages': self.refreshReadyImages,
147            'toggleInventoryButton': self.toggleInventoryButton,
148        }
149        self.inventory_storage = self.model.game_state.player_character.inventory
150        if self.inventory == None:
151            self.inventory = inventorygui.InventoryGUI(self.controller,
152                                                       self.inventory_storage,
153                                                       inv_callbacks)
154        else:
155            self.inventory.inventory_storage = self.inventory_storage
156        self.refreshReadyImages()
157
158    def initializeContextMenu(self):
159        """Initialize the Context Menu
160           @return: None"""
161        self.context_menu = ContextMenu (self.engine, [], (0, 0))
162        self.context_menu.hide()
163
164    def showContextMenu(self, data, pos):
165        """Display the Context Menu with model at pos
166           @type model: list
167           @param model: model to pass to context menu
168           @type pos: tuple
169           @param pos: tuple of x and y coordinates
170           @return: None"""
171        self.context_menu = ContextMenu(self.engine, data, pos)
172
173    def hideContextMenu(self):
174        """Hides the context menu
175           @return: None"""
176        self.context_menu.hide()
177
178    def initializeMainMenu(self):
179        """Initalize the main menu.
180           @return: None"""
181        self.main_menu = pychan.loadXML("gui/hud_main_menu.xml")
182        self.menu_events = {"resumeButton":self.hideMenu, 
183                            "optionsButton":self.settings.onOptionsPress,
184                            "helpButton":self.displayHelp}
185        self.main_menu.mapEvents(self.menu_events)
186
187    def displayMenu(self):
188        """Displays the main in-game menu.
189           @return: None"""
190        if (self.menu_displayed == False):
191            self.main_menu.show()
192            self.menu_displayed = True
193        elif (self.menu_displayed == True):
194            self.hideMenu()
195
196    def hideMenu(self):
197        """Hides the main in-game menu.
198           @return: None"""
199        self.main_menu.hide()
200        self.menu_displayed = False
201
202
203    def initializeHelpMenu(self):
204        """Initialize the help menu
205           @return: None"""
206        self.help_dialog = pychan.loadXML("gui/help.xml")
207        help_events = {"closeButton":self.help_dialog.hide}
208        self.help_dialog.mapEvents(help_events)
209        main_help_text = u"Welcome to Post-Apocalyptic RPG or PARPG![br][br]"\
210        "This game is still in development, so please expect for there to be "\
211        "bugs and[br]feel free to tell us about them at "\
212        "http://www.forums.parpg.net.[br]This game uses a "\
213        "\"Point 'N' Click\" interface, which means that to move around,[br]"\
214        "just click where you would like to go and your character will move "\
215        "there.[br]PARPG also utilizes a context menu. To access this, just "\
216        "right click anywhere[br]on the screen and a menu will come up. This "\
217        "menu will change depending on[br]what you have clicked on, hence "\
218        "it's name \"context menu\".[br][br]"
219       
220        k_text = u" Keybindings" 
221        k_text += "[br] A : Add a test action to the actions display"
222        k_text += "[br] I : Toggle the inventory screen"
223        k_text += "[br] F5 : Take a screenshot"
224        k_text += "[br]      (saves to <parpg>/screenshots/)"
225        k_text += "[br] F10 : Toggle console"
226        k_text += "[br] PAUSE : (Un)Pause the game"
227        k_text += "[br] Q : Quit the game"
228        self.help_dialog.distributeInitialData({
229                "MainHelpText":main_help_text,
230                "KeybindText":k_text
231                })
232
233    def displayHelp(self):
234        """Display the help screen.
235           @return: None"""
236        self.help_dialog.show()
237
238    def saveGame(self):
239        """ Called when the user wants to save the game.
240            @return: None"""
241        save_browser = FileBrowser(self.engine,
242                                   self.save_game_callback,
243                                   save_file=True,
244                                   gui_xml_path="gui/savebrowser.xml",
245                                   extensions = ('.dat'))
246        save_browser.showBrowser()
247           
248    def newGame(self):
249        """Called when user request to start a new game.
250           @return: None"""
251        print 'new game'
252
253    def loadGame(self):
254        """ Called when the user wants to load a game.
255            @return: None"""
256        load_browser = FileBrowser(self.engine,
257                                   self.load_game_callback,
258                                   save_file=False,
259                                   gui_xml_path='gui/loadbrowser.xml',
260                                   extensions=('.dat'))
261        load_browser.showBrowser()
262   
263    def initializeQuitDialog(self):
264        """Creates the quit confirmation dialog
265           @return: None"""
266        self.quit_window = pychan.widgets.Window(title=unicode("Quit?"), \
267                                                 min_size=(200,0))
268
269        hbox = pychan.widgets.HBox()
270        are_you_sure = "Are you sure you want to quit?"
271        label = pychan.widgets.Label(text=unicode(are_you_sure))
272        yes_button = pychan.widgets.Button(name="yes_button", 
273                                           text=unicode("Yes"),
274                                           min_size=(90,20),
275                                           max_size=(90,20))
276        no_button = pychan.widgets.Button(name="no_button",
277                                          text=unicode("No"),
278                                          min_size=(90,20),
279                                          max_size=(90,20))
280
281        self.quit_window.addChild(label)
282        hbox.addChild(yes_button)
283        hbox.addChild(no_button)
284        self.quit_window.addChild(hbox)
285
286        events_to_map = { "yes_button": self.quit_callback,
287                          "no_button":  self.quit_window.hide }
288       
289        self.quit_window.mapEvents(events_to_map)
290
291
292    def quitGame(self):
293        """Called when user requests to quit game.
294           @return: None"""
295
296        self.quit_window.show()
297
298    def toggleInventoryButton(self):
299        """Manually toggles the inventory button.
300           @return: None"""
301        button = self.hud.findChild(name="inventoryButton")
302        if button.toggled == 0:
303            button.toggled = 1
304        else:
305            button.toggled = 0
306
307    def toggleInventory(self, toggle_image=True):
308        """Displays the inventory screen
309           @return: None"""
310        if self.inventory == None:
311            self.initializeInventory()
312        self.inventory.toggleInventory(toggle_image)
313
314    def refreshReadyImages(self):
315        """Make the Ready slot images on the HUD be the same as those
316           on the inventory
317           @return: None"""
318        for ready in range(1, 5):
319            button = self.hud.findChild(name=("hudReady%d" % ready))
320            if self.inventory_storage == None :
321                origin = None
322            else:
323                origin = self.inventory_storage.getItemsInSlot('ready', ready-1)
324            if origin == None:
325                self.setImages(button, 
326                               self.inventory.slot_empty_images['ready'])
327            else:
328                self.setImages(button, origin.getInventoryThumbnail())
329
330    def setImages(self, widget, image):
331        """Set the up, down, and hover images of an Imagebutton.
332           @type widget: pychan.widget
333           @param widget: widget to set
334           @type image: string
335           @param image: image to use
336           @return: None"""
337        widget.up_image = image
338        widget.down_image = image
339        widget.hover_image = image
340
341    def initializeEvents(self):
342        """Intialize Hud events
343           @return: None"""
344        events_to_map = {}
345
346        # when we click the toggle button don't change the image
347        events_to_map["inventoryButton"] = cbwa(self.toggleInventory, False)
348        events_to_map["saveButton"] = self.saveGame
349        events_to_map["loadButton"] = self.loadGame
350
351        hud_ready_buttons = ["hudReady1", "hudReady2", \
352                             "hudReady3", "hudReady4"]
353
354        for item in hud_ready_buttons:
355            events_to_map[item] = cbwa(self.readyAction, item)
356
357        self.hud.mapEvents(events_to_map)
358
359        menu_events = {}
360        menu_events["newButton"] = self.newGame
361        menu_events["quitButton"] = self.quitGame
362        menu_events["saveButton"] = self.saveGame
363        menu_events["loadButton"] = self.loadGame
364        self.main_menu.mapEvents(menu_events)
365
366    def setOption(self, name, value):
367        """Set an option within the xml.
368           @type name: string
369           @param name: The name of the option within the xml
370           @type value: any
371           @param value: The value that the option 'name' should be set to
372           @return: None"""
373        element = self.settings.root_element.find(name)
374        if(element != None):
375            if(value != element.text):
376                element.text = str(value)
377        else:
378            print 'Setting,', name, 'does not exist!'
379   
380    def readyAction(self, ready_button):
381        """ Called when the user selects a ready button from the HUD """
382        text = "Used the item from %s" % ready_button       
383        self.addAction(text)
384       
385    def createBoxGUI(self, title, container):
386        """Creates a window to display the contents of a box
387           @type title: string
388           @param title: The title for the window
389           @param items: The box to display
390           @return: A new ContainerGui"""
391        events = {'takeAllButton':self.hideContainer,
392                  'closeButton':self.hideContainer}
393        #hide previous container if any, to avoid orphaned dialogs
394        self.hideContainer()
395
396        self.box_container = ContainerGUI(self.controller,
397                                              unicode(title), container)
398        self.box_container.gui.mapEvents(events)
399        self.box_container.showContainer()
400        return self.box_container
401
402    def hideContainer(self):
403        """Hide the container box
404           @return: None"""
405        if self.box_container:
406            self.box_container.hideContainer()
407            #TODO: Move the close() call into OpenBoxAction(). This can be done
408            # after createBoxGUI becomes a blocking call or it's otherwise
409            # possible to wait till the box GUI is closed.
410            self.box_container.container.close()
411            self.box_container = None
412
413    def createExamineBox(self, title, desc):
414        """Create an examine box. It displays some textual description of an
415           object
416           @type title: string
417           @param title: The title of the examine box
418           @type desc: string
419           @param desc: The main body of the examine box
420           @return: None"""
421        if self.examine_box is not None:
422            self.examine_box.closePopUp()
423        self.examine_box = ExaminePopup(self.engine, title, desc)
424        self.examine_box.showPopUp()
425
426    def showDialogue(self, npc):
427        """Show the NPC dialogue window
428           @type npc: actors.NonPlayerCharacter
429           @param npc: the npc that we are having a dialogue with
430           @return: None"""
431        dialogue = DialogueGUI(
432                    self.controller,
433                    npc,
434                    self.model.game_state.quest_engine,
435                    self.model.game_state.player_character)
436        dialogue.initiateDialogue()
Note: See TracBrowser for help on using the repository browser.