コード例 #1
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
    def __init__(self):
        super().__init__(5, 'Proficiencies')
        self.set_subtitle('Choose available proficiencies')

        self.proficiency_table = [row for row in DbQuery.getTable('Items') if row['Is_Proficiency'].lower() == "yes"]
        self.class_table = DbQuery.getTable('Classes')
        self.race_table = DbQuery.getTable('Races')
        self.slots_remaining = 0
        self.orig_proficiencies = []
        self.specialised_list = []
        self.double_specialised_list = []
        self.shadow_list = None

        prof_data = {
            'fill_avail': self.fill_proficiencies,
            'slots': self.get_proficiency_slots,
            'slots_name': 'Proficiency',
            # 'category_field': 'Damage_Type',
            # 'category_callback': self.get_category_tab_name,
            'tool_tip': self.get_tool_tip,
            'add': self.add_proficiency,
            'remove': self.remove_proficiency,
        }
        proficiencies = Widget('Proficiencies', 'DualList', data=prof_data)

        self.add_row([proficiencies, ])
コード例 #2
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
 def fill_proficiencies( self ):
     self.specialised_list = []
     self.double_specialised_list = []
     class_dict = self.fields['Class']
     race_dict = self.fields['Race']
     item_dict_list = [ i for i in DbQuery.getTable( 'Items' ) if i['Is_Proficiency'] == 'yes' ]
     if 'classes' in class_dict:
         wp_list = [ cl['Weapons_Permitted' ] for cl in class_dict[ 'classes' ] ]
         weapons_permitted = self.race_wp( wp_list, race_dict['unique_id'], item_dict_list )
     else:
         weapons_permitted = [ weapon.strip().lower() for weapon in class_dict['Weapons_Permitted'].split( ',' ) ]
     item_list = []
     for item_dict in item_dict_list:
         item_tuple = ( item_dict['Name'], item_dict )
         damage_type_list = [ damage_type.strip().lower() for damage_type in item_dict['Damage_Type'].split( ',' ) ]
         if 'any' in weapons_permitted:
             item_list.append( item_tuple )
         elif any( weapon in item_dict['Name'].lower() for weapon in weapons_permitted ):
             item_list.append( item_tuple )
         elif [ i for i in weapons_permitted if i in damage_type_list ]:
             item_list.append( item_tuple )
         elif 'single-handed swords (except bastard swords)' in weapons_permitted:
             if item_dict['unique_id'].startswith( 'sword' ) and \
             'both-hand' not in damage_type_list and 'two-hand' not in damage_type_list:
                 item_list.append( item_tuple )
     return item_list
コード例 #3
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
 def initialize_page(self, fields, pages, external_data):
     spells_table = DbQuery.getTable('Spells')
     pc = external_data['Character List Current']
     wizard_category = pages['Level Up'].wizard_category
     other_spellcaster_category = pages['Level Up'].other_spellcaster_category
     if wizard_category:
         class_name = wizard_category['Name']
         spell_type = wizard_category['Primary_Spell_List'].replace('_', ' ').title()
     else:
         class_name = other_spellcaster_category['Name']
         spell_type = other_spellcaster_category['Primary_Spell_List'].replace('_', ' ').title()
     if spell_type != class_name:
         class_name = spell_type
     self.meta_row_type = 'DailySpells'
     if external_data['Daily Spells 2'] and\
             external_data['Daily Spells 2'][0]['Type'].replace('_', ' ').title() == class_name:
         self.meta_row_type = 'DailySpells2'
     spell_ids = []
     for meta_row in pc['Characters_meta']:
         if meta_row['Type'] == self.meta_row_type:
             spell_ids.append(meta_row['Entry_ID'])
     spells = []
     for spell in spells_table:
         if spell['spell_id'] in spell_ids:
             for _ in range(spell_ids.count(spell['spell_id'])):
                 spells.append(spell)
     self.set_subtitle('Choose Daily {} Spells'.format(class_name))
     return {self.field_name: spells}
コード例 #4
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
    def get_available_races(self):
        race_dict_list = DbQuery.getTable('Races')

        #print 'STR: ' + self.fields['STR']
        if self.fields['STR']:
            attribute_dict = {
                attr: int(self.fields[attr])
                for attr in get_attribute_names()
            }
        else:
            attribute_dict = None

        if attribute_dict is None:
            return [(race['Name'], race) for race in race_dict_list]

        l = []
        for race in race_dict_list:
            allowed = True
            for attr in get_attribute_names():
                attr_cap = attr.capitalize()
                min_score = race['Minimum_' + attr_cap]
                max_score = race['Maximum_' + attr_cap]
                if not min_score <= attribute_dict[attr] <= max_score:
                    allowed = False
            if allowed:
                l.append((race['Name'], race))

        return l
コード例 #5
0
ファイル: LevelUp.py プロジェクト: lowhrtz/gm
    def initialize_page( self, fields, pages, external_data ):
        pc = external_data['Character List Current']
        classes = pc['Classes'].split( '/' )
        level = str( pc['Level'] ).split( '/' )
        self.ready_list = ready_to_level_up( pc )
        self.ready_dict_list = [ cl for cl in DbQuery.getTable( 'Classes' ) if cl['unique_id'] in self.ready_list ]
        self.wizard_category = False
        self.priest_category = False
        self.proficiency_slots_available = 0
        for cl in self.ready_dict_list:
            if cl['Category'] == 'wizard':
                self.wizard_category = cl
            if cl['Category'] == 'priest':
                self.priest_category == cl
            wpa = cl['Weapon_Proficiency_Advancement'].split('/')
            slots = int( wpa[0] )
            per_level = int( wpa[1] )
            pc_level = int( level[ classes.index( cl['unique_id'] ) ] )
            if pc_level % per_level == 0:
                self.proficiency_slots_available = slots

        if self.wizard_category:
            self.next_page_id = pages['Spellbook'].get_page_id()

        elif self.proficiency_slots_available:
            self.next_page_id = pages['Proficiencies'].get_page_id()

        elif self.ready_list:
            self.next_page_id = pages['Review'].get_page_id()

        else:
            self.next_page_id = -1
            return { 'Intro Text': 'There are no classes ready to level up for this character!',
                     'Intro Text2': '' }
コード例 #6
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
def ready_to_level_up(pc):
    classes_meta = DbQuery.getTable('Classes_meta')
    classes = pc['Classes'].split('/')
    xp = str(pc['XP']).split('/')
    level = str(pc['Level']).split('/')
    level_up_classes = []
    for i, cl in enumerate(classes):
        cl_xp = int(xp[i])
        cl_level = int(level[i])
        xp_table = [row for row in classes_meta if row['class_id'] == cl and row['Type'] == 'xp table']
        each = None
        for j, row in enumerate(xp_table):
            if row['Level'].lower() == 'each':
                each = j
        if each is not None:
            each = xp_table.pop(each)

        xp_table.sort(key=lambda x: int(x['Level']))
        top_row = xp_table[len(xp_table) - 1]
        top_row_level = int(top_row['Level'])
        if cl_level > top_row_level:
            levels_past_top_row = (cl_xp - top_row['XP']) // each['XP']
            if top_row_level + levels_past_top_row > cl_level:
                level_up_classes.append(cl)
        else:
            for j, row in enumerate(xp_table):
                if int(row['Level']) == cl_level + 1:
                    if cl_xp >= row['XP']:
                        level_up_classes.append(cl)
                    break

    return level_up_classes
コード例 #7
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def get_available_races( self ):
        race_dict_list = DbQuery.getTable( 'Races' )

        #print 'STR: ' + self.fields['STR']
        if self.fields['STR']:
            attribute_dict = { attr : int( self.fields[attr] ) for attr in get_attribute_names() }
        else:
            attribute_dict = None

        if attribute_dict is None:
            return [ ( race['Name'], race ) for race in race_dict_list ]

        l = []
        for race in race_dict_list:
            allowed = True
            for attr in get_attribute_names():
                attr_cap = attr.capitalize()
                min_score = race[ 'Minimum_' + attr_cap ]
                max_score = race[ 'Maximum_' + attr_cap ]
                if not min_score <= attribute_dict[attr] <= max_score:
                    allowed = False
            if allowed:
                l.append( ( race['Name'], race ) )

        return l
コード例 #8
0
ファイル: LevelUp.py プロジェクト: lowhrtz/gm
def ready_to_level_up( pc ):
    classes_meta = DbQuery.getTable( 'Classes_meta' )
    classes = pc['Classes'].split( '/' )
    xp = str( pc['XP'] ).split( '/' )
    level = str( pc['Level'] ).split( '/' )
    level_up_classes = []
    for i, cl in enumerate( classes ):
        cl_xp = int( xp[i] )
        cl_level = int( level[i] )
        xp_table = [ row for row in classes_meta if row['class_id'] == cl and row['Type'] == 'xp table' ]
        each = None
        for j, row in enumerate( xp_table ):
            if row['Level'].lower() == 'each':
                each = j
        if each is not None:
            each = xp_table.pop( each )

        xp_table.sort( key=lambda x: int( x['Level'] ) )
        top_row = xp_table[ len( xp_table ) - 1 ]
        top_row_level = int( top_row['Level'] )
        if cl_level > top_row_level:
            levels_past_top_row = ( cl_xp - top_row['XP'] ) // each['XP']
            if top_row_level + levels_past_top_row > cl_level:
                level_up_classes.append( cl )
        else:
            for j, row in enumerate( xp_table ):
                if int( row['Level'] ) == cl_level + 1:
                    if cl_xp >= row['XP']:
                        level_up_classes.append( cl )
                    break

    return level_up_classes
コード例 #9
0
ファイル: WebApp.py プロジェクト: lowhrtz/PyGM
def get_character(environ):
    remote_addr = environ['REMOTE_ADDR']
    webapp_table = DbQuery.getTable('WebApp')
    for entry in webapp_table:
        if entry['remote_addr'] == remote_addr:
            return get_existing_character(environ, entry['character_id'])
    return get_new_character(environ)
コード例 #10
0
ファイル: ClientManager.py プロジェクト: lowhrtz/PyGM
 def remove_client(fields):
     current_client = fields['Client List Current']
     DbQuery.deleteRow('WebApp', 'remote_addr',
                       current_client['remote_addr'])
     DbQuery.commit()
     web_app = DbQuery.getTable('WebApp')
     return {'Client List': [(i['remote_addr'], i) for i in web_app]}
