Beispiel #1
0
def _line_no_solid(from_xy, to_xy):
    from globals import world

    for x, y in libtcod.line_iter(from_xy.x, from_xy.y, to_xy.x, to_xy.y):
        if world.level.map[Pos(x,y)].blocked:
            return False

    return True
Beispiel #2
0
    def draw_line(self, sx, sy, tx, ty, color=None):
        # draw a line between starting point sx, sy and target point tx, ty
        if color is None:
            color = self.foreground

        points = libtcod.line_iter(sx, sy, tx, ty)
        for x, y in points:
            self.draw_point(x, y, color)
def draw_targeting_line(player, targeting_cursor, fov_map, game_map):
    for pts in libtcod.line_iter(player.x, player.y, targeting_cursor.x,
                                 targeting_cursor.y):
        if libtcod.map_is_in_fov(fov_map, pts[0],
                                 pts[1]) and (pts[0], pts[1]) not in [
                                     (targeting_cursor.x, targeting_cursor.y)
                                 ]:
            if game_map.tiles[pts[0]][pts[1]].block_sight:
                draw_layer_points(2, 0, pts[0], pts[1], 'lightest red', '*')
                targeting_cursor.color = 'red'
            else:
                draw_layer_points(2, 0, pts[0], pts[1], 'lightest yellow', '*')
                targeting_cursor.color = 'yellow'
Beispiel #4
0
def test_line_iter():
    """
    libtcodpy.line_iter
    """
    assert list(libtcodpy.line_iter(*LINE_ARGS)) == INCLUSIVE_RESULTS
def clear_targeting_line(player, targeting_cursor, fov_map):
    for pts in libtcod.line_iter(player.x, player.y, targeting_cursor.x,
                                 targeting_cursor.y):
        if libtcod.map_is_in_fov(fov_map, pts[0], pts[1]):
            clear_layer_points(2, 0, pts[0], pts[1])
Beispiel #6
0
 def _line_to(self, obj):
     map = globals.world.level.map
     for x, y in libtcod.line_iter(self.xy.x, self.xy.y, obj.xy.x, obj.xy.y):
         if map[Pos(x,y)].blocked:
             return False
     return True
