Search code examples
pythonpython-2.7attributeerror

Python; AttributeError: typeObject 'Object' has no attribute 'name', but I declared 'name' attribute


I (re)searched a lot about this problem, but I didn't manage to find proper answer/solution, although many subjects is about similar problem.

I make roguelike game (with libtcodpy library) and I encountered a problem.

I have class Object, classes that control opponents and function which opens the door.

class Object:

class Object:
    #obiekty
    def __init__(self, x, y, char, name, color, blocks=False, always_visible=False, remember=None, fighter=None, ai=None, item=None, equipment=None):
        self.x = x
        self.y = y
        self.char = char
        self.name = name
        self.color = color
        self.blocks = blocks
        self.always_visible = always_visible

        self.remember = remember

        if self.remember:
            self.remember.owner = self

        self.fighter = fighter
        if self.fighter: 
            self.fighter.owner = self

        self.ai = ai
        if self.ai:
            self.ai.owner = self

        self.item = item
        if self.item:
            self.item.owner = self

        self.equipment = equipment
        if self.equipment:
            self.equipment.owner = self

        self.item = Item()
            self.item.owner = self

    def move(self, dx, dy):
        #move if not blocked
        if not is_blocked(self.x + dx, self.y + dy):
            self.x += dx
            self.y += dy    

    def move_shop(self, dx, dy):
        #move in shops
        if not is_blocked(self.x + dx, self.y + dy) and is_object(self.x + dx, self.y + dy):
            self.x += dx
            self.y += dy

    def move_towards(self, target_x, target_y):
    #move to player
        dx = target_x - self.x
        dy = target_y - self.y
        ddx = 0
        ddy = 0
        if dx > 0:
            ddx = 1
        elif dx < 0:
            ddx = -1
        if dy > 0:
            ddy = 1
        elif dy < 0:
            ddy = -1
        if not is_blocked(self.x + ddx, self.y + ddy):
            self.move(ddx, ddy)
        elif is_blocked(self.x + ddx, self.y + ddy):
            if not is_door(self.x + ddx, self.y + ddy):
                if ddx != 0:
                    if not is_blocked(self.x + ddx, self.y):
                        self.move(ddx, 0)
                        return
                if ddy != 0:
                    if not is_blocked(self.x, self.y + ddy):
                        self.move(0, ddy)
                        return
            elif is_door(self.x + ddx, self.y + ddy):
                if ddx != 0:
                    use_door(object)
                    return
                elif ddy != 0:
                    use_door(object)
                    return

def distance_to(self, other):
    #return distance to object
    dx = other.x - self.x
    dy = other.y - self.y
    return math.sqrt(dx ** 2 + dy ** 2)

def distance(self, x, y):
    #return distance to coords
    return math.sqrt((x - self.x) ** 2 + (y - self.y) ** 2)

def send_to_back(self):
    #drawning objects
    global objects
    objects.remove(self)
    objects.insert(0, self)

def draw(self):
    if (libtcod.map_is_in_fov(fov_map, self.x, self.y) or
            (self.always_visible and map[self.x][self.y].explored)):
        libtcod.console_set_default_foreground(con, self.color)
        libtcod.console_put_char(con, self.x, self.y, self.char, libtcod.BKGND_NONE)

def clear(self):
    #erase
    if libtcod.map_is_in_fov(fov_map, self.x, self.y):
        libtcod.console_put_char_ex(con, self.x, self.y, '.', libtcod.darker_yellow, libtcod.black)

simple 'ai' class for unique npc:

