def capture_1(target: NPC):
    """
    Get something, go someplace and use it to capture somebody
    :param target:
    :return:
    """
    item_to_fetch = Item.get_or_none(type=ItemTypes.tool.name,
                                     usage=T.capture.value)
    if not item_to_fetch:
        # No item usable for capture, left in the world
        item_to_fetch = Item.create(
            name='arbitrary_capture_tool_' + str(randint(100, 999)),
            type=ItemTypes.tool.name,
            usage=T.capture.value,
            generic=GenericItem.get_or_create(
                name=ItemTypes.singleton.name)[0],
            place=Place.select().order_by(fn.Random()).get(),
            impact_factor=1.0,
            worth=0.75)
        Message.debug(
            "No item usable for 'capture' left in the world, create a new one '%s'"
            % item_to_fetch)

    # steps:
    # get
    # goto
    # T.capture
    steps = [[item_to_fetch], [target.place, target], [target]]
    Message.instruction("Get '%s', then goto '%s' and capture '%s'" %
                        (item_to_fetch, target, target))
    return steps
Beispiel #2
0
def comfort_2(motivated: NPC) -> list:
    """
    Kill pests
    :param motivated:
    :return:
    """
    # find enemy of motivated, or create one
    results = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if results:
        enemy = results.get()
    else:
        # No NPC left in the world except the motivated
        enemies_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).get()
        enemy = NPC.create(place=Place.select().order_by(fn.Random()).get(),
                           clan=enemies_clan,
                           name=NPCName.fetch_new())

    player = Player.current()
    damage_report_intel = Intel.construct(
        other='arbitrary_pest_damage_report_' + str(randint(100, 999)))
    PlayerKnowledgeBook.create(player=player, intel=damage_report_intel)

    # steps:
    #   goto enemies place
    #   kill enemies
    #   goto motivated place
    #   T.report intel(?) to motivated
    steps = [[enemy.place, enemy], [enemy], [motivated.place, motivated],
             [damage_report_intel, motivated]]

    Message.instruction("%s: Take care of that pest '%s' for me" %
                        (motivated, enemy))
    return steps
def sub_quest_2(suggested_destination: Place = None) -> list:
    player = Player.current()

    if suggested_destination:
        return_point = suggested_destination
    else:
        return_point = player.place

    results = Place.select()\
        .join(Intel)\
        .join(PlayerKnowledgeBook, JOIN.LEFT_OUTER)\
        .group_by(Intel).having(fn.COUNT(PlayerKnowledgeBook.id) == 0)

    locations_scores = [player.distance(place) for place in results]
    results = sort_by_list(results, locations_scores)

    if results:
        place_to_go = results[0]
    else:
        # not enough places to go, then create a new place unknown to player
        place_to_go = narrative_helper.create_place()

    player.next_location = place_to_go
    player.save()

    # steps:
    #   goto
    #   Quest
    #   goto
    steps = [[place_to_go], [], [return_point]]
    Message.instruction("Goto '%s' do another Quest, then go to '%s'" %
                        (place_to_go, return_point))
    return steps
Beispiel #4
0
def reputation_2(motivated: NPC) -> list:
    """
    Kill enemies of motivated
    :param motivated: given from higher level nodes
    :return:
    """
    results = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if results:
        enemy = results.get()
    else:
        # No NPC left in the world except the motivated
        enemies_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).get()
        enemy = NPC.create(place=Place.select().order_by(fn.Random()).get(),
                           clan=enemies_clan,
                           name=NPCName.fetch_new())

    player = Player.current()
    killing_report_intel = Intel.construct(other='arbitrary_killing_report_' +
                                           str(randint(100, 999)))
    PlayerKnowledgeBook.create(player=player, intel=killing_report_intel)

    # steps:
    #   goto enemies place
    #   kill enemies
    #   goto motivated place
    #   T.report intel(?) to motivated
    steps = [[enemy.place, enemy], [enemy], [motivated.place, motivated],
             [killing_report_intel, motivated]]
    Message.instruction("%s: Kill my enemy '%s', and report it" %
                        (motivated, enemy))
    return steps
Beispiel #5
0
def serenity_1(motivated: NPC):
    """
    Revenge, Justice
    :param motivated:
    :return:
    """
    enemies = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if enemies:
        target = enemies[0]
    else:
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()
        enemy_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).limit(1).get()
        target = NPC.create(clan=enemy_clan,
                            name=NPCName.fetch_new(),
                            place=place)

    # steps
    #   goto
    #   damage
    steps = [[target.place, target], [target]]
    Message.instruction("%s: Get my revenge from '%s'" % (motivated, target))
    return steps
