4 # Codé par 20-100 le 23/04/12
6 # Un bot IRC qui sort des déconnaissances
16 config_password
="PatrickSébastien"
17 config_pseudo
="deconnaisseur"
18 config_chanlist
=["#bot","#flood"]
19 config_play_channels
=["#flood"]
20 config_stay_channels
=["#flood","#bot"]
21 config_overops
=["[20-100]","[20-100]_","PEB"]
22 config_ops
=["Nit","Eguel","Harry"]
24 config_source_file_template
="deconnaissances.%s.txt" #il faut rajouter le nom du serveur
25 def get_config_source_file(serveur
):
26 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
27 return config_source_file_template
%(serveurs
[serveur
])
28 ttrig
=120 #time trigger (normalement 120, mais diminué pour les tests)
29 Ttrig
=600 #between two enigms
30 config_time_incompressible
=60 #on peut pas retrigger en dessous de ce temps (60)
31 config_time_incompressible_clue
=60 #on peut pas forcer la demande d'indice en dessous
34 class UnicodeBotError(Exception):
36 def bot_unicode(chain
):
39 except UnicodeDecodeError:
42 def log(channel
,auteur
=None,message
=None):
43 #f=open(config_logfile,"a")
44 #if auteur==message==None:
47 # chain="%s [%s:%s] %s"%(time.strftime("%T"),channel,auteur,message)
55 """Renvoie une regexp plus tolérante"""
56 reg
=unicode(regexp
,"utf8").lower()
57 reg
=reg
.replace(u
"á",u
"(á|a)").replace(u
"à",u
"(à|a)").replace(u
"â",u
"(â|a)").replace(u
"ä",u
"(ä|a)")
58 reg
=reg
.replace(u
"é",u
"(é|e)").replace(u
"è",u
"(è|e)").replace(u
"ê",u
"(ê|e)").replace(u
"ë",u
"(ë|e)")
59 reg
=reg
.replace(u
"í",u
"(í|i)").replace(u
"ì",u
"(ì|i)").replace(u
"î",u
"(î|i)").replace(u
"ï",u
"(ï|i)")
60 reg
=reg
.replace(u
"ó",u
"(ó|o)").replace(u
"ò",u
"(ò|o)").replace(u
"ô",u
"(ô|o)").replace(u
"ö",u
"(ö|o)")
61 reg
=reg
.replace(u
"ú",u
"(ú|u)").replace(u
"ù",u
"(ù|u)").replace(u
"û",u
"(û|u)").replace(u
"ü",u
"(ü|u)")
62 reg
=reg
.replace(u
"ý",u
"(ý|y)").replace(u
"ỳ",u
"(ỳ|y)").replace(u
"ŷ",u
"(ŷ|y)").replace(u
"ÿ",u
"(ÿ|y)")
63 reg
=reg
.replace(u
"œ",u
"(œ|oe)").replace(u
"æ",u
"(æ|ae)")
66 class RefuseError(Exception):
69 class Deconnaisseur(ircbot
.SingleServerIRCBot
):
70 def __init__(self
,serveur
,debug
=False):
71 temporary_pseudo
=config_pseudo
+str(random
.randrange(10000,100000))
72 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
73 temporary_pseudo
,"Un bot irc.[flagellez 20-100, il le mérite]", 10)
76 self
.overops
=config_overops
77 self
.ops
=self
.overops
+config_ops
78 self
.chanlist
=config_chanlist
79 self
.stay_channels
=config_stay_channels
80 self
.play_channels
=config_play_channels
81 self
.play_status
={i
:[0] for i
in self
.play_channels
}
84 def give_me_my_pseudo(self
,serv
):
85 serv
.privmsg("NickServ","RECOVER %s %s"%(config_pseudo
,config_password
))
86 serv
.privmsg("NickServ","RELEASE %s %s"%(config_pseudo
,config_password
))
88 serv
.nick(config_pseudo
)
90 def on_welcome(self
, serv
, ev
):
91 self
.give_me_my_pseudo(serv
)
92 serv
.privmsg("NickServ","identify %s"%(config_password))
95 self
.chanlist
=["#bot"]
96 self
.play_channels
=["#bot"]
97 for c
in self
.chanlist
:
100 for c
in self
.play_channels
:
101 token
=time
.time()-3600
102 self
.play_status
[c
]=[0,token
]
103 serv
.execute_delayed(random
.randrange(ttrig
),self
.start_enigme
,(serv
,c
,token
))
105 def start_enigme(self
,serv
,channel
,token
=None):
106 if self
.play_status
[channel
][0]==0 and channel
in self
.play_channels
:
108 if token
==self
.play_status
[channel
][-1]:
111 if time
.time() > self
.play_status
[channel
][-1]+config_time_incompressible
:
116 enigme
,indice
,answer_reg
,answer
=self
.get_enigme()
117 print "%s; %s; %s; %s"%(enigme
, indice
, answer_reg
, answer
)
118 serv
.privmsg(channel
,enigme
)
120 self
.play_status
[channel
]=[1,enigme
,indice
,answer_reg
,answer
,token
]
121 serv
.execute_delayed(random
.randrange(ttrig
*3,ttrig
*5),self
.give_indice
,(serv
,channel
,token
))
124 def give_indice(self
,serv
,channel
,token
):
125 if self
.play_status
[channel
][0]==1:
127 # c'est donc que l'indice a été demandé
128 if self
.play_status
[channe
][-1]+config_time_incompressible_clue
<time
.time():
129 token
=self
.play_status
[channel
][-1]
130 if self
.play_status
[channel
][-1]==token
:
131 indice
=self
.play_status
[channel
][2]
132 serv
.privmsg(channel
,"indice : %s"%(indice))
133 self
.play_status
[channel
][0]=2
134 serv
.execute_delayed(random
.randrange(ttrig
*1,ttrig
*3),self
.give_answer
,(serv
,channel
,token
))
135 def give_answer(self
,serv
,channel
,token
):
136 if self
.play_status
[channel
][0]==2 and self
.play_status
[channel
][-1]==token
:
137 answer
=self
.play_status
[channel
][4]
138 serv
.privmsg(channel
,"C'était : %s"%(answer))
140 self
.play_status
[channel
]=[0,token
]
141 serv
.execute_delayed(random
.randrange(Ttrig
*5,Ttrig
*10),self
.start_enigme
,(serv
,channel
,token
))
143 def get_enigme(self
):
144 f
=open(get_config_source_file(self
.serveur
))
146 l
=re
.findall("%\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n",t
)
147 l
=[list(i
) for i
in l
if len(i
)==5]
148 l
.sort(lambda x
,y
: cmp(int(x
[4]),int(y
[4])))
149 # on récupère le nombre d'occurrences le plus faible
151 # on garde que ceux qui ont le même nombre d'occurrences
152 l_mini
=[en
for en
in l
if en
[4]==mini
]
153 # on tire au hasard dedans
154 choisi
=random
.randrange(len(l_mini
))
155 enigme
,indice
,answer_reg
,answer
,_
=l_mini
[choisi
]
156 real_index
=l
.index(l_mini
[choisi
])
157 l
[real_index
][4]=str(int(l
[real_index
][4])+1)
158 f
=open(get_config_source_file(self
.serveur
),"w")
159 f
.write("%\n"+"\n%\n".join(["%s\n%s\n%s\n%s\n%s"%(i
[0],i
[1],i
[2],i
[3],i
[4]) for i
in l
])+"\n%")
161 return enigme
,indice
,answer_reg
,answer
163 def pourmoi(self
, serv
, message
):
164 pseudo
=serv
.get_nickname()
166 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
167 return (True,message
[size
+1:].strip(" "))
169 return (False,message
)
171 def on_privmsg(self
, serv
, ev
):
172 message
=ev
.arguments()[0]
173 auteur
= irclib
.nm_to_n(ev
.source())
175 test
=bot_unicode(message
)
176 except UnicodeBotError
:
178 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
180 message
=message
.split()
181 cmd
=message
[0].lower()
184 helpmsg_default
="""Liste des commandes :
185 HELP Affiche ce message d'aide
186 SCORES Affiche les scores"""
188 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
189 LEAVE Faire quitter un channel
190 PLAY Passe un channel en mode "jouer"
191 NOPLAY Passe un channel en mode "ne pas jouer" """
193 SAY Fais envoyer un message sur un chan ou à une personne
194 STAY Ignorera les prochains LEAVE pour un chan
195 NOSTAY Opposé de STAY
196 STATUS Montre l'état courant
198 helpmsg
=helpmsg_default
199 if auteur
in self
.ops
:
201 if auteur
in self
.overops
:
202 helpmsg
+=helpmsg_overops
203 for ligne
in helpmsg
.split("\n"):
204 serv
.privmsg(auteur
,ligne
)
206 if auteur
in self
.ops
:
208 if message
[1] in self
.chanlist
:
209 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
211 serv
.join(message
[1])
212 self
.chanlist
.append(message
[1])
213 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
214 log("priv",auteur
," ".join(message
))
216 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
220 if auteur
in self
.ops
and len(message
)>1:
221 if message
[1] in self
.chanlist
:
222 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
223 serv
.part(message
[1])
224 self
.chanlist
.remove(message
[1])
225 log("priv",auteur
," ".join(message
)+"[successful]")
227 serv
.privmsg(auteur
,"Non, je reste !")
228 log("priv",auteur
," ".join(message
)+"[failed]")
230 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
234 if auteur
in self
.overops
:
236 if message
[1] in self
.stay_channels
:
237 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
238 log("priv",auteur
," ".join(message
)+"[failed]")
240 self
.stay_channels
.append(message
[1])
241 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
242 log("priv",auteur
," ".join(message
)+"[successful]")
244 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
248 if auteur
in self
.overops
:
250 if message
[1] in self
.stay_channels
:
251 self
.stay_channels
.remove(message
[1])
252 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
253 log("priv",auteur
," ".join(message
)+"[successful]")
255 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
256 log("priv",auteur
," ".join(message
)+"[failed]")
260 if auteur
in self
.ops
:
262 if message
[1] in self
.play_channels
:
263 serv
.privmsg(auteur
,"Je play déjà sur %s."%(message
[1]))
264 log("priv",auteur
," ".join(message
)+"[failed]")
266 self
.play_channels
.append(message
[1])
267 self
.play_status
[message
[1]]=[0,time
.time()-3600]
268 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
269 log("priv",auteur
," ".join(message
)+"[successful]")
271 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
275 if auteur
in self
.ops
:
277 if message
[1] in self
.play_channels
:
278 self
.play_channels
.remove(message
[1])
279 serv
.privmsg(auteur
,"Play channels : "+" ".join(self
.play_channels
))
280 log("priv",auteur
," ".join(message
)+"[successful]")
282 serv
.privmsg(auteur
,"Je ne play pas sur %s."%(message
[1]))
283 log("priv",auteur
," ".join(message
)+"[failed]")
286 elif cmd
in ["states","status"]:
287 if auteur
in self
.overops
:
288 for k
in self
.play_status
.keys():
289 serv
.privmsg(auteur
,"%s : %s"%(k
,"; ".join([str(i
) for i
in self
.play_status
[k
]])))
291 if auteur
in self
.overops
and len(message
)>2:
292 serv
.privmsg(message
[1]," ".join(message
[2:]))
293 log("priv",auteur
," ".join(message
))
294 elif len(message
)<=2:
295 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
299 if auteur
in self
.overops
:
302 serv
.privmsg(auteur
,"Votre score : %s"%(self
.scores
.get(auteur
,0)) )
304 scores
=self
.scores
.items()
306 scores
.sort(lambda x
,y
:cmp(x
[1].lower(),y
[1].lower()))
308 serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
310 scores
.sort(lambda x
,y
:cmp(x
[0],y
[0]))
312 serv
.privmsg(auteur
,"Scores by pseudo : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
316 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
318 def on_pubmsg(self
, serv
, ev
):
319 auteur
= irclib
.nm_to_n(ev
.source())
321 message
= ev
.arguments()[0]
323 test
=bot_unicode(message
)
324 except UnicodeBotError
:
325 if not canal
in self
.quiet_channels
:
327 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
330 pour_moi
,message
=self
.pourmoi(serv
,message
)
331 if pour_moi
and message
.split()!=[]:
332 cmd
=message
.split()[0].lower()
334 args
=" ".join(message
.split()[1:])
337 if cmd
in ["meurs","die","crève"]:
338 if auteur
in self
.overops
:
340 log(canal
,auteur
,message
+"[successful]")
342 serv
.privmsg(canal
,"%s: crève !"%(auteur))
343 log(canal
,auteur
,message
+"[failed]")
344 if cmd
in ["meur", "meurt","meurre","meurres"]:
345 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du pluriel : "meurs" (de rien)'%(auteur))
346 if cmd
in ["part","leave","dégage"]:
347 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
348 or auteur
in self
.overops
):
349 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
350 log(canal
,auteur
,message
+"[successful]")
351 self
.chanlist
.remove(canal
)
353 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
354 log(canal
,auteur
,message
+"[failed]")
356 if cmd
in ["deviens","pseudo"]:
357 if auteur
in self
.ops
:
360 log(canal
,auteur
,message
+"[successful]")
362 if cmd
in ["coucou"]:
363 serv
.privmsg(canal
,"%s: coucou"%(auteur))
365 serv
.privmsg(canal
,"%s: pong"%(auteur))
366 if cmd
in ["déconnaissance","deconnaissance","énigme","enigme","encore"]:
367 if canal
in self
.play_channels
:
368 if self
.play_status
.get(canal
,[-1])[0]==0:
370 self
.start_enigme(serv
,canal
)
372 serv
.privmsg(canal
,"%s: Je peux souffler une minute ?"%(auteur))
374 serv
.privmsg(canal
,"%s: Rappel : %s"%(auteur
,self
.play_status
[canal
][1]))
376 serv
.privmsg(canal
,"%s: pas ici…"%(auteur))
382 if self
.play_status
.get(canal
,[-1])[0] in [1,2]:
383 answer_regexp
=self
.play_status
[canal
][3]
384 if re
.match(tolere(answer_regexp
),unicode(message
,"utf8").lower()):
385 answer
=self
.play_status
[canal
][4]
386 serv
.privmsg(canal
,"%s: bravo ! (C'était %s)"%(auteur
,answer
))
387 self
.scoreplus(auteur
)
389 self
.play_status
[canal
]=[0,token
]
390 serv
.execute_delayed(random
.randrange(Ttrig
*5,Ttrig
*10),self
.start_enigme
,(serv
,canal
,token
))
392 def scoreplus(self
,pseudo
):
393 if self
.scores
.has_key(pseudo
):
394 self
.scores
[pseudo
]+=1
396 self
.scores
[pseudo
]=1
398 if __name__
=="__main__":
401 print "Usage : deconnaisseur.py <serveur> [--debug]"
404 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
408 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
409 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
411 serveur
=serveurs
[serveur
]
413 print "Server Unknown : %s"%(serveur)
415 deco
=Deconnaisseur(serveur
,debug
)