Changeset 346 for trunk/game/scripts


Ignore:
Timestamp:
10/24/09 06:17:27 (10 years ago)
Author:
b0rland_parpg
Message:

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

Location:
trunk/game/scripts
Files:
1 deleted
4 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/game/scripts/hud.py

    r326 r346  
    2323from scripts.filebrowser import FileBrowser 
    2424from scripts.context_menu import ContextMenu 
    25 from scripts import inventory 
     25from scripts import inventorygui 
    2626from scripts.popups import ExaminePopup, ContainerGUI 
    2727from scripts.dialoguegui import DialogueGUI 
     
    5454        } 
    5555 
    56         self.inventory = inventory.Inventory(self.engine, \ 
    57                                              inv_model, inv_callbacks) 
     56 
     57        self.inventory = inventorygui.InventoryGUI(self.engine, \ 
     58                                                   inv_model, inv_callbacks) 
     59 
    5860        self.refreshReadyImages() 
    5961 
  • trunk/game/scripts/inventory.py

    r313 r346  
    1 #/usr/bin/python 
     1# This file is part of PARPG. 
     2#  
     3# PARPG is free software: you can redistribute it and/or modify 
     4# it under the terms of the GNU General Public License as published by 
     5# the Free Software Foundation, either version 3 of the License, or 
     6# (at your option) any later version. 
     7#  
     8# PARPG is distributed in the hope that it will be useful, 
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of 
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     11# GNU General Public License for more details. 
     12#  
     13# You should have received a copy of the GNU General Public License 
     14# along with PARPG.  If not, see <http://www.gnu.org/licenses/>. 
    215 
    3 #   This file is part of PARPG. 
     16from scripts.objects.base import GameObject, Container, Carryable 
     17from scripts.objects.composed import CarryableContainer, SingleItemContainer as Slot 
     18import copy 
    419 
    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. 
     20class Inventory(CarryableContainer): 
     21    """The class to represent inventory 'model': allow operations with 
     22    inventory contents, perform weight/bulk calculations, etc""" 
     23    def __init__(self, ID, **kwargs): 
     24        """Initialise instance""" 
     25        CarryableContainer.__init__(self, ID=ID, **kwargs) 
     26        self.items = {"head": Slot(ID), "neck": Slot(ID), "shoulders": Slot(ID), 
     27                      "chest": Slot(ID), "abdomen": Slot(ID), "left_arm": Slot(ID), 
     28                      "right_arm": Slot(ID),"groin": Slot(ID), "hips": Slot(ID), 
     29                      "left_leg": Slot(ID), "right_leg": Slot(ID), 
     30                      "backpack": CarryableContainer(ID)} 
     31        for key,item in self.items.iteritems(): 
     32            item.name = key 
     33        self.item_lookup = {} 
    934 
    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. 
     35    def placeItem(self,item): 
     36        self.items["backpack"].placeItem(item) 
     37        self.item_lookup[item.ID] = "backpack" 
     38         
     39    def takeItem(self,item): 
     40        if not item.ID in self.item_lookup: 
     41            raise ValueError ('I do not contain this item: %s' % item) 
     42        self.items[self.item_lookup[item.ID]].takeItem(item) 
     43        self.item_lookup[item.ID] = None 
    1444 
    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/>. 
     45    def getWeight(self): 
     46        """Total weight of all items in container + container's own weight""" 
     47        return sum((item.weight for item in self.items.values()), self.own_weight) 
    1748 
    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 
     49    def setWeightDummy(self, weight): 
     50        pass 
    2651 
    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'] 
     52    weight = property(getWeight, setWeightDummy, "Total weight of container") 
    10553 
    106         for key in items: 
    107             widget = self.inventory.findChild(name=key) 
    108             item = items[key] 
    109             image = item_image_dict[item] 
    11054 
    111             widget.item = item 
    112             widget.up_image = image 
    113             widget.down_image = image 
    114             widget.hover_image = image             
     55    def count(self): 
     56        return sum(item.count() for item in self.items.values()) 
     57     
     58    def takeOff(self, item): 
     59        return self.moveItemToSlot(item, "backpack") 
    11560 
    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 = "" 
     61    def moveItemToSlot(self,item,slot): 
     62        if not slot in self.items: 
     63            raise(ValueError,"%s: No such slot" % slot) 
    12364 
    124         self.events_to_map['close_button'] = self.closeInventoryAndToggle 
    125         self.inventory.mapEvents(self.events_to_map)    
    126         self.resetMouseCursor() 
     65        if item.ID in self.item_lookup: 
     66            self.items[self.item_lookup[item.ID]].takeItem(item) 
     67        try: 
     68            self.items[slot].placeItem(item) 
     69        except ValueError: 
     70            self.takeOff(self.items[slot].items[0]) 
     71            self.items[slot].placeItem(item) 
     72        self.item_lookup[item.ID] = slot 
     73      
     74    def getItemsInSlot(self, slot): 
     75        if not slot in self.items: 
     76            raise(ValueError,"%s: No such slot" % slot) 
     77        return copy.copy(self.items[slot].items) 
    12778 
    128     def closeInventory(self): 
    129         """Close the inventory. 
    130            @return: None""" 
    131         self.inventory.hide() 
     79    def isSlotEmpty(self, slot): 
     80        if not slot in self.items: 
     81            raise(ValueError,"%s: No such slot" % slot) 
     82        return self.items[slot].count() == 0 
    13283 
    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  
     84    def __repr__(self): 
     85        return "[%s:%s "%(self.name, self.ID)+reduce((lambda a,b: str(a) +', '+str(b)), self.items.values())+" ]" 
  • trunk/game/scripts/inventorygui.py

    r288 r346  
    1616#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>. 
    1717 
    18 import sys, os, fife, fifelog, pychan 
     18import sys 
     19import os 
     20import fife 
     21import fifelog 
     22import pychan 
    1923from scripts import drag_drop_data as data_drag 
    2024from pychan.tools import callbackWithArguments as cbwa 
    2125from scripts.items import item_image_dict 
    2226 
    23 class Inventory(object): 
    24     """Main inventory class""" 
     27class InventoryGUI(object): 
     28    """Inventory GUI class""" 
    2529    def __init__(self, engine, items, callbacks): 
    2630        """Initialise the instance. 
     
    2832           @param engine: An instance of the fife engine 
    2933           @type items: dict 
    30            @param items: A dictionary for every slot that goes '{slot:item, slot:item}' 
    31                          if a slot is not included in the dict, it is assumed to be empty 
     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 
    3237           @type callbacks: dict 
    3338           @param callbacks: a dict of callbacks 
     
    4550        # TODO: remove hard-coded string? 
    4651        self.inventory = pychan.loadXML("gui/inventory.xml") 
    47         self.inventoryShown = False  
     52        self.inventory_shown = False 
    4853        self.events_to_map = {} 
    4954        # the images that should be used for the buttons when they are "empty" 
     
    112117            # make every button's callback be self.dragDrop 
    113118            self.events_to_map[button] = cbwa(self.dragDrop, button) 
    114             ch = self.inventory.findChild(name = button) 
     119            ch = self.inventory.findChild(name=button) 
    115120            # make every slot's item be none if it has not already been set 
    116121            if button not in items: 
     
    131136        self.closeInventory() 
    132137        self.toggleInventoryButtonCallback() 
    133         self.inventoryShown = False 
     138        self.inventory_shown = False 
    134139 
    135140    def toggleInventory(self, toggleImage=True): 
     
    143148               image implicitly, so we don't change it. 
    144149           @return: None""" 
    145         if not self.inventoryShown: 
     150        if not self.inventory_shown: 
    146151            self.showInventory() 
    147             self.inventoryShown = True 
     152            self.inventory_shown = True 
    148153        else: 
    149154            self.closeInventory() 
    150             self.inventoryShown = False 
     155            self.inventory_shown = False 
    151156 
    152157        if toggleImage: 
     
    158163        self.inventory.show() 
    159164 
    160     def setMouseCursor(self, image, dummy_image, type = "native"):  
     165    def setMouseCursor(self, image, dummy_image, type="native"):  
    161166        """Set the mouse cursor to an image. 
    162167           @type image: string 
     
    286291    def getItems(self): 
    287292        """ 
    288         Get the items in the inventory slots. If there is no item in the slot, it is skipped 
     293        Get the items in the inventory slots. If there is no item in the slot, 
     294        it is skipped 
    289295         
    290296        @rtype: dict 
  • trunk/game/scripts/objects/base.py

    r315 r346  
    208208        except AttributeError : 
    209209            pass 
    210          
    211 class Inventory (object): 
    212     """Aggregate class for things that have multiple Containers""" 
    213     def __init__ (self, **kwargs): 
    214         self.is_inventory = True 
    215         self.containers = [] 
    216      
     210 
     211    def count (self): 
     212        return len(self.items) 
     213 
     214         
    217215class Living (object): 
    218216    def __init__ (self, **kwargs): 
     
    247245         
    248246class Wearable (object): 
    249     def __init__ (self, **kwargs): 
     247    def __init__ (self, slots, **kwargs): 
    250248        """Allows the object to be worn somewhere on the body (e.g. pants)""" 
    251249        self.is_wearable = True 
     250        if isinstance(slots,tuple) : 
     251            self.slots = slots 
     252        else : 
     253            self.slots = (slots,) 
    252254     
    253255class Usable (object): 
  • trunk/game/scripts/objects/composed.py

    r310 r346  
    1818"""Composite game object classes are kept here""" 
    1919 
     20from hgext.inotify.linux.watcher import getter 
    2021from base import * 
    2122 
     
    3233        self.blocking = True 
    3334 
     35class CarryableContainer(GameObject, Container, Carryable): 
     36    """Composite class that will be used for backpack, pouches, etc.""" 
     37    def __init__ (self, ID, **kwargs): 
     38        GameObject.__init__(self, ID, **kwargs) 
     39        Container.__init__(self, **kwargs) 
     40        Carryable.__init__(self,**kwargs) 
     41        self.own_weight = 0 
     42 
     43    def getWeight(self): 
     44        """Total weight of all items in container + container's own weight""" 
     45        return sum((item.weight for item in self.items), self.own_weight) 
     46 
     47 
     48    def setWeight(self, weight): 
     49        self.own_weight = weight 
     50 
     51    weight = property(getWeight, setWeight, "Total weight of container") 
     52 
     53    def __repr__(self): 
     54        return "[%s:%s "%(self.name, self.ID) +str(reduce((lambda a,b: a +', '+str(b)), self.items,""))+" ]" 
     55 
     56 
     57class SingleItemContainer (CarryableContainer) : 
     58    """Container that can only store a single item. This class can represent single-item inventory slots""" 
     59    def __init__ (self, ID, **kwargs): 
     60        CarryableContainer.__init__(self, ID,**kwargs) 
     61 
     62    def placeItem(self,item): 
     63        if len(self.items) > 0 : 
     64            raise ValueError ('%s is already busy' % self) 
     65        CarryableContainer.placeItem(self, item) 
     66 
    3467class Door(GameObject, Lockable, Scriptable, Trappable): 
    3568    """Composite class that can be used to create doors on a map.""" 
Note: See TracChangeset for help on using the changeset viewer.