Beispiel #6
0
def reputation_3(motivated: NPC) -> list:
    """
    Visit a dangerous place
    :param motivated:
    :return:
    """
    # goto an enemies place
    enemies = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if enemies:
        place = enemies[0].place
    else:
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()

    player = Player.current()
    danger_report_intel = Intel.construct(other='arbitrary_danger_report_' +
                                          str(randint(100, 999)))
    PlayerKnowledgeBook.create(player=player, intel=danger_report_intel)

    # steps
    #   goto
    #   goto
    #   report
    steps = [[place], [motivated.place, motivated],
             [danger_report_intel, motivated]]
    Message.instruction(
        "%s: Goto the dangerous '%s' and report what you've seen there" %
        (motivated, place))
    return steps
Beispiel #7
0
def conquest_1(motivated: NPC) -> list:
    """
    Attack enemy
    :param motivated:
    :return:
    """
    # find enemy of motivated, or create one
    results = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if results:
        enemy = results.get()
    else:
        # No NPC left in the world except the motivated
        enemies_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).get()
        enemy = NPC.create(place=Place.select().order_by(fn.Random()).get(),
                           clan=enemies_clan,
                           name=NPCName.fetch_new())

    # steps:
    #   goto enemies place
    #   damage enemies
    steps = [[enemy.place, enemy], [enemy]]

    Message.instruction("%s: Damage my enemy '%s' for me" % (motivated, enemy))
    return steps
Beispiel #8
0
def protection_1(motivated: NPC) -> list:
    """
    Attack threatening entities
    :param motivated:
    :return:
    """
    # find enemy of motivated, or create one
    results = NPC.select().where(NPC.clan != motivated.clan).order_by(
        fn.Random()).limit(1)
    if results:
        enemy = results.get()
    else:
        # No NPC left in the world except the motivated
        enemies_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).get()
        enemy = NPC.create(place=Place.select().order_by(fn.Random()).get(),
                           clan=enemies_clan,
                           name=NPCName.fetch_new())

    player = Player.current()
    threat_report_intel = Intel.construct(
        other='arbitrary_threat_damage_report_' + str(randint(100, 999)))
    PlayerKnowledgeBook.create(player=player, intel=threat_report_intel)

    # steps:
    #   goto enemies place
    #   kill enemies
    #   goto motivated place
    #   T.report intel(?) to motivated
    steps = [[enemy.place, enemy], [enemy], [motivated.place, motivated],
             [threat_report_intel, motivated]]

    Message.instruction("%s: Relieve me of '%s' threats, then report it" %
                        (motivated, enemy))
    return steps
def sub_quest_1(suggested_destination: Place = None):
    # just go somewhere - pick a place_location unknown to player to go to
    # the reason for unknown place_location is, if "learn" comes up in next level, we'll be lucky,
    # if it doesn't, intel can be added to Players knowledge right away.
    player = Player.current()

    if suggested_destination:
        place_to_go = suggested_destination
    else:
        results = Place.select()\
            .join(Intel)\
            .join(PlayerKnowledgeBook, JOIN.LEFT_OUTER)\
            .group_by(Intel).having(fn.COUNT(PlayerKnowledgeBook.id) == 0)

        locations_scores = [player.distance(place) for place in results]
        results = sort_by_list(results, locations_scores)

        if results:
            place_to_go = results[0]
        else:
            # not enough places to go, then create a new place unknown to player
            place_to_go = narrative_helper.create_place()

    player.next_location = place_to_go
    player.save()

    # steps:
    # goto
    steps = [[place_to_go]]
    Message.instruction("Goto '%s'" % place_to_go)
    return steps
Beispiel #10
0
def quest_neutral(motivation: NT) -> List[List[BaseElement]]:
    # select an ally NPC with a certain motivation

    results = Motivation.select()\
        .where(Motivation.action == motivation.value,
               Motivation.motive > 0.5)\
        .order_by(Motivation.motive.desc()).limit(1)

    if results:
        motivated = results.get().npc
    else:
        # No motivated NPC found, create one
        place = Place.select().order_by(fn.Random()).get()
        clan = Clan.select().order_by(fn.Random()).get()
        motivated = NPC.create(place=place,
                               clan=clan,
                               name=NPCName.fetch_new())
        Motivation.create(npc=motivated, action=motivation.value, motive=0.65)

    # steps:
    #   give useful info to this NPC
    steps = [[motivated]]
    Message.instruction("NPC '%s' has '%s' motivation" %
                        (motivated.name, motivation.name))
    return steps
