pyircbot/pyircbot/modules/DogeScramble.py

273 lines
9.9 KiB
Python
Executable File

#!/usr/bin/env python
"""
.. module:: DogeScramble
:synopsis: This module provides a word scrambling game that rewards winners with small amounts of Dogecoin
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
"""
from pyircbot.modulebase import ModuleBase, ModuleHook
import random
import os
from threading import Timer
class DogeScramble(ModuleBase):
def __init__(self, bot, moduleName):
ModuleBase.__init__(self, bot, moduleName)
self.hooks = [ModuleHook("PRIVMSG", self.scramble)]
# Load attribute storage
self.attr = None
serviceProviders = self.bot.getmodulesbyservice("attributes")
if len(serviceProviders) == 0:
self.log.error("DogeScramble: Could not find a valid attributes service provider")
else:
self.log.info("DogeScramble: Selecting attributes service provider: %s" % serviceProviders[0])
self.attr = serviceProviders[0]
# Load doge RPC
self.doge = self.bot.getBestModuleForService("dogerpc")
# Per channel games
self.games = {}
def scramble(self, args, prefix, trailing):
channel = args[0]
if channel[0] == "#":
# Ignore messages from users without a dogewallet password
prefixObj = self.bot.decodePrefix(prefix)
if self.attr.getKey(prefixObj.nick, "password") is None:
return
if channel not in self.games:
self.games[channel] = scrambleGame(self, channel)
self.games[channel].scramble(args, prefix, trailing)
def ondisable(self):
self.log.info("DogeScramble: Unload requested, ending games...")
for game in self.games:
self.games[game].gameover()
class scrambleGame:
def __init__(self, master, channel):
self.master = master
self.channel = channel
# Running?
self.running = False
# Current word
self.currentWord = None
# Current word, scrambled
self.scrambled = None
# Online?
self.scrambleOn = False
# Count down to hints
self.hintTimer = None
# of hints given
self.hintsGiven = 0
# Cooldown between words
self.nextTimer = None
# How many guesses submitted this round
self.guesses = 0
# How many games in a row where nobody guessed
self.gamesWithoutGuesses = 0
# What file are we using
self.category_file = None
# How many words in this category have been used?
self.category_count = 0
# How long between categories
self.change_category_after_words = self.master.config["categoryduration"]
# Should we change categories at the next pick?
self.should_change_category = True
# Holds the processed category name
self.category_name = None
# list of last picked words
self.lastwords = []
# name of last winner for decreasing return
self.lastwinner = None
self.lastwinvalue = 0
self.delayHint = self.master.config["hintDelay"]
self.delayNext = self.master.config["delayNext"]
self.maxHints = self.master.config["maxHints"]
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]
def gameover(self):
self.clearTimers()
self.running = False
def clearTimers(self):
self.clearTimer(self.nextTimer)
self.clearTimer(self.hintTimer)
def clearTimer(self, timer):
if timer:
timer.cancel()
def scramble(self, args, prefix, trailing):
prefix = self.master.bot.decodePrefix(prefix)
sender = prefix.nick
senderIsOp = self.master.attr.getKey(prefix.nick, "op") == "yes"
cmd = self.master.bot.messageHasCommand(".scramble", trailing)
if cmd and not self.running:
# and senderIsOp
self.running = True
self.startScramble()
return
cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing)
if cmd and senderIsOp and self.running:
self.gameover()
self.running = False
return
if self.currentWord and trailing.strip().lower() == self.currentWord:
# Get winner withdraw address
useraddr = self.master.attr.getKey(prefix.nick, "dogeaddr")
userwallet = self.master.attr.getKey(prefix.nick, "dogeaccountname")
self.master.bot.act_PRIVMSG(self.channel, "%s got the word - %s!" % (sender, self.currentWord))
if not useraddr:
self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me "
"\".setdogeaddr\". Next word in %s seconds." %
(prefix.nick, self.delayNext))
else:
winamount = float(self.master.config["winAmount"])
if self.lastwinner == prefix.nick:
winamount = self.lastwinvalue * self.master.config["decreaseFactor"]
self.lastwinvalue = winamount
self.lastwinner = prefix.nick
self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." %
(prefix.nick, round(winamount, 8), self.delayNext))
self.master.doge.move('', userwallet, winamount)
self.currentWord = None
self.clearTimers()
self.hintsGiven = 0
self.nextTimer = Timer(self.delayNext, self.startNewWord)
self.nextTimer.start()
self.guesses = 0
self.category_count += 1
self.master.log.info("DogeScramble: category_count is: %s" % (self.category_count))
if self.category_count >= self.change_category_after_words:
self.should_change_category = True
else:
self.guesses += 1
def startScramble(self):
self.clearTimer(self.nextTimer)
self.nextTimer = Timer(0, self.startNewWord)
self.nextTimer.start()
def startNewWord(self):
self.currentWord = self.pickWord()
self.scrambled = self.scrambleWord(self.currentWord)
self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " %
(self.category_name, self.scrambled))
self.clearTimer(self.hintTimer)
self.hintTimer = Timer(self.delayHint, self.giveHint)
self.hintTimer.start()
def giveHint(self):
self.hintsGiven += 1
if self.hintsGiven >= len(self.currentWord) or self.hintsGiven > self.maxHints:
self.abortWord()
return
blanks = ""
for letter in list(self.currentWord):
if letter == " ":
blanks += " "
else:
blanks += "_"
partFromWord = self.currentWord[0:self.hintsGiven]
partFromBlanks = blanks[self.hintsGiven:]
hintstr = partFromWord + partFromBlanks
self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr))
self.clearTimer(self.hintTimer)
self.hintTimer = Timer(self.delayHint, self.giveHint)
self.hintTimer.start()
def abortWord(self):
cur = self.currentWord
self.currentWord = None
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." %
(cur, self.delayNext))
self.hintsGiven = 0
self.clearTimer(self.nextTimer)
if self.guesses == 0:
self.gamesWithoutGuesses += 1
if self.gamesWithoutGuesses >= self.abortAfterNoGuesses:
self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scramble to start again.")
self.gameover()
return
else:
self.gamesWithoutGuesses = 0
self.nextTimer = Timer(self.delayNext, self.startNewWord)
self.nextTimer.start()
def catFileNameToStr(self, s):
s = s.split(".")[0]
s = s.replace("_", " ")
return s.title()
def pickWord(self):
if self.should_change_category:
# clear flags
self.should_change_category = False
self.category_count = 0
# Get the path to word files dir
dirpath = self.master.getFilePath("")
# List dir
files = os.listdir(dirpath)
# choose a random file
random.shuffle(files)
self.category_file = files[0]
self.category_name = self.catFileNameToStr(self.category_file)
# Process the name & announce
self.master.bot.act_PRIVMSG(self.channel, "The category is now: %s " % self.category_name)
# count lines
f = open(self.master.getFilePath(self.category_file), "r")
lines = 0
while True:
lines += 1
if f.readline() == "":
break
f.close()
# change category
picked = ""
while picked == "" or picked in self.lastwords:
skip = random.randint(0, lines)
f = open(self.master.getFilePath(self.category_file), "r")
while skip >= 0:
f.readline()
skip -= 1
picked = f.readline().strip().lower()
f.close()
self.master.log.info("DogeScramble: picked %s for %s" % (picked, self.channel))
self.lastwords.append(picked)
if len(self.lastwords) > 5:
self.lastwords.pop(0)
return picked
def scrambleWord(self, word):
scrambled = ""
for subword in word.split(" "):
scrambled += self.scrambleIndividualWord(subword) + " "
return scrambled.strip()
def scrambleIndividualWord(self, word):
scrambled = list(word)
random.shuffle(scrambled)
return ''.join(scrambled).lower()