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],y
[1]))
307 serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
309 scores
.sort(lambda x
,y
:cmp(x
[0],y
[0]))
310 serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
314 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
316 def on_pubmsg(self
, serv
, ev
):
317 auteur
= irclib
.nm_to_n(ev
.source())
319 message
= ev
.arguments()[0]
321 test
=bot_unicode(message
)
322 except UnicodeBotError
:
323 if not canal
in self
.quiet_channels
:
325 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
328 pour_moi
,message
=self
.pourmoi(serv
,message
)
329 if pour_moi
and message
.split()!=[]:
330 cmd
=message
.split()[0].lower()
332 args
=" ".join(message
.split()[1:])
335 if cmd
in ["meurs","die","crève"]:
336 if auteur
in self
.overops
:
338 log(canal
,auteur
,message
+"[successful]")
340 serv
.privmsg(canal
,"%s: crève !"%(auteur))
341 log(canal
,auteur
,message
+"[failed]")
342 if cmd
in ["meur", "meurt","meurre","meurres"]:
343 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du pluriel : "meurs" (de rien)'%(auteur))
344 if cmd
in ["part","leave","dégage"]:
345 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
346 or auteur
in self
.overops
):
347 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
348 log(canal
,auteur
,message
+"[successful]")
349 self
.chanlist
.remove(canal
)
351 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
352 log(canal
,auteur
,message
+"[failed]")
354 if cmd
in ["deviens","pseudo"]:
355 if auteur
in self
.ops
:
358 log(canal
,auteur
,message
+"[successful]")
360 if cmd
in ["coucou"]:
361 serv
.privmsg(canal
,"%s: coucou"%(auteur))
363 serv
.privmsg(canal
,"%s: pong"%(auteur))
364 if cmd
in ["déconnaissance","deconnaissance","énigme","enigme","encore"]:
365 if canal
in self
.play_channels
:
366 if self
.play_status
.get(canal
,[-1])[0]==0:
368 self
.start_enigme(serv
,canal
)
370 serv
.privmsg(canal
,"%s: Je peux souffler une minute ?"%(auteur))
372 serv
.privmsg(canal
,"%s: Rappel : %s"%(auteur
,self
.play_status
[canal
][1]))
374 serv
.privmsg(canal
,"%s: pas ici…"%(auteur))
380 if self
.play_status
.get(canal
,[-1])[0] in [1,2]:
381 answer_regexp
=self
.play_status
[canal
][3]
382 if re
.match(tolere(answer_regexp
),unicode(message
,"utf8").lower()):
383 answer
=self
.play_status
[canal
][4]
384 serv
.privmsg(canal
,"%s: bravo ! (C'était %s)"%(auteur
,answer
))
385 self
.scoreplus(auteur
)
387 self
.play_status
[canal
]=[0,token
]
388 serv
.execute_delayed(random
.randrange(Ttrig
*5,Ttrig
*10),self
.start_enigme
,(serv
,canal
,token
))
390 def scoreplus(self
,pseudo
):
391 if self
.scores
.has_key(pseudo
):
392 self
.scores
[pseudo
]+=1
394 self
.scores
[pseudo
]=1
396 if __name__
=="__main__":
399 print "Usage : deconnaisseur.py <serveur> [--debug]"
402 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
406 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
407 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
409 serveur
=serveurs
[serveur
]
411 print "Server Unknown : %s"%(serveur)
413 deco
=Deconnaisseur(serveur
,debug
)