def goto_2(destination: Place, npc: NPC = None, item: Item = None):
    """
    Explore destination to find npc or item
    :return:
    """
    # place_location[1] is destination
    # area around location[1] is given to player to explore and find location[1]
    player = Player.current()

    # ensure player doesn't already know where the NPC or item is
    if npc:
        intel = Intel.construct(npc_place=npc)
        if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
            # player knows where the NPC is, move the NPC then
            npc.place = Place.select().where(Place.id != destination).order_by(
                fn.Random()).get()
            npc.save()
            destination = npc.place
            Message.event(
                "You just missed '%s' he has moved to somewhere else" % npc)
    elif item:
        intel = Intel.construct(item_place=item)
        if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
            # player knows where the Item is, move the item or item's holder
            if item.belongs_to:
                holder = item.belongs_to
                holder.place = Place.select().where(
                    Place.id != destination).order_by(fn.Random()).get()
                holder.save()
                destination = holder.place
                Message.event(
                    "Item '%s's holder just has been moved to somewhere else" %
                    item)
            else:
                item.place = Place.select().where(
                    Place.id != destination).order_by(fn.Random()).get()
                item.save()
                destination = item.place
                Message.event(
                    "Item '%s' just has been moved to somewhere else" % item)

    # steps:
    # T.explore
    steps = [[destination, npc, item]]
    Message.instruction("Explore around '%s'" % destination)
    return steps
Beispiel #12
0
def comfort_1(motivated: NPC) -> list:
    """
    Obtain luxuries for the motivated NPC
    :param motivated:
    :return:
    """
    # get item useful for motivated

    needed_item = Item.select().join(Need).where(Need.npc == motivated, Item.belongs_to_player.is_null())\
        .order_by(fn.Random()).limit(1)
    if needed_item:
        # motivated NPC need some items
        item = needed_item[0]
    else:
        # motivated NPC doesn't have any needs
        items_in_world = Item.select().where(
            Item.belongs_to_player.is_null()).order_by(
                Item.worth.desc()).limit(1)
        if items_in_world:
            item = items_in_world[0]
        else:
            # item not found in the world
            place = Place.select().order_by(fn.Random()).limit(1)
            if place:
                place = place[0]
            else:
                Message.debug("No place found in the World!")
                place = helper.create_place()
            item = Item.create(type=ItemTypes.unknown.name,
                               generic=GenericItem.get_or_create(
                                   name=ItemTypes.singleton.name)[0],
                               name='arbitrary_item_' + str(randint(100, 999)),
                               place=place,
                               worth=1)
            Message.debug("No Item found in the world, item created: %s" %
                          item)

    # steps:
    #   get
    #   goto
    #   give
    steps = [[item], [motivated.place, motivated], [item, motivated]]

    Message.instruction("%s: Get luxury item '%s' for me" % (motivated, item))
    return steps
Beispiel #13
0
def serenity_5(motivated: NPC) -> list:
    """
    Check on NPC(2)
    :param motivated:
    :return:
    """
    # find ally NPC to motivated get an item from he/she
    allies = NPC.select().where(NPC.clan == motivated.clan,
                                NPC.id != motivated).order_by(
                                    fn.Random()).limit(1)
    if allies:
        target = allies[0]
    else:
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()
        target = NPC.create(clan=motivated.clan,
                            name=NPCName.fetch_new(),
                            place=place)

    belongings = Item.select().where(Item.belongs_to == target.id).order_by(
        fn.Random()).limit(1)
    if belongings:
        item = belongings[0]
    else:
        item = Item.create(type=ItemTypes.singleton.name,
                           generic=GenericItem.get_or_create(
                               name=ItemTypes.singleton.name)[0],
                           name='arbitrary_item_' + str(randint(100, 999)),
                           belongs_to=target)
    # steps
    #   goto
    #   take
    #   goto
    #   give
    steps = [[target.place, target], [item, target],
             [motivated.place, motivated], [item, motivated]]
    Message.instruction("%s: Get item '%s' from my friend, '%s' for me" %
                        (motivated, item, target))
    return steps
Beispiel #14
0
def conquest_2(motivated: NPC) -> list:
    """
    Steal stuff
    :param motivated:
    :return:
    """
    # find something an enemy to motivated has
    item = None
    enemy_ids = NPC.select(NPC.id).where(NPC.clan != motivated.clan)
    if enemy_ids:
        items = Item.select().where(Item.belongs_to.in_(enemy_ids)).order_by(
            fn.Random()).limit(1)
        if items:
            item = items[0]

    if not item:
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()
        enemy_clan = Clan.select().where(Clan.id != motivated.clan).order_by(
            fn.Random()).limit(1).get()
        target = NPC.create(clan=enemy_clan,
                            name=NPCName.fetch_new(),
                            place=place)
        item = Item.create(type=ItemTypes.singleton.name,
                           generic=GenericItem.get_or_create(
                               name=ItemTypes.singleton.name)[0],
                           name='arbitrary_item_' + str(randint(100, 999)),
                           belongs_to=target)

    # steps
    #   goto
    #   steal
    #   goto
    #   give
    steps = [[item.place_(), None, item], [item, item.belongs_to],
             [motivated.place, motivated], [item, motivated]]
    Message.instruction("%s: Steal item '%s' from '%s' for me" %
                        (motivated, item, item.belongs_to))
    return steps
