Ejemplo n.º 1
0
    async def adminquest(self, ctx, action: str, coach_name: str, quest: str):
        """Manually marks the quest as achieved or not. Does not award the prize
      USAGE:
      !adminquest <action> <coach> <quest>
        <action>: on to mark as complete, off the clear flag
        <coach>: coach discord name or its part, must be unique
        <quest>: *collect3legends* or *buildyourownlegend*
      """
        self.is_admin_channel(ctx.channel)
        if action not in ["on", "off"]:
            raise ValueError("Invalid action")

        if quest not in ["collect3legends", "buildyourownlegend"]:
            raise ValueError("Invalid quest")

        coach = await coach_unique(coach_name, ctx)
        if coach is None:
            return

        if action == "on":
            value = True
        if action == "off":
            value = False
        CoachService.set_achievement(coach, ["quests", quest], value)
        db.session.commit()
        await ctx.send(
            f"Quest updated for {coach.short_name()}: {quest} - {action}")
        return
Ejemplo n.º 2
0
def activate_coach(coach_id, **kwargs):
    """Activates coach"""
    coach = kwargs['coach']
    if coach is None:
        abort(404)
    if not owning_coach(coach):
        raise InvalidUsage("Unauthorized access!!!!", status_code=403)
    try:
        card_ids = request.get_json()['card_ids']
        CoachService.activate_coach(coach=coach, card_ids=card_ids)
    except (ValueError, TypeError, TransactionError) as exc:
        raise InvalidUsage(str(exc), status_code=403)
    result = coach_schema.dump(coach)
    return jsonify(result.data)
Ejemplo n.º 3
0
 async def newcoach(self, ctx):
     """Creates new coach account"""
     coach = CoachService.discord_user_to_coach(ctx.author)
     if coach:
         await ctx.send(f"**{ctx.author.mention}** account exists already")
     elif Coach.get_by_discord_id(ctx.author.id, deleted=True):
         await ctx.send(
             f"**{ctx.author.mention}** account is inactive, use the web page to activate it"
         )
     else:
         coach = CoachService.new_coach(ctx.author, ctx.author.id)
         msg = f"**{ctx.author.mention}** account created\n" \
             + f"**Bank:** {coach.account.amount} coins\n" \
             + f"**Rules**: <{RULES_LINK}>"
         await ctx.send(msg)
Ejemplo n.º 4
0
    async def reaction(self, ctx, *card_name):
        """User reaction card
       USAGE:
      !reaction <card_name>
        <card_name>: name of the reaction card
      """
        coach = CoachService.discord_user_to_coach(ctx.author)
        room = ctx.channel.name

        if coach is None:
            await ctx.send(
                f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first."
            )
            return

        get_coach_deck_for_room_or_raise(room, coach)

        card_name = " ".join(card_name).strip()
        card = CardService.get_card_from_coach(coach, card_name)
        if card and card.template.card_type == "Reaction":
            msg = [
                f"**{coach.short_name()}** plays **{card.get('name')}**: {card.get('description')}"
            ]
            notification = f"Card **{card.get('name')}** removed from your collection"
            db.session.delete(card)
            db.session.expire(coach, ['cards'])
            reason = f"Reaction card {card.template.name} used in {room} tournament"
            tran = Transaction(description=reason, price=0)
            coach.make_transaction(tran)
            await self.send_message(ctx.channel, msg)
            await self.bank_notification(ctx, notification, coach)
        else:
            raise ValueError(f"Reaction card {card_name} was not found!!!")
        return
Ejemplo n.º 5
0
 async def CoMWithFriends(self, ctx):
     """**Randomise**. Open an Inducement Skill Pack and randomly apply all Training cards across your opponents' teams."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 6
0
 async def SoM3000(self, ctx):
     """Each team in the tournament receives a random stadium enhancement. Other stadium enhancement cards are ignored and may not be replaced."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 7
0
 async def CoMLegendBuilder(self, ctx):
     """Roll a dice to select a random rookie player from your roster. Open a Temporary Legend Pack for your chosen mixed team and apply all possible
        skills and injuries from the Legend to the chosen rookie player."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 8
0
 async def CoM2000(self, ctx):
     """**Randomise**. In the Deck Inducement phase, open an additional Inducement Skill Pack.
        Each Training Card in the pack must be applied to a random player on your team. This card
        is removed from your collection after use."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 9
0
 async def CoM9000(self, ctx):
     """**Randomise**. Choose one Special Play card that is yet to be resolved. The chosen card must
        now be played as if it had the **Randomise** key word. In the Deck Inducement phase, open three
        additional Inducement Coaching Packs. Each Training Card in the pack must be applied to a random
        player on your team. This card is removed from your collection after use."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 10
0
 async def CelebrityMasterChef(self, ctx):
     """All other teams in the tournament roll a D6. On a result of 1-3, they permanently lose a team re-roll
        for the entire tournament! Roll a D6. On a result of 4-6, you gain one team re-roll for the entire
        tournament! If multiple Celebrity Master Chefs are played, each team can only ever lose a maximum
        of one team re-roll across all instances of the card."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 11
0
 async def CommentatorsCurse(self, ctx):
     """The most powerful force in the known universe… joins your team! Add a Human Ogre or Ogre Ogre called
        Biff Bobbord to your team and grant him +ST, +AG, Break Tackle, Piling On, Juggernaut and Block. 
        All teams at the tournament (including your own) then roll a D6. On a result of 1-2, they must roll a Level 1
        Curse for their team. If all teams succeed their 3+ roll, you must instead roll a Level 2 curse
        for your own team."""
     me = CoachService.discord_user_to_coach(ctx.author)
     data = getattr(special_play,
                    inspect.currentframe().f_code.co_name)(ctx.channel.name,
                                                           me)
     await self.send_embed(data, ctx)
Ejemplo n.º 12
0
def new_coach():
    """creates new coach"""
    try:
        user = current_user()
        name = user['username'] + "#" + user['discriminator']
        coach = CoachService.new_coach(name, user['id'])
    except TransactionError as exc:
        raise InvalidUsage(str(exc), status_code=403)

    result = coach_schema.dump(coach)
    return jsonify(result.data)
Ejemplo n.º 13
0
    async def focus(self, ctx):
        """Reviews your deck and tells what the deck focus is"""
        me = CoachService.discord_user_to_coach(ctx.author)
        tourn = TournamentService.get_tournament_using_room(ctx.channel.name)
        deck = [ts.deck for ts in tourn.tournament_signups if ts.coach == me]
        if not deck:
            raise Exception(
                f"#{me.short_name()} is not signed into the tournament. Nice try!"
            )
        focus = DeckService.focus(deck[0])

        await ctx.send(f"Deck focus is {', '.join(focus)}")
