예제 #1
0
class DealerBot(irc.IRCClient):
    nickname = "dealer"
    channel_default = Config.CHANNEL_DEFAULT

    game = None
    playerqueue = {}
    joinindex = 0
    whoisinfo = {}

    def isQueued(self, nick):
        for k, v in self.playerqueue.iteritems():
            if nick == v.nick:
                return True
        return False

    def doHand(self, tokens, source, user):
        if self.game is not None:
            player = self.game.getPlayer(user)
            if player is not None:          
                msg = "Your cards: " + player.handToString() + ". Play a card by typing \"send <number>\"."
                self.msg(user, msg)

    def doJoin(self, tokens, source, user):
        if not self.isQueued(user) and source != self.nickname: # Ignore joiner who has already joined; no joining games from PM
            if self.game is not None:
                self.msg(user, "Game is currently in progress. Please wait until it has finished and join the next one!")
            elif len(self.playerqueue) >= Config.PLAYERS_MAX:
                msg = user + ": No more than " + str(Config.PLAYERS_MAX) + " players permitted."
                self.msg(self.channel_default, msg)
            else:
                d = self.whois(user)
                d.addCallback(self.addPlayer, user)

    def doPlayers(self, tokens, source, user):
        msg = user + ": "
        if self.game is not None:
            msg += "There is a game in progress. There are currently " + str(self.game.getPlayerCount())
            msg += " playing: " + self.game.playersToString() + ". The current question-setter is " + self.game.getSetter().nick + "."
        else:
            msg += "There is no game in progress. There are currently " + str(len(self.playerqueue)) + " players waiting for a game to begin."
        self.msg(self.channel_default, msg)

    def doQuit(self, tokens, source, user):
        if self.isQueued(user): # Game has not started, but player in queue wishes to quit
            for k, player in self.playerqueue.iteritems():
                if player.nick == user:
                    del self.playerqueue[k]
                    break
            msg = user + " has left the game. "
            if not self.playerqueue:
                msg += "No players remaining."
            else:
                msg += str(len(self.playerqueue)) + " player(s) remaining."
            self.msg(self.channel_default, msg)
            #self.mode(self.channel_default, False, "v", None, user)
        elif self.game is not None and self.game.isPlayer(user): # Game has started, player wishes to quit
            self.game.removePlayer(user)
            remaining = self.game.getPlayerCount()
            msg = user + " has left the game. "
            if remaining == 0:
                msg += "No players remaining."
                # Handle this
            elif remaining == 1:
                msg += "Only one player remaining."
                # Handle this - declare them the winner
            else:
                msg += str(self.game.getPlayerCount()) + " player(s) remaining."
            self.msg(self.channel_default, msg)
            #self.mode(self.channel_default, False, "v", None, user)

    def doScore(self, tokens, source, user):
        if self.game is not None:
            msg = user + ": Current scores: " + self.game.scoresToString()
            self.msg(self.channel_default, msg)

    def doSelect(self, tokens, source, user):
        if self.game is not None:
            msg, winningcard = self.game.getSelectResponse(tokens, user)
            self.msg(user, msg)
            if winningcard is not None:
                self.awardWin(winningcard)
                if self.game.toContinue():
                   self.game.resetRound()
                   self.round()
                else:
                    self.endGame()

    def doSend(self, tokens, source, user):
        if self.game is not None:

            msg, ready = self.game.getSendResponse(tokens, user)
            self.msg(user, msg)
            if ready:
                shuffle(self.game.played) # Shuffle the potential answers for the question-setter
                self.printSentToSetter()


    def doStart(self, tokens, source, user):

        # Someone attempts to start  
        if self.isQueued(user) and source != self.nickname: # Only players may start a game; no starting games from PM
            if len(self.playerqueue) < Config.PLAYERS_MIN:
                msg = user + ": Minimum of " + str(Config.PLAYERS_MIN) + " players required to start a game."
                self.msg(self.channel_default, msg)
            else:
                self.game = Game(self.playerqueue)
                self.msg(self.channel_default, self.game.getWelcome())
                self.playerqueue = {}        
                self.play()

    def doStats(self, tokens, source, user):
        pass

    def play(self):
        # prototype
        self.round()

        # the actual loop (not testing here)
        #while self.game.toContinue():
        #    self.round(channel)

       #self.endGame(channel)

    def round(self):
        setter = self.game.getSetter()
        question = self.game.dealQuestion()

        topicmsg = setter.nick + " asks: \"" + question + "\""
        self.topic(self.channel_default, topicmsg)

        pmmsg = topicmsg + ". Type \"hand\" to see your hand; type \"send <number>\" to send a response."
        pmmsgsetter = "You have asked: \"" + question + "\". I will PM you again when everyone has responded."
        for nick, player in self.game.players_bynick.iteritems():
            if player == self.game.getSetter():
                self.msg(nick, pmmsgsetter)
            else:
                self.msg(nick, pmmsg)
        # await responses
        # wait for setterto select winner
        # self.game.updateSetter()
        # return

    def addPlayer(self, mask, nick):
        self.playerqueue[self.joinindex] = Player(mask, nick)
        self.joinindex += 1
        print "[Bot:addPlayer] " + nick + " joining."
        for k, player in self.playerqueue.iteritems():
          print "Bot:addPlayer] " + player.nick + " " + player.hostmask
        msg = nick + " has joined the game and raised the number of players to " + str(len(self.playerqueue)) + "."
        self.msg(self.channel_default, msg)
        # this works, but commenting out during testing to reduce spam
        #self.mode(self.channel_default, True, "v", None, nick)

    def endGame(self):
        self.msg(self.channel_default, "Game over!")
        self.printWinner()
        for order, player in self.game.players_byorder.iteritems():
            self.mode(self.channel_default, False, "v", None, player.nick)
        self.topic(self.channel_default, Config.TOPIC_DEFAULT)
        self.game = None
        self.joinindex = 0

    commands = { "exit" : doQuit,
                 "hand" : doHand,
                 "j" : doJoin,
                 "join" : doJoin,
                 "leave" : doQuit,
                 "players" : doPlayers,
                 "q" : doQuit,
                 "quit" : doQuit,
                 "score" : doScore,
                 "scores" : doScore,
                 "select" : doSelect,
                 "send" : doSend,
                 "start" : doStart,
                 "stats" : doStats }

    def printWinner(self):
        winners, winningscore = self.game.getWinners()
        msg = ""

        if winners is not None and winningscore > 0:
            if len(winners) == 1:
                msg = "The winner is: " + winners[0].nick + " with " + str(winningscore) + " points!"
            else:
                msg = "There are " + str(len(winners)) + " players tied as winner: "
                for i in range(len(winners)-1):
                    msg += winners[i].nick + ", "
                msg += "and " + winners[len(winners)-1].nick + ", all on " + str(winningscore) + " points!"
        else:
            msg = "There were no winners in this game."

        self.msg(self.channel_default, msg)

    def printSentToSetter(self):
        setter = self.game.getSetter()
        msg = "Please select one of the following by typing \"select <number>\": "
        for i in range(len(self.game.played)):
            msg += "[" + str(i+1) + "] " + self.game.played[i][0] + ", "
        msg = msg[:-2] + "."
        self.msg(setter.nick, msg)

    def printSentToChannel(self):
        msg = "The available choices were: "
        for i in range(len(self.game.played)):
            msg += "[" + self.game.played[i][1].nick + "] " + self.game.played[i][0] + ", "
        msg = msg[:-2] + "."
        self.msg(self.channel_default, msg)

    def awardWin(self, winningcard):
        card = winningcard[0]
        player = winningcard[1]
        self.game.awardQuestion(player, card)
        self.printSentToChannel()
        msg = self.game.getSetter().nick + " chose " + player.nick + "'s: \"" + card + "\" as the winning answer."
        self.msg(self.channel_default, msg)

    def connectionMade(self):
        irc.IRCClient.connectionMade(self)
        self.logger = MessageLogger(open(self.factory.filename, "a"))
        self.logger.log("[connected at %s]" % 
                        time.asctime(time.localtime(time.time())))


    def connectionLost(self, reason):
        irc.IRCClient.connectionLost(self, reason)
        self.logger.log("[disconnected at %s]" % 
                        time.asctime(time.localtime(time.time())))
        self.logger.close()


    # Whois wrapper
    def whois(self, nick):
        d = defer.Deferred()
        if nick in self.whoisinfo:
            ds = self.whoisinfo[nick][0]
            ds.append(d)
            return d
  
        info = {}
        self.whoisinfo[nick] = [[d], info]
        irc.IRCClient.whois(self, nick, None)
        return d

    # callbacks for events

    def irc_RPL_WHOISUSER(self, prefix, params):
        nick = params[1]
        mask = params[2] + '@' + params[3]
        self.whoisinfo[nick][1] = mask

  
    def irc_RPL_ENDOFWHOIS(self, prefix, params):
        nick = params[1].lower()
        if nick in self.whoisinfo:
            ds = self.whoisinfo[nick][0]
            info = self.whoisinfo[nick][1]
            del self.whoisinfo[nick]
            [d.callback(info) for d in ds]


    def signedOn(self):
        self.join(self.factory.channel)


    def privmsg(self, user, channel, msg):
        user = user.split('!', 1)[0]
        self.logger.log("<%s> %s" % (user, msg))
        
        tokens = re.split(' *', msg.strip())

        # Check whether it starts with trigger
        if msg.startswith(Config.TRIGGER):
            cmd = tokens[0][len(Config.TRIGGER):]
            if cmd in self.commands:
                self.commands[cmd](self, tokens, channel, user)

        # Check to see if they're sending a private message
        # These are the same as messages in channel with trigger, except that here trigger is not needed
        elif channel == self.nickname:
            cmd = tokens[0]
            if cmd in self.commands:
                self.commands[cmd](self, tokens, channel, user)            

        # Otherwise check to see if it is a message directed at me
        #if msg.startswith(self.nickname + ":"):
        #    msg = "%s: lol" % user
        #    self.msg(channel, msg)
        #    self.logger.log("<%s> %s" % (self.nickname, msg))


    def action(self, user, channel, msg):
        """This will get called when the bot sees someone do an action."""
        user = user.split('!', 1)[0]
        self.logger.log("* %s %s" % (user, msg))


    def irc_NICK(self, prefix, params):
        """Called when an IRC user changes their nickname."""
        old_nick = prefix.split('!')[0]
        new_nick = params[0]
        self.logger.log("%s is now known as %s" % (old_nick, new_nick))


    def alterCollidedNick(self, nickname):
        return nickname + '^'