Beispiel #15
0
def knowledge_1(NPC_target: NPC):
    """
    Deliver item for study
    :param NPC_target:
    :return:
    """
    player = Player.current()
    results = Item.select().where(Item.belongs_to != NPC_target,
                                  Item.belongs_to_player != player)
    if results:
        locations_scores = [player.distance(res.place_()) for res in results]
        results = sort_by_list(results, locations_scores)
        item = results[0]
    else:
        results = NPC.select().where(NPC.id != NPC_target)
        if results:
            locations_scores = [player.distance(res.place) for res in results]
            results = sort_by_list(results, locations_scores)
            new_item_holder = results[0]
        else:
            # No NPC left in the world except the target
            new_item_holder = NPC.create(
                place=Place.select().order_by(fn.Random()).get(),
                clan=Clan.select().order_by(fn.Random()).get(),
                name=NPCName.fetch_new())
        item = Item.create(type=ItemTypes.unknown.name,
                           generic=GenericItem.get_or_create(
                               name=ItemTypes.singleton.name)[0],
                           name='arbitrary_item_unknown_' +
                           str(randint(100, 999)),
                           place=None,
                           belongs_to=new_item_holder)

    # steps:
    #   get item
    #   goto target place
    #   give item to target
    steps = [[item], [NPC_target.place, NPC_target], [item, NPC_target]]
    Message.instruction("%s: Get item '%s' for me, I want to study it" %
                        (NPC_target, item))
    return steps
def get_3(item_to_fetch: Item):
    """
    Go someplace and pick something up that’s lying around there
    :param item_to_fetch:
    :return:
    """
    if item_to_fetch.place:
        dest = item_to_fetch.place
    elif item_to_fetch.belongs_to:
        # someone took it and put it in a specific place, put it where the NPC is
        Message.event(
            "Someone has stolen the item '%s' and put it somewhere else" %
            item_to_fetch)
        dest = item_to_fetch.belongs_to.place
        item_to_fetch.belongs_to = None
        item_to_fetch.place = dest
        item_to_fetch.save()
    else:
        # player already has the item or no one has it, put it in a random place
        Message.event(
            "Someone has stolen the item '%s' and has put it in a random place"
            % item_to_fetch)
        dest = Place.select().order_by(fn.Random()).get()
        item_to_fetch.place = dest
        item_to_fetch.save()

    player = Player.current()
    player.next_location = dest
    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())

    # steps:
    # goto
    # gather
    steps = [[dest, None, item_to_fetch], [item_to_fetch]]
    Message.instruction("Gather '%s' from '%s'" % (item_to_fetch, dest))
    return steps
Beispiel #17
0
def reputation_1(motivated: NPC) -> list:
    """
    Obtain rare items
    :param motivated:
    :return:
    """
    # find high worth item

    worthy_item = Item.select().where(
        Item.belongs_to_player.is_null()).order_by(Item.worth.desc()).limit(1)
    if worthy_item:
        # item found for NPC
        item = worthy_item[0]
    else:
        # item not found in the world
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()
        item = Item.create(type=ItemTypes.unknown.name,
                           generic=GenericItem.get_or_create(
                               name=ItemTypes.singleton.name)[0],
                           name='arbitrary_item_' + str(randint(100, 999)),
                           place=place,
                           worth=1)
        Message.debug("No Item found in the world, item created: %s" % item)

    # steps:
    #   get
    #   goto
    #   give
    steps = [[item], [motivated.place, motivated], [item, motivated]]

    Message.instruction("%s: Get the rare item '%s' for me" %
                        (motivated, item))
    return steps
Beispiel #18
0
def serenity_4(motivated: NPC) -> list:
    """
    Check on NPC(1)
    :param motivated:
    :return:
    """
    # find ally NPC to motivated get generated intel about health and well being
    allies = NPC.select().where(NPC.clan == motivated.clan,
                                NPC.id != motivated).order_by(
                                    fn.Random()).limit(1)
    if allies:
        target = allies[0]
    else:
        place = Place.select().order_by(fn.Random()).limit(1)
        if place:
            place = place[0]
        else:
            Message.debug("No place found in the World!")
            place = helper.create_place()
        target = NPC.create(clan=motivated.clan,
                            name=NPCName.fetch_new(),
                            place=place)

    well_being_intel = Intel.construct(other='arbitrary_well_being_report_' +
                                       str(randint(100, 999)))
    NPCKnowledgeBook.create(npc=target, intel=well_being_intel)
    # steps
    #   goto
    #   listen
    #   goto
    #   report
    steps = [[target.place, target], [well_being_intel, target],
             [motivated.place, motivated], [well_being_intel, motivated]]
    Message.instruction(
        "%s: Check on my friend, '%s' ask how he's doing for me" %
        (motivated, target))
    return steps