Ejemplo n.º 14
0
    async def list(self, ctx, all=None):
        """List details about coach's collection"""
        with db.session.no_autoflush:
            coach = CoachService.discord_user_to_coach(ctx.author)
            show_starter = True if all == "all" else False

            if coach is None:
                await ctx.send(
                    f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first."
                )
                return

            all_cards = coach.active_cards()
            sp_msg = " (with Starter Pack)"
            if not show_starter:
                all_cards = [card for card in all_cards if not card.is_starter]
                sp_msg = ""

            msg = [
                f"**Bank:** {coach.account.amount} coins\n",
                f"**Tournaments:**", *[
                    f'{t.tournament_id}. {t.name}, status: {t.status}, expected start: {t.expected_start_date}'
                    for t in coach.tournaments
                ], f"\n**Collection**{sp_msg}:", "-" * 65 + "",
                PackHelper.format_pack(all_cards,
                                       show_hidden=True), "-" * 65 + "\n"
            ]

            if coach.duster:
                msg.append(
                    f"**Dusting** - {coach.duster.type} - {coach.duster.status}"
                )

            admin_in = Tournament.query.filter(
                Tournament.admin == coach.short_name(),
                Tournament.status.in_(("OPEN", "RUNNING"))).all()

            if admin_in:
                msg.append(f"**Tournament Admin:**")
                msg.extend([
                    f'{t.tournament_id}. {t.name}, status: {t.status}, channel: {t.discord_channel}'
                    for t in admin_in
                ])

            free_packs = coach.get_freepacks()
            if free_packs:
                msg.append(f"**Free Packs:**")
                msg.append((', ').join(free_packs))

            await self.send_message(ctx.author, msg)
            await ctx.send("Info sent to PM")
Ejemplo n.º 15
0
 async def resign(self, ctx, tournament_id: int):
     """Resigns coach from tournament
   USAGE:
   !resign <tournament_id>
     <tournament_id>: id of tournament from !complist
   """
     coach = CoachService.discord_user_to_coach(ctx.author)
     if coach is None:
         await ctx.send(
             f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first."
         )
         return
     await resign(tournament_id, coach, ctx)
     return
Ejemplo n.º 16
0
    async def done(self, ctx):
        """Confirms Special Play, Inducement and Blood Bowl phase"""
        coach = CoachService.discord_user_to_coach(ctx.author)
        room = ctx.channel.name

        if coach is None:
            await ctx.send(
                f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first."
            )
            return

        if TournamentService.get_phase(room) in [
                Tourn.DB_PHASE, Tourn.LOCKED_PHASE
        ]:
            msg = "This command has no effect in this phase. Go and commit your deck!"
        elif TournamentService.confirm_phase(coach, room):
            msg = f"Phase confirmed for {coach.short_name()}"
        else:
            msg = "No deck found!"
        await ctx.send(msg)
Ejemplo n.º 17
0
def get_deck(deck_id):
    if not current_user():
        raise InvalidUsage('You are not authenticated', status_code=401)

    deck = Deck.query.get(deck_id)
    if deck is None:
        abort(404)

    coach = Coach.query.options(raiseload(Coach.cards),raiseload(Coach.packs)).filter_by(disc_id=current_user()['id']).one_or_none()

    if not deck.commited and not (coach.id==deck.tournament_signup.coach.id or coach.short_name()=="TomasT"):
        raise InvalidUsage("Deck not commited, only owner can display it!", status_code=403)

    # is committed    
    if deck.tournament_signup.tournament.phase=="deck_building" and not (coach.id==deck.tournament_signup.coach.id or coach.short_name()==deck.tournament_signup.tournament.admin or coach.short_name()=="TomasT"):
        raise InvalidUsage("Only owner and admin can see display commited deck in the Deck Building phase!", status_code=403)    

    starter_cards = CoachService.get_starter_cards(deck.tournament_signup.coach)
    result = deck_schema.dump(deck)
    result2 = cards_schema.dump(starter_cards)
    return jsonify({'deck':result.data, 'starter_cards':result2.data})
