예제 #1
0
    def execute(self):
        """
        Equips player with item in inventory.
        """
        #Create variables
        inventory = self._player.getInventory()
        equipped = self._player.getEquipped()
        equippable = ItemSet()
        
        #Create list of equippable items
        for item in inventory:
            if (isinstance(item, Weapon) or isinstance(item, Armor) or 
            isinstance(item, Charm)) and item not in equipped:
                equippable.addItem(item)
        
        #If no equippable items
        if equippable.count() == 0:
            print "No equippable items in inventory."
            return

        #User prompt   
        print "%s may equip:" % self._player.getName()
        for item in equippable:
            print "\t%s" % item.getName()
        print ""
        itemToEquip = raw_input("Which item do you want to equip? ")

        #Attempt to equip item
        item = inventory.getItemByName(itemToEquip)
        if item:
            statement = self._player.equip(item)
            print statement
        else:
            print "Item not in inventory."
    def execute(self):
        """
        Uses potion in inventory to heal player.
        """
        #Check that potions in inventory
        inventory = self._player.getInventory()
        potions = ItemSet()
        
        for item in inventory:
            if isinstance(item, Potion):
                potions.addItem(item)
        if potions.count() == 0:
            print "%s has no potions." % self._player.getName()
            return
        
        #User prompt
        print "%s currently has:" % self._player.getName()
        for potion in potions:
            print "\t%s with %s healing power." % (potion.getName(), 
            potion.getHealing())
        print ""
    
        choice = None
        while True:
            choice = raw_input("Which potion would you like to use? ")
            if potions.containsItemWithName(choice):
                break
            else:
                print "%s does not have that potion." % self._player.getName()
                print ""

        #Healing mechanics
        potionChoice = potions.getItemByName(choice)
        healing = potionChoice.getHealing()
        
        preHealedHealth = self._player.getHp()
        self._player.heal(healing)
        postHealedHealth = self._player.getHp()
        healed = postHealedHealth - preHealedHealth
        
        inventory.removeItem(potionChoice)
        
        print "%s was healed by %s! %s's health is now %s." \
        % (self._player.getName(), healed, self._player.getName(), 
        self._player.getHp())
예제 #3
0
def getItems(region, numItems, quality):
    """
    Generates random items for shop.

    @param region:       The region the shop is in.
    @param numItems:     The number of items to generate
    @param quality:      Integer from 0-20 that determines quality of items 
                         generated.
    @return:             A list of randomly generated item objects.
    """
    items = ItemSet()

    for item in range(numItems):
        #Generate random number used in determining item type
        randType = random.random()
        
        #Randomize quality
        quality = qualityRandomizer(quality)
        
        #Generate items and append to items list
        if randType < constants.ShopFactoryConstants.WEAPON_UPPER_LIMIT:
            item = genWeapon(quality, region)
            items.addItem(item)
        elif randType < constants.ShopFactoryConstants.ARMOR_UPPER_LIMIT:
            item = genArmor(quality, region)
            items.addItem(item)
        elif randType < constants.ShopFactoryConstants.POTION_UPPER_LIMIT:
            item = genPotion(quality, region)
            items.addItem(item)
        else:
            #Only shops advanced in the game generate uniques
            if (constants.ShopFactoryConstants.UNIQUE_QUALITY_REQ <= 
                quality and lowLevelFindableUniques):
                item = random.choice(lowLevelFindableUniques)
                items.addItem(item)
            #Low-level shops generate additional potions
            else:
                item = genPotion(quality, region)
                items.addItem(item)
                
    return items
예제 #4
0
def getItems(region, numItems, quality):
    """
    Generates random items for shop.

    @param region:       The region the shop is in.
    @param numItems:     The number of items to generate
    @param quality:      Integer from 0-20 that determines quality of items 
                         generated.
    @return:             A list of randomly generated item objects.
    """
    items = ItemSet()

    for item in range(numItems):
        #Generate random number used in determining item type
        randType = random.random()
        
        #Randomize quality
        quality = qualityRandomizer(quality)
        
        #Generate items and append to items list
        if randType < constants.ShopFactoryConstants.WEAPON_UPPER_LIMIT:
            item = genWeapon(quality, region)
            items.addItem(item)
        elif randType < constants.ShopFactoryConstants.ARMOR_UPPER_LIMIT:
            item = genArmor(quality, region)
            items.addItem(item)
        else:
            item = genPotion(quality, region)
            items.addItem(item)
                
    return items
예제 #5
0
class ItemSetTest(unittest.TestCase):
    """
    Tests ItemSet class.
    """
    INITIAL_COUNT = 3
    INITIAL_WEIGHT = 4

    def setUp(self):
        from items.item import Item
        from items.item_set import ItemSet

        sword = Item("sword", "made by elves", 2)
        helmet = Item("helmet", "made by men", 1)
        potion = Item("potion", "restores health", 1)

        self._itemList = [sword, helmet, potion]
        self._items = ItemSet([sword, helmet, potion])

    def tearDown(self):
        self._itemList = self._items = None

    def testInitItemSet(self):
        errorMsg = "ItemSet object has more objects than it was given " \
                    "during initialization."
        self.assertEqual(len(self._items._items), ItemSetTest.INITIAL_COUNT,
                         errorMsg)

        errorMsg = "ItemSet object does not include all objects given " \
                    "during initialization."
        for item in self._itemList:
            self.assertTrue(item in self._items._items, errorMsg)

    def testCountItems(self):
        expectedCount = ItemSetTest.INITIAL_COUNT
        actualCount = self._items.count()

        errorMsg = "Actual count and expected count different for ItemSet object."
        self.assertEqual(expectedCount, actualCount, errorMsg)

    def testAddRemoveContainsItems(self):
        from items.item import Item
        antidote = Item("antidote", "cures poison", 1)

        #Verify item not included in collection
        errorMsg = "ItemSet.containsItem() claimed to contain item not present."
        self.assertFalse(self._items.containsItem(antidote), errorMsg)

        #Add item
        self._items.addItem(antidote)

        errorMsg = "ItemSet.containsItem() failed to identify existing item."
        self.assertTrue(self._items.containsItem(antidote), errorMsg)

        #Remove item
        self._items.removeItem(antidote)

        errorMsg = "ItemSet.containsItem() claimed to contain item not present."
        self.assertFalse(self._items.containsItem(antidote), errorMsg)

    def testItemsWeight(self):
        from items.item import Item

        errorMsg = "Initial weight of ItemSet object incorrect."
        expectedWeight = ItemSetTest.INITIAL_WEIGHT
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

        heavyRock = Item("heavy rock", "weighs a ton", 2000)

        #Add item
        self._items.addItem(heavyRock)

        errorMsg = "ItemSet.weight() reported incorrect weight."
        expectedWeight += 2000
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

        #Remove item
        self._items.removeItem(heavyRock)

        expectedWeight -= 2000
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

    def testItemSetIter(self):
        #Verify iterator returns by ItemSet object visits the exact
        #collection of objects added to ItemSet

        #(Implicitly) use iterator in for loop
        for item in self._items:
            #Verify item returned is recognized
            errorMsg = "ItemSet iterator returned unrecognized object."
            self.assertTrue(item in self._itemList, errorMsg)

            #Remove item from original list of items
            self._itemList.remove(item)

        #Assert all items are accounted for
        errorMsg = "ItemSet object contained Item not added during initialization."
        self.assertEqual(len(self._itemList), 0, errorMsg)
