Beispiel #1
0
 def create_river(self, tile):
     center_x = self.width // 2
     center_y = self.height // 2
     # from one side towards the other
     configs = [(center_x, 0, 90), (center_x, self.height - 1, -90),
                (0, center_y, 0), (self.width - 1, center_y, 180)]
     choice = rl.random_int(0, len(configs) - 1)
     x, y, angle = configs[choice]
     #x, y, angle = center_x, center_y, rl.random_int(0, 359)
     width = 2
     finished = False
     while not finished:
         #if player.distance(x, y) < 10:
         #    break
         dx = int(math.cos(math.pi * angle / 180) * 5)
         dy = int(math.sin(math.pi * angle / 180) * 5)
         for i, j in util.line_iter(x, y, x + dx, y + dy):
             if i < 0 or i >= self.width or j < 0 or j >= self.height:
                 finished = True
                 break
             self.fill_circle(i, j, width, tile)
         x += dx
         y += dy
         angle += rl.random_int(0, 60) - 30
         width += (rl.random_int(0, 100) - 50) / 100
         if width < 2:
             width = 2
         if width > 5:
             width = 5
Beispiel #2
0
def place_objects(level, room):
    # this is where we decide the chance of each monster or item appearing.
 
    # maximum number of monsters per room
    max_monsters = from_dungeon_level([[1, 1], [1, 2], [2, 3], [2, 4], [3, 5], [2, 6], [1, 7], [0, 8]])
    #max_monsters = game.dungeon_level
 
    # maximum number of items per room
    max_items = from_dungeon_level([[4, 1], [12, 2]])
 
    # chance of each item (by default they have a chance of 0 at level 1, which then goes up)
    item_chances = {}
    #item_chances['heal'] = 35  # healing potion always shows up, even if all other items have 0 chance
    item_chances['lightning'] = from_dungeon_level([[25, 1]])
    item_chances['fireball'] = from_dungeon_level([[25, 1]])
    item_chances['confuse'] = from_dungeon_level([[10, 1]])
    item_chances['sword'] = from_dungeon_level([[5, 1]])
    item_chances['shield'] = from_dungeon_level([[15, 1]])
 
    # choose random number of monsters
    num_monsters = rl.random_int(1, max_monsters)
 
    monster_type = random_choice(get_monster_chances())
    for i in range(num_monsters):
        # choose random spot for this monster
        x = rl.random_int(room.x1 + 1, room.x2 - 1)
        y = rl.random_int(room.y1 + 1, room.y2 - 1)
 
        # only place it if the tile is not blocked
        if not level.is_blocked(x, y):
            level.objects.append(make_monster(monster_type, x, y))
Beispiel #3
0
    def attack(self, target):
        if not self.is_hostile(target):
            print('warning, %s trying to attack friend %s' %
                  (self.owner.name, target.name))
            return
        # a simple formula for attack damage
        damage = rl.random_int(0, self.power) - rl.random_int(
            0, target.defense)
        print('attack:', self, target, self.power, target.defense, damage)

        if damage > 0:
            #damage = rl.random_int(1, damage)
            # make the target take some damage
            if player in [self, target] or player.can_see(self):
                ui.message(
                    util.capitalize(self.get_name('attack{s}')) + ' ' +
                    target.get_name() + ' for ' + str(damage) + ' hit points.')
            else:
                ui.message('You hear combat in the distance', rl.LIGHTGRAY)
            target.take_damage(damage, self)
        else:
            if player in [self, target] or player.can_see(self):
                ui.message(
                    util.capitalize(self.get_name('attack{s}')) + ' ' +
                    target.get_name() + ' but it has no effect!')
