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