]> gitweb.pimeys.fr Git - bots/deconnaisseur.git/blob - deconnaisseur.py
centimètre-?haies
[bots/deconnaisseur.git] / deconnaisseur.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 23/04/12
5
6 # Un bot IRC qui sort des déconnaissances
7
8 import threading
9 import random
10 import time
11 import pickle
12 import re
13 import signal
14 import sys
15 import os
16 from remplace_accents import remplace_accents
17
18 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
19 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
20 import irclib
21 import ircbot
22
23
24 config_password="PatrickSébastien"
25 config_pseudo="deconnaisseur"
26 config_chanlist=["#bot","#flood"]
27 config_play_channels=["#flood"]
28 config_stay_channels=["#flood","#bot"]
29 config_overops=["[20-100]","[20-100]_","PEB"]
30 config_ops=["Nit","Eguel","Harry"]
31
32 config_source_file="deconnaissances.txt"
33 config_played_file_template="played.%s.txt" #il faut rajouter le nom du serveur
34 def get_config_played_file(serveur):
35 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
36 return config_played_file_template%(serveurs[serveur])
37 ttrig=120 #time trigger (normalement 120, mais diminué pour les tests)
38 Ttrig=600 #between two enigms (600)
39 config_time_incompressible=15 #on peut pas retrigger en dessous de ce temps (60)
40 config_time_incompressible_clue=60 #on peut pas forcer la demande d'indice en dessous
41
42 config_score_file="scores.pickle"
43
44 config_tag_triggers=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut"]
45 config_tag_actions=[u"se tait",u"ferme sa gueule",u"se la ferme",u"la ferme"]
46 config_tag_answers=[u"J'me tais si j'veux !",
47 u"Je t'entends pas :°",
48 u"Héhé, try again",
49 u"Non, j'ai pas envie",
50 u"Peut-être quand toi tu la fermeras, et encore…"]
51
52 config_level2=[]
53 config_level3=["[20-100]","Petite-Peste","PEB","Constance","pika"]
54
55 config_debug_stdout = True
56 config_logfile_template="deconnaisseur.%s.log"
57 def get_config_logfile(serveur):
58 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
59 return config_logfile_template%(serveurs[serveur])
60
61 config_quit_messages=[u"Se décrocher la mâchoire, pas cuit bras d'oiseau ou métalld précieuxld"]
62
63 config_leave_messages=[u"On continuera à jouer plus tard ;)"]
64
65 # Quand personne ne cause, on finit par se taire
66 # temps au bout duquel, si personne n'a parlé, on se tait
67 config_idle_time=20*60
68 # liste des bots, qui ne sont pas considérés comme de l'activité
69 config_idle_bots=["deconnaisseur","Basile","historien","hung","salesman","Shadobot","Wen","___","Sanctuary","Saturnin"]
70
71 class UnicodeBotError(Exception):
72 pass
73 def bot_unicode(chain):
74 try:
75 unicode(chain,"utf8")
76 except UnicodeDecodeError:
77 raise UnicodeBotError
78
79 def log(serveur,channel,auteur=None,message=None):
80 f=open(get_config_logfile(serveur),"a")
81 if auteur==message==None:
82 # alors c'est que c'est pas un channel mais juste une ligne de log
83 chain="%s %s"%(time.strftime("%F %T"),channel)
84 else:
85 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
86 f.write(chain+"\n")
87 if config_debug_stdout:
88 print chain
89 f.close()
90
91
92 def reussi(message,answer,answer_regexp,auteur):
93 if auteur in config_level3:
94 return answer in message
95 if auteur in config_level2:
96 return remplace_accents(answer) in message
97 else:
98 if re.match(remplace_accents(answer_regexp).lower(),remplace_accents(message).lower()):
99 return True
100
101 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
102 if case_sensitive:
103 chain=unicode(chain,"utf8")
104 else:
105 chain=unicode(chain,"utf8").lower()
106 allmatches="("+"|".join(matches)+")"
107 reg=(avant+allmatches+apres).lower()
108 o=re.match(reg,chain)
109 return o
110
111 def is_tag(chain):
112 return is_something(chain,config_tag_triggers)
113
114 class RefuseError(Exception):
115 pass
116
117 class Deconnaisseur(ircbot.SingleServerIRCBot):
118 def __init__(self,serveur,debug=False):
119 temporary_pseudo=config_pseudo+str(random.randrange(10000,100000))
120 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
121 temporary_pseudo,"Un bot irc.[flagellez 20-100, il le mérite]", 10)
122 self.debug=debug
123 self.serveur=serveur
124 self.overops=config_overops
125 self.ops=self.overops+config_ops
126 self.chanlist=config_chanlist
127 self.stay_channels=config_stay_channels
128 self.play_channels=config_play_channels
129 self.play_status={i:[0] for i in self.play_channels}
130 self.last_activity={}
131 self.quiet_channels=[]
132
133 def give_me_my_pseudo(self,serv):
134 serv.privmsg("NickServ","RECOVER %s %s"%(config_pseudo,config_password))
135 serv.privmsg("NickServ","RELEASE %s %s"%(config_pseudo,config_password))
136 time.sleep(0.3)
137 serv.nick(config_pseudo)
138
139 def on_welcome(self, serv, ev):
140 self.serv=serv # ça serv ira :)
141 self.give_me_my_pseudo(serv)
142 serv.privmsg("NickServ","identify %s"%(config_password))
143 log(self.serveur,"Connected")
144 if self.debug:
145 self.chanlist=["#bot"]
146 self.play_channels=["#bot"]
147 for c in self.chanlist:
148 log(self.serveur,"JOIN %s"%(c))
149 serv.join(c)
150 self.update_activity(c,"") # la chaîne vide ne sera jamais un nom de bot et donc marchera toujours
151 for c in self.play_channels:
152 token=time.time()-3600
153 self.play_status[c]=[0,token]
154 serv.execute_delayed(random.randrange(ttrig),self.start_enigme,(serv,c,token))
155
156 def start_enigme(self,serv,channel,token=None):
157 # On reste silencieux si lechan n'est pas actif
158 if not self.is_active(channel):
159 serv.execute_delayed(ttrig*5,self.start_enigme,(serv,channel,token))
160 return
161 if self.play_status[channel][0]==0 and channel in self.play_channels:
162 ok="skip"
163 if token==self.play_status[channel][-1]:
164 ok="do_it"
165 if token==None:
166 if time.time() > self.play_status[channel][-1]+config_time_incompressible:
167 ok="do_it"
168 else:
169 ok="refuse"
170 if ok=="do_it":
171 enigme,indice,answer_reg,answer=self.get_enigme()
172 log(self.serveur,channel,u"$Énigme$".encode("utf8"),("%s; %s; %s; %s"%(enigme, indice, answer_reg, answer)).encode("utf8"))
173 serv.privmsg(channel,enigme.encode("utf8"))
174 token=time.time()
175 self.play_status[channel]=[1,enigme,indice,answer_reg,answer,token]
176 serv.execute_delayed(random.randrange(ttrig*3,ttrig*5),self.give_indice,(serv,channel,token))
177 elif ok=="refuse":
178 raise RefuseError
179 def give_indice(self,serv,channel,token):
180 if self.play_status[channel][0]==1:
181 if token==None:
182 # c'est donc que l'indice a été demandé
183 if self.play_status[channel][-1]+config_time_incompressible_clue<time.time():
184 token=self.play_status[channel][-1]
185 if self.play_status[channel][-1]==token:
186 indice=self.play_status[channel][2]
187 serv.privmsg(channel,"indice : %s"%(indice).encode("utf8"))
188 self.play_status[channel][0]=2
189 serv.execute_delayed(random.randrange(ttrig*1,ttrig*3),self.give_answer,(serv,channel,token))
190 def give_answer(self,serv,channel,token):
191 if self.play_status[channel][0]==2 and self.play_status[channel][-1]==token:
192 answer=self.play_status[channel][4]
193 serv.privmsg(channel,"C'était : %s"%(answer).encode("utf8"))
194 token=time.time()
195 self.play_status[channel]=[0,token]
196 serv.execute_delayed(random.randrange(Ttrig*5,Ttrig*10),self.start_enigme,(serv,channel,token))
197
198 def get_enigme(self):
199 # on récupère les déconnaissances
200 f=open(config_source_file)
201 t=f.read()
202 f.close()
203 l=re.findall("%\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n",t)
204 dec={int(i[0]):list(i[1:]) for i in l if len(i)==5}
205 # on va chercher combien de fois elles ont été jouées
206 played_file=get_config_played_file(self.serveur)
207 f=open(played_file)
208 t=f.read()
209 f.close()
210 l=re.findall("(.*):(.*)",t)
211 played={int(i[0]):int(i[1]) for i in l}
212 # on récupère le nombre d'occurrences le plus faible
213 mini=min(played.values())
214 # on choisit un id dans ceux qui ont ce nombre d'occurences
215 id_choisi=random.choice([k for k,v in played.items() if v==mini])
216 enigme,indice,answer_reg,answer=dec[id_choisi]
217 # on incrémente la choisie
218 played[id_choisi]+=1
219 # on enregistre le played_file
220 f=open(played_file,"w")
221 f.write("\n".join(["%-3s : %s"%(k,v) for k,v in played.items()]))
222 f.close()
223 return enigme.decode("utf8"),indice.decode("utf8"),answer_reg.decode("utf8"),answer.decode("utf8")
224
225 def pourmoi(self, serv, message):
226 pseudo=self.nick
227 size=len(pseudo)
228 if message[:size]==pseudo and len(message)>size and message[size]==":":
229 return (True,message[size+1:].strip(" "))
230 else:
231 return (False,message)
232
233 def on_privmsg(self, serv, ev):
234 message=ev.arguments()[0]
235 auteur = irclib.nm_to_n(ev.source())
236 try:
237 test=bot_unicode(message)
238 except UnicodeBotError:
239 serv.privmsg(auteur,
240 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
241 return
242 message=message.split()
243 cmd=message[0].lower()
244 notunderstood=False
245 if cmd=="help":
246 helpmsg_default="""Liste des commandes :
247 HELP Affiche ce message d'aide
248 SCORE Affiche ton score (SCORE TRANSFERT <pseudo> [<n>] pour transférer des points)
249 SCORES Affiche les scores"""
250 helpmsg_ops="""
251 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
252 LEAVE Faire quitter un channel
253 PLAY Passe un channel en mode "jouer"
254 NOPLAY Passe un channel en mode "ne pas jouer"
255 QUIET Se taire sur un channel
256 NOQUIET Opposé de QUIET"""
257 helpmsg_overops="""
258 SCORES {DEL|ADD|SUB} Tu veux un dessin ?
259 SAY Fais envoyer un message sur un chan ou à une personne
260 STAY Ignorera les prochains LEAVE pour un chan
261 NOSTAY Opposé de STAY
262 STATUS Montre l'état courant
263 DIE Mourir"""
264 helpmsg=helpmsg_default
265 if auteur in self.ops:
266 helpmsg+=helpmsg_ops
267 if auteur in self.overops:
268 helpmsg+=helpmsg_overops
269 for ligne in helpmsg.split("\n"):
270 serv.privmsg(auteur,ligne)
271 elif cmd=="join":
272 if auteur in self.ops:
273 if len(message)>1:
274 if message[1] in self.chanlist:
275 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
276 else:
277 serv.join(message[1])
278 self.chanlist.append(message[1])
279 self.update_activity(message[1],"")
280 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
281 log(self.serveur,"priv",auteur," ".join(message))
282 else:
283 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
284 else:
285 notunderstood=True
286 elif cmd=="leave":
287 if auteur in self.ops and len(message)>1:
288 if message[1] in self.chanlist:
289 if not (message[1] in self.stay_channels) or auteur in self.overops:
290 self.quitter(message[1]," ".join(message[2:]))
291 self.chanlist.remove(message[1])
292 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
293 else:
294 serv.privmsg(auteur,"Non, je reste !")
295 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
296 else:
297 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
298 else:
299 notunderstood=True
300 elif cmd=="stay":
301 if auteur in self.overops:
302 if len(message)>1:
303 if message[1] in self.stay_channels:
304 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
305 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
306 else:
307 self.stay_channels.append(message[1])
308 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
309 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
310 else:
311 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
312 else:
313 notunderstood=True
314 elif cmd=="nostay":
315 if auteur in self.overops:
316 if len(message)>1:
317 if message[1] in self.stay_channels:
318 self.stay_channels.remove(message[1])
319 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
320 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
321 else:
322 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
323 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
324 else:
325 notunderstood=True
326 elif cmd=="play":
327 if auteur in self.ops:
328 if len(message)>1:
329 if message[1] in self.play_channels:
330 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
331 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
332 else:
333 self.play_channels.append(message[1])
334 self.play_status[message[1]]=[0,time.time()-3600]
335 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
336 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
337 else:
338 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
339 else:
340 notunderstood=True
341 elif cmd=="noplay":
342 if auteur in self.ops:
343 if len(message)>1:
344 if message[1] in self.play_channels:
345 self.play_channels.remove(message[1])
346 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
347 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
348 else:
349 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
350 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
351 else:
352 notunderstood=True
353 elif cmd=="quiet":
354 if auteur in self.ops:
355 if len(message)>1:
356 if message[1] in self.quiet_channels:
357 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
358 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
359 else:
360 self.quiet_channels.append(message[1])
361 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
362 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
363 else:
364 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
365 else:
366 notunderstood=True
367 elif cmd=="noquiet":
368 if auteur in self.ops:
369 if len(message)>1:
370 if message[1] in self.quiet_channels:
371 self.quiet_channels.remove(message[1])
372 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
373 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
374 else:
375 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
376 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
377 else:
378 notunderstood=True
379 elif cmd in ["states","status"]:
380 if auteur in self.overops:
381 for k in self.play_status.keys():
382 serv.privmsg(auteur,(u"%s : %s"%(k,"; ".join([unicode(i) for i in self.play_status[k]]))).encode("utf8") )
383 elif cmd=="say":
384 if auteur in self.overops and len(message)>2:
385 serv.privmsg(message[1]," ".join(message[2:]))
386 log(self.serveur,"priv",auteur," ".join(message))
387 elif len(message)<=2:
388 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
389 else:
390 notunderstood=True
391 elif cmd=="die":
392 if auteur in self.overops:
393 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
394 self.mourir()
395 elif cmd=="score":
396 if len(message)>1:
397 if len(message) in [3,4] and message[1].lower()=="transfert":
398 scores=self.get_scores()
399 de,to=auteur,message[2]
400 value=scores.get(de,0)
401 if len(message)==4:
402 try:
403 asked=int(message[3])
404 except ValueError:
405 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
406 return
407 else:
408 asked=value
409 if value==0:
410 serv.privmsg(auteur,"Vous n'avez pas de points")
411 return
412 elif asked<=0:
413 serv.privmsg(auteur,"Bien tenté…")
414 return
415 elif asked>value:
416 serv.privmsg(auteur,"Vous n'avez que %s points"%(value))
417 return
418 else:
419 self.add_score(de,-asked)
420 self.add_score(to,asked)
421 serv.privmsg(auteur,"Transfert de %s points de %s à %s"%(asked,de,to))
422 else:
423 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
424 else:
425 serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
426 elif cmd=="scores":
427 if len(message)==1:
428 scores=self.get_scores().items()
429 # trie par score
430 scores.sort(lambda x,y:cmp(x[1],y[1]))
431 scores.reverse()
432 serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
433 # trie par pseudo
434 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
435 serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
436 elif auteur in self.overops:
437 souscmd=message[1].lower()
438 if souscmd=="del":
439 if len(message)==3:
440 todelete=message[2]
441 scores=self.get_scores()
442 if scores.has_key(todelete):
443 del scores[todelete]
444 self.save_scores(scores)
445 serv.privmsg(auteur,"Score de %s supprimé"%(todelete))
446 else:
447 serv.privmsg(auteur,"Ce score n'existe pas : %s"%(todelete))
448 else:
449 serv.privmsg(auteur,"Syntaxe : SCORES DEL <pseudo>")
450 elif souscmd in ["add","sub"]:
451 if len(message)==4:
452 toadd,val=message[2],message[3]
453 try:
454 val=int(val)
455 except ValueError:
456 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
457 return
458 if souscmd=="sub":
459 val=-val
460 self.add_score(toadd,val)
461 serv.privmsg(auteur,"Done")
462 else:
463 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
464 else:
465 serv.privmsg(auteur,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
466 else:
467 notunderstood=True
468 else:
469 notunderstood=True
470 if notunderstood:
471 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
472
473 def on_pubmsg(self, serv, ev):
474 auteur = irclib.nm_to_n(ev.source())
475 canal = ev.target()
476 message = ev.arguments()[0]
477 self.update_activity(canal,auteur)
478 try:
479 test=bot_unicode(message)
480 except UnicodeBotError:
481 if not canal in self.quiet_channels:
482 serv.privmsg(canal,
483 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
484 return
485 tryother=False
486 pour_moi,message=self.pourmoi(serv,message)
487 if pour_moi and message.split()!=[]:
488 cmd=message.split()[0].lower()
489 try:
490 args=" ".join(message.split()[1:])
491 except:
492 args=""
493 if cmd in ["meurs","die","crève"]:
494 if auteur in self.overops:
495 self.mourir()
496 log(self.serveur,canal,auteur,message+"[successful]")
497 else:
498 serv.privmsg(canal,"%s: crève !"%(auteur))
499 log(self.serveur,canal,auteur,message+"[failed]")
500 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
501 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
502 if cmd in ["part","leave","dégage"]:
503 if auteur in self.ops and (not (canal in self.stay_channels)
504 or auteur in self.overops):
505 self.quitter(canal)
506 log(self.serveur,canal,auteur,message+"[successful]")
507 self.chanlist.remove(canal)
508 else:
509 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
510 log(self.serveur,canal,auteur,message+"[failed]")
511
512 if cmd in ["deviens","pseudo"]:
513 if auteur in self.ops:
514 become=args
515 serv.nick(become)
516 log(self.serveur,canal,auteur,message+"[successful]")
517 if cmd in ["coucou"] and not canal in self.quiet_channels:
518 serv.privmsg(canal,"%s: coucou"%(auteur))
519 if cmd in ["ping"] and not canal in self.quiet_channels:
520 serv.privmsg(canal,"%s: pong"%(auteur))
521 if cmd in ["déconnaissance","deconnaissance","énigme","enigme","encore"]:
522 if canal in self.play_channels:
523 if self.play_status.get(canal,[-1])[0]==0:
524 try:
525 self.start_enigme(serv,canal)
526 except RefuseError:
527 serv.privmsg(canal,"%s: Je peux souffler une minute ?"%(auteur))
528 else:
529 serv.privmsg(canal,("%s: Rappel : %s"%(auteur,self.play_status[canal][1])).encode("utf8") )
530 else:
531 serv.privmsg(canal,"%s: pas ici…"%(auteur))
532 if cmd in ["score","!score"]:
533 serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
534 if cmd in ["scores","!scores"]:
535 scores=self.get_scores().items()
536 # trie par score
537 scores.sort(lambda x,y:cmp(x[1],y[1]))
538 scores.reverse()
539 serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
540 # trie par pseudo
541 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
542 serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
543 if cmd=="indice" and canal in self.play_channels:
544 self.give_indice(serv,canal,None)
545 if is_tag(message) and not canal in self.quiet_channels:
546 if auteur in self.ops:
547 action=random.choice(config_tag_actions)
548 serv.action(canal,action.encode("utf8"))
549 self.quiet_channels.append(canal)
550 else:
551 answer=random.choice(config_tag_answers)
552 for ligne in answer.split("\n"):
553 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
554 if "Bâille, cru aile ou orld" in message:
555 self.mourir(u"Un de mes easters eggs (non en fait j'en ai qu'un) a été découvert par %s !"%auteur)
556 else:
557 tryother=True
558 else:
559 tryother=True
560 if tryother:
561 if self.play_status.get(canal,[-1])[0] in [1,2]:
562 answer_regexp=self.play_status[canal][3]
563 answer=self.play_status[canal][4]
564 if reussi(message.decode("utf8"),answer,answer_regexp,auteur):
565 serv.privmsg(canal,(u"%s: bravo ! (C'était %s)"%(auteur,answer)).encode("utf8"))
566 log(self.serveur,canal,auteur+"$win",message)
567 self.add_score(auteur,1)
568 token=time.time()
569 self.play_status[canal]=[0,token]
570 serv.execute_delayed(random.randrange(Ttrig*5,Ttrig*10),self.start_enigme,(serv,canal,token))
571
572 def on_kick(self,serv,ev):
573 auteur = irclib.nm_to_n(ev.source())
574 channel = ev.target()
575 victime = ev.arguments()[0]
576 raison = ev.arguments()[1]
577 if victime==self.nick:
578 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
579 time.sleep(5)
580 serv.join(channel)
581 self.update_activity(channel,"")
582 # on ne dit rien au rejoin
583 #l1,l2=config_kick_answers,config_kick_actions
584 #n1,n2=len(l1),len(l2)
585 #i=random.randrange(n1+n2)
586 #if i>=n1:
587 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
588 #else:
589 # serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
590
591 def quitter(self,chan,leave_message=None):
592 if leave_message==None:
593 leave_message=random.choice(config_leave_messages)
594 self.serv.part(chan,message=leave_message.encode("utf8"))
595
596 def mourir(self,quit_message=None):
597 if quit_message==None:
598 quit_message=random.choice(config_quit_messages)
599 self.die(msg=quit_message.encode("utf8"))
600
601 def get_scores(self):
602 f=open(config_score_file)
603 scores=pickle.load(f)
604 f.close()
605 return scores
606
607 def add_score(self,pseudo,value):
608 scores=self.get_scores()
609 if scores.has_key(pseudo):
610 scores[pseudo]+=value
611 else:
612 scores[pseudo]=value
613 self.save_scores(scores)
614
615 def save_scores(self,scores):
616 f=open(config_score_file,"w")
617 pickle.dump(scores,f)
618 f.close()
619
620 def _getnick(self):
621 return self.serv.get_nickname()
622 nick = property(_getnick)
623
624 def update_activity(self,canal,pseudo):
625 if not pseudo in config_idle_bots:
626 self.last_activity[canal]=time.time()
627 def is_active(self,canal):
628 return time.time()-self.last_activity[canal]<config_idle_time
629
630 def start_as_daemon(self, outfile):
631 sys.stderr = Logger(outfile)
632 self.start()
633
634
635 class Logger(object):
636 """Pour écrire ailleurs que sur stdout"""
637 def __init__(self, filename="deconnaisseur.full.log"):
638 self.filename = filename
639
640 def write(self, message):
641 f = open(self.filename, "a")
642 f.write(message)
643 f.close()
644
645
646 if __name__=="__main__":
647 import sys
648 if len(sys.argv)==1:
649 print "Usage : deconnaisseur.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
650 print " --outfile sans --no-output ni --daemon n'a aucun effet"
651 exit(1)
652 serveur=sys.argv[1]
653 if "--daemon" in sys.argv:
654 thisfile = os.path.realpath(__file__)
655 thisdirectory = thisfile.rsplit("/", 1)[0]
656 os.chdir(thisdirectory)
657 daemon = True
658 else:
659 daemon = False
660 if "debug" in sys.argv or "--debug" in sys.argv:
661 debug=True
662 else:
663 debug=False
664 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
665 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
666 if "--no-output" in sys.argv or "--daemon" in sys.argv:
667 outfile = "/var/log/bots/deconnaisseur.full.log"
668 for arg in sys.argv:
669 arg = arg.split("=")
670 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
671 outfile = arg[1]
672 sys.stdout = Logger(outfile)
673 try:
674 serveur=serveurs[serveur]
675 except KeyError:
676 print "Server Unknown : %s"%(serveur)
677 exit(404)
678 deconnaisseur=Deconnaisseur(serveur,debug)
679 if daemon:
680 child_pid = os.fork()
681 if child_pid == 0:
682 os.setsid()
683 deconnaisseur.start_as_daemon(outfile)
684 else:
685 # on enregistre le pid de deconnaisseur
686 pidfile = "/var/run/bots/deconnaisseur.pid"
687 for arg in sys.argv:
688 arg = arg.split("=")
689 if arg[0].strip('-') in ["pidfile"]:
690 pidfile = arg[1]
691 f = open(pidfile, "w")
692 f.write("%s\n" % child_pid)
693 f.close()
694 else:
695 deconnaisseur.start()