Beispiel #4
0
    def control(self, monster):
        if self.num_turns > 0:  # still confused...
            # move in a random direction, and decrease the number of turns confused
            self.num_turns -= 1
            monster.move(rl.random_int(-1, 1), rl.random_int(-1, 1))

        else:  # restore the previous AI (this one will be deleted because it's not referenced anymore)
            monster.pop_controller()
            ui.message(
                util.capitalize(monster.get_name('{is}')) +
                ' no longer confused!', rl.RED)
            monster.controller.control(monster)
    def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player):
        rooms = []
        num_rooms = 0
 
        for r in range(max_rooms):
            # random width and height
            w = rl.random_int(room_min_size, room_max_size)
            h = rl.random_int(room_min_size, room_max_size)
            # random position without going out of the boundaries of the map
            x = rl.random_int(0, map_width - w - 1)
            y = rl.random_int(0, map_height - h - 1)
            # "Rect" class makes rectangles easier to work with
            new_room = Rect(x, y, w, h)
 
            # run through the other rooms and see if they intersect with this one
            for other_room in rooms:
                if new_room.intersect(other_room):
                    break
            else:
                # this means there are no intersections, so this room is valid
 
                # "paint" it to the map's tiles
                self.create_room(new_room)
 
                # center coordinates of new room, will be useful later
                (new_x, new_y) = new_room.center()
 
                if num_rooms == 0:
                    # this is the first room, where the player starts at
                    player.x = new_x
                    player.y = new_y
                else:
                    # all rooms after the first:
                    # connect it to the previous room with a tunnel
 
                    # center coordinates of previous room
                    (prev_x, prev_y) = rooms[num_rooms - 1].center()
 
                    # flip a coin (random number that is either 0 or 1)
                    if rl.random_int(0, 1) == 1:
                        # first move horizontally, then vertically
                        self.create_h_tunnel(prev_x, new_x, prev_y)
                        self.create_v_tunnel(prev_y, new_y, new_x)
                    else:
                        # first move vertically, then horizontally
                        self.create_v_tunnel(prev_y, new_y, prev_x)
                        self.create_h_tunnel(prev_x, new_x, new_y)
 
                # finally, append the new room to the list
                rooms.append(new_room)
                num_rooms += 1
Beispiel #6
0
def generate_level(num_rooms, template_subset):
    rooms = [Room(template_subset)]
    fails = 0
    while len(rooms) < num_rooms:
        a = rooms[rl.random_int(0, len(rooms) - 1)]
        door = a.doors[rl.random_int(0, len(a.doors) - 1)]
        if not door.used:
            b = Room(template_subset)
            other_door = b.doors[rl.random_int(0, len(b.doors) - 1)]
            b.x = a.x + door.x - other_door.x
            b.y = a.y + door.y - other_door.y
            ok = True
            for i, room in enumerate(rooms):
                if intersect(room, b):
                    ok = False
            if ok:
                door.used = True
                other_door.used = True
                rooms.append(b)
                fails = 0
            else:
                fails += 1
            if fails > 100:
                break
    min_x = rooms[0].x
    min_y = rooms[0].y
    max_x = rooms[0].x + rooms[0].width
    max_y = rooms[0].y + rooms[0].height
    for a in rooms[1:]:
        if a.x < min_x: min_x = a.x
        if a.x + a.width > max_x: max_x = a.x + a.width
        if a.y < min_y: min_y = a.y
        if a.y + a.height > max_y: max_y = a.y + a.height
    width = max_x - min_x
    height = max_y - min_y

    level = rl.Array(width, height)

    for room in rooms:
        room.bake(level, -min_x, -min_y)

    for j in range(height):
        for i in range(width):
            if level[i, j] == 3:
                if i == 0 or i == width - 1 or j == 0 or j == height - 1 \
                    or level[i - 1, j] == 0 or level[i + 1, j] == 0 or level[i, j - 1] == 0 or level[i, j + 1] == 0 \
                    or level[i - 1, j - 1] == 0 or level[i + 1, j - 1] == 0 or level[i - 1, j + 1] == 0 or level[i + 1, j + 1] == 0:
                    level[i, j] = 2
    level.replace(3, 1)
    level.replace(0, 2)
    return level
Beispiel #7
0
def make_forest_map():
    level = Level(const.MAP_WIDTH, const.MAP_HEIGHT)
    level.tiles.fill(Tile.GRASS)
    level.blocked.fill(0)

    center_x = level.width // 2
    center_y = level.height // 2
    radius = min([center_x, center_y])

    def contains_tree(x, y):
        d = math.sqrt((x - center_x)**2 + (y - center_y)**2)
        if d < 3:
            return False
        if d >= radius:
            return True
        p = 100 * d / radius
        v = rl.random_int(0, 100)
        return v < p

    level.objects = [player]
    player.x = center_x
    player.y = center_y
    for y in range(level.height):
        for x in range(level.width):
            if contains_tree(x, y):
                level[x, y] = Tile.mapping[Tile.WALL]
                #level.objects.append(actors.Actor(x, y, graphics.TREE, 'tree', rl.GREEN, always_visible=True))
                #level.blocked[x, y] = 1
    level.blocked = level.tiles.equals(Tile.WALL)

    angle = rl.random_int(0, 360)
    distance = rl.random_int(2, 3)
    level.stairs = actors.Actor(center_x + int(distance * math.cos(angle)),
                                center_y + int(distance * math.sin(angle)),
                                graphics.ROCK_STAIRS,
                                'stairs',
                                rl.WHITE,
                                always_visible=True,
                                z=-2)
    level.objects.append(level.stairs)
    level.compute_fov()

    #distance = level.blocked.copy()
    #distance.replace(0, rl.INT_MAX)
    #distance.replace(1, -1)
    #distance[player.x, player.y] = 0
    #distance.dijkstra()
    #distance.replace(rl.INT_MAX, -1)
    #print(distance.max(), distance.argmax())

    return level