Beispiel #7
0
def play_game(player, entities, game_map, message_log, game_state, constants):
    explosion_radius = 0
    explosion_target = []
    explosion_shape = []
    targeting_item = None
    lineshot_pts = []
    lineshot_clr = ''
    equip_index = 0
    move = ''

    # get the targeting cursor
    targeting_cursor = entity.find_entity_by_name(entities, 'TargetingCursor')

    # build the game map, setting up the fov for the map
    fov_recompute = True
    fov_map = fov_functions.initialize_fov(game_map)

    turn_cnt = 0
    game_state = GameStates.PLAYER_TURRET_TURN
    previous_game_state = game_state
    turret_find = True
    active_turrets = []
    disabled_turrets = []
    entity_turn_order = []
    active_enemy_turrets = []
    enemy_turret_results = []
    death_game_state = ''
    left_click = []

    while True:
        if DEBUG:
            turn_cnt += 1
            print('*******************************')
            print('TURN {} {}'.format(turn_cnt, game_state))
        player_turn_results = []
        found_turrets = False
        if fov_recompute:
            fov_functions.recompute_fov(fov_map, player.x, player.y,
                                        constants['fov_radius'],
                                        constants['fov_light_walls'],
                                        constants['fov_algorithm'])

        # initialize set target mode
        mindist = 1000
        foundtarget = None
        for ent in entities:
            if ent.ai and ent.combatship and ent not in [
                    player, targeting_cursor
            ] and libtcod.map_is_in_fov(fov_map, ent.x, ent.y):
                if ent.combatship.targeted:
                    foundtarget = None
                    break
                else:
                    dist = player.distance_to(ent)
                    if dist < mindist:
                        mindist = dist
                        foundtarget = ent
        if foundtarget is not None:
            foundtarget.combatship.targeted = True

        # player turrets take a turn
        # for targeting turrets (animated), cycle through the whole animation cycle, come back through for next turret
        if game_state == GameStates.PLAYER_TURRET_TURN:
            results = []

            # first get all the active turrets if turret_find flag is set
            if turret_find:
                for item_entity in player.inventory.items:
                    if item_entity.ai is not None and item_entity not in active_turrets and \
                            item_entity.item.max_charge_time is not None:
                        # handle charge time here as well.  Subtract one if charging, fire if charged
                        if not item_entity.item.charge_time:
                            active_turrets.append(item_entity)
                        else:
                            item_entity.item.charge_time -= 1
                found_turrets = True
                turret_find = False
            else:
                for item_entity in player.inventory.items:
                    if item_entity.ai is not None and item_entity not in active_turrets and not item_entity.item.charge_time:
                        active_turrets.append(item_entity)

            if DEBUG:
                print(
                    'DEBUG {} total items is {}, active turrets pre check is {}'
                    .format(player.name, len(player.inventory.items),
                            len(active_turrets)))
            # remove all the disabled turrets and recharging turrets second time through
            active_turrets = [
                turret for turret in active_turrets
                if turret not in disabled_turrets
            ]
            if DEBUG:
                print('DEBUG {} has {} remaining turrets'.format(
                    player.name, len(active_turrets)))
            # now look for a good target, get results if you used the turret and remove it from active turrets
            if active_turrets and not found_turrets:
                for ent in entities:
                    if ent.combatship:
                        if ent.combatship.targeted:
                            results = active_turrets[0].ai.take_turn(
                                player, ent, fov_map, game_map, entities)
                            if results:
                                player_turn_results.extend(results)
                                active_turrets.remove(active_turrets[0])
                                break
                    else:
                        results = []

            # with no shots or no active turrets, switch to players turn
            if not results:
                # do a pass through to rdy up turrets in case you only fired some of your complement
                if active_turrets:
                    for item_entity in player.inventory.items:
                        if item_entity.ai is not None and item_entity not in active_turrets and \
                                item_entity.item.max_charge_time is not None:
                            if item_entity.item.charge_time:
                                item_entity.item.charge_time -= 1
                game_state = GameStates.PLAYERS_TURN
            if not active_turrets:
                turret_find = True

        # print to screen for render_functions.render_all to display/refresh
        render_functions.render_all(entities, player, targeting_cursor,
                                    game_map, fov_map, fov_recompute,
                                    message_log, constants, game_state,
                                    equip_index, left_click, active_turrets,
                                    lineshot_pts, lineshot_clr,
                                    explosion_shape)

        # clear all explosion points and one line point each time (with delay)

        render_functions.clear_all(entities, fov_map)

        # blocking read input (unless an animation is going on)
        key = None
        if game_state not in [
                GameStates.EXPLOSION, GameStates.LINESHOT,
                GameStates.PLAYER_TURRET_TURN, GameStates.ENEMY_TURN,
                GameStates.ENEMY_TURRET_TURN
        ]:
            key = terminal.read()

        action = input_handlers.handle_keys(key, game_state)

        move = action.get('move')
        pickup = action.get('pickup')
        enter = action.get('enter')
        goto_equip = action.get('goto_equip')
        drop_equip = action.get('drop_equip')
        equip_inc = action.get('menupos')
        equip_select = action.get('select')
        set_target = action.get('set_target')
        exit = action.get('exit')
        fullscreen = action.get('fullscreen')
        left_click = action.get('left_click')
        right_click = action.get('right_click')

        # move the player and attack if an entity is in the way
        if move and game_state == GameStates.PLAYERS_TURN:
            dx, dy = move
            destination_x = player.x + dx
            destination_y = player.y + dy
            if not game_map.is_blocked(destination_x, destination_y):
                target = entity.get_blocking_entities_at_location(
                    entities, destination_x, destination_y)
                if target:
                    attack_results = player.combatship.attack(target)
                    player_turn_results.extend(attack_results)
                else:
                    player.move(dx, dy)
                    targeting_cursor.move(dx, dy)
                    fov_recompute = True
                player.combatship.regen_shields()
                game_state = GameStates.ENEMY_TURRET_TURN

        # if you hit g and there is an item under you, add to inventory
        elif pickup and game_state == GameStates.PLAYERS_TURN:
            for ent in entities:
                if ent.item and ent.x == player.x and ent.y == player.y:
                    pickup_results = player.inventory.add_item(ent)
                    player_turn_results.extend(pickup_results)
                    break
            else:
                message_log.add_message(
                    Message('There is nothing here to pick up.', 'yellow'))

        # change modes to show (i) / drop (d) if you hit those keys
        if goto_equip:
            previous_game_state = game_state
            game_state = GameStates.GOTO_EQUIP
        if drop_equip:
            previous_game_state = game_state
            game_state = GameStates.DROP_EQUIP
        if set_target:
            message_log.add_message(
                Message(
                    'Use the arrow keys and press enter to set an enemy target',
                    'light cyan'))
            previous_game_state = game_state
            game_state = GameStates.SET_TARGET

        # handle moving around within the inventory
        if equip_inc is not None and previous_game_state != GameStates.PLAYER_DEAD:
            equip_index += equip_inc
            if equip_index < 0:
                equip_index = 0
            elif equip_index >= len(player.inventory.items) - 1:
                equip_index = len(player.inventory.items) - 1

        # hit enter in inventory, use item / drop item and append to player_turn_results
        if equip_select:
            item = player.inventory.items[equip_index]
            if game_state == GameStates.GOTO_EQUIP:
                player_turn_results.extend(
                    player.inventory.use(item,
                                         entities=entities,
                                         fov_map=fov_map,
                                         inventory_enter_key=True))
            elif game_state == GameStates.DROP_EQUIP:
                player_turn_results.extend(player.inventory.drop_item(item))

        # once you finish animating the line, check if there is a turret left to fire
        # if not, going through the turret turn will rebuild active turrets list for next turn
        if not lineshot_pts and game_state == GameStates.LINESHOT:
            game_state = previous_game_state

        # first time through, build the shape of the explosion
        # second time through (it's been animated and cleared)
        if game_state == GameStates.EXPLOSION:
            if explosion_shape:
                explosion_shape = []
                game_state = previous_game_state
            else:
                explosion_shape = Diamond(
                    (explosion_target[0], explosion_target[1]),
                    explosion_radius)
                explosion_shape.build_diamond()

        # set target mode:
        if game_state == GameStates.SET_TARGET:
            if left_click:
                target_x, target_y = left_click
                for ent in entities:
                    if ent.ai and ent.combatship and ent not in [
                            player, targeting_cursor
                    ]:
                        if ent.x == target_x and ent.y == target_y:
                            ent.combatship.targeted = True
                        else:
                            ent.combatship.targeted = False
                player_turn_results.append({'set_target': True})
            elif right_click:
                player_turn_results.append({'set_target_cancelled': True})
            elif move:
                dx, dy = move
                if dx + dy >= 0:
                    move = 1
                else:
                    move = -1
                for ent in entities:
                    if ent.ai and ent.combatship and ent not in [
                            player, targeting_cursor
                    ]:
                        if ent.combatship.targeted:
                            ships = [
                                ent for ent in entities
                                if ent.ai and ent.combatship
                                and ent not in [player, targeting_cursor] and
                                libtcod.map_is_in_fov(fov_map, ent.x, ent.y)
                            ]
                            ent.combatship.targeted = False

                            ind = ships.index(ent)
                            newind = ind + move
                            if newind >= 0 and newind < len(ships):
                                entities[entities.index(
                                    ships[newind])].combatship.targeted = True
                            else:
                                if move == 1:
                                    entities[entities.index(
                                        ships[0])].combatship.targeted = True
                                else:
                                    entities[entities.index(
                                        ships[-1])].combatship.targeted = True
                            break
                player_turn_results.append({'move_target': True})
            elif enter:
                player_turn_results.append({'set_target': True})
        # targeting mode:
        # left click from mouse_handler targets entity (without using targeting cursor
        # right click cancels target mode
        # move will move around the targeting cursor
        # enter fires and resets cursor
        if game_state == GameStates.TARGETING:
            if left_click:
                target_x, target_y = left_click
                hit, blocked, target_x, target_y = \
                    item_functions.target_with_accuracy(player, target_x, target_y,
                                                        targeting_item.item.function_kwargs.get('accuracy'), game_map,
                                                        entities)
                item_use_results = player.inventory.use(targeting_item,
                                                        entities=entities,
                                                        fov_map=fov_map,
                                                        target_x=target_x,
                                                        target_y=target_y,
                                                        blocked=blocked,
                                                        hit=hit)
                player_turn_results.extend(item_use_results)
                player.combatship.regen_shields()
            elif right_click:
                targeting_cursor.render_order = render_functions.RenderOrder.INACTIVE_TARGETING
                targeting_cursor.x = player.x
                targeting_cursor.y = player.y
                player_turn_results.append({'targeting_cancelled': True})
            elif move:
                targeting_cursor.render_order = render_functions.RenderOrder.ACTIVE_TARGETING
                dx, dy = move
                targeting_cursor.move(dx, dy)

            elif enter:
                render_functions.clear_targeting_line(player, targeting_cursor,
                                                      fov_map)
                hit, blocked, target_x, target_y = \
                    item_functions.target_with_accuracy(player, targeting_cursor.x, targeting_cursor.y,
                                                        targeting_item.item.function_kwargs.get('accuracy'), game_map,
                                                        entities)
                item_use_results = player.inventory.use(targeting_item,
                                                        entities=entities,
                                                        fov_map=fov_map,
                                                        target_x=target_x,
                                                        target_y=target_y,
                                                        blocked=blocked,
                                                        hit=hit)
                player_turn_results.extend(item_use_results)
                targeting_cursor.render_order = render_functions.RenderOrder.INACTIVE_TARGETING
                targeting_cursor.x = player.x
                targeting_cursor.y = player.y
                player.combatship.regen_shields()

        # hit escape at any point
        # if in inventory mode, clears the inventory screen and goes back to player state
        if exit:
            if game_state in [
                    GameStates.GOTO_EQUIP, GameStates.DROP_EQUIP,
                    GameStates.SET_TARGET
            ]:
                terminal.clear()
                fov_recompute = True
                game_state = previous_game_state
            elif game_state == GameStates.TARGETING:
                targeting_cursor.render_order = render_functions.RenderOrder.INACTIVE_TARGETING
                targeting_cursor.x = player.x
                targeting_cursor.y = player.y
                player_turn_results.append({'targeting_cancelled': True})
            else:
                data_loaders.save_game(player, entities, game_map, message_log,
                                       game_state)
                return True

        if fullscreen:
            libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())

        for player_turn_result in player_turn_results:
            message = player_turn_result.get('message')
            autofire = player_turn_result.get('autofire')
            explosion = player_turn_result.get('explosion')
            lineshot = player_turn_result.get('lineshot')
            dead_entity = player_turn_result.get('dead')
            item_added = player_turn_result.get('item_added')
            item_dropped = player_turn_result.get('item_dropped')
            targeting = player_turn_result.get('targeting')
            toggle_turret = player_turn_result.get('toggle_turret')
            targeting_cancelled = player_turn_result.get('targeting_cancelled')
            set_target_result = player_turn_result.get('set_target')
            set_target_cancelled = player_turn_result.get(
                'set_target_cancelled')
            move_target = player_turn_result.get('move_target')

            if message:
                message_log.add_message(message)
            if autofire:
                pass
            if explosion:
                explosion_radius = explosion[0]
                explosion_target = explosion[1]
                game_state = GameStates.EXPLOSION
                previous_game_state = GameStates.ENEMY_TURRET_TURN
            if lineshot:
                lineshot_pts = [
                    step for step in libtcod.line_iter(player.x, player.y,
                                                       lineshot.get('pts')[0],
                                                       lineshot.get('pts')[1])
                ]
                lineshot_clr = lineshot.get('clr')
                game_state = GameStates.LINESHOT
                previous_game_state = GameStates.PLAYER_TURRET_TURN
            if dead_entity:
                if dead_entity == player:
                    message, game_state = death_functions.kill_player(
                        dead_entity)
                else:
                    entity_turn_order.remove(dead_entity)
                    message = death_functions.kill_enemy(dead_entity)

                message_log.add_message(message)
            if item_added:
                entities.remove(item_added)
                game_state = GameStates.ENEMY_TURRET_TURN
            if item_dropped:
                entities.append(item_dropped)
                game_state = GameStates.ENEMY_TURRET_TURN
            if targeting:
                terminal.clear()
                fov_recompute = True
                previous_game_state = GameStates.PLAYERS_TURN
                game_state = GameStates.TARGETING
                targeting_item = targeting
                message_log.add_message(targeting_item.item.targeting_message)
            if toggle_turret:
                if toggle_turret in disabled_turrets:
                    toggle_turret.item.targeting = 'auto_on'
                    disabled_turrets.remove(toggle_turret)
                else:
                    toggle_turret.item.targeting = 'auto_off'
                    disabled_turrets.append(toggle_turret)
                game_state = GameStates.PLAYERS_TURN
            if targeting_cancelled:
                fov_recompute = True
                game_state = previous_game_state
                message_log.add_message(Message('Targeting cancelled.'))
            if set_target_result:
                game_state = GameStates.PLAYERS_TURN
                fov_recompute = True
            if set_target_cancelled:
                game_state = previous_game_state
            if move_target:
                fov_recompute = True

        if game_state == GameStates.ENEMY_TURN:
            active_enemy_turrets = []
            if entity_turn_order:
                ent = entity_turn_order[0]
                entity_turn_order.remove(ent)
                enemy_turn_results = ent.ai.take_turn(player, fov_map,
                                                      game_map, entities,
                                                      constants)
                for enemy_turn_result in enemy_turn_results:
                    message = enemy_turn_result.get('message')
                    dead_entity = enemy_turn_result.get('dead')
                    if message:
                        message_log.add_message(message)
                    if dead_entity:
                        if dead_entity == player:
                            message, game_state = death_functions.kill_player(
                                dead_entity)
                        else:
                            entity_turn_order.remove(dead_entity)
                            message = death_functions.kill_enemy(dead_entity)

                        message_log.add_message(message)

                        if game_state == GameStates.PLAYER_DEAD:
                            break

                if game_state == GameStates.PLAYER_DEAD:
                    break
                elif not entity_turn_order:
                    game_state = GameStates.PLAYER_TURRET_TURN
                else:
                    game_state = GameStates.ENEMY_TURRET_TURN
            else:
                game_state = GameStates.PLAYER_TURRET_TURN

        if game_state == GameStates.ENEMY_TURRET_TURN:
            enemy_turret_results = []
            dead_entity = ''
            if entity_turn_order:
                ent = entity_turn_order[0]
                if not active_enemy_turrets:
                    for item_entity in ent.inventory.items:
                        if item_entity.ai is not None and item_entity not in active_turrets and \
                                item_entity.item.max_charge_time is not None:
                            # handle charge time here as well.  Subtract one if charging, fire if charged
                            if not item_entity.item.charge_time:
                                active_enemy_turrets.append(item_entity)
                            else:
                                item_entity.item.charge_time -= 1
                if DEBUG:
                    print('DEBUG {} {} items, {} with ai'.format(
                        ent.name, len(ent.inventory.items),
                        len([
                            i for i in ent.inventory.items if i.ai is not None
                        ])))
                    print('DEBUG {} position {}'.format(
                        ent.name, [ent.x, ent.y]))
                    print('DEBUG {} has {} remaining turrets'.format(
                        ent.name, len(active_enemy_turrets)))
                if active_enemy_turrets:
                    enemy_turret_results = ent.ai.handle_turret(
                        active_enemy_turrets[0], player, fov_map, game_map,
                        entities, constants)
                    active_enemy_turrets.remove(active_enemy_turrets[0])
                    for result in enemy_turret_results:
                        if DEBUG and result:
                            print('DEBUG {} turret result {}'.format(
                                ent.name, result))
                        dead_entity = result.get('dead')
                        lineshot = result.get('lineshot')
                        message = result.get('message')

                        if dead_entity == player and not death_game_state:
                            message, death_game_state = death_functions.kill_player(
                                dead_entity)
                        if lineshot:
                            lineshot_pts = [
                                step for step in libtcod.line_iter(
                                    ent.x, ent.y,
                                    lineshot.get('pts')[0],
                                    lineshot.get('pts')[1])
                            ]
                            lineshot_clr = lineshot.get('clr')

                            if DEBUG:
                                print(
                                    'DEBUG {} enemy target lineshot {}'.format(
                                        ent.name, lineshot_pts))
                            game_state = GameStates.LINESHOT
                            if not active_enemy_turrets:
                                previous_game_state = GameStates.ENEMY_TURN
                            else:
                                previous_game_state = GameStates.ENEMY_TURRET_TURN
                        if message:
                            message_log.add_message(message)
                    if death_game_state:
                        previous_game_state = death_game_state

                # with no shots or no active turrets, switch to players turn
                if not enemy_turret_results and not dead_entity:
                    # do a pass through to rdy up turrets in case you only fired some of your complement
                    if active_enemy_turrets:
                        for item_entity in ent.inventory.items:
                            if item_entity.ai is not None and item_entity not in active_turrets and \
                                    item_entity.item.max_charge_time is not None:
                                if item_entity.item.charge_time:
                                    item_entity.item.charge_time -= 1
                    game_state = GameStates.ENEMY_TURN
            else:
                game_state = GameStates.ENEMY_TURN

        # build list of enemies
        if not entity_turn_order:
            entity_turn_order = [
                ent for ent in entities if ent.ai is not None
                and libtcod.map_is_in_fov(fov_map, ent.x, ent.y)
            ]