コード例 #11
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
    def prefill_bought_list(self):
        race_dict = self.fields['Race']
        class_dict = self.fields['Class']
        items_dict_list = DbQuery.getTable('Items')
        item_id_list = []
        if race_dict['unique_id'] == 'elf' and 'fighter' in class_dict[
                'unique_id']:
            percent = Dice.randomInt(1, 100)
            if percent <= 5:
                item_id_list.append('armour_elfin_chain')
        if 'magic_user' in class_dict[
                'unique_id'] or 'illusionist' in class_dict['unique_id']:
            item_id_list.append('spellbook')
        if 'cleric' in class_dict['unique_id']:
            item_id_list.append('holy_symbol_pewter')
        if 'druid' in class_dict['unique_id']:
            item_id_list.append('holy_symbol_wooden')
        if 'thief' in class_dict['unique_id'] or 'assassin' in class_dict[
                'unique_id']:
            item_id_list.append('thieves_tools')
        item_list = []
        for item_dict in items_dict_list:
            if item_dict['unique_id'] in item_id_list:
                item_list.append(
                    (item_dict['Name'] + ' - ' + item_dict['Cost'], item_dict))

        return item_list
コード例 #12
0
def get_classes_options(environ):
    if environ.get('REQUEST_METHOD', '') != 'POST':
        return ''
    # print(f'ip = {environ["REMOTE_ADDR"]}')
    raw_post = environ.get('wsgi.input', '')
    post = raw_post.read(int(environ.get('CONTENT_LENGTH', 0)))
    post_dict = parse_qs(post.decode(), True)
    race_id = post_dict.get('race_id', None)
    if not race_id:
        return ''
    race = SystemSettings.get_race_dict({'Race': race_id[0]})
    class_options = []
    for races_meta in race['Races_meta']:
        if races_meta['Type'] == 'class' and races_meta['Subtype'] == 'permitted class options':
            class_options_string = races_meta['Modified']
            if not class_options_string:
                continue
            for class_option in class_options_string.split(','):
                class_option = class_option.strip()
                class_options.append((class_option.title().replace('_', ' '), class_option.replace('/', '_')))
    if not class_options:
        classes = DbQuery.getTable('Classes')
        class_options = [(normal_class['Name'], normal_class['unique_id']) for normal_class in classes]

    return ' '.join([f'<option value="{i[0]}">{i[0]}</option>' for i in class_options])
コード例 #13
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
 def get_full_items(items):
     items_table = DbQuery.getTable('Items')
     items_indexed = {i['unique_id']: i for i in items_table}
     full_items = []
     for item in items:
         if type(item) is tuple:
             gem_type, actual_value = item
             gem_type_list = [
                 i for i in items_table if i['Subcategory'] == gem_type
             ]
             gem_item = gem_type_list[Dice.randomInt(
                 0,
                 len(gem_type_list) - 1)]
             gem_item = copy(gem_item)
             gem_item['Value'] = actual_value
             full_items.append(gem_item)
         elif type(item) is list:
             print('list:', item)
         else:
             item_dict = copy(items_indexed[item])
             if item_dict['Category'] == 'Jewellery':
                 item_dict['Value'] = Dice.rollString(
                     item_dict['Value'])
             full_items.append(item_dict)
     return full_items
コード例 #14
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def get_available_classes( self ):
        if self.fields['STR']:
            attribute_dict = { attr : self.fields[attr] for attr in get_attribute_names() }
        else:
            attribute_dict = None
        class_dict_list = DbQuery.getTable( 'Classes' )
        race = self.fields['Race']
        all_normal_classes = [ ( cl['Name'], cl ) for cl in class_dict_list ]
        if not race and attribute_dict is None:
            return all_normal_classes

        class_option_list = []
        for race_meta_dict in race['Races_meta']:
            if race_meta_dict['Type'] == 'class' and race_meta_dict['Subtype'] == 'permitted class options':
                class_options = race_meta_dict['Modified']
                for class_option in class_options.split( ',' ):
                    class_option = class_option.strip()
                    if '/' in class_option:
                        multiclass_dict = {
                            'unique_id' : class_option.replace( '/', '_' ),
                            'Name' : '',
                            'Primary_Spell_List' : [],
                            'classes' : [],
                        }
                        name_list = []
                        for cl in class_option.split( '/' ):
                            class_record = self.find_class_record( cl, class_dict_list )
                            name_list.append( class_record['Name'] )
                            multiclass_dict['classes'].append( class_record )
                            if class_record['Primary_Spell_List'] != 'None' and SystemSettings.has_spells_at_level( 1, class_record ):
                                multiclass_dict['Primary_Spell_List'].append( class_record['Primary_Spell_List'] )
                        multiclass_dict['Name'] = '/'.join( name_list )
                        option_tuple = ( multiclass_dict['Name'], multiclass_dict )
                        class_option_list.append( option_tuple )
                    else:
                        class_record = self.find_class_record( class_option, class_dict_list )
                        option_tuple = ( class_record['Name'], class_record )
                        class_option_list.append( option_tuple )

        if not class_option_list:
            class_option_list = all_normal_classes

        allowed_list = []
        if attribute_dict is not None:
            attribute_dict = {k.lower():int(v) for k, v in attribute_dict.items()}

        allowed_normal_classes = [ normal_class['Name'] for normal_class in class_dict_list if self.class_allowed( normal_class, attribute_dict ) ]
        for class_option in class_option_list:
            class_option_allowed = True
            for class_option_item in class_option[0].split('/'):
                class_option_item = class_option_item.strip()
                if class_option_item not in allowed_normal_classes:
                    class_option_allowed = False
            if class_option_allowed:
                allowed_list.append( class_option )

        return allowed_list
コード例 #15
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
 def fill_list( self ):
     spells_dict_list = DbQuery.getTable( 'Spells' )
     self.wizard_type = self.pages['ChooseClassPage'].wizard_type
     spell_list = []
     for spell_dict in spells_dict_list:
         if spell_dict['Type'] == self.wizard_type and spell_dict['Level'] == 1:
             spell_tuple = ( spell_dict['Name'], spell_dict )
             spell_list.append( spell_tuple )
     return spell_list
コード例 #16
0
ファイル: WebApp.py プロジェクト: lowhrtz/PyGM
def get_existing_character(_environ, character_id):
    # pcs = environ['Extern']['PCs']
    pcs = DbQuery.getTable('Characters')
    pcs_indexed = {pc['unique_id']: pc for pc in pcs}
    # for c in pcs:
    #     if c['unique_id'] == character_id:
    #         # return SystemSettings.get_character_pdf_markup(c)[1]
    #         return get_character_html(c)
    return get_character_html(pcs_indexed[character_id])
コード例 #17
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def fill_list( self ):
        class_dict = self.fields['Class']
        items_dict_list = DbQuery.getTable( 'Items' )
        item_list = []
        for item_dict in items_dict_list:
            if item_dict['Cost'].lower() != 'not sold' and not item_dict['Cost'].lower().startswith( 'proficiency' ):
                item_tuple = ( item_dict['Name'] + ' - ' + item_dict['Cost'], item_dict )
                item_list.append( item_tuple )

        return item_list
コード例 #18
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
 def fill_list(self):
     spells_dict_list = DbQuery.getTable('Spells')
     self.wizard_type = self.pages['ChooseClassPage'].wizard_type
     spell_list = []
     for spell_dict in spells_dict_list:
         if spell_dict['Type'] == self.wizard_type and spell_dict[
                 'Level'] == 1:
             spell_tuple = (spell_dict['Name'], spell_dict)
             spell_list.append(spell_tuple)
     return spell_list
コード例 #19
0
ファイル: ClientManager.py プロジェクト: lowhrtz/PyGM
 def change_character(fields):
     current_character = fields['Choose Character Data']
     character_id = current_character['unique_id']
     current_client = fields['Client List Current']
     if current_client is None:
         return {}
     remote_addr = current_client['remote_addr']
     DbQuery.updateRow('WebApp', 'remote_addr', remote_addr,
                       (remote_addr, character_id))
     DbQuery.commit()
     return {'Client List': DbQuery.getTable('WebApp')}
コード例 #20
0
ファイル: LevelUp.py プロジェクト: lowhrtz/gm
    def __init__( self ):
        super( ProficiencyPage, self ).__init__( 4, 'Proficiencies' )
        self.set_subtitle( 'Choose available proficiencies' )

        self.proficiency_table = [ row for row in DbQuery.getTable( 'Items' ) if row['Is_Proficiency'].lower() == "yes" ]
        self.class_table = DbQuery.getTable( 'Classes' )
        self.race_table = DbQuery.getTable( 'Races' )
        self.slots_remaining = 0

        prof_data = {
        'fill_avail': self.fill_proficiencies,
        'slots': self.get_proficiency_slots,
        'slots_name': 'Proficiency',
        'category_field': 'Damage_Type',
        'tool_tip': self.get_tool_tip,
        'add': self.add_proficiency,
        'remove': self.remove_proficiency,
        }
        proficiencies = Widget( 'Proficiencies', 'DualList', data=prof_data )

        self.add_row( [ proficiencies, ] )
コード例 #21
0
ファイル: LevelUp.py プロジェクト: lowhrtz/gm
 def initialize_page( self, fields, pages, external_data ):
     spells_table = DbQuery.getTable( 'Spells' )
     pc = external_data['Character List Current']
     spellbook_ids = []
     for meta_row in pc['Characters_meta']:
         if meta_row['Type'] == 'Spellbook':
             spellbook_ids.append( meta_row['Entry_ID'] )
     spellbook = []
     for spell in spells_table:
         if spell['spell_id'] in spellbook_ids:
             spellbook.append( spell )
     return { 'Spellbook': spellbook }
コード例 #22
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
    def fill_list(self):
        class_dict = self.fields['Class']
        items_dict_list = DbQuery.getTable('Items')
        item_list = []
        for item_dict in items_dict_list:
            if item_dict['Cost'].lower() != 'not sold' and not item_dict[
                    'Cost'].lower().startswith('proficiency'):
                item_tuple = (item_dict['Name'] + ' - ' + item_dict['Cost'],
                              item_dict)
                item_list.append(item_tuple)

        return item_list
コード例 #23
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
 def initialize_page(self, fields, pages, external_data):
     self.spell_slots = '1'
     spells_table = DbQuery.getTable('Spells')
     pc = external_data['Character List Current']
     spellbook_ids = []
     for meta_row in pc['Characters_meta']:
         if meta_row['Type'] == 'Spellbook':
             spellbook_ids.append(meta_row['Entry_ID'])
     spellbook = []
     for spell in spells_table:
         if spell['spell_id'] in spellbook_ids:
             spellbook.append(spell)
     return {'Spellbook': spellbook}
