comparison src/plugins/plugin_misc_quiz.py @ 683:75e4f5e2cc65

plugins radiocol, card_game, quiz: code factorization
author souliane <souliane@mailoo.org>
date Wed, 23 Oct 2013 12:45:13 +0200
parents 2805fa3f4bdf
children f610864eb7a5
comparison
equal deleted inserted replaced
682:2805fa3f4bdf 683:75e4f5e2cc65
28 from zope.interface import implements 28 from zope.interface import implements
29 29
30 from wokkel import disco, iwokkel, data_form 30 from wokkel import disco, iwokkel, data_form
31 from sat.tools.xml_tools import dataForm2XML 31 from sat.tools.xml_tools import dataForm2XML
32 from sat.tools.frontends.games import TarotCard 32 from sat.tools.frontends.games import TarotCard
33 33 from sat.tools.plugins.games import RoomGame
34 from time import time 34 from time import time
35 35
36 try: 36 try:
37 from twisted.words.protocols.xmlstream import XMPPHandler 37 from twisted.words.protocols.xmlstream import XMPPHandler
38 except ImportError: 38 except ImportError:
53 "handler": "yes", 53 "handler": "yes",
54 "description": _("""Implementation of Quiz game""") 54 "description": _("""Implementation of Quiz game""")
55 } 55 }
56 56
57 57
58 class Quiz(object): 58 class Quiz(RoomGame):
59 59
60 def __init__(self, host): 60 def __init__(self, host):
61 info(_("Plugin Quiz initialization")) 61 info(_("Plugin Quiz initialization"))
62 self.host = host 62 RoomGame.__init__(self, host, PLUGIN_INFO, (NS_QG, QG_TAG), player_init_data={'score': 0},
63 self.games = {} 63 options={'stage': None})
64 self.waiting_inv = {} # Invitation waiting for people to join to launch a game 64 host.bridge.addMethod("quizGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.prepareRoom) # args: players, profile
65 host.bridge.addMethod("quizGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.quizGameLaunch) # args: players, profile 65 host.bridge.addMethod("quizGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) # args: room_jid, players, profile
66 host.bridge.addMethod("quizGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.quizGameCreate) # args: room_jid, players, profile 66 host.bridge.addMethod("quizGameReady", ".plugin", in_sign='sss', out_sign='', method=self.playerReady) # args: player, referee, profile
67 host.bridge.addMethod("quizGameReady", ".plugin", in_sign='sss', out_sign='', method=self.newPlayerReady) # args: player, referee, profile
68 host.bridge.addMethod("quizGameAnswer", ".plugin", in_sign='ssss', out_sign='', method=self.playerAnswer) 67 host.bridge.addMethod("quizGameAnswer", ".plugin", in_sign='ssss', out_sign='', method=self.playerAnswer)
69 host.bridge.addSignal("quizGameStarted", ".plugin", signature='ssass') # args: room_jid, referee, players, profile 68 host.bridge.addSignal("quizGameStarted", ".plugin", signature='ssass') # args: room_jid, referee, players, profile
70 host.bridge.addSignal("quizGameNew", ".plugin", 69 host.bridge.addSignal("quizGameNew", ".plugin",
71 signature='sa{ss}s', 70 signature='sa{ss}s',
72 doc={'summary': 'Start a new game', 71 doc={'summary': 'Start a new game',
114 doc={'summary': "Nobody answered the question in time", 113 doc={'summary': "Nobody answered the question in time",
115 'param_0': "room_jid: jid of game's room", 114 'param_0': "room_jid: jid of game's room",
116 'param_1': "time_left: time left before timer expiration", 115 'param_1': "time_left: time left before timer expiration",
117 'param_2': '%(doc_profile)s'}) 116 'param_2': '%(doc_profile)s'})
118 host.trigger.add("MUC user joined", self.userJoinedTrigger) 117 host.trigger.add("MUC user joined", self.userJoinedTrigger)
119
120 def createGameElt(self, to_jid, type="normal"):
121 type = "normal" if to_jid.resource else "groupchat"
122 elt = domish.Element((None, 'message'))
123 elt["to"] = to_jid.full()
124 elt["type"] = type
125 elt.addElement((NS_QG, QG_TAG))
126 return elt
127 118
128 def __game_data_to_xml(self, game_data): 119 def __game_data_to_xml(self, game_data):
129 """Convert a game data dict to domish element""" 120 """Convert a game data dict to domish element"""
130 game_data_elt = domish.Element((None, 'game_data')) 121 game_data_elt = domish.Element((None, 'game_data'))
131 for data in game_data: 122 for data in game_data:
170 score_elt['score'] = str(score[player]) 161 score_elt['score'] = str(score[player])
171 answer_result_elt.addChild(score_elt) 162 answer_result_elt.addChild(score_elt)
172 163
173 return answer_result_elt 164 return answer_result_elt
174 165
175 def __create_started_elt(self, players):
176 """Create a game_started domish element"""
177 started_elt = domish.Element((None, 'started'))
178 idx = 0
179 for player in players:
180 player_elt = domish.Element((None, 'player'))
181 player_elt.addContent(player)
182 player_elt['index'] = str(idx)
183 idx += 1
184 started_elt.addChild(player_elt)
185 return started_elt
186
187 def __ask_question(self, question_id, question, timer): 166 def __ask_question(self, question_id, question, timer):
188 """Create a element for asking a question""" 167 """Create a element for asking a question"""
189 question_elt = domish.Element((None, 'question')) 168 question_elt = domish.Element((None, 'question'))
190 question_elt['id'] = question_id 169 question_elt['id'] = question_id
191 question_elt['timer'] = str(timer) 170 question_elt['timer'] = str(timer)
198 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) # the player after the dealer start 177 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) # the player after the dealer start
199 game_data['first_player'] = next_player = game_data['players'][next_player_idx] 178 game_data['first_player'] = next_player = game_data['players'][next_player_idx]
200 to_jid = jid.JID(room_jid.userhost() + "/" + next_player) 179 to_jid = jid.JID(room_jid.userhost() + "/" + next_player)
201 mess = self.createGameElt(to_jid) 180 mess = self.createGameElt(to_jid)
202 yourturn_elt = mess.firstChildElement().addElement('your_turn') 181 yourturn_elt = mess.firstChildElement().addElement('your_turn')
203 self.host.profiles[profile].xmlstream.send(mess)
204
205 def userJoinedTrigger(self, room, user, profile):
206 """This trigger is used to check if we are waiting people in this room,
207 and to create a game if everybody is here"""
208 _room_jid = room.occupantJID.userhostJID()
209 if _room_jid in self.waiting_inv and len(room.roster) == 4:
210 #When we have 4 people in the room, we create the game
211 #TODO: check people identity
212 players = room.roster.keys()
213 del self.waiting_inv[_room_jid]
214 self.quizGameCreate(_room_jid.userhost(), players, profile_key=profile)
215 return True
216
217 def quizGameLaunch(self, players, profile_key='@DEFAULT@'):
218 """Launch a game: helper method to create a room, invite players, and create the quiz game
219 @param players: list for players jid"""
220 debug(_('Launching quiz game'))
221 profile = self.host.memory.getProfileName(profile_key)
222 if not profile:
223 error(_("Unknown profile"))
224 return
225
226 def quizRoomJoined(room):
227 _room = room.occupantJID.userhostJID()
228 for player in players:
229 self.host.plugins["XEP-0249"].invite(jid.JID(player), room.occupantJID.userhostJID(), {"game": "Quiz"}, profile)
230 self.waiting_inv[_room] = (time(), players) # TODO: remove invitation waiting for too long, using the time data
231
232 def after_init(ignore):
233 room_name = "sat_quiz_%s" % self.host.plugins["XEP-0045"].getUniqueName(profile_key)
234 print "\n\n===> room_name:", room_name
235 muc_service = None
236 for service in self.host.memory.getServerServiceEntities("conference", "text", profile):
237 if not ".irc." in service.userhost():
238 #FIXME:
239 #This awfull ugly hack is here to avoid an issue with openfire: the irc gateway
240 #use "conference/text" identity (instead of "conference/irc"), there is certainly a better way
241 #to manage this, but this hack fill do it for test purpose
242 muc_service = service
243 break
244 if not muc_service:
245 error(_("Can't find a MUC service"))
246 return
247
248 _jid, xmlstream = self.host.getJidNStream(profile)
249 d = self.host.plugins["XEP-0045"].join(jid.JID("%s@%s" % (room_name, muc_service.userhost())), _jid.user, {}, profile).addCallback(quizRoomJoined)
250
251 client = self.host.getClient(profile)
252 if not client:
253 error(_('No client for this profile key: %s') % profile_key)
254 return
255 client.client_initialized.addCallback(after_init)
256
257 def quizGameCreate(self, room_jid_param, players, profile_key='@DEFAULT@'):
258 """Create a new game
259 @param room_jid_param: jid of the room
260 @param players: list of players nick (nick must exist in the room)
261 @param profile_key: %(doc_profile_key)s"""
262 debug(_("Creating Quiz game"))
263 room_jid = jid.JID(room_jid_param)
264 profile = self.host.memory.getProfileName(profile_key)
265 if not profile:
266 error(_("profile %s is unknown") % profile_key)
267 return
268 if room_jid in self.games:
269 warning(_("Quiz game already started in room %s") % room_jid.userhost())
270 else:
271 room_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid.userhost(), profile)
272 if not room_nick:
273 error('Internal error')
274 return
275 referee = room_jid.userhost() + '/' + room_nick
276 status = {}
277 players_data = {}
278 for player in players:
279 players_data[player] = {'score': 0}
280 status[player] = "init"
281 self.games[room_jid.userhost()] = {'referee': referee, 'players': players, 'status': status, 'players_data': players_data, 'stage': None}
282 for player in players:
283 mess = self.createGameElt(jid.JID(room_jid.userhost() + '/' + player))
284 mess.firstChildElement().addChild(self.__create_started_elt(players))
285 self.host.profiles[profile].xmlstream.send(mess)
286
287 def newPlayerReady(self, player, referee, profile_key='@DEFAULT@'):
288 """Must be called when player is ready to start a new game"""
289 profile = self.host.memory.getProfileName(profile_key)
290 if not profile:
291 error(_("profile %s is unknown") % profile_key)
292 return
293 debug('new player ready: %s' % profile)
294 mess = self.createGameElt(jid.JID(referee))
295 ready_elt = mess.firstChildElement().addElement('player_ready')
296 ready_elt['player'] = player
297 self.host.profiles[profile].xmlstream.send(mess) 182 self.host.profiles[profile].xmlstream.send(mess)
298 183
299 def playerAnswer(self, player, referee, answer, profile_key='@DEFAULT@'): 184 def playerAnswer(self, player, referee, answer, profile_key='@DEFAULT@'):
300 """Called when a player give an answer""" 185 """Called when a player give an answer"""
301 profile = self.host.memory.getProfileName(profile_key) 186 profile = self.host.memory.getProfileName(profile_key)
369 else: 254 else:
370 reactor.callLater(4, self.restartTimer, room_jid, profile) 255 reactor.callLater(4, self.restartTimer, room_jid, profile)
371 256
372 def newGame(self, room_jid, profile): 257 def newGame(self, room_jid, profile):
373 """Launch a new round""" 258 """Launch a new round"""
374 debug(_('new Quiz game')) 259 common_data = {'game_score': 0}
375 game_data = self.games[room_jid.userhost()]
376 players = game_data['players']
377 players_data = game_data['players_data']
378 game_data['stage'] = "init"
379
380 for player in players:
381 players_data[player]['game_score'] = 0
382
383 new_game_data = {"instructions": _(u"""Bienvenue dans cette partie rapide de quizz, le premier à atteindre le score de 9 remporte le jeu 260 new_game_data = {"instructions": _(u"""Bienvenue dans cette partie rapide de quizz, le premier à atteindre le score de 9 remporte le jeu
384 261
385 Attention, tu es prêt ?""")} 262 Attention, tu es prêt ?""")}
386 263 msg_elts = self.__game_data_to_xml(new_game_data)
387 mess = self.createGameElt(room_jid) 264 RoomGame.newRound(self, room_jid, (common_data, msg_elts), profile)
388 mess.firstChildElement().addChild(self.__game_data_to_xml(new_game_data))
389 self.host.profiles[profile].xmlstream.send(mess)
390 reactor.callLater(10, self.askQuestion, room_jid, profile) 265 reactor.callLater(10, self.askQuestion, room_jid, profile)
391 266
392 def quiz_game_cmd(self, mess_elt, profile): 267 def quiz_game_cmd(self, mess_elt, profile):
393 from_jid = jid.JID(mess_elt['from']) 268 from_jid = jid.JID(mess_elt['from'])
394 room_jid = jid.JID(from_jid.userhost()) 269 room_jid = jid.JID(from_jid.userhost())