def get_table_name(table_name): """ Returns a table's name (value from 'name' key) or table_name """ value = table_name try: value = load_table(table_name)['name'] except: debug('cannot get table name:' + table_name) return value
def set_data_dir(data_dir): """ Set the data directory (DATA_DIR) Raises FileNotFoundError """ trace('set_data_dir') data_dir = os.path.realpath(data_dir) if os.path.isdir(data_dir): debug('Setting DATA_DIR to', data_dir) global DATA_DIR DATA_DIR = data_dir else: raise FileNotFoundError(data_dir)
def lookup_tables(table): """ Select a table from a tables table. Returns an item name. """ trace('lookup_tables') debug('lookup_tables', table['name']) #import pdb; pdb.set_trace() row = random_row(table) table_name = row['table'] subtable = load_table(table_name) if subtable['type'] == 'items': return lookup_items(subtable) elif subtable['type'] == 'tables': return lookup_tables(subtable)
def check_weights(table): """ Check that row weights add up to total-weight. Raise ValueError if not equal """ trace('check_weights') if 'total-weight' in table: total_weight = table['total-weight'] weight_total = 0 for row in table['rows']: row_weight = row['weight'] if 'weight' in row else 1 weight_total += row_weight debug('table', table['name'], 'weight', weight_total, 'of', total_weight) if total_weight != weight_total: raise ValueError("{}: row weights don't add up: {} of {}".format( table['name'], weight_total, total_weight)) else: debug('not a weighted table', table['name'])
def load_table(table_name): """ Load a table, cache the result. Returns a table (dict) Raises ValueError """ global _tables trace('load_table') table = None if table_name in _tables: table = _tables[table_name] debug('cache hit', table_name) else: table = tablator.data.load(table_name) check_weights(table) _tables[table_name] = table debug('loaded', table_name) return table
def roll_quantity(quantity): """ Roll some dice "3d6+6x10" -> ((3 x 1-6) + 6) x 10 -> 160 """ trace("roll_quantity") result = MATCHER.fullmatch(quantity) if result is None: debug('no match', quantity) value = quantity else: groups = result.groups() number = int(groups[0]) sides = int(groups[1]) if groups[2] is not None: adjustment = int(groups[2]) else: adjustment = 0 if groups[3] is not None: multiplier = int(groups[3]) else: multiplier = 1 debug('number', number, 'sides', sides, 'adjustment', adjustment, 'multiplier', multiplier) n = 0 for i in range(number): n += randint(1, sides) value = (n + adjustment) * multiplier debug('value', value) return str(value)
def is_table(table_name=None): """ Search DATA_DIR for a file called 'table_name.json' or 'table_name.yaml'. Returns True if found, False is not """ trace('is_table') if table_name is None: raise ValueError('table_name is None') for file_name in os.listdir(DATA_DIR): debug('file_name', file_name) if file_name == table_name + '.yaml': debug('found: ', DATA_DIR, '/', file_name) return True if file_name == table_name + '.json': debug('found: ', DATA_DIR + '/' + file_name) return True debug('not found: ', table_name, 'in', DATA_DIR) return False
def lookup_table_list(table): """ The top-level table is a list of tables. Roll once on each table in the list. Returns a list of item names. Each table item has: name: the name of the item or table chance: roll less than or equal to this value for item to be generated table: if None, use "quantity + name", else roll on table quantity: number of items (bunch) or rolls on table """ trace('lookup_table_list') debug('table name', table['name']) values = list() columns = table['columns'] for column in columns: chance = get_chance(column) roll = randint(1, 100) if roll > chance: debug('skip', column['name'], roll, 'vs', column['chance']) continue # failed chance roll if column['table'] is None: quantity = roll_quantity(column['quantity']) name = column['name'] values.append('{} {}'.format(quantity, name)) else: quantity = roll_quantity(column['quantity']) table_name = column['table'] for i in range(int(quantity)): debug('rolling on table', table_name) subtable = load_table(table_name) if subtable['type'] == 'items': item_name = lookup_items(subtable) values.append(item_name) elif subtable['type'] == 'tables': item_name = lookup_tables(subtable) values.append(item_name) elif subtable['type'] == 'table-list': item_list = lookup_table_list(subtable) values.extend(item_list) else: raise ValueError('invalid table type: ' + subtable['type']) return values
def lookup_items(table): """ Do a lookup in an 'items' table, return the result. Returns a string. Raises ValueError. """ trace('lookup_item') debug('lookup_item', table['name'], table['total-weight'], len(table['rows'])) item = random_row(table) item_name = item['name'] subitem = None quantity = None if 'subtable' in item: debug('roll on subtable', item['subtable']) subtable = load_table(item['subtable']) if subtable['type'] == 'items': subitem = lookup_items(subtable) elif subtable['type'] == 'tables': subitem = lookup_tables(subtable) else: raise ValueError('invalid table type: ' + subtable['type']) # if len(subitem) == 0: # subitem = None if 'quantity' in item: debug('roll quantity', item['quantity']) quantity = roll_quantity(item['quantity']) if quantity == "1": quantity = None elif 'value' in item: # quantity and value are mutually exclusive assert (quantity is None) quantity = roll_quantity(item['value']) + " gp" if subitem is not None and quantity is not None: item_name = '{} ({}, {})'.format(item['name'], subitem, quantity) elif subitem is not None: item_name = '{} ({})'.format(item['name'], subitem) elif quantity is not None: item_name = '{} ({})'.format(item['name'], quantity) else: item_name = '{}'.format(item['name']) return item_name
def print_plain(table_name): """ Print a table as plain text to the standard output. """ trace('print_plain') table = load_table(table_name) index = 1 if table['type'] == 'items': # A table of items debug('print "items" table') dice = str(table['total-weight']) if dice == '100': dice = '%' print(' d{}'.format(dice), table['name'], sep='\t') print('-----', '-' * len(table['name']), sep='\t') # TODO Include quantity, if present for row in table['rows']: wt = row['weight'] if 'weight' in row else 1 s = None if wt > 1: s = "{:02d}-{:02d}\t{}".format(index, index + wt - 1, row['name']) else: s = "{:02d}\t{}".format(index, row['name']) index += wt print(s) print() elif table['type'] == 'tables': # A table of tables debug('print "tables" table') dice = str(table['total-weight']) if dice == '100': dice = '%' print(' d{}'.format(dice), table['name'], sep='\t') print('-----', '-' * len(table['name']), sep='\t') for row in table['rows']: table_name = get_table_name(row['table']) wt = row['weight'] if 'weight' in row else 1 s = None if wt > 1: s = "{:02d}-{:02d}\t{}".format(index, index + wt - 1, table_name) else: s = "{:02d}\t{}".format(index, table_name) index += wt print(s) print() elif table['type'] == 'table-list': # A list of tables, roll on each table debug('print "table-list" table') print(table['name']) print('-' * len(table['name'])) for column in table['columns']: chance = '{0:3d}%'.format(get_chance(column)) quantity = column['quantity'] name = column['name'] if column['table'] is None: print(chance, quantity, name) else: table_name = get_table_name(column['table']) print(chance, quantity, table_name) print() else: debug('unknown table type', table['type'])