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, ])
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
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}
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
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': '' }
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
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
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
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)
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 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
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])
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
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
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
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])
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
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
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')}
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, ] )
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 }
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
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}
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])
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
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
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': '' }
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>'
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
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, ])
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, ] )
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
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
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
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
def prefill_chosen_spells( self ): spells_dict_list = DbQuery.getTable( 'Spells' ) return prefill_chosen_spells( self.wizard_type, spells_dict_list )
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])
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
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()
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])
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])
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)
def get_races_html(): return ' '.join([f'<option value="{i["unique_id"]}">{i["Name"]}</option>' for i in DbQuery.getTable('Races')])
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>‡</sup>' elif equip in specialised_list: equip_name = equip_name + '<sup>†</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 †=Specialised ‡=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 )
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])