Beispiel #8
0
def target_with_accuracy(owner, target_x, target_y, accuracy, game_map,
                         entities):
    blocked = False
    acc_roll = libtcod.random_get_int(0, 0, 100)
    if DEBUG:
        print('DEBUG {} actual target: {}, {}'.format(owner.name, target_x,
                                                      target_y))
        print('DEBUG {} roll: {}, accuracy: {}'.format(owner.name, acc_roll,
                                                       accuracy))
    if acc_roll < accuracy:  # hit! return target
        newtarget_x = target_x
        newtarget_y = target_y
        hit = 'yes'
    else:  # miss! continue the line a bit longer to allow the projectile to keep moving
        xoff = libtcod.random_get_int(0, 1, 1)
        yoff = libtcod.random_get_int(0, 1, 1)
        pos_or_neg = libtcod.random_get_int(0, 0, 1)
        if pos_or_neg:
            target_x = target_x + xoff
        else:
            target_x = target_x - xoff
        pos_or_neg = libtcod.random_get_int(0, 0, 1)
        if pos_or_neg:
            target_y = target_y + yoff
        else:
            target_y = target_y - yoff

        # build new line extending out much further
        newtarget_x = 2 * target_x - 1 * owner.x
        newtarget_y = 2 * target_y - 1 * owner.y

        # make sure its in the game map
        if newtarget_x <= 0:
            newtarget_y = newtarget_y - newtarget_x
            newtarget_x = 0
            if DEBUG:
                print('DEBUG {} out_of_map, using {}, {}'.format(
                    owner.name, newtarget_x, newtarget_y))
        elif newtarget_x >= game_map.width - 1:
            newtarget_y = newtarget_y - (newtarget_x - game_map.width - 1)
            newtarget_x = game_map.width - 1
            if DEBUG:
                print('DEBUG {} out_of_map, using {}, {}'.format(
                    owner.name, newtarget_x, newtarget_y))
        if newtarget_y <= 0:
            newtarget_x = newtarget_x - newtarget_y
            newtarget_y = 0
            if DEBUG:
                print('DEBUG {} out_of_map, using {}, {}'.format(
                    owner.name, newtarget_x, newtarget_y))
        elif newtarget_y >= game_map.height - 1:
            newtarget_x = newtarget_x - (newtarget_y - game_map.height - 1)
            newtarget_y = game_map.height - 1
            if DEBUG:
                print('DEBUG {} out_of_map, using {}, {}'.format(
                    owner.name, newtarget_x, newtarget_y))

        for pts in libtcod.line_iter(owner.x, owner.y, newtarget_x,
                                     newtarget_y):
            if game_map.is_blocked(
                    pts[0], pts[1]) or get_blocking_entities_at_location(
                        entities, pts[0], pts[1]):
                if (pts[0], pts[1]) != (owner.x, owner.y):
                    if DEBUG:
                        print('DEBUG {} blocked'.format(owner.name))
                    newtarget_x = pts[0]
                    newtarget_y = pts[1]
                    break
        hit = 'no'
        if DEBUG:
            print('DEBUG {} failed roll, new target: {}, {}, player: {}, {}'.
                  format(owner.name, newtarget_x, newtarget_y, owner.x,
                         owner.y))
    if game_map.is_blocked(newtarget_x, newtarget_y):
        blocked = True

    return hit, blocked, newtarget_x, newtarget_y