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 | |
---|
18 | import sys |
---|
19 | import os |
---|
20 | import fife |
---|
21 | import fifelog |
---|
22 | import pychan |
---|
23 | from scripts import drag_drop_data as data_drag |
---|
24 | from pychan.tools import callbackWithArguments as cbwa |
---|
25 | from scripts.items import item_image_dict |
---|
26 | |
---|
27 | class Inventory(object): |
---|
28 | """Main inventory 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 | |
---|