From 0ac45ffed07e5812d2b8b5011e59c2d562b23bf2 Mon Sep 17 00:00:00 2001 From: SimolZimol <70102430+SimolZimol@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:45:03 +0100 Subject: [PATCH] modified: app.py --- app.py | 143 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 20 deletions(-) diff --git a/app.py b/app.py index 35aff92..5da088f 100644 --- a/app.py +++ b/app.py @@ -127,6 +127,62 @@ T_LEVEL_MULTIPLIERS = { 3: 1.2 # T3 countries get more points } +# Emoji and formatting helpers +def _all_accessible_emojis(ctx: commands.Context) -> List[discord.Emoji]: + """Return emojis from current guild plus all guilds the bot is in.""" + try: + guild_emojis = list(ctx.guild.emojis) if ctx.guild else [] + except Exception: + guild_emojis = [] + try: + bot_emojis = list(bot.emojis) + except Exception: + bot_emojis = [] + return guild_emojis + bot_emojis + +def find_custom_emoji(ctx: commands.Context, keyword_variants: List[str]) -> Optional[str]: + """Try to find a custom emoji by a list of keyword variants (case-insensitive). Returns str(emoji) or None.""" + emojis = _all_accessible_emojis(ctx) + for kw in keyword_variants: + kw = kw.lower() + for e in emojis: + try: + if kw in (e.name or '').lower(): + return str(e) + except Exception: + continue + return None + +def get_t_emoji(ctx: commands.Context, t_level: int) -> str: + """Return a suitable emoji for a T level, preferring custom emojis if present.""" + mapping = { + 1: ["hoi4_t1", "t1", "tier1"], + 2: ["hoi4_t2", "t2", "tier2"], + 3: ["hoi4_t3", "t3", "tier3"], + } + custom = find_custom_emoji(ctx, mapping.get(t_level, [])) + if custom: + return custom + # Fallback unicode + return {1: "🔹", 2: "🔸", 3: "🔺"}.get(t_level, "🔹") + +def get_team_emoji(ctx: commands.Context, team_name: str) -> str: + """Return an emoji for common HOI4 team names like Axis/Allies/Comintern or a generic HOI4 emoji if available.""" + name = (team_name or "").lower() + if any(k in name for k in ["axis", "achse"]): + custom = find_custom_emoji(ctx, ["axis", "hoi4_axis"]) + return custom or "⚫" + if any(k in name for k in ["allies", "alliierten", "ally"]): + custom = find_custom_emoji(ctx, ["allies", "hoi4_allies"]) + return custom or "🔵" + if any(k in name for k in ["comintern", "ussr", "soviet"]): + custom = find_custom_emoji(ctx, ["comintern", "hoi4_comintern"]) + return custom or "🔴" + # Generic HOI4 emoji or fallback + custom = find_custom_emoji(ctx, ["hoi4", "hearts_of_iron", "iron"]) + return custom or "🎖️" + +# Database Functions # Database Functions async def init_database(): """Initialize database connection and create tables""" @@ -747,9 +803,9 @@ async def hoi4stats(ctx, user: Optional[discord.Member] = None): except Exception as e: await ctx.send(f"❌ Error getting stats: {str(e)}") -@bot.hybrid_command(name='hoi4games', description='Show active games') +@bot.hybrid_command(name='hoi4games', description='Show active games as team showcases') async def hoi4games(ctx): - """Show all active games""" + """Show all active games with teams presented side-by-side like a showcase.""" try: async with db_pool.acquire() as conn: async with conn.cursor(aiomysql.DictCursor) as cursor: @@ -757,37 +813,84 @@ async def hoi4games(ctx): "SELECT * FROM games WHERE status = 'setup' ORDER BY created_at DESC" ) games = await cursor.fetchall() - + if not games: await ctx.send("📝 No active games found. Use `/hoi4create` to create a new game!") return - + embed = discord.Embed( title="🎮 Active HOI4 Games", + description="Team lineups are shown side-by-side. Use /hoi4setup to add players.", color=discord.Color.green() ) - + + # Limit total embed fields to avoid Discord limit (25). Each game uses up to 3 fields. + max_games = max(1, 25 // 3) + games = games[:max_games] + for game in games: players = json.loads(game['players']) if game['players'] else [] - player_count = len(players) - - teams = {} - for player in players: - team = player['team_name'] - if team not in teams: - teams[team] = 0 - teams[team] += 1 - - team_info = ", ".join([f"{team} ({count})" for team, count in teams.items()]) if teams else "No players yet" - + + # Build team structures + teams: Dict[str, List[Dict]] = {} + for p in players: + teams.setdefault(p['team_name'], []).append(p) + + # Compute average ELO per team + team_avgs = {t: (sum(m['current_elo'] for m in mlist) / len(mlist)) if mlist else 0 for t, mlist in teams.items()} + + # Sort teams by name to keep stable order + ordered_teams = sorted(teams.items(), key=lambda x: x[0].lower()) + + # Helper to format a team's field + def build_team_field(team_name: str, members: List[Dict]) -> Dict[str, str]: + t_emoji = get_team_emoji(ctx, team_name) + avg = team_avgs.get(team_name, 0) + name = f"{t_emoji} {team_name} (avg {avg:.0f})" + # Each player line: T-level emoji, name, elo + lines = [] + for m in sorted(members, key=lambda mm: (-mm.get('t_level', 2), mm['username'].lower())): + te = get_t_emoji(ctx, int(m.get('t_level', 2))) + lines.append(f"{te} {m['username']} ({m['current_elo']})") + value = "\n".join(lines) if lines else "No players yet" + # Discord field value max ~1024 chars; trim if necessary + if len(value) > 1000: + value = value[:997] + "..." + return {"name": name, "value": value} + + # If no teams yet, show empty placeholder for this game + if not ordered_teams: + embed.add_field( + name=f"{game['game_name']} ({game['game_type'].title()})", + value="No players yet", + inline=False + ) + continue + + # For two teams, show A vs B with a center VS field; otherwise, list each team inline + team_fields = [build_team_field(tn, members) for tn, members in ordered_teams] + + # Add a header field per game embed.add_field( - name=f"{game['game_name']} ({game['game_type'].title()})", - value=f"Players: {player_count}\nTeams: {team_info}", + name=f"🎯 {game['game_name']} ({game['game_type'].title()})", + value=f"Players: {len(players)} | Teams: {len(ordered_teams)}", inline=False ) - + + if len(team_fields) == 1: + f1 = team_fields[0] + embed.add_field(name=f1["name"], value=f1["value"], inline=False) + elif len(team_fields) >= 2: + f1, f2 = team_fields[0], team_fields[1] + embed.add_field(name=f1["name"], value=f1["value"], inline=True) + embed.add_field(name="⚔️ VS ⚔️", value="\u200b", inline=True) + embed.add_field(name=f2["name"], value=f2["value"], inline=True) + # If more teams exist, add them below + for extra in team_fields[2:]: + embed.add_field(name=extra["name"], value=extra["value"], inline=False) + await ctx.send(embed=embed) - + except Exception as e: await ctx.send(f"❌ Error getting games: {str(e)}")