def show_worldtop(bot, update, args): battle_id = None if args: try: battle_id = int(args[0]) if battle_id < 0: battle_id = count_battle_id() + battle_id except ValueError: pass worldtop = load_worldtop(battle_id=battle_id) if worldtop is None and battle_id is None: battle_id = count_battle_id() for i in range(6): worldtop = load_worldtop(battle_id - i) if worldtop is not None: break response = "Worldtop: {}\n".format("битва {}\n({}):".format( battle_id, count_battle_time(battle_id).strftime("%d/%m/%y %H:%M:%S") ) if battle_id is not None else "") i = 1 for k, v in list(worldtop.items()): response += "# {} {}: <code>{:>5}</code> 🏆 очков\n".format(i, k, v) i += 1 bot.send_message(chat_id=update.message.chat_id, text=response, parse_mode='HTML')
def battle_equip(bot, update): mes = update.message if mes.from_user.id != SUPER_ADMIN_ID: return battle_id = re.search("\\d+", mes.text) if battle_id is None: battle_id = count_battle_id(mes) else: battle_id = int(battle_id.group(0)) full = 'full' in mes.text request = "select player_id, equip from reports where battle_id = %s and equip is not null " \ "order by equip ->> 'status'" cursor.execute(request, (battle_id, )) rows = cursor.fetchall() response = "Дроп с битвы {} - {} :\n".format( battle_id, count_battle_time(battle_id).strftime("%d/%m/%y %H:%M:%S")) for row in rows: name, found_from = row[1].get("name"), row[1].get("from") player = Player.get_player(row[0]) response += "{}<b>{}</b> {}\n".format( "{} ".format((player.castle + player.nickname) if full else ""), name, "(От {})".format(found_from) if found_from is not None else "") bot.send_message(chat_id=mes.chat_id, text=response, parse_mode='HTML')
def get_reports_count(self): if count_battle_id(None) != self.__reports_counted_battle_id or \ not (self.__total_reports_count >= 0 and self.__current_reports_count >= 0 and self.__previous_reports_count >= 0): self.count_reports() return [ self.__current_reports_count, self.__previous_reports_count, self.__total_reports_count ]
def save_worldtop(worldtop: dict, battle_id: int = None): try: if battle_id is None: battle_id = count_battle_id() request = "insert into worldtop(battle_id, " args = [battle_id] for k, v in list(worldtop.items()): request += "{}, ".format(emodji_to_castle_names.get(k)) args.append(v) request = request[:-2] + ')' + 'values(%s, %s, %s, %s, %s, %s, %s, %s)' cursor.execute(request, args) except Exception: logging.error(traceback.format_exc())
def load_worldtop(battle_id: int = None) -> dict: """ Загружает /worldtop после битвы с battle_id :return: { str: int } """ if battle_id is None: battle_id = count_battle_id() request = "select ferma, amber, oplot, rassvet, tortuga, night, skala from worldtop where battle_id = %s" cursor.execute(request, (battle_id, )) row = cursor.fetchone() if not row: return {} worldtop = {k: v for k, v in zip(castles, row)} sort_worldtop(worldtop) return worldtop
def parse_worldtop_strings_results(worldtop_strings): worldtop = load_worldtop(battle_id=count_battle_id() - 1) for string in worldtop_strings: parse = re.search("(.).* \\+(\\d+) 🏆 очков", string) if parse is None: continue castle = parse.group(1) count = int(parse.group(2)) score = worldtop.get(castle, 0) score += count worldtop.update({castle: score}) sort_worldtop(worldtop) logging.info("Worldtop updated: {}: {}".format(castle, count)) save_worldtop(worldtop) return worldtop
def count_reports(self): self.__current_reports_count, self.__previous_reports_count, self.__total_reports_count = 0, 0, 0 request = "select battle_id from reports where player_id = %s and exp != 0" cursor.execute(request, (self.id,)) row = cursor.fetchone() self.__reports_counted_battle_id = count_battle_id(None) current_week = count_week_by_battle_id(self.__reports_counted_battle_id) while row is not None: week = count_week_by_battle_id(row[0]) if week == current_week: self.__current_reports_count += 1 elif week == current_week - 1: self.__previous_reports_count += 1 self.__total_reports_count += 1 row = cursor.fetchone()
def count_battle_stats(self, battle_id: int = None): if battle_id is None: battle_id = count_battle_id() - 1 cursor = conn.cursor() request = "select r.attack, r.defense, r.exp, r.gold, r.stock " \ "from reports r join players p on r.player_id = p.id where p.guild = %s and r.battle_id = %s" cursor.execute(request, (self.id, battle_id)) row = cursor.fetchone() total_attack, total_defense, total_exp, total_gold, total_stock = 0, 0, 0, 0, 0 while row: attack, defense, exp, gold, stock = row total_attack += attack total_defense += defense total_exp += exp total_gold += gold total_stock += stock row = cursor.fetchone() return total_attack, total_defense, total_exp, total_gold, total_stock
def save_worldtop(worldtop: dict, battle_id: int = None): cursor = conn.cursor() try: if battle_id is None: battle_id = count_battle_id() request = "insert into worldtop(battle_id, " args = [battle_id] for k, v in list(worldtop.items()): request += "{}, ".format(emodji_to_castle_names.get(k)) args.append(v) request = request[:-2] + ')' + 'values(%s, %s, %s, %s, %s, %s, %s, %s)' cursor.execute(request, args) except psycopg2.IntegrityError: request = "update worldtop set " for k, v in list(worldtop.items()): request += "{} = {}, ".format(emodji_to_castle_names.get(k), v) request = request[:-2] + " where battle_id = {}".format(battle_id) cursor.execute(request) except Exception: logging.error(traceback.format_exc()) cursor.close()
def remember_exp(bot, job): cursor = conn.cursor() request = "select id, exp, exp_info from players" cursor.execute(request) rows = cursor.fetchall() battle_id = count_battle_id(None) for row in rows: player_id, exp, exp_info = row player = Player.get_player(player_id) if exp_info is None: exp_info = {} exp_info.update({str(battle_id): exp}) exp_info = { k: v for k, v in sorted(list(exp_info.items()), key=lambda x: int(x[0])) } player.exp_info = exp_info player.update() # request = "update players set exp_info = %s where id = %s" # cursor.execute(request, (json.dumps(exp_info, ensure_ascii=False), player_id)) plan_remember_exp()
def parse_stats(): data = castles_stats_queue.get() while data is not None: debug = data.get("debug", False) data = data.get("data") # logging.error("Got data in parse: {}".format(data)) if 'Результаты сражений:' in data: # Результаты битвы замков if not debug: response_all = "Игроки, попавшие в топ:\n" for guild_id in Guild.guild_ids: response = "" guild = Guild.get_guild(guild_id=guild_id) tag = guild.tag for castle_results_string in data.split("\n\n"): if tag in castle_results_string: try: attacked_castle = re.search( '[🍁☘🖤🐢🦇🌹🍆]', castle_results_string).group(0) except TypeError: attacked_castle = "???" nicknames_list = re.findall( ".\\[{}\\][^🍁☘🖤🐢🦇🌹🍆🎖\n]+".format(tag), castle_results_string) print(nicknames_list) for nickname in nicknames_list: if response == "": response = "Игроки, попавшие в топ:\n" response += "{}{} <b>{}</b>\n".format( "🛡️" if nickname[0] == attacked_castle else "⚔️", attacked_castle, nickname[:-1]) response_all += "{}{} <b>{}</b>\n".format( "🛡️" if nickname[0] == attacked_castle else "⚔️", attacked_castle, nickname[:-1]) if response != "": if guild.chat_id is None: continue dispatcher.bot.send_message(chat_id=guild.chat_id, text=response, parse_mode='HTML') if response_all != "Игроки, попавшие в топ:\n": dispatcher.bot.send_message(chat_id=CENTRAL_SQUARE_CHAT_ID, text=response_all, parse_mode='HTML') worldtop_strings = data.split("\n\n")[-1].splitlines() worldtop = load_worldtop(battle_id=count_battle_id() - 1) old_worldtop = copy.deepcopy(worldtop) for string in worldtop_strings: parse = re.search("(.).* \\+(\\d+) 🏆 очков", string) if parse is None: continue castle = parse.group(1) count = int(parse.group(2)) score = worldtop.get(castle) score += count worldtop.update({castle: score}) sort_worldtop(worldtop) logging.info("Worldtop updated: {}: {}".format(castle, count)) save_worldtop(worldtop) if not debug: send_worldtop_update(old_worldtop, worldtop) logging.info("Worldtop at the end: {}".format(worldtop)) elif data.startswith("🤝Headquarters news:") or data.startswith( "🗺State of map:"): # Итоги штабов альянсов logging.info("Got alliance news") parse_alliance_battle_results(data, debug) else: # Сообщение о пиратстве response_by_tags = {} data = data.replace("Attackers:", " 🗡Атакующие:") data = data.replace("Defenders:", " 🛡Обороняющиеся:") guild_list = re.split("[⚔🛡] ..?Гильдия", data) for guild_str in guild_list: new_str = guild_str new_str = "{}".format('⚔️' if 'атакована' in new_str else '🛡') + new_str tags = re.findall("[🍁☘🖤🐢🦇🌹🍆](\\w+)", guild_str) tags = list(set(tags)) for tag in tags: new_str = new_str.replace(tag, "<b>{}</b>".format(tag)) for tag in tags: lst = response_by_tags.get(tag) if lst is None: lst = "Итоги гильдейских битв с вашим участием:\n\n" response_by_tags.update({tag: lst}) lst += new_str + "\n" response_by_tags.update({tag: lst}) # dispatcher.bot.send_message(chat_id=SUPER_ADMIN_ID, text=guild_str, parse_mode='HTML') import json # logging.error("Guild list for parse_stats: {}".format(json.dumps(guild_list, indent=4, ensure_ascii=False))) logging.error("Response by tags: {}".format( json.dumps(response_by_tags, indent=4, ensure_ascii=False))) print(guild_list) print(json.dumps(response_by_tags, indent=4, ensure_ascii=False)) for tag, string in list(response_by_tags.items()): guild = Guild.get_guild(guild_tag=tag) if guild is None: continue dispatcher.bot.send_message(chat_id=guild.chat_id, text=string, parse_mode='HTML') data = castles_stats_queue.get()
def get_top_text(guild, battles_for_count, max_players=None, curr_cursor=None) -> [str]: if max_players is None: max_players = 10000 if curr_cursor is None: curr_cursor = cursor total_battles = count_battles_in_this_week() players = [] for player_id in guild.members: player = Player.get_player(player_id, notify_on_error=False) if player is None: continue request = "select exp, gold, stock from reports where player_id = %s and battle_id >= %s" curr_cursor.execute(request, (player_id, count_battle_id(message=None) - battles_for_count + 1)) # За последние 3 битвы row = curr_cursor.fetchone() exp, gold, stock = 0, 0, 0 while row is not None: exp += row[0] gold += row[1] stock += row[2] row = curr_cursor.fetchone() reports = player.get_reports_count()[0] players.append([ player, exp, gold, stock, "{}/{} ({}%)".format(reports, total_battles, reports * 100 // total_battles) ]) ret = [] response = "📈Топ <b>{}</b> за {} по битвам:\n".format( guild.tag, "день" if battles_for_count == 3 else "неделю") tops = [ "🔥По опыту:", "💰По золоту:", "📦По стоку:", "⚔️Участие в битвах на этой неделе:" ] for i, top in enumerate(tops): response += "\n<b>{}</b>\n".format(top) players.sort( key=lambda x: x[i + 1] if isinstance(x[i + 1], int) else int(x[i + 1].partition("/")[0]), reverse=True) for j, elem in enumerate(players): if (j < max_players or j == len(players) - 1) or (i == (len(tops) - 1) and battles_for_count == 21): response += "{}){}{} — {}<code>{}</code>" \ "\n".format(j + 1, elem[0].castle, "{}{}".format(elem[0].nickname.partition("]")[2] if "]" in elem[0].nickname else elem[0].nickname, '🎗' if elem[0].id == guild.commander_id else ""), top[0], elem[i + 1]) elif j == max_players: response += "...\n" if len(response) > MAX_MESSAGE_LENGTH: ret.append(response) response = "" if response != "": ret.append(response) return ret
def add_report(bot, update, user_data): """ Функция сохранения репорта от игрока """ mes = update.message s = mes.text player = Player.get_player(mes.from_user.id) if player is None: return try: forward_message_date = utc.localize( mes.forward_date).astimezone(tz=moscow_tz).replace(tzinfo=None) except ValueError: try: forward_message_date = mes.forward_date except AttributeError: forward_message_date = local_tz.localize( mes.date).astimezone(tz=moscow_tz).replace(tzinfo=None) line = re.search( "[🍆🍁☘️🌹🐢🦇🖤️]*(.*)\\s⚔:(\\d+)\\(?(.?\\d*)\\)?.*🛡:(\\d+)\\(?(.?\\d*)\\)?.*Lvl: (\\d+)\\s", s) """ . - замок, (.*)\\s - никнейм в игре - от замка до эмодзи атаки. ⚔:(\\d+) - Парсинг атаки в конкретной битве \\(? - Возможно атака подверглась модификациям, тогда сразу после числа атаки будет открывающая скобка. \\(?(.?\\d*)\\)? - Парсинг дополнительной атаки целиком. Группа будет равна ' ', то есть одному пробельному символу, если дополнительной атаки нет. .*🛡: - всё лишнее до дефа. Далее абсолютно аналогично атаке 🛡:(\\d+)\\(?(.?\\d*)\\)? .*Lvl: (\\d+)\\s - лишнее до уровня и парсинг уровня, в комментариях не нуждается """ nickname = line.group(1) if nickname != player.nickname: bot.send_message( chat_id=mes.chat_id, text="Это не ваш репорт. В случае ошибок обновите профиль.", reply_to_message_id=mes.message_id) return attack = int(line.group(2)) additional_attack = int(line.group(3)) if line.group(3) != " " else 0 defense = int(line.group(4)) additional_defense = int(line.group(5)) if line.group(5) != " " else 0 lvl = int(line.group(6)) exp = re.search("🔥Exp:\\s(-?\\d+)", s) exp = int(exp.group(1)) if exp is not None else 0 gold = re.search("💰Gold:\\s+(-?\\d+)", s) gold = int(gold.group(1)) if gold is not None else 0 stock = re.search("📦Stock:\\s+(-?\\d+)", s) stock = int(stock.group(1)) if stock is not None else 0 battle_id = count_battle_id(mes) hp = re.search("❤️Hp: (-?\\d+)", s) hp = int(hp.group(1)) if hp is not None else 0 outplay = re.search("You outplayed (.+) by ⚔️(\\d+)", s) outplay_dict = {} if outplay is not None: outplay_nickname = outplay.group(1) outplay_attack = int(outplay.group(2)) outplay_dict.update({ "nickname": outplay_nickname, "attack": outplay_attack }) if 'Встреча:' in s or ('Твои удары' in s.lower() and 'Атаки врагов' in s.lower() and 'Ластхит' in s.lower()): # Репорт с мобов earned = re.search("Получено: (.+) \\((\\d+)\\)", s) if earned is not None: name = earned.group(1) count = earned.group(2) code = get_item_code_by_name(name) if code is None: code = name drop = player.mobs_info.get("drop") if drop is None: drop = {} player.mobs_info.update({"drop": drop}) drop.update( {forward_message_date.timestamp(): { "code": code, "count": 1 }}) player.update() names, lvls, buffs = [], [], [] for string in mes.text.splitlines(): parse = re.search("(.+) lvl\\.(\\d+)", string) if parse is not None: name = parse.group(1) lvl = int(parse.group(2)) names.append(name) lvls.append(lvl) buffs.append("") else: parse = re.search(" ╰ (.+)", string) if parse is not None: buff = parse.group(1) buffs.pop() buffs.append(buff) hit = re.search("Твои удары: (\\d+)", s) hit = int(hit.group(1)) if hit is not None else 0 miss = re.search("Атаки врагов: (\\d+)", s) miss = int(miss.group(1)) if miss is not None else 0 last_hit = re.search("Ластхит: (\\d+)", s) last_hit = int(last_hit.group(1)) if last_hit is not None else 0 request = "select report_id from mob_reports where date_created = %s and player_id = %s" cursor.execute(request, (forward_message_date, player.id)) row = cursor.fetchone() if row is not None: return request = "insert into mob_reports(player_id, date_created, attack, additional_attack, defense, " \ "additional_defense, lvl, exp, gold, stock, mob_names, mob_lvls, buffs, hp, hit, miss, last_hit) " \ "values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" cursor.execute( request, (player.id, forward_message_date, attack, additional_attack, defense, additional_defense, lvl, exp, gold, stock, names, lvls, buffs, hp, hit, miss, last_hit)) return equip = re.search("Found: (.+) \\(from (.+)\\)", s) equip_change = None if equip is not None: name = equip.group(1) found_from = equip.group(2) equip_change = {"status": "Found", "name": name, "from": found_from} else: equip = re.search("Lost: (.+)", s) if equip is not None: name = equip.group(1) equip_change = {"status": "Lost", "name": name} request = "select report_id from reports where battle_id = %s and player_id = %s" cursor.execute(request, (battle_id, player.id)) row = cursor.fetchone() if row is not None: bot.send_message(chat_id=mes.from_user.id, text="Репорт за эту битву уже учтён!") return request = "insert into reports(player_id, battle_id, attack, additional_attack, defense, additional_defense, lvl, "\ "exp, gold, stock, equip, outplay) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" cursor.execute( request, (player.id, battle_id, attack, additional_attack, defense, additional_defense, lvl, exp, gold, stock, json.dumps(equip_change, ensure_ascii=False) if equip_change is not None else None, json.dumps(outplay_dict, ensure_ascii=False) if outplay_dict is not None else None)) player.count_reports() reputation = REPORT_REPUTATION_COUNT if forward_message_date < datetime.datetime( year=2019, month=5, day=29, hour=12): reputation = 0 player.reputation += reputation player.update() response = "Репорт учтён. Спасибо!\n" \ "{}".format("Получено {}🔘!".format(reputation) if not user_data.get("rp_off") else "") bot.send_message(chat_id=mes.from_user.id, text=response, parse_mode='HTML') if exp != 0: on_add_report(player, forward_message_date) """
def battle_stats(bot, update): mes = update.message cursor1 = conn.cursor() battle_id = re.search("_(\\d+)", mes.text) battle_id = int( battle_id.group(1)) if battle_id is not None else count_battle_id(mes) guilds = [] for guild_id in Guild.guild_ids: guild = Guild.get_guild(guild_id=guild_id) if guild is None or guild.division in SKIPPED_DIVISIONS: continue guild.clear_counted_reports() guilds.append(guild) guilds.sort(key=lambda x: x.division or "") guilds.append( Guild(-1, "Без гильдии", None, None, None, None, None, None, None, None, None, None, None, None)) request = "select player_id, attack, defense, gold from reports where battle_id = %s" cursor1.execute(request, (battle_id, )) row = cursor1.fetchone() response = "Статистика по битве {} - {}:\n".format( battle_id, count_battle_time(battle_id).strftime("%d/%m/%y %H:%M:%S")) while row is not None: player = Player.get_player(row[0]) if player.castle != '🖤': row = cursor1.fetchone() continue if player.guild is None: guild = guilds[-1] else: guild = Guild.get_guild(player.guild) guild.add_count_report(row[1], row[2], row[3]) row = cursor1.fetchone() total_reports = 0 total_attack = 0 total_defense = 0 total_gold = 0 guilds.sort(key=lambda x: (x.division or "", x.get_counted_report_values()[1]), reverse=True) current_division = guilds[0].division division_reports, division_attack, division_defense, division_gold = 0, 0, 0, 0 for guild in guilds: if guild.division != current_division: response += "Дивизион {}:\nВсего: {} репортов, ⚔️: <b>{}</b>, 🛡: <b>{}</b>, 💰: <b>{}</b>\n\n" \ "".format(current_division, division_reports, division_attack, division_defense, division_gold) total_attack += division_attack total_defense += division_defense total_gold += division_gold total_reports += division_reports division_reports, division_attack, division_defense, division_gold = 0, 0, 0, 0 current_division = guild.division values = guild.get_counted_report_values() division_reports += values[0] division_attack += values[1] division_defense += values[2] division_gold += values[3] response += "<code>{:<3}</code>-👣{} ⚔️{} 🛡{} 💰{}" \ "\n".format(guild.tag, values[0], values[1], values[2], values[3]) response += "\nВсего: {} репортов, ⚔️: <b>{}</b>, 🛡: <b>{}</b>, " \ "💰: <b>{}</b>\n".format(total_reports, total_attack, total_defense, total_gold) bot.send_message(chat_id=mes.chat_id, text=response, parse_mode='HTML')