def create():
    alliance = Clan.create(name='alliance')
    horde = Clan.create(name='horde')

    beach = Place.create(name='beach', x=10, y=80)
    azshara = Place.create(name='azshara', x=50, y=50)
    cataclysm = Place.create(name='cataclysm', x=70, y=90)
    crystalsong = Place.create(name='crystalsong', x=10, y=60)
    forest = Place.create(name='forest', x=60, y=20)
    dalaran = Place.create(name='dalaran', x=80, y=85)
    feralas = Place.create(name='feralas', x=10, y=10)
    harbor = Place.create(name='harbor', x=80, y=10)
    shrine = Place.create(name='shrine', x=30, y=80)
    nagrand = Place.create(name='nagrand', x=70, y=40)
    acherus = Place.create(name='acherus', x=10, y=40)
    alcaz = Place.create(name='alcaz', x=90, y=60)

    PlaceName.create(name='hamilton')
    PlaceName.create(name='denver')
    PlaceName.create(name='munich')
    PlaceName.create(name='quebec')

    player = Player.create(name='player_1', place=beach, clan=alliance)

    qeynos = NPC.create(name='qeynos', place=azshara, clan=alliance)
    npc_2 = NPC.create(name='npc2', place=beach, clan=alliance)  # = adon
    steve = NPC.create(name='steve', place=forest, clan=alliance)
    tomas = NPC.create(name='tomas', place=feralas, clan=alliance)
    lempeck = NPC.create(name='lempeck',
                         place=harbor,
                         clan=alliance,
                         health_meter=0.7)  # = Denros
    bixies = NPC.create(name='bixies', place=cataclysm, clan=horde)
    goblin = NPC.create(name='goblin', place=dalaran, clan=horde)

    NPCName.create(name='gabriel')
    NPCName.create(name='mariah')
    NPCName.create(name='sia')
    NPCName.create(name='silva')
    NPCName.create(name='berg')
    NPCName.create(name='jessie')
    NPCName.create(name='lizzy')
    NPCName.create(name='amanda')
    NPCName.create(name='bernard')
    NPCName.create(name='monica')
    NPCName.create(name='catrina')
    NPCName.create(name='leo')
    NPCName.create(name='richard')
    NPCName.create(name='naomi')
    NPCName.create(name='aaron')

    Motivation.create(npc=steve, action=NT.knowledge.value, motive=0.6)
    Motivation.create(npc=lempeck, action=NT.comfort.value, motive=0.9)
    Motivation.create(npc=npc_2, action=NT.reputation.value, motive=0.7)
    Motivation.create(npc=goblin, action=NT.serenity.value, motive=0.7)
    Motivation.create(npc=tomas, action=NT.protection.value, motive=0.7)
    Motivation.create(npc=qeynos, action=NT.conquest.value, motive=0.7)

    potion = Item.create(
        type=ItemTypes.tool.name,
        generic=GenericItem.get_or_create(name=ItemTypes.singleton.name)[0],
        name='potion',
        place=None,
        belongs_to=qeynos,
        usage=T.treat.value,
        impact_factor=0.5)
    jum = Item.create(type=ItemTypes.unknown.name,
                      generic=GenericItem.get_or_create(name='jum')[0],
                      name='jum',
                      place=None,
                      belongs_to=npc_2)
    comb = Item.create(type=ItemTypes.unknown.name,
                       generic=GenericItem.get_or_create(name='comb')[0],
                       name='comb',
                       place=None,
                       belongs_to=bixies)
    bandage = Item.create(type=ItemTypes.tool.name,
                          generic=GenericItem.get_or_create(name='bandage')[0],
                          name='bandage',
                          place=crystalsong,
                          belongs_to=None,
                          usage=T.treat.value)
    address_book = Item.create(
        type=ItemTypes.readable.name,
        generic=GenericItem.get_or_create(name=ItemTypes.singleton.name)[0],
        name='address_book',
        belongs_to=tomas)  # address-book (goblin loc)
    coin = Item.create(type=ItemTypes.unknown.name,
                       generic=GenericItem.get_or_create(name='coin')[0],
                       name='coin',
                       belongs_to_player=player)

    Need.create(npc=lempeck, item=potion)

    spell = Intel.construct(spell=Spell.create(
        name="needs_path",
        text="'Earth, grass, trees and seeds reveal the path to suit my needs'"
    ))
    spell_2 = Intel.construct(
        spell=Spell.create(name="flat_earth", text="Earth is flat! LoL"))
    spell_3 = Intel.construct(
        spell=Spell.create(name="gravity", text="Gravity is a myth"))

    # SpellName.create()

    NPCKnowledgeBook.create(npc=goblin, intel=spell)
    NPCKnowledgeBook.create(npc=bixies, intel=spell_2)
    NPCKnowledgeBook.create(npc=steve, intel=spell_2)

    intel_bandage_loc = Intel.construct(item_place=bandage)
    intel_npc2_loc = Intel.construct(npc_place=npc_2, worth=0.6)

    intel_goblin_loc = Intel.construct(npc_place=goblin, worth=0.8)
    ReadableKnowledgeBook.create(readable=address_book, intel=intel_goblin_loc)

    intel_tomas_loc = Intel.construct(npc_place=tomas)
    NPCKnowledgeBook.create(npc=bixies, intel=intel_tomas_loc)
    NPCKnowledgeBook.create(npc=lempeck, intel=intel_tomas_loc)

    intel_lempeck_loc = Intel.construct(npc_place=lempeck)
    NPCKnowledgeBook.create(npc=qeynos, intel=intel_lempeck_loc)

    intel_qeynos_loc = Intel.construct(npc_place=qeynos)
    NPCKnowledgeBook.create(npc=npc_2, intel=intel_qeynos_loc)

    intel_comb_place = Intel.construct(item_place=comb)
    NPCKnowledgeBook.create(npc=npc_2, intel=intel_comb_place)

    intel_cataclysm = Intel.construct(npc_place=bixies)
    NPCKnowledgeBook.create(npc=npc_2, intel=intel_cataclysm)

    Exchange.create(npc=qeynos,
                    item=potion,
                    need=Need.get_or_create(npc=qeynos, item=jum)[0])
    Exchange.create(npc=npc_2,
                    intel=intel_comb_place,
                    need=Need.get_or_create(npc=npc_2, item=bandage)[0])
    Exchange.create(npc=npc_2,
                    intel=intel_cataclysm,
                    need=Need.get_or_create(npc=npc_2, item=bandage)[0])
    Exchange.create(npc=npc_2,
                    item=jum,
                    need=Need.get_or_create(npc=npc_2, item=comb)[0])
    Exchange.create(npc=tomas,
                    item=address_book,
                    need=Need.get_or_create(npc=tomas, item=coin)[0])

    for place in Place.select():
        intel = Intel.construct(place_location=place)
        PlayerKnowledgeBook.create(player=player, intel=intel)
