From 30073ceafea7bf27d6f6394df85c276ab95aff7a Mon Sep 17 00:00:00 2001 From: Shadow15510 Date: Wed, 14 Jun 2023 11:54:00 +0200 Subject: [PATCH] =?UTF-8?q?Duck=20bot=20incoming=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- duck_hunting.db | Bin 0 -> 20480 bytes fun_cmnds.py | 255 +++++++++++++++++++++++++++++++++++++++++++++--- glados_cmnds.py | 17 +++- irc_api/api.py | 32 +++--- irc_api/irc.py | 4 +- main.py | 10 +- 6 files changed, 285 insertions(+), 33 deletions(-) create mode 100644 duck_hunting.db diff --git a/duck_hunting.db b/duck_hunting.db new file mode 100644 index 0000000000000000000000000000000000000000..360b70a60029d664138f34263482d9b33734903e GIT binary patch literal 20480 zcmeI(!A{gb7zgl~c9qU1%Xk1uFEHtWKr}|8o}of9go?0~L=L7Ib_cgWTWm|jgBRlq z$(?r~;U(|^@a*i?65`eq2f+L%nNB-j=bP#8)@i!A;YWoMyJ;57LcAc42&H5}2tw#r zLdb(Z)zIyrnOy|WfSA;##wIl9l!_=&zifdB*`009U<00Izz00eGF zfM1$FZf9o9`o9YBOZs8>*}g4}k4)G${oX0$&VlM3C56h$qp{fb+`too``Y(}Q+7IH zrpcT{#>!!V_dXD7?{wYreX-;%yIX!B3Kbtd)%V0{qP{q6Wi9aDc5A#lXs2BP7{LlNtKW0kiHNnB+qCDKwxmCA* z@OpdYt=rxftKRlZ2{GH8)v%MpxK+=S#}6mwZAzk~tB&(e2m0kclt)E6xDHF$aIS1k zJ*dTh5`&)_{G6XwInY7?0uX=z1Rwwb2tWV=5P$##AaI8S#tb$^DPxvpxt%OslzEgk z8e^2%R2Pd{n?2c0KeG|j?0?7~uUUFi_Zj?x@C*K{CX6l!KmY;|fB*y_009U<00Izz z00i!lK+Bw>S9=5oGi_Gx4cwzgz)~Rq0SG_<0uX=z1Rwwb2tWV=5V)B@|6l&=|MuT3 d8%9F_0uX=z1Rwwb2tWV=5P$##AaJJyegmrTjJp5; literal 0 HcmV?d00001 diff --git a/fun_cmnds.py b/fun_cmnds.py index 7d79b9b..7e5e985 100644 --- a/fun_cmnds.py +++ b/fun_cmnds.py @@ -2,23 +2,250 @@ from irc_api import api from irc_api.api import auto_help from random import randint, choice +import sqlite3 -@api.every(30, desc="Fait apparaître un canard de manière aléatoire") + +GAME_CHANNEL = "#glados" + + +def get_hunter(name: str): + def get(): + table = sqlite3.connect("duck_hunting.db") + c = table.cursor() + data = c.execute(f""" + SELECT * FROM hunter + WHERE name="{name}" + """).fetchall() + table.close() + return data + + data = get() + if not data: + add_hunter(name) + data = get() + + return list(data[0][1:]) + + +def add_hunter(name: str): + table = sqlite3.connect("duck_hunting.db") + c = table.cursor() + c.execute(f""" + INSERT INTO hunter (name) + VALUES ("{name}") + """) + table.commit() + table.close() + + +def del_hunter(name: str): + table = sqlite3.connect("duck_hunting.db") + c = table.cursor() + c.execute(f""" + DELETE FROM hunter + WHERE name="{name}" + """) + table.commit() + table.close() + + +def modify_hunter(name: str, **kwargs): + args = "" + for var, value in kwargs.items(): + args += f"{var}={value}, " + + table = sqlite3.connect("duck_hunting.db") + c = table.cursor() + c.execute(f""" + UPDATE hunter + SET {args[:-2]} + WHERE name="{name}" + """) + table.commit() + table.close() + + + +@api.every(30, desc="Fait apparaître un canard de manière aléatoire.") def pop_duck(bot): - if randint(1, 10) == 1: - ducks = ("Coin coin ! 🦆", "Couac ! 🦆") - bot.nb_ducks += 1 - bot.send("#glados", choice(ducks)) - if randint(1, 10) == 1 and bot.nb_ducks > 1: - bot.send("#glados", "Le canard est parti…") - bot.nb_ducks -= 1 + if randint(1, 100) <= 20: + if bot.troll_duck > 0 and randint(1, 4) <= 3: + bot.troll_duck -= 1 + bot.ducks_history.append(2) + ducks = ("crr… Coin coin ! 🦆", "Couac crr… ! 🦆") + elif randint(1, 10) == 1: + ducks = ("COIN COIN ! 🦆", "COUAC ! 🦆") + bot.ducks_history.append(1) + else: + ducks = ("Coin coin ! 🦆", "Couac ! 🦆") + bot.ducks_history.append(0) + + bot.send(GAME_CHANNEL, choice(ducks)) + if randint(1, 100) <= 15 and len(bot.ducks_history) > 1: + ducks = ("Le canard est parti…", "Le canard s'est envolé…") + bot.send(GAME_CHANNEL, "Le canard est parti…") + bot.ducks_history.pop(0) -@api.channel("#glados") -@api.command("pan", desc="Tirer sur un canard") +@api.channel(GAME_CHANNEL) +@api.command("pan", desc="Tirer sur un canard.") def fire(bot, msg): - if bot.nb_ducks > 0: - bot.nb_ducks -= 1 - bot.send("#glados", "Touché !") + money, ammo, ammo_in_chamber, _, has_scope, grease, is_jammed = get_hunter(msg.author) + + if ammo_in_chamber <= 0: + bot.send(GAME_CHANNEL, "Chambre vide ! Il faut recharger. 😉") + return + + if is_jammed: + bot.send(GAME_CHANNEL, "Votre fusil est enrayé !") + return + + if grease > 0: + grease -= 1 + elif grease == 0 and randint(1, 100) < 33: + is_jammed = 1 + + if len(bot.ducks_history) > 0: + is_hit = randint(1, 100) + if has_scope: + has_scope -= 1 + is_hit = randint(1, 15) + + if is_hit <= 80: + duck_type = bot.ducks_history.pop(-1) + money += 2 + if duck_type == 2: + hit = ("Oh un canard en plastique", "Peeww… CLONG") + bot.send(GAME_CHANNEL, "Canard mécanique ! [munition -1]\n" + choice(hit)) + elif duck_type == 1 or is_hit < 10: + money += 2 + hit = ("C'était un super canard !", "Ouh la belle bête !", "ÇA c'est du canard.") + bot.send(GAME_CHANNEL, "Super canard touché ! [argent +4, munition -1]\n" + choice(hit)) + if duck_type == 0: + hit = ("Touché !", "Et un canard en moins !", "You dit it bro!", "Joli tir !", "Peeww !") + bot.send(GAME_CHANNEL, "Canard touché ! [argent +2, munition -1]\n" + choice(hit)) + + + else: + fail = ("Et le canard est toujours vivant…", "Mais… Pourquoi tu tires à côté ?", "Il est pas passé loin de la vieille celui-là !") + bot.send(GAME_CHANNEL, "Tir raté… [munition -1]\n" + choice(fail)) + else: - bot.send("#glados", "Euh va check ta vue stp…") + no_ducks = ("Euh, va faire vérifier ta vue s'il-te-plaît.", "Il est où le canard ? Il est bien caché ?", "Et une grand mère en moins ! Une ! Wait…", "Un canard ne hurle pas comme ça.", "Joli tir… Mais ce n'était pas un canard…") + bot.send(GAME_CHANNEL, "Aucun canard en vue. [munition -1]\n" + choice(no_ducks)) + + modify_hunter(msg.author, money=money, ammo=ammo, ammo_in_chamber=ammo_in_chamber - 1, has_scope=has_scope, grease=grease, is_jammed=is_jammed) + + +@api.channel(GAME_CHANNEL) +@api.command("recharge", alias=("reload",), desc="Fait monter une balle du chargeur dans la chambre") +def reload(bot, msg): + ammo, ammo_in_chamber, max_ammo = get_hunter(msg.author)[1: 4] + ammo_to_fill = max_ammo - ammo_in_chamber + + if ammo_to_fill == 0: + bot.send(GAME_CHANNEL, "Ton arme est déjà chargée.") + elif ammo > 0: + if ammo >= ammo_to_fill: + ammo_filled = ammo_to_fill + else: + ammo_filled = ammo + modify_hunter(msg.author, ammo=ammo - ammo_filled, ammo_in_chamber=ammo_in_chamber + ammo_filled) + bot.send(GAME_CHANNEL, f"{msg.author} a rechargé son arme.") + else: + bot.send(GAME_CHANNEL, f"Plus de munitions ! Va voir le magasin pour en acheter. 😉") + + +@api.channel(GAME_CHANNEL) +@api.command("stat", alias=("info",), desc="Affiche les statistiques du joueur.") +def stat(bot, msg): + money, ammo, ammo_in_chamber, max_ammo, has_scope, grease, is_jammed = get_hunter(msg.author) + + additionnal_infos = "" + if has_scope: + additionnal_infos += "[lunette installée] " + if is_jammed: + additionnal_infos += "[fusil enrayé] " + + text = f"Statistiques de {msg.author} {additionnal_infos[:-1]}\n" + text += f" │ argent : {money}\n" + text += f" │ chargeur : {ammo_in_chamber} / {max_ammo}\n" + text += f" │ munitions : {ammo}\n" + text += f" │ graisse : {grease}" + + bot.send(GAME_CHANNEL, text) + + +@api.channel(GAME_CHANNEL) +@api.command("nettoyer", alias=("clean",), desc="Nettoie le fusil.") +def clear(bot, msg): + grease, is_jammed = get_hunter(msg.author)[5: 7] + + if is_jammed: + if grease: + bot.send(GAME_CHANNEL, f"{msg.author} a nettoyé son fusil !") + grease -= 1 + is_jammed = 0 + else: + bot.send(GAME_CHANNEL, "Vous devez acheter de la graisse pour pouvoir nettoyer votre fusil.") + else: + bot.send(GAME_CHANNEL, "Votre fusil est déjà en bon état.") + + modify_hunter(msg.author, grease=grease, is_jammed=is_jammed) + +@api.channel("Duck") +@api.command("duck", desc="Fait apparaître un canard mécanique.") +def fake_duck(bot, msg): + bot.troll_duck += 1 + bot.send(msg.author, "Un canard mécanique apparaîtra… ou pas !") + + +@api.channel(GAME_CHANNEL) +@api.command("reset", desc="Réinitialise le profil du joueur") +def reset(bot, msg): + hunter = get_hunter(msg.author)[:3] + bot.send(GAME_CHANNEL, f"Le profil de {msg.author} a été réinitialisé.") + del_hunter(msg.author) + + +@api.channel(GAME_CHANNEL) +@api.command("achat", alias=("magasin", "shop"), desc="Acheter des munitions et accessoires.\nLancer la commande sans arguments pour voir le magasin.") +def achat(bot, msg, article: str=""): + def get_spec(spec): + fields = ("argent", "munition", "munition dans la chambre", "capacité chargeur", "lunette de visée", "graisse") + text = "[" + for field_index, value in spec.items(): + text += f"{fields[field_index]} {('-', '+')[abs(value) == value]}{abs(value)}, " + return text[:-2] + "]" + + hunter = get_hunter(msg.author) + db_fields = ("money", "ammo", "ammo_in_chamber", "max_ammo", "has_scope", "grease") + + availables_articles = { + "chargeur": ("Ajoute cinq balles à ton inventaire", "un chargeur", {0: -4, 1: 5}), + "balle": ("Ajoute une balle à ton inventaire", "une balle", {0: -1, 1: 1}), + "capacité": ("Augmente la capacité du chargeur d'une balle", "un chargeur haute capacité", {0: -5, 3: 1}), + "viseur": ("Votre prochain tir touchera forcément un canard.", "une lunette de visée", {0: -3, 4: 1}), + "graisse": ("Permet de nettoyer son arme et de limiter le risque d'enrayement.", "une boîte de graisse pour fusil", {0: -3, 5: 5}) + } + + if article: + article = article.lower() + if article in availables_articles.keys(): + args = availables_articles[article] + + # not enough money + if hunter[0] < abs(args[2][0]): + bot.send(GAME_CHANNEL, f"Vous n'avez pas assez d'argent pour acheter {args[1]} {get_spec(args[2])}.") + else: + bot.send(GAME_CHANNEL, f"Vous avez acheté {args[1]} {get_spec(args[2])}.") + for index, value in args[2].items(): + hunter[index] += value + modify_hunter(msg.author, **{field: hunter[i] for i, field in enumerate(db_fields)}) + else: + msg = "Liste des articles disponibles :\n" + msg += "".join([ + f" | {article} : {args[0]} {get_spec(args[2])}\n" + for article, args in availables_articles.items() + ]) + bot.send(GAME_CHANNEL, msg) diff --git a/glados_cmnds.py b/glados_cmnds.py index 3437b24..4aa4bf9 100644 --- a/glados_cmnds.py +++ b/glados_cmnds.py @@ -4,7 +4,7 @@ import requests import time from irc_api import api -from irc_api.api import auto_help +# from irc_api.api import auto_help @api.on(lambda m: isinstance(re.match(r"(.*)(bonjour|coucou|salut|hey|hello|hi|yo) glados(.*)", m.text, re.IGNORECASE), re.Match)) @@ -35,6 +35,21 @@ def hour(bot, msg): bot.send(msg.to, f"Il est très exactement {now}.") +@api.on(lambda m: "mec" in m.text.lower() and "glados" in m.text.lower()) +def react_on_mec(bot, msg): + bot.send(msg.to, "Chuis pas ton mec, mon pote.") + + +@api.on(lambda m: "pote" in m.text.lower() and "glados" in m.text.lower()) +def react_on_pote(bot, msg): + bot.send(msg.to, "Chuis pas ton pote, mon gars.") + + +@api.on(lambda m: "gars" in m.text.lower() and "glados" in m.text.lower()) +def react_on_gars(bot, msg): + bot.send(msg.to, "Chuis pas ton gars, mec.") + + @api.command("wiki", desc="wiki [limite=1]\nFait une recherche wikipedia.") def wiki(bot, msg, text: str, limit: int=1): if not (1 < limit <= 10): diff --git a/irc_api/api.py b/irc_api/api.py index d758bea..14fb990 100644 --- a/irc_api/api.py +++ b/irc_api/api.py @@ -15,7 +15,7 @@ def command(name, alias=(), desc=""): return Command( name=name, func=func, - events=[lambda m: True in [m.text.startswith(PREFIX + cmd) for cmd in alias]], + events=[lambda m: True in [m.text == PREFIX + cmd or m.text.startswith(PREFIX + cmd + " ") for cmd in alias]], desc=desc, cmnd_type=1 ) @@ -103,6 +103,10 @@ class Command: return self.func(self.bot, msg, *args) +class WrongArg: + """If the transtyping has failed and the argument has no default value.""" + + class Bot: """Run the connexion between IRC's server and V5 one. @@ -155,10 +159,10 @@ class Bot: if commands_modules: self.add_commands_modules(*commands_modules) - def start(self): + def start(self, nick: str): """Starts the bot and connect it to the given IRC and V5 servers.""" # Start IRC - self.irc.connexion(self.auth[0], self.auth[1]) + self.irc.connexion(self.auth[0], self.auth[1], nick) # Join channels for channel in self.channels: @@ -210,8 +214,9 @@ class Bot: while True: command.func(bot) time.sleep(command.events) + logging.info("auto call : %s", command.name) - self.threads.append(Thread(target=timed_func, args=(self,))) + self.threads.append(Thread(target=lambda bot: timed_func(bot), args=(self,))) self.threads[-1].start() else: self.callbacks[command.name] = command @@ -249,17 +254,15 @@ def auto_help(bot, msg, fct_name: str=""): """Aide des commandes disponibles.""" if fct_name and fct_name in bot.commands_help.keys(): cmnd = bot.commands_help[fct_name] - if cmnd.cmnd_type == 1: - bot.send(msg.to, f"Aide sur la commande : {bot.prefix}{fct_name}") - else: - bot.send(msg.to, f"Aide sur la commande : {fct_name}") - + answer = f"Aide sur la commande : {bot.prefix}{fct_name}\n" for line in bot.commands_help[fct_name].desc.splitlines(): - bot.send(msg.to, f" │ {line}") + answer += f" │ {line}\n" else: - bot.send(msg.to, f"Liste des commandes ({PREFIX}aide pour plus d'info)") + answer = f"Liste des commandes ({PREFIX}aide pour plus d'info)\n" for cmnd_name in bot.commands_help.keys(): - bot.send(msg.to, f" - {cmnd_name}") + answer += f" - {cmnd_name}\n" + + bot.send(msg.to, answer) def parse(message): @@ -300,13 +303,14 @@ def check_args(func, *input_args): if len(input_args) < required_args: return None + wrong_arg = WrongArg() converted_args = [] for index, arg_type in enumerate(annotations.values()): # construction of a tuple (type, default_value) for each expected argument if index + 1 > required_args: check_args = (arg_type, defaults[index - required_args]) else: - check_args = (arg_type, None) + check_args = (arg_type, wrong_arg) # transtypes each given arguments to its target type if len(input_args) > index: @@ -315,7 +319,7 @@ def check_args(func, *input_args): converted_args.append(check_args[1]) # if an argument has no default value and transtyping has failed - if None in converted_args: + if wrong_arg in converted_args: return None return converted_args diff --git a/irc_api/irc.py b/irc_api/irc.py index 73f2f31..202320a 100644 --- a/irc_api/irc.py +++ b/irc_api/irc.py @@ -80,7 +80,7 @@ class IRC: self.__handler = Thread(target=self.__handle) # Public methods - def connexion(self, nick: str, password: str): + def connexion(self, username: str, password: str, nick: str): """Start the IRC layer. Manage authentication as well. Parameters @@ -95,7 +95,7 @@ class IRC: self.send(f"USER {nick} * * :{nick}") self.send(f"NICK {nick}") self.waitfor(lambda m: "NOTICE" in m and "/AUTH" in m) - self.send(f"AUTH {nick}:{password}") + self.send(f"AUTH {username}:{password}") self.waitfor(lambda m: "You are now logged in" in m) self.connected = True diff --git a/main.py b/main.py index 0ed33af..5ddf7cf 100755 --- a/main.py +++ b/main.py @@ -22,7 +22,13 @@ LOG_FORMAT = "%(asctime)s [%(levelname)s] <%(filename)s> %(funcName)s: %(message logging.basicConfig(format=LOG_FORMAT, level=logging.DEBUG) class MyBot(api.Bot): - nb_ducks = 0 + # ducks_history + # 0 : normal duck + # 1 : super duck + # 2 : mecanics duck + ducks_history = [] + # nb_ducks = 0 + troll_duck = 0 glados = MyBot( @@ -34,4 +40,4 @@ glados = MyBot( ) -glados.start() +glados.start("Duck")