Ejemplo n.º 18
0
    async def genpacktemp(self, ctx, pack_type:str, subtype:str=None):
        """Generates special play or inducement packs. These packs are for one time use and are not assigned to coaches permanent collection"""
        if not check_gentemp_command(pack_type, subtype):
          raise discord.ext.commands.CommandError("Invalid usage!")

        coach = CoachService.discord_user_to_coach(ctx.author)
        if coach is None:
          await ctx.send(f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first.")
          return

        if pack_type in ["player", "positional", "legendary"]:
            pack = PackService.generate(pack_type, team=subtype)
        elif pack_type in ["training", "special", "skill", "coaching", "brawl","hc"]:
            pack = PackService.generate(pack_type)
        elif pack_type == "booster":
            pack_type = "booster_budget" if not subtype else f"booster_{subtype}"
            pack = PackService.generate(pack_type)

        title = f"**Temporary {PackService.description(pack)}**"
        description = "**Note**: This is one time pack only!!!"
        pieces = PackHelper.format_pack_to_pieces(pack.cards)
        efs = []
        efs.append({
            'name': "Cards:",
            'value': pieces['cards'],
            'inline': False,
        })
        for desc in pieces['descriptions']:
          efs.append({
            'name': desc['name'],
            'value': desc['description'],
            'inline': False,
          })
        embed = {
          'embed_title': title,
          'embed_desc': description,
          'thumbnail_url': 'https://cdn2.rebbl.net/images/cards/dice_small.png',
          'embed_fields': efs,
        }
        await self.send_embed(embed, ctx)
Ejemplo n.º 19
0
    async def ransom(self, ctx):
        """Pay ransom for the kidnapped player"""
        coach = CoachService.discord_user_to_coach(ctx.author)
        if coach is None:
            await ctx.send(
                f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first."
            )
            return
        reason = 'Ransom'
        amount = -5
        tran = Transaction(description=reason, price=-1 * amount)
        coach.make_transaction(tran)

        msg = [
            f"Bank for {coach.name} updated to **{coach.account.amount}** coins:\n",
            f"Note: {reason}\n", f"Change: {amount} coins"
        ]
        await self.send_message(ctx.channel, msg)
        await self.bank_notification(
            ctx,
            f"Your bank has been updated by **{amount}** coins - {reason}",
            coach)
        return
Ejemplo n.º 20
0
    async def genpack(self, ctx, pack_type:str, subtype:str=None):
        """Generates packs"""
        if not check_gen_command(pack_type, subtype):
          raise discord.ext.commands.CommandError("Invalid usage!")

        coach = CoachService.discord_user_to_coach(ctx.author)
        if coach is None:
          await ctx.send(f"Coach {ctx.author.mention} does not exist. Use !newcoach to create coach first.")
          return

        pp_count = db.session.query(Pck.id).filter_by(coach_id=coach.id, pack_type="player").count()

        if pack_type == "player":
          first = True if pp_count == 0 else False
          pack = PackService.generate(pack_type, team=subtype, first=first, coach=coach)
        elif pack_type in ["training","special", "hc"]:
          pack = PackService.generate(pack_type, coach=coach)
        elif pack_type == "booster":
          pack_type = "booster_budget" if not subtype else f"booster_{subtype}"
          pack = PackService.generate(pack_type, coach=coach)

        duster = coach.duster
        duster_on = False
        duster_txt = ""
        if pp_count > 0 and duster and duster.status == "COMMITTED":
          if (pack_type == "player" and duster.type == "Tryouts" or
                pack_type == "training" and duster.type == "Drills" or
                pack_type == "special" and duster.type == "Drills"):
            duster_on = True
            duster_txt = f" ({duster.type})"
            db.session.delete(duster)

        free_packs = coach.get_freepacks()

        if pack_type in ["player"] and not duster_on:
          if pack_type in free_packs:
            pack.price = 0
            coach.remove_from_freepacks(pack_type)
          else:
            raise TransactionError(
              "You need to commit Tryouts or earn the pack through" +
              " Achievements to be able to generate this pack!"
            )

        if pack_type in ["training", "special"] and not duster_on:
          raise TransactionError(
            "You need to commit Drills to be able to generate this pack!"
          )

        if pack_type in ["booster_budget", "booster_premium"]:
          if pack_type in free_packs:
            pack.price = 0
            coach.remove_from_freepacks(pack_type)

        tran = Transaction(pack=pack, price=pack.price, description=PackService.description(pack))
        coach.make_transaction(tran)

        title = f"**{PackService.description(pack)}** for **{ctx.message.author.name}** - **{pack.price}** coins{duster_txt}"
        description = f"**Bank:** {coach.account.amount} coins"
        pieces = PackHelper.format_pack_to_pieces(pack.cards)

        await self.auto_cards(pack, ctx)
        CoachService.check_collect_three_legends_quest(coach)

        efs = []
        efs.append({
            'name': "Cards:",
            'value': pieces['cards'],
            'inline': False,
        })
        for desc in pieces['descriptions']:
          efs.append({
            'name': desc['name'],
            'value': desc['description'],
            'inline': False,
          })
        embed = {
          'embed_title': title,
          'embed_desc': description,
          'thumbnail_url': 'https://cdn2.rebbl.net/images/cards/dice_small.png',
          'embed_fields': efs,
        }
        await self.send_embed(embed, ctx)
Ejemplo n.º 21
0
    async def comp(self, ctx, *args):
        """Manages in-game competitions for tournaments. Needs to be run in the tournament discord channel
      USAGE:
      !comp list
        list all competitions for tournament
      !comp create ladder
        creates ladder comp for tournament if it does not exists
      !comp create 1on1 <competition_name>
        creates 1 on 1 comp with <competition_name> for tournament if it does not exists
      !comp create knockout <team_number> <name>
        creates knockout comp with <name> for <team_number> teams
      !comp ticket <competition_name>
        sends ticket to the <competition_name> to the coach issuing the command in the tournament room
      !comp start <competition_name>
        starts comp with <competition_name> for tournament
      """
        room = ctx.channel.name
        args_len = len(args)
        if args_len == 0 \
            or (args_len > 0 and args[0] not in ["list","create", "ticket", "start"]) \
            or (args[0] == "create" and \
                (args_len < 2 or args[1] not in ["ladder", "1on1","knockout"] or (args[1] == "1on1" and args_len == 2) \
                    or (args[1] == "knockout" and args_len < 4 and not represents_int(args[2])))) \
            or (args[0] in ["ticket", "start"] and args_len < 2):
            raise ValueError("Incorrect arguments")

        tourn = TournamentService.get_tournament_using_room(room)

        if tourn.status != "RUNNING":
            await ctx.send("Tournament is not running!")
            return

        if args[0] == "create":
            if args[1] == "ladder":
                comp_name = tourn.ladder_room_name()
                comp = CompetitionService.create_imperium_ladder(comp_name)
            if args[1] == "1on1":
                comp_name = " ".join(args[2:])
                comp_name = comp_name[:25] if len(
                    comp_name) > 25 else comp_name
                comp = CompetitionService.create_imperium_rr(comp_name)
            if args[1] == "knockout":
                comp_name = " ".join(args[3:])
                comp_name = comp_name[:25] if len(
                    comp_name) > 25 else comp_name
                comp = CompetitionService.create_imperium_knockout(
                    comp_name, int(args[2]))
            tourn.competitions.append(comp)
            db.session.commit()
            await ctx.send(
                f"Competition **{comp.name}** created in **{comp.league_name}**"
            )
            return

        if args[0] == "list":
            msg = []
            msg.append('{:25s} | {:25} | {:25}'.format("League", "Name",
                                                       "Type"))
            msg.append(78 * "-")
            for comp in tourn.competitions:
                msg.append('{:25s} | {:25} | {:25}'.format(
                    comp.league_name, comp.name, comp.type_str()))

            await self.send_message(ctx.channel, msg, block=True)
            # await ctx.send("\n".join(msg))
            return

        if args[0] == "ticket":
            comp_name = " ".join(args[1:])
            # get coach
            coach = CoachService.discord_user_to_coach(ctx.author)
            result = CompetitionService.ticket_competition(
                comp_name, coach, tourn)
            team_name = result['ResponseCreateCompetitionTicket'][
                'TicketInfos']['RowTeam']['Name']
            await ctx.send(
                f"Ticket sent to **{team_name}** for competition **{comp_name}**"
            )
            return

        if args[0] == "start":
            comp_name = " ".join(args[1:])
            comp = Competition.query.filter_by(name=comp_name).one_or_none()
            if not comp:
                raise CompetitionError(
                    f"Competition **{comp_name}** does not exist")
            result = CompetitionService.start_competition(comp)
            await ctx.send(f"Started competition **{comp_name}**")
            return
Ejemplo n.º 22
0
def main(argv):
    """main()"""
    try:
        opts, args = getopt.getopt(argv, "rs:")
    except getopt.GetoptError:
        print('recalculate_old_stats.py -r -s <season>')
        sys.exit(2)
    refresh = False
    for opt, arg in opts:
        if opt == '-r':
            refresh = True
            print("Recalculating statistics from the scratch")
        if opt == '-s':
            season = arg
            print(f"Using data for season {season}")

    logger = logging.getLogger('collector')
    logger.propagate = False
    logger.setLevel(logging.INFO)
    handler = RotatingFileHandler(os.path.join(ROOT, 'logs/collector.log'),
                                  maxBytes=10000000,
                                  backupCount=5,
                                  encoding='utf-8',
                                  mode='a')
    handler.setFormatter(
        logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
    logger.addHandler(handler)

    st = StatsHandler(season)
    stats = st.get_stats(refresh)
    matches_folder = st.matches_folder()

    st.set_folders()

    # stats rebuilding
    matchfiles = [
        f for f in os.listdir(matches_folder)
        if os.path.isfile(os.path.join(matches_folder, f))
    ]

    if not 'matchfiles' in stats:
        stats['matchfiles'] = []

    for file_name in matchfiles:
        file = open(os.path.join(matches_folder, file_name), "r")
        data = json.loads(file.read())
        file.close()

        match = bb2.Match(data)

        st.create_folder(st.competition_folder(match.competition_id()))
        st.write_file(
            os.path.join(st.competition_folder(match.competition_id()),
                         match.uuid()), data)

        if data['uuid'] in stats['matchfiles']:
            continue
        stats['matchfiles'].append(data['uuid'])

        logger.info("Processing stat calculation of match %s ", data['uuid'])

        # ignore concedes
        if bb2.is_concede(data):
            logger.info("Match %s is concede", data['uuid'])
            continue

        # initialize coaches
        coach1 = data['match']['coaches'][0]
        if not coach1['coachname'] in stats['coaches']:
            stats['coaches'][coach1['coachname']] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0,
                'max': {}
            }
            stats['coaches'][coach1['coachname']]['name'] = coach1['coachname']
            stats['coaches'][coach1['coachname']]['teams'] = {}
        coach2 = data['match']['coaches'][1]
        if not coach2['coachname'] in stats['coaches']:
            stats['coaches'][coach2['coachname']] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0,
                'max': {}
            }
            stats['coaches'][coach2['coachname']]['name'] = coach2['coachname']
            stats['coaches'][coach2['coachname']]['teams'] = {}

        # initialize teams
        team1 = data['match']['teams'][0]
        idraces1 = str(team1['idraces'])
        if not idraces1 in stats['teams']:
            stats['teams'][idraces1] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
            stats['teams'][idraces1]['idraces'] = idraces1
        team2 = data['match']['teams'][1]
        idraces2 = str(team2['idraces'])
        if not idraces2 in stats['teams']:
            stats['teams'][idraces2] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
            stats['teams'][idraces2]['idraces'] = idraces2

        #alias coaches and teams
        coach1_stats = stats['coaches'][coach1['coachname']]
        coach2_stats = stats['coaches'][coach2['coachname']]
        team1_stats = stats['teams'][idraces1]
        team2_stats = stats['teams'][idraces2]

        # initialize the team under coach
        if idraces1 not in coach1_stats['teams']:
            coach1_stats['teams'][idraces1] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
        if idraces2 not in coach2_stats['teams']:
            coach2_stats['teams'][idraces2] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }

        # coach team alias
        coach1_team_stats = coach1_stats['teams'][idraces1]
        coach2_team_stats = coach2_stats['teams'][idraces2]

        coach1_stats['matches'] += 1
        team1_stats['matches'] += 1
        coach1_team_stats['matches'] += 1
        coach2_stats['matches'] += 1
        team2_stats['matches'] += 1
        coach2_team_stats['matches'] += 1

        for stat in [
                "inflictedtouchdowns",
                "inflictedtackles",
                "inflictedcasualties",
                'inflictedinjuries',
                'inflictedko',
                'inflicteddead',
                'inflictedmetersrunning',
                'inflictedpasses',
                'inflictedcatches',
                'inflictedinterceptions',
                'sustainedexpulsions',
                'sustainedcasualties',
                'sustainedko',
                'sustainedinjuries',
                'sustaineddead',
                'inflictedmeterspassing',
        ]:
            if not stat in coach1_stats:
                coach1_stats[stat] = 0
            coach1_stats[stat] += team1[stat]
            if not stat in coach2_stats:
                coach2_stats[stat] = 0
            coach2_stats[stat] += team2[stat]

            if not stat in team1_stats:
                team1_stats[stat] = 0
            team1_stats[stat] += team1[stat]
            if not stat in team2_stats:
                team2_stats[stat] = 0
            team2_stats[stat] += team2[stat]

            if not stat in coach1_team_stats:
                coach1_team_stats[stat] = 0
            coach1_team_stats[stat] += team1[stat]
            if not stat in coach2_team_stats:
                coach2_team_stats[stat] = 0
            coach2_team_stats[stat] += team2[stat]

        #sustd workaround
        if not 'sustainedtouchdowns' in coach1_stats:
            coach1_stats['sustainedtouchdowns'] = 0
        coach1_stats['sustainedtouchdowns'] += team2['inflictedtouchdowns']
        if not 'sustainedtouchdowns' in coach2_stats:
            coach2_stats['sustainedtouchdowns'] = 0
        coach2_stats['sustainedtouchdowns'] += team1['inflictedtouchdowns']

        if not 'sustainedtouchdowns' in team1_stats:
            team1_stats['sustainedtouchdowns'] = 0
        team1_stats['sustainedtouchdowns'] += team2['inflictedtouchdowns']
        if not 'sustainedtouchdowns' in team2_stats:
            team2_stats['sustainedtouchdowns'] = 0
        team2_stats['sustainedtouchdowns'] += team1['inflictedtouchdowns']

        if not 'sustainedtouchdowns' in coach1_team_stats:
            coach1_team_stats['sustainedtouchdowns'] = 0
        coach1_team_stats['sustainedtouchdowns'] += team2[
            'inflictedtouchdowns']
        if not 'sustainedtouchdowns' in coach2_team_stats:
            coach2_team_stats['sustainedtouchdowns'] = 0
        coach2_team_stats['sustainedtouchdowns'] += team1[
            'inflictedtouchdowns']

        # inflictedpushouts fix
        if not 'inflictedpushouts' in coach1_stats:
            coach1_stats['inflictedpushouts'] = 0
        coach1_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])
        if not 'inflictedpushouts' in coach2_stats:
            coach2_stats['inflictedpushouts'] = 0
        coach2_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        if not 'inflictedpushouts' in team1_stats:
            team1_stats['inflictedpushouts'] = 0
        team1_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])

        if not 'inflictedpushouts' in team2_stats:
            team2_stats['inflictedpushouts'] = 0
        team2_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        if not 'inflictedpushouts' in coach1_team_stats:
            coach1_team_stats['inflictedpushouts'] = 0
        coach1_team_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])

        if not 'inflictedpushouts' in coach2_team_stats:
            coach2_team_stats['inflictedpushouts'] = 0
        coach2_team_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        # max tracking
        for stat in [
                "inflictedtouchdowns", "inflictedtackles",
                "inflictedcasualties", 'inflictedinjuries',
                'inflictedinterceptions'
        ]:
            if not stat in coach1_stats['max']:
                coach1_stats['max'][stat] = 0
            if team1[stat] > coach1_stats['max'][stat]:
                coach1_stats['max'][stat] = team1[stat]

            if not stat in coach2_stats['max']:
                coach2_stats['max'][stat] = 0
            if team2[stat] > coach2_stats['max'][stat]:
                coach2_stats['max'][stat] = team2[stat]

        if not 'max_cas_win' in coach1_stats['max']:
            coach1_stats['max']['max_cas_win'] = 0
        if not 'max_cas_win' in coach2_stats['max']:
            coach2_stats['max']['max_cas_win'] = 0
        if not 'max_tvdiff_win' in coach1_stats['max']:
            coach1_stats['max']['max_tvdiff_win'] = 0
        if not 'max_tvdiff_win' in coach2_stats['max']:
            coach2_stats['max']['max_tvdiff_win'] = 0
        # wins/drawslosses
        if team1['inflictedtouchdowns'] > team2['inflictedtouchdowns']:
            coach1_stats['wins'] += 1
            coach1_stats['points'] += 3
            coach2_stats['losses'] += 1

            team1_stats['wins'] += 1
            team1_stats['points'] += 3
            team2_stats['losses'] += 1

            coach1_team_stats['wins'] += 1
            coach1_team_stats['points'] += 3
            coach2_team_stats['losses'] += 1

            # cas achievement check
            if team1['sustainedcasualties'] > coach1_stats['max'][
                    'max_cas_win']:
                coach1_stats['max']['max_cas_win'] = team1[
                    'sustainedcasualties']

            # down TV achievement check
            tv_diff = team2['value'] - team1['value']
            if tv_diff > coach1_stats['max']['max_tvdiff_win']:
                coach1_stats['max']['max_tvdiff_win'] = tv_diff

        elif team1['inflictedtouchdowns'] < team2['inflictedtouchdowns']:
            coach2_stats['wins'] += 1
            coach2_stats['points'] += 3
            coach1_stats['losses'] += 1

            team2_stats['wins'] += 1
            team2_stats['points'] += 3
            team1_stats['losses'] += 1

            coach2_team_stats['wins'] += 1
            coach2_team_stats['points'] += 3
            coach1_team_stats['losses'] += 1

            # cas achievement check
            if team2['sustainedcasualties'] > coach2_stats['max'][
                    'max_cas_win']:
                coach2_stats['max']['max_cas_win'] = team2[
                    'sustainedcasualties']

            # down TV achievement check
            tv_diff = team1['value'] - team2['value']
            if tv_diff > coach2_stats['max']['max_tvdiff_win']:
                coach2_stats['max']['max_tvdiff_win'] = tv_diff
        else:
            coach1_stats['draws'] += 1
            coach1_stats['points'] += 1
            coach2_stats['draws'] += 1
            coach2_stats['points'] += 1

            team1_stats['draws'] += 1
            team1_stats['points'] += 1
            team2_stats['draws'] += 1
            team2_stats['points'] += 1

            coach1_team_stats['draws'] += 1
            coach1_team_stats['points'] += 1
            coach2_team_stats['draws'] += 1
            coach2_team_stats['points'] += 1

        tcoach = CoachService.link_bb2_coach(coach1['coachname'],
                                             team1['teamname'])
        if tcoach:
            msg = f"{coach1['coachname']} account linked to {tcoach.short_name()}"
            Notificator("achievement").notify(msg)
            logger.info(msg)
        tcoach = CoachService.link_bb2_coach(coach2['coachname'],
                                             team2['teamname'])
        if tcoach:
            msg = f"{coach2['coachname']} account linked to {tcoach.short_name()}"
            Notificator("achievement").notify(msg)
            logger.info(msg)
        db.session.commit()
        logger.info("Stats calculation of match %s completed", data['uuid'])

    try:
        all_coaches = Coach.query.all()
        stats['coaches_extra'] = leaderboard_coach_schema.dump(
            all_coaches).data
        stats['coaches'].pop('', None)
        st.save_stats(stats)
    except Exception as exp:
        logger.error(exp)
        raise exp
    logger.info("Stats recalculated")