class ImpNPC1_2:
    global friendly_villages, hostile_villages, hostile_npc

    memory_x = None
    memory_y = None

    def take_turn(self):
        #monsters turn
        monster = self.owner
            if '2npc_1c' not in hostile_npc:
                if '1st_city' in friendly_villages:
                    if libtcod.map_is_in_fov(fov_map, monster.x, monster.y):
                        self.owner.move_shop(libtcod.random_get_int(0, -1, 1), libtcod.random_get_int(0, -1, 1))
                if '1st_city' in hostile_villages:
                    if libtcod.map_is_in_fov(fov_map, monster.x, monster.y):
                        self.memory_x = player.x
                        self.memory_y = player.y
                        if monster.distance_to(player) >= 2:
                            monster.move_towards(player.x, player.y)

                        elif player.fighter.hp > 0:
                            monster.fighter.attack(player)
                    elif self.memory_x != None and self.memory_y != None: #simple fake-memory
                        monster.move_towards(self.memory_x, self.memory_y)
                        if monster.x == self.memory_x and monster.y == self.memory_y or libtcod.random_get_int(0, 0, 100) > AI_INTEREST:
                            self.memory_x = None
                            self.memory_y = None
                    else:
                        while True:
                            x = libtcod.random_get_int(0, monster.x - 20, monster.x + 20)
                            y = libtcod.random_get_int(0, monster.y - 20, monster.y + 20)
                            if can_walk_between(monster.x, monster.y, x, y): break
                        self.memory_x = x
                        self.memory_y = y
            if '2npc_1c' in hostile_npc:
                if libtcod.map_is_in_fov(fov_map, monster.x, monster.y):
                    self.memory_x = player.x
                    self.memory_y = player.y
                    if monster.distance_to(player) >= 2:
                        monster.move_towards(player.x, player.y)
                    elif player.fighter.hp > 0:
                        monster.fighter.attack(player)
                elif self.memory_x != None and self.memory_y != None:
                    monster.move_towards(self.memory_x, self.memory_y)
                    if monster.x == self.memory_x and monster.y == self.memory_y or libtcod.random_get_int(0, 0, 100) > AI_INTEREST:
                        self.memory_x = None
                        self.memory_y = None
                else:
                    while True:
                        x = libtcod.random_get_int(0, monster.x - 20, monster.x + 20)
                        y = libtcod.random_get_int(0, monster.y - 20, monster.y + 20)
                        if can_walk_between(monster.x, monster.y, x, y): break
                    self.memory_x = x
                    self.memory_y = y

(yup, I know this is repetitive, but I'm going to specify npc's behavior while in hostile_village).

Function use_door:

#DRZWI
def use_door(object):
    if 'locked' in object.name:
        message('The door is locked.', libtcod.white)
        return

    if 'closed' in object.name:
        map[object.x][object.y].blocked = False
        map[object.x][object.y].block_sight = False
        map[object.x][object.y].it_is_door = False
        object.blocks = False
        object.char = '/'
        object.name = 'open door'
        fov_recompute = True
    for obj in objects:
        if 'closed' in obj.name and obj.x == object.x + 1 and obj.y == object.y:
            return
        if 'closed' in obj.name and obj.x == object.x - 1 and obj.y == object.y:
            return
        if 'closed' in obj.name and obj.x == object.x and obj.y == object.y + 1:
            return
        if 'closed' in obj.name and obj.x == object.x and obj.y == object.y - 1:
            return
    initialize_fov()
    return

    if 'open' in object.name:
        map[object.x][object.y].blocked = True
        map[object.x][object.y].block_sight = True
        map[object.x][object.y].it_is_door = True
        object.blocks = True
        object.char = '+'
        object.name = 'closed door'
        fov_recompute = True
        for obj in objects:
            if 'open' in obj.name and obj.x == object.x + 1 and obj.y == object.y:
                return
            if 'open' in obj.name and obj.x == object.x - 1 and obj.y == object.y:
                return
            if 'open' in obj.name and obj.x == object.x and obj.y == object.y + 1:
                return
            if 'open' in obj.name and obj.x == object.x and obj.y == object.y - 1:
                return
        initialize_fov()
        return

Other code fragments (I think that this may be useful to locate problem):

def is_blocked(x, y):
    #check blocktiles
    if map[x][y].blocked:
        return True

    for object in objects:
        if object.blocks and object.x == x and object.y == y:
            return True

    return False

def is_object(x, y):
    #check objects
    if map[x][y].it_is_object:
        return True

    for object in objects:
        if object.blocks and object.x == x and object.y == y:
            return True

    return False

def is_door(x, y):
    #check doors
    if map[x][y].it_is_door:
        return True

    for object in objects:
        if object.blocks and object.x == x and object.y == y:
            return True

    return False

###ANOTHER_PIECE_OF_CODE

