Mercurial > libervia-backend
comparison src/plugins/plugin_misc_quiz.py @ 362:208107419b17
Quiz game: buzzer, timer, answer management
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 12 Jun 2011 22:34:15 +0200 |
parents | 141eeb7cd9e6 |
children | f964dcec1611 |
comparison
equal
deleted
inserted
replaced
361:141eeb7cd9e6 | 362:208107419b17 |
---|---|
65 self.games={} | 65 self.games={} |
66 self.waiting_inv = {} #Invitation waiting for people to join to launch a game | 66 self.waiting_inv = {} #Invitation waiting for people to join to launch a game |
67 host.bridge.addMethod("quizGameLaunch", ".communication", in_sign='ass', out_sign='', method=self.quizGameLaunch) #args: room_jid, players, profile | 67 host.bridge.addMethod("quizGameLaunch", ".communication", in_sign='ass', out_sign='', method=self.quizGameLaunch) #args: room_jid, players, profile |
68 host.bridge.addMethod("quizGameCreate", ".communication", in_sign='sass', out_sign='', method=self.quizGameCreate) #args: room_jid, players, profile | 68 host.bridge.addMethod("quizGameCreate", ".communication", in_sign='sass', out_sign='', method=self.quizGameCreate) #args: room_jid, players, profile |
69 host.bridge.addMethod("quizGameReady", ".communication", in_sign='sss', out_sign='', method=self.newPlayerReady) #args: player, referee, profile | 69 host.bridge.addMethod("quizGameReady", ".communication", in_sign='sss', out_sign='', method=self.newPlayerReady) #args: player, referee, profile |
70 host.bridge.addMethod("quizGameAnswer", ".communication", in_sign='ssss', out_sign='', method=self.playerAnswer) | |
70 host.bridge.addSignal("quizGameStarted", ".communication", signature='ssass') #args: room_jid, referee, players, profile | 71 host.bridge.addSignal("quizGameStarted", ".communication", signature='ssass') #args: room_jid, referee, players, profile |
71 host.bridge.addSignal("quizGameNew", ".communication", | 72 host.bridge.addSignal("quizGameNew", ".communication", |
72 signature='sa{ss}s', | 73 signature='sa{ss}s', |
73 doc = { 'summary': 'Start a new game', | 74 doc = { 'summary': 'Start a new game', |
74 'param_0': "jid of game's room", | 75 'param_0': "room_jid: jid of game's room", |
75 'param_1': "data of the game", | 76 'param_1': "game_data: data of the game", |
76 'param_2': '%(doc_profile)s'}) | 77 'param_2': '%(doc_profile)s'}) |
77 host.bridge.addSignal("quizGameQuestion", ".communication", | 78 host.bridge.addSignal("quizGameQuestion", ".communication", |
78 signature = 'sssis', | 79 signature = 'sssis', |
79 doc = { 'summary': "Send the current question", | 80 doc = { 'summary': "Send the current question", |
80 'param_0': "jid of game's room", | 81 'param_0': "room_jid: jid of game's room", |
81 'param_1': "question id", | 82 'param_1': "question_id: question id", |
82 'param_2': "question to ask", | 83 'param_2': "question: question to ask", |
83 'param_3': "timer", | 84 'param_3': "timer: timer", |
84 'param_4': '%(doc_profile)s'}) | 85 'param_4': '%(doc_profile)s'}) |
86 host.bridge.addSignal("quizGamePlayerBuzzed", ".communication", | |
87 signature = 'ssbs', | |
88 doc = { 'summary': "A player just pressed the buzzer", | |
89 'param_0': "room_jid: jid of game's room", | |
90 'param_1': "player: player who pushed the buzzer", | |
91 'param_2': "pause: should the game be paused ?", | |
92 'param_3': '%(doc_profile)s'}) | |
93 host.bridge.addSignal("quizGamePlayerSays", ".communication", | |
94 signature = 'sssis', | |
95 doc = { 'summary': "A player just pressed the buzzer", | |
96 'param_0': "room_jid: jid of game's room", | |
97 'param_1': "player: player who pushed the buzzer", | |
98 'param_2': "text: what the player say", | |
99 'param_3': "delay: how long, in seconds, the text must appear", | |
100 'param_4': '%(doc_profile)s'}) | |
101 host.bridge.addSignal("quizGameAnswerResult", ".communication", | |
102 signature = 'ssba{si}s', | |
103 doc = { 'summary': "Result of the just given answer", | |
104 'param_0': "room_jid: jid of game's room", | |
105 'param_1': "player: player who gave the answer", | |
106 'param_2': "good_answer: True if the answer is right", | |
107 'param_3': "score: dict of score with player as key", | |
108 'param_4': '%(doc_profile)s'}) | |
109 host.bridge.addSignal("quizGameTimerExpired", ".communication", | |
110 signature = 'ss', | |
111 doc = { 'summary': "Nobody answered the question in time", | |
112 'param_0': "room_jid: jid of game's room", | |
113 'param_1': '%(doc_profile)s'}) | |
114 host.bridge.addSignal("quizGameTimerRestarted", ".communication", | |
115 signature = 'sis', | |
116 doc = { 'summary': "Nobody answered the question in time", | |
117 'param_0': "room_jid: jid of game's room", | |
118 'param_1': "time_left: time left before timer expiration", | |
119 'param_2': '%(doc_profile)s'}) | |
85 host.trigger.add("MUC user joined", self.userJoinedTrigger) | 120 host.trigger.add("MUC user joined", self.userJoinedTrigger) |
86 | 121 |
87 def createGameElt(self, to_jid, type="normal"): | 122 def createGameElt(self, to_jid, type="normal"): |
88 type = "normal" if to_jid.resource else "groupchat" | 123 type = "normal" if to_jid.resource else "groupchat" |
89 elt = domish.Element(('jabber:client','message')) | 124 elt = domish.Element(('jabber:client','message')) |
105 """Convert a domish element with game_data to a dict""" | 140 """Convert a domish element with game_data to a dict""" |
106 game_data = {} | 141 game_data = {} |
107 for data_elt in game_data_elt.elements(): | 142 for data_elt in game_data_elt.elements(): |
108 game_data[data_elt.name] = unicode(data_elt) | 143 game_data[data_elt.name] = unicode(data_elt) |
109 return game_data | 144 return game_data |
145 | |
146 def __answer_result_to_signal_args(self, answer_result_elt): | |
147 """Parse answer result element and return a tuple of signal arguments | |
148 @param answer_result_elt: answer result element | |
149 @return: (player, good_answer, score)""" | |
150 score = {} | |
151 for score_elt in answer_result_elt.children: | |
152 score[score_elt['player']] = int(score_elt['score']) | |
153 return (answer_result_elt['player'], answer_result_elt['good_answer'] == str(True), score) | |
154 | |
155 def __answer_result(self, player_answering, good_answer, game_data): | |
156 """Convert a domish an answer_result element | |
157 @param player_answering: player who gave the answer | |
158 @param good_answer: True is the answer is right | |
159 @param game_data: data of the game""" | |
160 players_data = game_data['players_data'] | |
161 score = {} | |
162 for player in game_data['players']: | |
163 score[player] = players_data[player]['score'] | |
164 | |
165 answer_result_elt = domish.Element(('','answer_result')) | |
166 answer_result_elt['player'] = player_answering | |
167 answer_result_elt['good_answer'] = str(good_answer) | |
168 | |
169 for player in score: | |
170 score_elt = domish.Element(('',"score")) | |
171 score_elt['player'] = player | |
172 score_elt['score'] = str(score[player]) | |
173 answer_result_elt.addChild(score_elt) | |
174 | |
175 return answer_result_elt | |
110 | 176 |
111 def __create_started_elt(self, players): | 177 def __create_started_elt(self, players): |
112 """Create a game_started domish element""" | 178 """Create a game_started domish element""" |
113 started_elt = domish.Element(('','started')) | 179 started_elt = domish.Element(('','started')) |
114 idx = 0 | 180 idx = 0 |
118 player_elt['index'] = str(idx) | 184 player_elt['index'] = str(idx) |
119 idx+=1 | 185 idx+=1 |
120 started_elt.addChild(player_elt) | 186 started_elt.addChild(player_elt) |
121 return started_elt | 187 return started_elt |
122 | 188 |
123 def __ask_question(self, question_id, question, timer=30): | 189 def __ask_question(self, question_id, question, timer): |
124 """Create a element for asking a question""" | 190 """Create a element for asking a question""" |
125 question_elt = domish.Element(('','question')) | 191 question_elt = domish.Element(('','question')) |
126 question_elt['id'] = question_id | 192 question_elt['id'] = question_id |
127 question_elt['timer'] = str(timer) | 193 question_elt['timer'] = str(timer) |
128 question_elt.addContent(question) | 194 question_elt.addContent(question) |
131 def __start_play(self, room_jid, game_data, profile): | 197 def __start_play(self, room_jid, game_data, profile): |
132 """Start the game (tell to the first player after dealer to play""" | 198 """Start the game (tell to the first player after dealer to play""" |
133 game_data['stage'] = "play" | 199 game_data['stage'] = "play" |
134 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) #the player after the dealer start | 200 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) #the player after the dealer start |
135 game_data['first_player'] = next_player = game_data['players'][next_player_idx] | 201 game_data['first_player'] = next_player = game_data['players'][next_player_idx] |
136 to_jid = jid.JID(room_jid.userhost()+"/"+next_player) #FIXME: gof: | 202 to_jid = jid.JID(room_jid.userhost()+"/"+next_player) |
137 mess = self.createGameElt(to_jid) | 203 mess = self.createGameElt(to_jid) |
138 yourturn_elt = mess.firstChildElement().addElement('your_turn') | 204 yourturn_elt = mess.firstChildElement().addElement('your_turn') |
139 self.host.profiles[profile].xmlstream.send(mess) | 205 self.host.profiles[profile].xmlstream.send(mess) |
140 | 206 |
141 | 207 |
231 mess = self.createGameElt(jid.JID(referee)) | 297 mess = self.createGameElt(jid.JID(referee)) |
232 ready_elt = mess.firstChildElement().addElement('player_ready') | 298 ready_elt = mess.firstChildElement().addElement('player_ready') |
233 ready_elt['player'] = player | 299 ready_elt['player'] = player |
234 self.host.profiles[profile].xmlstream.send(mess) | 300 self.host.profiles[profile].xmlstream.send(mess) |
235 | 301 |
302 def playerAnswer(self, player, referee, answer, profile_key='@DEFAULT@'): | |
303 """Called when a player give an answer""" | |
304 profile = self.host.memory.getProfileName(profile_key) | |
305 if not profile: | |
306 error (_("profile %s is unknown") % profile_key) | |
307 return | |
308 debug ('new player answer (%(profile)s): %(answer)s' % {'profile':profile, 'answer':answer}) | |
309 mess = self.createGameElt(jid.JID(referee)) | |
310 answer_elt = mess.firstChildElement().addElement('player_answer') | |
311 answer_elt['player'] = player | |
312 answer_elt.addContent(answer) | |
313 self.host.profiles[profile].xmlstream.send(mess) | |
314 | |
315 def timerExpired(self, room_jid, profile): | |
316 """Called when nobody answered the question in time""" | |
317 game_data = self.games[room_jid.userhost()] | |
318 game_data['stage'] = 'expired' | |
319 mess = self.createGameElt(room_jid) | |
320 expired_elt = mess.firstChildElement().addElement('timer_expired') | |
321 self.host.profiles[profile].xmlstream.send(mess) | |
322 reactor.callLater(4, self.askQuestion, room_jid, profile) | |
323 | |
324 def pauseTimer(self, room_jid): | |
325 """Stop the timer and save the time left""" | |
326 game_data = self.games[room_jid.userhost()] | |
327 left = max(0, game_data["timer"].getTime() - time()) | |
328 game_data['timer'].cancel() | |
329 game_data['time_left'] = int(left) | |
330 game_data['previous_stage'] = game_data['stage'] | |
331 game_data['stage'] = "paused" | |
332 | |
333 def restartTimer(self, room_jid, profile): | |
334 """Restart a timer with the saved time""" | |
335 game_data = self.games[room_jid.userhost()] | |
336 assert(game_data['time_left'] != None) | |
337 mess = self.createGameElt(room_jid) | |
338 restarted_elt = mess.firstChildElement().addElement('timer_restarted') | |
339 restarted_elt["time_left"] = str(game_data['time_left']) | |
340 self.host.profiles[profile].xmlstream.send(mess) | |
341 game_data["timer"] = reactor.callLater(game_data['time_left'], self.timerExpired, room_jid, profile) | |
342 game_data["time_left"] = None | |
343 game_data['stage'] = game_data['previous_stage'] | |
344 del game_data['previous_stage'] | |
345 | |
236 def askQuestion(self, room_jid, profile): | 346 def askQuestion(self, room_jid, profile): |
347 """Ask a new question""" | |
348 game_data = self.games[room_jid.userhost()] | |
349 game_data['stage'] = "question" | |
350 game_data['question_id'] = "1" | |
351 timer = 30 | |
237 mess = self.createGameElt(room_jid) | 352 mess = self.createGameElt(room_jid) |
238 mess.firstChildElement().addChild(self.__ask_question("1", u"Quel est l'âge du capitaine ?")) | 353 mess.firstChildElement().addChild(self.__ask_question(game_data['question_id'], u"Quel est l'âge du capitaine ?", timer)) |
239 self.host.profiles[profile].xmlstream.send(mess) | 354 self.host.profiles[profile].xmlstream.send(mess) |
355 game_data["timer"] = reactor.callLater(timer, self.timerExpired, room_jid, profile) | |
356 game_data["time_left"] = None | |
357 | |
358 def checkAnswer(self, room_jid, player, answer, profile): | |
359 """Check if the answer given is right""" | |
360 game_data = self.games[room_jid.userhost()] | |
361 players_data = game_data['players_data'] | |
362 good_answer = game_data['question_id'] == "1" and answer=="42" | |
363 players_data[player]['score'] += 1 if good_answer else -1 | |
364 players_data[player]['score'] = min(9, max(0, players_data[player]['score'])) | |
365 | |
366 mess = self.createGameElt(room_jid) | |
367 mess.firstChildElement().addChild(self.__answer_result(player, good_answer, game_data)) | |
368 self.host.profiles[profile].xmlstream.send(mess) | |
369 | |
370 if good_answer: | |
371 reactor.callLater(4, self.askQuestion, room_jid, profile) | |
372 else: | |
373 reactor.callLater(4, self.restartTimer, room_jid, profile) | |
240 | 374 |
241 def newGame(self, room_jid, profile): | 375 def newGame(self, room_jid, profile): |
242 """Launch a new round""" | 376 """Launch a new round""" |
243 debug (_('new Quiz game')) | 377 debug (_('new Quiz game')) |
244 game_data = self.games[room_jid.userhost()] | 378 game_data = self.games[room_jid.userhost()] |
285 elif elt.name == 'game_data': | 419 elif elt.name == 'game_data': |
286 self.host.bridge.quizGameNew(room_jid.userhost(), self.__xml_to_game_data(elt), profile) | 420 self.host.bridge.quizGameNew(room_jid.userhost(), self.__xml_to_game_data(elt), profile) |
287 | 421 |
288 elif elt.name == 'question': #A question is asked | 422 elif elt.name == 'question': #A question is asked |
289 self.host.bridge.quizGameQuestion(room_jid.userhost(), elt["id"], unicode(elt), int(elt["timer"]), profile ) | 423 self.host.bridge.quizGameQuestion(room_jid.userhost(), elt["id"], unicode(elt), int(elt["timer"]), profile ) |
424 | |
425 elif elt.name == 'player_answer': | |
426 player = elt['player'] | |
427 pause = game_data['stage'] == 'question' #we pause the game only if we are have a question at the moment | |
428 #we first send a buzzer message | |
429 mess = self.createGameElt(room_jid) | |
430 buzzer_elt = mess.firstChildElement().addElement('player_buzzed') | |
431 buzzer_elt['player'] = player | |
432 buzzer_elt['pause'] = str(pause) | |
433 self.host.profiles[profile].xmlstream.send(mess) | |
434 if pause: | |
435 self.pauseTimer(room_jid) | |
436 #and we send the player answer | |
437 mess = self.createGameElt(room_jid) | |
438 _answer = unicode(elt) | |
439 say_elt = mess.firstChildElement().addElement('player_says') | |
440 say_elt['player'] = player | |
441 say_elt.addContent(_answer) | |
442 say_elt['delay'] = "3" | |
443 reactor.callLater(2, self.host.profiles[profile].xmlstream.send, mess) | |
444 reactor.callLater(6, self.checkAnswer, room_jid, player, _answer, profile=profile) | |
290 | 445 |
446 elif elt.name == 'player_buzzed': | |
447 self.host.bridge.quizGamePlayerBuzzed(room_jid.userhost(), elt["player"], elt['pause'] == str(True), profile) | |
448 | |
449 elif elt.name == 'player_says': | |
450 self.host.bridge.quizGamePlayerSays(room_jid.userhost(), elt["player"], unicode(elt), int(elt["delay"]), profile) | |
451 | |
452 elif elt.name == 'answer_result': | |
453 player, good_answer, score = self.__answer_result_to_signal_args(elt) | |
454 self.host.bridge.quizGameAnswerResult(room_jid.userhost(), player, good_answer, score, profile) | |
455 | |
456 elif elt.name == 'timer_expired': | |
457 self.host.bridge.quizGameTimerExpired(room_jid.userhost(), profile) | |
458 | |
459 elif elt.name == 'timer_restarted': | |
460 self.host.bridge.quizGameTimerRestarted(room_jid.userhost(), int(elt['time_left']), profile) | |
461 | |
291 else: | 462 else: |
292 error (_('Unmanaged game element: %s') % elt.name) | 463 error (_('Unmanaged game element: %s') % elt.name) |
293 | 464 |
294 def getHandler(self, profile): | 465 def getHandler(self, profile): |
295 return QuizGameHandler(self) | 466 return QuizGameHandler(self) |