Ejemplo n.º 23
0
    async def admincard(self,
                        ctx,
                        action: str,
                        coach_name: str = None,
                        *cards):
        """Adds or removes cards from coach, or updates card database
      USAGE 1:
      Add or remove cards from coach
      !admincard <action> <coach> <card>;...;<card>
        <action>: add or remove
        <coach>: coach discord name or its part, must be unique
        <card>: Exact card name as is in the All Cards list, if mutliple cards are specified separate them by **;**
      USAGE 2:
      Updates card database from the master sheet
      !admincard update
      """
        if action not in ["add", "remove", "update"]:
            raise ValueError("Incorrect action")

        if not cards and not coach_name and action in ["add", "remove"]:
            raise ValueError("Missing arguments")

        if action == "update":
            await ctx.send(f"Updating...")
            CardService.update()
            await ctx.send(f"Cards updated!!!")
            return
        else:
            coach = await coach_unique(coach_name, ctx)
            if coach is None:
                return
            card_names = [card.strip() for card in " ".join(cards).split(";")]

        if action == "add":
            pack = PackService.admin_pack(0, card_names, coach)
            # situation when some of the cards could not be found
            if len(card_names) != len(pack.cards):
                msg = []
                msg.append(f"Not all cards were found, check the names!!!\n")
                for card in card_names:
                    if card in [
                            card.get('name').lower() for card in pack.cards
                    ]:
                        found = True
                    else:
                        found = False
                    found_msg = "**not found**" if not found else "found"
                    msg.append(f"{card}: {found_msg}")
                await self.send_message(ctx.channel, msg)
                return

            reason = f"{action.capitalize()} {';'.join([str(card.get('name')) for card in pack.cards])} - by " + str(
                ctx.author.name)
            tran = Transaction(pack=pack, description=reason, price=0)
            coach.make_transaction(tran)

            msg = []
            msg.append(
                f"**{PackService.description(pack)}** for @{coach.name} - **{pack.price}** coins:\n"
            )
            # message sent to admin so display the hidden cards
            msg.append(
                f"{PackHelper.format_pack(pack.cards, show_hidden=True)}")
            msg.append(f"**Bank:** {coach.account.amount} coins")
            await self.send_message(ctx.channel, msg)
            # message sent to discord so hide the names
            await self.bank_notification(
                ctx,
                f"Card(s) **{', '.join([card.get('name', show_hidden=False) for card in pack.cards])}** added to your collection by {str(ctx.author.name)}",
                coach)
            await self.auto_cards(pack, ctx)
            CoachService.check_collect_three_legends_quest(coach)
            return

        if action == "remove":
            removed_cards = []
            unknown_cards = []

            for name in card_names:
                card = CardService.get_card_from_coach(coach, name)
                if card:
                    removed_cards.append(card)
                    db.session.delete(card)
                    db.session.expire(coach, ['cards'])
                else:
                    unknown_cards.append(name)
            reason = f"{action.capitalize()} {';'.join([card.get('name') for card in removed_cards])} - by " + str(
                ctx.author.name)
            tran = Transaction(description=reason, price=0)
            coach.make_transaction(tran)

            if removed_cards:
                msg = []
                msg.append(f"Cards removed from @{coach.name} collection:\n")
                msg.append(
                    f"{PackHelper.format_pack(removed_cards, show_hidden=True)}"
                )
                await self.send_message(ctx.channel, msg)
                await self.bank_notification(
                    ctx,
                    f"Card(s) **{', '.join([card.get('name') for card in removed_cards])}** removed from your collection by {str(ctx.author.name)}",
                    coach)

            if unknown_cards:
                msg = ["**Warning** - these cards have been skipped:"]
                for name in unknown_cards:
                    msg.append(f"{name}: **not found**")
                await self.send_message(ctx.channel, msg)
            return
