Пример #1
0
    def perform_character_creation_questions(
            self, existing_names: List[str]) -> Union[str, bool, list, dict]:
        questions = [
            {
                "type": "input",
                "message":
                emojis.encode(':man: Please enter your character name '),
                "validate": DuplicatedNamesValidator(existing_names),
                "invalid_message": "minimum of 1 letters, max of 20 letters",
                "name": "nickname"
            },
            {
                "type":
                "list",
                "message":
                emojis.encode(':skull: Please enter your character race? '),
                "choices":
                get_configuration(RACES_SECTION).keys(),
                "name":
                "race"
            },
            {
                "type":
                "list",
                "message":
                emojis.encode(
                    ':name_badge: Please enter your character job? '),
                "choices":
                get_configuration(JOBS_SECTION).keys(),
                "name":
                "job"
            },
        ]

        return prompt(questions)
Пример #2
0
    def attack(self, player: IPlayer) -> Optional[bool]:
        players = self.game.get_remaining_players(player)
        attack_range = player.get_ranged_attack_area()
        possible_foes = self.get_attack_possibilities(attack_range, player, players)
        if len(possible_foes) == 0:
            self.communicator.informer.no_foes_attack(player)
            return False
        enemy_to_attack = self.communicator.questioner.ask_enemy_to_attack(possible_foes)
        if enemy_to_attack is None:
            return False
        self.communicator.informer.force_loading(2)
        self.communicator.informer.event('attack')
        dice_result = self.game.roll_the_dice()
        self.communicator.informer.dice_result(player.name, dice_result, 'attack', self.game.dice_sides)

        damage = self.calculate_damage(player, enemy_to_attack, dice_result)
        self.check_player_level_up(player)
        if damage > 0:
            enemy_to_attack.suffer_damage(damage)
            self.communicator.informer.suffer_damage(player, enemy_to_attack, damage)
            experience = get_configuration(EXPERIENCE_EARNED_ACTION).get('attack', 0)

            player.earn_xp(experience)
            self.communicator.informer.player_earned_xp(player_name=player.name, xp=experience)

            if not enemy_to_attack.is_alive():
                experience = get_configuration(EXPERIENCE_EARNED_ACTION).get('kill', 0)
                player.earn_xp(experience)
                self.communicator.informer.player_killed_enemy_earned_xp(player_name=player.name, xp=experience)
        else:
            self.communicator.informer.missed(player, enemy_to_attack)
        return
Пример #3
0
 def check_experience(self, player: IPlayer, successful_skill: bool,
                      killed: bool) -> None:
     if successful_skill:
         experience = get_configuration(EXPERIENCE_EARNED_ACTION).get(
             'attack', 0)
         player.earn_xp(experience)
         self.communicator.informer.player_earned_xp(
             player_name=player.name, xp=experience)
     if killed:
         experience = get_configuration(EXPERIENCE_EARNED_ACTION).get(
             'kill', 0)
         player.earn_xp(experience)
         self.communicator.informer.player_earned_xp(
             player_name=player.name, xp=experience)
Пример #4
0
 def test_conf(self):
     # this test is self explanatory, as the game configuration class itself, already does a lot of
     # validations on all the required files, params and environment variables, the only test to be done it's
     # to check this class gets instantiated correctly, because as a Singleton, the class has all validators inside
     # its constructor
     configuration_object = get_configuration('')
     self.assertIsNotNone(configuration_object)
Пример #5
0
    def distribute_random_items(self) -> None:
        """
        Function to coordinate distribution of random items in the map

        The items will be placed in the half of the quantity of the walkable nodes in the map, and with the
        probabilities for each tier of item configured in the conf file, the quantity for each tier will be determined,
        and finally a random items will be picked for the respective quantities of each tier, and placed in some random
        places.

        :rtype: None
        """
        walkable_nodes = self.graph.get_walkable_nodes()

        number_of_walkable_nodes = len(walkable_nodes)
        number_of_items = floor(number_of_walkable_nodes / 2)
        probabilities = get_configuration('item_probabilities')
        common_items_number = round(number_of_items *
                                    probabilities.get('common', 0.6))
        uncommon_items_number = round(number_of_items *
                                      probabilities.get('uncommon', 0.2))
        rare_items_number = round(number_of_items *
                                  probabilities.get('rare', 0.15))
        legendary_items_number = round(number_of_items *
                                       probabilities.get('legendary', 0.05))
        item_type_distribution = {
            'common':
            ['healing'] * 45 + ['equipment'] * 30 + ['recovery'] * 25,
            'uncommon': ['healing'] * 50 + ['equipment'] * 50,
            'rare': ['healing'] * 20 + ['equipment'] * 80,
            'legendary': ['equipment'] * 80
        }

        for i in range(common_items_number + uncommon_items_number +
                       rare_items_number + legendary_items_number):
            key = random.choice(list(walkable_nodes.keys()))
            walkable_nodes.pop(key)
            tier = ''
            if common_items_number > 0:
                tier = 'common'
                common_items_number = common_items_number - 1
            elif uncommon_items_number > 0:
                tier = 'uncommon'
                uncommon_items_number = uncommon_items_number - 1
            elif rare_items_number > 0:
                tier = 'rare'
                rare_items_number = rare_items_number - 1
            elif legendary_items_number > 0:
                tier = 'legendary'
                legendary_items_number = legendary_items_number - 1

            item_type = random.choice(item_type_distribution.get(tier))
            item = get_random_item(tier, item_type)
            self.add_item_to_map(key, item)