예제 #6
0
class Space(object):
    """
    A given location on the map. Connects with other spaces
    to form larger geographic areas.
    """
    def __init__(self, name, description, region, battleProbability = 0, 
    battleBonusDifficulty = 0, items = None, city = None, uniquePlace = None):
        """
        Initialize a Space object.

        @param name:                   Name of space.
        @param description:            Description of space.
        @param battleProbability:      Probability between [0, 1] that a 
                                       random battle will occur between 
                                       successive game command executions.
        @param battleBonusDifficulty:  Probability between [0, 1] that is used 
                                       to determine battle bonus difficulty. 
                                       This stat results in a percentage 
                                       increase over default monster stats and 
                                       number for any given space.
                                       
                                       For instance, if bonus difficulty is 
                                       set to .5, space will spawn 50% more 
                                       monsters with 150% base stats.
                                       
        @keyword items:                (Optional) Items found in the space.
                                       May be a reference to a single item or 
                                       an ItemSet.
        @keyword city:                 (Optional) City objects in space. May 
                                       be a reference to an individual object 
                                       or a list.
        @keyword uniquePlace:          (Optional) Reference to unique places 
                                       in space. May be a reference to an 
                                       individual object or a list.
        """
        self._exits = {Direction.NORTH : None,
                       Direction.SOUTH : None,
                       Direction.EAST : None,
                       Direction.WEST : None}

        self._name = name
        self._description = description
        self._region = region
        self._battleProbability = battleProbability
        self._battleBonusDifficulty = battleBonusDifficulty
        self._items = ItemSet()
        self._city = city
        self._uniquePlace = uniquePlace

    def getName(self):
        """
        Returns the name of the space.

        @return:    Name of the space.
        """
        return self._name

    def getDescription(self):
        """
        Returns description of space.

        @return:    Description of space.
        """
        return self._description
        
    def getRegion(self):
        """
        Returns the region of the space.
        
        @return:    The region of space.
        """
        return self._region
        
    def getItems(self):
        """
        Returns a string of times.

        @return:    Items in Space (as ItemSet).
        """
        return self._items
        
    def addItem(self, item):
        """
        Adds an item to the space.

        @param item:    Item to add.
        """
        #Special prompt for theOneRing
        if item == theOneRing and self._name != "Orodruin":
            print "\nYou see some strange men walk by."
            return
            
        if isinstance(item, Item):
            self._items.addItem(item)
        elif isinstance(item, list):
            self._items.addItems(item)
        else:
            errorMsg = "space.AddItem() was given invalid item type."
            raise AssertionError(errorMsg)

    def removeItem(self, item):
        """
        Removes an item from the space.

        @param item:    Item to remove.
        """
        self._items.removeItem(item)

    def containsItem(self, item):
        """
        Determines if space contains an item.

        @param item:    Item object to search for.

        @return:    True if item is contained in 
                    Space, False otherwise.
        """
        return self._items.containsItem(item)

    def containsItemString(self, string):
        """
        Determines if space contains an item.

        @param string:   The name-string of 
                         the target item.

        @return:    True if item is contained 
                    in space, False otherwise.
        """ 
        return        self._items.containsItemWithName(string)
    
    def getCity(self):
        """
        Returns city object/objects.

        @return:    Reference to cit(ies).
                    May refer to a single city or list of cities.
        """
        return self._city

    def getUniquePlace(self):
        """
        Returns uniquePlace object(s).

        @return:    Reference to unique place(s).
                    May be reference to a single unique
                    place or a list of unique places.
        """
        return self._uniquePlace

    def getBattleProbability(self):
        """
        Returns probability of a random battle.

        @return:    The probability that a random
                    battle occurs.
        """
        return self._battleProbability

    def getBattleBonusDifficulty(self):
        """
        Returns bonus difficulty attribute of space.

        @return:    The difficulty parameter of space.
        """
        return self._battleBonusDifficulty

    def createExit(self, direction, space, outgoingOnly = False):
        """
        Create an exit to another space. By default, the method creates the 
        appropriate exit in the second space. (This can be suppressed, however, 
        using I{outgoingOnly}).
        
        Spaces can have multiple spaces per direction.

        @param direction:       Direction of exit.
        @param space:           Adjacent space.
        @keyword outgoingOnly:  By default, this method creates the appropriate
                                exit in the second space. Set I{outgoingOnly}
                                to False to suppress this behaviour.
        """
        #Make sure a valid direction has been specified
        if not self._isExit(direction):
            errorMsg = "Direction not valid: %s" % direction
            raise AssertionError(errorMsg)
        
        #Set exit to other space - if a space already exists
        if self._exits[direction]:
            currentSpace = self._exits[direction]
            #If multiple spaces already exist in that direction
            if isinstance(self._exits[direction], list):
                currentSpace.append(space)
            #If a single space exists in that direction
            else:
                self._exits[direction] = [currentSpace, space]
        #If no space already exists
        else:
            self._exits[direction] = space

        #Create exit from other space to this space
        if not outgoingOnly:
            oppositeDirection = self._oppositeDirection(direction)
            #outgoingOnly = True as to not create an infinite loop
            space.createExit(oppositeDirection, self, outgoingOnly = True)

    def clearExit(self, direction, outgoingOnly, space = None):
        """
        Removes an exit to another space. By default, the method removes the 
        appropriate exit from the second space. (This can be suppressed, 
        however, using I{outgoingOnly}).

        @param direction:       Direction of exit.
        @keyword outgoingOnly:  By default, this method removes the appropriate
                                exit from the second space. Set I{outgoingOnly}
                                to False to suppress this behavior.
        """
        #Make sure a valid direction has been specified
        if not self._isExit(direction):
            errorMsg = "Direction not valid: %s" % direction
            raise AssertionError(errorMsg)

        #If exit has not been set, there is nothing to do
        if self._exits[direction] == None:
            return
    
        #Create a temporary copy of adjacent space
        adjSpace = self._exits[direction]
        
        if isinstance(self._exits[direction], list):
            self._exits[direction].remove(space)
        else:
            self._exits[direction] = None
            
        if not outgoingOnly:
            oppositeDirection = self._oppositeDirection(direction)
            adjSpace.clearExit(oppositeDirection, True, space = self)

    def getExit(self, direction):
        """
        Returns a reference to an adjacent space.
        Returns None if no space exists in given direction.

        @param direction:   Direction of adjacent space.
                            Must be one of the directions defined in
                            constants.Direction.
        
        @return:            Reference to space in given direction.
                            (Returns None if no exit is defined
                            for given direction).
        """
        space = self._exits[direction]
        return space

    def getExits(self):
        """
        Returns dictionary of direction-space pairs.

        @return:            Dictionary of direction-space pairs.
        """
        return self._exits

    def _isExit(self, exit):
        """
        Makes sure that a string represents a valid exit.

        @param direction:   Name of exit.

        @return:            True if valid exit, False otherwise.
        """
        availableExits = self._exits.keys()
        if exit not in availableExits:
            return False
            
        return True

    def _oppositeDirection(self, direction):
        """
        Returns the opposite direction. (e.g. North is opposite of South)

        @param direction:   A direction (from constants.Direction)
        
        @return:            Opposite direction (from constants.Direction)
        """
        if direction == Direction.NORTH:
            return Direction.SOUTH
        elif direction == Direction.SOUTH:
            return Direction.NORTH
        elif direction == Direction.EAST:
            return Direction.WEST
        elif direction == Direction.WEST:
            return Direction.EAST
        else:
            raise AssertionError("Not a valid direction: %s" % direction)
