import discord from discord.ext import commands from discord import app_commands from datetime import datetime from database import Database import random CYBER_BLUE = discord.Color.from_rgb(52, 152, 219) CYBER_GREEN = discord.Color.from_rgb(46, 204, 113) CYBER_GOLD = discord.Color.from_rgb(241, 196, 15) class Level(commands.Cog): def __init__(self, bot): self.bot = bot # Cooldown: {user_id: last_msg_ts} self._xp_cooldown = {} self.COOLDOWN_SECONDS = 30 def _xp_for_level(self, level, difficulty=100): return 5 * (level ** 2) + 50 * level + 100 - level * difficulty // 10 def _level_from_xp(self, xp, difficulty=100): level = 0 while xp >= self._xp_for_level(level + 1, difficulty): level += 1 xp -= self._xp_for_level(level, difficulty) return level, xp async def _add_xp(self, member: discord.Member, xp_add: int): guild_id = member.guild.id user_id = member.id row = await Database.fetch_one( "SELECT * FROM seviye WHERE guild_id = ? AND user_id = ?", (guild_id, user_id) ) if not row: await Database.execute( "INSERT INTO seviye (guild_id, user_id, xp, seviye) VALUES (?, ?, ?, ?)", (guild_id, user_id, 0, 0) ) row = await Database.fetch_one( "SELECT * FROM seviye WHERE guild_id = ? AND user_id = ?", (guild_id, user_id) ) new_xp = row['xp'] + xp_add settings = await Database.fetch_one("SELECT * FROM seviye_ayarlar WHERE guild_id = ?", (guild_id,)) difficulty = settings['zorluk'] if settings and settings.get('zorluk') else 100 old_level = row['seviye'] new_level = self._level_from_xp(new_xp, difficulty)[0] await Database.execute( "UPDATE seviye SET xp = ?, seviye = ? WHERE guild_id = ? AND user_id = ?", (new_xp, new_level, guild_id, user_id) ) if new_level > old_level: # Level up bildirimi kanal_id = settings['mesaj_kanal_id'] if settings and settings.get('mesaj_kanal_id') else 0 kanal = member.guild.get_channel(kanal_id) if kanal_id else None embed = discord.Embed( title="🎉 Seviye Atlandı!", description=f"Tebrikler {member.mention}! **Seviye {new_level}**'e ulaştın! 🎊", color=CYBER_GOLD, timestamp=datetime.now() ) if kanal: try: await kanal.send(embed=embed) except: pass # Rol ödülü var mı kontrol et odul = await Database.fetch_one( "SELECT rol_id FROM seviye_oduller WHERE guild_id = ? AND seviye = ?", (guild_id, new_level) ) if odul: rol = member.guild.get_role(odul['rol_id']) if rol: try: await member.add_roles(rol, reason=f"Seviye {new_level} ödülü") except: pass @commands.Cog.listener() async def on_message(self, message: discord.Message): if message.author.bot or not message.guild: return if not await Database.modul_aktif_mi(message.guild.id, "Level"): return settings = await Database.fetch_one("SELECT aktif FROM seviye_ayarlar WHERE guild_id = ?", (message.guild.id,)) if settings and settings.get('aktif') == 0: return # Cooldown kontrolü import time now = time.time() last = self._xp_cooldown.get(message.author.id, 0) if now - last < self.COOLDOWN_SECONDS: return self._xp_cooldown[message.author.id] = now xp_gain = random.randint(15, 25) await self._add_xp(message.author, xp_gain) @commands.hybrid_command(name="seviye", description="Senin veya başka bir üyenin seviye kartını gösterir.") @app_commands.describe(uye="Seviyesine bakılacak üye") async def seviye(self, ctx: commands.Context, uye: discord.Member = None): if ctx.interaction: await ctx.defer() target = uye or ctx.author row = await Database.fetch_one( "SELECT * FROM seviye WHERE guild_id = ? AND user_id = ?", (ctx.guild.id, target.id) ) if not row: await ctx.send(f"ℹ️ {target.mention} henüz seviye verisine sahip değil.") return settings = await Database.fetch_one("SELECT * FROM seviye_ayarlar WHERE guild_id = ?", (ctx.guild.id,)) difficulty = settings['zorluk'] if settings and settings.get('zorluk') else 100 level = row['seviye'] xp = row['xp'] xp_for_current = self._xp_for_level(level, difficulty) xp_for_next = self._xp_for_level(level + 1, difficulty) xp_needed = xp_for_next - xp_for_current xp_progress = xp - xp_for_current progress_pct = int((xp_progress / max(xp_needed, 1)) * 100) bar_size = 20 filled = int((xp_progress / max(xp_needed, 1)) * bar_size) bar = "█" * filled + "░" * (bar_size - filled) # Sıralama hesapla all_users = await Database.fetch_all( "SELECT user_id, xp FROM seviye WHERE guild_id = ? ORDER BY xp DESC", (ctx.guild.id,) ) rank = 1 for i, u in enumerate(all_users, 1): if u['user_id'] == target.id: rank = i break embed = discord.Embed( title=f"🏆 Seviye Kartı - {target.display_name}", color=CYBER_GOLD, timestamp=datetime.now() ) embed.set_thumbnail(url=target.display_avatar.url) embed.add_field(name="Seviye", value=f"**{level}**", inline=True) embed.add_field(name="Toplam XP", value=f"**{xp}**", inline=True) embed.add_field(name="Sıralama", value=f"**#{rank}**", inline=True) embed.add_field( name=f"İlerleme ({progress_pct}%)", value=f"`{bar}`\n{xp_progress}/{xp_needed} XP", inline=False ) await ctx.send(embed=embed) @commands.hybrid_command(name="seviye-ayarla", description="Seviye sistemi ayarlarını yapar.") @commands.has_permissions(administrator=True) @app_commands.describe( mesaj_kanali="Seviye atladığında bildirim gönderilecek kanal", zorluk="Zorluk çarpanı (örn: 100 - ne kadar yüksek o kadar yavaş ilerleme)", aktif="Seviye sistemi aktif mi? (1=Açık, 0=Kapalı)" ) async def seviye_ayarla(self, ctx: commands.Context, mesaj_kanali: discord.TextChannel = None, zorluk: int = 100, aktif: int = 1): if ctx.interaction: await ctx.defer() kanal_id = mesaj_kanali.id if mesaj_kanali else 0 await Database.execute( """INSERT OR REPLACE INTO seviye_ayarlar (guild_id, mesaj_kanal_id, aktif, zorluk) VALUES (?, ?, ?, ?)""", (ctx.guild.id, kanal_id, aktif, zorluk) ) await ctx.send(f"✅ Seviye sistemi ayarlandı! Aktif: **{'Açık' if aktif else 'Kapalı'}**, Zorluk: **{zorluk}**") @commands.hybrid_command(name="seviye-ödül-ekle", description="Belirli bir seviyeye ulaşınca verilecek rol ödülü ekler.") @commands.has_permissions(administrator=True) @app_commands.describe(seviye="Hedef seviye", rol="Verilecek rol") async def seviye_odul_ekle(self, ctx: commands.Context, seviye: int, rol: discord.Role): if ctx.interaction: await ctx.defer() await Database.execute( "INSERT OR REPLACE INTO seviye_oduller (guild_id, seviye, rol_id) VALUES (?, ?, ?)", (ctx.guild.id, seviye, rol.id) ) await ctx.send(f"✅ Seviye **{seviye}**'e ulaşanlara **{rol.mention}** rolü verilecek.") @commands.hybrid_command(name="seviye-ödül-sil", description="Bir seviye ödülünü siler.") @commands.has_permissions(administrator=True) @app_commands.describe(seviye="Ödül silinecek seviye") async def seviye_odul_sil(self, ctx: commands.Context, seviye: int): if ctx.interaction: await ctx.defer() await Database.execute( "DELETE FROM seviye_oduller WHERE guild_id = ? AND seviye = ?", (ctx.guild.id, seviye) ) await ctx.send(f"✅ Seviye **{seviye}** ödülü silindi.") @commands.hybrid_command(name="seviye-sıralama", description="Sunucudaki en yüksek seviyeli üyeleri gösterir.") async def seviye_siralama(self, ctx: commands.Context): if ctx.interaction: await ctx.defer() records = await Database.fetch_all( "SELECT user_id, xp, seviye FROM seviye WHERE guild_id = ? ORDER BY xp DESC LIMIT 10", (ctx.guild.id,) ) if not records: await ctx.send("ℹ️ Henüz seviye verisi bulunmamaktadır.") return embed = discord.Embed(title="🏆 Seviye Sıralaması", color=CYBER_GOLD, timestamp=datetime.now()) desc = "" for i, r in enumerate(records, 1): member = ctx.guild.get_member(r['user_id']) name = member.mention if member else f"ID: {r['user_id']}" emoji = "🥇" if i == 1 else "🥈" if i == 2 else "🥉" if i == 3 else f"#{i}" desc += f"{emoji} {name} — Seviye **{r['seviye']}** ({r['xp']} XP)\n" embed.description = desc await ctx.send(embed=embed) @commands.hybrid_command(name="seviye-sıfırla", description="Bir üyenin seviyesini sıfırlar.") @commands.has_permissions(administrator=True) @app_commands.describe(uye="Seviyesi sıfırlanacak üye") async def seviye_sifirla(self, ctx: commands.Context, uye: discord.Member): if ctx.interaction: await ctx.defer() await Database.execute( "UPDATE seviye SET xp = 0, seviye = 0 WHERE guild_id = ? AND user_id = ?", (ctx.guild.id, uye.id) ) await ctx.send(f"✅ {uye.mention} kullanıcısının seviyesi sıfırlandı.") async def setup(bot): await bot.add_cog(Level(bot))