1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Containes classes defining the base properties of all interactable in-game
19 objects (such as Carryable, Openable, etc. These are generally independent
20 classes, which can be combined in almost any way and order.
21
22 Some rules that should be followed when CREATING base property classes:
23
24 1. If you want to support some custom initialization arguments,
25 always define them as keyword ones. Only GameObject would use
26 positional arguments.
27 2. In __init__() **ALWAYS** call the parent's __init__(**kwargs), preferably
28 *at the end* of your __init__() (makes it easier to follow)
29 3. There should always be an attributes.append(x) call on __init__
30 (where X is the name of the class)
31
32 EXAMPLE:
33
34 class Openable(object):
35 def __init__ (self, is_open = True, **kwargs):
36 self.attribbutes.append("openable")
37 self.is_open = is_open
38 super(Openable,self).__init__ (**kwargs)
39
40
41 Some rules are to be followed when USING the base classes to make composed
42 ones:
43
44 1. The first parent should always be the base GameObject class
45 2. Base classes other than GameObject can be inherited in any order
46 3. The __init__ functoin of the composed class should always invoke the
47 parent's __init__() *before* it starts customizing any variables.
48
49 EXAMPLE:
50
51 class TinCan (GameObject, Container, Scriptable, Destructable, Carryable):
52 def __init__ (self, *args, **kwargs):
53 super(TinCan,self).__init__ (*args, **kwargs)
54 self.name = 'Tin Can'"""
55
57 """A base class that supports dynamic attributes functionality"""
59 if not self.__dict__.has_key("attributes"):
60 self.attributes = []
61
63 """Method that checks if the instance has an attribute"""
64 return attr in self.attributes
65
67 """Returns state for saving
68 """
69 state = {}
70 state["attributes"] = self.attributes
71 return state
72
74 """Class with basic attributes"""
75 - def __init__ (self, name="Dynamic object", real_name=None, image=None, **kwargs):
76 """Initialise minimalistic set of data
77 @type name: String
78 @param name: Object display name
79 @type image: String or None
80 @param name: Filename of image to use in inventory"""
81 BaseObject.__init__(self)
82 self.name = name
83 self.real_name = real_name or name
84 self.image = image
85
87 """Prepares state for saving
88 @type state: dictionary
89 @param state: State of the object
90 """
91 pass
92
94 """Restores a state from a saved state
95 @type state: dictionary
96 @param state: Saved state
97 """
98 self.__dict__.update(state)
99
104
107
109 """Returns state for saving
110 """
111 state = BaseObject.getStateForSaving(self)
112 state["Name"] = self.name
113 state["RealName"] = self.real_name
114 state["Image"] = self.image
115 return state
116
118 """A base class to be inherited by all game objects. This must be the
119 first class (left to right) inherited by any game object."""
120 - def __init__ (self, ID, gfx = None, xpos = 0.0, ypos = 0.0, map_id = None,
121 blocking=True, name="Generic object", real_name="Generic object", text="Item description",
122 desc="Detailed description", **kwargs):
123 """Set the basic values that are shared by all game objects.
124 @type ID: String
125 @param ID: Unique object identifier. Must be present.
126 @type gfx: Dictionary
127 @param gfx: Dictionary with graphics for the different contexts
128 @type coords 2-item tuple
129 @param coords: Initial coordinates of the object.
130 @type map_id: String
131 @param map_id: Identifier of the map where the object is located
132 @type blocking: Boolean
133 @param blocking: Whether the object blocks character movement
134 @type name: String
135 @param name: The display name of this object (e.g. 'Dirty crate')
136 @type text: String
137 @param text: A longer description of the item
138 @type desc: String
139 @param desc: A long description of the item that is displayed when it is examined
140 """
141 DynamicObject.__init__(self, name, real_name, **kwargs)
142 self.ID = ID
143 self.gfx = gfx or {}
144 self.X = xpos
145 self.Y = ypos
146 self.map_id = map_id
147 self.blocking = True
148 self.text = text
149 self.desc = desc
150
152 """Get-er property function"""
153 return (self.X, self.Y)
154
156 """Set-er property function"""
157 self.X, self.Y = float(coords[0]), float (coords[1])
158
159 coords = property (_getCoords, _setCoords,
160 doc = "Property allowing you to get and set the object's \
161 coordinates via tuples")
162
164 """A debugging string representation of the object"""
165 return "<%s:%s>" % (self.name, self.ID)
166
168 """Returns state for saving
169 """
170 state = super(GameObject, self).getStateForSaving()
171 state["ObjectModel"] = self.gfx
172 state["Text"] = self.text
173 state["Desc"] = self.desc
174 state["Position"] = list(self.coords)
175 return state
176
177
179 """Allows objects to have predefined scripts executed on certain events"""
180 - def __init__ (self, scripts = None, **kwargs):
181 """Init operation for scriptable objects
182 @type scripts: Dictionary
183 @param scripts: Dictionary where the event strings are keys. The
184 values are 3-item tuples (function, positional_args, keyword_args)"""
185 BaseObject.__init__(self)
186 self.attributes.append("scriptable")
187 self.scripts = scripts or {}
188
190 """Runs the script for the given event"""
191 if event in self.scripts and self.scripts[event]:
192 func, args, kwargs = self.scripts[event]
193 func (*args, **kwargs)
194
195 - def setScript (self, event, func, args = None , kwargs = None):
196 """Sets a script to be executed for the given event."""
197 args = args or {}
198 kwargs = kwargs or {}
199 self.scripts[event] = (func, args, kwargs)
200
201 -class Openable(DynamicObject, Scriptable):
202 """Adds open() and .close() capabilities to game objects
203 The current state is tracked by the .is_open variable"""
204 - def __init__(self, is_open = True, **kwargs):
205 """Init operation for openable objects
206 @type is_open: Boolean
207 @param is_open: Keyword boolean argument sets the initial state."""
208 DynamicObject.__init__(self, **kwargs)
209 Scriptable.__init__(self, **kwargs)
210 self.attributes.append("openable")
211 self.is_open = is_open
212
214 """Opens the object, and runs an 'onOpen' script, if present"""
215 self.is_open = True
216 try:
217 if self.trueAttr ('scriptable'):
218 self.runScript('onOpen')
219 except AttributeError :
220 pass
221
223 """Opens the object, and runs an 'onClose' script, if present"""
224 self.is_open = False
225 try:
226 if self.trueAttr ('scriptable'):
227 self.runScript('onClose')
228 except AttributeError :
229 pass
230
232 """Allows objects to be locked"""
233 - def __init__ (self, locked = False, is_open = True, **kwargs):
234 """Init operation for lockable objects
235 @type locked: Boolean
236 @param locked: Keyword boolen argument sets the initial locked state.
237 @type is_open: Boolean
238 @param is_open: Keyword boolean argument sets the initial open state.
239 It is ignored if locked is True -- locked objects
240 are always closed."""
241 self.attributes.append("lockable")
242 self.locked = locked
243 if locked :
244 is_open = False
245 Openable.__init__( self, is_open, **kwargs )
246
248 """Handles unlocking functionality"""
249 self.locked = False
250
252 """Handles locking functionality"""
253 self.close()
254 self.locked = True
255
256 - def open (self, *args, **kwargs):
257 """Adds a check to see if the object is unlocked before running the
258 .open() function of the parent class"""
259 if self.locked:
260 raise ValueError ("Open failed: object locked")
261 super (Lockable, self).open(*args, **kwargs)
262
264 """Allows objects to be stored in containers"""
265 - def __init__ (self, weight=0.0, bulk=0.0, **kwargs):
273
275 """Returns the inventory thumbnail of the object"""
276
277 if self.image == None:
278 return "gui/inv_images/inv_litem.png"
279 else:
280 return self.image
281
283 """Gives objects the capability to hold other objects"""
285 """Exception to be raised when the object is too big
286 to fit into container"""
287 pass
288
290 """Exception to be raised when the requested slot is occupied"""
291 pass
292
294 """Exception to be raised when trying to add the container as an item"""
295 pass
296
297 - def __init__ (self, capacity = 0, items = None, **kwargs):
306
308 """Adds the provided carryable item to the inventory.
309 Runs an 'onStoreItem' script, if present"""
310 if item is self:
311 raise self.ItemSelf("Paradox: Can't contain myself")
312 if not item.trueAttr ('carryable'):
313 raise TypeError ('%s is not carryable!' % item)
314 if self.capacity and self.getContentsBulk()+item.bulk > self.capacity:
315 raise self.TooBig ('%s is too big to fit into %s' % (item, self))
316 item.in_container = self
317 if index == None:
318 self._placeAtVacant(item)
319 else:
320 if index in self.items :
321 raise self.SlotBusy('Slot %d is busy in %s' % (index,
322 self.name))
323 self.items[index] = item
324
325
326 try:
327 if self.trueAttr ('scriptable'):
328 self.runScript('onPlaceItem')
329 except AttributeError :
330 pass
331
333 """Places an item at a vacant slot"""
334 vacant = None
335 for i in range(len(self.items)):
336 if i not in self.items :
337 vacant = i
338 if vacant == None :
339 vacant = len(self.items)
340 self.items[vacant] = item
341
343 """Takes the listed item out of the inventory.
344 Runs an 'onTakeItem' script"""
345 if not item in self.items.values():
346 raise ValueError ('I do not contain this item: %s' % item)
347 del self.items[self.items.keys()[self.items.values().index(item)]]
348
349
350 try:
351 if self.trueAttr ('scriptable'):
352 self.runScript('onTakeItem')
353 except AttributeError :
354 pass
355
357 """Replaces the old item with the new one
358 @param old_item: Old item which is removed
359 @type old_item: Carryable
360 @param new_item: New item which is added
361 @type new_item: Carryable
362 """
363 old_index = self.indexOf(old_item.ID)
364 self.removeItem(old_item)
365 self.placeItem(new_item, old_index)
366
368 """Removes an item from the container, basically the same as 'takeItem'
369 but does run a different script. This should be used when an item is
370 destroyed rather than moved out.
371 Runs 'onRemoveItem' script
372 """
373 if not item in self.items.values():
374 raise ValueError ('I do not contain this item: %s' % item)
375 del self.items[self.items.keys()[self.items.values().index(item)]]
376
377
378 try:
379 if self.trueAttr ('scriptable'):
380 self.runScript('onRemoveItem')
381 except AttributeError :
382 pass
383
384 - def count (self, item_type = ""):
385 """Returns the number of items"""
386 if item_type:
387 ret_count = 0
388 for index in self.items :
389 if self.items[index].item_type == item_type:
390 ret_count += 1
391 return ret_count
392 return len(self.items)
393
394 - def getContentsBulk(self):
395 """Bulk of the container contents"""
396 return sum((item.bulk for item in self.items.values()))
397
399 return self.items[index]
400
402 """Returns the index of the item with the passed ID"""
403 for index in self.items :
404 if self.items[index].ID == ID:
405 return index
406 return None
407
409 """Returns the item with the passed ID"""
410 for i in self.items :
411 if self.items[i].ID == ID:
412 return self.items[i]
413 return None
414
416 """Returns the item with the passed item_type"""
417 for index in self.items :
418 if self.items[index].item_type == item_type:
419 return self.items[index]
420 return None
421
423 """Find an item in container by attributes. All params are optional.
424 @type name: String
425 @param name: If the name is non-unique, return first matching object
426 @type kind: String
427 @param kind: One of the possible object types
428 @return: The item matching criteria or None if none was found"""
429 for index in self.items :
430 if "name" in kwargs and self.items[index].name != kwargs["name"]:
431 continue
432 if "ID" in kwargs and self.items[index].ID != kwargs["ID"]:
433 continue
434 if "kind" in kwargs and not self.items[index].trueAttr(kwargs["kind"]):
435 continue
436 if "item_type" in kwargs and self.items[index].item_type != kwargs["item_type"]:
437 continue
438 return self.items[index]
439 return None
440
442 """Returns the items as a list"""
443 items = []
444 for index, item in self.items.iteritems():
445 item_dict = item.getStateForSaving()
446 item_dict["index"] = index
447 item_dict["type"] = item.item_type
448 items.append(item_dict)
449 return items
450
457
459 """Objects that 'live'"""
464
466 """Kills the object"""
467 self.lives = False
468
470 """Provides the object with character statistics"""
474
476 """Objects than can be weared"""
478 """Allows the object to be worn somewhere on the body (e.g. pants)"""
479 BaseObject.__init__(self)
480 self.attributes.append("wearable")
481 if isinstance(slots, tuple) :
482 self.slots = slots
483 else :
484 self.slots = (slots,)
485
487 """Allows the object to be used in some way (e.g. a Zippo lighter
488 to make a fire)"""
489 - def __init__ (self, actions = None, **kwargs):
493
495 """Allows the object to be used as a weapon"""
499
501 """Allows the object to be destroyed"""
505
507 """Provides trap slots to the object"""
511