Introduction
Introduction Statistics Contact Development Disclaimer Help
idlerpg-channel-service.py - annna - Annna the nice friendly bot.
git clone git://bitreich.org/annna/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws6…
Log
Files
Refs
Tags
README
---
idlerpg-channel-service.py (16901B)
---
1 #!/usr/bin/env python
2 # coding=UTF-8
3 #
4 # Copy me, if you can.
5 # by 20h
6 #
7
8 import os
9 import sys
10 import getopt
11 import time
12 import random
13 import select
14 import pyinotify
15 import errno
16 import fcntl
17 import functools
18
19 def readin_file(f):
20 lines = []
21 try:
22 fd = open(f)
23 except:
24 sys.exit(1)
25 lines = [e.strip() for e in fd.readlines()]
26 fd.close()
27 return lines
28
29 def readin_dictfile(f):
30 lines = []
31 rdict = {}
32 try:
33 fd = open(f)
34 except:
35 sys.exit(1)
36 lines = [e.strip().split("\t") for e in fd.readlines()]
37 fd.close()
38 for line in lines:
39 rdict[line[0]] = line[1:]
40 return rdict
41
42 def writeout_dictfile(f, d):
43 try:
44 fd = open(f, "w")
45 except:
46 sys.exit(1)
47 for key in d.keys():
48 fd.write("%s\t%s\n" % (key, "\t".join([str(s) for s in d[key]])))
49 fd.flush()
50 fd.close()
51
52 def say(fpath, text):
53 try:
54 fd = open(fpath, "w")
55 fd.write("%s\n" % (text))
56 fd.flush()
57 fd.close()
58 except:
59 sys.exit(1)
60
61 def usage(app):
62 app = os.path.basename(app)
63 print("usage: %s [-h] ircuser basepath ircpath server channel" % (ap…
64 sys.exit(1)
65
66 def main(args):
67 try:
68 opts, largs = getopt.getopt(args[1:], "h")
69 except getopt.GetoptError as err:
70 print(str(err))
71 usage(args[0])
72
73 for o, a in opts:
74 if opts == "-h":
75 usage(args[0])
76 else:
77 assert False, "unhandled option"
78
79 if len(largs) < 5:
80 usage(args[0])
81 return 1
82
83 ircuser = largs[0]
84 basepath = largs[1]
85 ircpath = largs[2]
86 server = largs[3]
87 channel = largs[4]
88 serverpath = "%s/%s" % (ircpath, server)
89 chanpath = "%s/%s" % (serverpath, channel)
90
91 chaninpath = "%s/in" % (chanpath)
92
93 def get_channel_users():
94 say(chaninpath, "/names %s\n" % (channel))
95 serveroutlines = readin_file("%s/out" % (serverpath))
96 namesstring = " 353 %s = %s :" % (ircuser, channel)
97 users = []
98 for line in serveroutlines[::-1]:
99 if namesstring in line:
100 for user in line.strip().split(namesstring)[1].split(" "…
101 if user.startswith("@"):
102 user = user[1:]
103 if user not in users:
104 users.append(user)
105 return users
106
107 users = get_channel_users()
108 if len(users) == 0:
109 return 1
110
111 penalties = readin_dictfile("%s/penalties.txt" % (basepath))
112
113 classes = readin_dictfile("%s/classes.txt" % (basepath))
114 hardware = readin_dictfile("%s/hardware.txt" % (basepath))
115 shields = readin_dictfile("%s/shields.txt" % (basepath))
116 weapons = readin_dictfile("%s/weapons.txt" % (basepath))
117 quests = readin_dictfile("%s/quests.txt" % (basepath))
118 events = readin_dictfile("%s/events.txt" % (basepath))
119
120 hackers = readin_dictfile("%s/hackers.txt" % (basepath))
121 for hacker in hackers.keys():
122 hackers[hacker][0] = int(hackers[hacker][0])
123 hackers[hacker][5] = int(hackers[hacker][5])
124 # All are offline by default.
125 try:
126 hackers[hacker][6] = 0
127 except IndexError:
128 hackers[hacker].append(0)
129
130 admins = readin_dictfile("%s/admins.txt" % (basepath))
131
132 def random_hacker():
133 hacker = []
134 # Idletime
135 hacker.append(0)
136 # Class
137 hacker.append(random.choice(list(classes.keys())))
138 # Hardware
139 hacker.append(random.choice(list(hardware.keys())))
140 # Shield
141 hacker.append(random.choice(list(shields.keys())))
142 # Weapon
143 hacker.append(random.choice(list(weapons.keys())))
144 # Level
145 hacker.append(0)
146 # Online
147 hacker.append(1)
148 return hacker
149
150 def calamity(hackers, hacker):
151 calamity_type = random.randint(1, 10)
152 if calamity_type == 1:
153 change_type = random.randint(1, 4)
154 if change_type == 1:
155 new_class = None
156 while new_class != hackers[hacker][1]:
157 new_class = random.choice(list(classes.keys()))
158 hackers[hacker][1] = new_class
159 say(chaninpath, "Due to a bit flip during a solar flare,…
160 "%s's hacker class changed to %s." \
161 % (hacker, hackers[hacker][1]))
162 elif change_type == 2:
163 new_hardware = None
164 while new_hardware != hackers[hacker][2]:
165 new_hardware = random.choice(list(hardware.keys()))
166 hackers[hacker][2] = new_hardware
167 say(chaninpath, "It is %s's birthday. " \
168 "%s's hardware changed to %s." \
169 % (hacker, hacker, hackers[hacker][2]))
170 elif change_type == 3:
171 new_shield = None
172 while new_shield != hackers[hacker][3]:
173 new_shield = random.choice(list(shields.keys()))
174 hackers[hacker][3] = new_shield
175 say(chaninpath, "%s fell over a Windows 95 CD. " \
176 "%s's shield changed to %s." \
177 % (hacker, hacker, hackers[hacker][3]))
178 elif change_type == 4:
179 new_weapon = None
180 while new_weapon != hackers[hacker][4]:
181 new_weapon = random.choice(list(weapons.keys()))
182 hackers[hacker][4] = new_weapon
183 say(chaninpath, "%s had to reinstall the OS. " \
184 "%s's weapon changed to %s." \
185 % (hacker, hacker, hackers[hacker][4]))
186 else:
187 event = random.choice(list(events.keys()))
188 boost = random.randint(-10, 10) * 100
189 hackers[hacker][0] += boost
190 say(chaninpath, "%s! This caused the idle time to " \
191 "change by %d to %d." \
192 % (event % (hacker), boost, hackers[hacker][0]))
193
194 def hand_of_rms(hackers, hacker):
195 win = random.randint(0, 5)
196 rmstime = random.randint(1, 10) * 100
197 if win:
198 hackers[hacker][0] += rmstime
199 say(chaninpath, "The holy hand of RMS moved %s %d seconds" \
200 " forward in idle time." % (hacker, rmstime))
201 else:
202 hackers[hacker][0] -= rmstime
203 say(chaninpath, "RMS had a bad day and moved %s %d seconds" \
204 " back in idle time." % (hacker, rmstime))
205
206 def go_on_quest(hackers, questhackers):
207 quest = random.choice(list(quests.keys()))
208 success = random.randint(1, 16)
209 damage = (success - 5) * 100
210 if damage >= 0:
211 say(chaninpath, quest \
212 % (", ".join(questhackers), "succeeded", damage))
213 else:
214 say(chaninpath, quest \
215 % (", ".join(questhackers), "failed", damage))
216 for hacker in questhackers:
217 hackers[hacker][0] += damage
218
219 def attack(hackers, attacker, defender):
220 attackweapon = hackers[attacker][4]
221 defendweapon = hackers[defender][4]
222 attackshield = hackers[attacker][3]
223 defendshield = hackers[defender][3]
224
225 attackweapon_roll = random.randint(1,12)
226 defendshield_roll = random.randint(1,12)
227 damage = (attackweapon_roll - defendshield_roll) * 100
228
229 attackinfo = "The hacker "
230 if damage > 0:
231 # Attack success
232 hackers[defender][0] -= damage
233 attackinfo = "%s attacked %s with a %s" \
234 ", causing %s seconds of activity. %s, your " \
235 "idle time has been increased by %d to %s." \
236 % (attacker, defender, attackweapon, damage, defender, \
237 damage, hackers[defender][0])
238 elif damage < 0:
239 # Defence success
240 damage = abs(damage)
241 hackers[attacker][0] -= damage
242 attackinfo = "%s defended an attack from %s " \
243 "with their %s, causing %s seconds of activity. %s, " \
244 "your idle time has been reduced by %d to %s." \
245 % (defender, attacker, defendshield, damage, attacker, \
246 damage, hackers[attacker][0])
247 else:
248 attackinfo = "%s attacked %s with a %s" \
249 ", but %s defended so well with %s, " \
250 "that no damage occured." \
251 % (attacker, defender, attackweapon, defender, \
252 defendshield)
253 say(chaninpath, attackinfo)
254
255 def hacker_info(hackers, hacker):
256 hackerinfo = "The hacker %s of the class %s " % (hacker, hacker…
257 hackerinfo += "is using %s hardware " % (hackers[hacker][2])
258 hackerinfo += "which is protected by %s. " % (hackers[hacker][3])
259 hackerinfo += "%s's weapon is %s. " % (hacker, hackers[hacker][4…
260 hackerinfo += "%s has idled for %d seconds and has reached level…
261 say(chaninpath, hackerinfo)
262
263 def update_hackers_from_users(hackers, users):
264 for user in users:
265 # Build a hacker for newly appeared irc user
266 if user not in list(hackers.keys()) and user != ircuser:
267 hackers[user] = random_hacker()
268 elif user in list(hackers.keys()):
269 hackers[user][6] = 1
270
271 def sync_hackers_with_channel(hackers):
272 users = get_channel_users()
273 update_hackers_from_users(hackers, users)
274
275 update_hackers_from_users(hackers, users)
276
277 try:
278 inotifywm = pyinotify.WatchManager()
279 inotifywm.add_watch("%s/out" % (chanpath), pyinotify.IN_MODIFY)
280 except:
281 sys.exit(1)
282 inotifyfd = inotifywm.get_fd()
283
284 def event_processor(notifier):
285 pass
286 notifier = pyinotify.Notifier(inotifywm, default_proc_fun=event_proc…
287
288 try:
289 chanoutfd = open("%s/out" % (chanpath), "r+")
290 except:
291 sys.exit(1)
292
293 chanoutfd.readlines()
294 while 1:
295 # Game ticks every 5 seconds.
296 try:
297 (rfds, wfds, sfds) = select.select([inotifyfd], [], [], 5)
298 except select.error as err:
299 if err.args[0] == errno.EINTR:
300 continue
301 break
302 if rfds == [] and wfds == [] and sfds == []:
303 for hacker in hackers.keys():
304 # Is offline.
305 if hackers[hacker][6] == 0:
306 continue
307
308 hackers[hacker][0] += 5
309 # Level up every 5 days.
310 newlevel = int(hackers[hacker][0]/(86400*5))
311 if newlevel > hackers[hacker][5]:
312 say(chaninpath, "%s levelled up to level %s!" % (hac…
313 elif newlevel < hackers[hacker][5]:
314 say(chaninpath, "%s levelled down to level %s." % (h…
315 hackers[hacker][5] = newlevel
316
317 if random.randint(1, 65535) > 65500 and len(hackers) > 1:
318 (attacker, defender) = random.sample(list(hackers.keys()…
319 attack(hackers, attacker, defender)
320 elif random.randint(1, 65535) < 30 and len(hackers) > 1:
321 questhackers = random.sample(list(hackers.keys()), rando…
322 go_on_quest(hackers, questhackers)
323 elif random.randint(1, 65535) < 5 and len(hackers) > 1:
324 hand_of_rms(hackers, random.choice(list(hackers.keys())))
325 elif random.randint(1, 65535) < 10 and len(hackers) > 1:
326 calamity(hackers, random.choice(list(hackers.keys())))
327
328 writeout_dictfile("%s/hackers.txt" % (basepath), hackers)
329 continue
330
331 notifier.read_events()
332 notifier.process_events()
333
334 lines = chanoutfd.readlines()
335 lines = [line.strip() for line in lines]
336 for line in lines:
337 if line == None or line == "":
338 continue
339
340 penalty = None
341 try:
342 (timestamp, user, remain) = line.split(" ", 2)
343 except ValueError:
344 continue
345
346 if user.startswith("<") and user.endswith(">"):
347 hacker = user.split("<", 1)[1].split(">", 1)[0]
348 is_admin = False
349 if hacker in admins.keys():
350 is_admin = True
351 else:
352 penalty = "text"
353 if remain.startswith("!"):
354 (cmd, *cmdargs) = remain.split(" ")
355 if cmd == "!info" and is_admin and len(cmdargs) > 0:
356 if cmdargs[0] in hackers:
357 hacker_info(hackers, cmdargs[0])
358 else:
359 hacker_info(hackers, hacker)
360 elif cmd == "!attack":
361 if len(cmdargs) > 0 and cmdargs[0] in hackers:
362 attack(hackers, hacker, cmdargs[0])
363 else:
364 (attacker, defender) = random.sample(list(ha…
365 attack(hackers, attacker, defender)
366 elif cmd == "!quest":
367 if len (cmdargs) > 0 and cmdargs[0] in hackers:
368 argsinhackers = [hacker]
369 for cmdarg in cmdargs:
370 if cmdarg in hackers:
371 argsinhackers.append(cmdarg)
372 go_on_quest(hackers, argsinhackers)
373 else:
374 questhackers = random.sample(list(hackers.ke…
375 go_on_quest(hackers, questhackers)
376 elif cmd == "!hor":
377 if len(cmdargs) > 0 and cmdargs[0] in hackers:
378 hand_of_rms(hackers, cmdargs[0])
379 else:
380 hand_of_rms(hackers, random.choice(list(hack…
381 elif cmd == "!calamity":
382 if len(cmdargs) > 0 and cmdargs[0] in hackers:
383 calamity(hackers, cmdargs[0])
384 else:
385 calamity(hackers, random.choice(list(hackers…
386 elif cmd == "!stats":
387 say(chaninpath, "%s, try gophers://bitreich.org/…
388 % (hacker))
389
390 elif user == "-!-":
391 (hacker, text) = remain.split(" ", 1)
392 if "has joined " in text:
393 penalty = "join"
394 hacker = hacker.split("(", 1)[0]
395 if hacker not in hackers:
396 hackers[hacker] = random_hacker()
397 hacker_info(hackers, hacker)
398 else:
399 hackers[hacker][6] = 1
400 sync_hackers_with_channel(hackers)
401 elif "has left " in text:
402 penalty = "part"
403 hacker = hacker.split("(", 1)[0]
404 if hacker in hackers:
405 hackers[hacker][6] = 0
406 sync_hackers_with_channel(hackers)
407 elif "has quit " in text:
408 penalty = "quit"
409 hacker = hacker.split("(", 1)[0]
410 if hacker in hackers:
411 hackers[hacker][6] = 0
412 sync_hackers_with_channel(hackers)
413 elif "changed nick to " in text:
414 # TODO: Fix. It is now in channelmaster.
415 # Instead we sync on part and quit.
416 penalty = "nick"
417 newhacker = text.split("to ", 1)[1].split("\"")[1]
418 if newhacker not in hackers:
419 hackers[newhacker] = random_hacker()
420 hacker_info(hackers, newhacker)
421 elif "kicked " in text:
422 penalty = "kick"
423 hacker = text.split(" ", 3)[2]
424 if hacker in hackers:
425 hackers[hacker][6] = 0
426 sync_hackers_with_channel(hackers)
427
428 if hacker == ircuser:
429 continue
430 if hacker not in hackers:
431 continue
432
433 if penalty != None and penalty in penalties:
434 penaltytime = int(penalties[penalty][0])
435 hackers[hacker][0] -= penaltytime
436 say(chaninpath, "%s, your idletime has been reduced by %…
437 % (hacker, penaltytime, hackers[hacker][0], pena…
438 writeout_dictfile("%s/hackers.txt" % (basepath), hackers)
439
440 return 0
441
442 if __name__ == "__main__":
443 sys.exit(main(sys.argv))
444
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.