Beispiel #8
0
def random_choice_index(chances):
    dice = rl.random_int(1, sum(chances))
    running_sum = 0
    choice = 0
    for w in chances:
        running_sum += w
        if dice <= running_sum:
            return choice
        choice += 1
Beispiel #9
0
 def contains_tree(x, y):
     d = math.sqrt((x - center_x)**2 + (y - center_y)**2)
     if d < 3:
         return False
     if d >= radius:
         return True
     p = 100 * d / radius
     v = rl.random_int(0, 100)
     return v < p
Beispiel #10
0
 def summon_monster(name):
     print(name)
     x, y = 0, 0
     i = 0
     while i < 100:
         angle = rl.random_int(0, 359)
         distance = rl.random_int(2, 4)
         x = int(caster.x + .5 + math.cos(math.pi * angle / 180) * distance)
         y = int(caster.y + .5 + math.sin(math.pi * angle / 180) * distance)
         print(x, y)
         if not level.is_blocked(x, y) and caster.can_see_tile(x, y):
             break
         i += 1
     if i == 100:
         if caster is player:
             ui.message('You fail to cast the summon spell.', rl.BLUE)
     monster = monsters.make_monster(name, x, y)
     if not hostile:
         monster.master = caster
     level.objects.append(monster)
     if caster is player or player.can_see(caster) or player.can_see(monster):
         ui.message(util.capitalize(caster.get_name('summon{s}')) + ' ' + monster.get_name(determiner='a') + '.', rl.BLUE)
Beispiel #11
0
 def control(self, actor):
     dx, dy = rl.random_int(-1, 1), rl.random_int(-1, 1)
     actor.set_action(actions.Move(actor, dx, dy))
Beispiel #12
0
    def control(self, monster):
        old_target = monster.target
        old_flee = monster.flee

        def info(*args, **kwargs):
            pass
            #if debug.active:
            #    if (player.can_see(monster) or old_flee is player or old_target is player):
            #        print('AI', monster.name, *args, **kwargs)

        info(monster.info())
        target = monster.target
        # dangling target after it becomes friendly
        # no dead target
        # 25% chance to forget target if monster can't see it
        if target \
            and (not target.is_hostile(monster) \
                or target.hp <= 0 \
                or (not monster.can_see(target) and rl.random() < .25)):
            target = monster.target = None
            info('  forget target')

        # save target last seen location to be able to follow it when it leaves fov
        if target:
            monster.target_location = (target.x, target.y)
            info('  save target location %d,%d' % (target.x, target.y))
        else:
            monster.target_location = None

        flee = monster.flee
        # dangling flee after it becomes friendly
        # no dead flee
        # 25% chance to forget flee if monster can't see it
        if flee \
            and (not flee.is_hostile(monster) \
                or flee.hp <= 0 \
                or (not monster.can_see(flee) and rl.random() < .25)):
            flee = monster.flee = None
            info('  forget flee')

        # compute flee based on friends and foes
        friends, foes = util.friends_and_foes(monster)
        friends += [monster]
        if len(foes) > 0:
            #foes_hp = sum([m.hp for m in foes])
            friends_hp = sum([m.hp for m in friends])
            foes_power = sum([m.power for m in foes])
            #friends_power = sum([m.power for m in friends])
            #foes_defense = sum([m.defense for m in foes])
            friends_defense = sum([m.defense for m in friends])
            if foes_power - friends_defense >= friends_hp:
                flee = monster.flee = util.closest_hostile(
                    monster, monster.sight_radius)
                info('  outnumbered, flee', str(flee))

        # highest priority is to flee
        if flee and monster.can_see(flee):
            monster.move_away_from(flee.x, flee.y)
            info('  flee: move away from', str(flee))
        elif not target:
            # if no target, move towards master or select new target
            if monster.master and monster.distance_to(monster.master) > 3:
                monster.move_towards(monster.master.x, monster.master.y)
                info('  no target: move towards master')
            else:
                target = monster.target = util.closest_hostile(
                    monster, monster.sight_radius)
                info('  new target: ', str(target))
        else:
            if monster.can_see(target):
                if monster.distance_to(target) >= 2:
                    potential_actions = [
                        action for action in monster.actions
                        if monster.mana >= action.cost
                    ]
                    info('potential-actions', monster.mana, potential_actions)
                    value = rl.random()
                    info(value, value < .5, value > .5)
                    if len(potential_actions) > 0 and value < .5:
                        selected = rl.random_int(0, len(monster.actions) - 1)
                        action = monster.actions[selected]
                        info('selected', action)
                        if monster.distance_to(target) <= action.range:
                            if action in [
                                    powers.LIGHTNING, powers.FEAR,
                                    powers.SUMMON, powers.SUMMON_BAT,
                                    powers.SUMMON_EYE, powers.SUMMON_RAT,
                                    powers.SUMMON_SKELETON, powers.SUMMON
                            ]:
                                action.perform(monster)
                            elif action in [
                                    powers.CONFUSE, powers.FREEZE,
                                    powers.TELEPORT
                            ]:
                                action.perform(monster, target)
                            elif action in [powers.FIREBALL, powers.DIG]:
                                action.perform(monster, target.x, target.y)
                            else:
                                raise ValueError(
                                    'monster cannot handle action ' +
                                    str(action))
                            info('  perform action: ', str(action))
                        else:
                            monster.move_towards(target.x, target.y)
                            info('  move towards target: ', str(target))
                    else:
                        monster.move_towards(target.x, target.y)
                        info('  move towards target: ', str(target))
                else:
                    monster.attack(target)
                    info('  move towards target: ', str(target))
            elif monster.target_location is not None and not (
                    monster.x == monster.target_location[0]
                    and monster.y == monster.target_location[1]):
                monster.move_towards(monster.target_location[0],
                                     monster.target_location[1])
                info('  move towards old target location %d,%d' %
                     monster.target_location)
            elif target is not None:
                if powers.DIG in monster.actions:
                    powers.DIG.perform(monster, x=target.x, y=target.y)
                    info('  dig to reach target at %d,%d' %
                         (target.x, target.y))
                else:
                    info('  wait, no dig')
            else:
                info('  wait')

        info('  <<', monster.info())
        if monster.action is None:
            monster.wait()