예제 #7
0
class Player(object):
    """
    Represents the (human) player.
    """
    def __init__(self, name, location):
        """
        Initializes the player.
        
        @param name:             The name of the player (e.g. "Frodo").
        @param location:         The location of player.
        """
        self._name = name
        self._location = location
        self._money = constants.STARTING_MONEY

        #Initialize player inventory and equipment
        self._inventory = ItemSet()
        self._equipped = ItemSet()

        #Initialize player stats
        self._experience = constants.STARTING_EXPERIENCE
        self._level = constants.STARTING_LEVEL

        self._hp = self._level * constants.HP_STAT
        self._maxHp = self._level * constants.HP_STAT
        self._attack = self._level * constants.ATTACK_STAT

        #Initialize items bonuses
        self._weaponAttack = 0
        self._totalAttack = self._attack + self._weaponAttack
        self._armorDefense = 0

    def getName(self):
        """
        Returns player name.

        @return:          The name of the player.
        """
        return self._name

    def attack(self, target):
        """
        Allows player to attack target. 

        @param target:    The target player is to attack.
        """
        self._totalAttack = self._attack + self._weaponAttack
        target.takeAttack(self._totalAttack)

    def getAttack(self):
        """
        Gets a player's total attack power (including items).
        
        @return:          Sum of player attack and weapon attack.
        """
        return self._totalAtack

    def takeAttack(self, attack):
        """
        Allows player to receive an attack.

        @param attack:     The attack player is to receive.
        """
        self._hp = max(self._hp - max(attack - self._armorDefense, 0), 0)

    def getExperience(self):
        """
        Return's player experience.
        
        @return:    Returns player experience.
        """
        return self._experience

    def increaseExperience(self, newExperience):
        """
        Allows player to receive additional experience.

        @param newExperience:    The experience player is to receive.
        """
        self._experience += newExperience

    def getLevel(self):
        """
        Return's player level.
        
        @return:      Player level.
        """
        return self._level

    def _updateLevel(self):
        """
        Levels up player and updates player stats. 
        """
        #Checks to see if player has leveled up
        if self._level == constants.MAX_LEVEL:
            return
        if self._level != floor(self._experience / 20) + 1:
            self._level = floor(self._experience / 20) + 1

            #Player has leveled up. Updates player level and stats.
            print "%s leveled up! %s is now level %s" \
                  % (self._name, self._name, self._level)
            self._maxHp = self._level * constants.HP_STAT
            self._attack = self._level * constants.ATTACK_STAT
            self._totalAttack = self._attack + self._weaponAttack

    def getHp(self):
        """
        Returns player hp.

        @return:    Player hp.
        """
        return self._hp

    def getMaxHp(self):
        """
        Returns player maximum hp.

        @return:    Player maximum hp.
        """
        return self._maxHp

    def heal(self, amount):
        """
        Allows player to heal up to maximum starting hp.

        @param amount:    The amount of hp to be healed.
        """
        #If amount that player may be healed is less than amount possible
        if self._maxHp - self._hp < amount:
            amountHealed = maxHp - self._hp
        #If amount that player may be healed is equal to or more than amount possible
        else:
            amountHealed = amount

        self._hp += amountHealed

        print "%s got healed by %s! %s's health is now at %s" % (
            self._name, amountHealed, self._name, self._hp)

    def equip(self, item):
        """
        Allows a character to equip an item in inventory.
        
        Note: An item *must* be in the player's inventory
        before it can be equipped. The item must also
        be a piece of Armor or a Weapon.

        @param item:    The item to be equipped.
        """

        #TODO: Need to revisit the logic of this method.
        #      The method should take advantage of the unequip() method
        #      now that it exists.
        #
        #      After that change, review the overall logic
        #      to make sure it makes sense.

        #Check to see if item may be equipped
        if not (item in self._inventory) \
            or not (isinstance(item, Armor) or isinstance(item, Weapon)) \
            or item in self._equipped:
            print ""
            print "Cannot equip %s." % item.getName()
            return

        #Unequip currently equipped armor/weapon if necessary
        if isinstance(item, Armor):
            self._armor = item
            self._armorDefense = self._armor.getDefense()
        elif isinstance(item, Weapon):
            self._weapon = item
            self._weaponAttack = self._weapon.getAttack()

        for currentItem in self._equipped:
            if isinstance(item, Weapon) and isinstance(currentItem, Weapon):
                self.unequip(currentItem)
            elif isinstance(item, Armor) and isinstance(currentItem, Armor):
                self.unequip(currentItem)

        #Update player to reflect equipment
        if isinstance(item, Armor):
            self._armor = item
            self._armorDefense = self._armor.getDefense()
        elif isinstance(item, Weapon):
            self._weapon = item
            self._weaponAttack = self._weapon.getAttack()

        self._equipped.addItem(item)

        print "%s equipped %s." % (self._name, item.getName())

    def unequip(self, item):
        """
        Allows a character to unequip a currently equipped item.

        @param item:    The item to be unequipped.
        """
        print ""
        if item in self._equipped:
            self._equipped.removeItem(item)

            #Update player to reflect equipment
            if isinstance(item, Weapon):
                self._weapon = None
                self._weaponAttack = 0
            if isinstance(item, Armor):
                self._armor = None
                self._armorDefense = 0

            print "%s unequipped %s." % (self._name, item.getName())

        else:
            print "Cannot unequip %s." % item.getName()

    def getWeapon(self):
        """
        Returns play weapon.

        @return:    Player's current weapon.
        """
        return self._weapon

    def getArmor(self):
        """
        Returns player armor.

        @return:    Player's current armor.
        """
        return self._armor

    def getEquipped(self):
        """
        Returns the player's currently equipped equipment.

        @return:    Player's current gear.
        """
        return self._equipped

    def addToInventory(self, item):
        """
        Adds an item to inventory.

        @param item:   The item to be added to inventory.
        """
        if (isinstance(item, Item) and (item not in self._inventory)):
            print "Added %s to inventory." % item.getName()
            self._inventory.addItem(item)
        else:
            print "Cannot add %s to inventory." % item

    def removeFromInventory(self, item):
        """
        Removes an item from inventory. If item is currently equipped, unequips item.

        @param item:   The item to be removed.
        """
        if item in self._inventory:
            if item in self._equipped:
                self.unequip(item)
            self._inventory.removeItem(item)

    def getInventory(self):
        """
        Returns the player's inventory.

        @return:    Player's inventory.
        """
        return self._inventory

    def getMoney(self):
        """
        Returns player's money.

        @return:    Player's money.
        """
        return self._money

    def increaseMoney(self, amount):
        """
        Increases player money.
        """
        if amount <= 0:
            errorMsg = "Method increaseMoney() was given a negative value"
            raise AssertionError(errorMsg)

        self._money += amount

    def decreaseMoney(self, amount):
        """
        Decreases player money.
        """
        if amount <= 0:
            errorMsg = "Method decreaseMoney() was given a negative value"
            raise AssertionError(errorMsg)

        self._money -= amount

    def canMoveNorth(self):
        """
        Determines if player can move north.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.NORTH)

        if exit:
            return True
        return False

    def canMoveSouth(self):
        """
        Determines if player can move south.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.SOUTH)

        if exit:
            return True
        return False

    def canMoveEast(self):
        """
        Determines if player can move east.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.EAST)

        if exit:
            return True
        return False

    def canMoveWest(self):
        """
        Determines if player can move west.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.WEST)

        if exit:
            return True
        return False

    def moveNorth(self):
        """
        Moves player north one space.
        """
        northSpace = self._location.getExit(constants.Direction.NORTH)

        #If north space does not exist, do nothing
        if not northSpace:
            return
        #...otherwise, move to new space
        self._location = northSpace

    def moveSouth(self):
        """
        Moves player south one space.
        """
        southSpace = self._location.getExit(constants.Direction.SOUTH)

        #If south space does not exist, do nothing
        if not southSpace:
            return
        #...otherwise, move to new space
        self._location = southSpace

    def moveEast(self):
        """
        Moves player east one space.
        """
        eastSpace = self._location.getExit(constants.Direction.EAST)

        #If east space does not exist, do nothing
        if not eastSpace:
            return
        #...otherwise, move to new space
        self._location = eastSpace

    def moveWest(self):
        """
        Moves player west one space.
        """
        westSpace = self._location.getExit(constants.Direction.WEST)

        #If west space does not exist, do nothing
        if not westSpace:
            return
        #...otherwise, move to new space
        self._location = westSpace

    def getLocation(self):
        """
        Returns player's current location (i.e. space).

        @return:    Player's current location.
        """
        return self._location