コード例 #24
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
    def __init__(self, encounter_id):
        super().__init__(title='XP Breakdown')

        encounters = DbQuery.getTable('Encounters')
        encounters_indexed = {e['unique_id']: e for e in encounters}
        enemies_serialized = encounters_indexed[encounter_id]['enemy_team']
        enemies = json.loads(enemies_serialized)

        def adjust_enemy_xp(dialog_return, fields, enemy_index):
            new_xp = dialog_return
            enemy = enemies[enemy_index]
            enemy['XP Value'] = new_xp
            serialized_enemies = json.dumps(enemies)
            DbQuery.update_cols('Encounters', 'unique_id', encounter_id,
                                ('enemy_team', ), (serialized_enemies, ))
            DbQuery.commit()

            new_total = \
                sum(fields[f] for f in fields if f.startswith('Current XP') and f != f'Current XP {enemy_index}')\
                + new_xp

            return {
                f'Current XP {enemy_index}': new_xp,
                'Total Label': f'<b>Total XP: </b>{new_total}',
            }

        # Define Widgets
        total_xp = 0
        for i, e in enumerate(enemies):
            xp_value = e['XP Value'] if type(e['XP Value']) is int else 0
            total_xp += xp_value
            n = Widget('Name', 'TextLabel', data=f'''<b>{e['Name']}</b>''')
            w = Widget(f'Current XP {i}_',
                       'SpinBox',
                       enable_edit=False,
                       data=xp_value)
            b = Widget(f'Adjust XP {i}', 'PushButton', data='Adjust XP')
            # Add Action
            self.add_action(
                Action('EntryDialog',
                       b,
                       w,
                       callback=callback_factory_2param(adjust_enemy_xp, i)))
            # Initialize GUI
            self.add_row([n, w, b])

        total_label = Widget('Total Label',
                             'TextLabel',
                             data=f'<b>Total XP: </b>{total_xp}',
                             col_span=3)
        self.add_row([total_label])
コード例 #25
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def fill_list( self ):
        spells_dict_list = DbQuery.getTable( 'Spells' )
        spell_list = []

        if self.pages['SpellsPage'].multi_next_spell_type == self.pages['ChooseClassPage'].wizard_type:
            for spell_dict in self.fields['SpellbookList']:
                spell_tuple = (spell_dict['Name'], spell_dict)
                spell_list.append( spell_tuple )
        else:
            for spell_dict in spells_dict_list:
                if spell_dict['Type'] == self.pages['SpellsPage'].multi_next_spell_type and spell_dict['Level'] == 1:
                    spell_tuple = (spell_dict['Name'], spell_dict)
                    spell_list.append( spell_tuple )
        return spell_list
コード例 #26
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
 def fill_items(_owned_items, _fields):
     items = [
         item for item in DbQuery.getTable('Items')
         if not item['Cost'].lower().startswith('proficiency')
     ]
     # These two lines sort the list to guarantee the tab order
     category_order = {
         'General': 0,
         'Weapon': 1,
         'Armour': 2,
         'Clothing': 3
     }
     items.sort(key=lambda x: category_order.get(
         x.get('Category', 'General'), 4))
     return items
コード例 #27
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
    def initialize_page(self, fields, pages, external_data):
        pc = external_data['Character List Current']
        classes = pc['Classes'].split('/')
        level = str(pc['Level']).split('/')
        self.ready_list = ready_to_level_up(pc)
        self.ready_dict_list = [cl for cl in DbQuery.getTable('Classes') if cl['unique_id'] in self.ready_list]
        self.wizard_category = False
        self.other_spellcaster_category = False
        self.other_spellcaster_category2 = False
        self.proficiency_slots_available = 0
        self.spell_classes = 0
        for cl in self.ready_dict_list:
            wpa = cl['Weapon_Proficiency_Advancement'].split('/')
            slots = int(wpa[0])
            per_level = int(wpa[1])
            pc_level = int(level[classes.index(cl['unique_id'])])
            # self.proficiency_slots_available = 2
            if pc_level % per_level == 0:
                self.proficiency_slots_available = slots
            has_spells = SystemSettings.has_spells_at_level(pc_level + 1, cl)
            if cl['Category'] == 'wizard' and has_spells:
                self.wizard_category = cl
                self.spell_classes += 1
            elif cl['Primary_Spell_List'] != 'None' and has_spells:
                if not self.other_spellcaster_category:
                    self.other_spellcaster_category = cl
                else:
                    self.other_spellcaster_category2 = cl
                self.spell_classes += 1

        if self.wizard_category:
            self.next_page_id = pages['Spellbook'].get_page_id()

        elif self.other_spellcaster_category:
            self.next_page_id = pages['Daily Spells'].get_page_id()

        elif self.proficiency_slots_available:
            self.next_page_id = pages['Proficiencies'].get_page_id()

        elif self.ready_list:
            self.next_page_id = pages['Review'].get_page_id()

        else:
            self.next_page_id = -1
            return {
                'Intro Text': 'There are no classes ready to level up for this character!',
                'Intro Text2': ''
            }
コード例 #28
0
ファイル: WebApp.py プロジェクト: lowhrtz/PyGM
def get_save_background(environ):
    raw_post = environ.get('wsgi.input', '')
    post = raw_post.read(int(environ.get('CONTENT_LENGTH', 0)))
    post_dict = parse_qs(post.decode(), True)
    character_id = post_dict.get('character_id', None)
    background = post_dict.get('background', None)
    if character_id and background:
        character_id = character_id[0]
        background = background[0]
        characters = DbQuery.getTable('Characters')
        for c in characters:
            if c['unique_id'] == character_id:
                DbQuery.update_cols('Characters', 'unique_id', character_id, ['Background'], (background, ))
                DbQuery.commit()
                return get_existing_character(environ, character_id)
    return '<h1>Problem saving background!</h1>'
コード例 #29
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
    def fill_list(self):
        spells_dict_list = DbQuery.getTable('Spells')
        spell_list = []

        if self.pages['SpellsPage'].multi_next_spell_type == self.pages[
                'ChooseClassPage'].wizard_type:
            for spell_dict in self.fields['SpellbookList']:
                spell_tuple = (spell_dict['Name'], spell_dict)
                spell_list.append(spell_tuple)
        else:
            for spell_dict in spells_dict_list:
                if spell_dict['Type'] == self.pages[
                        'SpellsPage'].multi_next_spell_type and spell_dict[
                            'Level'] == 1:
                    spell_tuple = (spell_dict['Name'], spell_dict)
                    spell_list.append(spell_tuple)
        return spell_list
コード例 #30
0
ファイル: LevelUp.py プロジェクト: lowhrtz/PyGM
    def __init__(self):
        super().__init__(1, 'Spellbook')
        self.set_subtitle('Choose a spell to add to your spellbook')

        self.orig_spells = []
        self.spell_slots = None
        self.spells_table = DbQuery.getTable('Spells')

        sb_data = {
            'fill_avail': self.fill_spells,
            'slots': self.get_spell_slots,
            'slots_name': 'Spells',
            'category_field': 'Level',
            'tool_tip': self.get_tool_tip,
            'add': self.add_spell,
            'remove': self.remove_spell,
        }
        sb_list = Widget('Spellbook', 'DualList', align='Center', data=sb_data)

        self.add_row([sb_list, ])
コード例 #31
0
ファイル: LevelUp.py プロジェクト: lowhrtz/gm
    def __init__( self ):
        super( SpellbookPage, self ).__init__( 1, 'Spellbook' )
        self.set_subtitle( 'Choose a spell to add to your spellbook' )

        self.orig_spells = []
        self.spell_slots = '1'
        self.spells_table = DbQuery.getTable( 'Spells' )

        sb_data = {
            'fill_avail': self.fill_spells,
            'slots': self.get_spell_slots,
            'slots_name': 'Spells',
            'category_field': 'Level',
            'tool_tip': self.get_tool_tip,
            'add': self.add_spell,
            'remove': self.remove_spell,
        }
        sb_list = Widget( 'Spellbook', 'DualList', align='Center', data=sb_data )

        self.add_row( [ sb_list, ] )
コード例 #32
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def fill_list( self ):
        class_dict = self.fields['Class']
        spells_dict_list = DbQuery.getTable( 'Spells' )
        if 'classes' in class_dict:
            self.spell_types = class_dict['Primary_Spell_List']
            if len(self.spell_types) > 1:
                self.multi_next_spell_type = self.spell_types[1]
        else:
            self.spell_types = [ class_dict['Primary_Spell_List'], ]
        spell_list = []
        if self.spell_types[0] == self.pages['ChooseClassPage'].wizard_type:
            for spell_dict in self.fields['SpellbookList']:
                spell_tuple = ( spell_dict['Name'], spell_dict )
                spell_list.append( spell_tuple )
        else:
            for spell_dict in spells_dict_list:
                if spell_dict['Type'] == self.spell_types[0] and spell_dict['Level'] == 1:
                    spell_tuple = ( spell_dict['Name'], spell_dict )
                    spell_list.append( spell_tuple )

        return spell_list
コード例 #33
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
    def prefill_bought_list( self ):
        race_dict = self.fields['Race']
        class_dict = self.fields['Class']
        items_dict_list = DbQuery.getTable( 'Items' )
        item_id_list = []
        if race_dict['unique_id'] == 'elf' and 'fighter' in class_dict['unique_id']:
            percent = Dice.randomInt(1, 100)
            if percent <= 5:
                item_id_list.append( 'armour_elfin_chain' )
        if 'magic_user' in class_dict['unique_id'] or 'illusionist' in class_dict['unique_id']:
            item_id_list.append( 'spellbook' )
        if 'cleric' in class_dict['unique_id']:
            item_id_list.append( 'holy_symbol_pewter' )
        if 'druid' in class_dict['unique_id']:
            item_id_list.append( 'holy_symbol_wooden' )
        if 'thief' in class_dict['unique_id'] or 'assassin' in class_dict['unique_id']:
            item_id_list.append( 'thieves_tools' )
        item_list = []
        for item_dict in items_dict_list:
            if item_dict['unique_id'] in item_id_list:
                item_list.append( ( item_dict['Name'] + ' - ' + item_dict['Cost'], item_dict ) )

        return item_list