Пример #6
0
def bot_factory(number_of_bots: int) -> List[IBotPlayer]:
    """
    Function that will generated all the bots, depending of the number that was informed as the argument,
    each bot race and job, will be picked randomly.

    :param int number_of_bots: Number of bots to create.
    :rtype: List[IBotPlayer].
    """
    bots = []
    jobs = list(get_configuration(JOBS_SECTION).keys())
    races = list(get_configuration(RACES_SECTION).keys())
    for n in range(int(number_of_bots)):
        name = generate_name()
        chosen_job = jobs[randrange(len(jobs))]
        chosen_race = races[randrange(len(races))]
        job = dynamic_jobs_classes[chosen_job]()
        race = dynamic_races_classes[chosen_race]()
        bag = Bag()
        equipment = Equipment()
        bots.append(BotPlayer(name, job, race, bag, equipment))

    return bots
Пример #7
0
def get_random_item(tier: str, item_type: str) -> Item:
    """
    Function to get a random item along all the items from the items.yaml file,
    considering a specific tier and type.

    :param str tier: The tier of the item.
    :param str item_type: The type of the item(healing, recovery, equipment)
    :rtype: Item
    """
    items_dicts = get_configuration(ITEMS_SECTION)
    item_key = random.choice(
        list({
            k: v
            for (k, v) in items_dicts.items()
            if v.get('tier') == tier and v.get('type') == item_type
        }.keys()))
    item_dict = items_dicts.get(item_key)

    if item_dict.get('type') == 'healing':
        return HealingItem(name=item_dict.get('name'),
                           tier=item_dict.get('tier'),
                           description=item_dict.get('description'),
                           weight=item_dict.get('weight'),
                           attribute=item_dict.get('attribute'),
                           base=item_dict.get('base'))
    elif item_dict.get('type') == 'recovery':
        return RecoveryItem(name=item_dict.get('name'),
                            tier=item_dict.get('tier'),
                            description=item_dict.get('description'),
                            weight=item_dict.get('weight'),
                            status=item_dict.get('status'))
    elif item_dict.get('type') == 'equipment':
        '''
        Side-effects are instantiated here, because when the user equips the item, the side-effect it's 
        already instantiated and it will be appended into the user's side-effect list, passing the same instance,
        which makes the changes to duration attribute, each time a new turn comes, reflects both in the list of side
        effects and also in the bag. 
        
        '''
        side_effects = instantiate_side_effects(item_dict.get('side_effects'))

        return EquipmentItem(name=item_dict.get('name'),
                             tier=item_dict.get('tier'),
                             description=item_dict.get('description'),
                             weight=item_dict.get('weight'),
                             attribute=item_dict.get('attribute'),
                             base=item_dict.get('base'),
                             side_effects=side_effects,
                             category=item_dict.get('category'),
                             usage=item_dict.get('usage'),
                             wielding=item_dict.get('wielding', 0))
