# ai command cogs import logging import discord from discord.ext import commands from other_functions import discord_friendly_send, discord_friendly_reply from __future__ import annotations import asyncio import logging from conanjurer_functions import watch, Event log = logging.getLogger("discord") def is_gm(): async def predicate(ctx: commands.Context) -> bool: role_id = ctx.bot.cfg.gm_role_id ok = any(r.id == role_id for r in getattr(ctx.author, "roles", [])) if not ok: await ctx.reply("⛔ Tylko GM.", mention_author=False) return ok return commands.check(predicate) class FromConan(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot self._task: asyncio.Task | None = None async def cog_load(self): self._task = asyncio.create_task(self._run()) async def cog_unload(self): if self._task: self._task.cancel() async def _run(self): await self.bot.wait_until_ready() cfg = self.bot.cfg chat_ch = self.bot.get_channel(cfg.chan_chat) evt_ch = self.bot.get_channel(cfg.chan_events) async def on_event(e: Event): target = chat_ch if e.kind == "chat" else evt_ch if target is not None: # allowed_mentions: nie pinguj nikogo treścią z gry await target.send(e.text, allowed_mentions=discord.AllowedMentions.none()) log.info("Start obserwacji logu (tryb=%s)", cfg.log_mode) await watch(cfg, on_event) class ToConan(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot @commands.command(name="say") @is_gm() async def say(self, ctx: commands.Context, *, message: str): """Discord -> Conan: ogłoszenie widoczne dla wszystkich graczy w grze.""" resp = await self.bot.rcon.command(f"broadcast {message}") await ctx.reply(f"✅ Wysłano do gry. (serwer: `{resp.strip() or 'OK'}`)", mention_author=False) @commands.command(name="players") @is_gm() async def players(self, ctx: commands.Context): """Lista graczy online (RCON listplayers).""" resp = await self.bot.rcon.command("listplayers") await ctx.reply(f"```\n{resp.strip() or 'brak danych'}\n```", mention_author=False) @commands.command(name="kick") @is_gm() async def kick(self, ctx: commands.Context, *, who: str): """Wyrzuć gracza (po nazwie/charname — zależnie od wersji serwera).""" resp = await self.bot.rcon.command(f"kick {who}") await ctx.reply(f"👢 `{resp.strip() or 'OK'}`", mention_author=False) @commands.command(name="rcon") @is_gm() async def raw_rcon(self, ctx: commands.Context, *, cmd: str): """Surowa komenda RCON (dla zaawansowanych GM). Używaj ostrożnie.""" resp = await self.bot.rcon.command(cmd) await ctx.reply(f"```\n{resp.strip() or 'OK'}\n```", mention_author=False) # --- HOOK pod przyszły mod mostu (Chat V2 API) --- @commands.command(name="ogłoś", aliases=["oglos", "rp"]) @is_gm() async def rp_announce(self, ctx: commands.Context, nadawca: str, *, message: str): """Wiadomość RP 'z nadawcą' (np. ogłoszenie w imieniu Króla Khasara). Na samym RCON realizujemy to jako sformatowany broadcast. Gdy dodasz własny mod na Chat V2 API z dedykowaną komendą czatu, podmień tę linię na wywołanie tej komendy (np. 'tot_rp_say '). """ resp = await self.bot.rcon.command(f"broadcast [{nadawca}]: {message}") await ctx.reply(f"📜 Ogłoszono jako **{nadawca}**.", mention_author=False) async def setup(bot: commands.Bot): await bot.add_cog(ToConan(bot)) await bot.add_cog(FromConan(bot))