Beispiel #13
0
def choose_template(templates):
    return templates[rl.random_int(0, len(templates) - 1)]
Beispiel #14
0
def apply_transform(template):
    transform = transforms[rl.random_int(0, len(transforms) - 1)]
    return transform(template)
Beispiel #15
0
def make_dungeon_map():
    level = Level(const.MAP_WIDTH, const.MAP_HEIGHT)
    level.tiles.fill(Tile.WALL)
    level.blocked.fill(1)
    level.objects = [player]

    rooms = []
    num_rooms = 0

    for r in range(const.MAX_ROOMS):
        if num_rooms == 0:
            w = rl.random_int(const.ROOM_MIN_SIZE - 1, const.ROOM_MIN_SIZE + 2)
            h = rl.random_int(const.ROOM_MIN_SIZE - 1, const.ROOM_MIN_SIZE + 2)
        else:
            w = rl.random_int(const.ROOM_MIN_SIZE, const.ROOM_MAX_SIZE)
            h = rl.random_int(const.ROOM_MIN_SIZE, const.ROOM_MAX_SIZE)

        x = rl.random_int(0, level.width - w - 1)
        y = rl.random_int(0, level.height - h - 1)

        new_room = Rect(x, y, w, h)

        failed = False
        for other_room in rooms:
            if new_room.intersect(other_room):
                failed = True
                break

        if not failed:
            level.create_room(new_room)
            (new_x, new_y) = new_room.center()

            if num_rooms == 0:
                player.x = new_x
                player.y = new_y
            else:
                (prev_x, prev_y) = rooms[num_rooms - 1].center()

                if rl.random_int(0, 1) == 1:
                    level.create_h_tunnel(prev_x, new_x, prev_y)
                    level.create_v_tunnel(prev_y, new_y, new_x)
                else:
                    level.create_v_tunnel(prev_y, new_y, prev_x)
                    level.create_h_tunnel(prev_x, new_x, new_y)

                monsters.place_objects(level, new_room)

            rooms.append(new_room)
            num_rooms += 1

    if game.dungeon_level == 3:
        level.create_river(Tile.WATER)
    elif game.dungeon_level == 5:
        level.create_river(Tile.LAVA)

    level.stairs = actors.Actor(new_x,
                                new_y,
                                graphics.stairs_for_level[game.dungeon_level],
                                'stairs',
                                rl.WHITE,
                                always_visible=True,
                                z=-2)
    level.objects.append(level.stairs)
    level.compute_fov()
    return level