Пример #8
0
def improve_attributes_automatically(job: IJob, race: IRace) -> Dict:
    """
    This function can be used by both bots and humans to upgrade their attributes, this method
    Takes the result of the combination of the attributes from job and race, and select the greater ones to improve.

    :param Job job: base job of the player.
    :param Race race: base race of the player.
    :rtype: dict.
    """
    unsorted_attributes_dict = {}
    chosen_attributes = {}
    job_attribute_points = get_configuration(JOBS_SECTION).get(job)
    race_attribute_points = get_configuration(RACES_SECTION).get(race)
    level_up_increment_attributes = get_configuration(LEVEL_UP_INCREMENT)

    for key, value in level_up_increment_attributes.items():
        unsorted_attributes_dict[
            key] = job_attribute_points[key] + race_attribute_points[key]

    sorted_list = iter(
        sorted(unsorted_attributes_dict,
               key=unsorted_attributes_dict.get,
               reverse=True))
    first_attribute = next(sorted_list)
    second_attribute = next(sorted_list)
    not_allowed_together_list = ['magic_points', 'health_points']

    # As HP and MP, always have a higher distribution percentage, most probably they will always be the first two
    # elements of the sorted list, so to prevent all bots to always improve only these attributes, this IF is necessary.
    if first_attribute in not_allowed_together_list and second_attribute in not_allowed_together_list:
        second_attribute = next(sorted_list)

    chosen_attributes[first_attribute] = level_up_increment_attributes.get(
        first_attribute, 0)
    chosen_attributes[second_attribute] = level_up_increment_attributes.get(
        second_attribute, 0)

    return chosen_attributes
Пример #9
0
def improve_attributes_randomly() -> Dict:
    """
    This function can be used by bots and humans, and it will randomly pick 2 attributes to upgrade.

    :rtype: dict.
    """
    level_up_increment_attributes = copy(get_configuration(LEVEL_UP_INCREMENT))
    first_key, first_val = random.choice(
        list(level_up_increment_attributes.items()))
    level_up_increment_attributes.pop(first_key, None)
    second_key, second_val = random.choice(
        list(level_up_increment_attributes.items()))

    return {first_key: first_val, second_key: second_val}
Пример #10
0
 def __init__(self, clsname, superclasses, attributedict):
     if clsname == 'Race':
         return
     super_class = superclasses[0]
     race_attributes = get_configuration('races').get(clsname, {})
     super_class.__init__(self, race_attributes.get('health_points', 0),
                          race_attributes.get('magic_points', 0),
                          race_attributes.get('move_speed', 0),
                          race_attributes.get('strength', 0),
                          race_attributes.get('intelligence', 0),
                          race_attributes.get('accuracy', 0),
                          race_attributes.get('armour', 0),
                          race_attributes.get('magic_resist', 0),
                          race_attributes.get('will', 0)
                          )
Пример #11
0
def create_dynamic_races():
    races_dynamic_classes = {}
    race_from_config = get_configuration(RACES_SECTION)
    for race in race_from_config:
        custom_race = type(race, (Race,), {
            # constructor
            "__init__": constructor,

            "name": race,
            # member functions
            "func_arg": display_method,
            "class_func": class_method,
            "get_name": get_name
        })
        races_dynamic_classes[race] = custom_race

    return races_dynamic_classes
Пример #12
0
 def __init__(self, clsname, superclasses, attributedict):
     if clsname == 'Job':
         return
     super_class = superclasses[0]
     jobs_attributes = get_configuration('jobs').get(clsname, {})
     super_class.__init__(
         self,
         jobs_attributes.get('health_points', 0),
         jobs_attributes.get('magic_points', 0),
         jobs_attributes.get('move_speed', 0),
         jobs_attributes.get('strength', 0),
         jobs_attributes.get('intelligence', 0),
         jobs_attributes.get('accuracy', 0),
         jobs_attributes.get('armour', 0),
         jobs_attributes.get('magic_resist', 0),
         jobs_attributes.get('will', 0),
         jobs_attributes.get('attack_type', 'melee'),
         jobs_attributes.get('damage_vector', 'strength'),
     )
Пример #13
0
def get_player_available_skills(player: IPlayer) -> List[ISkill]:
    """
    Skills can be unlocked/revealed for players depending their levels and jobs, this method compare the current
    attributes of a player, will all the skills, to check which ones this current player has eligibility to use.

    :param IPlayer player: The current player to discover new skills.

    :rtype: List[ISkill].
    """
    skill_dicts = get_configuration(SKILLS_SECTION)
    available_skills: List[ISkill] = []

    for key, value in skill_dicts.items():
        if player.job.get_name() == value.get(
                'job') and player.level >= value.get(
                    'level_requirement') and player.mana > value.get('cost'):
            available_skills.append(get_instantiated_skill({key: value}))

    return available_skills
Пример #14
0
def create_dynamic_jobs():
    jobs_dynamic_classes = {}
    job_from_config = get_configuration(JOBS_SECTION)
    for job in job_from_config:
        custom_job = type(
            job,
            (Job, ),
            {
                # constructor
                "__init__": constructor,
                "name": job,
                # member functions
                "func_arg": display_method,
                "class_func": class_method,
                "get_name": get_name
            })
        jobs_dynamic_classes[job] = custom_job

    return jobs_dynamic_classes
