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