コード例 #34
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
 def fill_proficiencies(self):
     self.specialised_list = []
     self.double_specialised_list = []
     class_dict = self.fields['Class']
     race_dict = self.fields['Race']
     item_dict_list = [
         i for i in DbQuery.getTable('Items')
         if i['Is_Proficiency'] == 'yes'
     ]
     if 'classes' in class_dict:
         wp_list = [cl['Weapons_Permitted'] for cl in class_dict['classes']]
         weapons_permitted = self.race_wp(wp_list, race_dict['unique_id'],
                                          item_dict_list)
     else:
         weapons_permitted = [
             weapon.strip().lower()
             for weapon in class_dict['Weapons_Permitted'].split(',')
         ]
     item_list = []
     for item_dict in item_dict_list:
         item_tuple = (item_dict['Name'], item_dict)
         damage_type_list = [
             damage_type.strip().lower()
             for damage_type in item_dict['Damage_Type'].split(',')
         ]
         if 'any' in weapons_permitted:
             item_list.append(item_tuple)
         elif any(weapon in item_dict['Name'].lower()
                  for weapon in weapons_permitted):
             item_list.append(item_tuple)
         elif [i for i in weapons_permitted if i in damage_type_list]:
             item_list.append(item_tuple)
         elif 'single-handed swords (except bastard swords)' in weapons_permitted:
             if item_dict['unique_id'].startswith( 'sword' ) and \
             'both-hand' not in damage_type_list and 'two-hand' not in damage_type_list:
                 item_list.append(item_tuple)
     return item_list
コード例 #35
0
ファイル: Wizard.py プロジェクト: lowhrtz/PyGM
    def fill_list(self):
        class_dict = self.fields['Class']
        spells_dict_list = DbQuery.getTable('Spells')
        if 'classes' in class_dict:
            self.spell_types = class_dict['Primary_Spell_List']
            if len(self.spell_types) > 1:
                self.multi_next_spell_type = self.spell_types[1]
        else:
            self.spell_types = [
                class_dict['Primary_Spell_List'],
            ]
        spell_list = []
        if self.spell_types[0] == self.pages['ChooseClassPage'].wizard_type:
            for spell_dict in self.fields['SpellbookList']:
                spell_tuple = (spell_dict['Name'], spell_dict)
                spell_list.append(spell_tuple)
        else:
            for spell_dict in spells_dict_list:
                if spell_dict['Type'] == self.spell_types[0] and spell_dict[
                        'Level'] == 1:
                    spell_tuple = (spell_dict['Name'], spell_dict)
                    spell_list.append(spell_tuple)

        return spell_list
コード例 #36
0
ファイル: Wizard.py プロジェクト: lowhrtz/gm
 def prefill_chosen_spells( self ):
     spells_dict_list = DbQuery.getTable( 'Spells' )
     return prefill_chosen_spells( self.wizard_type, spells_dict_list )
コード例 #37
0
ファイル: ClientManager.py プロジェクト: lowhrtz/PyGM
    def __init__(self):
        super().__init__('Client Manager', modality='unblock')

        characters = DbQuery.getTable('Characters')
        characters_indexed = {c['unique_id']: c for c in characters}

        # Define Internal Functions
        def fill_client_list(_fields):
            webapp = DbQuery.getTable('WebApp')
            cl_list = [(c['remote_addr'], c) for c in webapp]
            return {'Client List': cl_list}

        def client_tool_tip(item, _fields):
            character_id = item['character_id']
            character = characters_indexed[character_id]
            tt_ml = f'''\
<b>{character['Name']}</b><br />
<img height="200" src=data:image;base64,{character['Portrait']} />'''

            return tt_ml

        def remove_client(fields):
            current_client = fields['Client List Current']
            DbQuery.deleteRow('WebApp', 'remote_addr',
                              current_client['remote_addr'])
            DbQuery.commit()
            web_app = DbQuery.getTable('WebApp')
            return {'Client List': [(i['remote_addr'], i) for i in web_app]}

        def select_character(fields):
            current_character = fields['Choose Character Data']
            character_class = SystemSettings.get_class_names(current_character)
            return {
                'Character Info':
                f'''\
<b>{current_character['Name']}</b><br />
Level {current_character['Level']} {character_class}<br />
<img height=200 src=data:image;base64,{current_character['Portrait']} />'''
            }

        def change_character(fields):
            current_character = fields['Choose Character Data']
            character_id = current_character['unique_id']
            current_client = fields['Client List Current']
            if current_client is None:
                return {}
            remote_addr = current_client['remote_addr']
            DbQuery.updateRow('WebApp', 'remote_addr', remote_addr,
                              (remote_addr, character_id))
            DbQuery.commit()
            return {'Client List': DbQuery.getTable('WebApp')}

        # Define Widgets
        empty = Widget('', 'Empty')

        client_list = Widget('Client List',
                             'ListBox',
                             col_span=2,
                             row_span=2,
                             tool_tip=client_tool_tip)
        remove_button = Widget('Remove Client', 'PushButton')
        change_button = Widget(
            'Change Character',
            'PushButton',
            tool_tip='Set current character to selected client.')
        character_chooser = Widget('Choose Character',
                                   'ComboBox',
                                   align='Top',
                                   data=DbQuery.getTable('Characters'))
        character_info = Widget('Character Info', 'TextLabel', align='Center')

        # Add Actions
        self.add_action(Action('OnShow', empty, callback=fill_client_list))
        self.add_action(Action('OnShow', empty, callback=select_character))
        self.add_action(
            Action('FillFields', remove_button, callback=remove_client))
        self.add_action(
            Action('FillFields', character_chooser, callback=select_character))
        self.add_action(
            Action('FillFields', change_button, callback=change_character))

        # Initialize GUI
        self.add_row([client_list, empty, character_chooser])
        self.add_row([empty, empty, character_info])
        self.add_row([remove_button, change_button])