예제 #8
0
class Space(object):
    """
    A given location on the map. Connects with other spaces
    to form larger geographic areas.
    """
    def __init__(self, name, description, items = None, city = None, uniquePlaces = None):
        """
        Initialize a Space object.

        @param name:            Name of space.
        @param description:     Description of space.

        @keyword items:         (Optional) Items found in the space.
                                May be a reference to a single item or an ItemSet.
        @keyword city:          (Optional) Reference to unique place(s).
                                May be a reference to an object or a list.
        @keyword uniquePlaces:  (Optional) Reerence to city/cities. 
                                May be a reference to an object or a list.

        """
        self._exits = { Direction.NORTH : None,
                        Direction.SOUTH : None,
                        Direction.EAST : None,
                        Direction.WEST : None }

        self._name = name
        self._description = description
        #TODO: Need to add items passed into method; items is currently ignored.
        #      Will need to check if items refers to single object or to an ItemSet.
        #      If it points to an ItemSet, you can just set self._items to that ItemSet. 
        #      (self._items = items)
        self._items = ItemSet()
        self._city = city
        self._uniquePlaces = uniquePlaces

    def getName(self):
        """
        Returns the name of the room.

        @return:    Name of the room.
        """
        return self._name

    def getDescription(self):
        """
        Returns description of the room.

        @return:    Description of room.
        """
        return self._description
        
    def getItems(self):
        """
        Returns a string of times.

        @return:    Items in Space (as ItemSet).
        """
        return self._items
        
    def addItem(self, item):
        """
        Adds an item to the room.

        @param item:    Item to add.
        """
        self._items.addItem(item)

    def removeItem(self, item):
        """
        Removes an item from the room.

        @param item:    Item to remove.
        """
        self._items.removeItem(item)

    def containsItem(self, item):
        """
        Determines if room contains an item.

        @param item:    Item object to search for.

        @return:    True if item is contained in Space, False otherwise.
        """
        return self._items.containsItem(item)

    def containsItemString(self, string):
        """
        Determines if room contains an item.

        @param item:     The string associated with the name of the item that we are looking for.

        @return:    True if item is contained in Space, False otherwise.
        """
        #TODO: Use ItemSet's containsItemWithName() instead here. 

        for item in self._items:
            if item.getName() == string:
                return True
            
        return False
    
    def getCity(self):
        """
        Returns city object.

        @return:    Reference to cit(ies).
                    May be reference to single city or list of cities.
        """
        return self._city

    def getUniquePlace(self):
        """
        Returns uniquePlace object(s).

        @return:    Reference to unique place(s).
                    May be reference to single unique place or list of unique places.
        """
        return self._uniquePlaces

    def createExit(self, direction, space, outgoingOnly = False):
        """
        Create an exit to another space. By default,
        the method creates the appropriate exit
        in the second space. (This can be suppressed, however,
        using I{outgoingOnly}).

        @param direction:       Direction of exit.
        @param space:           Adjacent space.
        @keyword outgoingOnly:  By default, this method creates the appropriate
                                exit in the second space. Set I{outgoingOnly}
                                to False to supress this behavior.
        """
        #Make sure a valid direction has been specified
        if not self._isExit(direction):
            errorMsg = "Direction not valid: %s" % direction 
            raise AssertionError(errorMsg)

        #Set exit to other space
        self._exits[direction] = space

        #Create exit from other space to this space
        if not outgoingOnly:
            oppositeDirection = self._oppositeDirection(direction)
            space._exits[oppositeDirection] = self

    def clearExit(self, direction, outgoingOnly):
        """
        Removes an exit to another space. By default,
        the method removes the appropriate exit from
        the second space. (This can be suppressed, however,
        using I{outgoingOnly}).

        @param direction:       Direction of exit.
        @keyword outgoingOnly:  By default, this method removes the appropriate
                                exit from the second space. Set I{outgoingOnly}
                                to False to suppress this behavior.
        """
        #Make sure a valid direction has been specified
        if not self._isExit(direction):
            errorMsg = "Direction not valid: %s" % direction 
            raise AssertionError(errorMsg)

        #If exit has not been set, there is nothing to do
        if self._exits[direction] == None:
            return

        #Create a temporary copy of adjacent space
        adjSpace = self._exits[direction]

        #Clear exit from this space
        self._exits[direction] = None

        #Clear exit from other space to this space
        if not outgoingOnly:
            oppositeDirection = self._oppositeDirection(direction)
            adjSpace._exits[oppositeDirection] = None

    def getExit(self, direction):
        """
        Returns a reference to an adjacent space.
        Returns None if no space exists in given direction.

        @param direction:   Direction of adjacent space.
                            Must be one of the directions defined in
                            constants.Direction.
        
        @return:            Reference to space in given direction.
                            (Returns None if no exit is defined
                            for given direction).
        """
        space = self._exits[direction]
        return space

    def _isExit(self, exit):
        """
        Makes sure that a string represents a valid exit.

        @param direction:   Name of exit.

        @return:            True if valid exit, False otherwise.
        """
        availableExits = self._exits.keys()
        if exit not in availableExits:
            return False
        return True

    def _oppositeDirection(self, direction):
        """
        Returns the opposite direction. (e.g. North is opposite of South)

        @param direction:   A direction (from constants.Direction)
        
        @return:            Opposite direction (from constants.Direction)
        """
        if direction == Direction.NORTH:
            return Direction.SOUTH
        elif direction == Direction.SOUTH:
            return Direction.NORTH
        elif direction == Direction.EAST:
            return Direction.WEST
        elif direciton == Direction.WEST:
            return Direction.EAST
        else:
            raise AssertionError("Not a valid direction: %s" % direction)