def goto_3(destination: Place, npc: NPC = None, item: Item = None):
    """
    Find out where to go and go there.
    :return:
    """
    # place_location[1] is destination
    # location[1] is place_location[1] exact location
    player = Player.current()

    # find correct type of Intel from npc_place, item_place and place_location
    if npc:
        intel = Intel.get_or_none(type=IntelTypes.npc_place.name,
                                  npc_place=npc)
        if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
            # player already knows, move the npc
            destination = Place.select().where(Place.id != npc.place).order_by(
                fn.Random())
            if destination:
                destination = destination.get()
            else:
                destination = narrative_helper.create_place()
            npc.place = destination
            npc.save()
            # by moving NPC place, npc_place intel removes from player knowledge book automatically
            Message.event("NPC %s has moved to somewhere else" % npc)
    elif item:
        if item.belongs_to:
            intel = Intel.get_or_none(type=IntelTypes.npc_place.name,
                                      npc_place=item.belongs_to)
            if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
                # player already knows where the item holder is, move the npc
                holder = item.belongs_to
                destination = Place.select().where(
                    Place.id != holder.place).order_by(fn.Random())
                if destination:
                    destination = destination.get()
                else:
                    destination = narrative_helper.create_place()
                holder.place = destination
                holder.save()
                Message.debug(
                    "Item holder (%s) is moved somewhere else (item: %s)" %
                    (item.belongs_to, item))
                Message.event(
                    "Item '%s's holder has been just moved to somewhere else" %
                    item)
        else:
            intel = Intel.get_or_none(type=IntelTypes.item_place.name,
                                      item_place=item)
            if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
                # player already knows where the item is located at, move the item
                destination = Place.select().where(
                    Place.id != item.place).order_by(fn.Random())
                if destination:
                    destination = destination.get()
                else:
                    destination = narrative_helper.create_place()
                item.place = destination
                item.save()
                Message.event("Item '%s' has been misplaced" % item)
    else:
        intel = Intel.get_or_none(type=IntelTypes.location.name,
                                  place_location=destination)
        if PlayerKnowledgeBook.get_or_none(player=player, intel=intel):
            # player already knows where the place is exactly,
            # so create a new place at the same location with a different name, now player doesn't know!
            destination = Place.create(name=PlaceName.fetch_new(),
                                       x=destination.x,
                                       y=destination.y)
            intel = Intel.construct(place_location=destination)
            Message.event("Change of plans, destination is now '%s'" %
                          destination)

    if not intel:
        # create the correct type of intel based on what is being asked
        if npc:
            intel = Intel.construct(npc_place=npc)
        elif item and item.belongs_to:
            intel = Intel.construct(npc_place=item.belongs_to)
        elif item:
            intel = Intel.construct(item_place=item)
        else:
            intel = Intel.construct(place_location=destination)

    # update player's next location
    player.next_location = destination
    player.save()

    # steps:
    #   learn: location[1]
    #   T.goto: location[1]
    steps = [[intel], [destination]]

    if PlayParams.debug_mode and (npc or item):
        destination_str = str(npc if npc else item) + ' (' + str(
            destination) + ')'
    else:
        if npc:
            destination_str = npc
        elif item:
            destination_str = item
        else:
            destination_str = destination

    Message.instruction("Find out how to get to '%s' location, then go to it" %
                        destination_str)

    return steps
