Пример #1
0
    def shop(self):
        """
        Покупает в магазине вещи.
        """
        self.log(f'🛍 *{self.user.name}* идет в магазин…')

        logger.info('Requesting shops…')
        slots: List[Tuple[str, str]] = [
            (shop_id, slot.id) for shop_id in constants.SHOP_IDS
            for slot in self.api.get_shop(shop_id)
            if (not slot.is_bought) and (not slot.cost.star_money) and (
                slot.reward.keywords & self.settings.bot.shops)
        ]

        logger.info(f'Going to buy {len(slots)} slots.')
        for shop_id, slot_id in slots:
            logger.info(
                f'Buying slot #{slot_id} in shop «{shop_name(shop_id)}»…')
            try:
                reward = self.api.shop(shop_id=shop_id, slot_id=slot_id)
            except NotEnoughError as e:
                logger.warning(f'Not enough: {e}')
            except AlreadyError as e:
                logger.warning(f'Already: {e}')
            else:
                with self.logger:
                    self.logger.append(f'🛍 *{self.user.name}* купил:', '')
                    reward.log(self.logger)

        self.log(f'🛍 *{self.user.name}* сходил в магазин.')
Пример #2
0
    def farm_quests(self, quests: List[Quest] = None):
        """
        Собирает награды из заданий.
        """
        if quests is not None and not quests:
            logger.info('No quests to farm.')  # provided but empty
            return

        logger.info('Farming quests…')
        self.log(f'✅ *{self.user.name}* выполняет задачи…')
        if quests is None:
            quests = self.api.get_all_quests()
        for quest in quests:
            if not quest.is_reward_available:
                continue
            if self.settings.bot.no_experience and quest.reward.experience:
                logger.warning(
                    f'Ignoring {quest.reward.experience} experience reward for quest #{quest.id}.'
                )
                continue
            with self.logger:
                self.logger.append(f'✅ *{self.user.name}* получает за задачу:',
                                   '')
                self.api.farm_quest(quest.id).log(self.logger)
        self.log(f'✅ *{self.user.name}* выполнил задачи.')
Пример #3
0
 def send_daily_gift(self):
     """
     Отправляет сердечки друзьям.
     """
     self.log(f'❤️ *{self.user.name}* дарит сердечки друзьям…')
     if self.settings.bot.friend_ids:
         self.farm_quests(
             self.api.send_daily_gift(self.settings.bot.friend_ids))
     else:
         logger.warning('No friends specified.')
     self.log(f'❤️ *{self.user.name}* подарил сердечки друзьям.')
Пример #4
0
    def farm_zeppelin_gift(self):
        """
        Собирает ключ у валькирии и открывает артефактные сундуки.
        """
        self.log(f'🔑 *{self.user.name}* открывает артефактные сундуки…')

        self.api.farm_zeppelin_gift().log()
        for _ in range(constants.MAX_OPEN_ARTIFACT_CHESTS):
            try:
                rewards = self.api.open_artifact_chest()
            except NotEnoughError:
                logger.info('All keys are spent.')
                break
            with self.logger:
                self.logger.append(
                    f'🔑 *{self.user.name}* получил из артефактного сундука:',
                    '')
                log_rewards(rewards, self.logger)
        else:
            logger.warning('Maximum number of chests opened.')

        self.log(f'🔑 *{self.user.name}* открыл артефактные сундуки.')
Пример #5
0
    def hall_of_fame(self):
        """
        Турнир Стихий.
        """
        self.log(f'💨 *{self.user.name}* идет в Турнир Стихий…')

        weekday = now().weekday()

        if weekday == calendar.SATURDAY:
            logger.info('Farming reward today…')
            trophy = self.api.get_hall_of_fame().trophy
            if trophy:
                reward = self.api.farm_hall_of_fame_trophy_reward(trophy.week)
                with self.logger:
                    self.logger.append(
                        f'💨 *{self.user.name}* получил в Турнире Стихий:\n')
                    reward.log(self.logger)
            else:
                logger.warning('No trophy.')
        else:
            logger.info('Doing nothing today.')

        self.log(f'💨 *{self.user.name}* закончил Турнир Стихий.')
