source: branches/active/character_customization/game/parpg/gui/hud.py @ 754

Revision 754, 19.3 KB checked in by aspidites, 8 years ago (diff)

Patch Aspidites:

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