modified: app.py

new file:   emotes.markdown
	new file:   tags.txt
This commit is contained in:
SimolZimol
2025-10-27 16:23:40 +01:00
parent 0ac45ffed0
commit 82fd5449ae
3 changed files with 288 additions and 3 deletions

156
app.py
View File

@@ -151,6 +151,21 @@ def find_custom_emoji(ctx: commands.Context, keyword_variants: List[str]) -> Opt
return str(e)
except Exception:
continue
# Fallback to markdown-defined emojis if available
try:
if EMOTE_MAP:
for kw in keyword_variants:
key = kw.lower()
# Exact name match
if key in EMOTE_MAP:
return EMOTE_MAP[key]
# Substring match
for name_lower, mention in EMOTE_MAP.items():
if key in name_lower:
return mention
except NameError:
# EMOTE_MAP not defined yet
pass
return None
def get_t_emoji(ctx: commands.Context, t_level: int) -> str:
@@ -180,8 +195,128 @@ def get_team_emoji(ctx: commands.Context, team_name: str) -> str:
return custom or "🔴"
# Generic HOI4 emoji or fallback
custom = find_custom_emoji(ctx, ["hoi4", "hearts_of_iron", "iron"])
if not custom:
custom = find_custom_emoji(ctx, ["eagle_hoi", "peace_hoi", "navy_hoi", "secretweapon_hoi"])
return custom or "🎖️"
def _flag_from_iso2(code: str) -> Optional[str]:
"""Return unicode flag from 2-letter ISO code (e.g., 'DE' -> 🇩🇪)."""
if not code or len(code) != 2:
return None
code = code.upper()
base = 0x1F1E6
try:
return chr(base + ord(code[0]) - ord('A')) + chr(base + ord(code[1]) - ord('A'))
except Exception:
return None
# Emotes markdown loader and map
def load_emote_markdown(path: Optional[str] = None) -> Dict[str, str]:
"""Parse emotes.markdown and return a mapping of lowercased emoji names to their mention strings.
Expected line format: <:Name:123456789012345678>
Lines that don't match are ignored."""
if path is None:
base_dir = os.path.dirname(os.path.abspath(__file__))
path = os.path.join(base_dir, 'emotes.markdown')
mapping: Dict[str, str] = {}
try:
with open(path, 'r', encoding='utf-8') as f:
for raw in f:
line = raw.strip()
if not line or not line.startswith('<:') or ':' not in line[2:]:
continue
# Format is <:NAME:ID>
try:
inner = line[2:-1] if line.endswith('>') else line[2:]
name, emoji_id = inner.split(':', 1)
name = name.strip()
mention = f"<:{name}:{emoji_id.strip('>')}>"
mapping[name.lower()] = mention
except Exception:
continue
except FileNotFoundError:
# Silent if not present
pass
except Exception as e:
print(f"⚠️ Failed to load emotes.markdown: {e}")
return mapping
# Load emotes mapping at import
EMOTE_MAP: Dict[str, str] = load_emote_markdown()
if EMOTE_MAP:
print(f"😀 Loaded {len(EMOTE_MAP)} custom emojis from emotes.markdown")
def load_country_tags(path: Optional[str] = None) -> Dict[str, str]:
"""Load HOI4 country tags mapping from tags.txt.
Supported formats per line:
TAG=Country Name | TAG:Country Name | TAG,Country Name | TAG Country Name
Lines starting with # are ignored.
Returns dict like { 'GER': 'Germany', ... }"""
if path is None:
base_dir = os.path.dirname(os.path.abspath(__file__))
path = os.path.join(base_dir, 'tags.txt')
mapping: Dict[str, str] = {}
try:
with open(path, 'r', encoding='utf-8') as f:
for raw in f:
line = raw.strip()
if not line or line.startswith('#'):
continue
tag = None
name = None
for sep in ['=', ';', ',', ':']:
if sep in line:
left, right = line.split(sep, 1)
tag = left.strip().upper()
name = right.strip()
break
if tag is None:
parts = line.split(None, 1)
if len(parts) == 2:
tag = parts[0].strip().upper()
name = parts[1].strip()
else:
tag = line.strip().upper()
name = line.strip()
if tag and name:
mapping[tag] = name
except FileNotFoundError:
print(" tags.txt not found; proceeding without country tag labels")
except Exception as e:
print(f"⚠️ Failed to load tags.txt: {e}")
return mapping
# Loaded at import
COUNTRY_TAGS: Dict[str, str] = load_country_tags()
if COUNTRY_TAGS:
print(f"🗺️ Loaded {len(COUNTRY_TAGS)} HOI4 country tags")
def get_country_label(country_tag: Optional[str]) -> Optional[str]:
"""Return a display label like "[GER] Germany" if known, or "[GER]" if unknown."""
if not country_tag:
return None
tag = country_tag.strip().upper()
name = COUNTRY_TAGS.get(tag)
return f"[{tag}] {name}" if name else f"[{tag}]"
def get_country_emoji(ctx: commands.Context, country: Optional[str]) -> str:
"""Prefer custom emoji matching the HOI4 tag (e.g., ger, hoi4_ger). If parameter is ISO2, show unicode flag. Else empty."""
if not country:
return ""
c = country.strip()
# Try custom emoji lookups using tag variants
variants = [c, c.lower(), f"hoi4_{c.lower()}", f"country_{c.lower()}"]
custom = find_custom_emoji(ctx, variants)
if custom:
return custom
# If user passed ISO2, render unicode flag
if len(c) == 2:
flag = _flag_from_iso2(c)
if flag:
return flag
# Otherwise, no emoji fallback to avoid noisy globes
return ""
# Database Functions
# Database Functions
async def init_database():
@@ -433,7 +568,7 @@ async def hoi4create(ctx, game_type: str, game_name: str):
await ctx.send(f"❌ Error creating game: {str(e)}")
@bot.hybrid_command(name='hoi4setup', description='Add a player to an existing game')
async def hoi4setup(ctx, game_name: str, user: discord.Member, team_name: str, t_level: int):
async def hoi4setup(ctx, game_name: str, user: discord.Member, team_name: str, t_level: int, country: Optional[str] = None):
"""Add a player to an existing game"""
if t_level not in [1, 2, 3]:
await ctx.send("❌ T-Level must be 1, 2, or 3")
@@ -471,7 +606,8 @@ async def hoi4setup(ctx, game_name: str, user: discord.Member, team_name: str, t
'username': user.display_name,
'team_name': team_name,
't_level': t_level,
'current_elo': player[f"{game['game_type']}_elo"]
'current_elo': player[f"{game['game_type']}_elo"],
'country': country.strip() if country else None
}
players.append(player_data)
@@ -490,6 +626,11 @@ async def hoi4setup(ctx, game_name: str, user: discord.Member, team_name: str, t
embed.add_field(name="Team", value=team_name, inline=True)
embed.add_field(name="T-Level", value=f"T{t_level}", inline=True)
embed.add_field(name="Current ELO", value=player[f"{game['game_type']}_elo"], inline=True)
if country:
flag = get_country_emoji(ctx, country)
label = get_country_label(country)
value = f"{flag} {label}".strip()
embed.add_field(name="Country", value=value, inline=True)
embed.add_field(name="Players in Game", value=len(players), inline=True)
await ctx.send(embed=embed)
@@ -851,7 +992,16 @@ async def hoi4games(ctx):
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']})")
ctry = m.get('country')
flag = get_country_emoji(ctx, ctry) if ctry else ""
label = get_country_label(ctry) if ctry else None
parts = [te]
if flag:
parts.append(flag)
if label:
parts.append(label)
parts.append(m['username'])
lines.append(f"{' '.join(parts)} ({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: