From b80880328870d5dfde12555912029b1af175e4a6 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 17 Jul 2012 11:52:55 -0700 Subject: [PATCH 01/67] Initial commit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c939e2f --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +supybot-plugin-DuckHunt +======================= + +A DuckHunt game for IRC, as a plugin for supybot \ No newline at end of file From 568678e2536919627011d4a64031fa0acf6b6f32 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 17 Jul 2012 20:59:22 +0200 Subject: [PATCH 02/67] First commit, the DuckHunt game for IRC --- README.txt | 6 + __init__.py | 65 +++++++ config.py | 58 ++++++ plugin.py | 519 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test.py | 36 ++++ 5 files changed, 684 insertions(+) create mode 100644 README.txt create mode 100644 __init__.py create mode 100644 config.py create mode 100644 plugin.py create mode 100644 test.py diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..d184008 --- /dev/null +++ b/README.txt @@ -0,0 +1,6 @@ +This is a DuckHunt game for supybot +Start a hunt with the "start" command. +Once the hunt is started, the bot will launch a duck from time to time. +The first person that shoots the duck (with the "bang" command) gets one point. +When someone shoots when there is no duck (or the duck has already been shot), he loses one point. +Scores as well as best times are saved per channel and you can display them at anytime with the "listscores" and "listtimes" commands. diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..0f7de5a --- /dev/null +++ b/__init__.py @@ -0,0 +1,65 @@ +### +# Copyright (c) 2012, Matthias Meusburger +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +""" +This is a DuckHunt game for supybot +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/DuckHunt/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/config.py b/config.py new file mode 100644 index 0000000..efdcca6 --- /dev/null +++ b/config.py @@ -0,0 +1,58 @@ +### +# Copyright (c) 2012, Matthias Meusburger +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot to configure this module. advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('DuckHunt', True) + + +DuckHunt = conf.registerPlugin('DuckHunt') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(Quote, 'someConfigVariableName', +# registry.Boolean(False, """Help for someConfigVariableName.""")) +conf.registerChannelValue(DuckHunt, 'autoRestart', + registry.Boolean(False, """Does a new hunt automatically start when the previous one is over?""")) + +conf.registerChannelValue(DuckHunt, 'ducks', + registry.Integer(3, """Number of ducks during a hunt?""")) + + +conf.registerChannelValue(DuckHunt, + 'frequency', registry.Probability(0.3, """ + Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that a ducks will be launched one after another. """)) + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugin.py b/plugin.py new file mode 100644 index 0000000..85605bb --- /dev/null +++ b/plugin.py @@ -0,0 +1,519 @@ +### +# Copyright (c) 2012, Matthias Meusburger +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from supybot.commands import * +import supybot.plugins as plugins +import supybot.callbacks as callbacks +import threading, random, pickle, os, time +import supybot.ircdb as ircdb + + + + +class DuckHunt(callbacks.Plugin): + """ + A DuckHunt game for supybot. Use the "start" command to start a game. + The bot will randomly launch ducks. Whenever a duck is launched, the first + person to use the "bang" command wins a point. Using the "bang" command + when there is no duck launched costs a point. + """ + +# threaded = True + + # Those parameters are per-channel parameters + started = {} # Has the hunt started? + duck = {} # Is there currently a duck to shoot? + shoots = {} # Number of successfull shoots in a hunt + scores = {} # Scores for the current hunt + times = {} # Elapsed time since the last duck was launched + channelscores = {} # Saved scores for the channel + toptimes = {} # Times for the current hunt + channeltimes = {} # Saved times for the channel + + # Where to save scores? + path = "supybot/data/DuckHunt/" + + # Does a duck needs to be launched? + probability = 1 + lastSpoke = time.time() + minthrottle = 15 + maxthrottle = 45 + throttle = random.randint(minthrottle, maxthrottle) + debug = 0 + + # Adds new scores and times to the already saved ones + # and saves them back to the disk + def _write_scores(self, msg): + currentChannel = msg.args[0] + # scores + # Adding current scores to the channel scores + for player in self.scores[currentChannel].keys(): + if not player in self.channelscores[currentChannel]: + # It's a new player + self.channelscores[currentChannel][player] = self.scores[currentChannel][player] + else: + # It's a player that already has a saved score + self.channelscores[currentChannel][player] += self.scores[currentChannel][player] + + outputfile = open(self.path + msg.args[0] + ".scores", "wb") + pickle.dump(self.channelscores[currentChannel], outputfile) + outputfile.close() + + # times + # Adding times scores to the channel scores + for player in self.toptimes[currentChannel].keys(): + if not player in self.channeltimes[currentChannel]: + # It's a new player + self.channeltimes[currentChannel][player] = self.toptimes[currentChannel][player] + else: + # It's a player that already has a saved score + # And we save the time of the current hunt if it's better than it's previous time + if(self.toptimes[currentChannel][player] < self.channeltimes[currentChannel][player]): + self.channeltimes[currentChannel][player] = self.toptimes[currentChannel][player] + + outputfile = open(self.path + msg.args[0] + ".times", "wb") + pickle.dump(self.channeltimes[currentChannel], outputfile) + outputfile.close() + + + # Reads scores and times from disk + def _read_scores(self, msg): + # scores + if os.path.isfile(self.path + msg.args[0] + ".scores"): + inputfile = open(self.path + msg.args[0] + ".scores", "rb") + self.channelscores[msg.args[0]] = pickle.load(inputfile) + inputfile.close() + + # times + if os.path.isfile(self.path + msg.args[0] + ".times"): + inputfile = open(self.path + msg.args[0] + ".times", "rb") + self.channeltimes[msg.args[0]] = pickle.load(inputfile) + inputfile.close() + + + # Starts a hunt + def start(self, irc, msg, args): + """ + Starts the hunt + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + + if(self.started.get(currentChannel) == True): + irc.reply("There is already a hunt right now!") + else: + + # Init frequency + if self.registryValue('frequency', currentChannel): + self.probability = self.registryValue('frequency', currentChannel) + else: + self.probability = 0.3 + + # Init saved scores + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} + + # Init saved times + try: + self.channeltimes[currentChannel] + except: + self.channeltimes[currentChannel] = {} + + # Init times + self.toptimes[currentChannel] = {} + + # Init bangdelay + self.times[currentChannel] = False + + if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel]: + self._read_scores(msg) + + # Reinit current hunt scores + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} + + # Reinit current hunt times + self.toptimes[currentChannel] = {} + + # No duck launched + self.duck[currentChannel] = False + + # Hunt started + self.started[currentChannel] = True + + irc.reply("The hunt starts now!") + else: + irc.error('You have to be on a channel') + start = wrap(start) + + # Stops the current hunt + def stop(self, irc, msg, args): + """ + Stops the hunt + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + self._end(irc, msg, args) + else: + irc.error('You have to be on a channel') + stop = wrap(stop) + + # Tells if there is currently a duck + def launched(self, irc, msg, args): + """ + Is there a duck right now? + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + if(self.duck[currentChannel] == True): + irc.reply("There is currently a duck! You can shoot it with the 'bang' command") + else: + irc.reply("There is no duck right now! Wait for one to be launched!") + else: + irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") + else: + irc.error('You have to be on a channel') + launched = wrap(launched) + + + # Shows the score for a given nick + def score(self, irc, msg, args, nick): + """: Shows the score for a given nick """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} + + if not self.channelscores[currentChannel]: + self._read_scores(msg) + + try: + irc.reply(self.channelscores[currentChannel][nick]) + except: + irc.reply("There is no score for %s on %s" % (nick, currentChannel)) + else: + irc.error('You have to be on a channel') + + score = wrap(score, ['anything']) + + # Merge scores + # nickto gets the points of nickfrom and nickfrom is removed from the scorelist + def merge(self, irc, msg, args, nickto, nickfrom): + """ : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ + if self._capability(msg, 'owner'): + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + try: + self.channelscores[currentChannel][nickto] += self.channelscores[currentChannel][nickfrom] + del self.channelscores[currentChannel][nickfrom] + irc.reply("Okay! (will be effective at the end of the hunt)") + + except: + irc.error("Something went wrong") + + + else: + irc.error('You have to be on a channel') + + else: + irc.error("Who are you again?") + + merge = wrap(merge, ['anything', 'anything']) + + + + # Shows all scores for the channel + def listscores(self, irc, msg, args): + """ + Shows the score list for the current channel + """ + + currentChannel = msg.args[0] + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} + + if not self.channelscores[currentChannel]: + self._read_scores(msg) + + # Sort the scores (reversed: the higher the better) + scores = sorted(self.channelscores[currentChannel].iteritems(), key=lambda (k,v):(v,k), reverse=True) + + msgstring = "" + for item in scores: + # Why do we show the nicks as xnickx? + # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list + msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt scores for " + msg.args[0] + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any scores for this channel yet.") + listscores = wrap(listscores) + + + # Shows all times for the channel + def listtimes(self, irc, msg, args): + """ + Shows the times list for the current channel + """ + + currentChannel = msg.args[0] + try: + self.channeltimes[currentChannel] + except: + self.channeltimes[currentChannel] = {} + + if not self.channeltimes[currentChannel]: + self._read_scores(msg) + + # Sort the times (not reversed: the lower the better) + times = sorted(self.channeltimes[currentChannel].iteritems(), key=lambda (k,v):(v,k), reverse=False) + + msgstring = "" + for item in times: + # Same as in listscores for the xnickx + msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt times for " + msg.args[0] + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any times for this channel yet.") + listscores = wrap(listscores) + + + # This is the callback when someones speaks in the channel + # We use this to determine if a duck has to be launched + def doPrivmsg(self, irc, msg): + currentChannel = msg.args[0] + now = time.time() + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + if (self.duck[currentChannel] == False): + if now > self.lastSpoke + self.throttle: + if random.random() < self.probability: + self._launch(irc, msg, '') + self.lastSpoke = now + + + # This is the debug function: when debug is enabled, + # it launches a duck when called + def dbg(self, irc, msg, args): + """ This is a debug command. If debug mode is not enabled, it won't do anything """ + currentChannel = msg.args[0] + if (self.debug): + if irc.isChannel(currentChannel): + self._launch(irc, msg, '') + dbg = wrap(dbg) + + + # Shoots the duck! + def bang(self, irc, msg, args): + """ + Shoots the duck! + """ + currentChannel = msg.args[0] + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) + else: + maxShoots = 10 + + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + + # bangdelay: how much time between the duck and launched and this shot? + if self.times[currentChannel]: + bangdelay = time.time() - self.times[currentChannel] + else: + bangdelay = False + + # There was a duck + if (self.duck[currentChannel] == True): + + # Adds one point for the nick that shot the duck + try: + self.scores[currentChannel][msg.nick] += 1 + except: + try: + self.scores[currentChannel][msg.nick] = 1 + except: + self.scores[currentChannel] = {} + self.scores[currentChannel][msg.nick] = 1 + + irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) + + # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) + try: + previoustime = self.toptimes[currentChannel][msg.nick] + if(bangdelay < previoustime): + self.toptimes[currentChannel][msg.nick] = bangdelay + except: + self.toptimes[currentChannel][msg.nick] = bangdelay + + self.duck[currentChannel] = False + # End of Hunt + if (self.shoots[currentChannel] == maxShoots): + self._end(irc, msg, args) + + # If autorestart is enabled, we restart a hunt automatically! + if self.registryValue('autoRestart', currentChannel): + self.started[currentChannel] = True + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} + irc.reply("The hunt starts now!") + + + # There was no duck or the duck has already been shot + else: + + # Removes one point for the nick that shot + try: + self.scores[currentChannel][msg.nick] -= 1 + except: + try: + self.scores[currentChannel][msg.nick] = -1 + except: + self.scores[currentChannel] = {} + self.scores[currentChannel][msg.nick] = -1 + + + # If we were able to have a bangdelay (ie: a duck was launched before someone did bang) + if (bangdelay): + irc.reply("There was no duck! %s: %i (%.2f seconds) " % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) + else: + irc.reply("There was no duck! %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick])) + else: + irc.reply("The hunt has not started yet!") + else: + irc.error('You have to be on a channel') + + bang = wrap(bang) + + # End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) + def _end(self, irc, msg, args): + currentChannel = msg.args[0] + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} + + irc.reply("The hunt stops now!") + + # Showing scores + irc.reply(self.scores.get(currentChannel)) + + # Getting channel best time (to see if the best time of this hunt is better) + channelbestnick = None + channelbesttime = None + if self.channeltimes.get(currentChannel): + channelbestnick, channelbesttime = min(self.channeltimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + + # Showing best time + recordmsg = '' + if (self.toptimes.get(currentChannel)): + key,value = min(self.toptimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + if (channelbesttime and value < channelbesttime): + recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' + else: + try: + if(value < self.channeltimes[currentChannel][key]): + recordmsg = ' (this is your new record in this channel! Your previous record was ' + str(round(self.channeltimes[currentChannel][key],2)) + ')' + except: + recordmsg = '' + + irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) + + # Write the scores and times to disk + self._write_scores(msg) + + # Reinit current hunt scores + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} + + # Reinit current hunt times + if self.toptimes.get(currentChannel): + self.toptimes[currentChannel] = {} + + # No duck lauched + self.duck[currentChannel] = False + + # Hunt not started + self.started[currentChannel] = False + + # Reinit number of shoots + self.shoots[currentChannel] = 0 + + + + # Launch a duck + def _launch(self, irc, msg, args): + """ + Launch a duck + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + if(self.started[currentChannel] == True): + if (self.duck[currentChannel] == False): + self.times[currentChannel] = time.time() + self.throttle = random.randint(self.minthrottle, self.maxthrottle) + irc.reply("\_o< quack!") + self.duck[currentChannel] = True + # Store time here + try: + self.shoots[currentChannel] += 1 + except: + self.shoots[currentChannel] = 1 + else: + + irc.reply("Already a duck") + else: + irc.reply("The hunting has not started yet!") + else: + irc.error('You have to be on a channel') + + + def _capability(self, msg, c): + try: + u = ircdb.users.getUser(msg.prefix) + if u._checkCapability(c): + return True + except: + return False + + + +Class = DuckHunt + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/test.py b/test.py new file mode 100644 index 0000000..ec4ac7c --- /dev/null +++ b/test.py @@ -0,0 +1,36 @@ +### +# Copyright (c) 2012, Matthias Meusburger +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from supybot.test import * + +class DuckHuntTestCase(PluginTestCase): + plugins = ('DuckHuntTestCase',) + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From 14537359184df8ede4d026ff2712cef927e6576c Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 17 Jul 2012 22:06:14 +0200 Subject: [PATCH 03/67] Update documentation --- README.md | 4 ---- README.txt | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index c939e2f..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -supybot-plugin-DuckHunt -======================= - -A DuckHunt game for IRC, as a plugin for supybot \ No newline at end of file diff --git a/README.txt b/README.txt index d184008..0a7b331 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,5 @@ -This is a DuckHunt game for supybot -Start a hunt with the "start" command. -Once the hunt is started, the bot will launch a duck from time to time. -The first person that shoots the duck (with the "bang" command) gets one point. -When someone shoots when there is no duck (or the duck has already been shot), he loses one point. -Scores as well as best times are saved per channel and you can display them at anytime with the "listscores" and "listtimes" commands. +A DuckHunt game for supybot. Use the "start" command to start a game. +The bot will randomly launch ducks. Whenever a duck is launched, the first +person to use the "bang" command wins a point. Using the "bang" command +when there is no duck launched costs a point. + From 5e5049de50b91effa25b5846b0336a9f2c1788b4 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 19 Jul 2012 17:31:30 +0200 Subject: [PATCH 04/67] Several modifications/improvements: - Use threading - Send the duck directly without queuing, so times are more accurate - Adds comments --- plugin.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/plugin.py b/plugin.py index 85605bb..34a096f 100644 --- a/plugin.py +++ b/plugin.py @@ -32,6 +32,8 @@ import supybot.plugins as plugins import supybot.callbacks as callbacks import threading, random, pickle, os, time import supybot.ircdb as ircdb +import supybot.ircmsgs as ircmsgs + @@ -44,7 +46,7 @@ class DuckHunt(callbacks.Plugin): when there is no duck launched costs a point. """ -# threaded = True + threaded = True # Those parameters are per-channel parameters started = {} # Has the hunt started? @@ -486,11 +488,19 @@ class DuckHunt(callbacks.Plugin): if irc.isChannel(currentChannel): if(self.started[currentChannel] == True): if (self.duck[currentChannel] == False): + + # Store the time when the duck has been launched self.times[currentChannel] = time.time() - self.throttle = random.randint(self.minthrottle, self.maxthrottle) - irc.reply("\_o< quack!") + + # Store the fact that there's a duck now self.duck[currentChannel] = True - # Store time here + + # Send message directly (instead of queuing it with irc.reply) + irc.sendMsg(ircmsgs.privmsg(currentChannel, "\_o< quack!")) + + # Define a new throttle for the next launch + self.throttle = random.randint(self.minthrottle, self.maxthrottle) + try: self.shoots[currentChannel] += 1 except: From 64c5b0fd5f10b2005b27c574cea97e8606e80306 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 20 Jul 2012 12:20:14 +0200 Subject: [PATCH 05/67] Adds a lock when someone bangs, to prevent from lauching a duck at the same time --- README.txt | 2 ++ plugin.py | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/README.txt b/README.txt index 0a7b331..862407f 100644 --- a/README.txt +++ b/README.txt @@ -1,3 +1,5 @@ +\_o< ~ DuckHunt game for supybot ~ >o_/ + A DuckHunt game for supybot. Use the "start" command to start a game. The bot will randomly launch ducks. Whenever a duck is launched, the first person to use the "bang" command wins a point. Using the "bang" command diff --git a/plugin.py b/plugin.py index 34a096f..8ad73aa 100644 --- a/plugin.py +++ b/plugin.py @@ -51,6 +51,7 @@ class DuckHunt(callbacks.Plugin): # Those parameters are per-channel parameters started = {} # Has the hunt started? duck = {} # Is there currently a duck to shoot? + banging = {} # Is there someone "banging" ;) right now? shoots = {} # Number of successfull shoots in a hunt scores = {} # Scores for the current hunt times = {} # Elapsed time since the last duck was launched @@ -171,6 +172,9 @@ class DuckHunt(callbacks.Plugin): # Hunt started self.started[currentChannel] = True + # Init banging + self.banging[currentChannel] = False + irc.reply("The hunt starts now!") else: irc.error('You have to be on a channel') @@ -324,10 +328,13 @@ class DuckHunt(callbacks.Plugin): if irc.isChannel(currentChannel): if(self.started.get(currentChannel) == True): if (self.duck[currentChannel] == False): + if now > self.lastSpoke + self.throttle: if random.random() < self.probability: - self._launch(irc, msg, '') - self.lastSpoke = now + # If someone is "banging" right now, do not launch a duck + if (not self.banging[currentChannel]): + self._launch(irc, msg, '') + self.lastSpoke = now # This is the debug function: when debug is enabled, @@ -347,15 +354,12 @@ class DuckHunt(callbacks.Plugin): Shoots the duck! """ currentChannel = msg.args[0] - if self.registryValue('ducks', currentChannel): - maxShoots = self.registryValue('ducks', currentChannel) - else: - maxShoots = 10 + self.banging[currentChannel] = True if irc.isChannel(currentChannel): if(self.started.get(currentChannel) == True): - # bangdelay: how much time between the duck and launched and this shot? + # bangdelay: how much time between the duck was launched and this shot? if self.times[currentChannel]: bangdelay = time.time() - self.times[currentChannel] else: @@ -385,6 +389,12 @@ class DuckHunt(callbacks.Plugin): self.toptimes[currentChannel][msg.nick] = bangdelay self.duck[currentChannel] = False + + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) + else: + maxShoots = 10 + # End of Hunt if (self.shoots[currentChannel] == maxShoots): self._end(irc, msg, args) @@ -421,6 +431,8 @@ class DuckHunt(callbacks.Plugin): else: irc.error('You have to be on a channel') + self.banging[currentChannel] = False + bang = wrap(bang) # End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) From b76251f1e9bf3570aa37c5393f634a1085214989 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 20 Jul 2012 12:22:43 +0200 Subject: [PATCH 06/67] Rename merge command to mergescores Add mergetimes, rmscore and rmtime commands --- plugin.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index 8ad73aa..ebc32e2 100644 --- a/plugin.py +++ b/plugin.py @@ -235,7 +235,7 @@ class DuckHunt(callbacks.Plugin): # Merge scores # nickto gets the points of nickfrom and nickfrom is removed from the scorelist - def merge(self, irc, msg, args, nickto, nickfrom): + def mergescores(self, irc, msg, args, nickto, nickfrom): """ : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ if self._capability(msg, 'owner'): currentChannel = msg.args[0] @@ -255,7 +255,78 @@ class DuckHunt(callbacks.Plugin): else: irc.error("Who are you again?") - merge = wrap(merge, ['anything', 'anything']) + mergescores = wrap(mergescores, ['anything', 'anything']) + + # Merge times + def mergetimes(self, irc, msg, args, nickto, nickfrom): + """ : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist """ + if self._capability(msg, 'owner'): + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + try: + if self.channeltimes[currentChannel][nickfrom] < self.channeltimes[currentChannel][nickto]: + self.channeltimes[currentChannel][nickto] = self.channeltimes[currentChannel][nickfrom] + del self.channeltimes[currentChannel][nickfrom] + irc.reply("Okay! (will be effective at the end of the hunt)") + + except: + irc.error("Something went wrong") + + + else: + irc.error('You have to be on a channel') + + else: + irc.error("Who are you again?") + + mergetimes = wrap(mergetimes, ['anything', 'anything']) + + + # Remove 's best time + def rmtime(self, irc, msg, args, nick): + """: Remove 's best time """ + if self._capability(msg, 'owner'): + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + try: + del self.channeltimes[currentChannel][nick] + irc.reply("Okay! (will be effective at the end of the hunt)") + + except: + irc.error("Something went wrong") + + + else: + irc.error('You have to be on a channel') + + else: + irc.error("Who are you again?") + + rmtime = wrap(rmtime, ['anything']) + + + # Remove 's best time + def rmscore(self, irc, msg, args, nick): + """: Remove 's score """ + if self._capability(msg, 'owner'): + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + try: + del self.channelscores[currentChannel][nick] + irc.reply("Okay! (will be effective at the end of the hunt)") + + except: + irc.error("Something went wrong") + + + else: + irc.error('You have to be on a channel') + + else: + irc.error("Who are you again?") + + rmscore = wrap(rmscore, ['anything']) + From 43be7c99c215212ca7410885798972c7ba248c08 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 20 Jul 2012 17:37:58 +0200 Subject: [PATCH 07/67] Adds an optional parameter to rmtime, rmscore, listtimes and listscores Separate scores calculation and writing (so that rmtime, rmscore, listtimes and listscores) are immedialely effective --- plugin.py | 243 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 133 insertions(+), 110 deletions(-) diff --git a/plugin.py b/plugin.py index ebc32e2..c3a949a 100644 --- a/plugin.py +++ b/plugin.py @@ -72,52 +72,58 @@ class DuckHunt(callbacks.Plugin): # Adds new scores and times to the already saved ones # and saves them back to the disk - def _write_scores(self, msg): - currentChannel = msg.args[0] + def _calc_scores(self, channel): # scores # Adding current scores to the channel scores - for player in self.scores[currentChannel].keys(): - if not player in self.channelscores[currentChannel]: + for player in self.scores[channel].keys(): + if not player in self.channelscores[channel]: # It's a new player - self.channelscores[currentChannel][player] = self.scores[currentChannel][player] + self.channelscores[channel][player] = self.scores[channel][player] else: # It's a player that already has a saved score - self.channelscores[currentChannel][player] += self.scores[currentChannel][player] - - outputfile = open(self.path + msg.args[0] + ".scores", "wb") - pickle.dump(self.channelscores[currentChannel], outputfile) - outputfile.close() + self.channelscores[channel][player] += self.scores[channel][player] # times # Adding times scores to the channel scores - for player in self.toptimes[currentChannel].keys(): - if not player in self.channeltimes[currentChannel]: + for player in self.toptimes[channel].keys(): + if not player in self.channeltimes[channel]: # It's a new player - self.channeltimes[currentChannel][player] = self.toptimes[currentChannel][player] + self.channeltimes[channel][player] = self.toptimes[channel][player] else: # It's a player that already has a saved score # And we save the time of the current hunt if it's better than it's previous time - if(self.toptimes[currentChannel][player] < self.channeltimes[currentChannel][player]): - self.channeltimes[currentChannel][player] = self.toptimes[currentChannel][player] + if(self.toptimes[channel][player] < self.channeltimes[channel][player]): + self.channeltimes[channel][player] = self.toptimes[channel][player] - outputfile = open(self.path + msg.args[0] + ".times", "wb") - pickle.dump(self.channeltimes[currentChannel], outputfile) + + def _write_scores(self, channel): + # scores + outputfile = open(self.path + channel + ".scores", "wb") + pickle.dump(self.channelscores[channel], outputfile) + outputfile.close() + + # times + outputfile = open(self.path + channel + ".times", "wb") + pickle.dump(self.channeltimes[channel], outputfile) outputfile.close() + # Reads scores and times from disk - def _read_scores(self, msg): + def _read_scores(self, channel): # scores - if os.path.isfile(self.path + msg.args[0] + ".scores"): - inputfile = open(self.path + msg.args[0] + ".scores", "rb") - self.channelscores[msg.args[0]] = pickle.load(inputfile) - inputfile.close() + if not self.channelscores.get(channel): + if os.path.isfile(self.path + channel + ".scores"): + inputfile = open(self.path + channel + ".scores", "rb") + self.channelscores[channel] = pickle.load(inputfile) + inputfile.close() # times - if os.path.isfile(self.path + msg.args[0] + ".times"): - inputfile = open(self.path + msg.args[0] + ".times", "rb") - self.channeltimes[msg.args[0]] = pickle.load(inputfile) - inputfile.close() + if not self.channeltimes.get(channel): + if os.path.isfile(self.path + channel + ".times"): + inputfile = open(self.path + channel + ".times", "rb") + self.channeltimes[channel] = pickle.load(inputfile) + inputfile.close() # Starts a hunt @@ -157,7 +163,7 @@ class DuckHunt(callbacks.Plugin): self.times[currentChannel] = False if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel]: - self._read_scores(msg) + self._read_scores(currentChannel) # Reinit current hunt scores if self.scores.get(currentChannel): @@ -216,13 +222,12 @@ class DuckHunt(callbacks.Plugin): """: Shows the score for a given nick """ currentChannel = msg.args[0] if irc.isChannel(currentChannel): + self._read_scores(currentChannel) try: self.channelscores[currentChannel] except: self.channelscores[currentChannel] = {} - if not self.channelscores[currentChannel]: - self._read_scores(msg) try: irc.reply(self.channelscores[currentChannel][nick]) @@ -241,9 +246,12 @@ class DuckHunt(callbacks.Plugin): currentChannel = msg.args[0] if irc.isChannel(currentChannel): try: + self._read_scores(currentChannel) self.channelscores[currentChannel][nickto] += self.channelscores[currentChannel][nickfrom] del self.channelscores[currentChannel][nickfrom] - irc.reply("Okay! (will be effective at the end of the hunt)") + self._write_scores(currentChannel) + #TODO: Reply with the config success message + irc.reply("Okay!") except: irc.error("Something went wrong") @@ -264,10 +272,13 @@ class DuckHunt(callbacks.Plugin): currentChannel = msg.args[0] if irc.isChannel(currentChannel): try: + self._read_scores(currentChannel) if self.channeltimes[currentChannel][nickfrom] < self.channeltimes[currentChannel][nickto]: self.channeltimes[currentChannel][nickto] = self.channeltimes[currentChannel][nickfrom] del self.channeltimes[currentChannel][nickfrom] - irc.reply("Okay! (will be effective at the end of the hunt)") + self._write_scores(currentChannel) + + irc.reply("Okay!") except: irc.error("Something went wrong") @@ -283,112 +294,123 @@ class DuckHunt(callbacks.Plugin): # Remove 's best time - def rmtime(self, irc, msg, args, nick): - """: Remove 's best time """ + def rmtime(self, irc, msg, args, channel, nick): + """[] : Remove 's best time """ if self._capability(msg, 'owner'): - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): + + if (not channel): + channel = msg.args[0] + + if irc.isChannel(channel): + self._read_scores(channel) + del self.channeltimes[channel][nick] + self._write_scores(channel) + irc.reply("Okay!") + + + + else: + irc.error('Are you sure ' + str(channel) + ' is a channel?') + + else: + irc.error("Who are you again?") + + rmtime = wrap(rmtime, [optional('anything'), 'anything']) + + + # Remove 's best score + def rmscore(self, irc, msg, args, channel, nick): + """[] : Remove 's score """ + if self._capability(msg, 'owner'): + + if (not channel): + channel = msg.args[0] + + if irc.isChannel(channel): try: - del self.channeltimes[currentChannel][nick] - irc.reply("Okay! (will be effective at the end of the hunt)") + self._read_scores(channel) + del self.channelscores[channel][nick] + self._write_scores(channel) + irc.reply("Okay!") except: irc.error("Something went wrong") else: - irc.error('You have to be on a channel') + irc.error('Are you sure this is a channel?') else: irc.error("Who are you again?") - rmtime = wrap(rmtime, ['anything']) - - - # Remove 's best time - def rmscore(self, irc, msg, args, nick): - """: Remove 's score """ - if self._capability(msg, 'owner'): - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - try: - del self.channelscores[currentChannel][nick] - irc.reply("Okay! (will be effective at the end of the hunt)") - - except: - irc.error("Something went wrong") - - - else: - irc.error('You have to be on a channel') - - else: - irc.error("Who are you again?") - - rmscore = wrap(rmscore, ['anything']) + rmscore = wrap(rmscore, [optional('anything'), 'anything']) # Shows all scores for the channel - def listscores(self, irc, msg, args): - """ - Shows the score list for the current channel - """ + def listscores(self, irc, msg, args, channel): + """[]: Shows the score list for (or for the current channel if no channel is given)""" + if (not channel): + channel = msg.args[0] - currentChannel = msg.args[0] - try: - self.channelscores[currentChannel] - except: - self.channelscores[currentChannel] = {} + if irc.isChannel(channel): + try: + self.channelscores[channel] + except: + self.channelscores[channel] = {} - if not self.channelscores[currentChannel]: - self._read_scores(msg) + self._read_scores(channel) - # Sort the scores (reversed: the higher the better) - scores = sorted(self.channelscores[currentChannel].iteritems(), key=lambda (k,v):(v,k), reverse=True) + # Sort the scores (reversed: the higher the better) + scores = sorted(self.channelscores[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) - msgstring = "" - for item in scores: - # Why do we show the nicks as xnickx? - # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list - msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt scores for " + msg.args[0] + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any scores for this channel yet.") - listscores = wrap(listscores) + msgstring = "" + for item in scores: + # Why do we show the nicks as xnickx? + # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list + msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt scores for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") + listscores = wrap(listscores, [optional('anything')]) # Shows all times for the channel - def listtimes(self, irc, msg, args): - """ - Shows the times list for the current channel - """ + def listtimes(self, irc, msg, args, channel): + """[]: Shows the time list for (or for the current channel if no channel is given)""" - currentChannel = msg.args[0] - try: - self.channeltimes[currentChannel] - except: - self.channeltimes[currentChannel] = {} + if (not channel): + channel = msg.args[0] - if not self.channeltimes[currentChannel]: - self._read_scores(msg) + if irc.isChannel(channel): + self._read_scores(channel) - # Sort the times (not reversed: the lower the better) - times = sorted(self.channeltimes[currentChannel].iteritems(), key=lambda (k,v):(v,k), reverse=False) + try: + self.channeltimes[channel] + except: + self.channeltimes[channel] = {} - msgstring = "" - for item in times: - # Same as in listscores for the xnickx - msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt times for " + msg.args[0] + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any times for this channel yet.") - listscores = wrap(listscores) + + # Sort the times (not reversed: the lower the better) + times = sorted(self.channeltimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=False) + + msgstring = "" + for item in times: + # Same as in listscores for the xnickx + msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt times for " + msg.args[0] + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any times for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") + listtimes = wrap(listtimes, [optional('anything')]) # This is the callback when someones speaks in the channel @@ -541,7 +563,8 @@ class DuckHunt(callbacks.Plugin): irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) # Write the scores and times to disk - self._write_scores(msg) + self._calc_scores(currentChannel) + self._write_scores(currentChannel) # Reinit current hunt scores if self.scores.get(currentChannel): From f016a3bc1b967564de10acf45f0f4dd9ee5960b0 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 21 Jul 2012 14:54:29 +0200 Subject: [PATCH 08/67] Adds an optional channel parameter to the mergescores and mergetimes commands. Also, use more precise wraps (channel and nick instead of anything) --- plugin.py | 61 +++++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/plugin.py b/plugin.py index c3a949a..5eccd16 100644 --- a/plugin.py +++ b/plugin.py @@ -236,20 +236,19 @@ class DuckHunt(callbacks.Plugin): else: irc.error('You have to be on a channel') - score = wrap(score, ['anything']) + score = wrap(score, ['nick']) # Merge scores # nickto gets the points of nickfrom and nickfrom is removed from the scorelist - def mergescores(self, irc, msg, args, nickto, nickfrom): - """ : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ + def mergescores(self, irc, msg, args, channel, nickto, nickfrom): + """[] : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ if self._capability(msg, 'owner'): - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): + if irc.isChannel(channel): try: - self._read_scores(currentChannel) - self.channelscores[currentChannel][nickto] += self.channelscores[currentChannel][nickfrom] - del self.channelscores[currentChannel][nickfrom] - self._write_scores(currentChannel) + self._read_scores(channel) + self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] + del self.channelscores[channel][nickfrom] + self._write_scores(channel) #TODO: Reply with the config success message irc.reply("Okay!") @@ -263,20 +262,20 @@ class DuckHunt(callbacks.Plugin): else: irc.error("Who are you again?") - mergescores = wrap(mergescores, ['anything', 'anything']) + mergescores = wrap(mergescores, ['channel', 'nick', 'nick']) # Merge times - def mergetimes(self, irc, msg, args, nickto, nickfrom): - """ : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist """ + def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): + """[] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist """ if self._capability(msg, 'owner'): - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): + + if irc.isChannel(channel): try: - self._read_scores(currentChannel) - if self.channeltimes[currentChannel][nickfrom] < self.channeltimes[currentChannel][nickto]: - self.channeltimes[currentChannel][nickto] = self.channeltimes[currentChannel][nickfrom] - del self.channeltimes[currentChannel][nickfrom] - self._write_scores(currentChannel) + self._read_scores(channel) + if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: + self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] + del self.channeltimes[channel][nickfrom] + self._write_scores(channel) irc.reply("Okay!") @@ -290,7 +289,7 @@ class DuckHunt(callbacks.Plugin): else: irc.error("Who are you again?") - mergetimes = wrap(mergetimes, ['anything', 'anything']) + mergetimes = wrap(mergetimes, ['channel', 'nick', 'nick']) # Remove 's best time @@ -298,24 +297,19 @@ class DuckHunt(callbacks.Plugin): """[] : Remove 's best time """ if self._capability(msg, 'owner'): - if (not channel): - channel = msg.args[0] - if irc.isChannel(channel): self._read_scores(channel) del self.channeltimes[channel][nick] self._write_scores(channel) irc.reply("Okay!") - - else: irc.error('Are you sure ' + str(channel) + ' is a channel?') else: irc.error("Who are you again?") - rmtime = wrap(rmtime, [optional('anything'), 'anything']) + rmtime = wrap(rmtime, ['channel', 'nick']) # Remove 's best score @@ -323,9 +317,6 @@ class DuckHunt(callbacks.Plugin): """[] : Remove 's score """ if self._capability(msg, 'owner'): - if (not channel): - channel = msg.args[0] - if irc.isChannel(channel): try: self._read_scores(channel) @@ -336,14 +327,13 @@ class DuckHunt(callbacks.Plugin): except: irc.error("Something went wrong") - else: irc.error('Are you sure this is a channel?') else: irc.error("Who are you again?") - rmscore = wrap(rmscore, [optional('anything'), 'anything']) + rmscore = wrap(rmscore, ['channel', 'nick']) @@ -351,8 +341,6 @@ class DuckHunt(callbacks.Plugin): # Shows all scores for the channel def listscores(self, irc, msg, args, channel): """[]: Shows the score list for (or for the current channel if no channel is given)""" - if (not channel): - channel = msg.args[0] if irc.isChannel(channel): try: @@ -377,16 +365,13 @@ class DuckHunt(callbacks.Plugin): irc.reply("There aren't any scores for this channel yet.") else: irc.reply("Are you sure this is a channel?") - listscores = wrap(listscores, [optional('anything')]) + listscores = wrap(listscores, ['channel']) # Shows all times for the channel def listtimes(self, irc, msg, args, channel): """[]: Shows the time list for (or for the current channel if no channel is given)""" - if (not channel): - channel = msg.args[0] - if irc.isChannel(channel): self._read_scores(channel) @@ -410,7 +395,7 @@ class DuckHunt(callbacks.Plugin): irc.reply("There aren't any times for this channel yet.") else: irc.reply("Are you sure this is a channel?") - listtimes = wrap(listtimes, [optional('anything')]) + listtimes = wrap(listtimes, ['channel']) # This is the callback when someones speaks in the channel From 86cd7aed8c2f751860f59460af9beef7210c025b Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 21 Jul 2012 15:07:43 +0200 Subject: [PATCH 09/67] Use the 'admin' converter for the mergescores, mergetimes, rmscore and rmtime commands (instead of checking the capability in the code) --- plugin.py | 113 +++++++++++++++++++++--------------------------------- 1 file changed, 43 insertions(+), 70 deletions(-) diff --git a/plugin.py b/plugin.py index 5eccd16..165c3cc 100644 --- a/plugin.py +++ b/plugin.py @@ -242,98 +242,81 @@ class DuckHunt(callbacks.Plugin): # nickto gets the points of nickfrom and nickfrom is removed from the scorelist def mergescores(self, irc, msg, args, channel, nickto, nickfrom): """[] : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ - if self._capability(msg, 'owner'): - if irc.isChannel(channel): - try: - self._read_scores(channel) - self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] - del self.channelscores[channel][nickfrom] - self._write_scores(channel) - #TODO: Reply with the config success message - irc.reply("Okay!") + if irc.isChannel(channel): + try: + self._read_scores(channel) + self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] + del self.channelscores[channel][nickfrom] + self._write_scores(channel) + #TODO: Reply with the config success message + irc.reply("Okay!") - except: - irc.error("Something went wrong") + except: + irc.error("Something went wrong") - else: - irc.error('You have to be on a channel') - else: - irc.error("Who are you again?") + irc.error('You have to be on a channel') - mergescores = wrap(mergescores, ['channel', 'nick', 'nick']) + + mergescores = wrap(mergescores, ['channel', 'nick', 'nick', 'admin']) # Merge times def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): """[] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist """ - if self._capability(msg, 'owner'): - - if irc.isChannel(channel): - try: - self._read_scores(channel) - if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: - self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] - del self.channeltimes[channel][nickfrom] - self._write_scores(channel) + if irc.isChannel(channel): + try: + self._read_scores(channel) + if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: + self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] + del self.channeltimes[channel][nickfrom] + self._write_scores(channel) - irc.reply("Okay!") + irc.reply("Okay!") - except: - irc.error("Something went wrong") + except: + irc.error("Something went wrong") - else: - irc.error('You have to be on a channel') - else: - irc.error("Who are you again?") + irc.error('You have to be on a channel') - mergetimes = wrap(mergetimes, ['channel', 'nick', 'nick']) + + mergetimes = wrap(mergetimes, ['channel', 'nick', 'nick', 'admin']) # Remove 's best time def rmtime(self, irc, msg, args, channel, nick): """[] : Remove 's best time """ - if self._capability(msg, 'owner'): - - if irc.isChannel(channel): - self._read_scores(channel) - del self.channeltimes[channel][nick] - self._write_scores(channel) - irc.reply("Okay!") - - else: - irc.error('Are you sure ' + str(channel) + ' is a channel?') + if irc.isChannel(channel): + self._read_scores(channel) + del self.channeltimes[channel][nick] + self._write_scores(channel) + irc.reply("Okay!") else: - irc.error("Who are you again?") + irc.error('Are you sure ' + str(channel) + ' is a channel?') - rmtime = wrap(rmtime, ['channel', 'nick']) + rmtime = wrap(rmtime, ['channel', 'nick', 'admin']) # Remove 's best score def rmscore(self, irc, msg, args, channel, nick): """[] : Remove 's score """ - if self._capability(msg, 'owner'): + if irc.isChannel(channel): + try: + self._read_scores(channel) + del self.channelscores[channel][nick] + self._write_scores(channel) + irc.reply("Okay!") - if irc.isChannel(channel): - try: - self._read_scores(channel) - del self.channelscores[channel][nick] - self._write_scores(channel) - irc.reply("Okay!") - - except: - irc.error("Something went wrong") - - else: - irc.error('Are you sure this is a channel?') + except: + irc.error("Something went wrong") else: - irc.error("Who are you again?") + irc.error('Are you sure this is a channel?') - rmscore = wrap(rmscore, ['channel', 'nick']) + rmscore = wrap(rmscore, ['channel', 'nick', 'admin']) @@ -605,16 +588,6 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') - def _capability(self, msg, c): - try: - u = ircdb.users.getUser(msg.prefix) - if u._checkCapability(c): - return True - except: - return False - - - Class = DuckHunt # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From 0afd95324e69fc6e9d0d001c77e9abfc43349471 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 9 Aug 2012 12:38:51 +0200 Subject: [PATCH 10/67] Adds worst times Adds minthrottle and maxthrottle as channel values Adds extra points for a perfect hunt (all ducks shot by the same player) Prevent error when a hunt is stopped and no duck has been shot --- config.py | 10 ++- plugin.py | 189 +++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 168 insertions(+), 31 deletions(-) diff --git a/config.py b/config.py index efdcca6..46f7a0b 100644 --- a/config.py +++ b/config.py @@ -49,10 +49,18 @@ conf.registerChannelValue(DuckHunt, 'autoRestart', conf.registerChannelValue(DuckHunt, 'ducks', registry.Integer(3, """Number of ducks during a hunt?""")) - conf.registerChannelValue(DuckHunt, 'frequency', registry.Probability(0.3, """ Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that a ducks will be launched one after another. """)) +conf.registerChannelValue(DuckHunt, + 'minthrottle', registry.Integer(15, """ + The minimum amount of time before a new duck may be launched (in seconds)""")) + +conf.registerChannelValue(DuckHunt, + 'maxthrottle', registry.Integer(45, """ + The maximum amount of time before a new duck may be launched (in seconds)""")) + + # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugin.py b/plugin.py index 165c3cc..a1b6598 100644 --- a/plugin.py +++ b/plugin.py @@ -58,6 +58,8 @@ class DuckHunt(callbacks.Plugin): channelscores = {} # Saved scores for the channel toptimes = {} # Times for the current hunt channeltimes = {} # Saved times for the channel + worsttimes = {} # Worst times for the current hunt + channelworsttimes = {} # Saved worst times for the channel # Where to save scores? path = "supybot/data/DuckHunt/" @@ -70,6 +72,10 @@ class DuckHunt(callbacks.Plugin): throttle = random.randint(minthrottle, maxthrottle) debug = 0 + # Other params + perfectbonus = 5 + + # Adds new scores and times to the already saved ones # and saves them back to the disk def _calc_scores(self, channel): @@ -95,6 +101,19 @@ class DuckHunt(callbacks.Plugin): if(self.toptimes[channel][player] < self.channeltimes[channel][player]): self.channeltimes[channel][player] = self.toptimes[channel][player] + # worst times + # Adding worst times scores to the channel scores + for player in self.worsttimes[channel].keys(): + if not player in self.channelworsttimes[channel]: + # It's a new player + self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + else: + # It's a player that already has a saved score + # And we save the time of the current hunt if it's worst than it's previous time + if(self.worsttimes[channel][player] > self.channelworsttimes[channel][player]): + self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + + def _write_scores(self, channel): # scores @@ -107,6 +126,13 @@ class DuckHunt(callbacks.Plugin): pickle.dump(self.channeltimes[channel], outputfile) outputfile.close() + # worst times + outputfile = open(self.path + channel + ".worsttimes", "wb") + pickle.dump(self.channelworsttimes[channel], outputfile) + outputfile.close() + + + # Reads scores and times from disk @@ -125,6 +151,14 @@ class DuckHunt(callbacks.Plugin): self.channeltimes[channel] = pickle.load(inputfile) inputfile.close() + # worst times + if not self.channelworsttimes.get(channel): + if os.path.isfile(self.path + channel + ".worsttimes"): + inputfile = open(self.path + channel + ".worsttimes", "rb") + self.channelworsttimes[channel] = pickle.load(inputfile) + inputfile.close() + + # Starts a hunt def start(self, irc, msg, args): @@ -137,7 +171,20 @@ class DuckHunt(callbacks.Plugin): if(self.started.get(currentChannel) == True): irc.reply("There is already a hunt right now!") else: - + + # Init min throttle and max throttle + if self.registryValue('minthrottle', currentChannel): + self.minthrottle = self.registryValue('minthrottle', currentChannel) + else: + self.minthrottle = 15 + + if self.registryValue('maxthrottle', currentChannel): + self.maxthrottle = self.registryValue('maxthrottle', currentChannel) + else: + self.maxthrottle = 45 + + self.throttle = random.randint(self.minthrottle, self.maxthrottle) + # Init frequency if self.registryValue('frequency', currentChannel): self.probability = self.registryValue('frequency', currentChannel) @@ -156,22 +203,27 @@ class DuckHunt(callbacks.Plugin): except: self.channeltimes[currentChannel] = {} + # Init saved times + try: + self.channelworsttimes[currentChannel] + except: + self.channelworsttimes[currentChannel] = {} + + # Init times self.toptimes[currentChannel] = {} + self.worsttimes[currentChannel] = {} # Init bangdelay self.times[currentChannel] = False - if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel]: + if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel] or not self.channelworsttimes[currentChannel]: self._read_scores(currentChannel) # Reinit current hunt scores if self.scores.get(currentChannel): self.scores[currentChannel] = {} - # Reinit current hunt times - self.toptimes[currentChannel] = {} - # No duck launched self.duck[currentChannel] = False @@ -263,13 +315,21 @@ class DuckHunt(callbacks.Plugin): # Merge times def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): - """[] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist """ + """[] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. """ if irc.isChannel(channel): try: self._read_scores(channel) + + # Merge best times if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] del self.channeltimes[channel][nickfrom] + + # Merge worst times + if self.channelworsttimes[channel][nickfrom] > self.channelworsttimes[channel][nickto]: + self.channelworsttimes[channel][nickto] = self.channelworsttimes[channel][nickfrom] + del self.channelworsttimes[channel][nickfrom] + self._write_scores(channel) irc.reply("Okay!") @@ -363,6 +423,12 @@ class DuckHunt(callbacks.Plugin): except: self.channeltimes[channel] = {} + try: + self.channelworsttimes[channel] + except: + self.channelworsttimes[channel] = {} + + # Sort the times (not reversed: the lower the better) times = sorted(self.channeltimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=False) @@ -372,10 +438,24 @@ class DuckHunt(callbacks.Plugin): # Same as in listscores for the xnickx msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt times for " + msg.args[0] + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt times for " + channel + " ~ >o_/") irc.reply(msgstring) else: - irc.reply("There aren't any times for this channel yet.") + irc.reply("There aren't any best times for this channel yet.") + + times = sorted(self.channelworsttimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) + msgstring = "" + for item in times: + # Same as in listscores for the xnickx + msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt worst (or best?) times for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any worst times for this channel yet.") + + + else: irc.reply("Are you sure this is a channel?") listtimes = wrap(listtimes, ['channel']) @@ -449,6 +529,16 @@ class DuckHunt(callbacks.Plugin): except: self.toptimes[currentChannel][msg.nick] = bangdelay + + # Now save the bang delay for the player (if it's worst than it's previous bangdelay) + try: + previoustime = self.worsttimes[currentChannel][msg.nick] + if(bangdelay > previoustime): + self.worsttimes[currentChannel][msg.nick] = bangdelay + except: + self.worsttimes[currentChannel][msg.nick] = bangdelay + + self.duck[currentChannel] = False if self.registryValue('ducks', currentChannel): @@ -507,32 +597,69 @@ class DuckHunt(callbacks.Plugin): irc.reply("The hunt stops now!") # Showing scores - irc.reply(self.scores.get(currentChannel)) + if (self.scores.get(currentChannel)): + irc.reply(self.scores.get(currentChannel)) - # Getting channel best time (to see if the best time of this hunt is better) - channelbestnick = None - channelbesttime = None - if self.channeltimes.get(currentChannel): - channelbestnick, channelbesttime = min(self.channeltimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) - - # Showing best time - recordmsg = '' - if (self.toptimes.get(currentChannel)): - key,value = min(self.toptimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) - if (channelbesttime and value < channelbesttime): - recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' + # Is there a perfect? + winnernick, winnerscore = max(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) else: - try: - if(value < self.channeltimes[currentChannel][key]): - recordmsg = ' (this is your new record in this channel! Your previous record was ' + str(round(self.channeltimes[currentChannel][key],2)) + ')' - except: - recordmsg = '' + maxShoots = 10 - irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) + if (winnerscore == maxShoots): + irc.reply("\o/ %s: %i ducks out of %i: perfect!!! +%i \o/" % (winnernick, winnerscore, maxShoots, self.perfectbonus)) + self.scores[currentChannel][winnernick] += self.perfectbonus - # Write the scores and times to disk - self._calc_scores(currentChannel) - self._write_scores(currentChannel) + # Getting channel best time (to see if the best time of this hunt is better) + channelbestnick = None + channelbesttime = None + if self.channeltimes.get(currentChannel): + channelbestnick, channelbesttime = min(self.channeltimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + + # Showing best time + recordmsg = '' + if (self.toptimes.get(currentChannel)): + key,value = min(self.toptimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + if (channelbesttime and value < channelbesttime): + recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' + else: + try: + if(value < self.channeltimes[currentChannel][key]): + recordmsg = ' (this is your new record in this channel! Your previous record was ' + str(round(self.channeltimes[currentChannel][key],2)) + ')' + except: + recordmsg = '' + + irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) + + # Getting channel worst time (to see if the worst time of this hunt is worst) + channelworstnick = None + channelworsttime = None + if self.channelworsttimes.get(currentChannel): + channelworstnick, channelworsttime = max(self.channelworsttimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + + + # Showing worst time + recordmsg = '' + if (self.worsttimes.get(currentChannel)): + key,value = max(self.worsttimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + if (channelworsttime and value > channelworsttime): + recordmsg = '. This is the new worst time for this channel! (previous worst time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' + else: + try: + if(value < self.channeltimes[currentChannel][key]): + recordmsg = ' (this is your new worst time in this channel! Your previous worst time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' + except: + recordmsg = '' + + irc.reply("Worst time: %s with %.2f seconds%s" % (key, value, recordmsg)) + + + # Write the scores and times to disk + self._calc_scores(currentChannel) + self._write_scores(currentChannel) + else: + irc.reply("Not a single duck was shot during this hunt!") # Reinit current hunt scores if self.scores.get(currentChannel): @@ -541,6 +668,8 @@ class DuckHunt(callbacks.Plugin): # Reinit current hunt times if self.toptimes.get(currentChannel): self.toptimes[currentChannel] = {} + if self.worsttimes.get(currentChannel): + self.worsttimes[currentChannel] = {} # No duck lauched self.duck[currentChannel] = False From 61fd7f80bd004ef8eb34da5d41cd675f0ff892eb Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 22 Aug 2012 17:27:25 +0200 Subject: [PATCH 11/67] Change some display (be less verbose) Shorten scores-list and times-lists to 5 elements Sort scores of the hunt --- plugin.py | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/plugin.py b/plugin.py index a1b6598..11d193d 100644 --- a/plugin.py +++ b/plugin.py @@ -73,7 +73,8 @@ class DuckHunt(callbacks.Plugin): debug = 0 # Other params - perfectbonus = 5 + perfectbonus = 5 # How many extra-points are given when someones does a perfect hunt? + toplist = 5 # How many high{scores|times} are displayed by default? # Adds new scores and times to the already saved ones @@ -385,6 +386,9 @@ class DuckHunt(callbacks.Plugin): def listscores(self, irc, msg, args, channel): """[]: Shows the score list for (or for the current channel if no channel is given)""" + + # TODO: Let the caller choose how many elements to display + if irc.isChannel(channel): try: self.channelscores[channel] @@ -395,6 +399,7 @@ class DuckHunt(callbacks.Plugin): # Sort the scores (reversed: the higher the better) scores = sorted(self.channelscores[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) + del scores[self.toplist:] msgstring = "" for item in scores: @@ -402,7 +407,7 @@ class DuckHunt(callbacks.Plugin): # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt scores for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " scores for " + channel + " ~ >o_/") irc.reply(msgstring) else: irc.reply("There aren't any scores for this channel yet.") @@ -432,27 +437,31 @@ class DuckHunt(callbacks.Plugin): # Sort the times (not reversed: the lower the better) times = sorted(self.channeltimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=False) + del times[self.toplist:] msgstring = "" for item in times: # Same as in listscores for the xnickx msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt times for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " times for " + channel + " ~ >o_/") irc.reply(msgstring) else: irc.reply("There aren't any best times for this channel yet.") + times = sorted(self.channelworsttimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) + del times[self.toplist:] + msgstring = "" for item in times: # Same as in listscores for the xnickx msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt worst (or best?) times for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " longest times for " + channel + " ~ >o_/") irc.reply(msgstring) else: - irc.reply("There aren't any worst times for this channel yet.") + irc.reply("There aren't any longest times for this channel yet.") @@ -555,7 +564,6 @@ class DuckHunt(callbacks.Plugin): self.started[currentChannel] = True if self.scores.get(currentChannel): self.scores[currentChannel] = {} - irc.reply("The hunt starts now!") # There was no duck or the duck has already been shot @@ -594,19 +602,27 @@ class DuckHunt(callbacks.Plugin): except: self.channelscores[currentChannel] = {} - irc.reply("The hunt stops now!") + + if not self.registryValue('autoRestart', currentChannel): + irc.reply("The hunt stops now!") # Showing scores if (self.scores.get(currentChannel)): - irc.reply(self.scores.get(currentChannel)) - # Is there a perfect? + # Getting winner winnernick, winnerscore = max(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) if self.registryValue('ducks', currentChannel): maxShoots = self.registryValue('ducks', currentChannel) else: maxShoots = 10 + # Showing scores + #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) + #irc.reply(self.scores.get(currentChannel)) + #TODO: Better display + irc.reply(sorted(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k), reverse=True)) + + # Is there a perfect? if (winnerscore == maxShoots): irc.reply("\o/ %s: %i ducks out of %i: perfect!!! +%i \o/" % (winnernick, winnerscore, maxShoots, self.perfectbonus)) self.scores[currentChannel][winnernick] += self.perfectbonus @@ -644,15 +660,17 @@ class DuckHunt(callbacks.Plugin): if (self.worsttimes.get(currentChannel)): key,value = max(self.worsttimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) if (channelworsttime and value > channelworsttime): - recordmsg = '. This is the new worst time for this channel! (previous worst time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' + recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' else: try: if(value < self.channeltimes[currentChannel][key]): - recordmsg = ' (this is your new worst time in this channel! Your previous worst time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' + recordmsg = ' (this is your new longest time in this channel! Your previous longest time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' except: recordmsg = '' - irc.reply("Worst time: %s with %.2f seconds%s" % (key, value, recordmsg)) + # Only display worst time if something new + if (recordmsg != ''): + irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) # Write the scores and times to disk From 72cec63deae9d2d8141fd340751015126e8fcdb3 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 24 Aug 2012 08:26:41 +0200 Subject: [PATCH 12/67] Use a .md for README instead of a .txt --- README.txt => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.txt => README.md (100%) diff --git a/README.txt b/README.md similarity index 100% rename from README.txt rename to README.md From f4bf109566ae7492c1cf78ca98bb009c8b86d012 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 24 Aug 2012 08:40:50 +0200 Subject: [PATCH 13/67] Updates README.md --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 862407f..21ce0ff 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,25 @@ \_o< ~ DuckHunt game for supybot ~ >o_/ +======================================= -A DuckHunt game for supybot. Use the "start" command to start a game. -The bot will randomly launch ducks. Whenever a duck is launched, the first -person to use the "bang" command wins a point. Using the "bang" command -when there is no duck launched costs a point. +How to play +----------- +Use the "start" command to start a game. +The bot will randomly launch ducks. Whenever a duck is launched, the first person to use the "bang" command wins a point. +Using the "bang" command when there is no duck launched costs a point. +If a player shoots all the ducks during a hunt, it's a perfect! This player gets extra bonus points. +The best scores for a channel are recorded and can be displayed with the "listscores" command. +The quickest and longest shoots are also recorded and can be displayed with the "listtimes" command. +The "launched" command tells if there is currently a duck to shoot. +How to install +-------------- +Just place the DuckHunt plugin in the plugins directory of your supybot installation and load the module. + +How to configure +---------------- +Several per-channel configuration variables are available (look at the "channel" command to learn more on how to configure per-channel configuration variables): + * autoRestart: Does a new hunt automatically start when the previous one is over? + * ducks: Number of ducks during a hunt? + * frequency: Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that a ducks will be launched one after another. + * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) + * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) From 412269da0124085978d3edee95b0706b9675d438 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 24 Aug 2012 08:43:10 +0200 Subject: [PATCH 14/67] Updates README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 21ce0ff..bdc6a7f 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ How to play ----------- -Use the "start" command to start a game. -The bot will randomly launch ducks. Whenever a duck is launched, the first person to use the "bang" command wins a point. -Using the "bang" command when there is no duck launched costs a point. -If a player shoots all the ducks during a hunt, it's a perfect! This player gets extra bonus points. -The best scores for a channel are recorded and can be displayed with the "listscores" command. -The quickest and longest shoots are also recorded and can be displayed with the "listtimes" command. -The "launched" command tells if there is currently a duck to shoot. + * Use the "start" command to start a game. + * The bot will randomly launch ducks. Whenever a duck is launched, the first person to use the "bang" command wins a point. + * Using the "bang" command when there is no duck launched costs a point. + * If a player shoots all the ducks during a hunt, it's a perfect! This player gets extra bonus points. + * The best scores for a channel are recorded and can be displayed with the "listscores" command. + * The quickest and longest shoots are also recorded and can be displayed with the "listtimes" command. + * The "launched" command tells if there is currently a duck to shoot. How to install -------------- From cc762f61326f86f830717bd5a2a68a6fefc2a333 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 24 Aug 2012 12:31:29 +0200 Subject: [PATCH 15/67] Update docstrings and add generated documentation --- doc/DuckHunt.html | 393 ++++++++++++++++++++++++++++++++++++++++++++++ doc/DuckHunt.rst | 90 +++++++++++ doc/DuckHunt.stx | 110 +++++++++++++ plugin.py | 89 +++++++---- 4 files changed, 653 insertions(+), 29 deletions(-) create mode 100644 doc/DuckHunt.html create mode 100644 doc/DuckHunt.rst create mode 100644 doc/DuckHunt.stx diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html new file mode 100644 index 0000000..27dfcdd --- /dev/null +++ b/doc/DuckHunt.html @@ -0,0 +1,393 @@ + + + + + + +Documentation for the DuckHunt plugin for Supybot + + + +
+

Documentation for the DuckHunt plugin for Supybot

+ +
+

Purpose

+

This is a DuckHunt game for supybot

+
+
+

Usage

+

A DuckHunt game for supybot. Use the "start" command to start a game. The +bot will randomly launch ducks. Whenever a duck is launched, the first +person to use the "bang" command wins a point. Using the "bang" command +when there is no duck launched costs a point.

+
+
+

Commands

+
+
bang
+
Shoots the duck!
+
dbg
+
This is a debug command. If debug mode is not enabled, it won't do anything
+
launched
+
Is there a duck right now?
+
listscores
+
[<channel>]: Shows the score list for <channel> (or for the current channel +if no channel is given)
+
listtimes
+
[<channel>]: Shows the time list for <channel> (or for the current channel if +no channel is given)
+
mergescores
+
[<channel>] <nickto> <nickfrom>: nickto gets the points of nickfrom and +nickfrom is removed from the scorelist
+
mergetimes
+
[<channel>] <nickto> <nickfrom>: nickto gets the best time of nickfrom if +nickfrom time is better than nickto time, and nickfrom is removed from the +timelist. Also works with worst times.
+
rmscore
+
[<channel>] <nick>: Remove <nick>'s score
+
rmtime
+
[<channel>] <nick>: Remove <nick>'s best time
+
score
+
<nick>: Shows the score for a given nick
+
start
+
Starts the hunt
+
stop
+
Stops the hunt
+
+
+
+

Configuration

+
+
supybot.plugins.DuckHunt.public
+

This config variable defaults to True and is not channel specific.

+

Determines whether this plugin is publicly visible.

+
+
supybot.plugins.DuckHunt.autoRestart
+

This config variable defaults to False and is channel specific.

+

Does a new hunt automatically start when the previous one is over?

+
+
supybot.plugins.DuckHunt.ducks
+

This config variable defaults to 3 and is channel specific.

+

Number of ducks during a hunt?

+
+
supybot.plugins.DuckHunt.frequency
+

This config variable defaults to 0.29999999999999999 and is channel specific.

+

Determines how often a duck will be launched. 0 means that no duck will ever +be launched. 1 means that a ducks will be launched one after another.

+
+
supybot.plugins.DuckHunt.minthrottle
+

This config variable defaults to 15 and is channel specific.

+

The minimum amount of time before a new duck may be launched (in seconds)

+
+
supybot.plugins.DuckHunt.maxthrottle
+

This config variable defaults to 45 and is channel specific.

+

The maximum amount of time before a new duck may be launched (in seconds)

+
+
+
+
+ + diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst new file mode 100644 index 0000000..004d22c --- /dev/null +++ b/doc/DuckHunt.rst @@ -0,0 +1,90 @@ +Documentation for the DuckHunt plugin for Supybot +================================================= + +Purpose +------- +This is a DuckHunt game for supybot + +Usage +----- +A DuckHunt game for supybot. Use the "start" command to start a game. The +bot will randomly launch ducks. Whenever a duck is launched, the first +person to use the "bang" command wins a point. Using the "bang" command +when there is no duck launched costs a point. + +Commands +-------- +bang + Shoots the duck! + +dbg + This is a debug command. If debug mode is not enabled, it won't do anything + +launched + Is there a duck right now? + +listscores + []: Shows the score list for (or for the current channel + if no channel is given) + +listtimes + []: Shows the time list for (or for the current channel if + no channel is given) + +mergescores + [] : nickto gets the points of nickfrom and + nickfrom is removed from the scorelist + +mergetimes + [] : nickto gets the best time of nickfrom if + nickfrom time is better than nickto time, and nickfrom is removed from the + timelist. Also works with worst times. + +rmscore + [] : Remove 's score + +rmtime + [] : Remove 's best time + +score + : Shows the score for a given nick + +start + Starts the hunt + +stop + Stops the hunt + +Configuration +------------- +supybot.plugins.DuckHunt.public + This config variable defaults to True and is not channel specific. + + Determines whether this plugin is publicly visible. + +supybot.plugins.DuckHunt.autoRestart + This config variable defaults to False and is channel specific. + + Does a new hunt automatically start when the previous one is over? + +supybot.plugins.DuckHunt.ducks + This config variable defaults to 3 and is channel specific. + + Number of ducks during a hunt? + +supybot.plugins.DuckHunt.frequency + This config variable defaults to 0.29999999999999999 and is channel specific. + + Determines how often a duck will be launched. 0 means that no duck will ever + be launched. 1 means that a ducks will be launched one after another. + +supybot.plugins.DuckHunt.minthrottle + This config variable defaults to 15 and is channel specific. + + The minimum amount of time before a new duck may be launched (in seconds) + +supybot.plugins.DuckHunt.maxthrottle + This config variable defaults to 45 and is channel specific. + + The maximum amount of time before a new duck may be launched (in seconds) + diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx new file mode 100644 index 0000000..cb58d48 --- /dev/null +++ b/doc/DuckHunt.stx @@ -0,0 +1,110 @@ +Documentation for the DuckHunt plugin for Supybot + + Purpose + + This is a DuckHunt game for supybot + + Usage + + A DuckHunt game for supybot. Use the "start" command to start a game. + The bot will randomly launch ducks. Whenever a duck is launched, the first + person to use the "bang" command wins a point. Using the "bang" command + when there is no duck launched costs a point. + + Commands + + * bang + + Shoots the duck! + + * dbg + + This is a debug command. If debug mode is not enabled, it won't do + anything + + * launched + + Is there a duck right now? + + * listscores + + []: Shows the score list for (or for the current + channel if no channel is given) + + * listtimes + + []: Shows the time list for (or for the current + channel if no channel is given) + + * mergescores + + [] : nickto gets the points of nickfrom and + nickfrom is removed from the scorelist + + * mergetimes + + [] : nickto gets the best time of nickfrom if + nickfrom time is better than nickto time, and nickfrom is removed from + the timelist. Also works with worst times. + + * rmscore + + [] : Remove 's score + + * rmtime + + [] : Remove 's best time + + * score + + : Shows the score for a given nick + + * start + + Starts the hunt + + * stop + + Stops the current hunt + + Configuration + + * supybot.plugins.DuckHunt.public + + This config variable defaults to True and is not channel specific. + + Determines whether this plugin is publicly visible. + + * supybot.plugins.DuckHunt.autoRestart + + This config variable defaults to False and is channel specific. + + Does a new hunt automatically start when the previous one is over? + + * supybot.plugins.DuckHunt.ducks + + This config variable defaults to 3 and is channel specific. + + Number of ducks during a hunt? + + * supybot.plugins.DuckHunt.frequency + + This config variable defaults to 0.29999999999999999 and is channel + specific. + + Determines how often a duck will be launched. 0 means that no duck will + ever be launched. 1 means that a ducks will be launched one after + another. + + * supybot.plugins.DuckHunt.minthrottle + + This config variable defaults to 15 and is channel specific. + + The minimum amount of time before a new duck may be launched (in seconds) + + * supybot.plugins.DuckHunt.maxthrottle + + This config variable defaults to 45 and is channel specific. + + The maximum amount of time before a new duck may be launched (in seconds) + diff --git a/plugin.py b/plugin.py index 11d193d..6aa75f7 100644 --- a/plugin.py +++ b/plugin.py @@ -77,9 +77,11 @@ class DuckHunt(callbacks.Plugin): toplist = 5 # How many high{scores|times} are displayed by default? - # Adds new scores and times to the already saved ones - # and saves them back to the disk def _calc_scores(self, channel): + """ + Adds new scores and times to the already saved ones and saves them back to the disk + """ + # scores # Adding current scores to the channel scores for player in self.scores[channel].keys(): @@ -117,6 +119,10 @@ class DuckHunt(callbacks.Plugin): def _write_scores(self, channel): + """ + Write scores + """ + # scores outputfile = open(self.path + channel + ".scores", "wb") pickle.dump(self.channelscores[channel], outputfile) @@ -136,8 +142,11 @@ class DuckHunt(callbacks.Plugin): - # Reads scores and times from disk def _read_scores(self, channel): + """ + Reads scores and times from disk + """ + # scores if not self.channelscores.get(channel): if os.path.isfile(self.path + channel + ".scores"): @@ -161,11 +170,11 @@ class DuckHunt(callbacks.Plugin): - # Starts a hunt def start(self, irc, msg, args): """ Starts the hunt """ + currentChannel = msg.args[0] if irc.isChannel(currentChannel): @@ -239,11 +248,13 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') start = wrap(start) - # Stops the current hunt + + def stop(self, irc, msg, args): """ - Stops the hunt + Stops the current hunt """ + currentChannel = msg.args[0] if irc.isChannel(currentChannel): self._end(irc, msg, args) @@ -251,11 +262,13 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') stop = wrap(stop) - # Tells if there is currently a duck + + def launched(self, irc, msg, args): """ Is there a duck right now? """ + currentChannel = msg.args[0] if irc.isChannel(currentChannel): if(self.started.get(currentChannel) == True): @@ -270,9 +283,11 @@ class DuckHunt(callbacks.Plugin): launched = wrap(launched) - # Shows the score for a given nick + def score(self, irc, msg, args, nick): - """: Shows the score for a given nick """ + """ + : Shows the score for a given nick + """ currentChannel = msg.args[0] if irc.isChannel(currentChannel): self._read_scores(currentChannel) @@ -291,10 +306,12 @@ class DuckHunt(callbacks.Plugin): score = wrap(score, ['nick']) - # Merge scores - # nickto gets the points of nickfrom and nickfrom is removed from the scorelist + + def mergescores(self, irc, msg, args, channel, nickto, nickfrom): - """[] : nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ + """ + [] : nickto gets the points of nickfrom and nickfrom is removed from the scorelist + """ if irc.isChannel(channel): try: self._read_scores(channel) @@ -314,9 +331,12 @@ class DuckHunt(callbacks.Plugin): mergescores = wrap(mergescores, ['channel', 'nick', 'nick', 'admin']) - # Merge times + + def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): - """[] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. """ + """ + [] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. + """ if irc.isChannel(channel): try: self._read_scores(channel) @@ -346,9 +366,11 @@ class DuckHunt(callbacks.Plugin): mergetimes = wrap(mergetimes, ['channel', 'nick', 'nick', 'admin']) - # Remove 's best time + def rmtime(self, irc, msg, args, channel, nick): - """[] : Remove 's best time """ + """ + [] : Remove 's best time + """ if irc.isChannel(channel): self._read_scores(channel) del self.channeltimes[channel][nick] @@ -361,9 +383,11 @@ class DuckHunt(callbacks.Plugin): rmtime = wrap(rmtime, ['channel', 'nick', 'admin']) - # Remove 's best score + def rmscore(self, irc, msg, args, channel, nick): - """[] : Remove 's score """ + """ + [] : Remove 's score + """ if irc.isChannel(channel): try: self._read_scores(channel) @@ -381,10 +405,10 @@ class DuckHunt(callbacks.Plugin): - - # Shows all scores for the channel def listscores(self, irc, msg, args, channel): - """[]: Shows the score list for (or for the current channel if no channel is given)""" + """ + []: Shows the score list for (or for the current channel if no channel is given) + """ # TODO: Let the caller choose how many elements to display @@ -416,9 +440,11 @@ class DuckHunt(callbacks.Plugin): listscores = wrap(listscores, ['channel']) - # Shows all times for the channel + def listtimes(self, irc, msg, args, channel): - """[]: Shows the time list for (or for the current channel if no channel is given)""" + """ + []: Shows the time list for (or for the current channel if no channel is given) + """ if irc.isChannel(channel): self._read_scores(channel) @@ -487,10 +513,11 @@ class DuckHunt(callbacks.Plugin): self.lastSpoke = now - # This is the debug function: when debug is enabled, - # it launches a duck when called + def dbg(self, irc, msg, args): - """ This is a debug command. If debug mode is not enabled, it won't do anything """ + """ + This is a debug command. If debug mode is not enabled, it won't do anything + """ currentChannel = msg.args[0] if (self.debug): if irc.isChannel(currentChannel): @@ -498,7 +525,7 @@ class DuckHunt(callbacks.Plugin): dbg = wrap(dbg) - # Shoots the duck! + def bang(self, irc, msg, args): """ Shoots the duck! @@ -594,8 +621,13 @@ class DuckHunt(callbacks.Plugin): bang = wrap(bang) - # End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) + + def _end(self, irc, msg, args): + """ + End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) + """ + currentChannel = msg.args[0] try: self.channelscores[currentChannel] @@ -700,7 +732,6 @@ class DuckHunt(callbacks.Plugin): - # Launch a duck def _launch(self, irc, msg, args): """ Launch a duck From 203849a53509218302c3150a3fe9be268bea0860 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 27 Aug 2012 18:12:40 +0200 Subject: [PATCH 16/67] Fix longest time display bug at the end of a hunt --- plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index 6aa75f7..ac0a352 100644 --- a/plugin.py +++ b/plugin.py @@ -695,7 +695,7 @@ class DuckHunt(callbacks.Plugin): recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' else: try: - if(value < self.channeltimes[currentChannel][key]): + if(value > self.channelworsttimes[currentChannel][key]): recordmsg = ' (this is your new longest time in this channel! Your previous longest time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' except: recordmsg = '' From 1a50a5bb8ee79a882bd24eabe7b19da4241820c5 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 27 Aug 2012 19:26:25 +0200 Subject: [PATCH 17/67] Adds the size parameter to the listscores and listtimes commands --- plugin.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/plugin.py b/plugin.py index ac0a352..c2ebc23 100644 --- a/plugin.py +++ b/plugin.py @@ -405,14 +405,11 @@ class DuckHunt(callbacks.Plugin): - def listscores(self, irc, msg, args, channel): + def listscores(self, irc, msg, args, size, channel): """ - []: Shows the score list for (or for the current channel if no channel is given) + [] []: Shows the -sized score list for (or for the current channel if no channel is given) """ - - # TODO: Let the caller choose how many elements to display - if irc.isChannel(channel): try: self.channelscores[channel] @@ -421,9 +418,15 @@ class DuckHunt(callbacks.Plugin): self._read_scores(channel) + # How many results do we display? + if (not size): + listsize = self.toplist + else: + listsize = size + # Sort the scores (reversed: the higher the better) scores = sorted(self.channelscores[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) - del scores[self.toplist:] + del scores[listsize:] msgstring = "" for item in scores: @@ -431,19 +434,19 @@ class DuckHunt(callbacks.Plugin): # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " scores for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " scores for " + channel + " ~ >o_/") irc.reply(msgstring) else: irc.reply("There aren't any scores for this channel yet.") else: irc.reply("Are you sure this is a channel?") - listscores = wrap(listscores, ['channel']) + listscores = wrap(listscores, [optional('int'), 'channel']) - def listtimes(self, irc, msg, args, channel): + def listtimes(self, irc, msg, args, size, channel): """ - []: Shows the time list for (or for the current channel if no channel is given) + [] []: Shows the -sized time list for (or for the current channel if no channel is given) """ if irc.isChannel(channel): @@ -459,32 +462,36 @@ class DuckHunt(callbacks.Plugin): except: self.channelworsttimes[channel] = {} - + # How many results do we display? + if (not size): + listsize = self.toplist + else: + listsize = size # Sort the times (not reversed: the lower the better) times = sorted(self.channeltimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=False) - del times[self.toplist:] + del times[listsize:] msgstring = "" for item in times: # Same as in listscores for the xnickx msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " times for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") irc.reply(msgstring) else: irc.reply("There aren't any best times for this channel yet.") times = sorted(self.channelworsttimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) - del times[self.toplist:] + del times[listsize:] msgstring = "" for item in times: # Same as in listscores for the xnickx msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(self.toplist) + " longest times for " + channel + " ~ >o_/") + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " longest times for " + channel + " ~ >o_/") irc.reply(msgstring) else: irc.reply("There aren't any longest times for this channel yet.") @@ -493,7 +500,7 @@ class DuckHunt(callbacks.Plugin): else: irc.reply("Are you sure this is a channel?") - listtimes = wrap(listtimes, ['channel']) + listtimes = wrap(listtimes, [optional('int'), 'channel']) # This is the callback when someones speaks in the channel From bd790b0b4270a7a4f94381df194fac6740c0f2bd Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 30 Aug 2012 18:31:55 +0200 Subject: [PATCH 18/67] Adds stringified display for longest times (instead of showing just seconds) --- plugin.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugin.py b/plugin.py index c2ebc23..ce5e8c6 100644 --- a/plugin.py +++ b/plugin.py @@ -30,7 +30,7 @@ from supybot.commands import * import supybot.plugins as plugins import supybot.callbacks as callbacks -import threading, random, pickle, os, time +import threading, random, pickle, os, time, datetime import supybot.ircdb as ircdb import supybot.ircmsgs as ircmsgs @@ -432,7 +432,7 @@ class DuckHunt(callbacks.Plugin): for item in scores: # Why do we show the nicks as xnickx? # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list - msgstring += "x" + item[0] + "x: "+ str(item[1]) + ", " + msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " if msgstring != "": irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " scores for " + channel + " ~ >o_/") irc.reply(msgstring) @@ -475,7 +475,7 @@ class DuckHunt(callbacks.Plugin): msgstring = "" for item in times: # Same as in listscores for the xnickx - msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " + msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + " | " if msgstring != "": irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") irc.reply(msgstring) @@ -489,7 +489,10 @@ class DuckHunt(callbacks.Plugin): msgstring = "" for item in times: # Same as in listscores for the xnickx - msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + ", " + #msgstring += "x" + item[0] + "x: "+ time.strftime('%H:%M:%S', time.gmtime(item[1])) + ", " + roundseconds = round(item[1]) + delta = datetime.timedelta(seconds=roundseconds) + msgstring += "x" + item[0] + "x: " + str(delta) + " | " if msgstring != "": irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " longest times for " + channel + " ~ >o_/") irc.reply(msgstring) From fa2f3eef0f2750fe637d71ea59ec9f8d89f692d2 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 1 Sep 2012 16:58:05 +0200 Subject: [PATCH 19/67] Use supybot default success and error messages --- plugin.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/plugin.py b/plugin.py index ce5e8c6..ecb5799 100644 --- a/plugin.py +++ b/plugin.py @@ -318,11 +318,10 @@ class DuckHunt(callbacks.Plugin): self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] del self.channelscores[channel][nickfrom] self._write_scores(channel) - #TODO: Reply with the config success message - irc.reply("Okay!") + irc.replySuccess() except: - irc.error("Something went wrong") + irc.replyError() else: @@ -353,10 +352,10 @@ class DuckHunt(callbacks.Plugin): self._write_scores(channel) - irc.reply("Okay!") + irc.replySuccess() except: - irc.error("Something went wrong") + irc.replyError() else: @@ -375,7 +374,7 @@ class DuckHunt(callbacks.Plugin): self._read_scores(channel) del self.channeltimes[channel][nick] self._write_scores(channel) - irc.reply("Okay!") + irc.replySuccess() else: irc.error('Are you sure ' + str(channel) + ' is a channel?') @@ -393,10 +392,10 @@ class DuckHunt(callbacks.Plugin): self._read_scores(channel) del self.channelscores[channel][nick] self._write_scores(channel) - irc.reply("Okay!") + irc.replySuccess() except: - irc.error("Something went wrong") + irc.replyError() else: irc.error('Are you sure this is a channel?') From 1db3962c00490855cc5bf2fea6ba762927e2a698 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 18:18:00 +0200 Subject: [PATCH 20/67] Uses supybot's scheduler instead of doPrivmsg. This change was made in order to prevent the "The more people are talking in the channel, the more the bot launches ducks" behavior --- plugin.py | 56 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/plugin.py b/plugin.py index ecb5799..9b087ca 100644 --- a/plugin.py +++ b/plugin.py @@ -30,12 +30,11 @@ from supybot.commands import * import supybot.plugins as plugins import supybot.callbacks as callbacks -import threading, random, pickle, os, time, datetime +import supybot.schedule as schedule import supybot.ircdb as ircdb import supybot.ircmsgs as ircmsgs - - +import threading, random, pickle, os, time, datetime class DuckHunt(callbacks.Plugin): @@ -243,12 +242,34 @@ class DuckHunt(callbacks.Plugin): # Init banging self.banging[currentChannel] = False + # Init schedule + def myEventCaller(): + self._launchEvent(irc, msg) + try: + schedule.addPeriodicEvent(myEventCaller, self.minthrottle, 'DuckHunt_' + currentChannel, False) + except AssertionError: + irc.reply('The scheduler ' + 'DuckHunt_' + currentChannel + ' was already running. This shouldn\'t happen. This is a bug.'); + irc.reply("The hunt starts now!") else: irc.error('You have to be on a channel') start = wrap(start) + def _launchEvent(self, irc, msg): + currentChannel = msg.args[0] + now = time.time() + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + if (self.duck[currentChannel] == False): + if now > self.lastSpoke + self.throttle: + if random.random() < self.probability: + # If someone is "banging" right now, do not launch a duck + if (not self.banging[currentChannel]): + self._launch(irc, msg, '') + self.lastSpoke = now + + def stop(self, irc, msg, args): """ @@ -257,7 +278,17 @@ class DuckHunt(callbacks.Plugin): currentChannel = msg.args[0] if irc.isChannel(currentChannel): - self._end(irc, msg, args) + if (self.started.get(currentChannel) == True): + self._end(irc, msg, args) + + # If someone uses the stop command, + # we stop the scheduler, even if autoRestart is enabled + try: + schedule.removeEvent('DuckHunt_' + currentChannel) + except KeyError: + irc.reply('Error: the spammer wasn\'t running! This is a bug.') + else: + irc.reply('Nothing to stop: there\'s no hunt right now.') else: irc.error('You have to be on a channel') stop = wrap(stop) @@ -505,23 +536,6 @@ class DuckHunt(callbacks.Plugin): listtimes = wrap(listtimes, [optional('int'), 'channel']) - # This is the callback when someones speaks in the channel - # We use this to determine if a duck has to be launched - def doPrivmsg(self, irc, msg): - currentChannel = msg.args[0] - now = time.time() - if irc.isChannel(currentChannel): - if(self.started.get(currentChannel) == True): - if (self.duck[currentChannel] == False): - - if now > self.lastSpoke + self.throttle: - if random.random() < self.probability: - # If someone is "banging" right now, do not launch a duck - if (not self.banging[currentChannel]): - self._launch(irc, msg, '') - self.lastSpoke = now - - def dbg(self, irc, msg, args): """ From 398a8dc26eb88a8c7bb1f52c1b38b470432cb00c Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 20:38:39 +0200 Subject: [PATCH 21/67] Documentation update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bdc6a7f..653c6e6 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,6 @@ How to configure Several per-channel configuration variables are available (look at the "channel" command to learn more on how to configure per-channel configuration variables): * autoRestart: Does a new hunt automatically start when the previous one is over? * ducks: Number of ducks during a hunt? - * frequency: Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that a ducks will be launched one after another. + * frequency: Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that ducks will be launched one after another (somewhere between minthrottle and maxthrottle, of course). * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) From c32d16daf16e5269de13ffbd6316988ba6016948 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 20:39:03 +0200 Subject: [PATCH 22/67] Uses an arbitrary 5 seconds delay between scheduler calls (instead of minthrottle) --- plugin.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugin.py b/plugin.py index 9b087ca..226bfd3 100644 --- a/plugin.py +++ b/plugin.py @@ -33,6 +33,8 @@ import supybot.callbacks as callbacks import supybot.schedule as schedule import supybot.ircdb as ircdb import supybot.ircmsgs as ircmsgs +import supybot.log as log + import threading, random, pickle, os, time, datetime @@ -78,7 +80,7 @@ class DuckHunt(callbacks.Plugin): def _calc_scores(self, channel): """ - Adds new scores and times to the already saved ones and saves them back to the disk + Adds new scores and times to the already saved ones """ # scores @@ -119,7 +121,7 @@ class DuckHunt(callbacks.Plugin): def _write_scores(self, channel): """ - Write scores + Write scores and times to the disk """ # scores @@ -246,7 +248,7 @@ class DuckHunt(callbacks.Plugin): def myEventCaller(): self._launchEvent(irc, msg) try: - schedule.addPeriodicEvent(myEventCaller, self.minthrottle, 'DuckHunt_' + currentChannel, False) + schedule.addPeriodicEvent(myEventCaller, 5, 'DuckHunt_' + currentChannel, False) except AssertionError: irc.reply('The scheduler ' + 'DuckHunt_' + currentChannel + ' was already running. This shouldn\'t happen. This is a bug.'); @@ -266,6 +268,7 @@ class DuckHunt(callbacks.Plugin): if random.random() < self.probability: # If someone is "banging" right now, do not launch a duck if (not self.banging[currentChannel]): + #log.error("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke)) self._launch(irc, msg, '') self.lastSpoke = now From c902f6c65e3dbda1e12c9b150ed7a1f76dd89247 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 20:53:43 +0200 Subject: [PATCH 23/67] Ending the hunt has to be done asap when the _end function is called --- plugin.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugin.py b/plugin.py index 226bfd3..e24afa1 100644 --- a/plugin.py +++ b/plugin.py @@ -655,6 +655,10 @@ class DuckHunt(callbacks.Plugin): """ currentChannel = msg.args[0] + + # End the hunting + self.started[currentChannel] = False + try: self.channelscores[currentChannel] except: @@ -750,9 +754,6 @@ class DuckHunt(callbacks.Plugin): # No duck lauched self.duck[currentChannel] = False - # Hunt not started - self.started[currentChannel] = False - # Reinit number of shoots self.shoots[currentChannel] = 0 From 942842d56ebf2f65b7a602d6eb2ee4d26f7a9553 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 21:31:53 +0200 Subject: [PATCH 24/67] Since frequency, minthrottle and maxthrottle are channel configuration variables, let's handle them this way! --- plugin.py | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/plugin.py b/plugin.py index e24afa1..916fc91 100644 --- a/plugin.py +++ b/plugin.py @@ -62,15 +62,16 @@ class DuckHunt(callbacks.Plugin): worsttimes = {} # Worst times for the current hunt channelworsttimes = {} # Saved worst times for the channel + # Does a duck needs to be launched? + probability = {} + lastSpoke = {} + minthrottle = {} + maxthrottle = {} + throttle = {} + # Where to save scores? path = "supybot/data/DuckHunt/" - # Does a duck needs to be launched? - probability = 1 - lastSpoke = time.time() - minthrottle = 15 - maxthrottle = 45 - throttle = random.randint(minthrottle, maxthrottle) debug = 0 # Other params @@ -183,24 +184,24 @@ class DuckHunt(callbacks.Plugin): irc.reply("There is already a hunt right now!") else: - # Init min throttle and max throttle + # Init min throttle[currentChannel] and max throttle[currentChannel] if self.registryValue('minthrottle', currentChannel): - self.minthrottle = self.registryValue('minthrottle', currentChannel) + self.minthrottle[currentChannel] = self.registryValue('minthrottle', currentChannel) else: - self.minthrottle = 15 + self.minthrottle[currentChannel] = 15 if self.registryValue('maxthrottle', currentChannel): - self.maxthrottle = self.registryValue('maxthrottle', currentChannel) + self.maxthrottle[currentChannel] = self.registryValue('maxthrottle', currentChannel) else: - self.maxthrottle = 45 + self.maxthrottle[currentChannel] = 45 - self.throttle = random.randint(self.minthrottle, self.maxthrottle) + self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) # Init frequency if self.registryValue('frequency', currentChannel): - self.probability = self.registryValue('frequency', currentChannel) + self.probability[currentChannel] = self.registryValue('frequency', currentChannel) else: - self.probability = 0.3 + self.probability[currentChannel] = 0.3 # Init saved scores try: @@ -228,6 +229,9 @@ class DuckHunt(callbacks.Plugin): # Init bangdelay self.times[currentChannel] = False + # Init lastSpoke + self.lastSpoke[currentChannel] = time.time() + if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel] or not self.channelworsttimes[currentChannel]: self._read_scores(currentChannel) @@ -264,13 +268,13 @@ class DuckHunt(callbacks.Plugin): if irc.isChannel(currentChannel): if(self.started.get(currentChannel) == True): if (self.duck[currentChannel] == False): - if now > self.lastSpoke + self.throttle: - if random.random() < self.probability: + if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: + if random.random() < self.probability[currentChannel]: # If someone is "banging" right now, do not launch a duck if (not self.banging[currentChannel]): - #log.error("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke)) + #log.error("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke[currentChannel]) + " throttle[currentChannel]: " + str(self.throttle[currentChannel]) + " minthrottle[currentChannel]: " + str(self.minthrottle[currentChannel]) + " maxthrottle[currentChannel]: " + str(self.maxthrottle[currentChannel])) self._launch(irc, msg, '') - self.lastSpoke = now + self.lastSpoke[currentChannel] = now @@ -777,8 +781,8 @@ class DuckHunt(callbacks.Plugin): # Send message directly (instead of queuing it with irc.reply) irc.sendMsg(ircmsgs.privmsg(currentChannel, "\_o< quack!")) - # Define a new throttle for the next launch - self.throttle = random.randint(self.minthrottle, self.maxthrottle) + # Define a new throttle[currentChannel] for the next launch + self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) try: self.shoots[currentChannel] += 1 From 567c2a2a5811c7792af173c4a32809e8a8e07e9a Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 3 Sep 2012 22:48:59 +0200 Subject: [PATCH 25/67] Adjusting default values for minthrottle and maxthrottle Removing frequency, as it's kinda unneeded since scheduler is used Updating documentation --- config.py | 10 +++------- doc/DuckHunt.html | 21 ++++++++------------- doc/DuckHunt.rst | 22 ++++++++-------------- doc/DuckHunt.stx | 23 +++++++---------------- plugin.py | 26 ++++++++++---------------- 5 files changed, 36 insertions(+), 66 deletions(-) diff --git a/config.py b/config.py index 46f7a0b..b28e7e7 100644 --- a/config.py +++ b/config.py @@ -47,18 +47,14 @@ conf.registerChannelValue(DuckHunt, 'autoRestart', registry.Boolean(False, """Does a new hunt automatically start when the previous one is over?""")) conf.registerChannelValue(DuckHunt, 'ducks', - registry.Integer(3, """Number of ducks during a hunt?""")) + registry.Integer(5, """Number of ducks during a hunt?""")) conf.registerChannelValue(DuckHunt, - 'frequency', registry.Probability(0.3, """ - Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that a ducks will be launched one after another. """)) - -conf.registerChannelValue(DuckHunt, - 'minthrottle', registry.Integer(15, """ + 'minthrottle', registry.Integer(30, """ The minimum amount of time before a new duck may be launched (in seconds)""")) conf.registerChannelValue(DuckHunt, - 'maxthrottle', registry.Integer(45, """ + 'maxthrottle', registry.Integer(300, """ The maximum amount of time before a new duck may be launched (in seconds)""")) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 27dfcdd..07e4630 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -334,11 +334,11 @@ when there is no duck launched costs a point.

launched
Is there a duck right now?
listscores
-
[<channel>]: Shows the score list for <channel> (or for the current channel -if no channel is given)
+
[<size>] [<channel>]: Shows the <size>-sized score list for <channel> (or for +the current channel if no channel is given)
listtimes
-
[<channel>]: Shows the time list for <channel> (or for the current channel if -no channel is given)
+
[<size>] [<channel>]: Shows the <size>-sized time list for <channel> (or for +the current channel if no channel is given)
mergescores
[<channel>] <nickto> <nickfrom>: nickto gets the points of nickfrom and nickfrom is removed from the scorelist
@@ -355,7 +355,7 @@ timelist. Also works with worst times.
start
Starts the hunt
stop
-
Stops the hunt
+
Stops the current hunt
@@ -370,20 +370,15 @@ timelist. Also works with worst times.

Does a new hunt automatically start when the previous one is over?

supybot.plugins.DuckHunt.ducks
-

This config variable defaults to 3 and is channel specific.

+

This config variable defaults to 5 and is channel specific.

Number of ducks during a hunt?

-
supybot.plugins.DuckHunt.frequency
-

This config variable defaults to 0.29999999999999999 and is channel specific.

-

Determines how often a duck will be launched. 0 means that no duck will ever -be launched. 1 means that a ducks will be launched one after another.

-
supybot.plugins.DuckHunt.minthrottle
-

This config variable defaults to 15 and is channel specific.

+

This config variable defaults to 30 and is channel specific.

The minimum amount of time before a new duck may be launched (in seconds)

supybot.plugins.DuckHunt.maxthrottle
-

This config variable defaults to 45 and is channel specific.

+

This config variable defaults to 300 and is channel specific.

The maximum amount of time before a new duck may be launched (in seconds)

diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index 004d22c..7dbb772 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -24,12 +24,12 @@ launched Is there a duck right now? listscores - []: Shows the score list for (or for the current channel - if no channel is given) + [] []: Shows the -sized score list for (or for + the current channel if no channel is given) listtimes - []: Shows the time list for (or for the current channel if - no channel is given) + [] []: Shows the -sized time list for (or for + the current channel if no channel is given) mergescores [] : nickto gets the points of nickfrom and @@ -53,7 +53,7 @@ start Starts the hunt stop - Stops the hunt + Stops the current hunt Configuration ------------- @@ -68,23 +68,17 @@ supybot.plugins.DuckHunt.autoRestart Does a new hunt automatically start when the previous one is over? supybot.plugins.DuckHunt.ducks - This config variable defaults to 3 and is channel specific. + This config variable defaults to 5 and is channel specific. Number of ducks during a hunt? -supybot.plugins.DuckHunt.frequency - This config variable defaults to 0.29999999999999999 and is channel specific. - - Determines how often a duck will be launched. 0 means that no duck will ever - be launched. 1 means that a ducks will be launched one after another. - supybot.plugins.DuckHunt.minthrottle - This config variable defaults to 15 and is channel specific. + This config variable defaults to 30 and is channel specific. The minimum amount of time before a new duck may be launched (in seconds) supybot.plugins.DuckHunt.maxthrottle - This config variable defaults to 45 and is channel specific. + This config variable defaults to 300 and is channel specific. The maximum amount of time before a new duck may be launched (in seconds) diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index cb58d48..fab0abd 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -28,13 +28,13 @@ Documentation for the DuckHunt plugin for Supybot * listscores - []: Shows the score list for (or for the current - channel if no channel is given) + [] []: Shows the -sized score list for (or + for the current channel if no channel is given) * listtimes - []: Shows the time list for (or for the current - channel if no channel is given) + [] []: Shows the -sized time list for (or + for the current channel if no channel is given) * mergescores @@ -83,28 +83,19 @@ Documentation for the DuckHunt plugin for Supybot * supybot.plugins.DuckHunt.ducks - This config variable defaults to 3 and is channel specific. + This config variable defaults to 5 and is channel specific. Number of ducks during a hunt? - * supybot.plugins.DuckHunt.frequency - - This config variable defaults to 0.29999999999999999 and is channel - specific. - - Determines how often a duck will be launched. 0 means that no duck will - ever be launched. 1 means that a ducks will be launched one after - another. - * supybot.plugins.DuckHunt.minthrottle - This config variable defaults to 15 and is channel specific. + This config variable defaults to 30 and is channel specific. The minimum amount of time before a new duck may be launched (in seconds) * supybot.plugins.DuckHunt.maxthrottle - This config variable defaults to 45 and is channel specific. + This config variable defaults to 300 and is channel specific. The maximum amount of time before a new duck may be launched (in seconds) diff --git a/plugin.py b/plugin.py index 916fc91..cc84c2a 100644 --- a/plugin.py +++ b/plugin.py @@ -63,7 +63,6 @@ class DuckHunt(callbacks.Plugin): channelworsttimes = {} # Saved worst times for the channel # Does a duck needs to be launched? - probability = {} lastSpoke = {} minthrottle = {} maxthrottle = {} @@ -188,20 +187,15 @@ class DuckHunt(callbacks.Plugin): if self.registryValue('minthrottle', currentChannel): self.minthrottle[currentChannel] = self.registryValue('minthrottle', currentChannel) else: - self.minthrottle[currentChannel] = 15 + self.minthrottle[currentChannel] = 30 if self.registryValue('maxthrottle', currentChannel): self.maxthrottle[currentChannel] = self.registryValue('maxthrottle', currentChannel) else: - self.maxthrottle[currentChannel] = 45 + self.maxthrottle[currentChannel] = 300 self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) - - # Init frequency - if self.registryValue('frequency', currentChannel): - self.probability[currentChannel] = self.registryValue('frequency', currentChannel) - else: - self.probability[currentChannel] = 0.3 + #log.info("throttle : " + str(self.throttle[currentChannel])) # Init saved scores try: @@ -254,7 +248,7 @@ class DuckHunt(callbacks.Plugin): try: schedule.addPeriodicEvent(myEventCaller, 5, 'DuckHunt_' + currentChannel, False) except AssertionError: - irc.reply('The scheduler ' + 'DuckHunt_' + currentChannel + ' was already running. This shouldn\'t happen. This is a bug.'); + pass irc.reply("The hunt starts now!") else: @@ -269,12 +263,11 @@ class DuckHunt(callbacks.Plugin): if(self.started.get(currentChannel) == True): if (self.duck[currentChannel] == False): if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: - if random.random() < self.probability[currentChannel]: - # If someone is "banging" right now, do not launch a duck - if (not self.banging[currentChannel]): - #log.error("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke[currentChannel]) + " throttle[currentChannel]: " + str(self.throttle[currentChannel]) + " minthrottle[currentChannel]: " + str(self.minthrottle[currentChannel]) + " maxthrottle[currentChannel]: " + str(self.maxthrottle[currentChannel])) - self._launch(irc, msg, '') - self.lastSpoke[currentChannel] = now + # If someone is "banging" right now, do not launch a duck + if (not self.banging[currentChannel]): + #log.info("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke[currentChannel]) + " / throttle[currentChannel]: " + str(self.throttle[currentChannel]) + " / minthrottle[currentChannel]: " + str(self.minthrottle[currentChannel]) + " / maxthrottle[currentChannel]: " + str(self.maxthrottle[currentChannel])) + self._launch(irc, msg, '') + self.lastSpoke[currentChannel] = now @@ -783,6 +776,7 @@ class DuckHunt(callbacks.Plugin): # Define a new throttle[currentChannel] for the next launch self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) + #log.info("throttle for " + currentChannel + " : " + str(self.throttle[currentChannel])) try: self.shoots[currentChannel] += 1 From 303fd221d8e261d4343bf4a934a686393494f50a Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 4 Sep 2012 17:30:01 +0200 Subject: [PATCH 26/67] Stop/start the scheduler before starting a hunt Reset the basetime for the waiting time before the next duck Adds the 'total' command --- plugin.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index cc84c2a..403174b 100644 --- a/plugin.py +++ b/plugin.py @@ -243,6 +243,14 @@ class DuckHunt(callbacks.Plugin): self.banging[currentChannel] = False # Init schedule + + # First of all, stop the scheduler if it was still running + try: + schedule.removeEvent('DuckHunt_' + currentChannel) + except KeyError: + pass + + # Then restart it def myEventCaller(): self._launchEvent(irc, msg) try: @@ -267,7 +275,6 @@ class DuckHunt(callbacks.Plugin): if (not self.banging[currentChannel]): #log.info("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke[currentChannel]) + " / throttle[currentChannel]: " + str(self.throttle[currentChannel]) + " / minthrottle[currentChannel]: " + str(self.minthrottle[currentChannel]) + " / maxthrottle[currentChannel]: " + str(self.maxthrottle[currentChannel])) self._launch(irc, msg, '') - self.lastSpoke[currentChannel] = now @@ -473,6 +480,26 @@ class DuckHunt(callbacks.Plugin): listscores = wrap(listscores, [optional('int'), 'channel']) + def total(self, irc, msg, args, channel): + """ + Shows the total amount of ducks shot in (or in the current channel if no channel is given) + """ + + if irc.isChannel(channel): + self._read_scores(channel) + if (self.channelscores.get(channel)): + scores = self.channelscores[channel] + total = 0 + for player in scores.keys(): + total += scores[player] + irc.reply(str(total) + " ducks have been shot in " + channel + "!") + else: + irc.reply("There are no scores for this channel yet") + + else: + irc.reply("Are you sure this is a channel?") + total = wrap(total, ['channel']) + def listtimes(self, irc, msg, args, size, channel): """ @@ -600,6 +627,9 @@ class DuckHunt(callbacks.Plugin): self.duck[currentChannel] = False + # Reset the basetime for the waiting time before the next duck + self.lastSpoke[currentChannel] = time.time() + if self.registryValue('ducks', currentChannel): maxShoots = self.registryValue('ducks', currentChannel) else: @@ -636,7 +666,7 @@ class DuckHunt(callbacks.Plugin): else: irc.reply("There was no duck! %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick])) else: - irc.reply("The hunt has not started yet!") + irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") else: irc.error('You have to be on a channel') From 5830c4007e045c29481e6ed5153a09b7d2c457e0 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 5 Sep 2012 13:20:22 +0200 Subject: [PATCH 27/67] Use conf.supybot.directories.data to store scores and times --- plugin.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/plugin.py b/plugin.py index 403174b..041eae1 100644 --- a/plugin.py +++ b/plugin.py @@ -34,6 +34,7 @@ import supybot.schedule as schedule import supybot.ircdb as ircdb import supybot.ircmsgs as ircmsgs import supybot.log as log +import supybot.conf as conf import threading, random, pickle, os, time, datetime @@ -69,8 +70,10 @@ class DuckHunt(callbacks.Plugin): throttle = {} # Where to save scores? - path = "supybot/data/DuckHunt/" + fileprefix = "DuckHunt_" + path = conf.supybot.directories.data + # Enable the 'dbg' command, which launch a duck, if true debug = 0 # Other params @@ -125,17 +128,17 @@ class DuckHunt(callbacks.Plugin): """ # scores - outputfile = open(self.path + channel + ".scores", "wb") + outputfile = open(self.path.dirize(self.fileprefix + channel + ".scores"), "wb") pickle.dump(self.channelscores[channel], outputfile) outputfile.close() # times - outputfile = open(self.path + channel + ".times", "wb") + outputfile = open(self.path.dirize(self.fileprefix + channel + ".times"), "wb") pickle.dump(self.channeltimes[channel], outputfile) outputfile.close() # worst times - outputfile = open(self.path + channel + ".worsttimes", "wb") + outputfile = open(self.path.dirize(self.fileprefix + channel + ".worsttimes"), "wb") pickle.dump(self.channelworsttimes[channel], outputfile) outputfile.close() @@ -147,25 +150,25 @@ class DuckHunt(callbacks.Plugin): """ Reads scores and times from disk """ - + filename = self.path.dirize(self.fileprefix + channel) # scores if not self.channelscores.get(channel): - if os.path.isfile(self.path + channel + ".scores"): - inputfile = open(self.path + channel + ".scores", "rb") + if os.path.isfile(filename + ".scores"): + inputfile = open(filename + ".scores", "rb") self.channelscores[channel] = pickle.load(inputfile) inputfile.close() # times if not self.channeltimes.get(channel): - if os.path.isfile(self.path + channel + ".times"): - inputfile = open(self.path + channel + ".times", "rb") + if os.path.isfile(filename + ".times"): + inputfile = open(filename + ".times", "rb") self.channeltimes[channel] = pickle.load(inputfile) inputfile.close() # worst times if not self.channelworsttimes.get(channel): - if os.path.isfile(self.path + channel + ".worsttimes"): - inputfile = open(self.path + channel + ".worsttimes", "rb") + if os.path.isfile(filename + ".worsttimes"): + inputfile = open(filename + ".worsttimes", "rb") self.channelworsttimes[channel] = pickle.load(inputfile) inputfile.close() From 80a482bc83ffa9e2e1f0d549e51db60260027cf5 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 17:47:48 +0200 Subject: [PATCH 28/67] Adds kickMode :) --- config.py | 4 ++++ plugin.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/config.py b/config.py index b28e7e7..66b052f 100644 --- a/config.py +++ b/config.py @@ -57,6 +57,10 @@ conf.registerChannelValue(DuckHunt, 'maxthrottle', registry.Integer(300, """ The maximum amount of time before a new duck may be launched (in seconds)""")) +conf.registerChannelValue(DuckHunt, 'kickMode', + registry.Boolean(True, """If someone shoots when there is no duck, should he be kicked from the channel?""")) + + # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugin.py b/plugin.py index 041eae1..9b0469c 100644 --- a/plugin.py +++ b/plugin.py @@ -39,6 +39,7 @@ import supybot.conf as conf import threading, random, pickle, os, time, datetime +# TODO: Average time class DuckHunt(callbacks.Plugin): """ @@ -668,6 +669,11 @@ class DuckHunt(callbacks.Plugin): irc.reply("There was no duck! %s: %i (%.2f seconds) " % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) else: irc.reply("There was no duck! %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick])) + + # If kickMode is enabled for this channel, and the bot have op capability, let's kick! + if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: + irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, 'There was no duck! You just shot yourself!')) + else: irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") else: From 6a4606a2791af50b5290fa4abe6449824e330a16 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 18:03:46 +0200 Subject: [PATCH 29/67] Adds average shooting time for the current hunt --- plugin.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index 9b0469c..4e041b3 100644 --- a/plugin.py +++ b/plugin.py @@ -39,7 +39,6 @@ import supybot.conf as conf import threading, random, pickle, os, time, datetime -# TODO: Average time class DuckHunt(callbacks.Plugin): """ @@ -63,6 +62,7 @@ class DuckHunt(callbacks.Plugin): channeltimes = {} # Saved times for the channel worsttimes = {} # Worst times for the current hunt channelworsttimes = {} # Saved worst times for the channel + averagetime = {} # Average shooting time for the current hunt # Does a duck needs to be launched? lastSpoke = {} @@ -246,6 +246,9 @@ class DuckHunt(callbacks.Plugin): # Init banging self.banging[currentChannel] = False + # Init averagetime + self.averagetime[currentChannel] = 0; + # Init schedule # First of all, stop the scheduler if it was still running @@ -611,6 +614,8 @@ class DuckHunt(callbacks.Plugin): irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) + self.averagetime[currentChannel] += bangdelay + # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) try: previoustime = self.toptimes[currentChannel][msg.nick] @@ -648,6 +653,7 @@ class DuckHunt(callbacks.Plugin): self.started[currentChannel] = True if self.scores.get(currentChannel): self.scores[currentChannel] = {} + self.averagetime[currentChannel] = 0 # There was no duck or the duck has already been shot @@ -770,6 +776,8 @@ class DuckHunt(callbacks.Plugin): if (recordmsg != ''): irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) + # Showing average shooting time: + irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / maxShoots))) # Write the scores and times to disk self._calc_scores(currentChannel) From 0a49be00919aab18c5b9b134e4a05b481a36b4c5 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 18:06:03 +0200 Subject: [PATCH 30/67] Documentation update --- config.py | 2 +- doc/DuckHunt.html | 8 ++++++++ doc/DuckHunt.rst | 10 ++++++++++ doc/DuckHunt.stx | 12 ++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index 66b052f..031b9c1 100644 --- a/config.py +++ b/config.py @@ -58,7 +58,7 @@ conf.registerChannelValue(DuckHunt, The maximum amount of time before a new duck may be launched (in seconds)""")) conf.registerChannelValue(DuckHunt, 'kickMode', - registry.Boolean(True, """If someone shoots when there is no duck, should he be kicked from the channel?""")) + registry.Boolean(True, """If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel)""")) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 07e4630..801f9b1 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -356,6 +356,9 @@ timelist. Also works with worst times.
Starts the hunt
stop
Stops the current hunt
+
total
+
Shows the total amount of ducks shot in <channel> (or in the current channel +if no channel is given)
@@ -381,6 +384,11 @@ timelist. Also works with worst times.

This config variable defaults to 300 and is channel specific.

The maximum amount of time before a new duck may be launched (in seconds)

+
supybot.plugins.DuckHunt.kickMode
+

This config variable defaults to True and is channel specific.

+

If someone shoots when there is no duck, should he be kicked from the +channel? (this requires the bot to be op on the channel)

+
diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index 7dbb772..e1ff795 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -55,6 +55,10 @@ start stop Stops the current hunt +total + Shows the total amount of ducks shot in (or in the current channel + if no channel is given) + Configuration ------------- supybot.plugins.DuckHunt.public @@ -82,3 +86,9 @@ supybot.plugins.DuckHunt.maxthrottle The maximum amount of time before a new duck may be launched (in seconds) +supybot.plugins.DuckHunt.kickMode + This config variable defaults to True and is channel specific. + + If someone shoots when there is no duck, should he be kicked from the + channel? (this requires the bot to be op on the channel) + diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index fab0abd..567d9f1 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -67,6 +67,11 @@ Documentation for the DuckHunt plugin for Supybot Stops the current hunt + * total + + Shows the total amount of ducks shot in (or in the current + channel if no channel is given) + Configuration * supybot.plugins.DuckHunt.public @@ -99,3 +104,10 @@ Documentation for the DuckHunt plugin for Supybot The maximum amount of time before a new duck may be launched (in seconds) + * supybot.plugins.DuckHunt.kickMode + + This config variable defaults to True and is channel specific. + + If someone shoots when there is no duck, should he be kicked from the + channel? (this requires the bot to be op on the channel) + From 74cc8620540245e8851b2d3af2dc3186a366255d Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 18:08:31 +0200 Subject: [PATCH 31/67] README update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 653c6e6..62eb490 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,6 @@ How to configure Several per-channel configuration variables are available (look at the "channel" command to learn more on how to configure per-channel configuration variables): * autoRestart: Does a new hunt automatically start when the previous one is over? * ducks: Number of ducks during a hunt? - * frequency: Determines how often a duck will be launched. 0 means that no duck will ever be launched. 1 means that ducks will be launched one after another (somewhere between minthrottle and maxthrottle, of course). * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) + * kickMode: If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) From 3e55af27ff63ead156e0c095196b2a579c3a4d7f Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 18:28:29 +0200 Subject: [PATCH 32/67] Average time fix --- plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index 4e041b3..2763b8e 100644 --- a/plugin.py +++ b/plugin.py @@ -777,7 +777,7 @@ class DuckHunt(callbacks.Plugin): irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) # Showing average shooting time: - irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / maxShoots))) + irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) # Write the scores and times to disk self._calc_scores(currentChannel) From dabcca504c1e932d6cc1e2fb2c1a7fff10598cd3 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 6 Sep 2012 19:42:58 +0200 Subject: [PATCH 33/67] README update --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 62eb490..50abcbd 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,7 @@ Several per-channel configuration variables are available (look at the "channel" * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) * kickMode: If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) + +Update +------ +Get latest version at : https://github.com/veggiematts/supybot-duckhunt From 0f51246f8477dfc53c05bfd09f833514dffa6e1c Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 7 Sep 2012 16:38:58 +0200 Subject: [PATCH 34/67] Adds friday mode Improve kick message when kickmode is enabled --- plugin.py | 79 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/plugin.py b/plugin.py index 2763b8e..fe3fe03 100644 --- a/plugin.py +++ b/plugin.py @@ -63,6 +63,7 @@ class DuckHunt(callbacks.Plugin): worsttimes = {} # Worst times for the current hunt channelworsttimes = {} # Saved worst times for the channel averagetime = {} # Average shooting time for the current hunt + fridayMode = {} # Does a duck needs to be launched? lastSpoke = {} @@ -173,6 +174,28 @@ class DuckHunt(callbacks.Plugin): self.channelworsttimes[channel] = pickle.load(inputfile) inputfile.close() + + def _initthrottle(self, irc, msg, args, channel): + + if (not self.fridayMode.get(channel)): + self.fridayMode[channel] = False + if self.fridayMode[channel] == False: + # Init min throttle[currentChannel] and max throttle[currentChannel] + if self.registryValue('minthrottle', channel): + self.minthrottle[channel] = self.registryValue('minthrottle', channel) + else: + self.minthrottle[channel] = 30 + + if self.registryValue('maxthrottle', channel): + self.maxthrottle[channel] = self.registryValue('maxthrottle', channel) + else: + self.maxthrottle[channel] = 300 + + else: + self.minthrottle[channel] = 3 + self.maxthrottle[channel] = 60 + + self.throttle[channel] = random.randint(self.minthrottle[channel], self.maxthrottle[channel]) def start(self, irc, msg, args): @@ -187,18 +210,8 @@ class DuckHunt(callbacks.Plugin): irc.reply("There is already a hunt right now!") else: - # Init min throttle[currentChannel] and max throttle[currentChannel] - if self.registryValue('minthrottle', currentChannel): - self.minthrottle[currentChannel] = self.registryValue('minthrottle', currentChannel) - else: - self.minthrottle[currentChannel] = 30 + self._initthrottle(irc, msg, args, currentChannel) - if self.registryValue('maxthrottle', currentChannel): - self.maxthrottle[currentChannel] = self.registryValue('maxthrottle', currentChannel) - else: - self.maxthrottle[currentChannel] = 300 - - self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) #log.info("throttle : " + str(self.throttle[currentChannel])) # Init saved scores @@ -307,7 +320,29 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') stop = wrap(stop) + def fridaymode(self, irc, msg, args, channel): + """ + Enable/disable friday mode! (there are lots of ducks on friday :)) + """ + if irc.isChannel(channel): + if (not self.fridayMode.get(channel)): + self.fridayMode[channel] = False + + if self.fridayMode[channel] == True: + self.fridayMode[channel] = False + irc.reply("Friday mode is now disabled.") + + else: + self.fridayMode[channel] = True + irc.reply("Friday mode is now enabled! Shoot alllllllllllll the ducks!") + + self._initthrottle(irc, msg, args, channel) + else: + irc.error('You have to be on a channel') + + + fridaymode = wrap(fridaymode, ['channel']) def launched(self, irc, msg, args): """ @@ -650,7 +685,9 @@ class DuckHunt(callbacks.Plugin): # If autorestart is enabled, we restart a hunt automatically! if self.registryValue('autoRestart', currentChannel): + # This code shouldn't be here self.started[currentChannel] = True + self._initthrottle(irc, msg, args, currentChannel) if self.scores.get(currentChannel): self.scores[currentChannel] = {} self.averagetime[currentChannel] = 0 @@ -669,16 +706,28 @@ class DuckHunt(callbacks.Plugin): self.scores[currentChannel] = {} self.scores[currentChannel][msg.nick] = -1 + # Base message + message = 'There was no duck!' + + # Adding additional message if kick + if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: + message += ' You just shot yourself!' + + # Adding nick and score + message += " %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick]) # If we were able to have a bangdelay (ie: a duck was launched before someone did bang) if (bangdelay): - irc.reply("There was no duck! %s: %i (%.2f seconds) " % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) - else: - irc.reply("There was no duck! %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick])) + # Adding time + message += " (" + str(round(bangdelay,2)) + " seconds)" # If kickMode is enabled for this channel, and the bot have op capability, let's kick! if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: - irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, 'There was no duck! You just shot yourself!')) + irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, message)) + else: + # Else, just say it + irc.reply(message) + else: irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") From 313da892425c720db34741a0e22b869045688700 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 9 Sep 2012 17:08:05 +0200 Subject: [PATCH 35/67] Adds autoFriday channel value --- config.py | 2 ++ plugin.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index 031b9c1..8b7bff8 100644 --- a/config.py +++ b/config.py @@ -60,6 +60,8 @@ conf.registerChannelValue(DuckHunt, conf.registerChannelValue(DuckHunt, 'kickMode', registry.Boolean(True, """If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel)""")) +conf.registerChannelValue(DuckHunt, 'autoFriday', + registry.Boolean(True, """ Do we need to automatically launch more ducks on friday? """)) diff --git a/plugin.py b/plugin.py index fe3fe03..b8acc8d 100644 --- a/plugin.py +++ b/plugin.py @@ -179,6 +179,13 @@ class DuckHunt(callbacks.Plugin): if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False + + + # autoFriday? + if self.registryValue('autoFriday', channel) and int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 18: + self.fridayMode[channel] = True + + if self.fridayMode[channel] == False: # Init min throttle[currentChannel] and max throttle[currentChannel] if self.registryValue('minthrottle', channel): @@ -342,7 +349,7 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') - fridaymode = wrap(fridaymode, ['channel']) + fridaymode = wrap(fridaymode, ['channel', 'admin']) def launched(self, irc, msg, args): """ From a5b4d8d19b18efe10373d09551469ca2e209e015 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 9 Sep 2012 19:50:04 +0200 Subject: [PATCH 36/67] Add some tests Fix average time bug Update docstrings --- plugin.py | 34 ++++++++++++++++++++++++++-------- test.py | 14 ++++++++++++-- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/plugin.py b/plugin.py index b8acc8d..621938d 100644 --- a/plugin.py +++ b/plugin.py @@ -266,6 +266,9 @@ class DuckHunt(callbacks.Plugin): # Init banging self.banging[currentChannel] = False + # Init shoots + self.shoots[currentChannel] = 0 + # Init averagetime self.averagetime[currentChannel] = 0; @@ -373,7 +376,9 @@ class DuckHunt(callbacks.Plugin): def score(self, irc, msg, args, nick): """ - : Shows the score for a given nick + + + Shows the score for a given nick """ currentChannel = msg.args[0] if irc.isChannel(currentChannel): @@ -397,7 +402,9 @@ class DuckHunt(callbacks.Plugin): def mergescores(self, irc, msg, args, channel, nickto, nickfrom): """ - [] : nickto gets the points of nickfrom and nickfrom is removed from the scorelist + [] + + nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ if irc.isChannel(channel): try: @@ -421,7 +428,9 @@ class DuckHunt(callbacks.Plugin): def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): """ - [] : nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. + [] + + nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. """ if irc.isChannel(channel): try: @@ -455,7 +464,9 @@ class DuckHunt(callbacks.Plugin): def rmtime(self, irc, msg, args, channel, nick): """ - [] : Remove 's best time + [] + + Remove 's best time """ if irc.isChannel(channel): self._read_scores(channel) @@ -472,7 +483,9 @@ class DuckHunt(callbacks.Plugin): def rmscore(self, irc, msg, args, channel, nick): """ - [] : Remove 's score + [] + + Remove 's score """ if irc.isChannel(channel): try: @@ -493,7 +506,9 @@ class DuckHunt(callbacks.Plugin): def listscores(self, irc, msg, args, size, channel): """ - [] []: Shows the -sized score list for (or for the current channel if no channel is given) + [] [] + + Shows the -sized score list for (or for the current channel if no channel is given) """ if irc.isChannel(channel): @@ -552,7 +567,9 @@ class DuckHunt(callbacks.Plugin): def listtimes(self, irc, msg, args, size, channel): """ - [] []: Shows the -sized time list for (or for the current channel if no channel is given) + [] [] + + Shows the -sized time list for (or for the current channel if no channel is given) """ if irc.isChannel(channel): @@ -833,7 +850,8 @@ class DuckHunt(callbacks.Plugin): irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) # Showing average shooting time: - irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) + if (self.shoots[currentChannel] > 1): + irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) # Write the scores and times to disk self._calc_scores(currentChannel) diff --git a/test.py b/test.py index ec4ac7c..8d88724 100644 --- a/test.py +++ b/test.py @@ -29,8 +29,18 @@ from supybot.test import * -class DuckHuntTestCase(PluginTestCase): - plugins = ('DuckHuntTestCase',) +class DuckHuntTestCase(ChannelPluginTestCase): + plugins = ('DuckHunt',) + + + def tests(self): + self.assertResponse("bang", "There is no hunt right now! You can start a hunt with the 'start' command") + self.assertResponse("stop", "Nothing to stop: there's no hunt right now.") + self.assertResponse("start", "The hunt starts now!") + self.assertResponse("start", "There is already a hunt right now!") + self.assertRegexp("bang", "^There was no duck!") + self.assertResponse("stop", "The hunt stops now!") + self.assertNotError("listscores") # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From 859679e0aa4a85078c27dbba00eade65fab33892 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 9 Sep 2012 19:53:25 +0200 Subject: [PATCH 37/67] Documentation update --- README.md | 1 + doc/DuckHunt.html | 20 +++++++++++++------- doc/DuckHunt.rst | 22 +++++++++++++++------- doc/DuckHunt.stx | 24 +++++++++++++++++------- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 50abcbd..3a3f442 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Several per-channel configuration variables are available (look at the "channel" * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) * kickMode: If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) + * autoFriday: Do we need to automatically launch more ducks on friday? Update ------ diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 801f9b1..796e375 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -331,27 +331,29 @@ when there is no duck launched costs a point.

Shoots the duck!
dbg
This is a debug command. If debug mode is not enabled, it won't do anything
+
fridaymode
+
Enable/disable friday mode! (there are lots of ducks on friday :))
launched
Is there a duck right now?
listscores
-
[<size>] [<channel>]: Shows the <size>-sized score list for <channel> (or for +
[<size>] [<channel>] Shows the <size>-sized score list for <channel> (or for the current channel if no channel is given)
listtimes
-
[<size>] [<channel>]: Shows the <size>-sized time list for <channel> (or for +
[<size>] [<channel>] Shows the <size>-sized time list for <channel> (or for the current channel if no channel is given)
mergescores
-
[<channel>] <nickto> <nickfrom>: nickto gets the points of nickfrom and +
[<channel>] <nickto> <nickfrom> nickto gets the points of nickfrom and nickfrom is removed from the scorelist
mergetimes
-
[<channel>] <nickto> <nickfrom>: nickto gets the best time of nickfrom if +
[<channel>] <nickto> <nickfrom> nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times.
rmscore
-
[<channel>] <nick>: Remove <nick>'s score
+
[<channel>] <nick> Remove <nick>'s score
rmtime
-
[<channel>] <nick>: Remove <nick>'s best time
+
[<channel>] <nick> Remove <nick>'s best time
score
-
<nick>: Shows the score for a given nick
+
<nick> Shows the score for a given nick
start
Starts the hunt
stop
@@ -389,6 +391,10 @@ if no channel is given)

If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel)

+
supybot.plugins.DuckHunt.autoFriday
+

This config variable defaults to True and is channel specific.

+

Do we need to automatically launch more ducks on friday?