예제 #9
0
class ItemSetTest(unittest.TestCase):
    """
    Tests ItemSet class.
    """
    INITIAL_COUNT = 3
    INITIAL_WEIGHT = 4

    def setUp(self):
        from items.item import Item
        from items.item_set import ItemSet

        sword = Item("sword", "made by elves", 2)
        helmet = Item("helmet", "made by men", 1)
        potion = Item("potion", "restores health", 1)

        self._itemList = [sword, helmet, potion]
        self._items = ItemSet([sword, helmet, potion])

    def tearDown(self):
        self._itemList = self._items = None

    def testInitItemSet(self):
        errorMsg = "ItemSet object has more objects than it was given " \
                    "during initialization."
        self.assertEqual(len(self._items._items), ItemSetTest.INITIAL_COUNT, errorMsg)

        errorMsg = "ItemSet object does not include all objects given " \
                    "during initialization."
        for item in self._itemList:
            self.assertTrue(item in self._items._items, errorMsg)

    def testCountItems(self):
        expectedCount = ItemSetTest.INITIAL_COUNT
        actualCount = self._items.count()
        
        errorMsg = "Actual count and expected count different for ItemSet object."
        self.assertEqual(expectedCount, actualCount, errorMsg)

    def testAddRemoveContainsItems(self):
        from items.item import Item
        antidote = Item("antidote", "cures poison", 1)

        #Verify item not included in collection
        errorMsg = "ItemSet.containsItem() claimed to contain item not present."
        self.assertFalse(self._items.containsItem(antidote), errorMsg)

        #Add item
        self._items.addItem(antidote)

        errorMsg = "ItemSet.containsItem() failed to identify existing item." 
        self.assertTrue(self._items.containsItem(antidote), errorMsg)

        #Remove item
        self._items.removeItem(antidote)

        errorMsg = "ItemSet.containsItem() claimed to contain item not present."
        self.assertFalse(self._items.containsItem(antidote), errorMsg)

    def testItemsWeight(self):
        from items.item import Item 

        errorMsg = "Initial weight of ItemSet object incorrect."
        expectedWeight = ItemSetTest.INITIAL_WEIGHT
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

        heavyRock = Item("heavy rock", "weighs a ton", 2000)

        #Add item
        self._items.addItem(heavyRock)

        errorMsg = "ItemSet.weight() reported incorrect weight." 
        expectedWeight += 2000
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

        #Remove item
        self._items.removeItem(heavyRock)

        expectedWeight -= 2000
        actualWeight = self._items.weight()
        self.assertEqual(expectedWeight, actualWeight, errorMsg)

    def testItemSetIter(self):
        #Verify iterator returns by ItemSet object visits the exact
        #collection of objects added to ItemSet

        #(Implicitly) use iterator in for loop
        for item in self._items:
            #Verify item returned is recognized
            errorMsg = "ItemSet iterator returned unrecognized object."
            self.assertTrue(item in self._itemList, errorMsg)

            #Remove item from original list of items
            self._itemList.remove(item)

        #Assert all items are accounted for
        errorMsg = "ItemSet object contained Item not added during initialization."
        self.assertEqual(len(self._itemList), 0, errorMsg)
