def used(bot, trigger): """Fetches a used trigger from the Weaver Dice trigger spreadsheet.""" #Use the provided trigger if there is one if trigger.group(2): #Make sure the trigger number a valid integer if not is_integer(trigger.group(2)): return say(bot,"Please provide a valid trigger number.") #Make sure the trigger number is in range trigger_index = int(trigger.group(2)) if trigger_index>len(shared_var['used_list'])+1 or trigger_index < 2: return say(bot,"Used trigger '"+str(trigger_index)+"' is out of range.") t = shared_var['used_list'][trigger_index-2] return mute_say(bot, trigger, trigger.nick + ' ' + t['prefix'] + t['text'], 6) else: if trigger.is_privmsg is False: delay=get_delay_timer('trigger') if delay>0: return say(bot,"ZzZz...["+str(delay)+"s]") set_delay_timer('trigger',30) t = random.choice([x for x in shared_var['used_list'] if x['blank'] == False]) return mute_say(bot, trigger, trigger.nick + ' ' + t['prefix'] + t['text'], 6)
def luck_specific(bot, trigger): """Returns a power/life perk or flaw.""" options = [ 'life perk', 'life flaw', 'life advantage', 'life disadvantage', 'power perk', 'power flaw', 'power advantage', 'power disadvantage', 'perk life', 'perk power', 'advantage life', 'advantage power', 'flaw life', 'flaw power', 'disadvantage life', 'disadvantage power', 'life', 'power', 'perk', 'flaw', 'advantage', 'disadvantage' ] string = trigger.group(1).lower() if trigger.group(2): string = string + ' ' + trigger.group(2).lower() for i in range(0, len(options)): if string.startswith(options[i]): option = options[i] break string = string[len(option):].strip() option = option.replace('disadvantage', 'flaw') option = option.replace('advantage', 'perk') option = option.title() if option.startswith("Perk") or option.startswith("Flaw"): option = ' '.join(reversed(option.split())) if string: if is_integer(string): if option in [ 'Life Perk', 'Life Flaw', 'Power Perk', 'Power Flaw' ]: data = int(string) if data > 1 and data < 80: return say( bot, trigger.nick + ' ' + shared_var['luck_list'][option][data - 2]['text'], 8) else: return say(bot, 'Please provide a number 2 - 79.', 3) else: return say(bot, 'Please be more specific.', 3) else: return luck_keyword(bot, trigger, string, option) else: if option == 'Perk': option = random.choice(['Life Perk', 'Power Perk']) elif option == 'Flaw': option = random.choice(['Life Flaw', 'Power Flaw']) elif option == 'Life': option = random.choice(['Life Perk', 'Life Flaw']) elif option == 'Power': option = random.choice(['Power Perk', 'Power Flaw']) selection = random.choice([ x for x in shared_var['luck_list'][option] if x['blank'] == False ])['text'] return mute_say(bot, trigger, trigger.nick + ' ' + selection, 8)
def luck(bot, trigger): """Rolls 2dx (default 1d4, 1d4) and fetches the relevant perks and/or flaws from the detail sheet.""" die = [4, 4] if trigger.group(2): if is_integer(trigger.group(2)): sides = int(trigger.group(2)) die = [4, sides] else: return luck_keyword(bot, trigger) if (sides < 4): return say(bot, "The dice must have at least 4 sides.") delay = get_delay_timer('luck') if delay > 0: return say(bot, "ZzZz...[" + str(delay) + "s]") set_delay_timer('luck', 15) result = [] roll = [] for x in range(0, 2): selection = ['None'] * die[x] selection[0] = 'Life Flaw' selection[1] = 'Power Flaw' selection[die[x] - 2] = 'Life Perk' selection[die[x] - 1] = 'Power Perk' r = random.randint(1, die[x]) roll.append(str(r) + "/" + str(die[x])) if selection[r - 1] is not 'None': selection = random.choice([ x for x in shared_var['luck_list'][selection[r - 1]] if x['blank'] == False ])['text'] result.append(selection) roll_string = '[' + ', '.join(roll) + ']' if result: result[0] = trigger.nick + ' ' + roll_string + ' ' + result[0] mute_say(bot, trigger, result, 20) else: return say(bot, trigger.nick + ' ' + roll_string + ' [None]')
def card(bot, trigger): """Documentation can be found here: https://goo.gl/6icZb5""" if trigger.group(2): data = trigger.group(2).split(' ') if is_integer(data[-1]): cards(bot, [{ 'key': ' '.join(data[:-1]), 'pre': '', 'card': int(data[-1]) }]) elif data[-1][0] == '"' and data[-1][-1] == '"': cards(bot, [{ 'key': ' '.join(data[:-1]), 'pre': '', 'card': data[-1][1:-1].lower() }]) else: cards(bot, [{'key': trigger.group(2), 'pre': ''}]) else: return say(bot, "Please specify a card.")
def claim(bot, trigger): """Moves a trigger to the used section of the Weaver Dice trigger spreadsheet. The square brackets around Player_Name should be included.""" if trigger.sender.lower() != '#weaverdice': return say(bot,'Please perform claims in #Weaverdice.') #Validate command if not trigger.group(2): return say(bot,"Specify a trigger from 1-100.") data = shared_var['re_claim'].match(trigger.group(2)) if data.group(1): if is_integer(data.group(1)): trigger_index = int(data.group(1)) else: return say(bot,"Invalid trigger index.") else: return say(bot,"Specify a trigger from 1-100.") game = data.group(2).strip() if data.group(2) else '?' claimer = data.group(3).strip()[1:-1] if data.group(3) else trigger.nick description = data.group(4).strip() if data.group(4) else '' delay=get_delay_timer('claim') if delay>0: return say(bot,"ZzZz...["+str(delay)+"s]") set_delay_timer('claim',15) #Initialize spreadsheet spreadsheet = google_sheet_get(shared_var['trigger_sheet']) trigger_worksheet = spreadsheet.worksheet('Triggers') trigger_worksheet_height = trigger_worksheet.row_count used_worksheet = spreadsheet.worksheet('Used') used_worksheet_height = used_worksheet.row_count say(bot,'Claiming trigger. This might take a moment...') #Sort through trigger list and fetch the trigger string/author. Might as well grab the whole thing so the trigger cache can be updated. triggers = [["",""] for y in range(trigger_worksheet_height)] cell_list = trigger_worksheet.range('A1:B'+str(trigger_worksheet_height)) for cell in cell_list: triggers[cell.row-1][cell.col-1] = cell.value trigger_string = triggers[trigger_index-1][0] if not trigger_string: return say(bot,"...Trigger '"+str(trigger_index)+"' is blank.") trigger_string=trigger_string.encode('utf-8', 'ignore').decode('utf-8') trigger_author = triggers[trigger_index-1][1] if not trigger_author: trigger_author="?" else: trigger_author=trigger_author.encode('utf-8', 'ignore').decode('utf-8') #Sort through used trigger list and find blank spot. Grab the whole thing so the cache can be updated. used_triggers = used_worksheet.col_values(2) used_triggers += [None] * (used_worksheet_height - len(used_triggers)) update_used_cache(used_triggers[1:]) #Find blank spot to append used trigger. If none is available, append a row. try: slot = used_triggers[1:].index(None)+2 used_worksheet.update_cell(slot, 1, game) used_worksheet.update_cell(slot, 2, trigger_string) used_worksheet.update_cell(slot, 3, trigger_author) used_worksheet.update_cell(slot, 4, claimer) used_worksheet.update_cell(slot, 5, description) shared_var['used_list'][slot-2] = { 'prefix': '{'+str(slot)+'}: ', 'text': trigger_string.encode('utf-8', 'ignore').decode('utf-8'), 'blank': False } except ValueError: used_worksheet.append_row([game,trigger_string,trigger_author,claimer,description]) shared_var['used_list'].append({ 'prefix': '{'+str(used_worksheet_height+1)+'}: ', 'text': trigger_string.encode('utf-8', 'ignore').decode('utf-8'), 'blank': False }) slot = used_worksheet_height+1 #Update trigger list triggers.pop(trigger_index-1) triggers.append([""]*2) for cell in cell_list: cell.value = triggers[cell.row-1][cell.col-1] if not cell.value: cell.value="" trigger_worksheet.update_cells(cell_list) #Update trigger cache update_trigger_cache([row[0] for row in triggers]) #Fin return say(bot,'...Trigger ['+str(trigger_index)+'] moved to Used Trigger slot {'+str(slot)+'}.')
def cape(bot, trigger): """Searches the cape database for a name or ID.""" ids = [] if trigger.group(2): if is_integer(trigger.group(2)): ids = [(int(trigger.group(2)), 0)] elif trigger.group(2)[0] == '#' and is_integer(trigger.group(2)[1:]): ids = [(int(trigger.group(2)[1:]), 0)] else: key = trigger.group(2).lower() ids = [] for id, cape in enumerate(shared_var['capes']): # PERFECT MATCH if any(key == alias for alias in cape['s_name']): ids.append((id, 0)) continue if any(key == alias for alias in cape['s_alias'][1:]): ids.append((id, 1)) continue if key == cape['s_alias'][0]: ids.append((id, 2)) continue # SEMI-FUZZY MATCH 1 if key in [ words for segments in cape['s_name'] for words in segments.split() ]: ids.append((id, 3)) continue if key in [ words for segments in cape['s_alias'][1:] for words in segments.split() ]: ids.append((id, 4)) continue if key in cape['s_alias'][0].split(): ids.append((id, 5)) continue # SEMI-FUZZY MATCH 2 if any(alias.startswith(key) for alias in cape['s_name']): ids.append((id, 6)) continue if any(alias.startswith(key) for alias in cape['s_alias'][1:]): ids.append((id, 7)) continue if cape['s_alias'][0].startswith(key): ids.append((id, 8)) continue # FUZZY MATCH if any(key in alias for alias in cape['s_name']): ids.append((id, 9)) continue if any(key in alias for alias in cape['s_alias'][1:]): ids.append((id, 10)) continue if key in cape['s_alias'][0]: ids.append((id, 11)) continue if ids: ids.sort(key=lambda tup: tup[1]) #ID cape = shared_var['capes'][ids[0][0]] #NAME message = '[#' + str(ids[0][0]) + '] ' + cape['name'] #ALIASES if [x for x in cape['alias'] if x]: message = message + ' (AKA ' + ', '.join( [x for x in cape['alias'] if x]) + ')' #OWNER + NPC/PC message = message + ' is' if cape['owner']: if cape['owner'].endswith(('s', 'z')): message = message + ' ' + cape['owner'] + "' " else: message = message + ' ' + cape['owner'] + "'s " if cape['character type']: message = message + cape['character type'] else: message = message + 'character' else: if cape['character type']: if cape['character type'].lower( ) == 'NPC' or cape['character type'].lower().startswith( ('a', 'e', 'i', 'o', 'u')): message = message + ' an ' + cape['character type'] else: message = message + ' a ' + cape['character type'] else: message = message + ' a character' #CAMPAIGN if cape['campaign']: message = message + ' from ' + cape['campaign'] + '.' else: message = message + ' from an unknown campaign.' #EVERYTHING ELSE for key in ('alignment', 'status', 'affiliation', 'classification', 'power', 'notes'): if cape[key]: message = message + ' | ' + key.upper() + ': ' + cape[key] #OUTPUT message = re.sub('(?i)wildbow', "'bow", message) say(bot, message) if len(ids) > 1: say( bot, 'See also: ' + ', '.join(shared_var['capes'][id[0]]['name'] + ' [#' + str(id[0]) + ']' for id in ids[1:10])) return else: return say(bot, 'No cape found.')
def cache_cards(bot): bot.memory['card_help'] = {} shared_var['cards'] = {} shared_var['cards_by_keyword'] = {} shared_var['cards_by_group'] = {} shared_var['cards_by_name'] = {} shared_var['card_commands'] = [] shared_var['card_sub_commands'] = [] spreadsheet = google_sheet_get(shared_var['sheet']) worksheets = spreadsheet.worksheets() id = 0 for worksheet in worksheets: values = worksheet.get_all_values() key_group = worksheet.title.lower() key_group = '' if key_group == 'main' else key_group + ' ' for row in values: key_deck = row[0].lower() if key_group == '' and key_deck != 'commands': shared_var['card_sub_commands'].append(key_deck) for col in row[1:]: if col.strip(): help = '' tmp_card = { 'text': col, 'cards': [], 'names': [], 'inline_cards': [], 'odds': 1 } #Inline Cards match = shared_var['re_inline_cards'].search( tmp_card['text']) number = 1 while match and number < 50: tmp_card['inline_cards'].append( [x.strip() for x in match.group(1).split('|')]) tmp_card['text'] = tmp_card['text'][:match.start( 1)] + str(number) + tmp_card['text'][match.end(1):] match = shared_var['re_inline_cards'].search( tmp_card['text']) number = number + 1 #Sub Cards match = shared_var['re_cards'].search(tmp_card['text']) number = 0 while match and number < 50: sub_card_data = match.group(1).split('|') sub_card_data += [''] * (3 - len(sub_card_data)) subcard = {'keyword': [], 'preface': [], 'tags': []} if sub_card_data[0].strip(): subcard['keyword'] = [ x.strip() for x in sub_card_data[0].split(',') ] if sub_card_data[1].strip(): subcard['preface'] = [ x.strip() for x in sub_card_data[1].split(',') ] if sub_card_data[2].strip(): subcard['tags'] = [ x.strip() for x in sub_card_data[2].split(',') ] tmp_card['cards'].append(subcard) tmp_card['text'] = tmp_card['text'][:match.start( )] + tmp_card['text'][match.end():] match = shared_var['re_cards'].search(tmp_card['text']) number = number + 1 #Help match = shared_var['re_card_help'].search(tmp_card['text']) if match: help = match.group(1).strip() tmp_card['text'] = tmp_card['text'][:match.start( )] + tmp_card['text'][match.end():] #Names match = shared_var['re_card_names'].search( tmp_card['text']) number = 0 while match and number < 50: tmp_card['names'].append( match.group(1).strip().lower()) tmp_card['text'] = tmp_card['text'][:match.start( )] + tmp_card['text'][match.end():] match = shared_var['re_card_names'].search( tmp_card['text']) number = number + 1 #Odds match = shared_var['re_card_odds'].search(tmp_card['text']) number = 0 while match and number < 50: if is_integer(match.group(1).strip().lower()): tmp_card['odds'] = int( match.group(1).strip().lower()) tmp_card['text'] = tmp_card['text'][:match.start( )] + tmp_card['text'][match.end():] match = shared_var['re_card_odds'].search( tmp_card['text']) number = number + 1 tmp_card['text'] = tmp_card['text'].strip() tmp_card['id'] = id id = id + 1 #Group + Keyword if key_group + key_deck in shared_var['cards']: shared_var['cards'][key_group + key_deck].append(tmp_card) else: shared_var['cards'][key_group + key_deck] = [tmp_card] #Keyword if key_deck in shared_var['cards_by_keyword']: shared_var['cards_by_keyword'][key_deck].append( tmp_card) else: shared_var['cards_by_keyword'][key_deck] = [tmp_card] #Group if key_group.strip() in shared_var['cards_by_group']: shared_var['cards_by_group'][key_group.strip()].append( tmp_card) else: shared_var['cards_by_group'][key_group.strip()] = [ tmp_card ] #Name for name in tmp_card['names']: if key_group + key_deck + ' ' + name in shared_var[ 'cards_by_name']: shared_var['cards_by_name'][key_group + key_deck + ' ' + name].append(tmp_card) else: shared_var['cards_by_name'][key_group + key_deck + ' ' + name] = [tmp_card] #Commands if key_group + key_deck == 'commands': shared_var['card_commands'] = shared_var[ 'card_commands'] + tmp_card['names'] if help: for name in tmp_card['names']: bot.memory['card_help'][name] = help bot.memory['card_commands'] = shared_var['card_commands']
def process_card(card, prefix=[]): global recursions recursions = recursions + 1 if recursions > recursion_limit: return {'output': '', 'queue': []} new_queue = [] text = card['text'] #inline cards for index, value in enumerate(card['inline_cards']): keep = value[0].lower().startswith('keep!') if keep: value[0] = value[0][5:] subdeck = get_deck(value) if not subdeck: return say(bot, "Invalid card '" + ' | '.join(value) + "'") else: options = [x for x in subdeck if x['id'] not in drawn_cards] if not options: options = subdeck # Draw card by odds r = random.uniform(0, sum(item['odds'] for item in options)) s = 0.0 for x in options: subcard = x s += x['odds'] if r < s: break response = process_card(subcard) if not keep: drawn_cards.append(subcard['id']) insert = response['output'] if value[0][0].isupper(): insert = insert[:1].upper() + insert[1:] text = text.replace('{' + str(index + 1) + '}', insert) text = text.replace('{!' + str(index + 1) + '}', insert.capitalize()) #a(n) replacement match = shared_var['re_card_an'].search(text) number = 0 while match and number < 50: article = indefinite_article(match.group(2)) text = text[:match.start(1)] + article + text[match.end(1):] match = shared_var['re_card_an'].search(text) #output output = ''.join(['[' + x + '] ' for x in prefix]) + text #additional cards sub_count = 0 for subcard in card['cards']: show = True card_index = None primary = False if count > 0 else True sep = False ending = False keep = False for tag in subcard['tags']: negate = False if tag and tag[0] == '!': negate = True t = tag[1:] else: t = tag #Draw Order Rejection if t in positions: if positions.index(t) >= count: if negate: show = False elif not negate: show = False #Sub-Draw Order Rejection if is_integer(t): if sub_count >= int(t): if not negate: show = False elif negate: show = False #Percentage if t[-1] == '%' and is_float(t[:-1]): target = float(t[:-1]) if random.uniform(0, 100.0) > target: if not negate: show = False elif negate: show = False #Card Index if t[0] == '#': if is_integer(t[1:]): card_index = int(t[1:]) else: card_index = t[1:] #Separator if t == 'S': sep = not negate #Primary if t == 'P': primary = not negate #Primary if t == 'K': keep = not negate #Add to Queue if show: if sep and (count > 1 or len(new_queue) > 0): new_queue.append(separator) new_queue.append({ 'key': subcard['keyword'], 'pre': subcard['preface'], 'card': card_index, 'primary': primary, 'keep': keep }) sub_count = sub_count + 1 return {'output': output, 'queue': new_queue}