コード例 #38
0
ファイル: WebApp.py プロジェクト: lowhrtz/PyGM
def get_character_html(character_dict):
    get_bonus_string = SystemSettings.get_attribute_bonus_string
    class_dict = SystemSettings.get_class_dict(character_dict)
    race_dict = {}
    for race in DbQuery.getTable('Races'):
        if race['unique_id'] == character_dict['Race']:
            race_dict = race
    equip_id_list = []
    spellbook_id_list = []
    daily_spells_id_list = []
    daily_spells2_id_list = []
    daily_spells3_id_list = []
    proficiency_id_dict = {}
    gp = pp = ep = sp = cp = 0
    for meta_row in character_dict['Characters_meta']:
        if meta_row['Type'] == 'Equipment':
            equip_id_list.append(meta_row['Entry_ID'])
        elif meta_row['Type'] == 'Treasure':
            if meta_row['Entry_ID'] == 'gp':
                gp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'pp':
                pp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'ep':
                ep = meta_row['Data']

            elif meta_row['Entry_ID'] == 'sp':
                sp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'cp':
                cp = meta_row['Data']
        elif meta_row['Type'] == 'Spellbook':
            spellbook_id_list.append(meta_row['Entry_ID'])
        elif meta_row['Type'] == 'DailySpells':
            daily_spells_id_list.append(meta_row['Entry_ID'])
        elif meta_row['Type'] == 'DailySpells2':
            daily_spells2_id_list.append(meta_row['Entry_ID'])
        elif meta_row['Type'] == 'DailySpells3':
            daily_spells3_id_list.append(meta_row['Entry_ID'])
        elif meta_row['Type'] == 'Proficiency':
            proficiency_id_dict[meta_row['Entry_ID']] = meta_row['Data']

    items_table = DbQuery.getTable('Items')
    proficiency_list = []
    specialised_list = []
    double_specialised_list = []
    for prof in items_table:
        if prof['Is_Proficiency'].lower() == 'yes' and prof['unique_id'] in list(proficiency_id_dict.keys()):
            prof_level = proficiency_id_dict[prof['unique_id']]
            if prof_level == 'P':
                proficiency_list.append(prof)
            elif prof_level == 'S':
                specialised_list.append(prof)
            elif prof_level == '2XS':
                double_specialised_list.append(prof)

    indexed_items = {item['unique_id']: item for item in items_table}
    equipment_list = [indexed_items[equip_id] for equip_id in equip_id_list]

    level = character_dict['Level']
    class_abilities = {}
    if 'classes' in class_dict:
        level_list = [int(lvl) for lvl in level.split('/')]
        for i, cl in enumerate(class_dict['classes']):
            class_abilities[cl['Name']] = SystemSettings.get_class_abilities(level_list[i], character_dict, cl)
    else:
        class_abilities[class_dict['Name']] = SystemSettings.get_class_abilities(level, character_dict, class_dict)
    race_abilities = SystemSettings.get_race_abilities(race_dict)

    spells_table = DbQuery.getTable('Spells')
    spellbook = []
    daily_spells = []
    daily_spells2 = []
    daily_spells3 = []
    for spell in spells_table:
        if spell['spell_id'] in spellbook_id_list:
            spellbook.append(spell)
        if spell['spell_id'] in daily_spells_id_list:
            daily_spells.append(spell)
        if spell['spell_id'] in daily_spells2_id_list:
            daily_spells2.append(spell)
        if spell['spell_id'] in daily_spells3_id_list:
            daily_spells3.append(spell)
    ac = SystemSettings.calculate_ac(character_dict, class_dict, race_dict, equipment_list)
    saves_dict = SystemSettings.get_saves(level, character_dict, class_dict, race_dict)
    movement_tuple = SystemSettings.calculate_movement(race_dict, class_dict, character_dict, equipment_list)
    movement_rate, movement_desc = movement_tuple
    html = f'''\
<div class="character_sheet">
<input type="hidden" id="character_id" value="{character_dict['unique_id']}" />

<div class="character_page" style="display: block;" id="basic_info">
<span style="position: absolute; left: 30px;"><b>HP:</b> {character_dict['HP']}<br /><b>AC:</b> {ac}</span>
<img style="height: 600px; margin: 30px auto 30px auto;" src="data:image;base64,{character_dict['Portrait']}" />
<b>{character_dict['Name']}</b><br />
<b>Level:</b> {character_dict['Level']}<br />
<b>Class:</b> {SystemSettings.get_class_names(character_dict)}<br />
<b>Race:</b> {race_dict['Name']}<br />
<b>Alignment:</b> {character_dict['Alignment']}
</div>

<div class="character_page" id="attributes">
<table style="padding: 20px;">
<tr><th>Str:</th><td onclick="toggleBonus('str_bonus')">{character_dict['STR']}</td><td class="bonus" id="str_bonus">{get_bonus_string('STR', character_dict['STR'])}</td></tr>
<tr><th>Int:</th><td onclick="toggleBonus('int_bonus')">{character_dict['INT']}</td><td class="bonus" id="int_bonus">{get_bonus_string('INT', character_dict['INT'])}</td></tr>
<tr><th>Wis:</th><td onclick="toggleBonus('wis_bonus')">{character_dict['WIS']}</td><td class="bonus" id="wis_bonus">{get_bonus_string('WIS', character_dict['WIS'])}</td></tr>
<tr><th>Dex:</th><td onclick="toggleBonus('dex_bonus')">{character_dict['DEX']}</td><td class="bonus" id="dex_bonus">{get_bonus_string('DEX', character_dict['DEX'])}</td></tr>
<tr><th>Con:</th><td onclick="toggleBonus('con_bonus')">{character_dict['CON']}</td><td class="bonus" id="con_bonus">{get_bonus_string('CON', character_dict['CON'])}</td></tr>
<tr><th>Cha:</th><td onclick="toggleBonus('cha_bonus')">{character_dict['CHA']}</td><td class="bonus" id="cha_bonus">{get_bonus_string('CHA', character_dict['CHA'])}</td></tr>
</table>
<hr />
<b>Saving Throws</b>
<div style="font-size: 50%;">
<b>Aimed Magic Items:</b> {saves_dict['Aimed_Magic_Items']}<br />
<b>Breath Weapon:</b> {saves_dict['Breath_Weapons']}<br />
<b>Death, Paralysis, Poison:</b> {saves_dict['Death_Paralysis_Poison']}<br />
<b>Petrifaction, Polymorph:</b> {saves_dict['Petrifaction_Polymorph']}<br />
<b>Spells:</b> {saves_dict['Spells']}
</div>
</div>

<div class="character_page" id="equipment">
{''.join('<div class="more_info">' + e['Name'] + '</div><div>' + item_html(e) + '</div>' for e in equipment_list)}
<br />
<hr />
<b>PP:</b>{pp} <b>GP:</b>{gp} <b>SP:</b>{sp} <b>EP:</b>{ep} <b>CP:</b>{cp}
<hr />

</div>

<div class="character_page" id="abilities">
{class_abilities_html(class_abilities)}
{'<fieldset><legend><b>' + race_dict['Name'] + ' Abilities</b></legend>' +
 ''.join(f'<div>{ra[0]} {ra[1]} {ra[2]}</div>' for ra in race_abilities) + '</fieldset>' if race_abilities else ''}
{'<fieldset><legend><b>Spell Book</b></legend>' +
 ''.join('<div class="more_info spell">' + s['Name'] + '</div><div>' + spell_html(s) + '</div>' for s in spellbook)
 + '</fieldset>' if spellbook else ''}
{f'<fieldset><legend><b>{daily_spells[0]["Type"].title().replace("_", " ")} Daily Spells</b></legend>' +
 ''.join('<div class="more_info spell">' + s['Name'] + '</div><div>' + spell_html(s) + '</div>' for s in daily_spells)
 + '</fieldset>' if daily_spells else ''}
{f'<fieldset><legend><b>{daily_spells2[0]["Type"].title().replace("_", " ")} Daily Spells</b></legend>' +
 ''.join('<div class="more_info spell">' + s['Name'] + '</div><div>' + spell_html(s) + '</div>' for s in daily_spells2)
 + '</fieldset>' if daily_spells2 else ''}
{f'<fieldset><legend><b>{daily_spells3[0]["Type"].title().replace("_", " ")} Daily Spells</b></legend>' +
 ''.join('<div class="more_info spell">' + s['Name'] + '</div><div>' + spell_html(s) + '</div>' for s in daily_spells3)
 + '</fieldset>' if daily_spells3 else ''}
</div>

<div class="character_page" id="combat_info">
<table class="tohit-table" style="font-size: 50%; margin-top: 20px;" border=1 align=center>
<tr><td><b>Enemy AC</b></td><td align=center> -10 </td><td align=center> -9 </td><td align=center> -8 </td>
<td align=center> -7 </td><td align=center> -6 </td><td align=center> -5 </td>
<td align=center> -4 </td><td align=center> -3 </td><td align=center> -2 </td><td align=center> -1 </td>
<td align=center> 0 </td><td align=center> 1 </td><td align=center> 2 </td><td align=center> 3 </td>
<td align=center> 4 </td><td align=center> 5 </td><td align=center> 6 </td><td align=center> 7 </td>
<td align=center> 8 </td><td align=center> 9 </td><td align=center> 10 </td></tr>
<tr><td><b>To Hit</b></td>{'<td align=center>' + '</td><td align=center>'
        .join(SystemSettings.get_tohit_row(level, class_dict, race_dict)) + '</td>'}</tr>
</table>
<b>Movement Rate:</b> {movement_rate} ft/round<br />
<b>Surprise:</b> {movement_desc}<br />
<b>Non-Proficiency Penalty: </b> {SystemSettings.get_non_proficiency_penalty(class_dict, race_dict)}

{'<fieldset><legend><b>Proficiency</b></legend>' + '<br />'.join(p['Name'] for p in proficiency_list) +
'</fieldset>' if proficiency_list else ''}

{'<fieldset><legend><b>Specialised</b></legend>' + '<br />'.join(p['Name'] for p in specialised_list) +
 '</fieldset>' if specialised_list else ''}


{'<fieldset><legend><b>Double Specialised</b></legend>' + '<br />'.join(p['Name'] for p in double_specialised_list) +
 '</fieldset>' if double_specialised_list else ''}

</div>

<div class="character_page" id="personal_info">
<div style="margin: 15px 5px;">
<b>Height:</b> {character_dict['Height']} <b>Weight:</b> {character_dict['Weight']}<br />
<b>Sex:</b> {character_dict['Gender']}<br />
</div>
<b>Background</b><br />
<textarea style="font-size: 30px; margin-bottom: 35px;" id="background_text" rows=15 cols=35>
{character_dict['Background']}
</textarea><br />
<button style="font-size: 50px;" onclick="saveBackground()")">Save Background</button>
</div>

<div class="character_menu">
<span onclick="changeCharacterPage('basic_info')">Basic Info</span>
<span onclick="changeCharacterPage('attributes')">Attributes</span>
<span onclick="changeCharacterPage('equipment')">Equipment</span>
<span onclick="changeCharacterPage('abilities')">Abilities</span>
<span onclick="changeCharacterPage('combat_info')">Combat Info</span>
<span onclick="changeCharacterPage('personal_info')">Personal Info</span>
</div>
</div>
'''
    return html
コード例 #39
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
    def accept(self, fields, pages, external_data):
        encounters = DbQuery.getTable('Encounters')
        encounters_indexed = {e['unique_id']: e for e in encounters}
        characters = DbQuery.getTable('Characters')
        characters_indexed = {c['unique_id']: c for c in characters}
        character_classes = DbQuery.getTable('Classes')
        c_classes_indexed = {c['unique_id']: c for c in character_classes}

        party_treasure = [
            t for t in self.campaign['Campaigns_meta']
            if t['Type'] == 'Party Treasure'
        ]
        everything_else = [
            e for e in self.campaign['Campaigns_meta']
            if e['Type'] != 'Party Treasure'
        ]
        # new_treasure = deepcopy(pages['Wrap Up'].treasure)
        new_treasure = {
            'cp': fields['CP'],
            'sp': fields['SP'],
            'ep': fields['EP'],
            'gp': fields['GP'],
            'pp': fields['PP'],
            'items': fields['Items'],
        }
        new_treasure_xp_value = Treasure.get_xp_value(new_treasure)
        for pt in party_treasure:
            t = pt['Data']
            t = json.loads(t)
            for k, v in t.items():
                # print(k, v)
                new_treasure[k] += v
        new_treasure_entry = {
            'Type': 'Party Treasure',
            'Entry_ID': None,
            'Data': json.dumps(new_treasure),
            'Notes': None
        }

        everything = everything_else + [
            new_treasure_entry,
        ]
        DbQuery.begin()
        DbQuery.deleteRow('Campaigns_meta', 'campaign_id',
                          self.campaign['unique_id'])
        for i in everything:
            row = self.campaign['unique_id'], i['Type'], i['Entry_ID'], i[
                'Data'], i['Notes']
            DbQuery.insertRow('Campaigns_meta', row)
        # DbQuery.commit()
        self.campaign['Campaigns_meta'] = everything

        encounter_id = pages['Encounter Tracker'].encounter_id
        enemies_serialized = encounters_indexed[encounter_id]['enemy_team']
        enemies = json.loads(enemies_serialized)
        xp_total = sum(e['XP Value'] for e in enemies)
        if fields['Include Treasure XP']:
            xp_total += new_treasure_xp_value
        pc_team = external_data['PC Team']
        xp_eligible = []
        for pc in pc_team:
            pc_id = pc['unique_id']
            pc = characters_indexed[pc_id]
            current_hp = get_character_hp(pc)
            if current_hp > 0:
                xp_eligible.append(pc)
        num_of_eligible = len(xp_eligible)
        xp_per = xp_total // num_of_eligible
        # print(xp_total, num_of_eligible, xp_per)
        from decimal import Decimal
        for pc in xp_eligible:
            pc_id = pc['unique_id']
            xp_list = str(pc['XP']).split('/')
            add_xp = xp_per // len(xp_list)
            pc_class_list = pc['Classes'].split('/')
            if len(pc_class_list) == 1:
                cl = c_classes_indexed[pc_class_list[0]]
                xp_bonus_string = cl['Experience_Bonus']
                xp_bonus = SystemSettings.parse_xp_bonus(xp_bonus_string, pc)
                if xp_bonus:
                    add_xp = int(add_xp *
                                 (1 + Decimal(xp_bonus) / Decimal(100)))
            new_xp_list = [int(xp) + add_xp for xp in xp_list]
            new_xp = '/'.join(str(xp) for xp in new_xp_list)
            DbQuery.update_cols('Characters', 'unique_id', pc_id, ('XP', ),
                                (new_xp, ))
        DbQuery.commit()