+
diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index e1ff795..7e912c5 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -20,34 +20,37 @@ bang dbg This is a debug command. If debug mode is not enabled, it won't do anything +fridaymode + Enable/disable friday mode! (there are lots of ducks on friday :)) + launched Is there a duck right now? listscores - [] []: Shows the -sized score list for (or for + [] [] Shows the -sized score list for (or for the current channel if no channel is given) listtimes - [] []: Shows the -sized time list for (or for + [] [] Shows the -sized time list for (or for the current channel if no channel is given) mergescores - [] : nickto gets the points of nickfrom and + [] nickto gets the points of nickfrom and nickfrom is removed from the scorelist mergetimes - [] : nickto gets the best time of nickfrom if + [] nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. rmscore - [] : Remove 's score + [] Remove 's score rmtime - [] : Remove 's best time + [] Remove 's best time score - : Shows the score for a given nick + Shows the score for a given nick start Starts the hunt @@ -92,3 +95,8 @@ supybot.plugins.DuckHunt.kickMode If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) +supybot.plugins.DuckHunt.autoFriday + This config variable defaults to True and is channel specific. + + Do we need to automatically launch more ducks on friday? + diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index 567d9f1..94f23e4 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -22,42 +22,46 @@ Documentation for the DuckHunt plugin for Supybot This is a debug command. If debug mode is not enabled, it won't do anything + * fridaymode + + Enable/disable friday mode! (there are lots of ducks on friday :)) + * launched Is there a duck right now? * listscores - [] []: Shows the -sized score list for (or + [] [] Shows the -sized score list for (or for the current channel if no channel is given) * listtimes - [] []: Shows the -sized time list for (or + [] [] Shows the -sized time list for (or for the current channel if no channel is given) * mergescores - [] : nickto gets the points of nickfrom and + [] nickto gets the points of nickfrom and nickfrom is removed from the scorelist * mergetimes - [] : nickto gets the best time of nickfrom if + [] nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. * rmscore - [] : Remove 's score + [] Remove 's score * rmtime - [] : Remove 's best time + [] Remove 's best time * score - : Shows the score for a given nick + Shows the score for a given nick * start @@ -111,3 +115,9 @@ Documentation for the DuckHunt plugin for Supybot If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) + * supybot.plugins.DuckHunt.autoFriday + + This config variable defaults to True and is channel specific. + + Do we need to automatically launch more ducks on friday? + From cc7af63b3d2f32ea1cd566d09f2181a8a4e23e66 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 10 Sep 2012 20:11:33 +0200 Subject: [PATCH 38/67] No need to tell the score at the end of a hunt if it is a perfect. --- plugin.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugin.py b/plugin.py index 621938d..8b817e5 100644 --- a/plugin.py +++ b/plugin.py @@ -793,16 +793,18 @@ class DuckHunt(callbacks.Plugin): else: maxShoots = 10 - # Showing scores - #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) - #irc.reply(self.scores.get(currentChannel)) - #TODO: Better display - irc.reply(sorted(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k), reverse=True)) - # Is there a perfect? if (winnerscore == maxShoots): irc.reply("\o/ %s: %i ducks out of %i: perfect!!! +%i \o/" % (winnernick, winnerscore, maxShoots, self.perfectbonus)) self.scores[currentChannel][winnernick] += self.perfectbonus + else: + # Showing scores + #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) + #irc.reply(self.scores.get(currentChannel)) + #TODO: Better display + irc.reply(sorted(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k), reverse=True)) + + # Getting channel best time (to see if the best time of this hunt is better) channelbestnick = None From 84e6133d5f54f78c3dafc8e49b0937e7248b30dd Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 14 Sep 2012 10:35:28 +0200 Subject: [PATCH 39/67] Adds week scores --- plugin.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.py | 1 + 2 files changed, 90 insertions(+) diff --git a/plugin.py b/plugin.py index 8b817e5..2fe84a8 100644 --- a/plugin.py +++ b/plugin.py @@ -64,6 +64,8 @@ class DuckHunt(callbacks.Plugin): channelworsttimes = {} # Saved worst times for the channel averagetime = {} # Average shooting time for the current hunt fridayMode = {} + week = {} + channelweek = {} # Does a duck needs to be launched? lastSpoke = {} @@ -81,6 +83,9 @@ class DuckHunt(callbacks.Plugin): # Other params perfectbonus = 5 # How many extra-points are given when someones does a perfect hunt? toplist = 5 # How many high{scores|times} are displayed by default? + dow = int(time.strftime("%u")) # Day of week + woy = int(time.strftime("%V")) # Week of year + dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] def _calc_scores(self, channel): @@ -122,6 +127,18 @@ class DuckHunt(callbacks.Plugin): if(self.worsttimes[channel][player] > self.channelworsttimes[channel][player]): self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + # week scores + for player in self.scores[channel].keys(): + if not player in self.channelweek[channel][self.woy][self.dow]: + # It's a new player + self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] + log.info(channel + " " + str(self.woy) + " " + str(self.dow) + " " + player + " 1 ") + else: + # It's a player that already has a saved score + self.channelweek[channel][self.woy][self.dow][player] += self.scores[channel][player] + log.info(channel + " " + str(self.woy) + " " + str(self.dow) + " " + player + " + ") + + def _write_scores(self, channel): @@ -144,6 +161,13 @@ class DuckHunt(callbacks.Plugin): pickle.dump(self.channelworsttimes[channel], outputfile) outputfile.close() + # week scores + outputfile = open(self.path.dirize(self.fileprefix + channel + ".weekscores"), "wb") + pickle.dump(self.channelweek[channel], outputfile) + outputfile.close() + + + @@ -174,9 +198,36 @@ class DuckHunt(callbacks.Plugin): self.channelworsttimes[channel] = pickle.load(inputfile) inputfile.close() + # week scores + if not self.channelweek.get(channel): + if os.path.isfile(filename + ".weekscores"): + inputfile = open(filename + ".weekscores", "rb") + self.channelweek[channel] = pickle.load(inputfile) + inputfile.close() + + def _initthrottle(self, irc, msg, args, channel): + self.dow = int(time.strftime("%u")) # Day of week + self.woy = int(time.strftime("%V")) # Week of year + + # Init week scores + try: + self.channelweek[channel] + except: + self.channelweek[channel] = {} + try: + self.channelweek[channel][self.woy] + except: + self.channelweek[channel][self.woy] = {} + try: + self.channelweek[channel][self.woy][self.dow] + except: + self.channelweek[channel][self.woy][self.dow] = {} + + + if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False @@ -227,6 +278,8 @@ class DuckHunt(callbacks.Plugin): except: self.channelscores[currentChannel] = {} + + # Init saved times try: self.channeltimes[currentChannel] @@ -502,6 +555,42 @@ class DuckHunt(callbacks.Plugin): rmscore = wrap(rmscore, ['channel', 'nick', 'admin']) + def weekscores(self, irc, msg, args, week, channel): + """ + [] [] + + Shows the score list of the week for (or for the current channel if no channel is given) + """ + + if irc.isChannel(channel): + + self._read_scores(channel) + + if (not week): + week = self.woy + + if self.channelweek.get(channel): + if self.channelweek[channel].get(week): + # for each day of week + msgstring = '' + for i in (1,2,3,4,5,6,7): + log.info(channel + " " + str(week) + " " + str(i) ) + if self.channelweek[channel][week].get(i): + winnernick, winnerscore = max(self.channelweek[channel][week][i].iteritems(), key=lambda (k,v):(v,k)) + msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " + + if msgstring != "": + irc.reply("Week " + str(self.woy) + " scores: " + msgstring) + else: + irc.reply("There aren't any week scores for this week yet.") + else: + irc.reply("There aren't any week scores for this week yet.") + else: + irc.reply("There aren't any week scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") + weekscores = wrap(weekscores, [optional('int'), 'channel']) + def listscores(self, irc, msg, args, size, channel): diff --git a/test.py b/test.py index 8d88724..20ebafe 100644 --- a/test.py +++ b/test.py @@ -41,6 +41,7 @@ class DuckHuntTestCase(ChannelPluginTestCase): self.assertRegexp("bang", "^There was no duck!") self.assertResponse("stop", "The hunt stops now!") self.assertNotError("listscores") + self.assertNotError("weekscores") # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From 25460a6aea38e6a2efe8fe906bfb8097c5574574 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 14 Sep 2012 14:05:51 +0200 Subject: [PATCH 40/67] Adds week winner --- plugin.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/plugin.py b/plugin.py index 2fe84a8..d1c5f4e 100644 --- a/plugin.py +++ b/plugin.py @@ -85,7 +85,7 @@ class DuckHunt(callbacks.Plugin): toplist = 5 # How many high{scores|times} are displayed by default? dow = int(time.strftime("%u")) # Day of week woy = int(time.strftime("%V")) # Week of year - dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] + dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Caturday', 'Saturday', 'Sunday'] def _calc_scores(self, channel): @@ -268,6 +268,9 @@ class DuckHunt(callbacks.Plugin): irc.reply("There is already a hunt right now!") else: + # First of all, let's read the score if needed + self._read_scores(currentChannel) + self._initthrottle(irc, msg, args, currentChannel) #log.info("throttle : " + str(self.throttle[currentChannel])) @@ -303,9 +306,6 @@ class DuckHunt(callbacks.Plugin): # Init lastSpoke self.lastSpoke[currentChannel] = time.time() - if not self.channelscores[currentChannel] or not self.channeltimes[currentChannel] or not self.channelworsttimes[currentChannel]: - self._read_scores(currentChannel) - # Reinit current hunt scores if self.scores.get(currentChannel): self.scores[currentChannel] = {} @@ -565,6 +565,7 @@ class DuckHunt(callbacks.Plugin): if irc.isChannel(channel): self._read_scores(channel) + weekscores = {} if (not week): week = self.woy @@ -576,11 +577,25 @@ class DuckHunt(callbacks.Plugin): for i in (1,2,3,4,5,6,7): log.info(channel + " " + str(week) + " " + str(i) ) if self.channelweek[channel][week].get(i): + # Getting winner of the day winnernick, winnerscore = max(self.channelweek[channel][week][i].iteritems(), key=lambda (k,v):(v,k)) msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " + # Getting all scores, to get the winner of the week + for player in self.channelweek[channel][week][i].keys(): + try: + weekscores[player] += self.channelweek[channel][week][i][player] + except: + weekscores[player] = self.channelweek[channel][week][i][player] + + + if msgstring != "": irc.reply("Week " + str(self.woy) + " scores: " + msgstring) + # Who's the winner at this point? + winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) + irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) + else: irc.reply("There aren't any week scores for this week yet.") else: From c6bea37018e21020ed8c7d10d3191aca11fdd3fa Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 15 Sep 2012 11:13:53 +0200 Subject: [PATCH 41/67] Adds dayscore Adds option to weekscores Fix autoFriday Removes average shooting time --- plugin.py | 134 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 41 deletions(-) diff --git a/plugin.py b/plugin.py index d1c5f4e..d40f768 100644 --- a/plugin.py +++ b/plugin.py @@ -66,6 +66,7 @@ class DuckHunt(callbacks.Plugin): fridayMode = {} week = {} channelweek = {} + leader = {} # Does a duck needs to be launched? lastSpoke = {} @@ -132,11 +133,9 @@ class DuckHunt(callbacks.Plugin): if not player in self.channelweek[channel][self.woy][self.dow]: # It's a new player self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] - log.info(channel + " " + str(self.woy) + " " + str(self.dow) + " " + player + " 1 ") else: # It's a player that already has a saved score self.channelweek[channel][self.woy][self.dow][player] += self.scores[channel][player] - log.info(channel + " " + str(self.woy) + " " + str(self.dow) + " " + player + " + ") @@ -227,16 +226,17 @@ class DuckHunt(callbacks.Plugin): self.channelweek[channel][self.woy][self.dow] = {} + # autoFriday? + if self.registryValue('autoFriday', channel): + if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: + self.fridayMode[channel] = True + else: + self.fridayMode[channel] = None if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False - # autoFriday? - if self.registryValue('autoFriday', channel) and int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 18: - self.fridayMode[channel] = True - - if self.fridayMode[channel] == False: # Init min throttle[currentChannel] and max throttle[currentChannel] if self.registryValue('minthrottle', channel): @@ -273,16 +273,12 @@ class DuckHunt(callbacks.Plugin): self._initthrottle(irc, msg, args, currentChannel) - #log.info("throttle : " + str(self.throttle[currentChannel])) - # Init saved scores try: self.channelscores[currentChannel] except: self.channelscores[currentChannel] = {} - - # Init saved times try: self.channeltimes[currentChannel] @@ -295,7 +291,6 @@ class DuckHunt(callbacks.Plugin): except: self.channelworsttimes[currentChannel] = {} - # Init times self.toptimes[currentChannel] = {} self.worsttimes[currentChannel] = {} @@ -356,7 +351,6 @@ class DuckHunt(callbacks.Plugin): if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: # If someone is "banging" right now, do not launch a duck if (not self.banging[currentChannel]): - #log.info("Delay since the last launch for " + currentChannel + " " + str(now - self.lastSpoke[currentChannel]) + " / throttle[currentChannel]: " + str(self.throttle[currentChannel]) + " / minthrottle[currentChannel]: " + str(self.minthrottle[currentChannel]) + " / maxthrottle[currentChannel]: " + str(self.maxthrottle[currentChannel])) self._launch(irc, msg, '') @@ -555,11 +549,54 @@ class DuckHunt(callbacks.Plugin): rmscore = wrap(rmscore, ['channel', 'nick', 'admin']) - def weekscores(self, irc, msg, args, week, channel): + + + + def dayscores(self, irc, msg, args, channel): """ - [] [] + [] - Shows the score list of the week for (or for the current channel if no channel is given) + Shows the score list of the day for . + """ + + if irc.isChannel(channel): + + self._read_scores(channel) + self.dow = int(time.strftime("%u")) # Day of week + self.woy = int(time.strftime("%V")) # Week of year + day = self.dow + week = self.woy + + if self.channelweek.get(channel): + if self.channelweek[channel].get(week): + if self.channelweek[channel][week].get(day): + # Getting all scores, to get the winner of the week + msgstring = '' + scores = sorted(self.channelweek[channel][week][day].iteritems(), key=lambda (k,v):(v,k), reverse=True) + for item in scores: + msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " + + if msgstring != "": + irc.reply("Scores for today: " + msgstring) + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") + dayscores = wrap(dayscores, ['channel']) + + + + def weekscores(self, irc, msg, args, week, nick, channel): + """ + [] [] [] + + Shows the score list of the week for . If is provided, it will only show 's scores. """ if irc.isChannel(channel): @@ -572,39 +609,55 @@ class DuckHunt(callbacks.Plugin): if self.channelweek.get(channel): if self.channelweek[channel].get(week): - # for each day of week - msgstring = '' - for i in (1,2,3,4,5,6,7): - log.info(channel + " " + str(week) + " " + str(i) ) - if self.channelweek[channel][week].get(i): - # Getting winner of the day - winnernick, winnerscore = max(self.channelweek[channel][week][i].iteritems(), key=lambda (k,v):(v,k)) - msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " + # Showing the winner for each day + if not nick: + msgstring = '' + # for each day of week + for i in (1,2,3,4,5,6,7): + if self.channelweek[channel][week].get(i): + # Getting winner of the day + winnernick, winnerscore = max(self.channelweek[channel][week][i].iteritems(), key=lambda (k,v):(v,k)) + msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " - # Getting all scores, to get the winner of the week - for player in self.channelweek[channel][week][i].keys(): - try: - weekscores[player] += self.channelweek[channel][week][i][player] - except: - weekscores[player] = self.channelweek[channel][week][i][player] - + # Getting all scores, to get the winner of the week + for player in self.channelweek[channel][week][i].keys(): + try: + weekscores[player] += self.channelweek[channel][week][i][player] + except: + weekscores[player] = self.channelweek[channel][week][i][player] + - if msgstring != "": - irc.reply("Week " + str(self.woy) + " scores: " + msgstring) - # Who's the winner at this point? - winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) - irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) + if msgstring != "": + irc.reply("Scores for week " + str(self.woy) + ": " + msgstring) + # Who's the winner at this point? + winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) + irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) + else: + irc.reply("There aren't any week scores for this week yet.") else: - irc.reply("There aren't any week scores for this week yet.") + # Showing the scores of + msgstring = '' + for i in (1,2,3,4,5,6,7): + if self.channelweek[channel][week].get(i): + # Getting winner of the day + if self.channelweek[channel][week][i].get(nick): + msgstring += self.dayname[i - 1] + ": "+ str(self.channelweek[channel][week][i].get(nick)) + " | " + + if msgstring != "": + irc.reply(nick + " scores for week " + str(self.woy) + ": " + msgstring) + else: + irc.reply("There aren't any week scores for this nick.") + + else: irc.reply("There aren't any week scores for this week yet.") else: irc.reply("There aren't any week scores for this channel yet.") else: irc.reply("Are you sure this is a channel?") - weekscores = wrap(weekscores, [optional('int'), 'channel']) + weekscores = wrap(weekscores, [optional('int'), optional('nick'), 'channel']) @@ -956,8 +1009,8 @@ class DuckHunt(callbacks.Plugin): irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) # Showing average shooting time: - if (self.shoots[currentChannel] > 1): - irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) + #if (self.shoots[currentChannel] > 1): + #irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) # Write the scores and times to disk self._calc_scores(currentChannel) @@ -1003,7 +1056,6 @@ class DuckHunt(callbacks.Plugin): # Define a new throttle[currentChannel] for the next launch self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) - #log.info("throttle for " + currentChannel + " : " + str(self.throttle[currentChannel])) try: self.shoots[currentChannel] += 1 From 4a1f4c13ec06161ddfd7d699aa3e6d3290f5df84 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 16 Sep 2012 14:13:46 +0200 Subject: [PATCH 42/67] Tells if someone took the lead for the week at the end of a hunt --- plugin.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index d40f768..2e4589f 100644 --- a/plugin.py +++ b/plugin.py @@ -130,7 +130,7 @@ class DuckHunt(callbacks.Plugin): # week scores for player in self.scores[channel].keys(): - if not player in self.channelweek[channel][self.woy][self.dow]: + if not player in self.channelweek[channel][self.woy].get(self.dow): # It's a new player self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] else: @@ -226,6 +226,9 @@ class DuckHunt(callbacks.Plugin): self.channelweek[channel][self.woy][self.dow] = {} + if not self.leader.get(channel): + self.leader[channel] = None + # autoFriday? if self.registryValue('autoFriday', channel): if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: @@ -639,14 +642,16 @@ class DuckHunt(callbacks.Plugin): else: # Showing the scores of msgstring = '' + total = 0 for i in (1,2,3,4,5,6,7): if self.channelweek[channel][week].get(i): - # Getting winner of the day if self.channelweek[channel][week][i].get(nick): msgstring += self.dayname[i - 1] + ": "+ str(self.channelweek[channel][week][i].get(nick)) + " | " + total += self.channelweek[channel][week][i].get(nick) if msgstring != "": irc.reply(nick + " scores for week " + str(self.woy) + ": " + msgstring) + irc.reply("Total: " + str(total) + " points.") else: irc.reply("There aren't any week scores for this nick.") @@ -1015,6 +1020,28 @@ class DuckHunt(callbacks.Plugin): # Write the scores and times to disk self._calc_scores(currentChannel) self._write_scores(currentChannel) + + # Did someone took the lead? + weekscores = {} + if self.channelweek.get(currentChannel): + if self.channelweek[currentChannel].get(self.woy): + msgstring = '' + # for each day of week + for i in (1,2,3,4,5,6,7): + if self.channelweek[currentChannel][self.woy].get(i): + # Getting all scores, to get the winner of the week + for player in self.channelweek[currentChannel][self.woy][i].keys(): + try: + weekscores[player] += self.channelweek[currentChannel][self.woy][i][player] + except: + weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] + winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) + if (winnernick != self.leader[currentChannel]): + irc.reply("x%sx has the lead for the week with %i points." % (winnernick, winnerscore)) + self.leader[currentChannel] = winnernick + + + else: irc.reply("Not a single duck was shot during this hunt!") From 103deb19e08424460e8a9d15896e645e8f8515ca Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 16 Sep 2012 14:15:43 +0200 Subject: [PATCH 43/67] Documentation update --- doc/DuckHunt.html | 5 +++++ doc/DuckHunt.rst | 7 +++++++ doc/DuckHunt.stx | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 796e375..ba6b079 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -329,6 +329,8 @@ when there is no duck launched costs a point.

bang
Shoots the duck!
+
dayscores
+
[<channel>] Shows the score list of the day for <channel>.
dbg
This is a debug command. If debug mode is not enabled, it won't do anything
fridaymode
@@ -361,6 +363,9 @@ timelist. Also works with worst times.
total
Shows the total amount of ducks shot in <channel> (or in the current channel if no channel is given)
+
weekscores
+
[<week>] [<nick>] [<channel>] Shows the score list of the week for <channel>. +If <nick> is provided, it will only show <nick>'s scores.
diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index 7e912c5..193650d 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -17,6 +17,9 @@ Commands bang Shoots the duck! +dayscores + [] Shows the score list of the day for . + dbg This is a debug command. If debug mode is not enabled, it won't do anything @@ -62,6 +65,10 @@ total Shows the total amount of ducks shot in (or in the current channel if no channel is given) +weekscores + [] [] [] Shows the score list of the week for . + If is provided, it will only show 's scores. + Configuration ------------- supybot.plugins.DuckHunt.public diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index 94f23e4..bcb6663 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -17,6 +17,10 @@ Documentation for the DuckHunt plugin for Supybot Shoots the duck! + * dayscores + + [] Shows the score list of the day for . + * dbg This is a debug command. If debug mode is not enabled, it won't do @@ -76,6 +80,11 @@ Documentation for the DuckHunt plugin for Supybot Shows the total amount of ducks shot in (or in the current channel if no channel is given) + * weekscores + + [] [] [] Shows the score list of the week for + . If is provided, it will only show 's scores. + Configuration * supybot.plugins.DuckHunt.public From 3524d64bcc8e08fd0d1c107b735b21d073f8ce1e Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sun, 16 Sep 2012 14:51:23 +0200 Subject: [PATCH 44/67] Use year in weekscores filename --- plugin.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugin.py b/plugin.py index 2e4589f..9616c9c 100644 --- a/plugin.py +++ b/plugin.py @@ -86,6 +86,7 @@ class DuckHunt(callbacks.Plugin): toplist = 5 # How many high{scores|times} are displayed by default? dow = int(time.strftime("%u")) # Day of week woy = int(time.strftime("%V")) # Week of year + year = time.strftime("%Y") dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Caturday', 'Saturday', 'Sunday'] @@ -161,7 +162,7 @@ class DuckHunt(callbacks.Plugin): outputfile.close() # week scores - outputfile = open(self.path.dirize(self.fileprefix + channel + ".weekscores"), "wb") + outputfile = open(self.path.dirize(self.fileprefix + channel + self.year + ".weekscores"), "wb") pickle.dump(self.channelweek[channel], outputfile) outputfile.close() @@ -199,8 +200,8 @@ class DuckHunt(callbacks.Plugin): # week scores if not self.channelweek.get(channel): - if os.path.isfile(filename + ".weekscores"): - inputfile = open(filename + ".weekscores", "rb") + if os.path.isfile(filename + self.year + ".weekscores"): + inputfile = open(filename + self.year + ".weekscores", "rb") self.channelweek[channel] = pickle.load(inputfile) inputfile.close() @@ -210,6 +211,7 @@ class DuckHunt(callbacks.Plugin): self.dow = int(time.strftime("%u")) # Day of week self.woy = int(time.strftime("%V")) # Week of year + year = time.strftime("%Y") # Init week scores try: From 3a285da67dde4359fa77a3c2cd7ef13d6bc5b0c1 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 17 Sep 2012 17:20:33 +0200 Subject: [PATCH 45/67] Fix wrong week displayed in weekscores --- plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index 9616c9c..4cb666b 100644 --- a/plugin.py +++ b/plugin.py @@ -634,7 +634,7 @@ class DuckHunt(callbacks.Plugin): if msgstring != "": - irc.reply("Scores for week " + str(self.woy) + ": " + msgstring) + irc.reply("Scores for week " + str(week) + ": " + msgstring) # Who's the winner at this point? winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) @@ -1039,7 +1039,7 @@ class DuckHunt(callbacks.Plugin): weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) if (winnernick != self.leader[currentChannel]): - irc.reply("x%sx has the lead for the week with %i points." % (winnernick, winnerscore)) + irc.reply("%s has the lead for the week with %i points." % (winnernick, winnerscore)) self.leader[currentChannel] = winnernick From b668a39827894f5497a0834c171ea0ce9d10f3c4 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 18 Sep 2012 20:17:57 +0200 Subject: [PATCH 46/67] Change message if the lead for the week has just been took --- plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index 4cb666b..f4da2c9 100644 --- a/plugin.py +++ b/plugin.py @@ -1039,7 +1039,10 @@ class DuckHunt(callbacks.Plugin): weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) if (winnernick != self.leader[currentChannel]): - irc.reply("%s has the lead for the week with %i points." % (winnernick, winnerscore)) + if self.leader[currentChannel] != None: + irc.reply("%s took the lead for the week over %s with %i points." % (winnernick, self.leader[currentChannel], winnerscore)) + else: + irc.reply("%s has the lead for the week with %i points." % (winnernick, winnerscore)) self.leader[currentChannel] = winnernick From a8efe6683095e7157e8c55439f4d78015e164c4d Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Tue, 18 Sep 2012 20:32:37 +0200 Subject: [PATCH 47/67] Adds day scores merge to mergescores --- plugin.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/plugin.py b/plugin.py index f4da2c9..9a25e74 100644 --- a/plugin.py +++ b/plugin.py @@ -459,15 +459,33 @@ class DuckHunt(callbacks.Plugin): nickto gets the points of nickfrom and nickfrom is removed from the scorelist """ if irc.isChannel(channel): + self._read_scores(channel) + + # Total scores try: - self._read_scores(channel) self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] del self.channelscores[channel][nickfrom] self._write_scores(channel) - irc.replySuccess() + irc.reply("Total scores merged") except: - irc.replyError() + irc.error("Can't merge total scores") + + # Day scores + try: + + self.dow = int(time.strftime("%u")) # Day of week + self.woy = int(time.strftime("%V")) # Week of year + day = self.dow + week = self.woy + self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] + del self.channelweek[channel][week][day][nickfrom] + self._write_scores(channel) + irc.reply("Day scores merged") + + except: + irc.error("Can't merge day scores") + else: From db5c0260278046ea4b8c14e5a5c902fd78b4a123 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 22 Sep 2012 12:14:02 +0200 Subject: [PATCH 48/67] Adds a probability to miss the duck --- config.py | 13 ++--- doc/DuckHunt.html | 4 ++ doc/DuckHunt.rst | 5 ++ doc/DuckHunt.stx | 7 +++ plugin.py | 124 +++++++++++++++++++++++++--------------------- 5 files changed, 91 insertions(+), 62 deletions(-) diff --git a/config.py b/config.py index 8b7bff8..d962264 100644 --- a/config.py +++ b/config.py @@ -49,13 +49,14 @@ conf.registerChannelValue(DuckHunt, 'autoRestart', conf.registerChannelValue(DuckHunt, 'ducks', registry.Integer(5, """Number of ducks during a hunt?""")) -conf.registerChannelValue(DuckHunt, - 'minthrottle', registry.Integer(30, """ - The minimum amount of time before a new duck may be launched (in seconds)""")) +conf.registerChannelValue(DuckHunt, 'minthrottle', + registry.Integer(30, """The minimum amount of time before a new duck may be launched (in seconds)""")) -conf.registerChannelValue(DuckHunt, - 'maxthrottle', registry.Integer(300, """ - The maximum amount of time before a new duck may be launched (in seconds)""")) +conf.registerChannelValue(DuckHunt, 'maxthrottle', + registry.Integer(300, """The maximum amount of time before a new duck may be launched (in seconds)""")) + +conf.registerChannelValue(DuckHunt, 'missProbability', + registry.Probability(0.2, """The probability to miss the duck""")) conf.registerChannelValue(DuckHunt, 'kickMode', registry.Boolean(True, """If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel)""")) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index ba6b079..98b531a 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -391,6 +391,10 @@ If <nick> is provided, it will only show <nick>'s scores.

This config variable defaults to 300 and is channel specific.

The maximum amount of time before a new duck may be launched (in seconds)

+
supybot.plugins.DuckHunt.missProbability
+

This config variable defaults to 0.20000000000000001 and is channel specific.

+

The probability to miss the duck

+
supybot.plugins.DuckHunt.kickMode

This config variable defaults to True and is channel specific.

If someone shoots when there is no duck, should he be kicked from the diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index 193650d..e9294ae 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -96,6 +96,11 @@ supybot.plugins.DuckHunt.maxthrottle The maximum amount of time before a new duck may be launched (in seconds) +supybot.plugins.DuckHunt.missProbability + This config variable defaults to 0.20000000000000001 and is channel specific. + + The probability to miss the duck + supybot.plugins.DuckHunt.kickMode This config variable defaults to True and is channel specific. diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index bcb6663..384524f 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -117,6 +117,13 @@ Documentation for the DuckHunt plugin for Supybot The maximum amount of time before a new duck may be launched (in seconds) + * supybot.plugins.DuckHunt.missProbability + + This config variable defaults to 0.20000000000000001 and is channel + specific. + + The probability to miss the duck + * supybot.plugins.DuckHunt.kickMode This config variable defaults to True and is channel specific. diff --git a/plugin.py b/plugin.py index 9a25e74..704dd53 100644 --- a/plugin.py +++ b/plugin.py @@ -60,13 +60,14 @@ class DuckHunt(callbacks.Plugin): channelscores = {} # Saved scores for the channel toptimes = {} # Times for the current hunt channeltimes = {} # Saved times for the channel - worsttimes = {} # Worst times for the current hunt + worsttimes = {} # Worst times for the current hunt channelworsttimes = {} # Saved worst times for the channel averagetime = {} # Average shooting time for the current hunt - fridayMode = {} - week = {} - channelweek = {} - leader = {} + fridayMode = {} # Are we on friday mode? + missprobability = {} # Probability to miss a duck when shooting + week = {} # Scores for the week + channelweek = {} # Saved scores for the week + leader = {} # Who is the leader for the week? # Does a duck needs to be launched? lastSpoke = {} @@ -241,6 +242,12 @@ class DuckHunt(callbacks.Plugin): if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False + # Miss probability + if self.registryValue('missProbability', channel): + self.missprobability[channel] = self.registryValue('missProbability', channel) + else: + self.missprobability[channel] = 0.2 + if self.fridayMode[channel] == False: # Init min throttle[currentChannel] and max throttle[currentChannel] @@ -843,60 +850,65 @@ class DuckHunt(callbacks.Plugin): # There was a duck if (self.duck[currentChannel] == True): - # Adds one point for the nick that shot the duck - try: - self.scores[currentChannel][msg.nick] += 1 - except: - try: - self.scores[currentChannel][msg.nick] = 1 - except: - self.scores[currentChannel] = {} - self.scores[currentChannel][msg.nick] = 1 - - irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) - - self.averagetime[currentChannel] += bangdelay - - # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) - try: - previoustime = self.toptimes[currentChannel][msg.nick] - if(bangdelay < previoustime): - self.toptimes[currentChannel][msg.nick] = bangdelay - except: - self.toptimes[currentChannel][msg.nick] = bangdelay - - - # Now save the bang delay for the player (if it's worst than it's previous bangdelay) - try: - previoustime = self.worsttimes[currentChannel][msg.nick] - if(bangdelay > previoustime): - self.worsttimes[currentChannel][msg.nick] = bangdelay - except: - self.worsttimes[currentChannel][msg.nick] = bangdelay - - - self.duck[currentChannel] = False - - # Reset the basetime for the waiting time before the next duck - self.lastSpoke[currentChannel] = time.time() - - if self.registryValue('ducks', currentChannel): - maxShoots = self.registryValue('ducks', currentChannel) + # Did the player missed it? + if (random.random() < self.missprobability[currentChannel]): + irc.reply("%s, you missed the duck!" % (msg.nick)) else: - maxShoots = 10 - # End of Hunt - if (self.shoots[currentChannel] == maxShoots): - self._end(irc, msg, args) + # Adds one point for the nick that shot the duck + try: + self.scores[currentChannel][msg.nick] += 1 + except: + try: + self.scores[currentChannel][msg.nick] = 1 + except: + self.scores[currentChannel] = {} + self.scores[currentChannel][msg.nick] = 1 - # If autorestart is enabled, we restart a hunt automatically! - if self.registryValue('autoRestart', currentChannel): - # This code shouldn't be here - self.started[currentChannel] = True - self._initthrottle(irc, msg, args, currentChannel) - if self.scores.get(currentChannel): - self.scores[currentChannel] = {} - self.averagetime[currentChannel] = 0 + irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) + + self.averagetime[currentChannel] += bangdelay + + # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) + try: + previoustime = self.toptimes[currentChannel][msg.nick] + if(bangdelay < previoustime): + self.toptimes[currentChannel][msg.nick] = bangdelay + except: + self.toptimes[currentChannel][msg.nick] = bangdelay + + + # Now save the bang delay for the player (if it's worst than it's previous bangdelay) + try: + previoustime = self.worsttimes[currentChannel][msg.nick] + if(bangdelay > previoustime): + self.worsttimes[currentChannel][msg.nick] = bangdelay + except: + self.worsttimes[currentChannel][msg.nick] = bangdelay + + + self.duck[currentChannel] = False + + # Reset the basetime for the waiting time before the next duck + self.lastSpoke[currentChannel] = time.time() + + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) + else: + maxShoots = 10 + + # End of Hunt + if (self.shoots[currentChannel] == maxShoots): + self._end(irc, msg, args) + + # If autorestart is enabled, we restart a hunt automatically! + if self.registryValue('autoRestart', currentChannel): + # This code shouldn't be here + self.started[currentChannel] = True + self._initthrottle(irc, msg, args, currentChannel) + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} + self.averagetime[currentChannel] = 0 # There was no duck or the duck has already been shot From e8426c21e260484f0241280d30f76ee64436e988 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 22 Sep 2012 12:16:16 +0200 Subject: [PATCH 49/67] README Update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3a3f442..e2cf557 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Several per-channel configuration variables are available (look at the "channel" * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) * kickMode: If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) * autoFriday: Do we need to automatically launch more ducks on friday? + * missProbability: The probability to miss the duck Update ------ From 3391200b69a32291ab795a9816f0f1e0459e2032 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 3 Oct 2012 12:35:46 +0200 Subject: [PATCH 50/67] Updates __init__ file --- __init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 0f7de5a..ca24579 100644 --- a/__init__.py +++ b/__init__.py @@ -40,14 +40,14 @@ import supybot.world as world __version__ = "" # XXX Replace this with an appropriate author or supybot.Author instance. -__author__ = supybot.authors.unknown +__author__ = supybot.Author('Matthias Meusburger', 'veggiematts', '') # This is a dictionary mapping supybot.Author instances to lists of # contributions. __contributors__ = {} # This is a url where the most recent plugin package can be downloaded. -__url__ = '' # 'http://supybot.com/Members/yourname/DuckHunt/download' +__url__ = 'https://github.com/veggiematts/supybot-duckhunt' import config import plugin From f51e6080337314c65487aa9029b257be0a1c5ebc Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 4 Oct 2012 23:13:39 +0200 Subject: [PATCH 51/67] Fix mix-up between automatic and manual FridayMode --- plugin.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/plugin.py b/plugin.py index 704dd53..5c5000b 100644 --- a/plugin.py +++ b/plugin.py @@ -63,7 +63,8 @@ class DuckHunt(callbacks.Plugin): worsttimes = {} # Worst times for the current hunt channelworsttimes = {} # Saved worst times for the channel averagetime = {} # Average shooting time for the current hunt - fridayMode = {} # Are we on friday mode? + fridayMode = {} # Are we on friday mode? (automatic) + manualFriday = {} # Are we on friday mode? (manual) missprobability = {} # Probability to miss a duck when shooting week = {} # Scores for the week channelweek = {} # Saved scores for the week @@ -249,7 +250,7 @@ class DuckHunt(callbacks.Plugin): self.missprobability[channel] = 0.2 - if self.fridayMode[channel] == False: + if self.fridayMode[channel] == False and self.manualFriday[channel] == False: # Init min throttle[currentChannel] and max throttle[currentChannel] if self.registryValue('minthrottle', channel): self.minthrottle[channel] = self.registryValue('minthrottle', channel) @@ -389,29 +390,29 @@ class DuckHunt(callbacks.Plugin): irc.error('You have to be on a channel') stop = wrap(stop) - def fridaymode(self, irc, msg, args, channel): + def fridaymode(self, irc, msg, args, channel, status): """ + [] Enable/disable friday mode! (there are lots of ducks on friday :)) """ if irc.isChannel(channel): - if (not self.fridayMode.get(channel)): - self.fridayMode[channel] = False - - if self.fridayMode[channel] == True: - self.fridayMode[channel] = False - irc.reply("Friday mode is now disabled.") - + if (status == 'status'): + irc.reply('Manual friday mode for ' + channel + ' is ' + str(self.manualFriday.get(channel))); else: - self.fridayMode[channel] = True - irc.reply("Friday mode is now enabled! Shoot alllllllllllll the ducks!") + if (self.manualFriday.get(channel) == None or self.manualFriday[channel] == False): + self.manualFriday[channel] = True + irc.reply("Friday mode is now enabled! Shoot alllllllllllll the ducks!") + else: + self.manualFriday[channel] = False + irc.reply("Friday mode is now disabled.") - self._initthrottle(irc, msg, args, channel) + self._initthrottle(irc, msg, args, channel) else: irc.error('You have to be on a channel') - fridaymode = wrap(fridaymode, ['channel', 'admin']) + fridaymode = wrap(fridaymode, ['channel', 'admin', optional('anything')]) def launched(self, irc, msg, args): """ From de566a0e1886f185310ba55edae71fb683e77504 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 4 Oct 2012 23:16:07 +0200 Subject: [PATCH 52/67] Fix manualFriday init --- plugin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugin.py b/plugin.py index 5c5000b..30fdf94 100644 --- a/plugin.py +++ b/plugin.py @@ -243,6 +243,9 @@ class DuckHunt(callbacks.Plugin): if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False + if (not self.manualFriday.get(channel)): + self.manualFriday[channel] = False + # Miss probability if self.registryValue('missProbability', channel): self.missprobability[channel] = self.registryValue('missProbability', channel) From 7dff65121f8e3975e49142d0da9755b0a6ef4231 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 5 Oct 2012 04:40:58 +0200 Subject: [PATCH 53/67] Documentation update --- doc/DuckHunt.html | 2 +- doc/DuckHunt.rst | 2 +- doc/DuckHunt.stx | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 98b531a..8248c30 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -334,7 +334,7 @@ when there is no duck launched costs a point.

dbg
This is a debug command. If debug mode is not enabled, it won't do anything
fridaymode
-
Enable/disable friday mode! (there are lots of ducks on friday :))
+
[<status>] Enable/disable friday mode! (there are lots of ducks on friday :))
launched
Is there a duck right now?
listscores
diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index e9294ae..e03a340 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -24,7 +24,7 @@ dbg This is a debug command. If debug mode is not enabled, it won't do anything fridaymode - Enable/disable friday mode! (there are lots of ducks on friday :)) + [] Enable/disable friday mode! (there are lots of ducks on friday :)) launched Is there a duck right now? diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index 384524f..d5ce89e 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -28,7 +28,8 @@ Documentation for the DuckHunt plugin for Supybot * fridaymode - Enable/disable friday mode! (there are lots of ducks on friday :)) + [] Enable/disable friday mode! (there are lots of ducks on friday + :)) * launched From f817f4b298418b8c3aed1eda37b3e31cb09919e5 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Fri, 5 Oct 2012 18:09:58 +0200 Subject: [PATCH 54/67] Fix fridaymode init --- plugin.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugin.py b/plugin.py index 30fdf94..c9ea413 100644 --- a/plugin.py +++ b/plugin.py @@ -234,18 +234,19 @@ class DuckHunt(callbacks.Plugin): self.leader[channel] = None # autoFriday? - if self.registryValue('autoFriday', channel): - if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: - self.fridayMode[channel] = True - else: - self.fridayMode[channel] = None - if (not self.fridayMode.get(channel)): self.fridayMode[channel] = False if (not self.manualFriday.get(channel)): self.manualFriday[channel] = False + + if self.registryValue('autoFriday', channel): + if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: + self.fridayMode[channel] = True + else: + self.fridayMode[channel] = False + # Miss probability if self.registryValue('missProbability', channel): self.missprobability[channel] = self.registryValue('missProbability', channel) @@ -402,6 +403,7 @@ class DuckHunt(callbacks.Plugin): if (status == 'status'): irc.reply('Manual friday mode for ' + channel + ' is ' + str(self.manualFriday.get(channel))); + irc.reply('Auto friday mode for ' + channel + ' is ' + str(self.fridayMode.get(channel))); else: if (self.manualFriday.get(channel) == None or self.manualFriday[channel] == False): self.manualFriday[channel] = True From 9341a0e34a352312b03eac620c9a490982b66f0f Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 10 Oct 2012 22:41:03 +0200 Subject: [PATCH 55/67] Adds reload time --- README.md | 1 + config.py | 3 +++ doc/DuckHunt.html | 4 ++++ doc/DuckHunt.rst | 5 +++++ doc/DuckHunt.stx | 6 ++++++ plugin.py | 26 +++++++++++++++++++++++++- 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e2cf557..b33a9d2 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Several per-channel configuration variables are available (look at the "channel" * ducks: Number of ducks during a hunt? * minthrottle: The minimum amount of time before a new duck may be launched (in seconds) * maxthrottle: The maximum amount of time before a new duck may be launched (in seconds) + * reloadTime: The time it takes to reload your rifle once you have shot (in seconds) * kickMode: If someone shoots when there is no duck, should he be kicked from the channel? (this requires the bot to be op on the channel) * autoFriday: Do we need to automatically launch more ducks on friday? * missProbability: The probability to miss the duck diff --git a/config.py b/config.py index d962264..8260b0e 100644 --- a/config.py +++ b/config.py @@ -55,6 +55,9 @@ conf.registerChannelValue(DuckHunt, 'minthrottle', conf.registerChannelValue(DuckHunt, 'maxthrottle', registry.Integer(300, """The maximum amount of time before a new duck may be launched (in seconds)""")) +conf.registerChannelValue(DuckHunt, 'reloadTime', + registry.Integer(5, """The time it takes to reload your rifle once you have shot (in seconds)""")) + conf.registerChannelValue(DuckHunt, 'missProbability', registry.Probability(0.2, """The probability to miss the duck""")) diff --git a/doc/DuckHunt.html b/doc/DuckHunt.html index 8248c30..950f756 100644 --- a/doc/DuckHunt.html +++ b/doc/DuckHunt.html @@ -391,6 +391,10 @@ If <nick> is provided, it will only show <nick>'s scores.