예제 #10
0
class Player(object):
    """
    Represents the (human) player.
    """
    def __init__(self, name, location):
        """
        Initializes the player.
        
        @param name:             The name of the player (e.g. "Frodo").
        @param location:         The location of player.
        """
        self._name      = name
        self._location  = location
        self._money     = constants.STARTING_MONEY

        #Initialize player inventory and equipment
        self._inventory = ItemSet()
        self._equipped = ItemSet()

        #Initialize player stats
        self._experience = constants.STARTING_EXPERIENCE
        self._level = constants.STARTING_LEVEL
        
        self._hp = self._level * constants.HP_STAT
        self._maxHp = self._level * constants.HP_STAT
        self._attack = self._level * constants.ATTACK_STAT

        #Initialize items bonuses
        self._weaponAttack = 0
        self._totalAttack = self._attack + self._weaponAttack
        self._armorDefense = 0

    def getName(self):
        """
        Returns player name.

        @return:          The name of the player.
        """
        return self._name

    def attack(self, target):
        """
        Allows player to attack target. 

        @param target:    The target player is to attack.
        """
        self._totalAttack = self._attack + self._weaponAttack
        target.takeAttack(self._totalAttack)
        
    def getAttack(self):
        """
        Gets a player's total attack power (including items).
        
        @return:          Sum of player attack and weapon attack.
        """
        return self._totalAtack

    def takeAttack(self, attack):
        """
        Allows player to receive an attack.

        @param attack:     The attack player is to receive.
        """
        self._hp = max(self._hp - max(attack - self._armorDefense, 0), 0)
        
    def getExperience(self):
        """
        Return's player experience.
        
        @return:    Returns player experience.
        """
        return self._experience

    def increaseExperience(self, newExperience):
        """
        Allows player to receive additional experience.

        @param newExperience:    The experience player is to receive.
        """
        self._experience += newExperience
        
    def getLevel(self):
        """
        Return's player level.
        
        @return:      Player level.
        """
        return self._level
        
    def _updateLevel(self):
        """
        Levels up player and updates player stats. 
        """
        #Checks to see if player has leveled up
        if self._level == constants.MAX_LEVEL:
            return
        if self._level != floor(self._experience/20) + 1:
            self._level = floor(self._experience/20) + 1

            #Player has leveled up. Updates player level and stats.
            print "%s leveled up! %s is now level %s" \
                  % (self._name, self._name, self._level)
            self._maxHp = self._level * constants.HP_STAT
            self._attack = self._level * constants.ATTACK_STAT
            self._totalAttack = self._attack + self._weaponAttack
                  
    def getHp(self):
        """
        Returns player hp.

        @return:    Player hp.
        """
        return self._hp

    def getMaxHp(self):
        """
        Returns player maximum hp.

        @return:    Player maximum hp.
        """
        return self._maxHp
        
    def heal(self, amount):
        """
        Allows player to heal up to maximum starting hp.

        @param amount:    The amount of hp to be healed.
        """
        #If amount that player may be healed is less than amount possible
        if self._maxHp - self._hp < amount:
            amountHealed = self._maxHp - self._hp
        #If amount that player may be healed is equal to or more than amount possible
        else:
            amountHealed = amount
            
        self._hp += amountHealed

        print "%s got healed by %s! %s's health is now at %s" % (self._name, amountHealed, self._name, self._hp)

    def equip(self, item):
        """
        Allows a character to equip an item in inventory.
        
        Note: An item *must* be in the player's inventory
        before it can be equipped. The item must also
        be a piece of Armor or a Weapon.

        @param item:    The item to be equipped.
        """

		#TODO: Need to revisit the logic of this method.
		#      The method should take advantage of the unequip() method
        #      now that it exists.
        #
        #      After that change, review the overall logic
        #      to make sure it makes sense.

        #Check to see if item may be equipped
        if not (item in self._inventory) \
            or not (isinstance(item, Armor) or isinstance(item, Weapon)) \
            or item in self._equipped:
            print ""
            print "Cannot equip %s." %item.getName()
            return

        #Unequip currently equipped armor/weapon if necessary
        if isinstance(item, Armor):
            self._armor = item
            self._armorDefense = self._armor.getDefense()
        elif isinstance(item, Weapon):
            self._weapon = item
            self._weaponAttack = self._weapon.getAttack()

        for currentItem in self._equipped:
            if isinstance(item, Weapon) and isinstance(currentItem, Weapon):  
                self.unequip(currentItem)
            elif isinstance(item, Armor) and isinstance(currentItem, Armor):
                self.unequip(currentItem)
            
        #Update player to reflect equipment
        if isinstance(item, Armor):
            self._armor = item
            self._armorDefense = self._armor.getDefense()
        elif isinstance(item, Weapon):
            self._weapon = item
            self._weaponAttack = self._weapon.getAttack()

        self._equipped.addItem(item)
        
        print "%s equipped %s." %(self._name, item.getName())
            
    def unequip(self, item):
        """
        Allows a character to unequip a currently equipped item.

        @param item:    The item to be unequipped.
        """
        print ""
        if item in self._equipped:
            self._equipped.removeItem(item)
            
            #Update player to reflect equipment
            if isinstance(item, Weapon):
                self._weapon = None
                self._weaponAttack = 0
            if isinstance(item, Armor):
                self._armor = None
                self._armorDefense = 0
                
            print "%s unequipped %s." % (self._name, item.getName())
            
        else:
            print "Cannot unequip %s." % item.getName()

    def getWeapon(self):
        """
        Returns play weapon.

        @return:    Player's current weapon.
        """
        return self._weapon

    def getArmor(self):
        """
        Returns player armor.

        @return:    Player's current armor.
        """
        return self._armor

    def getEquipped(self):
        """
        Returns the player's currently equipped equipment.

        @return:    Player's current gear.
        """
        return self._equipped
    
    def addToInventory(self, item):
        """
        Adds an item to inventory.

        @param item:   The item to be added to inventory.
        """
        if (isinstance(item, Item) and (item not in self._inventory)):
            print "Added %s to inventory." % item.getName()
            self._inventory.addItem(item)
        else:
            print "Cannot add %s to inventory." % item

    def removeFromInventory(self, item):
        """
        Removes an item from inventory. If item is currently equipped, unequips item.

        @param item:   The item to be removed.
        """
        if item in self._inventory:
            if item in self._equipped:
                self.unequip(item)
            self._inventory.removeItem(item)
    
    def getInventory(self):
        """
        Returns the player's inventory.

        @return:    Player's inventory.
        """
        return self._inventory

    def getMoney(self):
        """
        Returns player's money.

        @return:    Player's money.
        """
        return self._money

    def increaseMoney(self, amount):
        """
        Increases player money.
        """
        if amount <= 0:
            errorMsg = "Method increaseMoney() was given a negative value"
            raise AssertionError(errorMsg)

        self._money += amount
        
    def decreaseMoney(self, amount):
        """
        Decreases player money.
        """
        if amount <= 0:
            errorMsg = "Method decreaseMoney() was given a negative value"
            raise AssertionError(errorMsg)

        self._money -= amount
    
    def canMoveNorth(self):
        """
        Determines if player can move north.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.NORTH)

        if exit:
            return True
        return False

    def canMoveSouth(self):
        """
        Determines if player can move south.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.SOUTH)

        if exit:
            return True
        return False

    def canMoveEast(self):
        """
        Determines if player can move east.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.EAST)

        if exit:
            return True
        return False

    def canMoveWest(self):
        """
        Determines if player can move west.

        @return:    True if possible, false otherwise.
        """
        exit = self._location.getExit(constants.Direction.WEST)

        if exit:
            return True
        return False


    def moveNorth(self):
        """
        Moves player north one space.
        """
        northSpace = self._location.getExit(constants.Direction.NORTH) 
        
        #If north space does not exist, do nothing
        if not northSpace:
            return
        #...otherwise, move to new space 
        self._location = northSpace

    def moveSouth(self):
        """
        Moves player south one space.
        """
        southSpace = self._location.getExit(constants.Direction.SOUTH)

        #If south space does not exist, do nothing
        if not southSpace:
            return
        #...otherwise, move to new space 
        self._location = southSpace 

    def moveEast(self):
        """
        Moves player east one space.
        """
        eastSpace = self._location.getExit(constants.Direction.EAST)

        #If east space does not exist, do nothing
        if not eastSpace:
            return
        #...otherwise, move to new space 
        self._location = eastSpace 

    def moveWest(self):
        """
        Moves player west one space.
        """
        westSpace = self._location.getExit(constants.Direction.WEST)

        #If west space does not exist, do nothing
        if not westSpace:
            return
        #...otherwise, move to new space 
        self._location = westSpace 

    def getLocation(self):
        """
        Returns player's current location (i.e. space).

        @return:    Player's current location.
        """
        return self._location
예제 #11
0
class Player(object):
    """
    Represents the (human) player.
    """
    def __init__(self, name, location):
        """
        Initializes the player.
        
        @param name:             The name of the player (e.g. "Frodo").
        @param location:         The location of player. When initialized,
                                 given space "shire."
        """
        self._name      = name
        self._location  = location
        
        #Initialize player stats
        self._money      = constants.PlayerInitialization.MONEY
        self._experience = constants.PlayerInitialization.EXPERIENCE
        self._level      = constants.PlayerInitialization.LEVEL
        
        self._hp          = constants.PlayerInitialization.MAX_HP
        self._maxHp       = constants.PlayerInitialization.MAX_HP
        self._attack      = constants.PlayerInitialization.ATTACK
        self._weightLimit = constants.PlayerInitialization.WEIGHT_LIMIT
        
        #Initialize player inventory and equipment
        self._inventory = ItemSet()
        self._equipped  = ItemSet()

        #Initialize item-based bonuses
        self._weaponAttack = constants.PlayerInitialization.WEAPON_ATTACK
        self._armorDefense = constants.PlayerInitialization.ARMOR_DEFENSE
        
        self._charmAttack   = constants.PlayerInitialization.CHARM_ATTACK
        self._charmDefense  = constants.PlayerInitialization.CHARM_DEFENSE
        self._charmHp       = constants.PlayerInitialization.CHARM_HP

        #Update player stats for item-based bonuses
        self._totalAttack    = (self._attack + self._weaponAttack + 
            self._charmAttack)
        self._totalDefense   = self._armorDefense + self._charmDefense
        self._totalMaxHp     = self._maxHp + self._charmHp
        
    def getName(self):
        """
        Returns player name.

        @return:          The name of the player.
        """
        return self._name

    def attack(self, target):
        """
        Allows player to attack target. 

        @param target:    The target player is to attack.
        """
        target.takeAttack(self._totalAttack)
        
    def getAttack(self):
        """
        Gets a player's total attack power (excluding items).
        
        @return:          Base player attack.
        """
        return self._attack

    def getTotalAttack(self):
        """
        Gets player's total attack power (including items).

        @return:          Total player attack value.
        """
        return self._totalAttack

    def takeAttack(self, attack):
        """
        Allows player to receive an attack.

        @param attack:     The attack player is to receive.
        """
        self._hp = max(self._hp - max(attack - self._totalDefense, 0), 0)
        
    def getTotalDefense(self):
        """
        Returns player's total defense.
        
        @return:     Player's total defense stat.
        """
        return self._totalDefense
        
    def getCharmAttack(self):
        """
        Returns player's charm attack.
        
        @return:     Player's charm attack stat.
        """
        return self._charmAttack
        
    def getCharmDefense(self):
        """
        Returns player's charm defense.
        
        @return:     Player's charm defense stat.
        """
        return self._charmDefense
        
    def getCharmHp(self):
        """
        Returns player's charm hp.
        
        @return:     Player's charm hp stat.
        """
        return self._charmHp
        
    def getWeightLimit(self):
        """
        Returns player's weight limit.
        
        @return:     Player weight limit.
        """
        return self._weightLimit
        
    def getExperience(self):
        """
        Return's player experience.
        
        @return:    Returns player experience.
        """
        return self._experience

    def increaseExperience(self, newExperience):
        """
        Allows player to receive additional experience.
        Runs _updateLevel() upon receiving additional
        experience.

        @param newExperience:    The experience player 
                                 is to receive.
        """
        self._experience += newExperience
        self._updateLevel()
        
    def getLevel(self):
        """
        Return's player level.
        
        @return:      Player level.
        """
        return self._level
        
    def _updateLevel(self):
        """
        Levels up player and updates player stats. This method creates a list 
        of levels for which player experiences qualifies. Player level is the 
        highest level for which player experience qualifies. 
        
        After level-up is determined, player stats are updated.
        """
        #Checks to see if player is max level
        if self._level == constants.MAX_LEVEL:
            return
            
        #Check to see if player has leveled up
        currentLevel = self._level
        potentialLevels = []
        
        #Create list of levels for which player experience qualifies
        for level in constants.LEVEL_EXP_REQUIREMENT:
            if self._experience >= constants.LEVEL_EXP_REQUIREMENT[level]:
                potentialLevels.append(level)
        
        #Player level is the highest of the qualified levels
        potentialNewLevel = max(potentialLevels)
        
        #If player has leveled up
        if currentLevel != potentialNewLevel:
            numberLevelUp = potentialNewLevel - currentLevel
            self._level = potentialNewLevel
            print "\n%s leveled up! %s is now level %s!" \
                  % (self._name, self._name, self._level)
                  
            #Updates player level and stats
            for level in range(numberLevelUp):
                self._maxHp = floor(self._maxHp * constants.HP_STAT)
                self._totalMaxHp = self._maxHp + self._charmHp
                self._attack = floor(self._attack * constants.ATTACK_STAT)
                self._totalAttack = (self._attack + self._weaponAttack + 
                    self._charmAttack)
                self._weightLimit = floor(self._weightLimit * 
                    constants.WEIGHT_LIMIT_STAT)
            
    def getHp(self):
        """
        Returns player hp.

        @return:    Player hp.
        """
        return self._hp

    def getMaxHp(self):
        """
        Returns player maximum hp.

        @return:    Player maximum hp.
        """
        return self._maxHp
        
    def getTotalMaxHp(self):
        """
        Returns player maximum hp, including charms.

        @return:    Player maximum hp.
        """
        return self._totalMaxHp
        
    def heal(self, amount):
        """
        Allows player to heal up to totalMaxHp.

        @param amount:    The amount of hp to be healed.
        """
        #If amount that player may be healed is less than amount possible
        if self._totalMaxHp - self._hp < amount:
            amountHealed = self._totalMaxHp - self._hp
            
        #If amount that player may be healed is greater than or equal to the 
        #amount possible
        else:
            amountHealed = amount
            
        self._hp += amountHealed

    def equip(self, item):
        """
        Allows a character to equip an item.
        
        Preconditions:
        -Item in inventory.
        -Item is instance of Armor, Weapon, or Charm.
        -Item is not currently in self._equipped.

        @param item:    The item to be equipped.
        """
        #Check to see that preconditions are met
        if item not in self._inventory:
            statement =  "%s not currently in inventory." % item.getName()
            return statement
        if not (isinstance(item, Armor) or isinstance(item, Weapon) or 
            isinstance(item, Charm)):
            statement = "Item must be a weapon, armor, or charm."
            return statement
        if item in self._equipped:
            statement =  "%s already equipped." % item.getName()
            return statement
        
        #Unequip currently equipped armor/weapon if necessary
        for currentItem in self._equipped:
            if isinstance(item, Weapon) and isinstance(currentItem, Weapon):  
                self.unequip(currentItem)
            elif isinstance(item, Armor) and isinstance(currentItem, Armor):
                self.unequip(currentItem)

        #Equip new item
        self._equipped.addItem(item)
        if isinstance(item, Weapon):
            self._weaponAttack = item.getAttack()
            self._totalAttack = (self._attack + self._weaponAttack + 
                self._charmAttack)
        elif isinstance(item, Armor):
            self._armorDefense = item.getDefense()
            self._totalDefense = self._armorDefense + self._charmDefense
        elif isinstance(item, Charm):
            self._charmAttack += item.getAttack()
            self._charmDefense += item.getDefense()
            self._charmHp += item.getHp()
            self._totalAttack = (self._attack + self._weaponAttack + 
                self._charmAttack)
            self._totalDefense = self._armorDefense + self._charmDefense
            self._totalMaxHp = self._maxHp + self._charmHp
        
        statement = "%s equipped %s." %(self._name, item.getName())
        
        #Sort self._equipped
        sortItems(self._equipped)
        
        return statement
        
    def unequip(self, item):
        """
        Allows a character to unequip a currently equipped item.

        @param item:    The item to be unequipped.
        """
        #Precondition - that item is currently equipped.
        if item not in self._equipped:
            statement = "%s not in equipped items." % item.getName()
            return statement
        
        #Unequip item and update player stats
        self._equipped.removeItem(item)
        
        if isinstance(item, Weapon):
            self._weaponAttack = 0
            self._totalAttack = (self._attack + self._weaponAttack + 
                self._charmAttack)
        if isinstance(item, Armor):
            self._armorDefense = 0
            self._totalDefense = self._armorDefense + self._charmDefense
        if isinstance(item, Charm):
            charmAttack = item.getAttack()
            charmDefense = item.getDefense()
            charmHp = item.getHp()
            
            self._charmAttack -= charmAttack
            self._charmDefense -= charmDefense
            self._charmHp -= charmHp
            
            self._totalAttack = (self._attack + self._weaponAttack + 
                self._charmAttack)
            self._totalDefense = self._armorDefense + self._charmDefense
            self._totalMaxHp = self._maxHp + self._charmHp
        
        #Update player Hp for charms
        self._updateHpForCharms()
        
        #Sort self._equipped
        sortItems(self._equipped)
        
        statement = "%s unequipped %s." % (self._name, item.getName())
        return statement
        
    def _updateHpForCharms(self):
        """
        For unequiping charms, player HP needs to be updated to reflect new 
        totalMaxHp.
        """
        currentHp = self._hp
        if self._totalMaxHp < currentHp:
            self._hp = self._totalMaxHp
    
    def getEquipped(self):
        """
        Returns the player's currently equipped equipment.

        @return:    Player's current gear.
        """
        sortItems(self._equipped)
        
        return self._equipped
    
    def addToInventory(self, item):
        """
        Adds an item to inventory.

        @param item:   The item to be added to inventory.
        
        @return:       True if execution suceeds, False 
                       otherwise.
        """
        inventory = self._inventory
        
        #If user input is not an item
        if not isinstance(item, Item):
            errorMsg = "Not an item."
            raise AssertionError(errorMsg)
        
        #Check inventory weight restriction
        itemWeight = item.getWeight()
        inventoryWeight = inventory.getWeight()
        
        if itemWeight + inventoryWeight > self._weightLimit:
            print "You are overburdened."
            return False
        
        #Successful execution
        inventory.addItem(item)
        sortItems(inventory)
        print "Added %s to inventory." % item.getName()
        return True
            
    def removeFromInventory(self, item):
        """
        Removes an item from inventory. If item is currently 
        equipped, unequips item.

        @param item:   The item to be removed.
        """
        #Item must be in inventory
        if not item in self._inventory:
            return
        
        #Unequip if necessary
        if item in self._equipped:
            self.unequip(item)
            
        self._inventory.removeItem(item)
        sortItems(self._inventory)
    
    def getInventory(self):
        """
        Returns the player's inventory.

        @return:    Player's inventory.
        """
        sortItems(self._inventory)
        
        return self._inventory
   
    def getMoney(self):
        """
        Returns player's money.

        @return:    Player's money.
        """
        return self._money

    def increaseMoney(self, amount):
        """
        Increases player money.
        """
        if amount < 0:
            errorMsg = "Method increaseMoney() was given a negative value."
            raise AssertionError(errorMsg)

        self._money += amount
        
    def decreaseMoney(self, amount):
        """
        Decreases player money.
        """
        if amount < 0:
            errorMsg = "Method decreaseMoney() was given a negative value."
            raise AssertionError(errorMsg)

        self._money -= amount
    
    def canMoveNorth(self):
        """
        Determines if player can move north.

        @return:    True if possible, False otherwise.
        """
        exit = self._location.getExit(constants.Direction.NORTH)

        if exit:
            return True
            
        return False

    def canMoveSouth(self):
        """
        Determines if player can move south.

        @return:    True if possible, False otherwise.
        """
        exit = self._location.getExit(constants.Direction.SOUTH)

        if exit:
            return True
            
        return False

    def canMoveEast(self):
        """
        Determines if player can move east.

        @return:    True if possible, False otherwise.
        """
        exit = self._location.getExit(constants.Direction.EAST)

        if exit:
            return True
            
        return False

    def canMoveWest(self):
        """
        Determines if player can move west.

        @return:    True if possible, False otherwise.
        """
        exit = self._location.getExit(constants.Direction.WEST)

        if exit:
            return True
            
        return False

    def moveNorth(self):
        """
        Moves player north one space.
        """
        northSpace = self._location.getExit(constants.Direction.NORTH) 
        
        #If north space does not exist, do nothing
        if not northSpace:
            return
            
        #...Otherwise, move to new space
        if not isinstance(northSpace, list):
            self._location = northSpace
        else:
            self._moveList(northSpace)

    def moveSouth(self):
        """
        Moves player south one space.
        """
        southSpace = self._location.getExit(constants.Direction.SOUTH)

        #If south space does not exist, do nothing
        if not southSpace:
            return
            
        #...Otherwise, move to new space 
        if not isinstance(southSpace, list):
            self._location = southSpace
        else:
            self._moveList(southSpace)

    def moveEast(self):
        """
        Moves player east one space.
        """
        eastSpace = self._location.getExit(constants.Direction.EAST)

        #If east space does not exist, do nothing
        if not eastSpace:
            return
            
        #...Otherwise, move to new space 
        if not isinstance(eastSpace, list):
            self._location = eastSpace
        else:
            self._moveList(eastSpace)

    def moveWest(self):
        """
        Moves player west one space.
        """
        westSpace = self._location.getExit(constants.Direction.WEST)

        #If west space does not exist, do nothing
        if not westSpace:
            return
            
        #...Otherwise, move to new space 
        if not isinstance(westSpace, list):
            self._location = westSpace
        else:
            self._moveList(westSpace)
    
    def _moveList(self, spaces):
        """
        Helper method for the four movement commands. Processes cases when 
        there are multiple spaces available for a single direction.
        """
        acceptableChoices = {}
        choice = None
        
        #Solicit user input
        print "You may move to the following:"
        for space in spaces:
            print "\t-%s" % space.getName()
            acceptableChoices[space] = space.getName()
        print ""
        
        while choice not in acceptableChoices.values():
            choice = raw_input("Where would you like to go? ")

        #Move to new space
        for pair in acceptableChoices.items():
            if choice in pair:
                space = pair[0]
                break
        self._location = space
        
    def getLocation(self):
        """
        Returns player's current location.

        @return:    Player current location.
        """
        return self._location