コード例 #40
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
    def __init__(self):
        super().__init__(3, 'Battle Rounds')
        self.set_subtitle('Each round is one minute')

        # self.initiative_winner = None
        self.round_number = 1
        self.initiative_roll = '1d6'
        self.spells_table = DbQuery.getTable('Spells')
        self.spells_indexed = {
            spell['spell_id']: spell
            for spell in self.spells_table
        }

        # Define Internal Functions
        def next_round(_fields, _pages, _external):
            self.round_number += 1
            return {
                'Round Text': f'Round {self.round_number}',
                'PC Team Initiative': Dice.rollString(self.initiative_roll),
                'Monster Team Initiative':
                Dice.rollString(self.initiative_roll),
            }

        def select_spell(field_name, fields):
            spell = fields[f'{field_name} Current']
            return {'Casting Time': spell['Casting_Time']}

        # Define Widgets
        round_text = Widget('Round Text',
                            'TextLabel',
                            data=f'Round {self.round_number}')
        next_round_button = Widget('Next Round', 'PushButton')
        open_hp_tracker_button = Widget('Open HP Tracker',
                                        'PushButton',
                                        align='Right')
        initiative_text = Widget('Initiative Text',
                                 'TextLabel',
                                 data='<b>Initiative</b>',
                                 align='Center',
                                 col_span=5)
        pc_team = Widget('PC Team Initiative', 'SpinBox', col_span=3)
        monster_team = Widget('Monster Team Initiative', 'SpinBox', col_span=3)
        pc_team_text = Widget('PC Team Text', 'TextLabel', col_span=3)
        monster_team_text = Widget('Monster Team Text',
                                   'TextLabel',
                                   col_span=3)
        casting_time_text = Widget('Spell Duration Text',
                                   'TextLabel',
                                   data='<b>Casting Time:</b>')
        casting_time = Widget('Casting Time', 'TextLabel')
        pc_spells = Widget('PC Spells',
                           'ListBox',
                           tool_tip=lambda s, f, p, e: spell_tooltip(s),
                           col_span=2)
        all_spells = Widget('All Spells',
                            'ListBox',
                            tool_tip=lambda s, f, p, e: spell_tooltip(s),
                            col_span=3)

        # Add Actions
        self.add_action(
            Action('FillFields', next_round_button, callback=next_round))
        self.add_action(
            Action('Window', open_hp_tracker_button, callback=open_hp_tracker))
        self.add_action(
            Action('FillFields',
                   pc_spells,
                   callback=lambda f, p, e: select_spell('PC Spells', f)))
        self.add_action(
            Action('FillFields',
                   all_spells,
                   callback=lambda f, p, e: select_spell('All Spells', f)))

        # Initialize GUI
        empty = Widget('', 'Empty')
        self.add_row([
            round_text, next_round_button, empty, empty, open_hp_tracker_button
        ])
        self.add_row([initiative_text])
        self.add_row([pc_team])
        self.add_row([monster_team])
        self.add_row([pc_team_text])
        self.add_row([monster_team_text])
        self.add_row([casting_time_text, casting_time])
        self.add_row([pc_spells, empty, all_spells])
コード例 #41
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
    def __init__(self, characters, encounter_id):
        super().__init__(title='HP Tracker', modality='unblock')

        pcs = DbQuery.getTable('Characters')
        encounters = DbQuery.getTable('Encounters')

        pcs_indexed = {pc['unique_id']: pc for pc in pcs}
        encounters_indexed = {e['unique_id']: e for e in encounters}

        current_encounter = encounters_indexed[encounter_id]
        enemies_serialized = current_encounter['enemy_team']
        enemies = json.loads(enemies_serialized)

        # Define Internal Functions
        # def get_meta_indexed(char):
        #     meta_indexed = {}
        #     for row in char['Characters_meta']:
        #         meta_type = row['Type']
        #         meta_list = meta_indexed.get(meta_type, [])
        #         meta_list.append(row)
        #         meta_indexed[meta_type] = meta_list
        #     return meta_indexed

        # def get_character_hp(char):
        #     # char_id = char['unique_id']
        #     # char = pcs_indexed[char_id]
        #     meta_indexed = get_meta_indexed(char)
        #
        #     return int(meta_indexed.get('Current HP', [{'Data': char['HP']}])[0]['Data'])

        def get_enemy_hp(en):
            if en['TableName'] == 'Monsters':
                return en['HP']
            return get_character_hp(en)

        def save_character_hp(char_id, new_hp):
            meta_indexed = get_meta_indexed(pcs_indexed[char_id])
            cur_hp_meta_row = meta_indexed.get('Current HP', None)

            if cur_hp_meta_row is None:
                cur_hp_insert_row = (char_id, 'Current HP', None, new_hp, None)
                DbQuery.insertRow('Characters_meta', cur_hp_insert_row)
                DbQuery.commit()
            else:
                DbQuery.update_cols('Characters_meta', 'character_id', char_id,
                                    ('Data', ), (new_hp, ), 'Type',
                                    'Current HP')
                DbQuery.commit()

        def adjust_character_hp(dialog_return, fields, char_id):
            new_hp = dialog_return + fields[f'Current HP {char_id}']
            save_character_hp(char_id, new_hp)

            return {
                f'Current HP {char_id}': new_hp,
            }

        def adjust_enemy_hp(dialog_return, fields, enemy_index):
            new_hp = dialog_return + fields[f'Current HP {enemy_index}']
            en = enemies[enemy_index]
            if en['TableName'] == 'Monsters':
                enemies[enemy_index]['HP'] = new_hp
                serialized_enemies = json.dumps(enemies)
                DbQuery.update_cols('Encounters', 'unique_id', encounter_id,
                                    ('enemy_team', ), (serialized_enemies, ))
                DbQuery.commit()
            else:
                char_id = en['unique_id']
                save_character_hp(char_id, new_hp)

            return {
                f'Current HP {enemy_index}': new_hp,
            }

        # Define Widgets
        tools_menu = Menu('&Tools')
        tools_menu.add_action(
            Action('Window',
                   Widget('&Dice Roller', 'MenuAction'),
                   callback=lambda x: DiceWindow()))
        self.add_menu(tools_menu)

        pc_team_header = Widget('PC Team Header',
                                'TextLabel',
                                data='<b>PC Team</b>',
                                align='Center',
                                col_span=3)
        self.add_row([pc_team_header])
        for character in characters:
            character_id = character['unique_id']
            character = pcs_indexed[character_id]
            character_name = Widget('Character Name',
                                    'TextLabel',
                                    data=f'<b>{character["Name"]}</b>')
            current_hp = Widget(f'Current HP {character_id}_',
                                'SpinBox',
                                enable_edit=False,
                                data=get_character_hp(character))
            adjust_hp = Widget(f'Adjust HP {character_id}',
                               'PushButton',
                               data='Adjust HP')
            # Add Actions
            self.add_action(
                Action('EntryDialog',
                       adjust_hp,
                       current_hp,
                       callback=callback_factory_2param(
                           adjust_character_hp, character_id)))
            # Initialize GUI
            self.add_row([character_name, current_hp, adjust_hp])

        enemy_team_header = Widget('Enemy Team Header',
                                   'TextLabel',
                                   data='<b>Enemy Team</b>',
                                   align='Center',
                                   col_span=3)
        self.add_row([enemy_team_header])
        for i, enemy in enumerate(enemies):
            enemy_name = Widget('Enemy Name',
                                'TextLabel',
                                data=f'<b>{enemy["Name"]}</b>')
            current_hp = Widget(f'Current HP {i}_',
                                'SpinBox',
                                enable_edit=False,
                                data=get_enemy_hp(enemy))
            adjust_hp = Widget(f'Adjust HP {i}',
                               'PushButton',
                               data='Adjust HP')
            # Add Actions
            self.add_action(
                Action('EntryDialog',
                       adjust_hp,
                       current_hp,
                       callback=callback_factory_2param(adjust_enemy_hp, i)))
            # Initialize GUI
            self.add_row([enemy_name, current_hp, adjust_hp])
コード例 #42
0
def cc_submit(environ):
    if environ.get('REQUEST_METHOD', '') != 'POST':
        return ''
    raw_post = environ.get('wsgi.input', '')
    post = raw_post.read(int(environ.get('CONTENT_LENGTH', 0)))
    post_dict = parse_qs(post.decode(), True)

    name = post_dict.get('name', [''])[0]
    gender = post_dict.get('gender', [''])[0]
    race_id = post_dict.get('race', [''])[0]
    class_name = post_dict.get('classes', [''])[0]
    alignment = post_dict.get('alignment', [''])[0]
    portrait = post_dict.get('portrait', [''])[0]
    full_class = SystemSettings.get_full_class(class_name)
    race = {r['unique_id']: r for r in DbQuery.getTable('Races')}[race_id]
    unique_id = f"{name.lower().replace(' ', '_')}-{full_class['unique_id']}-{time.time()}"

    if 'classes' in full_class:
        level = '/'.join('1' for _ in full_class['classes'])
        classes = '/'.join(cl['unique_id'] for cl in full_class['classes'])
        xp = '/'.join('0' for _ in full_class['classes'])
    else:
        level = '1'
        classes = full_class['unique_id']
        xp = '0'

    attr_dict = SystemSettings.adjust_attributes(
        SystemSettings.roll_attributes(None, race, full_class),
        race)
    hp = SystemSettings.roll_hp(attr_dict, 1, full_class)
    age = SystemSettings.roll_age(race, full_class)
    height, weight = SystemSettings.roll_height_weight(race, gender)

    proficiency_choices = SystemSettings.get_proficiency_choices(full_class, race)
    if 'classes' in full_class:
        slots = max([cl['Initial_Weapon_Proficiencies'] for cl in full_class['classes']])
    else:
        slots = full_class['Initial_Weapon_Proficiencies']
    proficiencies = Dice.get_random_items(proficiency_choices, slots, r=False)
    equipment = SystemSettings.starting_items_basic(full_class, race)
    equipment.extend([i['unique_id'] for i in Dice.get_random_items(proficiencies)])

    character_dict = {
        'unique_id': unique_id,
        'Name': name,
        'Level': level,
        'XP': xp,
        'Gender': gender,
        'Alignment': alignment,
        'Classes': classes,
        'Race': race_id,
        'HP': hp,
        'Age': age,
        'Height': f'{height[0]}ft {height[1]}in',
        'Weight': f'{weight} lbs',
        'Background': '',
        'Portrait': portrait,
        'Portrait_Image_Type': 'jpg',
        'STR': attr_dict['STR'],
        'INT': attr_dict['INT'],
        'WIS': attr_dict['WIS'],
        'DEX': attr_dict['DEX'],
        'CON': attr_dict['CON'],
        'CHA': attr_dict['CHA'],
        'Characters_meta': [],
    }

    def make_meta_row(data_list):
        meta_row = {
            'character_id': data_list[0],
            'Type': data_list[1],
            'Entry_ID': data_list[2],
            'Data': data_list[3],
            'Notes': data_list[4]
        }
        return meta_row

    for e in equipment:
        equip_data = [
            unique_id,
            'Equipment',
            e,
            '',
            '',
        ]
        character_dict['Characters_meta'].append(make_meta_row(equip_data))

    gp_data = [
        unique_id,
        'Treasure',
        'gp',
        SystemSettings.get_initial_wealth(full_class),
        '',
    ]
    character_dict['Characters_meta'].append(make_meta_row(gp_data))

    for p in proficiencies:
        p_data = [
            unique_id,
            'Proficiency',
            p['unique_id'],
            'P',
            '',
        ]
        character_dict['Characters_meta'].append(make_meta_row(p_data))

    if 'classes' in full_class:
        class_list = full_class['classes']
    else:
        class_list = [full_class]
    spellbook = []
    daily_1 = []
    daily_2 = []
    for i, c in enumerate(class_list):
        if SystemSettings.has_spells_at_level(1, c):
            spells = [s for s in DbQuery.getTable('Spells') if s['Type'] == c['unique_id'] and s['Level'] == 1]
            if c['Category'] == 'wizard':
                slots = 4
                if c['unique_id'] == 'magic_user':
                    slots = 3
                    for j, s in enumerate(spells):
                        if s['spell_id'] == 'read_magic':
                            spellbook.append(spells.pop(j))
                            break
                spellbook.extend(Dice.get_random_items(spells, slots, False))
                spells = spellbook
            if i == 0:
                slots = SystemSettings.get_xp_table_row(1, c)['Level_1_Spells']
                daily_1.extend(Dice.get_random_items(spells, slots))
            else:
                slots = SystemSettings.get_xp_table_row(1, c)['Level_1_Spells']
                daily_2.extend(Dice.get_random_items(spells, slots))
    for s in spellbook:
        s_data = [
            unique_id,
            'Spellbook',
            s['spell_id'],
            '',
            '',
        ]
        character_dict['Characters_meta'].append(make_meta_row(s_data))
    for d in daily_1:
        d_data = [
            unique_id,
            'DailySpells',
            d['spell_id'],
            '',
            '',
        ]
        character_dict['Characters_meta'].append(make_meta_row(d_data))
    for d in daily_2:
        d_data = [
            unique_id,
            'DailySpells2',
            d['spell_id'],
            '',
            '',
        ]
        character_dict['Characters_meta'].append(make_meta_row(d_data))

    SystemSettings.add_character(character_dict)
    DbQuery.insertRow('WebApp', [environ['REMOTE_ADDR'], unique_id])
    DbQuery.commit()

    return WebApp.get_character_html(character_dict)