def make_1st_city():
    global map
    global objects
    global village
    global upstairs
    global downstairs
    objects = [player]
    player.x = 3
    player.y = 20
    map = [ [ Tile(True) for y in range(MAP_HEIGHT) ] for x in range(MAP_WIDTH) ]
    smap = ['################################################################################',
            '#GGHHGGGHHGGGGHGGHGHGGGHGGHGGHHGGHGHGGHHGGHGGHGHGGGHGHHHGGHGGGHHGGGHHGGHGHGHGHG#',
            '#G1111111111111111111111111111111111111111111111111111111111111111111111111111G#',
            '#H1676767676767676767676111111111111111111111111111111122222222222221111111111G#',
            '#G16767676767676767676761111111111111111111111111111111KJJJJJJJJJJJ21111111111H#',
            '#G167676767676767676767611222222K2222222K222221111111113JJJJJJJJJJJ21111111111G#',
            '#H1676767676767676767676112JJJJJJJJJJJJJJJJJJ2111111111KJJJJJJJJJJJ21111111111H#',
            '#G1676767676767676767676112JJJJJJJJJJJJJJJJJJ211111111122222222222221111111111G#',
            '#H167676767676767676767611KJJJJJJJJJJJJJJJJJJK11111111111111111111111111111111G#',
            '#H1676767676767676767676112JJJJJJJJJJJJJJJJJJ211111111111111111111111111111111G#',
            '#G16767676767676767676761122K2222K232K22222K2211111111111111111111111111111111H#',
            '#G1111111111111111111111111111111111111111111111111111111111111111111111111111H#',
            '#G1111111111111111111111111111111111111111111111111111111111111111111111111111G#',
            '#H1111111111111111111111111111111111111111111111111111222222222222222211111111H#',
            '#H11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#G11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G111111111112222K222K232K222K2222111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G111111111112JJJJJJJJJJJJJJJJJJJ2111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H11111111111KJJJJJJJJJJJJJJJJJJJK111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H111111111112JJJJJJJJJJJJJJJJJJJ2111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#H111111111112JJJJJJJJJJJJJJJJJJJ2111118181111111111113JJJJJJJJJJJJJJ211111111G#',
            '#G111111111112JJJJJJJJJJJJJJJJJJJ2111111911111111111112JJJJJJJJJJJJJJ211111111G#',
            '#G11111111111KJJJJJJJJJJJJJJJJJJJK111118181111111111112JJJJJJJJJJJJJJ211111111H#',
            '#H111111111112JJJJJJJJJJJJJJJJJJJ2111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H11111111111222222222222222222222111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#H11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H11111111111111111111111111111111111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G11111111111232232232232232232211111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#G111111111112JJ2JJ2JJ2JJ2JJ2JJ211111111111111111111112JJJJJJJJJJJJJJ211111111G#',
            '#H111111111112JJ2JJ2JJ2JJ2JJ2JJ211111111111111111111112JJJJJJJJJJJJJJ211111111H#',
            '#G6776711111122222222222222222221111111111111111111111222222222222222211111111G#',
            '#G6677666711111111111116676676766667111111111111111111116777676711111111111111H#',
            '#54454667676777766766767745455444667667666761111166776677456676767611111111111H#',
            '#41145544776745454544677451111144446667674466677677676745444545676676111111111H#',
            '#41111114554541111114454511111111145664455444547776764541114444454676776711111G#',
            '#51111111111111111111111111111111114444111111445544454411111144544567676767677H#',
            '#41111111111111111111111111111111111111111111111111111111111111444445545666766H#',
            '#41111111111111111111111111111111111111111111111111111111111111111555554545455G#',
            '#GGGHHGHHHHHGGGGHGGHGHGGGHGHGGHGHGGHGHGGHGHGGGHGGGGHGHHGGGHGHGGHGHGHHGGHGHGGHGG#',
            '################################################################################',]
    MAP_HEIGHT1 = len(smap)
    MAP_WIDTH1 = len(smap[0])
    map = [ [ Tile(True) for y in range(MAP_HEIGHT) ] for x in range(MAP_WIDTH) ]
    for y in range(MAP_HEIGHT1):
        for x in range(MAP_WIDTH1):
            if smap[y][x] != '#':
                map[x][y] = Tile(False)
            if smap[y][x] == '#':
                map[x][y] = Tile(True)
            if smap[y][x] == '1':
                map[x][y] = Tile(False)
            if smap[y][x] == '2':
                wall = Object(x, y, '#', 'wall', libtcod.darker_gray, always_visible=True)
                objects.append(wall)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '3':
                door = Object(x, y, '+', 'closed door', libtcod.darkest_flame, always_visible=True)
                objects.append(door)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = True
            if smap[y][x] == '4':
                mountain1 = Object(x, y, '^', 'mountain', libtcod.dark_gray, always_visible=True)
                objects.append(mountain1)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '5':
                mountain2 = Object(x, y, '^', 'mountain', libtcod.white, always_visible=True)
                objects.append(mountain2)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '6':
                long_grass1 = Object(x, y, ';', 'long grass', libtcod.desaturated_yellow, always_visible=True)
                objects.append(long_grass1)
                map[x][y].blocked = False
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '7':
                long_grass2 = Object(x, y, ';', 'long grass', libtcod.desaturated_chartreuse, always_visible=True)
                objects.append(long_grass2)
                map[x][y].blocked = False
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '8':
                tree = Object(x, y, 'T', 'tree', libtcod.dark_green, always_visible=True)
                objects.append(tree)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == '9':
                tree2 = Object(x, y, '"', 'tree', libtcod.darker_orange, always_visible=True)
                objects.append(tree2)
                map[x][y].blocked = True
                map[x][y].block_sight = False
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == 'G':
                grass4 = Object(x, y, ',', 'grass', libtcod.darker_orange, always_visible=True)
                objects.append(grass4)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == 'H':
                grass6 = Object(x, y, ';', 'long grass', libtcod.darkest_orange, always_visible=True)
                objects.append(grass6)
                map[x][y].blocked = True
                map[x][y].block_sight = True
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False
            if smap[y][x] == 'J':
                floor = Object(x, y, '.', 'floor', libtcod.darkest_orange, always_visible=True)
                objects.append(floor)
                map[x][y].blocked = False
                map[x][y].block_sight = False
                map[x][y].it_is_object = True
                map[x][y].it_is_door = False
            if smap[y][x] == 'K':
                window = Object(x, y, '.', 'window', libtcod.lightest_sky, always_visible=True)
                objects.append(window)
                map[x][y].blocked = True
                map[x][y].block_sight = False
                map[x][y].it_is_object = False
                map[x][y].it_is_door = False

    npc = Object(32, 7, 't', '1st npc 1st city', libtcod.white, blocks=True, always_visible=False, ai=ImpNPC1_1())
    objects.append(npc)
    npc = Object(60, 4, 't', '2nd npc 1st city', libtcod.white, blocks=True, always_visible=False, ai=ImpNPC1_2())
    objects.append(npc)
    npc = Object(27, 22, 't', '3rd npc 1st city', libtcod.white, blocks=True, always_visible=False, ai=ImpNPC1_1())
    objects.append(npc)
    npc = Object(60, 22, 't', '4th npc 1st city', libtcod.white, blocks=True, always_visible=False, ai=ImpNPC1_1())
    objects.append(npc)

    upstairs = Object(3, 20, '<', 'stairs', libtcod.white, always_visible=True)
    objects.append(upstairs)
    upstairs.send_to_back()

    downstairs = Object(30, 41, '^', 'mountain', libtcod.white, always_visible=False)
    objects.append(downstairs)

