import random import re import copy import configparser import io from matrix_bot_api.matrix_bot_api import MatrixBotAPI from matrix_bot_api.mregex_handler import MRegexHandler from matrix_bot_api.mcommand_handler import MCommandHandler from matrix_client.client import MatrixClient # Version initiale par Philippe Depriester et Clement Gauche cartes_base = ["As de carreau", "2 de carreau", "3 de carreau", "4 de carreau", "5 de carreau", "6 de carreau", \ "7 de carreau", "8 de carreau", "9 de carreau", "10 de carreau", "Valet de carreau", "Dame de carreau", \ "Roi de carreau", "As de coeur", "2 de coeur", "3 de coeur", "4 de coeur", "5 de coeur", "6 de coeur", \ "7 de coeur", "8 de coeur", "9 de coeur", "10 de coeur", "Valet de coeur", "Dame de coeur", "Roi de coeur", \ "As de pique", "2 de pique", "3 de pique", "4 de pique", "5 de pique", "6 de pique", "7 de pique", "8 de pique", \ "9 de pique", "10 de pique", "Valet de pique", "Dame de pique", "Roi de pique", "As de trefle", "2 de trefle", \ "3 de trefle", "4 de trefle", "5 de trefle", "6 de trefle", "7 de trefle", "8 de trefle", "9 de trefle", \ "10 de trefle", "Valet de trefle", "Dame de trefle", "Roi de trefle", "Joker rouge", "Joker noir"] cartes=list(cartes_base) bot = None class Parser: #Pour parser la ligne de commande def __init__(self, str, nick, room): self._str = str.strip() self._nick = nick self._old = "" self._mtch = "" self._room = room self._arg = {} self._option = [False,False,False,0,0,0,0,0,False,0,0] @property def str(self): return self._str @str.setter def str(self, str): self._str = str @property def nick(self): return self._nick @nick.setter def nick(self, nick): self._nick = nick @property def old(self): return self._old @old.setter def old(self, old): self._old = old @property def mtch(self): return self._mtch @mtch.setter def mtch(self, mtch): self._mtch = mtch @property def room(self): return self._room @room.setter def room(self, room): self._room = room @property def arg(self): return self._arg @arg.setter def arg(self, arg): self._arg = arg @property def option(self): return self._option @option.setter def option(self, option): self._option = option def space(self): if (re.match("^\s", self._str) or re.match("^$", self._str)): return True else: return False def restaure(self): self._str += self._mtch self._old def eat(self,mtch,opt): pattern=r"^(\s*)(" + mtch + r")(.*)" if (re.match(pattern,self._str)): if (opt == 1): self._mtch = re.sub(pattern,r"\2",self._str) self._old += re.sub(pattern,r"\1\2",self._str) self._str = re.sub(pattern,r"\3",self._str) return True return False def card(room, event): room.send_text(cartes_base[random.randrange(0,len(cartes_base))]) def carte(room, event): global cartes args = event['content']['body'].split() if (len(args) > 1): cartes=list(cartes_base) room.send_text("Le paquet est melange") else: if (len(cartes) < 1): cartes=list(cartes_base) room.send_text("Le paquet est melange") i = random.randrange(0,len(cartes)) room.send_text(cartes[i]) cartes.pop(i) def help(room, event): args = event['content']['body'].split() args.pop(0) if (len(args) > 0): if (re.search("roll", args[0])): room.send_text(":roll (+-modifs ou des)\n\n- exemple :roll vr4g3 6d6 - \#g\#r3d6 +2 x3 : lance avec les details 6d6 en relancant les des avec un resultat de 4+ et en gardant les trois meilleurs, puis en retranchant 3d6 sans relancer les 4+ et en gardant tout, enfin ajouter 2. L'operation sera executee trois fois.\n\n- v : details (verbose) du jet\n- n : no add, chaque de est traite separement\n- e : explosif, si un de fait le maximum, on le relance et on additionne\n- f : difficulte a atteindre par de avec option n\n- g : nombre de des conserves\n- r : relance si le de a obtenu au moins ce nombre\n- m : Enleve un succes si ce nombre ou moins est atteint\n- s : seuil a atteindre et niveaux de reussites\n- w : lance un wild die avec les autres.") elif (re.search("sw", args[0])): room.send_text("- :sw : Lance les des en mode Savage Worlds\nVerbose/Noadd/Explosif/Seuil 4/Niveau de reussite 4/Wild Die d6.") elif (re.search("dom", args[0])): room.send_text("- :dom : Lance les dommages en mode Savage Worlds\nVerbose/Explosif/seuil 4/Niveau de reussite 4.") elif (re.search("owod", args[0])): room.send_text("- :owod : Lance les des en mode Ancien Monde des Tenebres\nVerbose/Noadd/Difficulte 6/Relance les 10/Les 1 enleve un succes.") elif (re.search("wod", args[0])): room.send_text("- :wod : Lance les des en mode Nouveau Monde des Tenebres\nVerbose/Noadd/Difficulte 8/Relance les 10.") elif (re.search("ars", args[0])): room.send_text("- :ars : Lance les des en mode Ars Magicka : de de tension\nVerbose/Noadd/Sur un 1, on relance et on double.") elif (re.search("des", args[0])): room.send_text("- :des : Lance des des de desastre\nVerbose/Noadd/Difficulte 10.") elif (re.search("carte", args[0])): room.send_text("- !carte : Tire une carte et la retire du paquet\n- !carte m : remelange le paquet.") elif (re.search("card", args[0])): room.send_text("- !card : tire une carte sans la retirer du paquet.") elif (re.search("liste", args[0])): room.send_text("- !liste [Nombre d'elements souhaites] : retourne ce nombre d'elements de la liste.") else: room.send_text("A venir") else: room.send_text("Commandes disponibles:\n- !card\n- !carte\n- !liste [Nombre d'elements souhaites]\n- :roll \n- :sw \n- :dom \n- :wod \n- :owod \n- :ars \n- :des \n\n- Pour plus de details, tapez !help \n\nRetrouvez Asmodee sur https://git.ombreport.info/nemesis/asmodee_matrix") def roll(result,type,explosif,nb,f,noadd,ars,relance,mitige): # verif type et contenu params? roll = 0 new = 0 moins = 0 if (ars): roll = 1 if (type > 1): tmp = 1 while (ars and tmp == 1): roll *= 2 tmp = random.randrange(1,type+1) roll = ((roll//2)*tmp) else: tmp = random.randrange(1,type+1) roll += int(tmp) #print("roll " + str(roll)) while (explosif and tmp == type): tmp = random.randrange(1,type+1) roll += int(tmp) if (relance != 0 and relance != 1 and relance <= roll): new = 1 if (mitige != 0 and mitige >= roll): moins = 1 result += (' ' if nb>0 else '') + str(roll) if (f != 0 and roll < f): roll = 0 elif (f != 0 and roll >= f and noadd): tmp = int(roll//type) roll = tmp + ((roll - tmp*type) >= 1 if f else 0) roll -= moins #print("fin roll " + str(result) + " " + str(roll) + " " + str(new)) return (result,roll,new) def rolls(result,jet,type,nb,explosif,noadd,wild,f,g,ars,relance,mitige): total = 0 allresult = [] tmp=(type and nb) if (tmp): jet += str(nb)+"d"+str(type) #print(jet) for _ in range(nb): new = 0 result, res1, new = roll(result,type,explosif,nb,f,noadd,ars,relance,mitige) allresult.append(res1) while (new == 1): result, res1, new = roll(result,type,explosif,nb,f,noadd,ars,relance,mitige) allresult.append(res1) if (wild != 0): jet += "w" + str(wild) result, res1, new = roll(result,wild,wild!=1,nb if nb else 0,f,noadd,ars,relance,mitige) allresult.append(res1) result += 'w' #print(allresult) allresult.sort(reverse=True) for i in range((len(allresult)) if (g == 0 and ((f != 0 and noadd) or not noadd)) else (0 if (noadd and f == 0) else g)): if (g == 0 or len(allresult) >= g): total += allresult[i] if allresult[i] else 0 if (noadd and f == 0): total += max(allresult) #print("total : " + str(total)) jet += (("g" + str(g)) if g != 0 else "#g") if g != parser.option[5] else (("g" + str(g)) if g != 0 else "") jet += (("f" + str(f)) if f != 0 else "#f") if f != parser.option[4] else (("f" + str(f)) if f != 0 else "") jet += (("r" + str(relance)) if relance != 0 else "#r") if relance != parser.option[9] else (("r" + str(relance)) if relance != 0 else "") jet += (("m" + str(mitige)) if mitige != 0 else "#m") if mitige != parser.option[9] else (("m" + str(mitige)) if mitige != 0 else "") if (tmp): jet += ("e" if explosif == True else "#e") if explosif != parser.option[0] else "" jet += ("n" if noadd == True else "#n") if noadd != parser.option[1] else "" jet += ("a" if ars == True else "#a") if ars != parser.option[8] else "" print("fin rolls : " + str(result) + "|" + str(total) + "|" + str(jet)) return (result,total,jet) def entryPoint(room, event): global parser text = event['content']['body'] members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" parser = Parser(text,nick,room) print(text) if (parser.eat(":roll",1)): parser.option = [False,False,False,0,0,0,0,0,False,0,0] rollXPoint() elif (parser.eat(":dom",1)): parser.option = [True,False,True,0,0,0,4,4,False,0,0] rollXPoint() elif (parser.eat(":sw",1)): parser.option = [True,True,True,0,0,0,4,4,False,0,0] rollXPoint() elif (parser.eat(":ars",1)): parser.option = [False,True,True,0,0,0,0,0,True,0,0] rollXPoint() elif (parser.eat(":des",1)): parser.option = [False,True,True,0,10,0,0,0,False,0,0] rollXPoint() elif (parser.eat(":wod",1)): parser.option = [False,True,True,0,8,0,0,0,False,10,0] rollXPoint() elif (parser.eat(":owod",1)): parser.option = [False,True,True,0,6,0,0,0,False,10,1] rollXPoint() else: parser.arg["error"] = True if (not parser.arg.get("error",None) and not parser.eat("$",0)): parser.arg["noerror"] = True room.send_text("Je n'ai pas compris " + text) def rollOptionPoint(): global parser while (True): if (parser.eat("[Ee]",1)): parser.option[0] = True elif (parser.eat("#[Ee]",1)): parser.option[0] = False elif (parser.eat("[Nn]",1)): parser.option[1] = True elif (parser.eat("#[Nn]",1)): parser.option[1] = False elif (parser.eat("[Vv]",1)): parser.option[2] = True elif (parser.eat("#[Vv]",1)): parser.option[2] = False elif (parser.eat("[Ww]",1)): if (parser.space()): parser.option[3] = 6 elif (parser.eat(r"\d+",1)): parser.option[3] = int(parser.mtch) else: parser.option[3] = 6 elif (parser.eat("#[Ww]",1)): parser.option[3] = 0 elif (parser.eat("[Ff]",1)): if (parser.space()): parser.option[4] = 6 elif (parser.eat(r"\d+",1)): parser.option[4] = int(parser.mtch) else: parser.option[4] = 6 elif (parser.eat("#[Ff]",1)): parser.option[4] = 0 elif (parser.eat("[Gg]",1)): if (parser.space()): parser.option[5] = 6 elif (parser.eat(r"\d+",1)): parser.option[5] = int(parser.mtch) else: parser.option[5] = 6 elif (parser.eat("#[Gg]",1)): parser.option[5] = 0 elif (parser.eat("[Ss]",1)): if (parser.space()): parser.option[6] = 4 elif (parser.eat(r"\d+",1)): parser.option[6] = int(parser.mtch) else: parser.option[6] = 4 if (parser.eat("[/]",1)): if (parser.space()): parser.option[7] = 4 elif (parser.eat(r"\d+",1)): parser.option[7] = int(parser.mtch) else: parser.option[7] = 4 else: parser.option[7] = 4 elif (parser.eat("#[Ss]",1)): parser.option[6] = 0 parser.option[7] = 0 elif (parser.eat("[Aa]",1)): parser.option[8] = True elif (parser.eat("#[Aa]",1)): parser.option[8] = False elif (parser.eat("[Rr]",1)): if (parser.space()): parser.option[9] = 10 elif (parser.eat(r"\d+",1)): parser.option[9] = int(parser.mtch) else: parser.option[9] = 10 elif (parser.eat("#[Rr]",1)): parser.option[9] = 0 elif (parser.eat("[Mm]",1)): if (parser.space()): parser.option[10] = 1 elif (parser.eat(r"\d+",1)): parser.option[10] = int(parser.mtch) else: parser.option[10] = 1 elif (parser.eat("#[Mm]",1)): parser.option[10] = 0 else: break def dupli(orig): salon = orig.room orig.room = None nouv = copy.deepcopy(orig) nouv.option = [orig.option[0],orig.option[1],orig.option[2],orig.option[3],orig.option[4],orig.option[5],orig.option[6],orig.option[7],orig.option[8],orig.option[9],orig.option[10]] orig.room = salon nouv.room = salon return nouv def rollXPoint(): global parser rollPlusMoinsPoint() if (parser.eat("[xX]",1)): if (parser.eat(r"\d+",1)): tmp = dupli(parser) str = parser.arg["jet"] xtime = int(parser.mtch)-1 xtime = xtime if (xtime < 11) else 10 for _ in range(xtime): parser = dupli(parser) parser.str = str print (parser.str) rollPlusMoinsPoint() parser = tmp else: parser.arg["error"] = True def rollPlusMoinsPoint(): global parser parser.arg["roll_sig"] = True parser.arg["error"] = None result = "" res1 = "" res2 = "" jet = "" rollOptionPoint() #print(parser.option) exp,noa,ver,will,f,g,s,d,ars,r,m = parser.option rollEntityPoint() #print("de " + str(parser.arg.get("roll_nb",None)) + "|" + str(parser.arg.get("roll_typ",None))) if (not parser.arg["error"]): if (not parser.arg.get("roll_sig",True)): jet += "-" result += "-" if (parser.arg.get("roll_typ",None) or parser.arg.get("roll_wil",None)): result += "(" exp2,noa2,ver2,will2,f2,g2,s2,d2,ars2,r2,m2 = parser.option parser.option = [exp,noa,ver,will,f,g,s,d,ars,r,m] result, res1, jet = rolls(result,jet,parser.arg.get("roll_typ",None),parser.arg.get("roll_nb",None),exp2,noa2,will2,f2,g2,ars2,r2,m2) result += " = " + str(res1) + ")" else: jet += str(parser.arg.get("roll_nb",None)) result += str(parser.arg.get("roll_nb",None)) res1 = parser.arg["roll_nb"] #print("prem " + result + " " +str(res1)) if (not parser.arg.get("roll_sig",True)): res1 = -res1 while (parser.eat("[+-]",1)): parser.arg["roll_sig"] = True if (parser.mtch == "-"): parser.arg["roll_sig"] = not parser.arg.get("roll_sig",True) rollEntityPoint() if (not parser.arg.get("error",None)): jet += " +" if parser.arg.get("roll_sig",True) else " -" result += " + " if parser.arg.get("roll_sig",True) else " - " if (parser.arg.get("roll_typ",None) or parser.arg.get("roll_wil",None)): result += "(" exp2,noa2,ver2,will2,f2,g2,s2,d2,ars2,r2,m2 = parser.option parser.option = [exp,noa,ver,will,f,g,s,d,ars,r,m] result, res2, jet = rolls(result,jet,parser.arg.get("roll_typ",None),parser.arg.get("roll_nb",None),exp2,noa2,will2,f2,g2,ars2,r2,m2) result += " = " + str(res2) + ")" else: jet += str(parser.arg.get("roll_nb",None)) result += str(parser.arg.get("roll_nb",None)) res2 = parser.arg.get("roll_nb",None) res1 += res2 if parser.arg.get("roll_sig",None) else -res2 #print("deux " + result + " " +str(res1)) if (res1): if (ver): result = jet + " = (" + result + ") = " + str(res1) else: result = jet + " = " + str(res1) if (d <= 0): d=1 tmp = (res1 - s) // d + 1 result += ("/" + ("0" if (tmp < 0) else str(tmp))) if (s != 0) else "" parser.arg["jet"] = jet parser.room.send_text(parser.nick + " rolls " + ("e" if exp else "") + ("n" if noa else "") + ("v" if ver else "") + ("a" if ars else "") + ("s"+str(s)+"/"+str(d) if (s != 0) else "") + (" " if (exp or noa or ver or s != 0) else "") + result) elif (not parser.arg.get("noerror",False)): parser.room.send_text("match = " + parser.mtch + "\nstr = " + parser.str) parser.room.send_text("Rien compris. Essayez '!help' pour obtenir de l'aide.") def rollEntityPoint(): global parser if (parser.eat("[-+]", 1)): if (parser.mtch == "-"): parser.arg["roll_sig"] = not parser.arg.get("roll_sig",True) rollOptionPoint() rollNbPoint() def rollNbPoint(): global parser parser.arg["roll_nb"] = None if (parser.eat(r"\d+",1)): parser.arg["roll_nb"] = int(parser.mtch) #print("nb " + str(parser.arg.get("roll_nb",1))) rollDPoint() def rollDPoint(): global parser if (parser.eat("[dD]",1)): if (not parser.arg.get("roll_nb",False)): parser.arg["roll_nb"] = 1 parser.arg["roll_bon"] = 0 rollTypePoint() elif (parser.arg.get("roll_nb",False)): parser.arg["roll_typ"] = None else: parser.arg["error"] = True def rollTypePoint(): global parser if (parser.space()): parser.arg["roll_typ"] = 6 elif (parser.eat(r"\d+",1)): parser.arg["roll_typ"] = int(parser.mtch) if (parser.mtch == "1"): parser.option[0] = False else: parser.arg["roll_typ"] = 6 rollOptionPoint() if (not parser.arg.get("roll_nb",False)): parser.arg["error"] = True def reponses(room, phrases): i = random.randrange(0,len(phrases)) room.send_text(phrases[i]) def jdr(room, event): members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" phrases = [] phrases.append("Rock & Role baby!") phrases.append("De toute maniere " + nick + ", les gens ont perdu la foi dans le rolisme.") phrases.append("Bon, c'est quand la prochaine partie " + nick + "?") reponses(room, phrases) def gens(room, event): members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" phrases = [] phrases.append("L'enfer c'est les autres.") phrases.append("Bah " + nick + ", les gens c'est pratique pour jouer aux osselets. Bon faut juste trouver ou mettre la chair ensuite.") phrases.append("Franchement " + nick + ", les gens c'est comme les films X. Plus il y'en a, plus ca part en couilles...") reponses(room, phrases) def va(room, event): members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" phrases = [] phrases.append("Moi ca va si jamais quelqu'un se pose la question...") phrases.append("Quand l'appetit va, tout va " + nick +"!") phrases.append("Attention a " + nick + ", la suite est 'not safe for depression'") reponses(room, phrases) def maman(room, event): members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" phrases = [] phrases.append("On avait dit 'Pas les mamans'!") phrases.append("Oh, c'est pas la mere a boire " + nick + "}!") phrases.append("C'est pas l'homme qui prend la mere, c'est la mere qui prend l'homme...") reponses(room, phrases) def hi_callback(room, event): # Somebody said hi, let's say Hi back members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" phrases = [] phrases.append("Salutations " + nick + "!") phrases.append("Chalut " + nick + " :)") phrases.append("Hello " + nick +"!") phrases.append("Oh non, et voilà de nouveau " + nick + "...") reponses(room, phrases) def echo_callback(room, event): args = event['content']['body'].split() args.pop(0) # Echo what they said back room.send_text(' '.join(args)) def liste(room, event): res = [] members = room.get_joined_members() nick = "" try: #nick = members[event['sender']]['displayname'] nick = [user.get_friendly_name() for user in members if user.user_id == event['sender']][0] except: nick = "Voisin du dessus" args = event['content']['body'].split() args.pop(0) try: nb = int(args[len(args)-1]) args.pop(len(args)-1) except: nb = 1 args = ' '.join(args) list = args.split('/') if (nb <= len(list)): for i in range(nb): id = random.randrange(0,len(list)) res.append(list.pop(id)) room.send_text(nick + " obtient :\n" + '\n'.join(res)) else: room.send_text("Utilisation : !liste [nombre d elements]") def invitations(room_id, state): global bot try: bot.client.join_room(room_id) except: print("Impossible de rejoindre ce salon") def main(): config = configparser.ConfigParser() config.read('asmodee.ini') USERNAME = "" # Bot's username PASSWORD = "" # Bot's password SERVER = "" # Matrix server URL if ('AUTH' in config): USERNAME = config['AUTH']['username'] # Bot's username PASSWORD = config['AUTH']['password'] # Bot's password SERVER = config['AUTH']['server'] # Matrix server URL else: print("Probleme de lecture de configuration asmodee.ini") # Create an instance of the MatrixBotAPI global bot bot = MatrixBotAPI(USERNAME, PASSWORD, SERVER) # Aide help_handler = MCommandHandler("help", help) bot.add_handler(help_handler) # Add a regex handler waiting for keywords and answers #hi_handler = MRegexHandler("[Ss]alut|[Cc]halut|'lut|[Cc]oucou|[Bb]onjour|[Hh]ello", hi_callback) #bot.add_handler(hi_handler) #jdr_handler = MRegexHandler("[Jj]dr|[Rr]pg", jdr) #bot.add_handler(jdr_handler) #gens_handler = MRegexHandler("[Gg]ens", gens) #bot.add_handler(gens_handler) #maman_handler = MRegexHandler("[Mm]aman|[Mm]ere", maman) #bot.add_handler(maman_handler) #va_handler = MRegexHandler("ca va|vas]", va) #bot.add_handler(va_handler) # Add a regex handler waiting for the dice commands and aliases entry_handler = MCommandHandler("", entryPoint, ':') bot.add_handler(entry_handler) # Cartes !card tire une carte d'un paquet plein !carte tire une carte qui disparait du paquet card_handler = MCommandHandler("card", card) bot.add_handler(card_handler) carte_handler = MCommandHandler("carte", carte) bot.add_handler(carte_handler) # Un élément d'une liste liste_handler = MCommandHandler("liste", liste) bot.add_handler(liste_handler) # Invitations bot.client.add_invite_listener(invitations) # Start polling bot.start_polling() # Infinitely read stdin to stall main thread while the bot runs in other threads while True: input() if __name__ == "__main__": main()