def learn_2(required_intel: Intel):
    """
    Go someplace, perform subquest, get info from NPC.
    :param required_intel:
    :return:
    """
    player = Player.current()

    # find NPC who has the intel, goto the NPC and listen to get the intel
    results = NPC.select()\
        .join(NPCKnowledgeBook)\
        .where(NPCKnowledgeBook.intel == required_intel, NPC.clan == player.clan)

    # sort by triangle distance
    locations_scores = [player.distance(row.place) for row in results]
    results = sort_by_list(results, locations_scores)

    if results:
        knowledgeable_npc = results[0]
    else:
        # NPC pool to add required intel to one of them
        results = NPC.select().where(NPC.clan == player.clan)
        if not results:
            # No NPC in clan found search among all NPCs
            Message.debug("No NPC in clan %s found, search among all NPCs" %
                          NPC.clan)
            results = NPC.select().order_by(fn.Random()).get()
            if required_intel.npc_place:
                # exclude the same NPC looking for
                results = results.where(NPC.id != required_intel.npc_place)
        elif required_intel.item_place and required_intel.item_place.belongs_to:
            # exclude the owner of the item to ask where is the item!
            results = results.where(
                NPC.id != required_intel.item_place.belongs_to)

        if not results:
            # No NPC left in the world
            knowledgeable_npc = NPC.create(
                place=Place.select().order_by(fn.Random()).get(),
                clan=Clan.select().order_by(fn.Random()).get(),
                name=NPCName.fetch_new())
            Message.debug(
                "No NPC left in the world, new one %s created for learn_2" %
                knowledgeable_npc)
        else:
            locations_scores = [player.distance(row.place) for row in results]
            results = sort_by_list(results, locations_scores)
            knowledgeable_npc = results[0]

        NPCKnowledgeBook.create(npc=knowledgeable_npc, intel=required_intel)

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

    # steps:
    # do sub-quest
    # goto knowledgeable_npc place_location
    # listen knowledgeable_npc to get required_intel
    steps = [[], [knowledgeable_npc.place, knowledgeable_npc],
             [required_intel, knowledgeable_npc]]
    Message.instruction(
        "Do a sub-quest, goto '%s', listen intel '%s' from '%s'" %
        (knowledgeable_npc, required_intel, knowledgeable_npc))
    return steps