What's the problem? Player and the computer use the same mechanics of opening the door. Player can open doors, without problems, bugs and crashes. When computer try to open a door, application crash.

Traceback:

Traceback (most recent call last):
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 13441, in <module>
    main_menu()
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 13422, in main_menu
    play_game()
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 13404, in play_game
    object.ai.take_turn()
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 633, in take_turn
    monster.move_towards(player.x, player.y)
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 252, in move_towards
    use_door(object)
  File "D:/progr/python/ide/pycharm/proj/humfall/#ASCII/hf_t2.py", line 11272, in use_door
    if 'locked' in object.name:
AttributeError: type object 'object' has no attribute 'name'
24 bits font.
key color : 0 0 0
24bits greyscale font. converting to 32bits

I know that calling the class 'Object' is unfortunate, but if I change replace this by Thing, trackback is the same: only "AttributeError: type object 'object' has no attribute 'name' " changes to "AttributeError: class Thing has no attribute 'name' "


Solution

  • Inside your move_towards function:

            elif is_door(self.x + ddx, self.y + ddy):
                if ddx != 0:
                    use_door(object)
                    return
                elif ddy != 0:
                    use_door(object)
                    return
    

    It looks like you intended for use_door's argument to be the Object at coordinates self.x + ddx, self.y + ddy, but that's not what you're passing here. You're just passing the built-in object class, which has nothing to do with the Object class you defined. I can't tell from your code snippets whether this is possible, but try fetching the object from map.

            elif is_door(self.x + ddx, self.y + ddy):
                if ddx != 0:
                    use_door(map[self.x + ddx][self.y + ddy])
                    return
                elif ddy != 0:
                    use_door(map[self.x + ddx][self.y + ddy])
                    return