Пример #15
0
    def validate(self, document: Document):
        """
        This function is used for validating  the number of bots inserted, when creating a new game.

        :param Document document: The document to be validated.
        :rtype: None.
        """
        max_bot_number = get_configuration(GAME_SECTION).get('max_number_bots')
        if not document.text.isnumeric():
            raise ValidationError(
                message="Input should be a number",
                cursor_position=document.cursor_position,
            )
        else:
            if int(document.text) > max_bot_number or int(document.text) <= 0:
                raise ValidationError(
                    message=
                    "The number of boots needs to be minimum 1 and maximum {maximum}"
                    .format(maximum=max_bot_number),
                    cursor_position=document.cursor_position,
                )
Пример #16
0
def instantiate_side_effects(
        side_effects_strings: List[str]) -> List[ISideEffect]:
    """
    This class will receive a list of strings that represents the names of each side-effects, those names of
    side-effects will be queried from the configuration, and instantiated to be ready to use.

    :param List[str] side_effects_strings: List with the name os the effects.

    :rtype: List[ISideEffect].
    """
    side_effects_library_dict = get_configuration('side_effects')
    side_effects: List[SideEffect] = []

    for side_effect_string in side_effects_strings:
        side_effect_dict = side_effects_library_dict.get(side_effect_string)
        side_effect = SideEffect(name=side_effect_string,
                                 effect_type=side_effect_dict.get('type'),
                                 attribute=side_effect_dict.get('attribute'),
                                 base=side_effect_dict.get('base'),
                                 duration=side_effect_dict.get('duration'),
                                 occurrence=side_effect_dict.get('occurrence'))
        side_effects.append(side_effect)

    return side_effects
Пример #17
0
 def wrapper(func):
     section_result = get_configuration(section)
     setattr(func, section, section_result)
     return func
Пример #18
0
    def ask_attributes_to_improve(self) -> Union[str, bool, list, List]:
        level_up_increment_attributes = get_configuration(LEVEL_UP_INCREMENT)
        health_points = level_up_increment_attributes.get('health_points', 5)
        magic_points = level_up_increment_attributes.get('magic_points', 5)
        move_speed = level_up_increment_attributes.get('move_speed', 1)
        strength = level_up_increment_attributes.get('strength', 3)
        intelligence = level_up_increment_attributes.get('intelligence', 3)
        accuracy = level_up_increment_attributes.get('accuracy', 1)
        armour = level_up_increment_attributes.get('armour', 3)
        magic_resist = level_up_increment_attributes.get('magic_resist', 3)
        will = level_up_increment_attributes.get('will', 3)

        level_up_questions = [
            {
                "type":
                "list",
                "message":
                "Select an action:",
                "choices": [
                    {
                        "name":
                        emojis.encode(
                            "+{points} Health Points :green_heart:".format(
                                points=health_points)),
                        "value": {
                            "attribute": "health_points",
                            "value": health_points
                        }
                    },
                    {
                        "name":
                        emojis.encode(
                            "+{points} Magic Points :blue_heart:".format(
                                points=magic_points)),
                        "value": {
                            "attribute": "magic_points",
                            "value": magic_points
                        }
                    },
                    {
                        "name":
                        emojis.encode("+{points} Move Speed :runner:".format(
                            points=move_speed)),
                        "value": {
                            "attribute": "move_speed",
                            "value": move_speed
                        }
                    },
                    {
                        "name":
                        emojis.encode("+{points} Strength :punch:".format(
                            points=strength)),
                        "value": {
                            "attribute": "strength",
                            "value": strength
                        }
                    },
                    {
                        "name":
                        emojis.encode("+{points} Intelligence :books:".format(
                            points=intelligence)),
                        "value": {
                            "attribute": "intelligence",
                            "value": intelligence
                        }
                    },
                    {
                        "name":
                        emojis.encode("+{points} Accuracy :dart:".format(
                            points=accuracy)),
                        "value": {
                            "attribute": "accuracy",
                            "value": accuracy
                        }
                    },
                    {
                        "name":
                        emojis.encode(
                            "+{points} Armour :anger:".format(points=armour)),
                        "value": {
                            "attribute": "armour",
                            "value": armour
                        }
                    },
                    {
                        "name":
                        emojis.encode(
                            "+{points} Magic Resist :cyclone:".format(
                                points=magic_resist)),
                        "value": {
                            "attribute": "magic_resist",
                            "value": magic_resist
                        }
                    },
                    {
                        "name":
                        emojis.encode(
                            "+{points} Will :pray:".format(points=will)),
                        "value": {
                            "attribute": "will",
                            "value": will
                        }
                    },
                ],
                "default":
                None,
                "multiselect":
                True,
                "validate":
                lambda selected: len(selected) == 2,
                "invalid_message":
                "You need to select 2 attributes to improve!",
                "show_cursor":
                True,
                "max_height":
                "100"
            },
        ]

        result = prompt(questions=level_up_questions)
        return result[0]
