def _parseShadowrunExtRoll(self, m): """ Parse Shadowrun-specific Extended test roll such as 14,3#sde. """ pool = int(m.group('pool')) if pool < 1 or pool > self.MAX_DICE: return threshold = int(m.group('thr')) if threshold < 1 or threshold > self.MAX_DICE: return result = 0 passes = 0 glitches = [] critGlitch = None while result < threshold: L = self._rollMultiple(1, 6, pool) self.log.debug(format('%L', [str(i) for i in L])) hits = L.count(6) + L.count(5) result += hits passes += 1 isHit = hits > 0 isGlitch = L.count(1) >= (pool + 1) / 2 if isGlitch: if not isHit: critGlitch = passes break glitches.append(ordinal(passes)) glitchStr = format(', glitch at %L', glitches) if len(glitches) > 0 else '' if critGlitch is None: return format('(pool %i, threshold %i) %n, %n%s', pool, threshold, (passes, 'pass'), (result, 'hit'), glitchStr) else: return format('(pool %i, threshold %i) critical glitch at %s pass%s, %n so far', pool, threshold, ordinal(critGlitch), glitchStr, (result, 'hit'))
def _parseShadowrunExtRoll(self, m): """ Parse Shadowrun-specific Extended test roll such as 14,3#sde. """ pool = int(m.group("pool")) if pool < 1 or pool > self.MAX_DICE: return threshold = int(m.group("thr")) if threshold < 1 or threshold > self.MAX_DICE: return result = 0 passes = 0 glitches = [] critGlitch = None while result < threshold: L = self._rollMultiple(1, 6, pool) self.log.debug(format("%L", [str(i) for i in L])) hits = L.count(6) + L.count(5) result += hits passes += 1 isHit = hits > 0 isGlitch = L.count(1) >= (pool + 1) / 2 if isGlitch: if not isHit: critGlitch = passes break glitches.append(ordinal(passes)) glitchStr = format(", glitch at %L", glitches) if len(glitches) > 0 else "" if critGlitch is None: return format( "(pool %i, threshold %i) %n, %n%s", pool, threshold, (passes, "pass"), (result, "hit"), glitchStr, ) else: return format( "(pool %i, threshold %i) critical glitch at %s pass%s, %n so far", pool, threshold, ordinal(critGlitch), glitchStr, (result, "hit"), )
def _parseShadowrunXRoll(self, m): """ Parse Shadowrun-specific 'exploding' roll such as 3#sdx. """ rolls = int(m.group('rolls')) if rolls < 1 or rolls > self.MAX_DICE: return L = self._rollMultiple(1, 6, rolls) self.log.debug(format("%L", [str(i) for i in L])) reroll = L.count(6) while reroll: rerolled = self._rollMultiple(1, 6, reroll) self.log.debug(format("%L", [str(i) for i in rerolled])) L.extend([r for r in rerolled if r >= 5]) reroll = rerolled.count(6) return self._processSRResults(L, rolls, True)
def _parse7Sea2edRoll(self, m): """ Parse 7th Sea 2ed roll (4s2 is its simplest form). Full spec: https://redd.it/80l7jm """ rolls = m.group('rolls') if rolls is None: return # additional validation if not re.match(self.validation7sea2ed, rolls): return roll_count = eval(rolls) if roll_count < 1 or roll_count > self.MAX_ROLLS: return skill = int(m.group('skill')) vivre = m.group('vivre') == '-' explode = m.group('explode') == 'ex' lashes = 0 if m.group('lashes') is None else int(m.group('lashes')) cursed = m.group('cursed') is not None self.log.debug( format( '7sea2ed: %i (%s) dices at %i skill. lashes = %i. explode is %s. vivre is %s', roll_count, str(rolls), skill, lashes, "enabled" if explode else "disabled", "enabled" if vivre else "disabled")) roller = SevenSea2EdRaiseRoller(lambda x: self._rollMultiple(1, 10, x), skill_rank=skill, explode=explode, lash_count=lashes, joie_de_vivre=vivre, raise_target=15 if cursed else 10) return '[%s]: %s' % (m.group(0), str( roller.roll_and_count(roll_count)))
def _printChangeset(self, values): yield format('%s [%s] by %s in %s (%n): %s', bold('Changeset'), values['rev'], underline(values['author']), values['path'], (values['file_count'], 'file'), ellipsisify(values['message'].strip(), 130)) yield '<%s>' % values['url']
def _printChangeset(self, values): yield format('%s [%s] by %s in %s (%n): %s', bold('Changeset'), values['rev'], underline(values['author']), values['path'], (values['file_count'], 'file'), ellipsisify(values['message'].strip(), 130) ) yield '<%s>' % values['url']
def _printWikiPage(self, values): action = values.get('action') if action is not None: if action == 'created': action = 'created by %s' % underline(values['author']) elif action == 'changed': action = 'changed by %s' % underline(values['author']) action = ' (%s)' % action yield format('%s%s %u', bold(values['name']), action or '', values['url'])
def _parseShadowrunRoll(self, m): """ Parse Shadowrun-specific roll such as 3#sd. """ rolls = int(m.group('rolls')) if rolls < 1 or rolls > self.MAX_DICE: return L = self._rollMultiple(1, 6, rolls) self.log.debug(format("%L", [str(i) for i in L])) return self._processSRResults(L, rolls)
def _parseWGRoll(self, m): """ Parse WH40K: Wrath & Glory roll (10#wg) """ rolls = int(m.group('rolls') or 1) if rolls < 1 or rolls > self.MAX_ROLLS: return L = self._rollMultiple(1, 6, rolls) self.log.debug(format("%L", [str(i) for i in L])) return self._processWGResults(L, rolls)
def _parse7SeaRoll(self, m): """ Parse 7th Sea-specific roll (4k2 is its simplest form). """ rolls = int(m.group("rolls")) if rolls < 1 or rolls > self.MAX_ROLLS: return count = int(m.group("count") or 1) keep = int(m.group("keep")) mod = int(m.group("mod") or 0) prefix = m.group("prefix") k = m.group("k") explode = prefix != "-" if keep < 1 or keep > self.MAX_ROLLS: return if keep > rolls: keep = rolls if rolls > 10: keep += rolls - 10 rolls = 10 if keep > 10: mod += (keep - 10) * 10 keep = 10 unkept = (prefix == "+" or k == "kk") and keep < rolls explodeStr = ", not exploding" if not explode else "" results = [] for _ in range(count): L = self._rollMultiple(1, 10, rolls) if explode: for i in range(len(L)): if L[i] == 10: while True: rerolled = self._roll(1, 10) L[i] += rerolled if rerolled < 10: break self.log.debug(format("%L", [str(i) for i in L])) L.sort(reverse=True) keptDice, unkeptDice = L[:keep], L[keep:] unkeptStr = (" | %s" % ", ".join([str(i) for i in unkeptDice]) if unkept else "") keptStr = ", ".join([str(i) for i in keptDice]) results.append("(%d) %s%s" % (sum(keptDice) + mod, keptStr, unkeptStr)) return "[%dk%d%s%s] %s" % ( rolls, keep, self._formatMod(mod), explodeStr, "; ".join(results), )
def _printWikiPage(self, values): action = values.get('action') if action is not None: if action == 'created': action = 'created by %s' % underline(values['author']) elif action == 'changed': action = 'changed by %s' % underline(values['author']) action = ' (%s)' % action yield format('%s%s %u', bold(values['name']), action or '', values['url'] )
def _parseWoDRoll(self, m): """ Parse New World of Darkness roll (5w) """ rolls = int(m.group("rolls")) if rolls < 1 or rolls > self.MAX_ROLLS: return if m.group("explode") == "-": explode = 0 elif m.group("explode") is not None and m.group("explode").isdigit(): explode = int(m.group("explode")) if explode < 8 or explode > 10: explode = 10 else: explode = 10 L = self._rollMultiple(1, 10, rolls) self.log.debug(format("%L", [str(i) for i in L])) successes = len([x for x in L if x >= 8]) if explode: for i in range(len(L)): if L[i] >= explode: while True: rerolled = self._roll(1, 10) self.log.debug(str(rerolled)) if rerolled >= 8: successes += 1 if rerolled < explode: break if explode == 0: explStr = ", not exploding" elif explode != 10: explStr = ", %d-again" % explode else: explStr = "" result = format("%n", (successes, "success")) if successes > 0 else "FAIL" return "(%d%s) %s" % (rolls, explStr, result)
def _parseWoDRoll(self, m): """ Parse New World of Darkness roll (5w) """ rolls = int(m.group('rolls')) if rolls < 1 or rolls > self.MAX_ROLLS: return if m.group('explode') == '-': explode = 0 elif m.group('explode') is not None and m.group('explode').isdigit(): explode = int(m.group('explode')) if explode < 8 or explode > 10: explode = 10 else: explode = 10 L = self._rollMultiple(1, 10, rolls) self.log.debug(format("%L", [str(i) for i in L])) successes = len([x for x in L if x >= 8]) if explode: for i in range(len(L)): if L[i] >= explode: while True: rerolled = self._roll(1, 10) self.log.debug(str(rerolled)) if rerolled >= 8: successes += 1 if rerolled < explode: break if explode == 0: explStr = ', not exploding' elif explode != 10: explStr = ', %d-again' % explode else: explStr = '' result = format('%n', (successes, 'success')) if successes > 0 else 'FAIL' return '(%d%s) %s' % (rolls, explStr, result)
def _processSRResults(results, pool, isExploding=False): hits = results.count(6) + results.count(5) ones = results.count(1) isHit = hits > 0 isGlitch = ones >= (pool + 1) / 2 explStr = ', exploding' if isExploding else '' if isHit: hitsStr = format('%n', (hits, 'hit')) glitchStr = ', glitch' if isGlitch else '' return '(pool %d%s) %s%s' % (pool, explStr, hitsStr, glitchStr) if isGlitch: return '(pool %d%s) critical glitch!' % (pool, explStr) return '(pool %d%s) 0 hits' % (pool, explStr)
def _processSRResults(results, pool, isExploding=False): hits = results.count(6) + results.count(5) ones = results.count(1) isHit = hits > 0 isGlitch = ones >= (pool + 1) / 2 explStr = ", exploding" if isExploding else "" if isHit: hitsStr = format("%n", (hits, "hit")) glitchStr = ", glitch" if isGlitch else "" return "(pool %d%s) %s%s" % (pool, explStr, hitsStr, glitchStr) if isGlitch: return "(pool %d%s) critical glitch!" % (pool, explStr) return "(pool %d%s) 0 hits" % (pool, explStr)
def _printTicket(self, values): action = values.get('action') if action is not None: if action == 'created': action = 'created by %s' % underline(values['reporter']) elif action == 'changed': action = 'changed by %s' % underline(values['author']) comment = values['comment'] if comment: comment = ', ' + comment action = ' (%s%s)' % (action, comment) yield format('%s #%s: %s%s', bold('Ticket'), values['id'], values['summary'], action or '') yield '<%s>' % values['url']
def _parse7SeaRoll(self, m): """ Parse 7th Sea-specific roll (4k2 is its simplest form). """ rolls = int(m.group('rolls')) if rolls < 1 or rolls > self.MAX_ROLLS: return count = int(m.group('count') or 1) keep = int(m.group('keep')) mod = int(m.group('mod') or 0) prefix = m.group('prefix') k = m.group('k') explode = prefix != '-' if keep < 1 or keep > self.MAX_ROLLS: return if keep > rolls: keep = rolls if rolls > 10: keep += rolls - 10 rolls = 10 if keep > 10: mod += (keep - 10) * 10 keep = 10 unkept = (prefix == '+' or k == 'kk') and keep < rolls explodeStr = ', not exploding' if not explode else '' results = [] for _ in range(count): L = self._rollMultiple(1, 10, rolls) if explode: for i in range(len(L)): if L[i] == 10: while True: rerolled = self._roll(1, 10) L[i] += rerolled if rerolled < 10: break self.log.debug(format("%L", [str(i) for i in L])) L.sort(reverse=True) keptDice, unkeptDice = L[:keep], L[keep:] unkeptStr = ' | %s' % ', '.join([str(i) for i in unkeptDice ]) if unkept else '' keptStr = ', '.join([str(i) for i in keptDice]) results.append('(%d) %s%s' % (sum(keptDice) + mod, keptStr, unkeptStr)) return '[%dk%d%s%s] %s' % (rolls, keep, self._formatMod(mod), explodeStr, '; '.join(results))
def _parse7SeaRoll(self, m): """ Parse 7th Sea-specific roll (4k2 is its simplest form). """ rolls = int(m.group('rolls')) if rolls < 1 or rolls > self.MAX_ROLLS: return count = int(m.group('count') or 1) keep = int(m.group('keep')) mod = int(m.group('mod') or 0) prefix = m.group('prefix') k = m.group('k') explode = prefix != '-' if keep < 1 or keep > self.MAX_ROLLS: return if keep > rolls: keep = rolls if rolls > 10: keep += rolls - 10 rolls = 10 if keep > 10: mod += (keep - 10) * 10 keep = 10 unkept = (prefix == '+' or k == 'kk') and keep < rolls explodeStr = ', not exploding' if not explode else '' results = [] for _ in range(count): L = self._rollMultiple(1, 10, rolls) if explode: for i in range(len(L)): if L[i] == 10: while True: rerolled = self._roll(1, 10) L[i] += rerolled if rerolled < 10: break self.log.debug(format("%L", [str(i) for i in L])) L.sort(reverse=True) keptDice, unkeptDice = L[:keep], L[keep:] unkeptStr = ' | %s' % ', '.join([str(i) for i in unkeptDice]) if unkept else '' keptStr = ', '.join([str(i) for i in keptDice]) results.append('(%d) %s%s' % (sum(keptDice) + mod, keptStr, unkeptStr)) return '[%dk%d%s%s] %s' % (rolls, keep, self._formatMod(mod), explodeStr, '; '.join(results))
def _printTicket(self, values): action = values.get('action') if action is not None: if action == 'created': action = 'created by %s' % underline(values['reporter']) elif action == 'changed': action = 'changed by %s' % underline(values['author']) comment = values['comment'] if comment: comment = ', ' + comment action = ' (%s%s)' % (action, comment) yield format('%s #%s: %s%s', bold('Ticket'), values['id'], values['summary'], action or '' ) yield '<%s>' % values['url']
def _parse7Sea2edRoll(self, m): """ Parse 7th Sea 2ed roll (4s2 is its simplest form). Full spec: https://redd.it/80l7jm """ rolls = m.group('rolls') if rolls is None: return # additional validation if not re.match(self.validation7sea2ed, rolls): return roll_count = eval(rolls) if roll_count < 1 or roll_count > self.MAX_ROLLS: return skill = int(m.group('skill')) vivre = m.group('vivre') == '-' explode = m.group('explode') == 'ex' lashes = 0 if m.group('lashes') is None else int(m.group('lashes')) cursed = m.group('cursed') is not None self.log.debug(format('7sea2ed: %i (%s) dices at %i skill. lashes = %i. explode is %s. vivre is %s', roll_count, str(rolls), skill, lashes, "enabled" if explode else "disabled", "enabled" if vivre else "disabled" )) roller = SevenSea2EdRaiseRoller( lambda x: self._rollMultiple(1, 10, x), skill_rank=skill, explode=explode, lash_count=lashes, joie_de_vivre=vivre, raise_target=15 if cursed else 10) return '[%s]: %s' % (m.group(0), str(roller.roll_and_count(roll_count)))
def configure(advanced): from supybot.questions import yn, something, output import sqlite import re import os from supybot.utils.str import format def anything(prompt, default=None): """Because supybot is pure fail""" from supybot.questions import expect return expect(prompt, [], default=default) Bantracker = conf.registerPlugin('Bantracker', True) def getReviewTime(): output("How many days should the bot wait before requesting a ban/quiet review?") review = something("Can be an integer or decimal value. Zero disables reviews.", default=str(Bantracker.request.review._default)) try: review = float(review) if review < 0: raise TypeError except TypeError: output("%r is an invalid value, it must be an integer or float greater or equal to 0" % review) return getReviewTime() else: return review enabled = yn("Enable Bantracker for all channels?") database = something("Location of the Bantracker database", default=conf.supybot.directories.data.dirize('bans.db')) bansite = anything("URL of the Bantracker web interface, without the 'bans.cgi'. (leave this blank if you don't want to run a web server)") request = yn("Enable review and comment requests from bot?", default=False) if request and advanced: output("Which types would you like the bot to request comments for?") output(format("The available request types are %L", Bantracker.request.type._default)) types = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.type._default)) type = set([]) for name in re.split(r',?\s+', types): name = name.lower() if name in ('removal', 'ban', 'quiet'): type.add(name) output("Which nicks should be bot not requets comments from?") output("Is case insensitive and wildcards '*' and '?' are accepted.") ignores = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.ignore._default)) ignore = set([]) for name in re.split(r',?\s+', ignores): name = name.lower() ignore.add(name) output("You can set the comment and review requests for some nicks to be forwarded to specific nicks/channels") output("Which nicks should these requests be forwarded for?") output("Is case insensitive and wildcards '*' and '?' are accepted.") forwards = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.forward._default)) forward = set([]) for name in re.split(r',?\s+', forwards): name = name.lower() forward.add(name) output("Which nicks/channels should the requests be forwarded to?") output("Is case insensitive and wildcards '*' and '?' are accepted.") channels_i = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.forward._default)) channels = set([]) for name in re.split(r',?\s+', channels_i): name = name.lower() channels.add(name) review = getReviewTime() else: type = Bantracker.request.type._default ignore = Bantracker.request.ignore._default forward = Bantracker.request.forward._default channels = Bantracker.request.forward.channels._default review = Bantracker.request.review._default Bantracker.enabled.setValue(enabled) Bantracker.database.setValue(database) Bantracker.bansite.setValue(bansite) Bantracker.request.setValue(request) Bantracker.request.type.setValue(type) Bantracker.request.ignore.setValue(ignore) Bantracker.request.forward.setValue(forward) Bantracker.request.forward.channels.setValue(channels) Bantracker.request.review.setValue(review) # Create the initial database db_file = Bantracker.database() if not db_file: db_file = conf.supybot.directories.data.dirize('bans.db') output("supybot.plugins.Bantracker.database will be set to %r" % db_file) Bantracker.database.setValue(db_file) if os.path.exists(db_file): return output("Creating an initial database in %r" % db_file) con = sqlite.connect(db_file) cur = con.cursor() try: cur.execute("""CREATE TABLE 'bans' ( id INTEGER PRIMARY KEY, channel VARCHAR(30) NOT NULL, mask VARCHAR(100) NOT NULL, operator VARCHAR(30) NOT NULL, time VARCHAR(300) NOT NULL, removal DATETIME, removal_op VARCHAR(30), log TEXT )""") #""" cur.execute("""CREATE TABLE comments ( ban_id INTEGER, who VARCHAR(100) NOT NULL, comment MEDIUMTEXT NOT NULL, time VARCHAR(300) NOT NULL )""") #""" cur.execute("""CREATE TABLE sessions ( session_id VARCHAR(50) PRIMARY KEY, user MEDIUMTEXT NOT NULL, time INT NOT NULL )""") #""" cur.execute("""CREATE TABLE users ( username VARCHAR(50) PRIMARY KEY, salt VARCHAR(8), password VARCHAR(50) )""") #""" except: con.rollback() raise else: con.commit() finally: cur.close() con.close()
zero_td = datetime.timedelta() time_until_today_420 = today_420 - now time_until_today_1620 = today_1620 - now # print(time_until_today_420) # print(time_until_today_1620) if time_until_today_420 >= zero_td or time_until_today_1620 >= zero_td: # if either 4:20 or 16:20 is later today if time_until_today_1620 < twelve_td: # if 16:20 will occur sooner than 12hrs time_until_next_420 = time_until_today_1620 else: time_until_next_420 = time_until_today_420 else: # else, 4:20 and 16:20 today are already gone, compute tomorrow's tomorrow_420 = today_420 + datetime.timedelta(days=1) time_until_next_420 = tomorrow_420 - now # convert timedelta format to seconds for supybot formatter. time_until_next_420_seconds = time_until_next_420.total_seconds() # print('Time until next 4:20 : ' + str(time_until_next_420) + f' for {timezone}') print( format('%T until next 4:20 for %s', time_until_next_420_seconds, timezone_code))
def configure(advanced): from supybot.questions import yn, something, output import sqlite import re import os from supybot.utils.str import format def anything(prompt, default=None): """Because supybot is pure fail""" from supybot.questions import expect return expect(prompt, [], default=default) Bantracker = conf.registerPlugin('Bantracker', True) def getReviewTime(): output( "How many days should the bot wait before requesting a ban/quiet review?" ) review = something( "Can be an integer or decimal value. Zero disables reviews.", default=str(Bantracker.request.review._default)) try: review = float(review) if review < 0: raise TypeError except TypeError: output( "%r is an invalid value, it must be an integer or float greater or equal to 0" % review) return getReviewTime() else: return review enabled = yn("Enable Bantracker for all channels?") database = something( "Location of the Bantracker database", default=conf.supybot.directories.data.dirize('bans.db')) bansite = anything( "URL of the Bantracker web interface, without the 'bans.cgi'. (leave this blank if you don't want to run a web server)" ) request = yn("Enable review and comment requests from bot?", default=False) if request and advanced: output("Which types would you like the bot to request comments for?") output( format("The available request types are %L", Bantracker.request.type._default)) types = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.type._default)) type = set([]) for name in re.split(r',?\s+', types): name = name.lower() if name in ('removal', 'ban', 'quiet'): type.add(name) output("Which nicks should be bot not requets comments from?") output("Is case insensitive and wildcards '*' and '?' are accepted.") ignores = anything("Separate types by spaces or commas:", default=', '.join( Bantracker.request.ignore._default)) ignore = set([]) for name in re.split(r',?\s+', ignores): name = name.lower() ignore.add(name) output( "You can set the comment and review requests for some nicks to be forwarded to specific nicks/channels" ) output("Which nicks should these requests be forwarded for?") output("Is case insensitive and wildcards '*' and '?' are accepted.") forwards = anything("Separate types by spaces or commas:", default=', '.join( Bantracker.request.forward._default)) forward = set([]) for name in re.split(r',?\s+', forwards): name = name.lower() forward.add(name) output("Which nicks/channels should the requests be forwarded to?") output("Is case insensitive and wildcards '*' and '?' are accepted.") channels_i = anything("Separate types by spaces or commas:", default=', '.join( Bantracker.request.forward._default)) channels = set([]) for name in re.split(r',?\s+', channels_i): name = name.lower() channels.add(name) review = getReviewTime() else: type = Bantracker.request.type._default ignore = Bantracker.request.ignore._default forward = Bantracker.request.forward._default channels = Bantracker.request.forward.channels._default review = Bantracker.request.review._default Bantracker.enabled.setValue(enabled) Bantracker.database.setValue(database) Bantracker.bansite.setValue(bansite) Bantracker.request.setValue(request) Bantracker.request.type.setValue(type) Bantracker.request.ignore.setValue(ignore) Bantracker.request.forward.setValue(forward) Bantracker.request.forward.channels.setValue(channels) Bantracker.request.review.setValue(review) # Create the initial database db_file = Bantracker.database() if not db_file: db_file = conf.supybot.directories.data.dirize('bans.db') output("supybot.plugins.Bantracker.database will be set to %r" % db_file) Bantracker.database.setValue(db_file) if os.path.exists(db_file): return output("Creating an initial database in %r" % db_file) con = sqlite.connect(db_file) cur = con.cursor() try: cur.execute("""CREATE TABLE 'bans' ( id INTEGER PRIMARY KEY, channel VARCHAR(30) NOT NULL, mask VARCHAR(100) NOT NULL, operator VARCHAR(30) NOT NULL, time VARCHAR(300) NOT NULL, removal DATETIME, removal_op VARCHAR(30), log TEXT )""") #""" cur.execute("""CREATE TABLE comments ( ban_id INTEGER, who VARCHAR(100) NOT NULL, comment MEDIUMTEXT NOT NULL, time VARCHAR(300) NOT NULL )""") #""" cur.execute("""CREATE TABLE sessions ( session_id VARCHAR(50) PRIMARY KEY, user MEDIUMTEXT NOT NULL, time INT NOT NULL )""") #""" cur.execute("""CREATE TABLE users ( username VARCHAR(50) PRIMARY KEY, salt VARCHAR(8), password VARCHAR(50) )""") #""" except: con.rollback() raise else: con.commit() finally: cur.close() con.close()