Duck bot incoming…

This commit is contained in:
Shadow15510 2023-06-14 11:54:00 +02:00
parent 89077db935
commit 30073ceafe
6 changed files with 285 additions and 33 deletions

BIN
duck_hunting.db Normal file

Binary file not shown.

View File

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

View File

@ -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 <recherche> [limite=1]\nFait une recherche wikipedia.")
def wiki(bot, msg, text: str, limit: int=1):
if not (1 < limit <= 10):

View File

@ -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 <cmnd> pour plus d'info)")
answer = f"Liste des commandes ({PREFIX}aide <cmnd> 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

View File

@ -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

10
main.py
View File

@ -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")