Exemplo n.º 1
0
class Entity(object):
    all_NPCs = []
    all_things = []
    player = None

    @staticmethod
    def add_new(entity):
        P = entity.properties
        if 'NPC' in P:
            Entity.all_NPCs.append(entity)
        elif 'thing' in P:
            Entity.all_things.append(entity)
        elif 'player' in P:
            Entity.player = entity

    @staticmethod
    def remove_old(entity):
        P = entity.properties
        if 'NPC' in P:
            Entity.all_NPCs.remove(entity)
        elif 'thing' in P:
            Entity.all_things.remove(entity)
        elif 'player' in P:
            Entity.player = None

    @staticmethod
    def erase_all_entities():
        Entity.all_NPCs = []
        Entity.all_things = []
        Entity.player = None

    def __init__(self, **kwargs):
        self.ID = kwargs.get('ID', None)
        self.properties = kwargs.get('properties', '')
        if 'tile' in self.properties:
            self.tile = self
        else:
            self.tile = kwargs.get('tile', None)
        if 'container' in self.properties:
            self.container = container.Container()
        if 'stackable' in self.properties:
            self.quantity = kwargs.get('quantity', 1)
        if 'NPC' in self.properties or 'player' in self.properties:
            self.attack = kwargs.get('attack', None)
            self.defense = kwargs.get('defense', None)
        if 'alive' in self.properties:
            self.hp = Resource(maximum=kwargs['hp'])
            self.is_alive = True
        if 'player' in self.properties:
            self.name = 'George'
        if 'needs food' in self.properties:
            self.hunger = Resource(maximum=kwargs['hunger'])
        if 'has vision' in self.properties:
            self.visibility_radius = kwargs['visibility radius']
            self.fov = FOV(self.tile, self.visibility_radius)
        if 'drawable' in self.properties:
            self.icon = kwargs.get('icon', '?')
            self.description = kwargs.get('description', '')
            self.color = kwargs.get('color', None)
            self.image = kwargs.get('image', None)
        if 'equipable' in self.properties:
            self.equipped = False
        if 'consumable' in self.properties:
            self.effects = kwargs.get('effects', {})

        for condition in kwargs.get('conditions', []):
            self.add_condition(condition)

        Entity.add_new(self)

    # OBJECTS HANDLING
    # ---- start -----
    def remove_tile(self):
        self.tile.container.rem(self)
        self.tile = None

    def set_tile(self, new_tile):
        new_tile.container.add(self)
        self.tile = new_tile

    def drop(self, item):
        # todo: move stackable into container
        ticks = 0
        message = None
        if item is None or item not in self.container:
            return ticks, message
        if 'stackable' in item.properties and item.quantity > 1:
            self.container.rem(item)
            new_item = copy.deepcopy(item)
            new_item.quantity = 1
            new_item.set_tile(self.tile)
        else:
            self.container.rem(item)
            item.set_tile(self.tile)
        message = 'You dropped %s' % item.ID
        return ticks, message

    def equip(self, item):
        ticks = 0
        message = None
        if 'equipable' in item.properties and not item.equipped:
            for condition in item.effects:
                self.add_condition(condition)
            item.equipped = True
            message = 'You put on %s.' % item.ID
            ticks = 1
        return ticks, message


    def pick(self, item):
        ticks = 1
        message = 'You picked up %s' % item.ID
        assert 'pickable' in item.properties
        item.remove_tile()
        self.container.add(item)
        return ticks, message

    def consume(self, item):
        assert 'consumable' in item.properties
        ticks = 1
        message = '%s consumed a %s' % (self.ID, item.ID)
        for condition in item.effects:
            self.add_condition(condition)
        self.container.rem(item)
        return ticks, message
    #----- end ------

    # CONDITIONS HANDLING
    def add_condition(self, condition):
        getattr(self, condition['resource']).add_condition(condition)

    # MOVEMENT HANDLING
    #----- start ------
    def move(self, target_tile):
        ticks = 0
        message = None
        b1 = 'movable' in self.properties
        b2 = not 'movement blocking' in target_tile.properties
        b3 = not target_tile.container.get(properties='movement blocking')

        if b1 and b2 and b3 and b3:
            self.tile.container.rem(self)
            target_tile.container.add(self)
            self.tile = target_tile
            ticks = 1
            message = 'Moved'
        return ticks, message

    def open_door(self, target_tile):
        ticks = 0
        message = None
        if 'can open doors' in self.properties and target_tile.tip == 'open door':
            target_tile.set_tip('open door')
            ticks = 1
            message = 'A door has been opened.'
        return ticks, message
    #----- end -----

    # ATTACK - TAKE HIT - DIE
    # ---- start ----
    def attack_to(self, other):
        ticks = 1
        message1 = self.hit(other)
        message2 = other.hit(self)
        message = message1 + ' ' + message2
        return ticks, message

    def hit(self, other):
        damage = max(self.attack - other.defense, 0)
        other.hp.change_current(-damage)
        message = '%s hit %s for %d damage.' % (self.ID, other.ID, damage)
        return message

    def update_status(self):
        assert 'NPC' in self.properties or 'player' in self.properties
        message = None
        game_over = False
        if 'needs food' in self.properties and self.hunger.less_than_minimum():
            self.is_alive = False
            message = '%s died of hunger.' % self.ID
        elif self.hp.less_than_minimum():
            self.is_alive = False
            message = '%s is dead.' % self.ID
        # is self dead
        if not self.is_alive:
            if 'NPC' in self.properties:
                self.remove_tile()
                Entity.remove_old(self)
            elif 'player' in self.properties:
                game_over = True

        return message, game_over

    def update_vision(self):
        self.fov.update(self.tile, self.visibility_radius)

    @property
    def inventory_repr(self):
        if 'stackable' in self.properties:
            return str(self.quantity) + ' ' + self.ID
        else:
            return self.ID