]> jfr.im git - erebus.git/blob - modules/trivia.py
more work on trivia
[erebus.git] / modules / trivia.py
1 # Erebus IRC bot - Author: Erebus Team
2 # trivia module
3 # This file is released into the public domain; see http://unlicense.org/
4
5 #TODO:
6 # timers (stop game/skip question/hinting)
7 # bonus points
8 # ability to REDUCE users points
9 # dynamic questions
10 # v2
11 # team play
12 # statistics
13
14 # module info
15 modinfo = {
16 'author': 'Erebus Team',
17 'license': 'public domain',
18 'compatible': [1], # compatible module API versions
19 'depends': [], # other modules required to work properly?
20 }
21
22 # preamble
23 import modlib
24 lib = modlib.modlib(__name__)
25 def modstart(parent, *args, **kwargs):
26 state.parent = parent
27 return lib.modstart(parent, *args, **kwargs)
28 def modstop(*args, **kwargs):
29 global state
30 del state
31 return lib.modstop(*args, **kwargs)
32
33 # module code
34 import json, random
35
36 class TriviaState(object):
37 def __init__(self, questionfile):
38 self.questionfile = questionfile
39 self.db = json.load(open(questionfile, "r"))
40 self.chan = self.db['chan']
41 self.curq = None
42 self.nextq = None
43
44 def __del__(self):
45 if json is not None and json.dump is not None:
46 json.dump(self.db, open(self.questionfile, "w"), indent=4, separators=(',',': '))
47
48 def nextquestion(self):
49 if state.nextq is not None:
50 nextq = state.nextq
51 self.curq = nextq
52 state.nextq = None
53 else:
54 nextq = random.choice(self.db['questions'])
55 self.curq = nextq
56
57 qtext = "\00300,01Next up: "
58 qary = nextq['question'].split(None)
59 for qword in qary:
60 qtext += "\00300,01"+qword+"\00301,01"+chr(random.randrange(32,126))
61 self.parent.channel(self.chan).bot.msg(self.chan, qtext)
62
63 def checkanswer(self, answer):
64 if self.curq is None:
65 return False
66 elif isinstance(self.curq['answer'], basestring):
67 return answer.lower() == self.curq['answer']
68 else: # assume it's a list or something.
69 return answer.lower() in self.curq['answer']
70
71 def addpoint(self, _user, count=1):
72 _user = str(_user)
73 user = _user.lower()
74 if user in self.db['users']:
75 self.db['users'][user]['points'] += count
76 else:
77 self.db['users'][user] = {'points': count, 'realnick': _user, 'rank': len(self.db['ranks'])}
78 self.db['ranks'].append(user)
79
80 oldrank = self.db['users'][user]['rank']
81 while oldrank != 0:
82 nextperson = self.db['ranks'][oldrank-1]
83 if self.db['users'][user]['points'] > self.db['users'][nextperson]['points']:
84 self.db['ranks'][oldrank-1] = user
85 self.db['users'][user]['rank'] = oldrank-1
86 self.db['ranks'][oldrank] = nextperson
87 self.db['users'][nextperson]['rank'] = oldrank
88 oldrank = oldrank-1
89 else:
90 break
91 return self.db['users'][user]['points']
92
93 def points(self, user):
94 user = str(user).lower()
95 if user in self.db['users']:
96 return self.db['users'][user]['points']
97 else:
98 return 0
99
100 def rank(self, user):
101 user = str(user).lower()
102 return self.db['users'][user]['rank']+1
103
104 def targetuser(self, user):
105 user = str(user).lower()
106 rank = self.db['users'][user]['rank']
107 if rank == 0:
108 return "you're in the lead!"
109 else:
110 return self.db['ranks'][rank-1]
111 def targetpoints(self, user):
112 user = str(user).lower()
113 rank = self.db['users'][user]['rank']
114 if rank == 0:
115 return "N/A"
116 else:
117 return self.db['users'][self.db['ranks'][rank-1]]['points']
118
119 state = TriviaState("/home/jrunyon/erebus/modules/trivia.json") #TODO get path from config
120
121 @lib.hookchan(state.db['chan'])
122 def trivia_checkanswer(bot, user, chan, *args):
123 line = ' '.join([str(arg) for arg in args])
124 if state.checkanswer(line):
125 bot.msg(chan, "\00308%s\003 has it! The answer was \00308%s\003. Current points: %d. Rank: %d. Target: %s (%s)." % (user, line, state.addpoint(user), state.rank(user), state.targetuser(user), state.targetpoints(user)))
126 state.nextquestion()
127
128 @lib.hook('points')
129 def cmd_points(bot, user, chan, realtarget, *args):
130 if chan == realtarget: replyto = chan
131 else: replyto = user
132
133 if len(args) != 0: who = args[0]
134 else: who = user
135
136 bot.msg(replyto, "%s has %d points." % (who, state.points(who)))
137
138 @lib.hook('give', clevel=lib.OP)
139 @lib.argsGE(1)
140 def cmd_give(bot, user, chan, realtarget, *args):
141 whoto = args[0]
142 if len(args) > 1:
143 numpoints = int(args[1])
144 else:
145 numpoints = 1
146 balance = state.addpoint(whoto, numpoints)
147 bot.msg(chan, "%s gave %s %d points. New balance: %d" % (user, whoto, numpoints, balance))
148
149 @lib.hook('setnext', clevel=lib.OP)
150 @lib.argsGE(1)
151 def cmd_setnext(bot, user, chan, realtarget, *args):
152 line = ' '.join([str(arg) for arg in args])
153 linepieces = line.split('*')
154 question = linepieces[0].strip()
155 answer = linepieces[1].strip()
156 state.nextq = {'question':question,'answer':answer}
157 bot.msg(user, "Done.")
158
159 @lib.hook('skip', clevel=lib.KNOWN)
160 def cmd_skip(bot, user, chan, realtarget, *args):
161 state.nextquestion()
162
163 @lib.hook('start')
164 def cmd_start(bot, user, chan, realtarget, *args):
165 if chan == realtarget: replyto = chan
166 else: replyto = user
167
168 if state.curq is None:
169 state.nextquestion()
170 else:
171 bot.msg(replyto, "Game is already started!")
172
173 @lib.hook('stop', clevel=lib.KNOWN)
174 def cmd_stop(bot, user, chan, realtarget, *args):
175 if chan == realtarget: replyto = chan
176 else: replyto = user
177
178 if state.curq is not None:
179 state.curq = None
180 bot.msg(chan, "Game ended by %s" % (user))
181 else:
182 bot.msg(replyto, "Game isn't running.")
183
184 @lib.hook('rank')
185 def cmd_rank(bot, user, chan, realtarget, *args):
186 if chan == realtarget: replyto = chan
187 else: replyto = user
188
189 if len(args) != 0: who = args[0]
190 else: who = user
191
192 bot.msg(replyto, "%s is in %d place." % (who, state.rank(who)))