def learn_3(required_intel: Intel):
    """
    Go someplace, get something, and read what is written on it.
    :param required_intel:
    :return:
    """
    player = Player.current()
    # intel[1] is to be learned
    # find a book[1] (readable, it could be a sign) that has intel[1] on it
    results = ReadableKnowledgeBook.select()\
        .join(Item, on=(ReadableKnowledgeBook.readable == Item.id))\
        .where(ReadableKnowledgeBook.intel == required_intel,
               Item.belongs_to_player != player)

    # sort by readable place_ triangle
    locations_scores = [
        player.distance(knowledge_book.readable.place_())
        for knowledge_book in results
    ]
    results = sort_by_list(results, locations_scores)

    if results:
        book_containing_intel = results[0].readable  # type: Item
    else:
        # create an address book containing the intel player is looking for
        known_places = Place.select()\
            .join(Intel, on=(Intel.place_location == Place.id))\
            .join(PlayerKnowledgeBook, on=(PlayerKnowledgeBook.intel == Intel.id))\
            .where(PlayerKnowledgeBook.player == player)
        if known_places:
            known_place = known_places.order_by(fn.Random()).get()
        else:
            known_place = narrative_helper.create_place()

        book_containing_intel = Item.create(
            type=ItemTypes.readable.name,
            generic=GenericItem.get_or_create(
                name=ItemTypes.singleton.name)[0],
            name=ItemName.fetch_new(),
            place=known_place)
        ReadableKnowledgeBook.create(readable=book_containing_intel,
                                     intel=required_intel)
        PlayerKnowledgeBook.create(
            player=player,
            intel=Intel.construct(item_place=book_containing_intel))

    player.next_location = book_containing_intel.place_()
    player.save()

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

    # steps:
    # goto: place_location[1]
    # get: book[1]
    # T.read: intel[1] from book[1]
    steps = [[book_containing_intel.place_(), None, book_containing_intel],
             [book_containing_intel], [required_intel, book_containing_intel]]
    Message.instruction("Get '%s', and read the intel '%s' from it" %
                        (book_containing_intel, required_intel))
    return steps
def learn_4(required_intel: Intel):
    # find an NPC who has the required intel in exchange, get the NPC's needed item to give

    if required_intel.npc_place:
        bad_needs = Need.select(Need.id).join(Item).where(
            (Need.npc == required_intel.npc_place)
            | (Item.belongs_to == required_intel.npc_place))
    elif required_intel.item_place:
        bad_needs = Need.select(
            Need.id).where(Need.item == required_intel.item_place)
    else:
        bad_needs = []

    # NPC who has the intel
    knowledgeable = NPC.select(NPC.id).join(NPCKnowledgeBook).where(
        NPC.id != required_intel.npc_place,
        NPCKnowledgeBook.intel == required_intel.id)
    exchange = None
    if knowledgeable.count():
        needs = Need.select()\
            .join(NPC)\
            .where(NPC.id.in_(knowledgeable),
                   Need.id.not_in(bad_needs),
                   Need.item_id.is_null(False))
        if needs:
            exchanges = Exchange.select().where(
                Exchange.need.in_(needs),
                Exchange.intel == required_intel.id).limit(1)
            if exchanges:
                exchange = exchanges[0]
            else:
                exchange = Exchange.create(need=needs[0], intel=required_intel)

    if not exchange:
        # no NPC has the intel or no need found
        accessible_items = Item.select().where(
            (Item.id != required_intel.item_place)
            & (Item.belongs_to_player.is_null())
            & ((Item.belongs_to.is_null())
               | Item.belongs_to != required_intel.npc_place)).order_by(
                   fn.Random()).limit(1)
        if accessible_items:
            item = accessible_items[0]
        else:
            holder = NPC.select().where(
                NPC.id != required_intel.npc_place).order_by(
                    fn.Random()).limit(1)
            if holder:
                holder = holder[0]
            else:
                holder = NPC.create(
                    name=NPCName.fetch_new(),
                    clan=Clan.select().order_by(fn.Random()).get(),
                    place=Place.select().order_by(fn.Random()).get())
            item = Item.create(name='arbitrary_item_' + str(randint(100, 999)),
                               generic=GenericItem.get_or_create(
                                   name=ItemTypes.singleton.name)[0],
                               belongs_to=holder,
                               type=ItemTypes.unknown.name)
        if knowledgeable:
            informer = knowledgeable.order_by(fn.Random()).get()
        else:
            npc = NPC.select().where(
                NPC.id != required_intel.npc_place).order_by(
                    fn.Random()).limit(1)
            if npc:
                informer = npc[0]
            else:
                informer = NPC.create(
                    name=NPCName.fetch_new(),
                    clan=Clan.select().order_by(fn.Random()).get(),
                    place=Place.select().order_by(fn.Random()).get())
            NPCKnowledgeBook.create(npc=informer, intel=required_intel)
        need = Need.create(npc=informer, item=item)
        exchange = Exchange.create(need=need, intel=required_intel)

    informer = exchange.need.npc
    item_to_get_for_exchange = exchange.need.item

    player = Player.current()
    player.next_location = informer.place
    player.save()

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

    # steps:
    # get
    # sub-quest
    # give
    # listen
    steps = [[item_to_get_for_exchange], [informer.place],
             [item_to_get_for_exchange, informer], [required_intel, informer]]
    Message.instruction(
        "Get '%s', perform a sub-quest, give the acquired item to '%s' in return get an intel on '%s'"
        % (item_to_get_for_exchange, informer, required_intel))
    return steps