Final beta for tonight
This commit is contained in:
BIN
.bot.py.swp
Normal file
BIN
.bot.py.swp
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
arbre.png
BIN
arbre.png
Binary file not shown.
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 614 KiB |
BIN
avatars/1334641803059793940.png
Normal file
BIN
avatars/1334641803059793940.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
BIN
avatars/565561317189091328.png
Normal file
BIN
avatars/565561317189091328.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 274 KiB |
BIN
avatars/582633859967877133.png
Normal file
BIN
avatars/582633859967877133.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
34
bot.py
34
bot.py
@ -74,14 +74,20 @@ async def enregistrer(interaction: discord.Interaction):
|
||||
async def adopter(interaction: discord.Interaction, enfant: discord.Member):
|
||||
parent = interaction.user
|
||||
|
||||
# Debug
|
||||
parent_gen = family.get_generation(str(parent.id))
|
||||
enfant_gen = family.get_generation(str(enfant.id))
|
||||
print(f"Adoption: {parent.display_name} (gen {parent_gen}) → {enfant.display_name} (gen {enfant_gen})")
|
||||
|
||||
# Validations
|
||||
if parent.id == enfant.id:
|
||||
await interaction.response.send_message("❌ Auto-adoption impossible !", ephemeral=True)
|
||||
return
|
||||
|
||||
if family.get_generation(str(enfant.id)) < family.get_generation(str(parent.id)):
|
||||
|
||||
# Nouvelle condition plus permissive
|
||||
if enfant_gen > parent_gen:
|
||||
await interaction.response.send_message(
|
||||
"❌ Structure familiale invalide !",
|
||||
"❌ Impossible d'adopter quelqu'un de plus ancien que vous !",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
@ -111,14 +117,14 @@ async def adopter(interaction: discord.Interaction, enfant: discord.Member):
|
||||
try:
|
||||
await enfant.add_roles(role)
|
||||
message = f"✅ {parent.mention} a adopté {enfant.mention} !"
|
||||
|
||||
|
||||
# Mentionne le partenaire si existe
|
||||
partner_id = family.get_partner(str(parent.id))
|
||||
if partner_id:
|
||||
partner = interaction.guild.get_member(int(partner_id))
|
||||
if partner:
|
||||
message += f"\n👫 Partenaire : {partner.mention}"
|
||||
|
||||
|
||||
await interaction.response.send_message(message)
|
||||
except discord.Forbidden:
|
||||
await interaction.response.send_message(
|
||||
@ -131,6 +137,16 @@ async def adopter(interaction: discord.Interaction, enfant: discord.Member):
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
@bot.tree.command(name="racine", description="Définir un membre comme racine")
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def racine(interaction: discord.Interaction, membre: discord.Member, est_racine: bool):
|
||||
success = family.set_as_root(str(membre.id), est_racine)
|
||||
await interaction.response.send_message(
|
||||
f"✅ {membre.mention} est maintenant {'une racine' if est_racine else 'plus une racine'} !"
|
||||
if success else "❌ Erreur",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
@bot.tree.command(name="couple", description="Officialiser une relation")
|
||||
async def couple(interaction: discord.Interaction, partenaire: discord.Member):
|
||||
membre = interaction.user
|
||||
@ -170,7 +186,7 @@ async def renier(interaction: discord.Interaction, enfant: discord.Member):
|
||||
"PETIT_ENFANT" if generation == 2 else
|
||||
"ARRIERE_PETIT_ENFANT"
|
||||
)
|
||||
|
||||
|
||||
if role_id:
|
||||
role = interaction.guild.get_role(role_id)
|
||||
if role:
|
||||
@ -191,7 +207,7 @@ async def renier(interaction: discord.Interaction, enfant: discord.Member):
|
||||
@bot.tree.command(name="arbre", description="Afficher l'arbre généalogique")
|
||||
async def arbre(interaction: discord.Interaction):
|
||||
await interaction.response.defer()
|
||||
|
||||
|
||||
# Télécharge les avatars des membres
|
||||
members = family.get_all_members()
|
||||
for member_id in members:
|
||||
@ -203,7 +219,7 @@ async def arbre(interaction: discord.Interaction):
|
||||
|
||||
# Génère l'arbre
|
||||
generate_tree("family.json", "arbre.png", config["ROOT_MEMBER_ID"])
|
||||
|
||||
|
||||
# Envoie le résultat
|
||||
try:
|
||||
await interaction.followup.send(file=discord.File("arbre.png"))
|
||||
@ -238,7 +254,7 @@ async def init(ctx):
|
||||
for member in ctx.guild.members:
|
||||
await update_member(member)
|
||||
count += 1
|
||||
|
||||
|
||||
await ctx.send(f"✅ {count} membres initialisés !")
|
||||
|
||||
bot.run(TOKEN)
|
||||
|
22
family.json
22
family.json
@ -29,7 +29,8 @@
|
||||
"id": "901473267104223232",
|
||||
"name": "Partenaire"
|
||||
}
|
||||
]
|
||||
],
|
||||
"avatar": "https://cdn.discordapp.com/avatars/436978132105560064/1d711ba4fea8d707903df35ea859a86c.png?size=1024"
|
||||
},
|
||||
"567371662165803009": {
|
||||
"name": "Je suis g\u00e9niale.ment on fire",
|
||||
@ -120,6 +121,21 @@
|
||||
"name": "NYM N'EST PAS UN CODE BARRE"
|
||||
}
|
||||
]
|
||||
},
|
||||
"565561317189091328": {
|
||||
"name": "BardimeduSAFF Hamilton ofthemind",
|
||||
"avatar": "https://cdn.discordapp.com/avatars/565561317189091328/c77280ab4a455cd482f73a2ef38d72f8.png?size=1024",
|
||||
"parents": []
|
||||
},
|
||||
"582633859967877133": {
|
||||
"name": "L'incarn\u00e9 zzz",
|
||||
"avatar": "https://cdn.discordapp.com/avatars/582633859967877133/89c60709a5e4c47ee16001844f0d51ad.png?size=1024",
|
||||
"parents": []
|
||||
},
|
||||
"1334641803059793940": {
|
||||
"name": "Epic The Ticketal",
|
||||
"avatar": "https://cdn.discordapp.com/avatars/1334641803059793940/e36465f33fa4c2cd35a9de212e6832fc.png?size=1024",
|
||||
"parents": []
|
||||
}
|
||||
},
|
||||
"couples": [
|
||||
@ -130,6 +146,10 @@
|
||||
[
|
||||
"506016482300395520",
|
||||
"769178722838118400"
|
||||
],
|
||||
[
|
||||
"565561317189091328",
|
||||
"582633859967877133"
|
||||
]
|
||||
]
|
||||
}
|
70
family.py
70
family.py
@ -13,7 +13,8 @@ class FamilyManager:
|
||||
with open(self.file_path, "w") as f:
|
||||
json.dump({
|
||||
"members": {},
|
||||
"couples": []
|
||||
"couples": [],
|
||||
"roots": []
|
||||
}, f, indent=2)
|
||||
|
||||
def _load(self) -> Dict:
|
||||
@ -26,6 +27,23 @@ class FamilyManager:
|
||||
with open(self.file_path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
def set_as_root(self, member_id: str, is_root: bool = True) -> bool:
|
||||
"""Définit un membre comme racine ou non"""
|
||||
data = self._load()
|
||||
if str(member_id) not in data["members"]:
|
||||
return False
|
||||
|
||||
if "roots" not in data:
|
||||
data["roots"] = []
|
||||
|
||||
if is_root and str(member_id) not in data["roots"]:
|
||||
data["roots"].append(str(member_id))
|
||||
elif not is_root and str(member_id) in data["roots"]:
|
||||
data["roots"].remove(str(member_id))
|
||||
|
||||
self._save(data)
|
||||
return True
|
||||
|
||||
def add_member(self, member_id: str, member_name: str, avatar_url: str = None):
|
||||
"""
|
||||
Ajoute ou met à jour un membre
|
||||
@ -34,7 +52,7 @@ class FamilyManager:
|
||||
:param avatar_url: URL de l'avatar (optionnel)
|
||||
"""
|
||||
data = self._load()
|
||||
|
||||
|
||||
if str(member_id) not in data["members"]:
|
||||
data["members"][str(member_id)] = {
|
||||
"name": member_name,
|
||||
@ -46,17 +64,18 @@ class FamilyManager:
|
||||
data["members"][str(member_id)]["name"] = member_name
|
||||
if avatar_url:
|
||||
data["members"][str(member_id)]["avatar"] = avatar_url
|
||||
|
||||
|
||||
self._save(data)
|
||||
|
||||
def add_child(self, parent_id: str, child_id: str):
|
||||
def add_child(self, parent_id: str, child_id: str) -> bool:
|
||||
"""
|
||||
Ajoute un lien parent-enfant
|
||||
:param parent_id: ID du parent
|
||||
:param child_id: ID de l'enfant
|
||||
:return: True si succès, False si échec
|
||||
"""
|
||||
data = self._load()
|
||||
|
||||
|
||||
# Vérifie que les membres existent
|
||||
if str(child_id) not in data["members"] or str(parent_id) not in data["members"]:
|
||||
return False
|
||||
@ -69,7 +88,7 @@ class FamilyManager:
|
||||
})
|
||||
|
||||
# Ajoute le partenaire comme parent secondaire si existe
|
||||
partner_id = self.get_partner(parent_id)
|
||||
partner_id = self.get_partner(str(parent_id))
|
||||
if partner_id:
|
||||
partner_name = data["members"].get(partner_id, {}).get("name", "Partenaire")
|
||||
data["members"][str(child_id)]["parents"].append({
|
||||
@ -87,7 +106,7 @@ class FamilyManager:
|
||||
"""
|
||||
data = self._load()
|
||||
couple = sorted([str(member1_id), str(member2_id)])
|
||||
|
||||
|
||||
if couple not in data["couples"]:
|
||||
data["couples"].append(couple)
|
||||
self._save(data)
|
||||
@ -109,15 +128,15 @@ class FamilyManager:
|
||||
"""
|
||||
data = self._load()
|
||||
changed = False
|
||||
|
||||
|
||||
if str(child_id) in data["members"]:
|
||||
original_count = len(data["members"][str(child_id)]["parents"])
|
||||
data["members"][str(child_id)]["parents"] = [
|
||||
p for p in data["members"][str(child_id)]["parents"]
|
||||
p for p in data["members"][str(child_id)]["parents"]
|
||||
if p["id"] != str(parent_id)
|
||||
]
|
||||
changed = len(data["members"][str(child_id)]["parents"]) < original_count
|
||||
|
||||
|
||||
if changed:
|
||||
self._save(data)
|
||||
return changed
|
||||
@ -143,20 +162,33 @@ class FamilyManager:
|
||||
def get_generation(self, member_id: str) -> int:
|
||||
"""
|
||||
Calcule la génération d'un membre
|
||||
:return: 0 pour la racine, 1 pour ses enfants, etc.
|
||||
:return: 0 pour les racines, 1 pour leurs enfants, etc.
|
||||
"""
|
||||
data = self._load()
|
||||
generation = 0
|
||||
current_id = str(member_id)
|
||||
|
||||
while current_id in data["members"] and data["members"][current_id].get("parents"):
|
||||
current_id = data["members"][current_id]["parents"][0]["id"]
|
||||
generation += 1
|
||||
if generation > 10: # Sécurité contre les boucles infinies
|
||||
break
|
||||
return generation
|
||||
# Si c'est une racine explicite
|
||||
if str(member_id) in data.get("roots", []):
|
||||
return 0
|
||||
|
||||
parents = data["members"].get(str(member_id), {}).get("parents", [])
|
||||
|
||||
# Si pas de parents => nouvelle racine (gen 0)
|
||||
if not parents:
|
||||
return 0
|
||||
|
||||
# Calcul basé sur les parents
|
||||
return 1 + min(
|
||||
self.get_generation(p["id"])
|
||||
for p in parents
|
||||
if p["id"] in data["members"]
|
||||
)
|
||||
|
||||
def get_all_members(self) -> List[str]:
|
||||
"""Liste tous les IDs des membres enregistrés"""
|
||||
data = self._load()
|
||||
return list(data["members"].keys())
|
||||
|
||||
def get_roots(self) -> List[str]:
|
||||
"""Liste toutes les racines"""
|
||||
data = self._load()
|
||||
return data.get("roots", [])
|
||||
|
9
tree.py
9
tree.py
@ -37,7 +37,14 @@ def create_avatar_with_name(user_id, name, avatar_path, output_path):
|
||||
print(f"Erreur création avatar+texte {user_id}: {e}")
|
||||
return False
|
||||
|
||||
def generate_tree(input_file, output_file, root_id):
|
||||
def generate_tree(input_file, output_file, root_id=None): # root_id devient optionnel
|
||||
with open(input_file) as f:
|
||||
data = json.load(f)
|
||||
|
||||
roots = data.get("roots", [root_id] if root_id else [])
|
||||
if not roots:
|
||||
roots = [mid for mid, m in data["members"].items() if not m.get("parents")]
|
||||
|
||||
with open(input_file) as f:
|
||||
data = json.load(f)
|
||||
|
||||
|
Reference in New Issue
Block a user