Пример #6
0
    def attack_any_arena(
        self,
        *,
        n_heroes: int,
        make_solver: Callable[[Model, List[Hero]], ArenaSolver],
        attack: Callable[[ArenaSolution], Tuple[ArenaResult, Quests]],
        finalise: Callable[[], Any],
    ):
        self.log(f'⚔️ *{self.user.name}* идет на арену…')

        # Load arena model.
        logger.info('Loading model…')
        try:
            model: Model = pickle.loads(b85decode(self.db['bot:model']))
        except KeyError:
            logger.warning('Model is not ready yet.')
            return
        logger.trace('Model: {}.', model)

        # Get all heroes.
        heroes = self.api.get_all_heroes()
        if len(heroes) < n_heroes:
            logger.warning('Not enough heroes: {} needed, you have {}.',
                           n_heroes, len(heroes))
            return

        # Refresh clan ID.
        self.user = self.api.get_user_info()

        # Pick an enemy and select attackers.
        solution = make_solver(model, heroes).solve()
        with self.logger:
            self.logger.append(f'⚔️ *{self.user.name}* атакует арену:', '')
            solution.log(self.logger)

        # Retry if win probability is too low.
        if solution.probability < constants.ARENA_MIN_PROBABILITY:
            logger.warning('Win probability is too low.')
            self.log(f'⚔️ *{self.user.name}* отменил атаку.')
            return now() + constants.ARENA_RETRY_INTERVAL

        # Attack!
        result, quests = attack(solution)

        # Collect results.
        with self.logger:
            self.logger.append(f'⚔️ *{self.user.name}* закончил арену:\n')
            result.log(self.logger)
        finalise()
        self.farm_quests(quests)
Пример #7
0
    def skip_tower(self):
        """
        Зачистка башни.
        """
        self.log(f'🗼 *{self.user.name}* проходит башню…')

        tower = self.api.get_tower_info()

        # Yeah, it's a bit complicated…
        while tower.floor_number <= 50:
            logger.info(f'Floor #{tower.floor_number}: {tower.floor_type}.')
            self.log(
                f'🗼 *{self.user.name}* на {tower.floor_number}-м этаже башни…')

            if tower.floor_type == TowerFloorType.BATTLE:
                # If we have the topmost level, then we can skip the tower entirely.
                # But we need to go chest by chest. So go to the next chest.
                if tower.may_full_skip:
                    tower = self.api.next_tower_chest()
                # Maybe we can skip the floor, because of the yesterday progress.
                elif tower.floor_number <= tower.may_skip_floor:
                    tower, reward = self.api.skip_tower_floor()
                    reward.log()
                # Otherwise, we're not able to continue.
                else:
                    break
            elif tower.floor_type == TowerFloorType.CHEST:
                # The simplest one. Just open a random chest.
                reward, _ = self.api.open_tower_chest(choice([0, 1, 2]))
                with self.logger:
                    self.logger.append(
                        f'🗼 *{self.user.name}* получил на {tower.floor_number}-м этаже башни:\n'
                    )
                    reward.log(self.logger)
                # If it was the topmost floor, we have to stop.
                if tower.floor_number == 50:
                    logger.success('Finished. It was the topmost floor.')
                    break
                # If we can skip the tower entirely, then go to the next chest.
                if tower.may_full_skip:
                    tower = self.api.next_tower_chest()
                # Otherwise, just proceed to the next floor.
                else:
                    tower = self.api.next_tower_floor()
            elif tower.floor_type == TowerFloorType.BUFF:
                # Buffs go from the cheapest to the most expensive.
                # So try to buy the most expensive ones first.
                for buff in reversed(tower.floor):
                    buff_id = int(buff['id'])
                    # Some buffs require to choose a hero. We ignore these.
                    if buff_id not in constants.TOWER_IGNORED_BUFF_IDS:
                        try:
                            self.api.buy_tower_buff(buff_id)
                        except NotEnoughError:
                            logger.info(
                                f'Not enough resources for buff #{buff_id}.')
                        except AlreadyError:
                            logger.info(f'Already bought buff #{buff_id}.')
                        except NotFoundError as e:
                            logger.warning(
                                f'Not found for buff #{buff_id}: {e}.')
                    else:
                        logger.debug(f'Skip buff #{buff_id}.')
                # Then normally proceed to the next floor.
                tower = self.api.next_tower_floor()

        self.log(
            f'🗼 *{self.user.name}* закончил башню на *{tower.floor_number}-м* этаже.'
        )