Пример #19
0
    def attack(self) -> None:
        if self.possible_foe is None:
            self.current_play_style = IPlayingMode.DEFENSIVE
            return

            # This dictionary represents the possibilities of attack/skills that a bot can perform, where the keys
        # are the attack/skills and the values the possible damage that this one may inflict
        attack_possibilities_dict = {}
        attack_range = self.current_bot.get_ranged_attack_area()
        attack_range_possibilities = self.game.game_map.graph.get_available_nodes_in_range(
            self.current_bot.position,
            attack_range)
        attack_range_possibilities.append(self.current_bot.position)

        if (self.current_bot.job.attack_type == 'melee' and self.possible_foe.position == self.current_bot.position) \
                or (
                self.current_bot.job.attack_type == 'ranged'
                and self.possible_foe.position in attack_range_possibilities):
            attack_possibilities_dict['attack'] = self.current_bot.get_attribute_real_value(
                self.current_bot.job.damage_vector, self.current_bot.job.attack_type
            )
        for skill in self.current_bot.skills:
            if skill.cost < self.current_bot.mana and skill.kind == 'inflict' \
                    and self.game.game_map.graph.is_target_in_range(self.current_bot.position,
                                                                    skill.ranged,
                                                                    self.possible_foe.position):
                attack_possibilities_dict[skill] = self.current_bot.get_attribute_real_value(
                    skill.base_attribute
                ) + skill.base

        if len(attack_possibilities_dict) < 1:
            self.current_play_style = IPlayingMode.DEFENSIVE
            return
        sorted_attack_possibilities_tuple = sorted(attack_possibilities_dict.items(), key=lambda x: x[1], reverse=True)
        best_attack = next(iter(sorted_attack_possibilities_tuple))[0]
        dice_result = self.game.roll_the_dice()

        if best_attack == 'attack':
            self.communicator.informer.event('attack')
            self.communicator.informer.dice_result(self.current_bot.name, dice_result, 'attack', self.game.dice_sides)

            targeted_defense = 'armour' if self.current_bot.job.damage_vector == 'strength' else 'magic_resist'

            damage = 0
            if self.current_bot.job.damage_vector == 'intelligence':
                damage = (self.current_bot.get_attribute_real_value(self.current_bot.job.damage_vector,
                                                                    self.current_bot.job.attack_type) / 2) + (
                                 dice_result / self.game.dice_sides) * 5
            elif self.current_bot.job.damage_vector == 'strength' and self.current_bot.job.attack_type == 'ranged':
                damage = self.current_bot.get_attribute_real_value(self.current_bot.job.damage_vector,
                                                                   self.current_bot.job.attack_type) \
                         + self.current_bot.get_attribute_real_value(
                    'accuracy') + (
                                 dice_result / self.game.dice_sides) * 5
            else:
                damage = self.current_bot.get_attribute_real_value(self.current_bot.job.damage_vector,
                                                                   self.current_bot.job.attack_type) + (
                                 dice_result / self.game.dice_sides) * 5

            damage = math.ceil(damage - self.possible_foe.get_attribute_real_value(targeted_defense))
            if damage > 0:
                self.possible_foe.suffer_damage(damage)
                self.communicator.informer.suffer_damage(self.current_bot, self.possible_foe, damage)
                experience = get_configuration(EXPERIENCE_EARNED_ACTION).get('attack', 0)
                self.current_bot.earn_xp(experience)
                self.communicator.informer.player_earned_xp(player_name=self.current_bot.name, xp=experience)

                if not self.possible_foe.is_alive():
                    experience = get_configuration(EXPERIENCE_EARNED_ACTION).get('kill', 0)
                    self.current_bot.earn_xp(experience)
                    self.communicator.informer.player_earned_xp(player_name=self.current_bot.name, xp=experience)
            else:
                self.communicator.informer.missed(self.current_bot, self.possible_foe)
            return
        elif isinstance(best_attack, ISkill):
            self.prepare_execute_skill(best_attack)
        else:
            self.current_play_style = IPlayingMode.DEFENSIVE