Ejemplo n.º 1
0
def generate(table_name, num_rolls=1):
    """
    Generate N items from the given table.
    Assumes DATA_DIR has been set.
    Return a list of item names (str).
    """
    trace('generate')

    table = load_table(table_name)
    if table is None:
        raise ValueError('Invalid table: ' + table_name)

    values = list()
    if table['type'] == 'items':
        for i in range(num_rolls):
            item_name = lookup_items(table)
            values.append(item_name)
    elif table['type'] == 'table-list':
        for i in range(num_rolls):
            item_list = lookup_table_list(table)
            values.extend(item_list)
    elif table['type'] == 'tables':
        for i in range(num_rolls):
            item_name = lookup_tables(table)
            values.append(item_name)
    else:
        raise ValueError('Unknown table type: ' + table['type'])

    return values
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
def list_tables(*args):
    """
    Return a list of tables in DATA_DIR.
    Any file in DATA_DIR with a json or yaml extension is considered to be
    a table.
    """
    trace('list_tables')
    files = list()
    for file_name in os.listdir(DATA_DIR):
        parts = file_name.split('.')
        if parts[-1] == 'json' or parts[-1] == 'yaml':
            files.append('.'.join(parts[:-1]))
    return files
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
def get_chance(column):
    """
    Get the optional chance value from a table-list column.
    Default is 100, if not present.
    :param column: dict
    :return: number in [1, 100]
    """
    trace('get_chance')
    value = 100
    if 'chance' in column:
        chance = column['chance']
        if chance > 0 or chance <= 100:
            value = chance
        else:
            ValueError('column chance out of range: {}'.format(chance))
    return value
Ejemplo n.º 7
0
def random_row(table):
    """
    Return a random row dict from a table.
    """
    trace('random_row')
    total_weight = table['total-weight']
    item_index = randint(1, total_weight)
    weight_total = 0
    for row in table['rows']:
        row_weight = row['weight'] if 'weight' in row else 1
        weight_total += row_weight
        if item_index <= weight_total:
            return row
    raise RuntimeError(
        'row index out of bounds: index {}, total_weight {}'.format(
            item_index, total_weight))
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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'])
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
def load(table_name=None):
    """
    Load a table from DATA_DIR, return Python.
    """
    trace('load')
    if table_name is None:
        raise ValueError('table_name is None')

    table_file = os.path.join(DATA_DIR, table_name + '.yaml')
    if os.path.exists(table_file):
        import yaml
        with open(table_file, 'r') as f:
            return yaml.load(f)

    table_file = os.path.join(DATA_DIR, table_name + '.json')
    if os.path.exists(table_file):
        import json
        with open(table_file, 'r') as f:
            return json.load(f)

    raise ValueError("Table not found: " + table_name)
Ejemplo n.º 14
0
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'])