Пример #8
0
    def prepare(self):
        self.user = self.api.get_user_info()

        # noinspection DuplicatedCode
        self.scheduler.add_tasks([
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=4, minute=48, tzinfo=self.user.tz),
                time(hour=9, minute=36, tzinfo=self.user.tz),
                time(hour=14, minute=24, tzinfo=self.user.tz),
                time(hour=19, minute=12, tzinfo=self.user.tz),
            ],
                 execute=self.attack_normal_arena,
                 offset=self.settings.bot.arena.schedule_offset),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=4, minute=48, tzinfo=self.user.tz),
                time(hour=9, minute=36, tzinfo=self.user.tz),
                time(hour=14, minute=24, tzinfo=self.user.tz),
                time(hour=19, minute=12, tzinfo=self.user.tz),
            ],
                 execute=self.attack_grand_arena,
                 offset=self.settings.bot.arena.schedule_offset),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=6, minute=0, tzinfo=self.user.tz),
                time(hour=12, minute=0, tzinfo=self.user.tz),
                time(hour=18, minute=0, tzinfo=self.user.tz),
            ],
                 execute=self.farm_mail),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=6, minute=0, tzinfo=self.user.tz),
                time(hour=12, minute=0, tzinfo=self.user.tz),
                time(hour=18, minute=0, tzinfo=self.user.tz),
            ],
                 execute=self.check_freebie),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=8, minute=0, tzinfo=self.user.tz),
                time(hour=16, minute=0, tzinfo=self.user.tz),
            ],
                 execute=self.farm_expeditions),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=12, minute=0, tzinfo=self.user.tz),
            ],
                 execute=self.get_arena_replays),
            Task(at=[
                time(hour=0, minute=0, tzinfo=self.user.tz),
                time(hour=4, minute=0, tzinfo=self.user.tz),
                time(hour=8, minute=0, tzinfo=self.user.tz),
                time(hour=12, minute=0, tzinfo=self.user.tz),
                time(hour=16, minute=0, tzinfo=self.user.tz),
                time(hour=20, minute=0, tzinfo=self.user.tz),
            ],
                 execute=self.raid_missions),
            Task(at=[
                time(hour=9, minute=30, tzinfo=self.user.tz),
                time(hour=14, minute=30, tzinfo=self.user.tz),
                time(hour=21, minute=30, tzinfo=self.user.tz),
            ],
                 execute=self.farm_quests),
            Task(at=[time(hour=6, minute=0, tzinfo=self.user.tz)],
                 execute=self.skip_tower),
            Task(at=[time(hour=7, minute=0, tzinfo=self.user.tz)],
                 execute=self.register),
            Task(at=[time(hour=7, minute=10, tzinfo=self.user.tz)],
                 execute=self.farm_daily_bonus),
            Task(at=[time(hour=7, minute=20, tzinfo=timezone.utc)],
                 execute=self.raid_bosses),
            Task(at=[time(hour=7, minute=30, tzinfo=self.user.tz)],
                 execute=self.buy_chest),
            Task(at=[time(hour=7, minute=40, tzinfo=timezone.utc)],
                 execute=self.hall_of_fame),
            Task(at=[time(hour=7, minute=50, tzinfo=self.user.tz)],
                 execute=self.level_up_titan_hero_gift),
            Task(at=[time(hour=8, minute=0, tzinfo=self.user.tz)],
                 execute=self.send_daily_gift),
            Task(at=[time(hour=8, minute=15, tzinfo=self.user.tz)],
                 execute=self.open_titan_artifact_chest),
            Task(at=[time(hour=8, minute=30, tzinfo=self.user.tz)],
                 execute=self.farm_offers),
            Task(at=[time(hour=8, minute=45, tzinfo=self.user.tz)],
                 execute=self.farm_zeppelin_gift),
        ])
        if self.settings.bot.shops:
            self.scheduler.add_task(
                Task(
                    at=[
                        # First shopping time should be later than usual event start time (2:00 UTC).
                        # Every 8 hours afterwards.
                        time(hour=2, minute=15, tzinfo=timezone.utc),
                        time(hour=10, minute=15, tzinfo=timezone.utc),
                        time(hour=18, minute=15, tzinfo=timezone.utc),
                    ],
                    execute=self.shop))
        if self.settings.bot.is_trainer:
            self.scheduler.add_task(
                Task(at=[time(hour=22, minute=0)],
                     execute=self.train_arena_model))
        if self.settings.bot.arena.randomize_grand_defenders:
            self.scheduler.add_task(
                Task(at=[time(hour=8, minute=30)],
                     execute=self.randomize_grand_defenders))
        if self.settings.bot.enchant_rune:
            self.scheduler.add_task(
                Task(at=[time(hour=8, minute=0)], execute=self.enchant_rune))
        if self.settings.bot.debug:
            logger.warning('Running in debug mode.')
            self.scheduler.add_task(
                Task(at=[(datetime.now() + timedelta(seconds=15)).time()],
                     execute=self.quack))