Ejemplo n.º 24
0
 def populate_db(self):
     with self.app.app_context():
         c = CoachService.new_coach("TomasT", "1")
         db.session.add(c)
         db.session.commit()
Ejemplo n.º 25
0
def main(argv):
    """main()"""
    try:
        opts, args = getopt.getopt(argv, "r")
    except getopt.GetoptError:
        print('update_stats.py -r')
        sys.exit(2)
    refresh = False
    for opt, arg in opts:
        if opt == '-r':
            refresh = True
            print("Recalculating statistics from the scratch")

    logger = logging.getLogger('collector')
    logger.propagate = False
    logger.setLevel(logging.INFO)
    handler = RotatingFileHandler(os.path.join(ROOT, 'logs/collector.log'),
                                  maxBytes=10000000,
                                  backupCount=5,
                                  encoding='utf-8',
                                  mode='a')
    handler.setFormatter(
        logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
    logger.addHandler(handler)
    st = StatsHandler()
    matches_folder = st.matches_folder()

    start_date = DT.date.today() - DT.timedelta(days=1)

    agent = bb2.Agent(app.config['BB2_API_KEY'])

    stats = st.get_stats(refresh)

    logger.info("Getting matches since %s", start_date)

    try:
        data = agent.matches(start=start_date,
                             league=','.join(app.config['LEAGUES']))
    except Exception as exc:
        logger.error(exc)
        raise exc

    logger.info("Matches colleted")

    st.set_folders()

    for match in data['matches']:
        filename = os.path.join(matches_folder, f"{match['uuid']}.json")
        if os.path.isfile(filename):
            logger.info("File %s exists", filename)
            continue
        logger.info("Collecting match %s", match['uuid'])
        try:
            detailed = agent.match(id=match['uuid'])
            file = open(filename, "a")
            file.write(json.dumps(detailed))
            file.close()
        except Exception as exc:
            logger.error(exc)
            raise exc
        logger.info("Match %s saved", match['uuid'])

    # stats rebuilding
    matchfiles = [
        f for f in os.listdir(matches_folder)
        if os.path.isfile(os.path.join(matches_folder, f))
    ]

    if not 'matchfiles' in stats:
        stats['matchfiles'] = []

    for file_name in matchfiles:
        file = open(os.path.join(matches_folder, file_name), "r")
        data = json.loads(file.read())
        file.close()

        match = bb2.Match(data)

        st.create_folder(st.competition_folder(match.competition_id()))
        st.write_file(
            os.path.join(st.competition_folder(match.competition_id()),
                         match.uuid()), data)

        if data['uuid'] in stats['matchfiles']:
            continue
        stats['matchfiles'].append(data['uuid'])

        logger.info("Processing stat calculation of match %s ", data['uuid'])

        # ignore concedes
        if bb2.match.is_concede(data):
            logger.info("Match %s is concede", data['uuid'])
            continue

        # initialize coaches
        coach1 = data['match']['coaches'][0]
        if not coach1['coachname'] in stats['coaches']:
            stats['coaches'][coach1['coachname']] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0,
                'max': {}
            }
            stats['coaches'][coach1['coachname']]['name'] = coach1['coachname']
            stats['coaches'][coach1['coachname']]['teams'] = {}
        coach2 = data['match']['coaches'][1]
        if not coach2['coachname'] in stats['coaches']:
            stats['coaches'][coach2['coachname']] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0,
                'max': {}
            }
            stats['coaches'][coach2['coachname']]['name'] = coach2['coachname']
            stats['coaches'][coach2['coachname']]['teams'] = {}

        # initialize teams
        team1 = data['match']['teams'][0]
        idraces1 = str(team1['idraces'])
        if not idraces1 in stats['teams']:
            stats['teams'][idraces1] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
            stats['teams'][idraces1]['idraces'] = idraces1
        team2 = data['match']['teams'][1]
        idraces2 = str(team2['idraces'])
        if not idraces2 in stats['teams']:
            stats['teams'][idraces2] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
            stats['teams'][idraces2]['idraces'] = idraces2

        #alias coaches and teams
        coach1_stats = stats['coaches'][coach1['coachname']]
        coach2_stats = stats['coaches'][coach2['coachname']]
        team1_stats = stats['teams'][idraces1]
        team2_stats = stats['teams'][idraces2]

        # initialize the team under coach
        if idraces1 not in coach1_stats['teams']:
            coach1_stats['teams'][idraces1] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }
        if idraces2 not in coach2_stats['teams']:
            coach2_stats['teams'][idraces2] = {
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'matches': 0,
                'points': 0
            }

        # coach team alias
        coach1_team_stats = coach1_stats['teams'][idraces1]
        coach2_team_stats = coach2_stats['teams'][idraces2]

        coach1_stats['matches'] += 1
        team1_stats['matches'] += 1
        coach1_team_stats['matches'] += 1
        coach2_stats['matches'] += 1
        team2_stats['matches'] += 1
        coach2_team_stats['matches'] += 1

        for stat in [
                "inflictedtouchdowns",
                "inflictedtackles",
                "inflictedcasualties",
                'inflictedinjuries',
                'inflictedko',
                'inflicteddead',
                'inflictedmetersrunning',
                'inflictedpasses',
                'inflictedcatches',
                'inflictedinterceptions',
                'sustainedexpulsions',
                'sustainedcasualties',
                'sustainedko',
                'sustainedinjuries',
                'sustaineddead',
                'inflictedmeterspassing',
        ]:
            if not stat in coach1_stats:
                coach1_stats[stat] = 0
            coach1_stats[stat] += team1[stat]
            if not stat in coach2_stats:
                coach2_stats[stat] = 0
            coach2_stats[stat] += team2[stat]

            if not stat in team1_stats:
                team1_stats[stat] = 0
            team1_stats[stat] += team1[stat]
            if not stat in team2_stats:
                team2_stats[stat] = 0
            team2_stats[stat] += team2[stat]

            if not stat in coach1_team_stats:
                coach1_team_stats[stat] = 0
            coach1_team_stats[stat] += team1[stat]
            if not stat in coach2_team_stats:
                coach2_team_stats[stat] = 0
            coach2_team_stats[stat] += team2[stat]

        #sustd workaround
        if not 'sustainedtouchdowns' in coach1_stats:
            coach1_stats['sustainedtouchdowns'] = 0
        coach1_stats['sustainedtouchdowns'] += team2['inflictedtouchdowns']
        if not 'sustainedtouchdowns' in coach2_stats:
            coach2_stats['sustainedtouchdowns'] = 0
        coach2_stats['sustainedtouchdowns'] += team1['inflictedtouchdowns']

        if not 'sustainedtouchdowns' in team1_stats:
            team1_stats['sustainedtouchdowns'] = 0
        team1_stats['sustainedtouchdowns'] += team2['inflictedtouchdowns']
        if not 'sustainedtouchdowns' in team2_stats:
            team2_stats['sustainedtouchdowns'] = 0
        team2_stats['sustainedtouchdowns'] += team1['inflictedtouchdowns']

        if not 'sustainedtouchdowns' in coach1_team_stats:
            coach1_team_stats['sustainedtouchdowns'] = 0
        coach1_team_stats['sustainedtouchdowns'] += team2[
            'inflictedtouchdowns']
        if not 'sustainedtouchdowns' in coach2_team_stats:
            coach2_team_stats['sustainedtouchdowns'] = 0
        coach2_team_stats['sustainedtouchdowns'] += team1[
            'inflictedtouchdowns']

        # inflictedpushouts fix
        if not 'inflictedpushouts' in coach1_stats:
            coach1_stats['inflictedpushouts'] = 0
        coach1_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])
        if not 'inflictedpushouts' in coach2_stats:
            coach2_stats['inflictedpushouts'] = 0
        coach2_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        if not 'inflictedpushouts' in team1_stats:
            team1_stats['inflictedpushouts'] = 0
        team1_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])

        if not 'inflictedpushouts' in team2_stats:
            team2_stats['inflictedpushouts'] = 0
        team2_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        if not 'inflictedpushouts' in coach1_team_stats:
            coach1_team_stats['inflictedpushouts'] = 0
        coach1_team_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team1['roster']
        ])

        if not 'inflictedpushouts' in coach2_team_stats:
            coach2_team_stats['inflictedpushouts'] = 0
        coach2_team_stats['inflictedpushouts'] += sum([
            player['stats']['inflictedpushouts'] for player in team2['roster']
        ])

        # max tracking
        for stat in [
                "inflictedtouchdowns", "inflictedtackles",
                "inflictedcasualties", 'inflictedinjuries',
                'inflictedinterceptions'
        ]:
            if not stat in coach1_stats['max']:
                coach1_stats['max'][stat] = 0
            if team1[stat] > coach1_stats['max'][stat]:
                coach1_stats['max'][stat] = team1[stat]

            if not stat in coach2_stats['max']:
                coach2_stats['max'][stat] = 0
            if team2[stat] > coach2_stats['max'][stat]:
                coach2_stats['max'][stat] = team2[stat]

        if not 'max_cas_win' in coach1_stats['max']:
            coach1_stats['max']['max_cas_win'] = 0
        if not 'max_cas_win' in coach2_stats['max']:
            coach2_stats['max']['max_cas_win'] = 0
        if not 'max_tvdiff_win' in coach1_stats['max']:
            coach1_stats['max']['max_tvdiff_win'] = 0
        if not 'max_tvdiff_win' in coach2_stats['max']:
            coach2_stats['max']['max_tvdiff_win'] = 0
        # wins/drawslosses
        if team1['inflictedtouchdowns'] > team2['inflictedtouchdowns']:
            coach1_stats['wins'] += 1
            coach1_stats['points'] += 3
            coach2_stats['losses'] += 1

            team1_stats['wins'] += 1
            team1_stats['points'] += 3
            team2_stats['losses'] += 1

            coach1_team_stats['wins'] += 1
            coach1_team_stats['points'] += 3
            coach2_team_stats['losses'] += 1

            # cas achievement check
            if team1['sustainedcasualties'] > coach1_stats['max'][
                    'max_cas_win']:
                coach1_stats['max']['max_cas_win'] = team1[
                    'sustainedcasualties']

            # down TV achievement check
            tv_diff = team2['value'] - team1['value']
            if tv_diff > coach1_stats['max']['max_tvdiff_win']:
                coach1_stats['max']['max_tvdiff_win'] = tv_diff

        elif team1['inflictedtouchdowns'] < team2['inflictedtouchdowns']:
            coach2_stats['wins'] += 1
            coach2_stats['points'] += 3
            coach1_stats['losses'] += 1

            team2_stats['wins'] += 1
            team2_stats['points'] += 3
            team1_stats['losses'] += 1

            coach2_team_stats['wins'] += 1
            coach2_team_stats['points'] += 3
            coach1_team_stats['losses'] += 1

            # cas achievement check
            if team2['sustainedcasualties'] > coach2_stats['max'][
                    'max_cas_win']:
                coach2_stats['max']['max_cas_win'] = team2[
                    'sustainedcasualties']

            # down TV achievement check
            tv_diff = team1['value'] - team2['value']
            if tv_diff > coach2_stats['max']['max_tvdiff_win']:
                coach2_stats['max']['max_tvdiff_win'] = tv_diff
        else:
            coach1_stats['draws'] += 1
            coach1_stats['points'] += 1
            coach2_stats['draws'] += 1
            coach2_stats['points'] += 1

            team1_stats['draws'] += 1
            team1_stats['points'] += 1
            team2_stats['draws'] += 1
            team2_stats['points'] += 1

            coach1_team_stats['draws'] += 1
            coach1_team_stats['points'] += 1
            coach2_team_stats['draws'] += 1
            coach2_team_stats['points'] += 1

        tcoach = CoachService.link_bb2_coach(coach1['coachname'],
                                             team1['teamname'])
        if tcoach:
            msg = f"{coach1['coachname']} account linked to {tcoach.short_name()}"
            Notificator("achievement").notify(msg)
            logger.info(msg)
        tcoach = CoachService.link_bb2_coach(coach2['coachname'],
                                             team2['teamname'])
        if tcoach:
            msg = f"{coach2['coachname']} account linked to {tcoach.short_name()}"
            Notificator("achievement").notify(msg)
            logger.info(msg)
        db.session.commit()
        logger.info("Stats calculation of match %s completed", data['uuid'])

    try:
        all_coaches = Coach.query.all()
        stats['coaches_extra'] = leaderboard_coach_schema.dump(
            all_coaches).data
        stats['coaches'].pop('', None)
        st.save_stats(stats)
    except Exception as exp:
        logger.error(exp)
        raise exp
    logger.info("Stats recalculated")

    logger.info("Achievement processing")
    # update achievements
    for coach in Coach.query.all():
        if not coach.bb2_name:
            continue
        coach_stats = stats['coaches'].get(coach.bb2_name, None)
        if not coach_stats:
            continue
        coach.achievements['match']['winwithall']['best'] = 0
        # team achievements
        for team_id, data in coach_stats['teams'].items():
            team_id = str(team_id)
            # win for all achievement
            if data['wins'] > 0:
                coach.achievements['match']['winwithall']['best'] += 1

            for key, ach in coach.achievements['team'][team_id][
                    'played'].items():
                ach['best'] = data['matches']
            for key, ach in coach.achievements['team'][team_id]['wins'].items(
            ):
                ach['best'] = data['wins']
            for key, ach in coach.achievements['team'][team_id][
                    'touchdowns'].items():
                ach['best'] = data['inflictedtouchdowns']
            for key, ach in coach.achievements['team'][team_id][
                    'casualties'].items():
                ach['best'] = data['inflictedcasualties']
            for key, ach in coach.achievements['team'][team_id]['kills'].items(
            ):
                ach['best'] = data['inflicteddead']
            for key, ach in coach.achievements['team'][team_id][
                    'passes'].items():
                ach['best'] = data['inflictedpasses']

        # match achievements
        coach.achievements['match']['passingtotal1']['best'] = coach_stats[
            'inflictedmeterspassing']
        coach.achievements['match']['passingtotal2']['best'] = coach_stats[
            'inflictedmeterspassing']

        coach.achievements['match']['runningtotal1']['best'] = coach_stats[
            'inflictedmetersrunning']
        coach.achievements['match']['runningtotal2']['best'] = coach_stats[
            'inflictedmetersrunning']

        coach.achievements['match']['surfstotal1']['best'] = coach_stats[
            'inflictedpushouts']
        coach.achievements['match']['surfstotal2']['best'] = coach_stats[
            'inflictedpushouts']

        coach.achievements['match']['blocks1game1']['best'] = coach_stats[
            'max']['inflictedtackles']
        coach.achievements['match']['blocks1game2']['best'] = coach_stats[
            'max']['inflictedtackles']

        coach.achievements['match']['breaks1game1']['best'] = coach_stats[
            'max']['inflictedinjuries']
        coach.achievements['match']['breaks1game2']['best'] = coach_stats[
            'max']['inflictedinjuries']

        coach.achievements['match']['cas1game1']['best'] = coach_stats['max'][
            'inflictedcasualties']
        coach.achievements['match']['cas1game2']['best'] = coach_stats['max'][
            'inflictedcasualties']

        coach.achievements['match']['score1game1']['best'] = coach_stats[
            'max']['inflictedtouchdowns']
        coach.achievements['match']['score1game2']['best'] = coach_stats[
            'max']['inflictedtouchdowns']

        coach.achievements['match']['int1game1']['best'] = coach_stats['max'][
            'inflictedinterceptions']

        coach.achievements['match']['sufferandwin1']['best'] = coach_stats[
            'max']['max_cas_win']
        coach.achievements['match']['sufferandwin2']['best'] = coach_stats[
            'max']['max_cas_win']

        coach.achievements['match']['win500down']['best'] = coach_stats['max'][
            'max_tvdiff_win']

        flag_modified(coach, "achievements")
        db.session.commit()

        # update achievements
        coach_mention = f'<@{coach.disc_id}>'
        for key, achievement in coach.achievements['match'].items():
            if achievement['target'] <= achievement[
                    'best'] and not achievement['completed']:
                achievement_bank_text = f"{achievement['award_text']} awarded - {achievement['desc']}"
                Notificator("achievement").notify(
                    f"{coach.short_name()}: {achievement['desc']} - completed")
                call, arg = achievement['award'].split(",")
                res, error = getattr(coach, call)(arg, achievement['desc'])
                if res:
                    logger.info("%s: %s awarded", coach_mention,
                                {achievement['desc']})
                    Notificator("bank").notify(
                        f"{coach_mention}: {achievement_bank_text}")
                    coach.achievements['match'][key]['completed'] = True
                    flag_modified(coach, "achievements")
                else:
                    logger.error(error)
                    Notificator("bank").notify(
                        f"{coach_mention}: {achievement['award_text']} " +
                        f"could not be awarded - {error}")
        for key1, stat in coach.achievements['team'].items():
            for key2, item in stat.items():
                for key3, achievement in item.items():
                    if (achievement['target'] <= achievement['best']
                            and not achievement['completed']):
                        achievement_bank_text = f"{achievement['award_text']} awarded - {achievement['desc']}"
                        Notificator("achievement").notify(
                            f"{coach.short_name()}: {achievement['desc']} - completed"
                        )
                        call, arg = achievement['award'].split(",")
                        res, error = getattr(coach, call)(arg,
                                                          achievement['desc'])
                        if res:
                            logger.info("%s: %s awarded", coach_mention,
                                        {achievement['desc']})
                            coach.achievements['team'][key1][key2][key3][
                                'completed'] = True
                            flag_modified(coach, "achievements")
                            Notificator("bank").notify(
                                f"{coach_mention}: {achievement_bank_text}")
                        else:
                            logger.error(error)
                            Notificator("bank").notify(
                                f"{coach_mention}: {achievement['award_text']} could "
                                + f"not be awarded - {error}")
        db.session.commit()
    logger.info("Achievement processed")