]> gitweb.pimeys.fr Git - bots/hung.git/blob - hung.py
f9917cc900eb1f0b7da9b82e9c71f5b492d6f434
[bots/hung.git] / hung.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 23/04/12
5
6 # Un test de bot irc, parce que c'est cool
7
8 import irclib
9 import ircbot
10 import threading
11 import random
12 import time
13 import socket, ssl, json
14 import pickle
15 import re
16 import os
17 from commands import getstatusoutput as ex
18
19 import sys
20 config_debug_stdout=True
21 if "--quiet" in sys.argv:
22 config_debug_stdout=False
23
24 config_irc_password="I'mAHungMan"
25 config_irc_pseudo="Hung"
26 config_chanlist=["#bot","#flood"]
27 config_stay_channels=["#bot","#flood"]
28 config_play_channels=["#flood"]
29 config_quiet_channels=[]
30 config_logfile_template="hung.%s.log"
31 def get_config_logfile(serveur):
32 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
33 return config_logfile_template%(serveurs[serveur])
34 config_overops=["[20-100]","[20-100]_"]
35 config_ops=[]
36 config_report_bugs_to=["[20-100]"]
37
38 config_dico_mots="mots.txt"
39 config_dico_defs="definitions.txt"
40
41 def log(serveur,channel,auteur=None,message=None):
42 f=open(get_config_logfile(serveur),"a")
43 if auteur==message==None:
44 # alors c'est que c'est pas un channel mais juste une ligne de log
45 chain="%s %s"%(time.strftime("%F %T"),channel)
46 else:
47 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
48 f.write(chain+"\n")
49 if config_debug_stdout:
50 print chain
51 f.close()
52
53 class UnicodeBotError(Exception):
54 pass
55 def bot_unicode(chain):
56 try:
57 unicode(chain,"utf8")
58 except UnicodeDecodeError as exc:
59 raise UnicodeBotError
60
61 class Hung(ircbot.SingleServerIRCBot):
62 def __init__(self,serveur,debug=False):
63 temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
64 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
65 temporary_pseudo,"Bot irc pour jouer au pendu", 10)
66 self.debug=debug
67 self.serveur=serveur
68 self.overops=config_overops
69 self.ops=self.overops+config_ops
70 self.report_bugs_to=config_report_bugs_to
71 self.chanlist=config_chanlist
72 self.stay_channels=config_stay_channels
73 self.play_channels=config_play_channels
74 self.play_status={}
75 self.quiet_channels=config_quiet_channels
76
77
78 def give_me_my_pseudo(self,serv):
79 serv.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo,config_irc_password))
80 serv.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo,config_irc_password))
81 time.sleep(0.3)
82 serv.nick(config_irc_pseudo)
83
84 def on_welcome(self, serv, ev):
85 self.give_me_my_pseudo(serv)
86 serv.privmsg("NickServ","IDENTIFY %s"%(config_irc_password))
87 log(self.serveur,"Connected")
88 if self.debug:
89 self.chanlist=["#bot"]
90 self.play_channels=["#bot"]
91 for c in self.chanlist:
92 log(self.serveur,"JOIN %s"%(c))
93 serv.join(c)
94
95 def pourmoi(self, serv, message):
96 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
97 pseudo=serv.get_nickname()
98 size=len(pseudo)
99 if message[:size]==pseudo and len(message)>size and message[size]==":":
100 return (True,message[size+1:].lstrip(" "))
101 else:
102 return (False,message)
103
104 def on_privmsg(self, serv, ev):
105 message=ev.arguments()[0]
106 auteur = irclib.nm_to_n(ev.source())
107 try:
108 test=bot_unicode(message)
109 except UnicodeBotError:
110 serv.privmsg(auteur,
111 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
112 return
113 message=message.split()
114 cmd=message[0].lower()
115 notunderstood=False
116 if cmd=="join":
117 if auteur in self.ops:
118 if len(message)>1:
119 if message[1] in self.chanlist:
120 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
121 else:
122 serv.join(message[1])
123 self.chanlist.append(message[1])
124 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
125 log(self.serveur,"priv",auteur," ".join(message))
126 else:
127 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
128 else:
129 notunderstood=True
130 elif cmd=="leave":
131 if auteur in self.ops and len(message)>1:
132 if message[1] in self.chanlist:
133 if not (message[1] in self.stay_channels) or auteur in self.overops:
134 serv.part(message[1])
135 self.chanlist.remove(message[1])
136 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
137 else:
138 serv.privmsg(auteur,"Non, je reste !")
139 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
140 else:
141 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
142 else:
143 notunderstood=True
144 elif cmd=="play":
145 if auteur in self.ops:
146 if len(message)>1:
147 if message[1] in self.play_channels:
148 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
149 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
150 else:
151 self.play_channels.append(message[1])
152 self.play_status[message[1]]=[[None,None,None]]
153 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
154 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
155 else:
156 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
157 else:
158 notunderstood=True
159 elif cmd=="noplay":
160 if auteur in self.ops:
161 if len(message)>1:
162 if message[1] in self.play_channels:
163 self.play_channels.remove(message[1])
164 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
165 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
166 else:
167 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
168 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
169 else:
170 notunderstood=True
171 elif cmd=="stay":
172 if auteur in self.overops:
173 if len(message)>1:
174 if message[1] in self.stay_channels:
175 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
176 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
177 else:
178 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
179 self.stay_channels.append(message[1])
180 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
181 else:
182 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
183 else:
184 notunderstood=True
185 elif cmd=="nostay":
186 if auteur in self.overops:
187 if len(message)>1:
188 if message[1] in self.stay_channels:
189 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
190 self.stay_channels.remove(message[1])
191 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
192 else:
193 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
194 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
195
196 else:
197 notunderstood=True
198 elif cmd in ["states","status"]:
199 if auteur in self.overops:
200 for k in self.play_status.keys():
201 serv.privmsg(auteur,"%s : %s (%s) [%s]"%(k,"".join([str(i[0]) for i in self.play_status[k][0]])
202 ,self.play_status[k][1], self.play_status[k][2]))
203 elif cmd=="die":
204 if auteur in self.overops:
205 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
206 self.die()
207 else:
208 notunderstood=True
209 elif cmd=="quiet":
210 if auteur in self.ops:
211 if len(message)>1:
212 if message[1] in self.quiet_channels:
213 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
214 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
215 else:
216 self.quiet_channels.append(message[1])
217 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
218 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
219 else:
220 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
221 else:
222 notunderstood=True
223 elif cmd=="noquiet":
224 if auteur in self.ops:
225 if len(message)>1:
226 if message[1] in self.quiet_channels:
227 self.quiet_channels.remove(message[1])
228 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
229 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
230 else:
231 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
232 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
233 else:
234 notunderstood=True
235 elif cmd=="say":
236 if auteur in self.overops and len(message)>2:
237 serv.privmsg(message[1]," ".join(message[2:]))
238 log(self.serveur,"priv",auteur," ".join(message))
239 elif len(message)<=2:
240 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
241 else:
242 notunderstood=True
243 elif cmd=="do":
244 if auteur in self.overops and len(message)>2:
245 serv.action(message[1]," ".join(message[2:]))
246 log(self.serveur,"priv",auteur," ".join(message))
247 elif len(message)<=2:
248 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
249 else:
250 notunderstood=True
251 else:
252 notunderstood=True
253 if notunderstood:
254 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
255
256 def affiche_mot(self, serv, canal, begin="Mot courant"):
257 if self.play_status.has_key(canal):
258 mot = self.play_status[canal][0]
259 obfuskated=" ".join([lettre[0] if lettre[1] else "_" for lettre in mot])
260 serv.privmsg(canal,"%s : %s"%(begin,obfuskated))
261
262 def start_partie(self, serv, canal):
263 mots=[mot.strip() for mot in open(config_dico_mots).readlines()]
264 defs=[defi.strip() for defi in open(config_dico_defs).readlines()]
265 indice = random.randrange(0,len(mots))
266 mot,definition=mots[indice],defs[indice]
267 # ' et - sont considérés comme déjà devinés
268 mot = [(lettre,lettre in "'-") for lettre in list(mot)]
269 self.play_status[canal]=[mot,definition,{}]
270 self.affiche_mot(serv, canal, begin="Devinez")
271
272 def on_pubmsg(self, serv, ev):
273 auteur = irclib.nm_to_n(ev.source())
274 canal = ev.target()
275 message = ev.arguments()[0]
276 try:
277 test=bot_unicode(message)
278 except UnicodeBotError:
279 if not canal in self.quiet_channels:
280 serv.privmsg(canal,
281 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
282 return
283 pour_moi,message=self.pourmoi(serv,message)
284 if pour_moi and message.split()!=[]:
285 cmd=message.split()[0].lower()
286 try:
287 args=" ".join(message.split()[1:])
288 except:
289 args=""
290 if cmd in ["meurs","die","crève"]:
291 if auteur in self.overops:
292 log(self.serveur,canal,auteur,message+"[successful]")
293 self.die()
294 else:
295 serv.privmsg(canal,"%s: crève !"%(auteur))
296 log(self.serveur,canal,auteur,message+"[failed]")
297 elif cmd in ["part","leave","dégage"]:
298 if auteur in self.ops and (not (canal in self.stay_channels)
299 or auteur in self.overops):
300 serv.part(canal,message="Éjecté par %s"%(auteur))
301 log(self.serveur,canal,auteur,message+"[successful]")
302 if canal in self.chanlist:
303 self.chanlist.remove(canal)
304 else:
305 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
306 log(self.serveur,canal,auteur,message+"[failed]")
307 elif cmd in ["play","jeu","encore","again","partie","pendu","game","mot","go","allez"]:
308 if not canal in self.quiet_channels and canal in self.play_channels:
309 if self.play_status.has_key(canal):
310 if self.play_status[canal]==[[None,None,None]]:
311 self.start_partie(serv, canal)
312 else:
313 self.affiche_mot(serv, canal, begin="%s: Rappel"%(auteur))
314 else:
315 self.play_status[canal]=[[None,None,None]]
316 self.start_partie(serv, canal)
317 elif not canal in self.play_channels:
318 serv.privmsg(canal,"%s: pas ici…"%(auteur))
319 elif (cmd in list("azertyuiopqsdfghjklmwxcvbn") and canal in self.play_channels
320 and self.play_status.has_key(canal) and self.play_status[canal]!=[[None,None,None]]):
321 giv_let=cmd.upper()
322 liste=self.play_status[canal][0]
323 listeapres=[(lettre[0],lettre[1] or lettre[0]==giv_let) for lettre in liste]
324 if liste!=listeapres:
325 nbtrouvees=(sum([lettre[1] for lettre in listeapres if not lettre[0] in "'-"])
326 - sum([lettre[1] for lettre in liste if not lettre[0] in "'-"]))
327 if self.play_status[canal][2].has_key(auteur):
328 self.play_status[canal][2][auteur]+= nbtrouvees
329 else:
330 self.play_status[canal][2][auteur] = nbtrouvees
331 self.play_status[canal][0]=listeapres
332 self.affiche_mot(serv, canal, begin="%s placé"%(giv_let))
333 if all([lettre[1] for lettre in listeapres]):
334 realword="".join([lettre[0] for lettre in self.play_status[canal][0]])
335 definition = self.play_status[canal][1]
336 serv.privmsg(canal,"Bravo ! C'était %s"%(realword))
337 serv.privmsg(canal,definition)
338 nlettre=float(len(realword.replace("'","").replace("-","")))
339 contribs=["%s:%s%%"%(pseudo,int(100*contrib/nlettre)) for pseudo,contrib in self.play_status[canal][2].items()]
340 serv.privmsg(canal,"Contributions : %s"%(" ".join(contribs)) )
341 self.play_status[canal]=[[None,None,None]]
342
343
344 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
345 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
346 else:
347 pass
348
349 def on_action(self, serv, ev):
350 action = ev.arguments()[0]
351 auteur = irclib.nm_to_n(ev.source())
352 channel = ev.target()
353 try:
354 test=bot_unicode(action)
355 except UnicodeBotError:
356 serv.privmsg(channel,
357 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
358 return
359 mypseudo=serv.get_nickname()
360
361 if __name__=="__main__":
362 import sys
363 if len(sys.argv)==1:
364 print "Usage : hung.py <serveur> [--debug]"
365 exit(1)
366 serveur=sys.argv[1]
367 if "debug" in sys.argv or "--debug" in sys.argv:
368 debug=True
369 else:
370 debug=False
371 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
372 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
373 try:
374 serveur=serveurs[serveur]
375 except KeyError:
376 print "Server Unknown : %s"%(serveur)
377 exit(404)
378 hung=Hung(serveur,debug)
379 hung.start()