source: trunk/game/scripts/inventorygui.py @ 366

Revision 346, 13.9 KB checked in by b0rland_parpg, 10 years ago (diff)

Ticket #107: patch by b0rland

  • Wrote initial version of the inventory storage class
  • Added some useful utility functions into container class and its derivatives
  • Created several combined classes for carryable containers
  • Extended tests and of course made new ones
  • Renamed old Inventory class to be InventoryGUI

Note: InventoryGUI still works the old way and doesn't use Inventory

  • Property svn:eol-style set to native
Line 
1#/usr/bin/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
18import sys
19import os
20import fife
21import fifelog
22import pychan
23from scripts import drag_drop_data as data_drag
24from pychan.tools import callbackWithArguments as cbwa
25from scripts.items import item_image_dict
26
27class InventoryGUI(object):
28    """Inventory GUI class"""
29    def __init__(self, engine, items, callbacks):
30        """Initialise the instance.
31           @type engine: fife.Engine
32           @param engine: An instance of the fife engine
33           @type items: dict
34           @param items: A dictionary for every slot that goes '{slot:item,
35                         slot:item}' if a slot is not included in the dict,
36                         it is assumed to be empty
37           @type callbacks: dict
38           @param callbacks: a dict of callbacks
39               refreshReadyImages:
40                   Function that will make the ready slots on the HUD
41                   reflect those within the inventory
42               toggleInventoryButton:
43                   Function that will toggle the state of the inventory button
44           @return: None"""
45        pychan.init(engine, debug = True)
46        self.engine = engine
47        self.readyCallback = callbacks['refreshReadyImages']
48        self.toggleInventoryButtonCallback = callbacks['toggleInventoryButton']
49        self.original_cursor_id = self.engine.getCursor().getId()
50        # TODO: remove hard-coded string?
51        self.inventory = pychan.loadXML("gui/inventory.xml")
52        self.inventory_shown = False
53        self.events_to_map = {}
54        # the images that should be used for the buttons when they are "empty"
55        self.empty_images = {'A1':'gui/inv_images/inv_backpack.png',
56                             'A2':'gui/inv_images/inv_backpack.png',
57                             'A3':'gui/inv_images/inv_backpack.png',
58                             'A4':'gui/inv_images/inv_backpack.png',
59                             'A5':'gui/inv_images/inv_backpack.png',
60                             'B1':'gui/inv_images/inv_backpack.png',
61                             'B2':'gui/inv_images/inv_backpack.png',
62                             'B3':'gui/inv_images/inv_backpack.png',
63                             'B4':'gui/inv_images/inv_backpack.png',
64                             'B5':'gui/inv_images/inv_backpack.png',
65                             'C1':'gui/inv_images/inv_backpack.png',
66                             'C2':'gui/inv_images/inv_backpack.png',
67                             'C3':'gui/inv_images/inv_backpack.png',
68                             'C4':'gui/inv_images/inv_backpack.png',
69                             'C5':'gui/inv_images/inv_backpack.png',
70                             'D1':'gui/inv_images/inv_backpack.png',
71                             'D2':'gui/inv_images/inv_backpack.png',
72                             'D3':'gui/inv_images/inv_backpack.png',
73                             'D4':'gui/inv_images/inv_backpack.png',
74                             'D5':'gui/inv_images/inv_backpack.png',
75                             'Head':'gui/inv_images/inv_head.png',
76                             'LeftHeld':'gui/inv_images/inv_litem.png',
77                             'RightHeld':'gui/inv_images/inv_ritem.png',
78                             'LeftHand':'gui/inv_images/inv_lhand.png',
79                             'RightHand':'gui/inv_images/inv_rhand.png',
80                             'Body':'gui/inv_images/inv_torso.png',
81                             'Belt':'gui/inv_images/inv_belt.png',
82                             'Ready1':'gui/inv_images/inv_belt_pouches.png',
83                             'Ready2':'gui/inv_images/inv_belt_pouches.png',
84                             'Ready3':'gui/inv_images/inv_belt_pouches.png',
85                             'Ready4':'gui/inv_images/inv_belt_pouches.png',
86                             'LeftFoot':'gui/inv_images/inv_lfoot.png',
87                             'RightFoot':'gui/inv_images/inv_rfoot.png'}
88        # every button on the inventory and its category
89        self.buttons = {'A1':'main_inv', 'A2':'main_inv', 'A3':'main_inv',
90                        'A4':'main_inv', 'A5':'main_inv', 'B1':'main_inv',
91                        'B2':'main_inv', 'B3':'main_inv', 'B4':'main_inv',
92                        'B5':'main_inv', 'C1':'main_inv', 'C2':'main_inv',
93                        'C3':'main_inv', 'C4':'main_inv', 'C5':'main_inv',
94                        'D1':'main_inv', 'D2':'main_inv', 'D3':'main_inv',
95                        'D4':'main_inv', 'D5':'main_inv',
96                        'LeftFoot':'foot', 'RightFoot':'foot',
97                        'LeftHand':'hand', 'RightHand':'hand',
98                        'Head':'head', 'Ready1':'ready', 
99                        'Ready2':'ready', 'Ready3':'ready', 
100                        'Ready4':'ready', 'Belt':'belt', 'LeftHeld':'held',
101                        'RightHeld':'held', 'Body':'body'}
102        # all possible categories
103        self.locations = ['ready', 'head', 'foot', 'hand',
104                          'belt', 'held', 'body']
105
106        for key in items:
107            widget = self.inventory.findChild(name=key)
108            item = items[key]
109            image = item_image_dict[item]
110
111            widget.item = item
112            widget.up_image = image
113            widget.down_image = image
114            widget.hover_image = image           
115
116        for button in self.buttons:
117            # make every button's callback be self.dragDrop
118            self.events_to_map[button] = cbwa(self.dragDrop, button)
119            ch = self.inventory.findChild(name=button)
120            # make every slot's item be none if it has not already been set
121            if button not in items:
122                ch.item = ""
123
124        self.events_to_map['close_button'] = self.closeInventoryAndToggle
125        self.inventory.mapEvents(self.events_to_map)   
126        self.resetMouseCursor()
127
128    def closeInventory(self):
129        """Close the inventory.
130           @return: None"""
131        self.inventory.hide()
132
133    def closeInventoryAndToggle(self):
134        """Close the inventory screen.
135           @return: None"""
136        self.closeInventory()
137        self.toggleInventoryButtonCallback()
138        self.inventory_shown = False
139
140    def toggleInventory(self, toggleImage=True):
141        """Pause the game and enter the inventory screen, or close the
142           inventory screen and resume the game.
143           @type toggleImage: bool
144           @param toggleImage:
145               Call toggleInventoryCallback if True. Toggling via a
146               keypress requires that we toggle the Hud inventory image
147               explicitly. Clicking on the Hud inventory button toggles the
148               image implicitly, so we don't change it.
149           @return: None"""
150        if not self.inventory_shown:
151            self.showInventory()
152            self.inventory_shown = True
153        else:
154            self.closeInventory()
155            self.inventory_shown = False
156
157        if toggleImage:
158            self.toggleInventoryButtonCallback()
159
160    def showInventory(self):
161        """Show the inventory.
162           @return: None"""
163        self.inventory.show()
164
165    def setMouseCursor(self, image, dummy_image, type="native"): 
166        """Set the mouse cursor to an image.
167           @type image: string
168           @param image: The image you want to set the cursor to
169           @type dummy_image: string
170           @param dummy_image: ???
171           @type type: string
172           @param type: ???
173           @return: None"""
174        cursor = self.engine.getCursor()
175        cursor_type = fife.CURSOR_IMAGE
176        img_pool = self.engine.getImagePool()
177        if(type == "target"):
178            target_cursor_id = img_pool.addResourceFromFile(image) 
179            dummy_cursor_id = img_pool.addResourceFromFile(dummy_image)
180            cursor.set(cursor_type,target_dummy_cursor_id)
181            cursor.setDrag(cursor_type,target_cursor_id,-16,-16)
182        else:
183            cursor_type = fife.CURSOR_IMAGE
184            zero_cursor_id = img_pool.addResourceFromFile(image)
185            cursor.set(cursor_type,zero_cursor_id)
186            cursor.setDrag(cursor_type,zero_cursor_id)
187           
188    def resetMouseCursor(self):
189        """Reset cursor to default image.
190           @return: None"""
191        c = self.engine.getCursor()
192        img_pool = self.engine.getImagePool()
193        cursor_type = fife.CURSOR_NATIVE
194        # this is the path to the default image
195        cursor_id = self.original_cursor_id
196        c.setDrag(cursor_type, cursor_id)
197        c.set(cursor_type, cursor_id)
198       
199    def dragDrop(self, obj):
200        """Decide whether to drag or drop the image.
201           @type obj: string
202           @param obj: The name of the object within
203                       the dictionary 'self.buttons'
204           @return: None"""
205        if(data_drag.dragging == True):
206            self.dropObject(obj)
207        elif(data_drag.dragging == False):
208            self.dragObject(obj)
209               
210    def dragObject(self, obj):
211        """Drag the selected object.
212           @type obj: string
213           @param obj: The name of the object within
214                       the dictionary 'self.buttons'
215           @return: None"""
216        # get the widget from the inventory with the name obj
217        drag_widget = self.inventory.findChild(name = obj)
218        # only drag if the widget is not empty
219        if (drag_widget.up_image != self.empty_images[obj]):
220            # get it's type (e.g. main_inv)
221            data_drag.dragged_type = self.buttons[obj]
222            # get the item that the widget is 'storing'
223            data_drag.dragged_item = drag_widget.item
224            # get the up and down images of the widget
225            up_image = drag_widget.up_image
226            down_image = drag_widget.down_image
227            # set the mouse cursor to be the widget's image
228            self.setMouseCursor(up_image.source,down_image.source)
229            data_drag.dragged_image = up_image.source
230            data_drag.dragging = True
231            # after dragging the 'item', set the widgets' images
232            # so that it has it's default 'empty' images
233            drag_widget.up_image=(self.empty_images[obj])
234            drag_widget.down_image=(self.empty_images[obj])
235            drag_widget.hover_image=(self.empty_images[obj])
236            # then set it's item to nothing
237            drag_widget.item = ""
238           
239    def dropObject(self, obj):
240        """Drops the object being dropped
241           @type obj: string
242           @param obj: The name of the object within
243                       the dictionary 'self.buttons'
244           @return: None"""
245        # find the type of the place that the object
246        # is being dropped onto
247        data_drag.dropped_type  =  self.buttons[obj]
248        # if the dragged obj or the place it is being dropped is
249        # in the main inventory, drop the object
250        if((data_drag.dragged_type == 'main_inv') or
251           (data_drag.dropped_type == 'main_inv')):
252            drag_widget = self.inventory.findChild(name = obj)
253            drag_widget.up_image = data_drag.dragged_image
254            drag_widget.hover_image = data_drag.dragged_image
255            drag_widget.down_image = data_drag.dragged_image
256            drag_widget.item = data_drag.dragged_item
257            print 'Item: ' + drag_widget.item
258            data_drag.dragging = False
259            #reset the mouse cursor to the normal cursor
260            self.resetMouseCursor()
261            # if the object was dropped onto a ready slot, then
262            # update the hud
263            if (data_drag.dropped_type == 'ready'):
264                self.readyCallback()
265       
266        # if the dragged object's type is the same as the location to
267        # to drop it at's, and the dragged object's type is in
268        # self.locations, then drop the object
269        elif((data_drag.dragged_type == data_drag.dropped_type) and
270             (data_drag.dragged_type in self.locations)):
271            drag_widget = self.inventory.findChild(name = obj)
272            drag_widget.up_image = data_drag.dragged_image
273            drag_widget.hover_image = data_drag.dragged_image
274            drag_widget.down_image = data_drag.dragged_image
275            drag_widget.item = data_drag.dragged_item
276            print 'Item: ' + drag_widget.item
277            data_drag.dragging = False
278            # reset the mouse cursor
279            self.resetMouseCursor()
280            # if the object was dropped onto a ready slot, then
281            # update the hud
282            if(data_drag.dropped_type == 'ready'):
283                self.readyCallback()
284        # otherwise, we assume that the player is trying to
285        # drop an object onto an incompatible slot
286        else:
287            # reset the mouse cursor
288            self.resetMouseCursor()
289            data_drag.dragging = False
290
291    def getItems(self):
292        """
293        Get the items in the inventory slots. If there is no item in the slot,
294        it is skipped
295       
296        @rtype: dict
297        @return: The items in the inventory
298        """
299        items = {}
300
301        for button in self.buttons:
302            widget = self.inventory.findChild(name=button)
303            if (widget.item != ""):
304                items[button] = widget.item
305
306        return items
307               
308    def getImage(self, name):
309        """Return a current image from the inventory
310           @type name: string
311           @param name: name of image to get
312           @return: None"""
313        return self.inventory.findChild(name=name)
314
Note: See TracBrowser for help on using the repository browser.