コード例 #43
0
def get_races_html():
    return ' '.join([f'<option value="{i["unique_id"]}">{i["Name"]}</option>' for i in DbQuery.getTable('Races')])
コード例 #44
0
ファイル: SystemSettings.py プロジェクト: lowhrtz/gm
def get_character_pdf_markup( character_dict ):
    class_table = DbQuery.getTable( 'Classes' )
    race_table = DbQuery.getTable( 'Races' )
    items_table = DbQuery.getTable( 'Items' )
    spells_table = DbQuery.getTable( 'Spells' )

    class_dict = { 'Name' : '', 'classes' : [] }
    classes_list = character_dict['Classes'].split( '/' )
    for class_id in classes_list:
        for cl in class_table:
            if class_id == cl['unique_id']:
                if class_dict['Name'] == '':
                    if len( classes_list ) == 1:
                        class_dict = cl
                        break
                    class_dict['Name'] = cl['Name']
                else:
                    class_dict['Name'] += '/{}'.format( cl['Name'] )
                class_dict['classes'].append(cl)

    level = character_dict['Level']
    class_name = class_dict['Name']
    class_font_size = '14px'
    class_padding = '0px'
    if len( class_name ) > 15:
        class_font_size = '8px'
        class_padding = '4px'

    for race in race_table:
        if race['unique_id'] == character_dict['Race']:
            race_dict = race

    portrait = character_dict['Portrait']
    ext = character_dict['Portrait_Image_Type']

    attr_dict = {
        'STR' : character_dict['STR'],
        'INT' : character_dict['INT'],
        'WIS' : character_dict['WIS'],
        'DEX' : character_dict['DEX'],
        'CON' : character_dict['CON'],
        'CHA' : character_dict['CHA'],
    }

    equip_id_list = []
    spellbook_id_list = []
    daily_spells_id_list = []
    daily_spells2_id_list = []
    proficiency_id_dict = {}
    for meta_row in character_dict['Characters_meta']:
        if meta_row['Type'] == 'Equipment':
            equip_id_list.append( meta_row['Entry_ID'] )
        elif meta_row['Type'] == 'Treasure':
            if meta_row['Entry_ID'] == 'gp':
                gp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'pp':
                pp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'ep':
                ep = meta_row['Data']

            elif meta_row['Entry_ID'] == 'sp':
                sp = meta_row['Data']

            elif meta_row['Entry_ID'] == 'cp':
                cp = meta_row['Data']
        elif meta_row['Type'] == 'Spellbook':
            spellbook_id_list.append( meta_row['Entry_ID'] )
        elif meta_row['Type'] == 'DailySpells':
            daily_spells_id_list.append( meta_row['Entry_ID'] )
        elif meta_row['Type'] == 'DailySpells2':
            daily_spells2_id_list.append( meta_row['Entry_ID'] )
        elif meta_row['Type'] == 'Proficiency':
            proficiency_id_dict[ meta_row['Entry_ID'] ] = meta_row['Data']

    proficiency_list = []
    specialised_list = []
    double_specialised_list = []
    for prof in items_table:
        if prof['Is_Proficiency'].lower() == 'yes' and prof['unique_id'] in list( proficiency_id_dict.keys() ):
            prof_name = prof['Name']
            prof_level = proficiency_id_dict[  prof['unique_id'] ]
            if prof_level == 'P':
                proficiency_list.append( prof )
            elif prof_level == 'S':
                specialised_list.append( prof )
            elif prof_level == '2XS':
                double_specialised_list.append( prof )

    equipment_list = []
    for equip in items_table:
        if equip['unique_id'] in equip_id_list:
            equipment_list.append( equip )

    class_abilities = {}
    if 'classes' in class_dict:
        level_list = [ int(l) for l in level.split('/') ]
        for i, cl in enumerate( class_dict['classes'] ):
            class_abilities[ cl['Name'] ] = get_class_abilities( level_list[i], attr_dict, cl )
    else:
        class_abilities[ class_dict['Name'] ] = get_class_abilities( level, attr_dict, class_dict )
    race_abilities = get_race_abilities( race_dict )

    spellbook = []
    daily_spells = []
    daily_spells2 = []
    for spell in spells_table:
        if spell['spell_id'] in spellbook_id_list:
            spellbook.append( spell )
        if spell['spell_id'] in daily_spells_id_list:
            daily_spells.append( spell )
        if spell['spell_id'] in daily_spells2_id_list:
            daily_spells2.append( spell )

    #print equipment_list
    saves_dict = get_saves( level, attr_dict, class_dict, race_dict )
    movement_tuple = calculate_movement( race_dict, class_dict, attr_dict, equipment_list )
    markup_template_dict = {
        'class_font_size' : class_font_size,
        'class_padding' : class_padding,
        'name' : character_dict['Name'],
        'gender' : character_dict['Gender'],
        'class' : class_dict['Name'],
        'alignment' : character_dict['Alignment'],
        'race' : race_dict['Name'],
        'xp' : character_dict['XP'],
        'hp' : character_dict['HP'],
        'ac' : calculate_ac( attr_dict, class_dict, race_dict, equipment_list ),
        'level' : level,
        'age' : character_dict['Age'],
        'height': character_dict['Height'],
        'weight': character_dict['Weight'],
        'portrait': portrait,
        'image_type': ext,
        'tohit_row': '<td align=center>' + '</td><td align=center>'.join( get_tohit_row( level, class_dict, race_dict ) ) + '</td>',
        'gp' : gp,
        'pp' : pp,
        'ep' : ep,
        'sp' : sp,
        'cp' : cp,
        'movement_rate' : movement_tuple[0],
        'movement_desc' : movement_tuple[1],
        'nonproficiency_penalty' : get_non_proficiency_penalty( class_dict, race_dict ),
        }
    for attr_name in list( attr_dict.keys() ):
        markup_template_dict[attr_name] = attr_dict[attr_name]
        markup_template_dict[ attr_name + '_bonus' ] = get_attribute_bonus_string( attr_name, attr_dict[attr_name] )
    for save in list( saves_dict.keys() ):
        markup_template_dict[save] = saves_dict[save]

    markup = '''\
<style type=text/css>
.border {
color: red;
border-style: solid;
border-color: purple;
margin-right: 5px;
}

.bigger-font {
font-size: 15px;
}

.smaller-font {
font-size: 10px;
}

.pad-cell {
padding-left: 5px;
padding-right: 5px;
}

.pad-bottom {
padding-bottom: 5px;
}

.pad-top-large {
padding-top: 10px;
}

.pad-all {
padding: 5px;
}

.no-pad {
padding: 0px;
}

.lpad {
padding-left: 15px;
}

.float-right {
float: right;
}

.class-font {
font-size: $class_font_size;
padding-top: $class_padding;
}

.alignment-font {
font-size: 10px;
padding-top: 3px;
}

.attr-bonuses {
font-size: 8px;
vertical-align: middle;
white-space: pre;
}

.tohit-table {
border-style: solid;
}

.tohit-table > tr > td {
padding: 2px;
vertical-align: middle;
}

.equipment-table > tr > th {
padding: 4px;
align: center;
font-size: 10px;
}

.equipment-table > tr > td {
padding: 4px;
align: center;
font-size: 10px;
}

.equip-legend {
font-size: 8px;
}

table.ability {
font-size: 12px;
}

table.ability > tr > th {
padding: 2px;
}

.pre {
white-space: pre;
}

p.page-break {
page-break-after:always;
}
</style>
<h1 align=center>$name</h1>

<table width=100%>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td class=lpad align=center rowspan=5><img height=140 src=data:image;base64,$portrait /></td></tr>
<tr><td class=pad-bottom><b>Name: </b></td><td align=right>$name</td><td class=lpad><b>XP: </b></td><td align=right>$xp</td><td class=lpad><b>Age: </b></td align=right><td align=right>$age</td></tr>
<tr><td class=pad-bottom><b>Class: </b></td><td align=right class=class-font>$class</td><td class=lpad><b>HP: </b></td><td align=right>$hp</td><td class=lpad><b>Height: </b></td><td align=right>$height</td></tr>
<tr><td class=pad-bottom><b>Alignment: </b></td><td align=right class=alignment-font>$alignment</td><td class=lpad><b>AC: </b></td><td align=right>$ac</td><td class=lpad><b>Weight: </b></td><td align=right>$weight</td></tr>
<tr><td class=pad-bottom><b>Race: </b></td><td align=right>$race</td><td class=lpad><b>Level: </b></td><td align=right>$level</td><td class=lpad><b>Gender: </b></td><td align=right>$gender</td></tr>
</table>

<hr />

<table align=center><tr>

<td>
<table class='border bigger-font' border=2 ><tr><td>
<table class=pad-cell>
<tr><td align=right class=pad-cell>Str:</td><td align=right class=pad-cell>$STR</td><td class=attr-bonuses> $STR_bonus </td></tr>
<tr><td align=right class=pad-cell>Int:</td><td align=right class=pad-cell>$INT</td><td class=attr-bonuses> $INT_bonus </td></tr>
<tr><td align=right class=pad-cell>Wis:</td><td align=right class=pad-cell>$WIS</td><td class=attr-bonuses> $WIS_bonus </td></tr>
<tr><td align=right class=pad-cell>Dex:</td><td align=right class=pad-cell>$DEX</td><td class=attr-bonuses> $DEX_bonus </td></tr>
<tr><td align=right class=pad-cell>Con:</td><td align=right class=pad-cell>$CON</td><td class=attr-bonuses> $CON_bonus  </td></tr>
<tr><td align=right class=pad-cell>Cha:</td><td align=right class=pad-cell>$CHA</td><td class=attr-bonuses> $CHA_bonus </td></tr>
</table>
</td></tr></table>
</td>

<td>
<table class=smaller-font align=center border=1>
<tr><td colspan=2><h3 align=center>Saving Throws</h3></td></tr>
<tr><td class=pad-cell>Aimed Magic Items</td><td class=pad-cell align=right>$Aimed_Magic_Items </td></tr>
<tr><td class=pad-cell>Breath Weapon</td><td class=pad-cell align=right>$Breath_Weapons </td></tr>
<tr><td class=pad-cell>Death, Paralysis, Poison</td><td class=pad-cell align=right>$Death_Paralysis_Poison </td></tr>
<tr><td class=pad-cell>Petrifaction, Polymorph</td><td class=pad-cell align=right>$Petrifaction_Polymorph </td></tr>
<tr><td class=pad-cell>Spells</td><td class=pad-cell align=right>$Spells </td></tr>
</tr></table>
</td>

</tr></table>

<hr />

<table class=tohit-table border=1 align=center>
<tr><td><b>Enemy AC</b></td><td align=center> -10 </td><td align=center> -9 </td><td align=center> -8 </td><td align=center> -7 </td><td align=center> -6 </td><td align=center> -5 </td>
<td align=center> -4 </td><td align=center> -3 </td><td align=center> -2 </td><td align=center> -1 </td><td align=center> 0 </td><td align=center> 1 </td>
<td align=center> 2 </td><td align=center> 3 </td><td align=center> 4 </td><td align=center> 5 </td><td align=center> 6 </td><td align=center> 7 </td>
<td align=center> 8 </td><td align=center> 9 </td><td align=center> 10 </td></tr>
<tr><td><b>To Hit</b></td>$tohit_row</tr>
</table>

<hr />

<div class=pre align=center>GP: $gp     PP: $pp     EP: $ep     SP: $sp     CP: $cp</div>

<hr />

<table align=center>
<tr><th><h4>Equipment</h4></th></tr>
<tr><td><table border=1 class=equipment-table>
<tr><th>Name</th><th>Damage Vs S or M</th><th>Damage Vs L</th><th>Damage Type</th><th>RoF</th><th>Range</th><th>Max Move</th><th>AC Effect</th><th>Notes</th></tr>
'''

