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:

30
emotes.markdown Normal file
View File

@@ -0,0 +1,30 @@
<:Civilian_Economy:1432372408941154325>
<:Disarmed_Nation:1432372405669724362>
<:Anarchism:1432372205647298672>
<:Communism:1432372203860525149>
<:Communism:1432372203860525149>
<:Democracy:1432372201943994368>
<:Fascism:1432372200756740281>
<:Neutrality:1432372199469355039>
<:Unknown_Ideology:1432372192879972353>
<:Nuclear_Strike:1432371908615213148>
<:Construction:1432371608806490132>
<:Decision:1432371606537109576>
<:Deployment:1432371605065044029>
<:Diplomacy:1432371603911606315>
<:Intelligence:1432371602531680337>
<:Logistics:1432371601168535582>
<:Production:1432371599524495540>
<:Research:1432371597989380258>
<:Trade:1432371596558991412>
<:navy_hoi:1432370988426985642>
<:peace_hoi:1432370987076423780>
<:secretweapon_hoi:1432370981607051397>
<:Eagle_hoi:1432370708771770509>
<:Cadet_hoi:1432370649053270140>
<:FreshRecruit:1432370967652335736>
<:ExperiencedRegular:1432370968818352191>
<:HardenedVeteran:1432370970135625748>
<:SkilledCaptain:1432370971792117810>
<:CommanderinChief:1432370973176238161>
<:WarHero:1432370974212489226>

105
tags.txt Normal file
View File

@@ -0,0 +1,105 @@
Kingdom of Afghanistan AFG
Albanian Kingdom ALB
Argentina ARG
Sultanate of Aussa AFA
Australia AST
Austria AUS
Belgian Congo COG
Belgium BEL
Bhutan BHU
Bolivian Republic BOL
Second Brazilian Republic BRA
British Burma BRM
British Malaya MAL
British Raj RAJ
Bulgaria BUL
BUZ
BUF
Dominion of Canada CAN
Chile CHL
China CHI
Colombia COL
Communist China PRC
Costa Rica COS
Cuba CUB
Czechoslovakia CZE
Denmark DEN
Dominican Republic DOM
Dutch East Indies INS
Ecuador ECU
El Salvador ELS
Estonia EST
Ethiopia ETH
Finland FIN
France FRA
VIC
German Reich GER
Kingdom of Greece GRE
Guangxi Clique GXC
Guatemala GUA
Haiti HAI
Honduras HON
Kingdom of Hungary HUN
Iceland ICE
Iran PER
Iraq IRQ
Ireland IRE
Italy ITA
RSI
RDS
Japan JAP
Sheikhdom of Kuwait KUW
Latvia LAT
Lebanese Republic LEB
Liberia LIB
Lithuania LIT
Luxembourg LUX
Manchukuo MAN
Mengkukuo MEN
Mexico MEX
Mongolian People's Republic MON
Sultanate of Muscat and Oman OMA
Nepal NEP
Netherlands HOL
New Zealand NZL
Nicaragua NIC
Norway NOR
Mandatory Palestine PAL
Panama PAN
Republic of Paraguay PAR
Peru PRU
Philippines PHI
Poland POL
Portugal POR
Romania ROM
Saudi Arabia SAU
Shanxi SHX
Kingdom of Siam SIA
Sinkiang SIK
South Africa SAF
Soviet Union SOV
SOS
SOT
SOB
SOP
SOU
Spain SPR
SPA
SPB
SPC
SPD
Sweden SWE
Switzerland SWI
Republic of Syria SYR
Tannu Tuva TAN
Tibet TIB
Emirate of Transjordan JOR
Turkey TUR
United Kingdom ENG
United States USA
Uruguay URG
Venezuela VEN
Xibei San Ma XSM
Yemen YEM
Yugoslavia YUG
Yunnan YUN