This config variable defaults to 300 and is channel specific.

The maximum amount of time before a new duck may be launched (in seconds)

+
supybot.plugins.DuckHunt.reloadTime
+

This config variable defaults to 5 and is channel specific.

+

The time it takes to reload your rifle once you have shot (in seconds)

+
supybot.plugins.DuckHunt.missProbability

This config variable defaults to 0.20000000000000001 and is channel specific.

The probability to miss the duck

diff --git a/doc/DuckHunt.rst b/doc/DuckHunt.rst index e03a340..7ea6c69 100644 --- a/doc/DuckHunt.rst +++ b/doc/DuckHunt.rst @@ -96,6 +96,11 @@ supybot.plugins.DuckHunt.maxthrottle The maximum amount of time before a new duck may be launched (in seconds) +supybot.plugins.DuckHunt.reloadTime + This config variable defaults to 5 and is channel specific. + + The time it takes to reload your rifle once you have shot (in seconds) + supybot.plugins.DuckHunt.missProbability This config variable defaults to 0.20000000000000001 and is channel specific. diff --git a/doc/DuckHunt.stx b/doc/DuckHunt.stx index d5ce89e..9f69f11 100644 --- a/doc/DuckHunt.stx +++ b/doc/DuckHunt.stx @@ -118,6 +118,12 @@ Documentation for the DuckHunt plugin for Supybot The maximum amount of time before a new duck may be launched (in seconds) + * supybot.plugins.DuckHunt.reloadTime + + This config variable defaults to 5 and is channel specific. + + The time it takes to reload your rifle once you have shot (in seconds) + * supybot.plugins.DuckHunt.missProbability This config variable defaults to 0.20000000000000001 and is channel diff --git a/plugin.py b/plugin.py index c9ea413..f4a996b 100644 --- a/plugin.py +++ b/plugin.py @@ -69,6 +69,8 @@ class DuckHunt(callbacks.Plugin): week = {} # Scores for the week channelweek = {} # Saved scores for the week leader = {} # Who is the leader for the week? + reloading = {} # Who is currently reloading? + reloadtime = {} # Time to reload after shooting (in seconds) # Does a duck needs to be launched? lastSpoke = {} @@ -133,7 +135,8 @@ class DuckHunt(callbacks.Plugin): # week scores for player in self.scores[channel].keys(): - if not player in self.channelweek[channel][self.woy].get(self.dow): + #FIXME: If the hunt starts a day and ends the day after, this will produce an error: + if not player in self.channelweek[channel][self.woy][self.dow]: # It's a new player self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] else: @@ -253,6 +256,11 @@ class DuckHunt(callbacks.Plugin): else: self.missprobability[channel] = 0.2 + # Reload time + if self.registryValue('reloadTime', channel): + self.reloadtime[channel] = self.registryValue('reloadTime', channel) + else: + self.reloadtime[channel] = 5 if self.fridayMode[channel] == False and self.manualFriday[channel] == False: # Init min throttle[currentChannel] and max throttle[currentChannel] @@ -322,6 +330,9 @@ class DuckHunt(callbacks.Plugin): if self.scores.get(currentChannel): self.scores[currentChannel] = {} + # Reinit reloading + self.reloading[currentChannel] = {} + # No duck launched self.duck[currentChannel] = False @@ -853,6 +864,16 @@ class DuckHunt(callbacks.Plugin): else: bangdelay = False + + # Is the player reloading? + if (self.reloading[currentChannel].get(msg.nick) and time.time() - self.reloading[currentChannel][msg.nick] < self.reloadtime[currentChannel]): + irc.reply("%s, you are reloading... (Reloading takes %i seconds)" % (msg.nick, self.reloadtime[currentChannel])) + return 0 + + + # This player is now reloading + self.reloading[currentChannel][msg.nick] = time.time(); + # There was a duck if (self.duck[currentChannel] == True): @@ -914,6 +935,9 @@ class DuckHunt(callbacks.Plugin): self._initthrottle(irc, msg, args, currentChannel) if self.scores.get(currentChannel): self.scores[currentChannel] = {} + if self.reloading.get(currentChannel): + self.reloading[currentChannel] = {} + self.averagetime[currentChannel] = 0 From 34243cf8109a83293aa674378c532502b0241616 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 11 Oct 2012 13:58:09 +0200 Subject: [PATCH 56/67] Fix day and weeks bug --- plugin.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plugin.py b/plugin.py index f4a996b..b6adbba 100644 --- a/plugin.py +++ b/plugin.py @@ -211,10 +211,9 @@ class DuckHunt(callbacks.Plugin): inputfile.close() - - def _initthrottle(self, irc, msg, args, channel): - self.dow = int(time.strftime("%u")) # Day of week + def _initdayweekyear(self, channel): + self.dow = int(time.strftime("%u")) # Day of week self.woy = int(time.strftime("%V")) # Week of year year = time.strftime("%Y") @@ -233,6 +232,11 @@ class DuckHunt(callbacks.Plugin): self.channelweek[channel][self.woy][self.dow] = {} + + def _initthrottle(self, irc, msg, args, channel): + + self._initdayweekyear(channel) + if not self.leader.get(channel): self.leader[channel] = None @@ -497,9 +501,7 @@ class DuckHunt(callbacks.Plugin): # Day scores try: - - self.dow = int(time.strftime("%u")) # Day of week - self.woy = int(time.strftime("%V")) # Week of year + self._initdayweekyear(channel) day = self.dow week = self.woy self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] @@ -609,8 +611,7 @@ class DuckHunt(callbacks.Plugin): if irc.isChannel(channel): self._read_scores(channel) - self.dow = int(time.strftime("%u")) # Day of week - self.woy = int(time.strftime("%V")) # Week of year + self._initdayweekyear(channel) day = self.dow week = self.woy From be0f1c629efaa2947e0123163d44e3f2c90f9f63 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Thu, 11 Oct 2012 17:34:34 +0200 Subject: [PATCH 57/67] Remove useless code Fix mergescores --- plugin.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugin.py b/plugin.py index b6adbba..a829b51 100644 --- a/plugin.py +++ b/plugin.py @@ -53,7 +53,6 @@ class DuckHunt(callbacks.Plugin): # Those parameters are per-channel parameters started = {} # Has the hunt started? duck = {} # Is there currently a duck to shoot? - banging = {} # Is there someone "banging" ;) right now? shoots = {} # Number of successfull shoots in a hunt scores = {} # Scores for the current hunt times = {} # Elapsed time since the last duck was launched @@ -343,9 +342,6 @@ class DuckHunt(callbacks.Plugin): # Hunt started self.started[currentChannel] = True - # Init banging - self.banging[currentChannel] = False - # Init shoots self.shoots[currentChannel] = 0 @@ -381,9 +377,7 @@ class DuckHunt(callbacks.Plugin): if(self.started.get(currentChannel) == True): if (self.duck[currentChannel] == False): if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: - # If someone is "banging" right now, do not launch a duck - if (not self.banging[currentChannel]): - self._launch(irc, msg, '') + self._launch(irc, msg, '') @@ -504,7 +498,12 @@ class DuckHunt(callbacks.Plugin): self._initdayweekyear(channel) day = self.dow week = self.woy - self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] + + try: + self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] + except: + self.channelweek[channel][week][day][nickto] = self.channelweek[channel][week][day][nickfrom] + del self.channelweek[channel][week][day][nickfrom] self._write_scores(channel) irc.reply("Day scores merged") @@ -854,7 +853,6 @@ class DuckHunt(callbacks.Plugin): Shoots the duck! """ currentChannel = msg.args[0] - self.banging[currentChannel] = True if irc.isChannel(currentChannel): if(self.started.get(currentChannel) == True): @@ -983,8 +981,6 @@ class DuckHunt(callbacks.Plugin): else: irc.error('You have to be on a channel') - self.banging[currentChannel] = False - bang = wrap(bang) From 800cad6b136a021a4fa17c20897b3efd0ba81882 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 20 Oct 2012 19:21:08 +0200 Subject: [PATCH 58/67] Fix autofriday --- plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index a829b51..7154c10 100644 --- a/plugin.py +++ b/plugin.py @@ -247,7 +247,7 @@ class DuckHunt(callbacks.Plugin): self.manualFriday[channel] = False - if self.registryValue('autoFriday', channel): + if self.registryValue('autoFriday', channel) == True: if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: self.fridayMode[channel] = True else: From d0992312b8d2bc0f52d5a3609ff6ee46903ece65 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Sat, 20 Oct 2012 19:23:15 +0200 Subject: [PATCH 59/67] Fix typo --- plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index 7154c10..0722bd9 100644 --- a/plugin.py +++ b/plugin.py @@ -992,7 +992,7 @@ class DuckHunt(callbacks.Plugin): currentChannel = msg.args[0] - # End the hunting + # End the hunt self.started[currentChannel] = False try: @@ -1154,7 +1154,7 @@ class DuckHunt(callbacks.Plugin): irc.reply("Already a duck") else: - irc.reply("The hunting has not started yet!") + irc.reply("The hunt has not started yet!") else: irc.error('You have to be on a channel') From 906961fddfa1a3aa5f8f4dc3d52dc2b8b38dad1f Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Mon, 23 Jan 2017 17:35:35 +0100 Subject: [PATCH 60/67] Reindent - 2to3 - Add "Don't pretend to be me!" --- __init__.py | 7 +- plugin.py | 1525 ++++++++++++++++++++++++++------------------------- 2 files changed, 773 insertions(+), 759 deletions(-) diff --git a/__init__.py b/__init__.py index ca24579..1d3b20c 100644 --- a/__init__.py +++ b/__init__.py @@ -34,6 +34,7 @@ This is a DuckHunt game for supybot import supybot import supybot.world as world +from imp import reload # Use this for the version of this plugin. You may wish to put a CVS keyword # in here if you're keeping the plugin in CVS or some similar system. @@ -49,14 +50,14 @@ __contributors__ = {} # This is a url where the most recent plugin package can be downloaded. __url__ = 'https://github.com/veggiematts/supybot-duckhunt' -import config -import plugin +from . import config +from . import plugin reload(plugin) # In case we're being reloaded. # Add more reloads here if you add third-party modules and want them to be # reloaded when this plugin is reloaded. Don't forget to import them as well! if world.testing: - import test + from . import test Class = plugin.Class configure = config.configure diff --git a/plugin.py b/plugin.py index 0722bd9..435d3dd 100644 --- a/plugin.py +++ b/plugin.py @@ -94,78 +94,78 @@ class DuckHunt(callbacks.Plugin): def _calc_scores(self, channel): - """ - Adds new scores and times to the already saved ones - """ + """ + Adds new scores and times to the already saved ones + """ - # scores - # Adding current scores to the channel scores - for player in self.scores[channel].keys(): - if not player in self.channelscores[channel]: - # It's a new player - self.channelscores[channel][player] = self.scores[channel][player] - else: - # It's a player that already has a saved score - self.channelscores[channel][player] += self.scores[channel][player] + # scores + # Adding current scores to the channel scores + for player in list(self.scores[channel].keys()): + if not player in self.channelscores[channel]: + # It's a new player + self.channelscores[channel][player] = self.scores[channel][player] + else: + # It's a player that already has a saved score + self.channelscores[channel][player] += self.scores[channel][player] - # times - # Adding times scores to the channel scores - for player in self.toptimes[channel].keys(): - if not player in self.channeltimes[channel]: - # It's a new player - self.channeltimes[channel][player] = self.toptimes[channel][player] - else: - # It's a player that already has a saved score - # And we save the time of the current hunt if it's better than it's previous time - if(self.toptimes[channel][player] < self.channeltimes[channel][player]): - self.channeltimes[channel][player] = self.toptimes[channel][player] + # times + # Adding times scores to the channel scores + for player in list(self.toptimes[channel].keys()): + if not player in self.channeltimes[channel]: + # It's a new player + self.channeltimes[channel][player] = self.toptimes[channel][player] + else: + # It's a player that already has a saved score + # And we save the time of the current hunt if it's better than it's previous time + if(self.toptimes[channel][player] < self.channeltimes[channel][player]): + self.channeltimes[channel][player] = self.toptimes[channel][player] - # worst times - # Adding worst times scores to the channel scores - for player in self.worsttimes[channel].keys(): - if not player in self.channelworsttimes[channel]: - # It's a new player - self.channelworsttimes[channel][player] = self.worsttimes[channel][player] - else: - # It's a player that already has a saved score - # And we save the time of the current hunt if it's worst than it's previous time - if(self.worsttimes[channel][player] > self.channelworsttimes[channel][player]): - self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + # worst times + # Adding worst times scores to the channel scores + for player in list(self.worsttimes[channel].keys()): + if not player in self.channelworsttimes[channel]: + # It's a new player + self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + else: + # It's a player that already has a saved score + # And we save the time of the current hunt if it's worst than it's previous time + if(self.worsttimes[channel][player] > self.channelworsttimes[channel][player]): + self.channelworsttimes[channel][player] = self.worsttimes[channel][player] - # week scores - for player in self.scores[channel].keys(): - #FIXME: If the hunt starts a day and ends the day after, this will produce an error: - if not player in self.channelweek[channel][self.woy][self.dow]: - # It's a new player - self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] - else: - # It's a player that already has a saved score - self.channelweek[channel][self.woy][self.dow][player] += self.scores[channel][player] + # week scores + for player in list(self.scores[channel].keys()): + #FIXME: If the hunt starts a day and ends the day after, this will produce an error: + if not player in self.channelweek[channel][self.woy][self.dow]: + # It's a new player + self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] + else: + # It's a player that already has a saved score + self.channelweek[channel][self.woy][self.dow][player] += self.scores[channel][player] def _write_scores(self, channel): - """ - Write scores and times to the disk - """ + """ + Write scores and times to the disk + """ - # scores + # scores outputfile = open(self.path.dirize(self.fileprefix + channel + ".scores"), "wb") pickle.dump(self.channelscores[channel], outputfile) outputfile.close() - # times + # times outputfile = open(self.path.dirize(self.fileprefix + channel + ".times"), "wb") pickle.dump(self.channeltimes[channel], outputfile) outputfile.close() - # worst times + # worst times outputfile = open(self.path.dirize(self.fileprefix + channel + ".worsttimes"), "wb") pickle.dump(self.channelworsttimes[channel], outputfile) outputfile.close() - # week scores + # week scores outputfile = open(self.path.dirize(self.fileprefix + channel + self.year + ".weekscores"), "wb") pickle.dump(self.channelweek[channel], outputfile) outputfile.close() @@ -177,111 +177,111 @@ class DuckHunt(callbacks.Plugin): def _read_scores(self, channel): - """ - Reads scores and times from disk - """ - filename = self.path.dirize(self.fileprefix + channel) - # scores - if not self.channelscores.get(channel): - if os.path.isfile(filename + ".scores"): - inputfile = open(filename + ".scores", "rb") - self.channelscores[channel] = pickle.load(inputfile) - inputfile.close() + """ + Reads scores and times from disk + """ + filename = self.path.dirize(self.fileprefix + channel) + # scores + if not self.channelscores.get(channel): + if os.path.isfile(filename + ".scores"): + inputfile = open(filename + ".scores", "rb") + self.channelscores[channel] = pickle.load(inputfile) + inputfile.close() - # times - if not self.channeltimes.get(channel): - if os.path.isfile(filename + ".times"): - inputfile = open(filename + ".times", "rb") - self.channeltimes[channel] = pickle.load(inputfile) - inputfile.close() + # times + if not self.channeltimes.get(channel): + if os.path.isfile(filename + ".times"): + inputfile = open(filename + ".times", "rb") + self.channeltimes[channel] = pickle.load(inputfile) + inputfile.close() - # worst times - if not self.channelworsttimes.get(channel): - if os.path.isfile(filename + ".worsttimes"): - inputfile = open(filename + ".worsttimes", "rb") - self.channelworsttimes[channel] = pickle.load(inputfile) - inputfile.close() + # worst times + if not self.channelworsttimes.get(channel): + if os.path.isfile(filename + ".worsttimes"): + inputfile = open(filename + ".worsttimes", "rb") + self.channelworsttimes[channel] = pickle.load(inputfile) + inputfile.close() - # week scores - if not self.channelweek.get(channel): - if os.path.isfile(filename + self.year + ".weekscores"): - inputfile = open(filename + self.year + ".weekscores", "rb") - self.channelweek[channel] = pickle.load(inputfile) - inputfile.close() + # week scores + if not self.channelweek.get(channel): + if os.path.isfile(filename + self.year + ".weekscores"): + inputfile = open(filename + self.year + ".weekscores", "rb") + self.channelweek[channel] = pickle.load(inputfile) + inputfile.close() def _initdayweekyear(self, channel): - self.dow = int(time.strftime("%u")) # Day of week - self.woy = int(time.strftime("%V")) # Week of year - year = time.strftime("%Y") + self.dow = int(time.strftime("%u")) # Day of week + self.woy = int(time.strftime("%V")) # Week of year + year = time.strftime("%Y") - # Init week scores - try: - self.channelweek[channel] - except: - self.channelweek[channel] = {} - try: - self.channelweek[channel][self.woy] - except: - self.channelweek[channel][self.woy] = {} - try: - self.channelweek[channel][self.woy][self.dow] - except: - self.channelweek[channel][self.woy][self.dow] = {} + # Init week scores + try: + self.channelweek[channel] + except: + self.channelweek[channel] = {} + try: + self.channelweek[channel][self.woy] + except: + self.channelweek[channel][self.woy] = {} + try: + self.channelweek[channel][self.woy][self.dow] + except: + self.channelweek[channel][self.woy][self.dow] = {} def _initthrottle(self, irc, msg, args, channel): - self._initdayweekyear(channel) - - if not self.leader.get(channel): - self.leader[channel] = None + self._initdayweekyear(channel) + + if not self.leader.get(channel): + self.leader[channel] = None - # autoFriday? - if (not self.fridayMode.get(channel)): - self.fridayMode[channel] = False + # autoFriday? + if (not self.fridayMode.get(channel)): + self.fridayMode[channel] = False - if (not self.manualFriday.get(channel)): - self.manualFriday[channel] = False + if (not self.manualFriday.get(channel)): + self.manualFriday[channel] = False - if self.registryValue('autoFriday', channel) == True: - if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: - self.fridayMode[channel] = True - else: - self.fridayMode[channel] = False + if self.registryValue('autoFriday', channel) == True: + if int(time.strftime("%w")) == 5 and int(time.strftime("%H")) > 8 and int(time.strftime("%H")) < 17: + self.fridayMode[channel] = True + else: + self.fridayMode[channel] = False - # Miss probability - if self.registryValue('missProbability', channel): - self.missprobability[channel] = self.registryValue('missProbability', channel) - else: - self.missprobability[channel] = 0.2 + # Miss probability + if self.registryValue('missProbability', channel): + self.missprobability[channel] = self.registryValue('missProbability', channel) + else: + self.missprobability[channel] = 0.2 - # Reload time - if self.registryValue('reloadTime', channel): - self.reloadtime[channel] = self.registryValue('reloadTime', channel) - else: - self.reloadtime[channel] = 5 + # Reload time + if self.registryValue('reloadTime', channel): + self.reloadtime[channel] = self.registryValue('reloadTime', channel) + else: + self.reloadtime[channel] = 5 - if self.fridayMode[channel] == False and self.manualFriday[channel] == False: - # Init min throttle[currentChannel] and max throttle[currentChannel] - if self.registryValue('minthrottle', channel): - self.minthrottle[channel] = self.registryValue('minthrottle', channel) - else: - self.minthrottle[channel] = 30 + if self.fridayMode[channel] == False and self.manualFriday[channel] == False: + # Init min throttle[currentChannel] and max throttle[currentChannel] + if self.registryValue('minthrottle', channel): + self.minthrottle[channel] = self.registryValue('minthrottle', channel) + else: + self.minthrottle[channel] = 30 - if self.registryValue('maxthrottle', channel): - self.maxthrottle[channel] = self.registryValue('maxthrottle', channel) - else: - self.maxthrottle[channel] = 300 + if self.registryValue('maxthrottle', channel): + self.maxthrottle[channel] = self.registryValue('maxthrottle', channel) + else: + self.maxthrottle[channel] = 300 - else: - self.minthrottle[channel] = 3 - self.maxthrottle[channel] = 60 + else: + self.minthrottle[channel] = 3 + self.maxthrottle[channel] = 60 - self.throttle[channel] = random.randint(self.minthrottle[channel], self.maxthrottle[channel]) + self.throttle[channel] = random.randint(self.minthrottle[channel], self.maxthrottle[channel]) def start(self, irc, msg, args): @@ -289,95 +289,95 @@ class DuckHunt(callbacks.Plugin): Starts the hunt """ - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): - if(self.started.get(currentChannel) == True): - irc.reply("There is already a hunt right now!") - else: + if(self.started.get(currentChannel) == True): + irc.reply("There is already a hunt right now!") + else: - # First of all, let's read the score if needed - self._read_scores(currentChannel) + # First of all, let's read the score if needed + self._read_scores(currentChannel) - self._initthrottle(irc, msg, args, currentChannel) + self._initthrottle(irc, msg, args, currentChannel) - # Init saved scores - try: - self.channelscores[currentChannel] - except: - self.channelscores[currentChannel] = {} + # Init saved scores + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} - # Init saved times - try: - self.channeltimes[currentChannel] - except: - self.channeltimes[currentChannel] = {} + # Init saved times + try: + self.channeltimes[currentChannel] + except: + self.channeltimes[currentChannel] = {} - # Init saved times - try: - self.channelworsttimes[currentChannel] - except: - self.channelworsttimes[currentChannel] = {} + # Init saved times + try: + self.channelworsttimes[currentChannel] + except: + self.channelworsttimes[currentChannel] = {} - # Init times - self.toptimes[currentChannel] = {} - self.worsttimes[currentChannel] = {} + # Init times + self.toptimes[currentChannel] = {} + self.worsttimes[currentChannel] = {} - # Init bangdelay - self.times[currentChannel] = False + # Init bangdelay + self.times[currentChannel] = False - # Init lastSpoke - self.lastSpoke[currentChannel] = time.time() + # Init lastSpoke + self.lastSpoke[currentChannel] = time.time() - # Reinit current hunt scores - if self.scores.get(currentChannel): - self.scores[currentChannel] = {} + # Reinit current hunt scores + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} - # Reinit reloading - self.reloading[currentChannel] = {} + # Reinit reloading + self.reloading[currentChannel] = {} - # No duck launched - self.duck[currentChannel] = False + # No duck launched + self.duck[currentChannel] = False - # Hunt started - self.started[currentChannel] = True + # Hunt started + self.started[currentChannel] = True - # Init shoots - self.shoots[currentChannel] = 0 + # Init shoots + self.shoots[currentChannel] = 0 - # Init averagetime - self.averagetime[currentChannel] = 0; + # Init averagetime + self.averagetime[currentChannel] = 0; - # Init schedule + # Init schedule - # First of all, stop the scheduler if it was still running - try: - schedule.removeEvent('DuckHunt_' + currentChannel) - except KeyError: - pass + # First of all, stop the scheduler if it was still running + try: + schedule.removeEvent('DuckHunt_' + currentChannel) + except KeyError: + pass - # Then restart it - def myEventCaller(): - self._launchEvent(irc, msg) - try: - schedule.addPeriodicEvent(myEventCaller, 5, 'DuckHunt_' + currentChannel, False) - except AssertionError: - pass + # Then restart it + def myEventCaller(): + self._launchEvent(irc, msg) + try: + schedule.addPeriodicEvent(myEventCaller, 5, 'DuckHunt_' + currentChannel, False) + except AssertionError: + pass - irc.reply("The hunt starts now!") - else: - irc.error('You have to be on a channel') + irc.reply("The hunt starts now!") + else: + irc.error('You have to be on a channel') start = wrap(start) def _launchEvent(self, irc, msg): - currentChannel = msg.args[0] - now = time.time() - if irc.isChannel(currentChannel): - if(self.started.get(currentChannel) == True): - if (self.duck[currentChannel] == False): - if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: - self._launch(irc, msg, '') + currentChannel = msg.args[0] + now = time.time() + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + if (self.duck[currentChannel] == False): + if now > self.lastSpoke[currentChannel] + self.throttle[currentChannel]: + self._launch(irc, msg, '') @@ -386,44 +386,44 @@ class DuckHunt(callbacks.Plugin): Stops the current hunt """ - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - if (self.started.get(currentChannel) == True): - self._end(irc, msg, args) + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + if (self.started.get(currentChannel) == True): + self._end(irc, msg, args) - # If someone uses the stop command, - # we stop the scheduler, even if autoRestart is enabled - try: - schedule.removeEvent('DuckHunt_' + currentChannel) - except KeyError: - irc.reply('Error: the spammer wasn\'t running! This is a bug.') - else: - irc.reply('Nothing to stop: there\'s no hunt right now.') - else: - irc.error('You have to be on a channel') + # If someone uses the stop command, + # we stop the scheduler, even if autoRestart is enabled + try: + schedule.removeEvent('DuckHunt_' + currentChannel) + except KeyError: + irc.reply('Error: the spammer wasn\'t running! This is a bug.') + else: + irc.reply('Nothing to stop: there\'s no hunt right now.') + else: + irc.error('You have to be on a channel') stop = wrap(stop) def fridaymode(self, irc, msg, args, channel, status): - """ - [] - Enable/disable friday mode! (there are lots of ducks on friday :)) - """ - if irc.isChannel(channel): + """ + [] + Enable/disable friday mode! (there are lots of ducks on friday :)) + """ + if irc.isChannel(channel): - if (status == 'status'): - irc.reply('Manual friday mode for ' + channel + ' is ' + str(self.manualFriday.get(channel))); - irc.reply('Auto friday mode for ' + channel + ' is ' + str(self.fridayMode.get(channel))); - else: - if (self.manualFriday.get(channel) == None or self.manualFriday[channel] == False): - self.manualFriday[channel] = True - irc.reply("Friday mode is now enabled! Shoot alllllllllllll the ducks!") - else: - self.manualFriday[channel] = False - irc.reply("Friday mode is now disabled.") + if (status == 'status'): + irc.reply('Manual friday mode for ' + channel + ' is ' + str(self.manualFriday.get(channel))); + irc.reply('Auto friday mode for ' + channel + ' is ' + str(self.fridayMode.get(channel))); + else: + if (self.manualFriday.get(channel) == None or self.manualFriday[channel] == False): + self.manualFriday[channel] = True + irc.reply("Friday mode is now enabled! Shoot alllllllllllll the ducks!") + else: + self.manualFriday[channel] = False + irc.reply("Friday mode is now disabled.") - self._initthrottle(irc, msg, args, channel) - else: - irc.error('You have to be on a channel') + self._initthrottle(irc, msg, args, channel) + else: + irc.error('You have to be on a channel') fridaymode = wrap(fridaymode, ['channel', 'admin', optional('anything')]) @@ -433,88 +433,88 @@ class DuckHunt(callbacks.Plugin): Is there a duck right now? """ - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - if(self.started.get(currentChannel) == True): - if(self.duck[currentChannel] == True): - irc.reply("There is currently a duck! You can shoot it with the 'bang' command") - else: - irc.reply("There is no duck right now! Wait for one to be launched!") - else: - irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") - else: - irc.error('You have to be on a channel') + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): + if(self.duck[currentChannel] == True): + irc.reply("There is currently a duck! You can shoot it with the 'bang' command") + else: + irc.reply("There is no duck right now! Wait for one to be launched!") + else: + irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") + else: + irc.error('You have to be on a channel') launched = wrap(launched) def score(self, irc, msg, args, nick): - """ - + """ + - Shows the score for a given nick - """ - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - self._read_scores(currentChannel) - try: - self.channelscores[currentChannel] - except: - self.channelscores[currentChannel] = {} + Shows the score for a given nick + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + self._read_scores(currentChannel) + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} - try: - irc.reply(self.channelscores[currentChannel][nick]) - except: - irc.reply("There is no score for %s on %s" % (nick, currentChannel)) - else: - irc.error('You have to be on a channel') + try: + irc.reply(self.channelscores[currentChannel][nick]) + except: + irc.reply("There is no score for %s on %s" % (nick, currentChannel)) + else: + irc.error('You have to be on a channel') score = wrap(score, ['nick']) def mergescores(self, irc, msg, args, channel, nickto, nickfrom): - """ - [] - - nickto gets the points of nickfrom and nickfrom is removed from the scorelist - """ - if irc.isChannel(channel): - self._read_scores(channel) + """ + [] + + nickto gets the points of nickfrom and nickfrom is removed from the scorelist + """ + if irc.isChannel(channel): + self._read_scores(channel) - # Total scores - try: - self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] - del self.channelscores[channel][nickfrom] - self._write_scores(channel) - irc.reply("Total scores merged") + # Total scores + try: + self.channelscores[channel][nickto] += self.channelscores[channel][nickfrom] + del self.channelscores[channel][nickfrom] + self._write_scores(channel) + irc.reply("Total scores merged") - except: - irc.error("Can't merge total scores") + except: + irc.error("Can't merge total scores") - # Day scores - try: - self._initdayweekyear(channel) - day = self.dow - week = self.woy + # Day scores + try: + self._initdayweekyear(channel) + day = self.dow + week = self.woy - try: - self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] - except: - self.channelweek[channel][week][day][nickto] = self.channelweek[channel][week][day][nickfrom] + try: + self.channelweek[channel][week][day][nickto] += self.channelweek[channel][week][day][nickfrom] + except: + self.channelweek[channel][week][day][nickto] = self.channelweek[channel][week][day][nickfrom] - del self.channelweek[channel][week][day][nickfrom] - self._write_scores(channel) - irc.reply("Day scores merged") + del self.channelweek[channel][week][day][nickfrom] + self._write_scores(channel) + irc.reply("Day scores merged") - except: - irc.error("Can't merge day scores") + except: + irc.error("Can't merge day scores") - else: - irc.error('You have to be on a channel') + else: + irc.error('You have to be on a channel') mergescores = wrap(mergescores, ['channel', 'nick', 'nick', 'admin']) @@ -522,35 +522,35 @@ class DuckHunt(callbacks.Plugin): def mergetimes(self, irc, msg, args, channel, nickto, nickfrom): - """ - [] - - nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. - """ - if irc.isChannel(channel): - try: - self._read_scores(channel) + """ + [] + + nickto gets the best time of nickfrom if nickfrom time is better than nickto time, and nickfrom is removed from the timelist. Also works with worst times. + """ + if irc.isChannel(channel): + try: + self._read_scores(channel) - # Merge best times - if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: - self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] - del self.channeltimes[channel][nickfrom] + # Merge best times + if self.channeltimes[channel][nickfrom] < self.channeltimes[channel][nickto]: + self.channeltimes[channel][nickto] = self.channeltimes[channel][nickfrom] + del self.channeltimes[channel][nickfrom] - # Merge worst times - if self.channelworsttimes[channel][nickfrom] > self.channelworsttimes[channel][nickto]: - self.channelworsttimes[channel][nickto] = self.channelworsttimes[channel][nickfrom] - del self.channelworsttimes[channel][nickfrom] + # Merge worst times + if self.channelworsttimes[channel][nickfrom] > self.channelworsttimes[channel][nickto]: + self.channelworsttimes[channel][nickto] = self.channelworsttimes[channel][nickfrom] + del self.channelworsttimes[channel][nickfrom] - self._write_scores(channel) + self._write_scores(channel) - irc.replySuccess() + irc.replySuccess() - except: - irc.replyError() + except: + irc.replyError() - else: - irc.error('You have to be on a channel') + else: + irc.error('You have to be on a channel') mergetimes = wrap(mergetimes, ['channel', 'nick', 'nick', 'admin']) @@ -558,42 +558,42 @@ class DuckHunt(callbacks.Plugin): def rmtime(self, irc, msg, args, channel, nick): - """ - [] - - Remove 's best time - """ - if irc.isChannel(channel): - self._read_scores(channel) - del self.channeltimes[channel][nick] - self._write_scores(channel) - irc.replySuccess() + """ + [] + + Remove 's best time + """ + if irc.isChannel(channel): + self._read_scores(channel) + del self.channeltimes[channel][nick] + self._write_scores(channel) + irc.replySuccess() - else: - irc.error('Are you sure ' + str(channel) + ' is a channel?') + else: + irc.error('Are you sure ' + str(channel) + ' is a channel?') rmtime = wrap(rmtime, ['channel', 'nick', 'admin']) def rmscore(self, irc, msg, args, channel, nick): - """ - [] - - Remove 's score - """ - if irc.isChannel(channel): - try: - self._read_scores(channel) - del self.channelscores[channel][nick] - self._write_scores(channel) - irc.replySuccess() + """ + [] + + Remove 's score + """ + if irc.isChannel(channel): + try: + self._read_scores(channel) + del self.channelscores[channel][nick] + self._write_scores(channel) + irc.replySuccess() - except: - irc.replyError() + except: + irc.replyError() - else: - irc.error('Are you sure this is a channel?') + else: + irc.error('Are you sure this is a channel?') rmscore = wrap(rmscore, ['channel', 'nick', 'admin']) @@ -602,248 +602,246 @@ class DuckHunt(callbacks.Plugin): def dayscores(self, irc, msg, args, channel): """ - [] - - Shows the score list of the day for . - """ + [] + + Shows the score list of the day for . + """ - if irc.isChannel(channel): + if irc.isChannel(channel): - self._read_scores(channel) - self._initdayweekyear(channel) - day = self.dow - week = self.woy + self._read_scores(channel) + self._initdayweekyear(channel) + day = self.dow + week = self.woy - if self.channelweek.get(channel): - if self.channelweek[channel].get(week): - if self.channelweek[channel][week].get(day): - # Getting all scores, to get the winner of the week - msgstring = '' - scores = sorted(self.channelweek[channel][week][day].iteritems(), key=lambda (k,v):(v,k), reverse=True) - for item in scores: - msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " + if self.channelweek.get(channel): + if self.channelweek[channel].get(week): + if self.channelweek[channel][week].get(day): + # Getting all scores, to get the winner of the week + msgstring = '' + scores = sorted(iter(self.channelweek[channel][week][day].items()), key=lambda k_v2:(k_v2[1],k_v2[0]), reverse=True) + for item in scores: + msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " - if msgstring != "": - irc.reply("Scores for today: " + msgstring) - else: - irc.reply("There aren't any day scores for today yet.") - else: - irc.reply("There aren't any day scores for today yet.") - else: - irc.reply("There aren't any day scores for today yet.") - else: - irc.reply("There aren't any day scores for this channel yet.") - else: - irc.reply("Are you sure this is a channel?") + if msgstring != "": + irc.reply("Scores for today: " + msgstring) + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for today yet.") + else: + irc.reply("There aren't any day scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") dayscores = wrap(dayscores, ['channel']) def weekscores(self, irc, msg, args, week, nick, channel): """ - [] [] [] - - Shows the score list of the week for . If is provided, it will only show 's scores. - """ + [] [] [] + + Shows the score list of the week for . If is provided, it will only show 's scores. + """ - if irc.isChannel(channel): + if irc.isChannel(channel): - self._read_scores(channel) - weekscores = {} + self._read_scores(channel) + weekscores = {} - if (not week): - week = self.woy + if (not week): + week = self.woy - if self.channelweek.get(channel): - if self.channelweek[channel].get(week): - # Showing the winner for each day - if not nick: - msgstring = '' - # for each day of week - for i in (1,2,3,4,5,6,7): - if self.channelweek[channel][week].get(i): - # Getting winner of the day - winnernick, winnerscore = max(self.channelweek[channel][week][i].iteritems(), key=lambda (k,v):(v,k)) - msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " + if self.channelweek.get(channel): + if self.channelweek[channel].get(week): + # Showing the winner for each day + if not nick: + msgstring = '' + # for each day of week + for i in (1,2,3,4,5,6,7): + if self.channelweek[channel][week].get(i): + # Getting winner of the day + winnernick, winnerscore = max(iter(self.channelweek[channel][week][i].items()), key=lambda k_v:(k_v[1],k_v[0])) + msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " - # Getting all scores, to get the winner of the week - for player in self.channelweek[channel][week][i].keys(): - try: - weekscores[player] += self.channelweek[channel][week][i][player] - except: - weekscores[player] = self.channelweek[channel][week][i][player] - + # Getting all scores, to get the winner of the week + for player in list(self.channelweek[channel][week][i].keys()): + try: + weekscores[player] += self.channelweek[channel][week][i][player] + except: + weekscores[player] = self.channelweek[channel][week][i][player] + + + if msgstring != "": + irc.reply("Scores for week " + str(week) + ": " + msgstring) + # Who's the winner at this point? + winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v1:(k_v1[1],k_v1[0])) + irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) + + else: + irc.reply("There aren't any week scores for this week yet.") + else: + # Showing the scores of + msgstring = '' + total = 0 + for i in (1,2,3,4,5,6,7): + if self.channelweek[channel][week].get(i): + if self.channelweek[channel][week][i].get(nick): + msgstring += self.dayname[i - 1] + ": "+ str(self.channelweek[channel][week][i].get(nick)) + " | " + total += self.channelweek[channel][week][i].get(nick) + + if msgstring != "": + irc.reply(nick + " scores for week " + str(self.woy) + ": " + msgstring) + irc.reply("Total: " + str(total) + " points.") + else: + irc.reply("There aren't any week scores for this nick.") - if msgstring != "": - irc.reply("Scores for week " + str(week) + ": " + msgstring) - # Who's the winner at this point? - winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) - irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) - - else: - irc.reply("There aren't any week scores for this week yet.") - else: - # Showing the scores of - msgstring = '' - total = 0 - for i in (1,2,3,4,5,6,7): - if self.channelweek[channel][week].get(i): - if self.channelweek[channel][week][i].get(nick): - msgstring += self.dayname[i - 1] + ": "+ str(self.channelweek[channel][week][i].get(nick)) + " | " - total += self.channelweek[channel][week][i].get(nick) - - if msgstring != "": - irc.reply(nick + " scores for week " + str(self.woy) + ": " + msgstring) - irc.reply("Total: " + str(total) + " points.") - else: - irc.reply("There aren't any week scores for this nick.") - - - else: - irc.reply("There aren't any week scores for this week yet.") - else: - irc.reply("There aren't any week scores for this channel yet.") - else: - irc.reply("Are you sure this is a channel?") + else: + irc.reply("There aren't any week scores for this week yet.") + else: + irc.reply("There aren't any week scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") weekscores = wrap(weekscores, [optional('int'), optional('nick'), 'channel']) def listscores(self, irc, msg, args, size, channel): """ - [] [] - - Shows the -sized score list for (or for the current channel if no channel is given) - """ + [] [] + + Shows the -sized score list for (or for the current channel if no channel is given) + """ - if irc.isChannel(channel): - try: - self.channelscores[channel] - except: - self.channelscores[channel] = {} + if irc.isChannel(channel): + try: + self.channelscores[channel] + except: + self.channelscores[channel] = {} - self._read_scores(channel) + self._read_scores(channel) - # How many results do we display? - if (not size): - listsize = self.toplist - else: - listsize = size + # How many results do we display? + if (not size): + listsize = self.toplist + else: + listsize = size - # Sort the scores (reversed: the higher the better) - scores = sorted(self.channelscores[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) - del scores[listsize:] + # Sort the scores (reversed: the higher the better) + scores = sorted(iter(self.channelscores[channel].items()), key=lambda k_v9:(k_v9[1],k_v9[0]), reverse=True) + del scores[listsize:] - msgstring = "" - for item in scores: - # Why do we show the nicks as xnickx? - # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list - msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " scores for " + channel + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any scores for this channel yet.") - else: - irc.reply("Are you sure this is a channel?") + msgstring = "" + for item in scores: + # Why do we show the nicks as xnickx? + # Just to prevent everyone that has ever played a hunt in the channel to be pinged every time anyone asks for the score list + msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " scores for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any scores for this channel yet.") + else: + irc.reply("Are you sure this is a channel?") listscores = wrap(listscores, [optional('int'), 'channel']) def total(self, irc, msg, args, channel): - """ - Shows the total amount of ducks shot in (or in the current channel if no channel is given) - """ + """ + Shows the total amount of ducks shot in (or in the current channel if no channel is given) + """ - if irc.isChannel(channel): - self._read_scores(channel) - if (self.channelscores.get(channel)): - scores = self.channelscores[channel] - total = 0 - for player in scores.keys(): - total += scores[player] - irc.reply(str(total) + " ducks have been shot in " + channel + "!") - else: - irc.reply("There are no scores for this channel yet") + if irc.isChannel(channel): + self._read_scores(channel) + if (self.channelscores.get(channel)): + scores = self.channelscores[channel] + total = 0 + for player in list(scores.keys()): + total += scores[player] + irc.reply(str(total) + " ducks have been shot in " + channel + "!") + else: + irc.reply("There are no scores for this channel yet") - else: - irc.reply("Are you sure this is a channel?") + else: + irc.reply("Are you sure this is a channel?") total = wrap(total, ['channel']) def listtimes(self, irc, msg, args, size, channel): """ - [] [] - - Shows the -sized time list for (or for the current channel if no channel is given) - """ + [] [] + + Shows the -sized time list for (or for the current channel if no channel is given) + """ - if irc.isChannel(channel): - self._read_scores(channel) + if irc.isChannel(channel): + self._read_scores(channel) - try: - self.channeltimes[channel] - except: - self.channeltimes[channel] = {} + try: + self.channeltimes[channel] + except: + self.channeltimes[channel] = {} - try: - self.channelworsttimes[channel] - except: - self.channelworsttimes[channel] = {} + try: + self.channelworsttimes[channel] + except: + self.channelworsttimes[channel] = {} - # How many results do we display? - if (not size): - listsize = self.toplist - else: - listsize = size + # How many results do we display? + if (not size): + listsize = self.toplist + else: + listsize = size - # Sort the times (not reversed: the lower the better) - times = sorted(self.channeltimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=False) - del times[listsize:] + # Sort the times (not reversed: the lower the better) + times = sorted(iter(self.channeltimes[channel].items()), key=lambda k_v10:(k_v10[1],k_v10[0]), reverse=False) + del times[listsize:] - msgstring = "" - for item in times: - # Same as in listscores for the xnickx - msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + " | " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any best times for this channel yet.") + msgstring = "" + for item in times: + # Same as in listscores for the xnickx + msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + " | " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any best times for this channel yet.") - times = sorted(self.channelworsttimes[channel].iteritems(), key=lambda (k,v):(v,k), reverse=True) - del times[listsize:] + times = sorted(iter(self.channelworsttimes[channel].items()), key=lambda k_v11:(k_v11[1],k_v11[0]), reverse=True) + del times[listsize:] - msgstring = "" - for item in times: - # Same as in listscores for the xnickx - #msgstring += "x" + item[0] + "x: "+ time.strftime('%H:%M:%S', time.gmtime(item[1])) + ", " - roundseconds = round(item[1]) - delta = datetime.timedelta(seconds=roundseconds) - msgstring += "x" + item[0] + "x: " + str(delta) + " | " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " longest times for " + channel + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any longest times for this channel yet.") + msgstring = "" + for item in times: + # Same as in listscores for the xnickx + #msgstring += "x" + item[0] + "x: "+ time.strftime('%H:%M:%S', time.gmtime(item[1])) + ", " + roundseconds = round(item[1]) + delta = datetime.timedelta(seconds=roundseconds) + msgstring += "x" + item[0] + "x: " + str(delta) + " | " + if msgstring != "": + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " longest times for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any longest times for this channel yet.") - - else: - irc.reply("Are you sure this is a channel?") + else: + irc.reply("Are you sure this is a channel?") listtimes = wrap(listtimes, [optional('int'), 'channel']) def dbg(self, irc, msg, args): - """ - This is a debug command. If debug mode is not enabled, it won't do anything - """ - currentChannel = msg.args[0] - if (self.debug): - if irc.isChannel(currentChannel): - self._launch(irc, msg, '') + """ + This is a debug command. If debug mode is not enabled, it won't do anything + """ + currentChannel = msg.args[0] + if (self.debug): + if irc.isChannel(currentChannel): + self._launch(irc, msg, '') dbg = wrap(dbg) @@ -854,309 +852,324 @@ class DuckHunt(callbacks.Plugin): """ currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - if(self.started.get(currentChannel) == True): + if irc.isChannel(currentChannel): + if(self.started.get(currentChannel) == True): - # bangdelay: how much time between the duck was launched and this shot? - if self.times[currentChannel]: - bangdelay = time.time() - self.times[currentChannel] - else: - bangdelay = False + # bangdelay: how much time between the duck was launched and this shot? + if self.times[currentChannel]: + bangdelay = time.time() - self.times[currentChannel] + else: + bangdelay = False - # Is the player reloading? - if (self.reloading[currentChannel].get(msg.nick) and time.time() - self.reloading[currentChannel][msg.nick] < self.reloadtime[currentChannel]): - irc.reply("%s, you are reloading... (Reloading takes %i seconds)" % (msg.nick, self.reloadtime[currentChannel])) - return 0 - + # Is the player reloading? + if (self.reloading[currentChannel].get(msg.nick) and time.time() - self.reloading[currentChannel][msg.nick] < self.reloadtime[currentChannel]): + irc.reply("%s, you are reloading... (Reloading takes %i seconds)" % (msg.nick, self.reloadtime[currentChannel])) + return 0 + - # This player is now reloading - self.reloading[currentChannel][msg.nick] = time.time(); + # This player is now reloading + self.reloading[currentChannel][msg.nick] = time.time(); - # There was a duck - if (self.duck[currentChannel] == True): + # There was a duck + if (self.duck[currentChannel] == True): - # Did the player missed it? - if (random.random() < self.missprobability[currentChannel]): - irc.reply("%s, you missed the duck!" % (msg.nick)) - else: + # Did the player missed it? + if (random.random() < self.missprobability[currentChannel]): + irc.reply("%s, you missed the duck!" % (msg.nick)) + else: - # Adds one point for the nick that shot the duck - try: - self.scores[currentChannel][msg.nick] += 1 - except: - try: - self.scores[currentChannel][msg.nick] = 1 - except: - self.scores[currentChannel] = {} - self.scores[currentChannel][msg.nick] = 1 + # Adds one point for the nick that shot the duck + try: + self.scores[currentChannel][msg.nick] += 1 + except: + try: + self.scores[currentChannel][msg.nick] = 1 + except: + self.scores[currentChannel] = {} + self.scores[currentChannel][msg.nick] = 1 - irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) + irc.reply("\_x< %s: %i (%.2f seconds)" % (msg.nick, self.scores[currentChannel][msg.nick], bangdelay)) - self.averagetime[currentChannel] += bangdelay + self.averagetime[currentChannel] += bangdelay - # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) - try: - previoustime = self.toptimes[currentChannel][msg.nick] - if(bangdelay < previoustime): - self.toptimes[currentChannel][msg.nick] = bangdelay - except: - self.toptimes[currentChannel][msg.nick] = bangdelay + # Now save the bang delay for the player (if it's quicker than it's previous bangdelay) + try: + previoustime = self.toptimes[currentChannel][msg.nick] + if(bangdelay < previoustime): + self.toptimes[currentChannel][msg.nick] = bangdelay + except: + self.toptimes[currentChannel][msg.nick] = bangdelay - # Now save the bang delay for the player (if it's worst than it's previous bangdelay) - try: - previoustime = self.worsttimes[currentChannel][msg.nick] - if(bangdelay > previoustime): - self.worsttimes[currentChannel][msg.nick] = bangdelay - except: - self.worsttimes[currentChannel][msg.nick] = bangdelay + # Now save the bang delay for the player (if it's worst than it's previous bangdelay) + try: + previoustime = self.worsttimes[currentChannel][msg.nick] + if(bangdelay > previoustime): + self.worsttimes[currentChannel][msg.nick] = bangdelay + except: + self.worsttimes[currentChannel][msg.nick] = bangdelay - self.duck[currentChannel] = False + self.duck[currentChannel] = False - # Reset the basetime for the waiting time before the next duck - self.lastSpoke[currentChannel] = time.time() + # Reset the basetime for the waiting time before the next duck + self.lastSpoke[currentChannel] = time.time() - if self.registryValue('ducks', currentChannel): - maxShoots = self.registryValue('ducks', currentChannel) - else: - maxShoots = 10 + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) + else: + maxShoots = 10 - # End of Hunt - if (self.shoots[currentChannel] == maxShoots): - self._end(irc, msg, args) + # End of Hunt + if (self.shoots[currentChannel] == maxShoots): + self._end(irc, msg, args) - # If autorestart is enabled, we restart a hunt automatically! - if self.registryValue('autoRestart', currentChannel): - # This code shouldn't be here - self.started[currentChannel] = True - self._initthrottle(irc, msg, args, currentChannel) - if self.scores.get(currentChannel): - self.scores[currentChannel] = {} - if self.reloading.get(currentChannel): - self.reloading[currentChannel] = {} + # If autorestart is enabled, we restart a hunt automatically! + if self.registryValue('autoRestart', currentChannel): + # This code shouldn't be here + self.started[currentChannel] = True + self._initthrottle(irc, msg, args, currentChannel) + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} + if self.reloading.get(currentChannel): + self.reloading[currentChannel] = {} - self.averagetime[currentChannel] = 0 + self.averagetime[currentChannel] = 0 - # There was no duck or the duck has already been shot - else: + # There was no duck or the duck has already been shot + else: - # Removes one point for the nick that shot - try: - self.scores[currentChannel][msg.nick] -= 1 - except: - try: - self.scores[currentChannel][msg.nick] = -1 - except: - self.scores[currentChannel] = {} - self.scores[currentChannel][msg.nick] = -1 + # Removes one point for the nick that shot + try: + self.scores[currentChannel][msg.nick] -= 1 + except: + try: + self.scores[currentChannel][msg.nick] = -1 + except: + self.scores[currentChannel] = {} + self.scores[currentChannel][msg.nick] = -1 - # Base message - message = 'There was no duck!' + # Base message + message = 'There was no duck!' - # Adding additional message if kick - if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: - message += ' You just shot yourself!' + # Adding additional message if kick + if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: + message += ' You just shot yourself!' - # Adding nick and score - message += " %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick]) + # Adding nick and score + message += " %s: %i" % (msg.nick, self.scores[currentChannel][msg.nick]) - # If we were able to have a bangdelay (ie: a duck was launched before someone did bang) - if (bangdelay): - # Adding time - message += " (" + str(round(bangdelay,2)) + " seconds)" + # If we were able to have a bangdelay (ie: a duck was launched before someone did bang) + if (bangdelay): + # Adding time + message += " (" + str(round(bangdelay,2)) + " seconds)" - # If kickMode is enabled for this channel, and the bot have op capability, let's kick! - if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: - irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, message)) - else: - # Else, just say it - irc.reply(message) + # If kickMode is enabled for this channel, and the bot have op capability, let's kick! + if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: + irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, message)) + else: + # Else, just say it + irc.reply(message) - else: - irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") - else: - irc.error('You have to be on a channel') + else: + irc.reply("There is no hunt right now! You can start a hunt with the 'start' command") + else: + irc.error('You have to be on a channel') bang = wrap(bang) + def doPrivmsg(self, irc, msg): + currentChannel = msg.args[0] + if irc.isChannel(msg.args[0]): + if (msg.args[1] == '\_o< quack!'): + message = msg.nick + ", don't pretend to be me!"; + # If kickMode is enabled for this channel, and the bot have op capability, let's kick! + if self.registryValue('kickMode', currentChannel) and irc.nick in irc.state.channels[currentChannel].ops: + irc.queueMsg(ircmsgs.kick(currentChannel, msg.nick, message)) + else: + # Else, just say it + irc.reply(message) + + + def _end(self, irc, msg, args): - """ - End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) - """ + """ + End of the hunt (is called when the hunts stop "naturally" or when someone uses the !stop command) + """ - currentChannel = msg.args[0] + currentChannel = msg.args[0] - # End the hunt - self.started[currentChannel] = False + # End the hunt + self.started[currentChannel] = False - try: - self.channelscores[currentChannel] - except: - self.channelscores[currentChannel] = {} + try: + self.channelscores[currentChannel] + except: + self.channelscores[currentChannel] = {} - if not self.registryValue('autoRestart', currentChannel): - irc.reply("The hunt stops now!") + if not self.registryValue('autoRestart', currentChannel): + irc.reply("The hunt stops now!") - # Showing scores - if (self.scores.get(currentChannel)): + # Showing scores + if (self.scores.get(currentChannel)): - # Getting winner - winnernick, winnerscore = max(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) - if self.registryValue('ducks', currentChannel): - maxShoots = self.registryValue('ducks', currentChannel) - else: - maxShoots = 10 + # Getting winner + winnernick, winnerscore = max(iter(self.scores.get(currentChannel).items()), key=lambda k_v12:(k_v12[1],k_v12[0])) + if self.registryValue('ducks', currentChannel): + maxShoots = self.registryValue('ducks', currentChannel) + else: + maxShoots = 10 - # Is there a perfect? - if (winnerscore == maxShoots): - irc.reply("\o/ %s: %i ducks out of %i: perfect!!! +%i \o/" % (winnernick, winnerscore, maxShoots, self.perfectbonus)) - self.scores[currentChannel][winnernick] += self.perfectbonus - else: - # Showing scores - #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) - #irc.reply(self.scores.get(currentChannel)) - #TODO: Better display - irc.reply(sorted(self.scores.get(currentChannel).iteritems(), key=lambda (k,v):(v,k), reverse=True)) + # Is there a perfect? + if (winnerscore == maxShoots): + irc.reply("\o/ %s: %i ducks out of %i: perfect!!! +%i \o/" % (winnernick, winnerscore, maxShoots, self.perfectbonus)) + self.scores[currentChannel][winnernick] += self.perfectbonus + else: + # Showing scores + #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) + #irc.reply(self.scores.get(currentChannel)) + #TODO: Better display + irc.reply(sorted(iter(self.scores.get(currentChannel).items()), key=lambda k_v4:(k_v4[1],k_v4[0]), reverse=True)) - # Getting channel best time (to see if the best time of this hunt is better) - channelbestnick = None - channelbesttime = None - if self.channeltimes.get(currentChannel): - channelbestnick, channelbesttime = min(self.channeltimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + # Getting channel best time (to see if the best time of this hunt is better) + channelbestnick = None + channelbesttime = None + if self.channeltimes.get(currentChannel): + channelbestnick, channelbesttime = min(iter(self.channeltimes.get(currentChannel).items()), key=lambda k_v5:(k_v5[1],k_v5[0])) - # Showing best time - recordmsg = '' - if (self.toptimes.get(currentChannel)): - key,value = min(self.toptimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) - if (channelbesttime and value < channelbesttime): - recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' - else: - try: - if(value < self.channeltimes[currentChannel][key]): - recordmsg = ' (this is your new record in this channel! Your previous record was ' + str(round(self.channeltimes[currentChannel][key],2)) + ')' - except: - recordmsg = '' + # Showing best time + recordmsg = '' + if (self.toptimes.get(currentChannel)): + key,value = min(iter(self.toptimes.get(currentChannel).items()), key=lambda k_v6:(k_v6[1],k_v6[0])) + if (channelbesttime and value < channelbesttime): + recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' + else: + try: + if(value < self.channeltimes[currentChannel][key]): + recordmsg = ' (this is your new record in this channel! Your previous record was ' + str(round(self.channeltimes[currentChannel][key],2)) + ')' + except: + recordmsg = '' - irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) + irc.reply("Best time: %s with %.2f seconds%s" % (key, value, recordmsg)) - # Getting channel worst time (to see if the worst time of this hunt is worst) - channelworstnick = None - channelworsttime = None - if self.channelworsttimes.get(currentChannel): - channelworstnick, channelworsttime = max(self.channelworsttimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) + # Getting channel worst time (to see if the worst time of this hunt is worst) + channelworstnick = None + channelworsttime = None + if self.channelworsttimes.get(currentChannel): + channelworstnick, channelworsttime = max(iter(self.channelworsttimes.get(currentChannel).items()), key=lambda k_v7:(k_v7[1],k_v7[0])) - # Showing worst time - recordmsg = '' - if (self.worsttimes.get(currentChannel)): - key,value = max(self.worsttimes.get(currentChannel).iteritems(), key=lambda (k,v):(v,k)) - if (channelworsttime and value > channelworsttime): - recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' - else: - try: - if(value > self.channelworsttimes[currentChannel][key]): - recordmsg = ' (this is your new longest time in this channel! Your previous longest time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' - except: - recordmsg = '' + # Showing worst time + recordmsg = '' + if (self.worsttimes.get(currentChannel)): + key,value = max(iter(self.worsttimes.get(currentChannel).items()), key=lambda k_v8:(k_v8[1],k_v8[0])) + if (channelworsttime and value > channelworsttime): + recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' + else: + try: + if(value > self.channelworsttimes[currentChannel][key]): + recordmsg = ' (this is your new longest time in this channel! Your previous longest time was ' + str(round(self.channelworsttimes[currentChannel][key],2)) + ')' + except: + recordmsg = '' - # Only display worst time if something new - if (recordmsg != ''): - irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) + # Only display worst time if something new + if (recordmsg != ''): + irc.reply("Longest time: %s with %.2f seconds%s" % (key, value, recordmsg)) - # Showing average shooting time: - #if (self.shoots[currentChannel] > 1): - #irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) + # Showing average shooting time: + #if (self.shoots[currentChannel] > 1): + #irc.reply("Average shooting time: %.2f seconds" % ((self.averagetime[currentChannel] / self.shoots[currentChannel]))) - # Write the scores and times to disk - self._calc_scores(currentChannel) - self._write_scores(currentChannel) + # Write the scores and times to disk + self._calc_scores(currentChannel) + self._write_scores(currentChannel) - # Did someone took the lead? - weekscores = {} - if self.channelweek.get(currentChannel): - if self.channelweek[currentChannel].get(self.woy): - msgstring = '' - # for each day of week - for i in (1,2,3,4,5,6,7): - if self.channelweek[currentChannel][self.woy].get(i): - # Getting all scores, to get the winner of the week - for player in self.channelweek[currentChannel][self.woy][i].keys(): - try: - weekscores[player] += self.channelweek[currentChannel][self.woy][i][player] - except: - weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] - winnernick, winnerscore = max(weekscores.iteritems(), key=lambda (k,v):(v,k)) - if (winnernick != self.leader[currentChannel]): - if self.leader[currentChannel] != None: - irc.reply("%s took the lead for the week over %s with %i points." % (winnernick, self.leader[currentChannel], winnerscore)) - else: - irc.reply("%s has the lead for the week with %i points." % (winnernick, winnerscore)) - self.leader[currentChannel] = winnernick + # Did someone took the lead? + weekscores = {} + if self.channelweek.get(currentChannel): + if self.channelweek[currentChannel].get(self.woy): + msgstring = '' + # for each day of week + for i in (1,2,3,4,5,6,7): + if self.channelweek[currentChannel][self.woy].get(i): + # Getting all scores, to get the winner of the week + for player in list(self.channelweek[currentChannel][self.woy][i].keys()): + try: + weekscores[player] += self.channelweek[currentChannel][self.woy][i][player] + except: + weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] + + winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v3:(k_v3[1],k_v3[0])) + if (winnernick != self.leader[currentChannel]): + if self.leader[currentChannel] != None: + irc.reply("%s took the lead for the week over %s with %i points." % (winnernick, self.leader[currentChannel], winnerscore)) + else: + irc.reply("%s has the lead for the week with %i points." % (winnernick, winnerscore)) + self.leader[currentChannel] = winnernick - else: - irc.reply("Not a single duck was shot during this hunt!") + else: + irc.reply("Not a single duck was shot during this hunt!") - # Reinit current hunt scores - if self.scores.get(currentChannel): - self.scores[currentChannel] = {} + # Reinit current hunt scores + if self.scores.get(currentChannel): + self.scores[currentChannel] = {} - # Reinit current hunt times - if self.toptimes.get(currentChannel): - self.toptimes[currentChannel] = {} - if self.worsttimes.get(currentChannel): - self.worsttimes[currentChannel] = {} + # Reinit current hunt times + if self.toptimes.get(currentChannel): + self.toptimes[currentChannel] = {} + if self.worsttimes.get(currentChannel): + self.worsttimes[currentChannel] = {} - # No duck lauched - self.duck[currentChannel] = False + # No duck lauched + self.duck[currentChannel] = False - # Reinit number of shoots - self.shoots[currentChannel] = 0 + # Reinit number of shoots + self.shoots[currentChannel] = 0 def _launch(self, irc, msg, args): - """ - Launch a duck - """ - currentChannel = msg.args[0] - if irc.isChannel(currentChannel): - if(self.started[currentChannel] == True): - if (self.duck[currentChannel] == False): + """ + Launch a duck + """ + currentChannel = msg.args[0] + if irc.isChannel(currentChannel): + if(self.started[currentChannel] == True): + if (self.duck[currentChannel] == False): - # Store the time when the duck has been launched - self.times[currentChannel] = time.time() + # Store the time when the duck has been launched + self.times[currentChannel] = time.time() - # Store the fact that there's a duck now - self.duck[currentChannel] = True + # Store the fact that there's a duck now + self.duck[currentChannel] = True - # Send message directly (instead of queuing it with irc.reply) - irc.sendMsg(ircmsgs.privmsg(currentChannel, "\_o< quack!")) + # Send message directly (instead of queuing it with irc.reply) + irc.sendMsg(ircmsgs.privmsg(currentChannel, "\_o< quack!")) - # Define a new throttle[currentChannel] for the next launch - self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) + # Define a new throttle[currentChannel] for the next launch + self.throttle[currentChannel] = random.randint(self.minthrottle[currentChannel], self.maxthrottle[currentChannel]) - try: - self.shoots[currentChannel] += 1 - except: - self.shoots[currentChannel] = 1 - else: + try: + self.shoots[currentChannel] += 1 + except: + self.shoots[currentChannel] = 1 + else: - irc.reply("Already a duck") - else: - irc.reply("The hunt has not started yet!") - else: - irc.error('You have to be on a channel') + irc.reply("Already a duck") + else: + irc.reply("The hunt has not started yet!") + else: + irc.error('You have to be on a channel') Class = DuckHunt From 4dfb96d710e86d6c2de10561c83e5d897d67743e Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 14:57:59 -0500 Subject: [PATCH 61/67] score fixes. python3 stuff. a beginning... --- plugin.py | 72 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/plugin.py b/plugin.py index 435d3dd..a470bf3 100644 --- a/plugin.py +++ b/plugin.py @@ -90,7 +90,7 @@ class DuckHunt(callbacks.Plugin): dow = int(time.strftime("%u")) # Day of week woy = int(time.strftime("%V")) # Week of year year = time.strftime("%Y") - dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Caturday', 'Saturday', 'Sunday'] + dayname = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] def _calc_scores(self, channel): @@ -284,7 +284,7 @@ class DuckHunt(callbacks.Plugin): self.throttle[channel] = random.randint(self.minthrottle[channel], self.maxthrottle[channel]) - def start(self, irc, msg, args): + def starthunt(self, irc, msg, args): """ Starts the hunt """ @@ -367,7 +367,7 @@ class DuckHunt(callbacks.Plugin): irc.reply("The hunt starts now!") else: irc.error('You have to be on a channel') - start = wrap(start) + starthunt = wrap(starthunt) def _launchEvent(self, irc, msg): @@ -381,7 +381,7 @@ class DuckHunt(callbacks.Plugin): - def stop(self, irc, msg, args): + def stophunt(self, irc, msg, args): """ Stops the current hunt """ @@ -397,11 +397,11 @@ class DuckHunt(callbacks.Plugin): schedule.removeEvent('DuckHunt_' + currentChannel) except KeyError: irc.reply('Error: the spammer wasn\'t running! This is a bug.') - else: + except: irc.reply('Nothing to stop: there\'s no hunt right now.') else: irc.error('You have to be on a channel') - stop = wrap(stop) + stophunt = wrap(stophunt) def fridaymode(self, irc, msg, args, channel, status): """ @@ -619,7 +619,7 @@ class DuckHunt(callbacks.Plugin): if self.channelweek[channel][week].get(day): # Getting all scores, to get the winner of the week msgstring = '' - scores = sorted(iter(self.channelweek[channel][week][day].items()), key=lambda k_v2:(k_v2[1],k_v2[0]), reverse=True) + scores = sorted(iter(list(self.channelweek[channel][week][day].items())), key=lambda k_v2:(k_v2[1],k_v2[0]), reverse=True) for item in scores: msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " @@ -663,21 +663,19 @@ class DuckHunt(callbacks.Plugin): for i in (1,2,3,4,5,6,7): if self.channelweek[channel][week].get(i): # Getting winner of the day - winnernick, winnerscore = max(iter(self.channelweek[channel][week][i].items()), key=lambda k_v:(k_v[1],k_v[0])) + winnernick, winnerscore = max(iter(list(self.channelweek[channel][week][i].items())), key=lambda k_v:(k_v[1],k_v[0])) msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " # Getting all scores, to get the winner of the week - for player in list(self.channelweek[channel][week][i].keys()): - try: - weekscores[player] += self.channelweek[channel][week][i][player] - except: - weekscores[player] = self.channelweek[channel][week][i][player] - + for i, players in self.channelweek[channel][week].items(): + for player, value in players.items(): + weekscores.setdefault(player, 0) + weekscores[player] += value if msgstring != "": irc.reply("Scores for week " + str(week) + ": " + msgstring) # Who's the winner at this point? - winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v1:(k_v1[1],k_v1[0])) + winnernick, winnerscore = max(iter(list(weekscores.items())), key=lambda k_v1:(k_v1[1],k_v1[0])) irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) else: @@ -731,7 +729,7 @@ class DuckHunt(callbacks.Plugin): listsize = size # Sort the scores (reversed: the higher the better) - scores = sorted(iter(self.channelscores[channel].items()), key=lambda k_v9:(k_v9[1],k_v9[0]), reverse=True) + scores = sorted(iter(list(self.channelscores[channel].items())), key=lambda k_v9:(k_v9[1],k_v9[0]), reverse=True) del scores[listsize:] msgstring = "" @@ -797,21 +795,23 @@ class DuckHunt(callbacks.Plugin): listsize = size # Sort the times (not reversed: the lower the better) - times = sorted(iter(self.channeltimes[channel].items()), key=lambda k_v10:(k_v10[1],k_v10[0]), reverse=False) + times = sorted(iter(list(self.channeltimes[channel].items())), key=lambda k_v10:(k_v10[1],k_v10[0]), reverse=False) del times[listsize:] msgstring = "" for item in times: # Same as in listscores for the xnickx - msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + " | " - if msgstring != "": - irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") - irc.reply(msgstring) - else: - irc.reply("There aren't any best times for this channel yet.") + #msgstring += "x" + item[0] + "x: "+ str(round(item[1],2)) + " | " + msgstring.join("x{0}x: {1} | ".format(item[0], str(round(item[1],2)))) + if item: + if msgstring: + irc.reply("\_o< ~ DuckHunt top-" + str(listsize) + " times for " + channel + " ~ >o_/") + irc.reply(msgstring) + else: + irc.reply("There aren't any best times for this channel yet.") - times = sorted(iter(self.channelworsttimes[channel].items()), key=lambda k_v11:(k_v11[1],k_v11[0]), reverse=True) + times = sorted(iter(list(self.channelworsttimes[channel].items())), key=lambda k_v11:(k_v11[1],k_v11[0]), reverse=True) del times[listsize:] msgstring = "" @@ -1020,7 +1020,7 @@ class DuckHunt(callbacks.Plugin): if (self.scores.get(currentChannel)): # Getting winner - winnernick, winnerscore = max(iter(self.scores.get(currentChannel).items()), key=lambda k_v12:(k_v12[1],k_v12[0])) + winnernick, winnerscore = max(iter(list(self.scores.get(currentChannel).items())), key=lambda k_v12:(k_v12[1],k_v12[0])) if self.registryValue('ducks', currentChannel): maxShoots = self.registryValue('ducks', currentChannel) else: @@ -1035,7 +1035,7 @@ class DuckHunt(callbacks.Plugin): #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) #irc.reply(self.scores.get(currentChannel)) #TODO: Better display - irc.reply(sorted(iter(self.scores.get(currentChannel).items()), key=lambda k_v4:(k_v4[1],k_v4[0]), reverse=True)) + irc.reply(sorted(iter(list(self.scores.get(currentChannel).items())), key=lambda k_v4:(k_v4[1],k_v4[0]), reverse=True)) @@ -1043,12 +1043,12 @@ class DuckHunt(callbacks.Plugin): channelbestnick = None channelbesttime = None if self.channeltimes.get(currentChannel): - channelbestnick, channelbesttime = min(iter(self.channeltimes.get(currentChannel).items()), key=lambda k_v5:(k_v5[1],k_v5[0])) + channelbestnick, channelbesttime = min(iter(list(self.channeltimes.get(currentChannel).items())), key=lambda k_v5:(k_v5[1],k_v5[0])) # Showing best time recordmsg = '' if (self.toptimes.get(currentChannel)): - key,value = min(iter(self.toptimes.get(currentChannel).items()), key=lambda k_v6:(k_v6[1],k_v6[0])) + key,value = min(iter(list(self.toptimes.get(currentChannel).items())), key=lambda k_v6:(k_v6[1],k_v6[0])) if (channelbesttime and value < channelbesttime): recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' else: @@ -1064,13 +1064,13 @@ class DuckHunt(callbacks.Plugin): channelworstnick = None channelworsttime = None if self.channelworsttimes.get(currentChannel): - channelworstnick, channelworsttime = max(iter(self.channelworsttimes.get(currentChannel).items()), key=lambda k_v7:(k_v7[1],k_v7[0])) + channelworstnick, channelworsttime = max(iter(list(self.channelworsttimes.get(currentChannel).items())), key=lambda k_v7:(k_v7[1],k_v7[0])) # Showing worst time recordmsg = '' if (self.worsttimes.get(currentChannel)): - key,value = max(iter(self.worsttimes.get(currentChannel).items()), key=lambda k_v8:(k_v8[1],k_v8[0])) + key,value = max(iter(list(self.worsttimes.get(currentChannel).items())), key=lambda k_v8:(k_v8[1],k_v8[0])) if (channelworsttime and value > channelworsttime): recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' else: @@ -1101,13 +1101,11 @@ class DuckHunt(callbacks.Plugin): for i in (1,2,3,4,5,6,7): if self.channelweek[currentChannel][self.woy].get(i): # Getting all scores, to get the winner of the week - for player in list(self.channelweek[currentChannel][self.woy][i].keys()): - try: - weekscores[player] += self.channelweek[currentChannel][self.woy][i][player] - except: - weekscores[player] = self.channelweek[currentChannel][self.woy][i][player] - - winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v3:(k_v3[1],k_v3[0])) + for i, players in self.channelweek[channel][week].items(): + for player, value in players.items(): + weekscores.setdefault(player, 0) + weekscores[player] += value + winnernick, winnerscore = max(iter(list(weekscores.items())), key=lambda k_v3:(k_v3[1],k_v3[0])) if (winnernick != self.leader[currentChannel]): if self.leader[currentChannel] != None: irc.reply("%s took the lead for the week over %s with %i points." % (winnernick, self.leader[currentChannel], winnerscore)) From 83c6b73052967a4e2f4876d1453c95f04dfb1ba9 Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 15:01:03 -0500 Subject: [PATCH 62/67] Update __init__.py --- __init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 1d3b20c..6589e91 100644 --- a/__init__.py +++ b/__init__.py @@ -35,6 +35,7 @@ This is a DuckHunt game for supybot import supybot import supybot.world as world from imp import reload +import importlib # Use this for the version of this plugin. You may wish to put a CVS keyword # in here if you're keeping the plugin in CVS or some similar system. @@ -52,7 +53,7 @@ __url__ = 'https://github.com/veggiematts/supybot-duckhunt' from . import config from . import plugin -reload(plugin) # In case we're being reloaded. +importlib.reload(plugin) # In case we're being reloaded. # Add more reloads here if you add third-party modules and want them to be # reloaded when this plugin is reloaded. Don't forget to import them as well! From 8a4d3e84b4a6d378e37210318fee0337c644e490 Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 15:10:52 -0500 Subject: [PATCH 63/67] cleanup. more python3 stuff. keys->items etc. --- plugin.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plugin.py b/plugin.py index a470bf3..7db05a5 100644 --- a/plugin.py +++ b/plugin.py @@ -100,7 +100,7 @@ class DuckHunt(callbacks.Plugin): # scores # Adding current scores to the channel scores - for player in list(self.scores[channel].keys()): + for player in self.scores[channel].items(): if not player in self.channelscores[channel]: # It's a new player self.channelscores[channel][player] = self.scores[channel][player] @@ -110,7 +110,7 @@ class DuckHunt(callbacks.Plugin): # times # Adding times scores to the channel scores - for player in list(self.toptimes[channel].keys()): + for player in self.toptimes[channel].items(): if not player in self.channeltimes[channel]: # It's a new player self.channeltimes[channel][player] = self.toptimes[channel][player] @@ -122,7 +122,7 @@ class DuckHunt(callbacks.Plugin): # worst times # Adding worst times scores to the channel scores - for player in list(self.worsttimes[channel].keys()): + for player in self.worsttimes[channel].items(): if not player in self.channelworsttimes[channel]: # It's a new player self.channelworsttimes[channel][player] = self.worsttimes[channel][player] @@ -133,7 +133,7 @@ class DuckHunt(callbacks.Plugin): self.channelworsttimes[channel][player] = self.worsttimes[channel][player] # week scores - for player in list(self.scores[channel].keys()): + for player in self.scores[channel].items(): #FIXME: If the hunt starts a day and ends the day after, this will produce an error: if not player in self.channelweek[channel][self.woy][self.dow]: # It's a new player @@ -619,7 +619,7 @@ class DuckHunt(callbacks.Plugin): if self.channelweek[channel][week].get(day): # Getting all scores, to get the winner of the week msgstring = '' - scores = sorted(iter(list(self.channelweek[channel][week][day].items())), key=lambda k_v2:(k_v2[1],k_v2[0]), reverse=True) + scores = sorted(iter(self.channelweek[channel][week][day].items()), key=lambda k_v2:(k_v2[1],k_v2[0]), reverse=True) for item in scores: msgstring += "x" + item[0] + "x: "+ str(item[1]) + " | " @@ -663,7 +663,7 @@ class DuckHunt(callbacks.Plugin): for i in (1,2,3,4,5,6,7): if self.channelweek[channel][week].get(i): # Getting winner of the day - winnernick, winnerscore = max(iter(list(self.channelweek[channel][week][i].items())), key=lambda k_v:(k_v[1],k_v[0])) + winnernick, winnerscore = max(iter(self.channelweek[channel][week][i].items()), key=lambda k_v:(k_v[1],k_v[0])) msgstring += self.dayname[i - 1] + ": x" + winnernick + "x ("+ str(winnerscore) + ") | " # Getting all scores, to get the winner of the week @@ -675,7 +675,7 @@ class DuckHunt(callbacks.Plugin): if msgstring != "": irc.reply("Scores for week " + str(week) + ": " + msgstring) # Who's the winner at this point? - winnernick, winnerscore = max(iter(list(weekscores.items())), key=lambda k_v1:(k_v1[1],k_v1[0])) + winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v1:(k_v1[1],k_v1[0])) irc.reply("Leader: x%sx with %i points." % (winnernick, winnerscore)) else: @@ -729,7 +729,7 @@ class DuckHunt(callbacks.Plugin): listsize = size # Sort the scores (reversed: the higher the better) - scores = sorted(iter(list(self.channelscores[channel].items())), key=lambda k_v9:(k_v9[1],k_v9[0]), reverse=True) + scores = sorted(iter(self.channelscores[channel].items()), key=lambda k_v9:(k_v9[1],k_v9[0]), reverse=True) del scores[listsize:] msgstring = "" @@ -757,7 +757,7 @@ class DuckHunt(callbacks.Plugin): if (self.channelscores.get(channel)): scores = self.channelscores[channel] total = 0 - for player in list(scores.keys()): + for player in scores.items(): total += scores[player] irc.reply(str(total) + " ducks have been shot in " + channel + "!") else: @@ -795,7 +795,7 @@ class DuckHunt(callbacks.Plugin): listsize = size # Sort the times (not reversed: the lower the better) - times = sorted(iter(list(self.channeltimes[channel].items())), key=lambda k_v10:(k_v10[1],k_v10[0]), reverse=False) + times = sorted(iter(self.channeltimes[channel].items()), key=lambda k_v10:(k_v10[1],k_v10[0]), reverse=False) del times[listsize:] msgstring = "" @@ -811,7 +811,7 @@ class DuckHunt(callbacks.Plugin): irc.reply("There aren't any best times for this channel yet.") - times = sorted(iter(list(self.channelworsttimes[channel].items())), key=lambda k_v11:(k_v11[1],k_v11[0]), reverse=True) + times = sorted(iter(self.channelworsttimes[channel].items()), key=lambda k_v11:(k_v11[1],k_v11[0]), reverse=True) del times[listsize:] msgstring = "" @@ -1020,7 +1020,7 @@ class DuckHunt(callbacks.Plugin): if (self.scores.get(currentChannel)): # Getting winner - winnernick, winnerscore = max(iter(list(self.scores.get(currentChannel).items())), key=lambda k_v12:(k_v12[1],k_v12[0])) + winnernick, winnerscore = max(iter(self.scores.get(currentChannel).items()), key=lambda k_v12:(k_v12[1],k_v12[0])) if self.registryValue('ducks', currentChannel): maxShoots = self.registryValue('ducks', currentChannel) else: @@ -1035,7 +1035,7 @@ class DuckHunt(callbacks.Plugin): #irc.reply("Winner: %s with %i points" % (winnernick, winnerscore)) #irc.reply(self.scores.get(currentChannel)) #TODO: Better display - irc.reply(sorted(iter(list(self.scores.get(currentChannel).items())), key=lambda k_v4:(k_v4[1],k_v4[0]), reverse=True)) + irc.reply(sorted(iter(self.scores.get(currentChannel).items()), key=lambda k_v4:(k_v4[1],k_v4[0]), reverse=True)) @@ -1043,12 +1043,12 @@ class DuckHunt(callbacks.Plugin): channelbestnick = None channelbesttime = None if self.channeltimes.get(currentChannel): - channelbestnick, channelbesttime = min(iter(list(self.channeltimes.get(currentChannel).items())), key=lambda k_v5:(k_v5[1],k_v5[0])) + channelbestnick, channelbesttime = min(iter(self.channeltimes.get(currentChannel).items()), key=lambda k_v5:(k_v5[1],k_v5[0])) # Showing best time recordmsg = '' if (self.toptimes.get(currentChannel)): - key,value = min(iter(list(self.toptimes.get(currentChannel).items())), key=lambda k_v6:(k_v6[1],k_v6[0])) + key,value = min(iter(self.toptimes.get(currentChannel).items()), key=lambda k_v6:(k_v6[1],k_v6[0])) if (channelbesttime and value < channelbesttime): recordmsg = '. This is the new record for this channel! (previous record was held by ' + channelbestnick + ' with ' + str(round(channelbesttime,2)) + ' seconds)' else: @@ -1064,13 +1064,13 @@ class DuckHunt(callbacks.Plugin): channelworstnick = None channelworsttime = None if self.channelworsttimes.get(currentChannel): - channelworstnick, channelworsttime = max(iter(list(self.channelworsttimes.get(currentChannel).items())), key=lambda k_v7:(k_v7[1],k_v7[0])) + channelworstnick, channelworsttime = max(iter(self.channelworsttimes.get(currentChannel).items()), key=lambda k_v7:(k_v7[1],k_v7[0])) # Showing worst time recordmsg = '' if (self.worsttimes.get(currentChannel)): - key,value = max(iter(list(self.worsttimes.get(currentChannel).items())), key=lambda k_v8:(k_v8[1],k_v8[0])) + key,value = max(iter(self.worsttimes.get(currentChannel).items()), key=lambda k_v8:(k_v8[1],k_v8[0])) if (channelworsttime and value > channelworsttime): recordmsg = '. This is the new longest time for this channel! (previous longest time was held by ' + channelworstnick + ' with ' + str(round(channelworsttime,2)) + ' seconds)' else: @@ -1105,7 +1105,7 @@ class DuckHunt(callbacks.Plugin): for player, value in players.items(): weekscores.setdefault(player, 0) weekscores[player] += value - winnernick, winnerscore = max(iter(list(weekscores.items())), key=lambda k_v3:(k_v3[1],k_v3[0])) + winnernick, winnerscore = max(iter(weekscores.items()), key=lambda k_v3:(k_v3[1],k_v3[0])) if (winnernick != self.leader[currentChannel]): if self.leader[currentChannel] != None: irc.reply("%s took the lead for the week over %s with %i points." % (winnernick, self.leader[currentChannel], winnerscore)) From 54552a3502aaf055255de53972bd5eb9c2cd4585 Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 15:36:20 -0500 Subject: [PATCH 64/67] fix count of 'total' --- plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.py b/plugin.py index 7db05a5..364e1bb 100644 --- a/plugin.py +++ b/plugin.py @@ -757,8 +757,8 @@ class DuckHunt(callbacks.Plugin): if (self.channelscores.get(channel)): scores = self.channelscores[channel] total = 0 - for player in scores.items(): - total += scores[player] + for player, value in scores.items(): + total += value irc.reply(str(total) + " ducks have been shot in " + channel + "!") else: irc.reply("There are no scores for this channel yet") From 78e0524f654f865814d93c1c2d8d064d98d75417 Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 15:40:12 -0500 Subject: [PATCH 65/67] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b33a9d2..4fb4e55 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +Requires Python3, Limnoria. +Python 3 and score fixes by me. Plugin working. + \_o< ~ DuckHunt game for supybot ~ >o_/ ======================================= From aee383c3d5c949167b5b50760dec5f084eab371a Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 15:40:39 -0500 Subject: [PATCH 66/67] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fb4e55..0e96cad 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Requires Python3, Limnoria. -Python 3 and score fixes by me. Plugin working. + +Python 3 and score fixes. Plugin working. \_o< ~ DuckHunt game for supybot ~ >o_/ ======================================= From b3c68d53fdb9affa0064db3c65291b72dbe7d40a Mon Sep 17 00:00:00 2001 From: Gordon Shumway <39967334+oddluck@users.noreply.github.com> Date: Sat, 23 Feb 2019 16:21:49 -0500 Subject: [PATCH 67/67] oops. bad copy/paste and a few more fixes --- plugin.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugin.py b/plugin.py index 364e1bb..85cd3bf 100644 --- a/plugin.py +++ b/plugin.py @@ -100,20 +100,20 @@ class DuckHunt(callbacks.Plugin): # scores # Adding current scores to the channel scores - for player in self.scores[channel].items(): + for player, value in self.scores[channel].items(): if not player in self.channelscores[channel]: # It's a new player - self.channelscores[channel][player] = self.scores[channel][player] + self.channelscores[channel][player] = value else: # It's a player that already has a saved score - self.channelscores[channel][player] += self.scores[channel][player] + self.channelscores[channel][player] += value # times # Adding times scores to the channel scores - for player in self.toptimes[channel].items(): + for player, value in self.toptimes[channel].items(): if not player in self.channeltimes[channel]: # It's a new player - self.channeltimes[channel][player] = self.toptimes[channel][player] + self.channeltimes[channel][player] = value else: # It's a player that already has a saved score # And we save the time of the current hunt if it's better than it's previous time @@ -122,25 +122,25 @@ class DuckHunt(callbacks.Plugin): # worst times # Adding worst times scores to the channel scores - for player in self.worsttimes[channel].items(): + for player, value in self.worsttimes[channel].items(): if not player in self.channelworsttimes[channel]: # It's a new player - self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + self.channelworsttimes[channel][player] = value else: # It's a player that already has a saved score # And we save the time of the current hunt if it's worst than it's previous time - if(self.worsttimes[channel][player] > self.channelworsttimes[channel][player]): - self.channelworsttimes[channel][player] = self.worsttimes[channel][player] + if(self.worsttimes[channel][player] > value): + self.channelworsttimes[channel][player] = value # week scores - for player in self.scores[channel].items(): + for player, value in self.scores[channel].items(): #FIXME: If the hunt starts a day and ends the day after, this will produce an error: if not player in self.channelweek[channel][self.woy][self.dow]: # It's a new player - self.channelweek[channel][self.woy][self.dow][player] = self.scores[channel][player] + self.channelweek[channel][self.woy][self.dow][player] = value else: # It's a player that already has a saved score - self.channelweek[channel][self.woy][self.dow][player] += self.scores[channel][player] + self.channelweek[channel][self.woy][self.dow][player] += value @@ -1101,7 +1101,7 @@ class DuckHunt(callbacks.Plugin): for i in (1,2,3,4,5,6,7): if self.channelweek[currentChannel][self.woy].get(i): # Getting all scores, to get the winner of the week - for i, players in self.channelweek[channel][week].items(): + for i, players in self.channelweek[currentChannel][self.woy].items(): for player, value in players.items(): weekscores.setdefault(player, 0) weekscores[player] += value