modified: app.py
This commit is contained in:
143
app.py
143
app.py
@@ -127,6 +127,62 @@ T_LEVEL_MULTIPLIERS = {
|
|||||||
3: 1.2 # T3 countries get more points
|
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
|
# Database Functions
|
||||||
async def init_database():
|
async def init_database():
|
||||||
"""Initialize database connection and create tables"""
|
"""Initialize database connection and create tables"""
|
||||||
@@ -747,9 +803,9 @@ async def hoi4stats(ctx, user: Optional[discord.Member] = None):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f"❌ Error getting stats: {str(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):
|
async def hoi4games(ctx):
|
||||||
"""Show all active games"""
|
"""Show all active games with teams presented side-by-side like a showcase."""
|
||||||
try:
|
try:
|
||||||
async with db_pool.acquire() as conn:
|
async with db_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.DictCursor) as cursor:
|
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"
|
"SELECT * FROM games WHERE status = 'setup' ORDER BY created_at DESC"
|
||||||
)
|
)
|
||||||
games = await cursor.fetchall()
|
games = await cursor.fetchall()
|
||||||
|
|
||||||
if not games:
|
if not games:
|
||||||
await ctx.send("📝 No active games found. Use `/hoi4create` to create a new game!")
|
await ctx.send("📝 No active games found. Use `/hoi4create` to create a new game!")
|
||||||
return
|
return
|
||||||
|
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="🎮 Active HOI4 Games",
|
title="🎮 Active HOI4 Games",
|
||||||
|
description="Team lineups are shown side-by-side. Use /hoi4setup to add players.",
|
||||||
color=discord.Color.green()
|
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:
|
for game in games:
|
||||||
players = json.loads(game['players']) if game['players'] else []
|
players = json.loads(game['players']) if game['players'] else []
|
||||||
player_count = len(players)
|
|
||||||
|
# Build team structures
|
||||||
teams = {}
|
teams: Dict[str, List[Dict]] = {}
|
||||||
for player in players:
|
for p in players:
|
||||||
team = player['team_name']
|
teams.setdefault(p['team_name'], []).append(p)
|
||||||
if team not in teams:
|
|
||||||
teams[team] = 0
|
# Compute average ELO per team
|
||||||
teams[team] += 1
|
team_avgs = {t: (sum(m['current_elo'] for m in mlist) / len(mlist)) if mlist else 0 for t, mlist in teams.items()}
|
||||||
|
|
||||||
team_info = ", ".join([f"{team} ({count})" for team, count in teams.items()]) if teams else "No players yet"
|
# 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(
|
embed.add_field(
|
||||||
name=f"{game['game_name']} ({game['game_type'].title()})",
|
name=f"🎯 {game['game_name']} ({game['game_type'].title()})",
|
||||||
value=f"Players: {player_count}\nTeams: {team_info}",
|
value=f"Players: {len(players)} | Teams: {len(ordered_teams)}",
|
||||||
inline=False
|
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)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await ctx.send(f"❌ Error getting games: {str(e)}")
|
await ctx.send(f"❌ Error getting games: {str(e)}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user