| 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 |
| |
| 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: |
| |
| 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 |
|
|
| |
| 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 |
|
|
| |
| 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) |
|
|
| |
| 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)) |
|
|