#    proficiency_page = self.pages['ProficiencyPage']
#    specialised_list = proficiency_page.specialised_list
#    double_specialised_list = proficiency_page.double_specialised_list
    for equip in equipment_list:
        equip_name = equip['Name']
        if equip in double_specialised_list:
            equip_name = equip_name + '<sup>&Dagger;</sup>'
        elif equip in specialised_list:
            equip_name = equip_name + '<sup>&dagger;</sup>'
        elif equip in proficiency_list:
            equip_name = equip_name + '*'
        equip_list = [ equip_name, equip['Damage_Vs_S_or_M'], equip['Damage_Vs_L'], equip['Damage_Type'],
                       equip['Rate_of_Fire'], equip['Range'], equip['Max_Move_Rate'], str( equip['AC_Effect'] ), equip['Notes'] ]
        markup += '<tr><td align=center>' + '</td><td align=center>'.join( equip_list ) + '</td></tr>'

    markup += '''
</table></td></tr></table>
<div align=center class="equip-legend pre">*=Proficient     &dagger;=Specialised     &Dagger;=Double Specialised</div>
<div><b>Movement Rate: </b>$movement_rate ft/round<br />
<b>Surprise: </b>$movement_desc<br />
<b>Non-Proficiency Penalty: </b>$nonproficiency_penalty</div>

<p class=page-break></p>
<h2>Ablities</h2>
'''

    if class_abilities:
        for cl in list( class_abilities.keys() ):
            markup += '\n<h5>{} Abilities</h5>\n'.format( cl )
            for i, a in enumerate( class_abilities[cl] ):
                if a[0]:
                    if i > 0:
                        markup += '<br />'
                    markup += '<b>{}: </b>{}\n'.format( *a )
                else:
                    markup += '<table class=ability align=center border=1>\n<tr>'
                    for h in a[1][0]:
                        markup += '<th align=center>{}</th>'.format(h)
                    markup += '</tr>\n<tr>'
                    for d in a[1][1]:
                        markup += '<td align=center>{}</td>'.format(d)
                    markup += '</tr>\n</table>\n'

    if race_abilities:
        markup += '\n<h5>{} Abilites</h5>\n'.format( race_dict['Name'] )
        markup += '<ul>\n'
        for a in race_abilities:
            markup += '<li>'
            markup += a[0]
            if a[1]:
                markup += ' {}'.format( a[1] )
            if a[2]:
                markup += ' {}'.format( a[2] )
            markup += '</li>\n'
        markup += '</ul>\n'

    spellcaster = False
    if 'classes' in class_dict:
        level_list = [ int(l) for l in level.split( '/' ) ]
        for i, cl in enumerate( class_dict['classes'] ):
            if has_spells_at_level( level_list[i], cl ):
                spellcaster = True
    else:
        if has_spells_at_level( level, class_dict ):
            spellcaster = True

    if spellcaster:
        spell_item_string = '''
<h3>{Name}</h3>
<b>Reversible: </b>{Reversible}<br/>
<b>Level: </b>{Level}<br />
<b>Damage: </b>{Damage}<br />
<b>Range: </b>{Range}<br />
<b>Duration: </b>{Duration}<br />
<b>Area of Effect: </b>{Area_of_Effect}<br />
<b>Components: </b>{Components}<br />
<b>Casting Time: </b>{Casting_Time}<br />
<b>Saving Throw: </b>{Saving_Throw}<br />
<b>Description: </b><span class=pre>{Description}</span><br /><br />
'''
        markup += '<p class=page-break></p>\n<h2>Spells</h2>\n'
        if spellbook:
            markup += '<h5>Spellbook</h5>\n<hr />'
            for spell in spellbook:
                markup += spell_item_string.format( **spell )
            markup += '<hr />\n'
        if daily_spells:
            markup += '<h5>{} Daily Spells</h5>\n<hr />'.format( daily_spells[0]['Type'].title().replace( '_', ' ' ) )
            for spell in daily_spells:
                markup += spell_item_string.format( **spell )
            markup += '<hr />\n'
        if daily_spells2:
            markup += '<h5>{} Daily Spells</h5>\n<hr />'.format( daily_spells2[0]['Type'].title().replace( '_', ' ' ) )
            for spell in daily_spells2:
                markup += spell_item_string.format( **spell )
            markup += '<hr />\n'

    t = Template(markup)
    final_markup = t.safe_substitute( markup_template_dict )

    return ( '{}.pdf'.format( character_dict['Name'] ), final_markup )
コード例 #45
0
ファイル: EncounterTracker.py プロジェクト: lowhrtz/PyGM
    def __init__(self):
        super().__init__(1, 'Surprise')
        self.set_subtitle('Determine Surprise')

        item_table = DbQuery.getTable('Items')
        indexed_items = {item['unique_id']: item for item in item_table}

        # Define internal functions
        def pc_tool_tip(pc, _fields, _pages, _external):
            race_dict = SystemSettings.get_race_dict(pc)
            class_dict = SystemSettings.get_class_dict(pc)
            equipment_ids = [
                row['Entry_ID'] for row in pc['Characters_meta']
                if row['Type'] == 'Equipment'
            ]
            # equipment = [equip for equip in item_table if equip['unique_id'] in equipment_ids]
            equipment = [
                indexed_items[equipment_id] for equipment_id in equipment_ids
            ]
            _, surprise = SystemSettings.calculate_movement(
                race_dict, class_dict, pc, equipment)
            return f'''\
<b>{pc['Name']}</b><br />
Surprise: {surprise}<br />
AC: {SystemSettings.calculate_ac(pc, class_dict, race_dict, equipment)}
'''

        def enemy_tool_tip(enemy, _fields, _pages, _external):
            if enemy['TableName'] == 'Monsters':
                special_attacks = enemy['Special_Attacks']
                special_defences = enemy['Special_Defences']
                description = enemy['Description']
                return f'''\
<b>{enemy['Name']}</b><br />
AC: {enemy['AC']}<br />
Special Attacks: {special_attacks}<br />
Special Defences: {special_defences}<br /><br />
{description}
'''
            else:
                return pc_tool_tip(enemy, _fields, _pages, _external)

        # Define Widgets
        pc_team_surprise = Widget('PC Team Surprise', 'SpinBox')
        open_hp_tracker_button = Widget('Open HP Tracker',
                                        'PushButton',
                                        align='Right')
        pc_team = Widget('PC Team',
                         'ListBox',
                         tool_tip=pc_tool_tip,
                         col_span=2)
        monster_team_surprise = Widget('Monster Team Surprise', 'SpinBox')
        monster_team = Widget('Monster Team',
                              'ListBox',
                              tool_tip=enemy_tool_tip,
                              col_span=2)

        # Add Actions
        self.add_action(
            Action('Window', open_hp_tracker_button, callback=open_hp_tracker))
        # self.add_action(Action('Window', pc_team, callback=open_hp_tracker))
        # self.add_action(Action('Window', monster_team, callback=open_hp_tracker))

        # Initialize GUI
        self.add_row([pc_team_surprise, open_hp_tracker_button])
        self.add_row([pc_team])
        self.add_row([monster_team_surprise])
        self.add_row([monster_team])