def read(intel: Intel, readable: Item):

    # check if the readable has the intel
    if not ReadableKnowledgeBook.get_or_none(
            ReadableKnowledgeBook.intel == intel,
            ReadableKnowledgeBook.readable == readable):
        Message.debug(
            "Readable '%s' does not contain the intel '%s', ReadableKnowledgeBook not found"
            % (readable, intel))
        Message.error(
            "Readable '%s' does not contain the intel player looking for" %
            readable)
        return False

    player = Player.current()
    # check if player owns the readable
    if readable.belongs_to_player != player:
        Message.debug("Player doesn't have the readable '%s'" % readable)
        if readable.place_() == player.place:
            readable.belongs_to = None
            readable.belongs_to_player = player
            readable.save()
            Message.debug(
                "Player didn't own the readable (%s) but at its place so he take it"
                % readable)
        else:
            Message.debug(
                "Player neither own the readable (%s), nor at the item's place_location (%s)"
                % (readable, readable.place_()))
            Message.error(
                "You neither own the readable (%s), nor are at the item's location"
                % readable)
            return False

    # update Player's intel
    NarrativeHelper.add_intel(intel)

    Message.achievement("By reading '%s', intel '%s' has been learned" %
                        (readable, intel.detail()))
    return True
def get_4(item_to_fetch: Item):
    """
    an NPC have the item, but you need to give the NPC something in an exchange
    :param item_to_fetch:
    :return:
    """
    player = Player.current()

    # find an NPC who has the needed item, and has it in exchange list
    exchanges = Exchange.select().join(Item)
    if item_to_fetch.is_singleton():
        exchanges = exchanges.where(Exchange.item == item_to_fetch)
    else:
        exchanges = exchanges.where(
            Exchange.item.generic == item_to_fetch.generic)

    if exchanges:

        locations_scores = [
            player.distance(exc.need.npc.place) for exc in exchanges
        ]
        exchanges = sort_by_list(exchanges, locations_scores)

        exchange = exchanges[0]
        item_to_give = exchange.need.item
        item_holder = exchange.need.npc
    else:
        # no one wants to offer the "item_to_fetch" in exchange for something else
        # you can even trade with your enemies so alliance doesn't really matters here
        # first try find someone who needs this item
        Message.debug(
            "No one wants to offer the '%s' in exchange for something else" %
            item_to_fetch)
        needs = Need.select().where(Need.item == item_to_fetch).group_by(
            Need.npc)
        if needs.count():
            need = needs.order_by(fn.Random()).get()
            item_holder = need.npc
            Message.debug(
                "NPC '%s' needs something, ideal to create an exchange motive with the item '%s' for him"
                % (item_holder, item_to_fetch))
        else:
            # no one need anything create a need for coin for an NPC
            results = NPC.select()
            locations_scores = [player.distance(npc.place) for npc in results]
            results = sort_by_list(results, locations_scores)
            item_holder = results[0]
            Message.debug(
                "No one need anything create a need for 'coin' for a close-by NPC '%s'"
                % item_holder)

            need = Need.create(
                npc=item_holder,
                item=Item.get(generic=GenericItem.get(name='coin')))

        Exchange.create(need=need, item=item_to_fetch)

        if item_to_fetch.belongs_to != item_holder:
            # ensure NPC has the item
            item_to_fetch.belongs_to = item_holder
            item_to_fetch.save()

        item_to_give = need.item

    player.next_location = item_holder.place
    player.save()

    intel = Intel.construct(item_place=item_to_fetch)
    PlayerKnowledgeBook.get_or_create(player=player, intel=intel)
    Message.achievement("Intel '%s' learned" % intel.detail())

    # check for player belonging for the exchange item
    if item_to_give.is_singleton():
        player_owns = (item_to_give.belongs_to_player == player)
    else:
        player_owns = Item.select().where(Item.generic == item_to_give.generic,
                                          Item.belongs_to_player
                                          == player) is True

    if player_owns:
        # player has the item
        # goto
        # exchange
        steps = [[], [], [], [item_holder.place, item_holder],
                 [item_holder, item_to_give, item_to_fetch]]
        Message.instruction(
            "Do a sub-quest, meet '%s' and exchange '%s' with '%s'" %
            (item_holder, item_to_give, item_to_fetch))
        return steps

    # steps:
    # goto
    # get
    # sub-quest
    # goto
    # exchange
    steps = [[item_to_give.place_(), None, item_to_give], [item_to_give], [],
             [item_holder.place, item_holder],
             [item_holder, item_to_give, item_to_fetch]]
    Message.instruction(
        "Get '%s', do a sub-quest, meet '%s' and exchange '%s' with '%s'" %
        (item_to_give, item_holder, item_to_give, item_to_fetch))
    return steps