def prefstring(df): # Get the smallthings ModBase raws, which is where this data will be coming from smallraws = getsmallraws() if not smallraws: return pydwarf.failure('Failed to read smallthings raws.') # Get all creatures smallcreatures = smallraws.allobj('CREATURE') dfcreaturesdict = df.objdict('CREATURE') # Add the new prefstrings failedcreatures = 0 for smallcreature in smallcreatures: dfcreature = dfcreaturesdict.get(smallcreature.args[0]) if not dfcreature: pydwarf.log.debug( 'Found prefstrings for %s but there was no corresponding creature in the DF raws. Skipping.' % smallcreature) failedcreatures += 1 else: prefs = smallcreature.allprop(exact_value='PREFSTRING', args_count=1) dfcreature.add(tokens=prefs.copy()) pydwarf.log.debug('Added %d prefstrings to %s.' % (len(prefs), dfcreature)) # All done! if (len(smallcreatures) - failedcreatures): return pydwarf.success('Added prefstrings to %d creatures.' % (len(smallcreatures) - failedcreatures)) else: return pydwarf.failure('Added prefstrings to no creatures.')
def prefstring(df): # Get the smallthings ModBase raws, which is where this data will be coming from smallraws = getsmallraws() if not smallraws: return pydwarf.failure('Failed to read smallthings raws.') # Get all creatures smallcreatures = smallraws.allobj('CREATURE') dfcreaturesdict = df.objdict('CREATURE') # Add the new prefstrings failedcreatures = 0 for smallcreature in smallcreatures: dfcreature = dfcreaturesdict.get(smallcreature.args[0]) if not dfcreature: pydwarf.log.debug('Found prefstrings for %s but there was no corresponding creature in the DF raws. Skipping.' % smallcreature) failedcreatures += 1 else: prefs = smallcreature.allprop(exact_value='PREFSTRING', args_count=1) dfcreature.add(tokens=prefs.copy()) pydwarf.log.debug('Added %d prefstrings to %s.' % (len(prefs), dfcreature)) # All done! if (len(smallcreatures) - failedcreatures): return pydwarf.success('Added prefstrings to %d creatures.' % (len(smallcreatures) - failedcreatures)) else: return pydwarf.failure('Added prefstrings to no creatures.')
def restrictnobles_custom(raws, inclusions=None, exclusions=None): mountain = raws.get('ENTITY:MOUNTAIN') if mountain: positions = mountain.alluntil(exact_value='POSITION', until_exact_value='ENTITY') if inclusions: pydwarf.log.debug('Handling position inclusions %s...' % inclusions) for inclusion in inclusions: for position in positions: addwm(position, 'ALLOWED_CLASS:WITTY_%s' % inclusion) creature = raws.getobj('CREATURE', inclusion) if creature: addwm(creature, 'CREATURE_CLASS:WITTY_%s' % inclusion) else: return pydwarf.failure('Couldn\'t find CREATURE:%s.' % inclusion) if exclusions: pydwarf.log.debug('Handling position exclusions %s...' % exclusions) for exclusion in exclusions: for position in positions: addwm(position, 'REJECTED_CLASS:WITTY_%s' % exclusion) creature = raws.getobj('CREATURE', exclusion) if creature: addwm(creature, 'CREATURE_CLASS:WITTY_%s' % exclusion) else: return pydwarf.failure('Couldn\'t find CREATURE:%s.' % exclusion) return pydwarf.success('Restricted %d positions.' % len(positions)) else: return pydwarf.failure('Couldn\'t find ENTITY:MOUNTAIN.')
def bauxitetoaluminum(df, aluminum_value=0.75, entities=default_entities, add_to_file=default_file): # Affect value of aluminum pydwarf.log.debug('Multiplying value of aluminum by %f.' % aluminum_value) try: aluminum = df.getobj('INORGANIC:ALUMINUM') if aluminum is None: return pydwarf.failure('Couldn\'t find aluminum token to affect its value.') matvaluetoken = aluminum.getprop('MATERIAL_VALUE') matvaluetoken.args[0] = int( float(matvaluetoken.args[0]) * aluminum_value ) except: pydwarf.log.exception('Failed to affect value of aluminum.') return pydwarf.failure() # Add the reaction return pydwarf.urist.getfn('pineapple.utils.addobject')( df, type = 'REACTION', id = 'SMELT_BAUXITE_ALUMINUM_PINEAPPLE', tokens = ''' [NAME:smelt aluminum from bauxite] [SMELTER] [REAGENT:1:STONE:NO_SUBTYPE:STONE:BAUXITE] [REAGENT:1:STONE:NO_SUBTYPE:STONE:CRYOLITE] [PRODUCT:100:1:BAR:NO_SUBTYPE:METAL:ALUMINUM] [FUEL] ''', add_to_file = add_to_file, permit_entities = entities )
def subterraneanplants(df): # Get subterranean plants subplants = [] for plant in df.allobj('PLANT'): if plant.getprop('BIOME:SUBTERRANEAN_WATER'): subplants.append(plant) if not len(subplants): return pydwarf.failure('Found no subterranean plants.') # Ensure each has all four seasons pydwarf.log.info('Found %d subterranean plants. Modifying...' % len(subplants)) modified = 0 for subplant in subplants: seasontokens = subplant.allprop(value_in=seasons) if len(seasontokens) > 0 and len(seasontokens) < len(seasons): pydwarf.log.debug('Adding season tokens to %s...' % subplant) # First remove the existing tokens (To avoid making duplicates) for seasontoken in seasontokens: seasontoken.remove() # Then add all four anew for season in seasons: subplant.add(raws.token(value=season)) modified += 1 else: pydwarf.log.debug('Plant %s either has no seasonal tokens or already has all of them, skipping.' % subplant) # All done if modified > 0: return pydwarf.success('Made %d subterranean plants grow year-round.' % modified) else: return pydwarf.failure('All subterranean plants already grew year-round.')
def bauxitetoaluminum(df, aluminum_value=0.75, entities=default_entities, add_to_file=default_file): # Affect value of aluminum pydwarf.log.debug('Multiplying value of aluminum by %f.' % aluminum_value) try: aluminum = df.getobj('INORGANIC:ALUMINUM') if aluminum is None: return pydwarf.failure( 'Couldn\'t find aluminum token to affect its value.') matvaluetoken = aluminum.getprop('MATERIAL_VALUE') matvaluetoken.args[0] = int( float(matvaluetoken.args[0]) * aluminum_value) except: pydwarf.log.exception('Failed to affect value of aluminum.') return pydwarf.failure() # Add the reaction return pydwarf.urist.getfn('pineapple.utils.addobject')( df, type='REACTION', id='SMELT_BAUXITE_ALUMINUM_PINEAPPLE', tokens=''' [NAME:smelt aluminum from bauxite] [SMELTER] [REAGENT:1:STONE:NO_SUBTYPE:STONE:BAUXITE] [REAGENT:1:STONE:NO_SUBTYPE:STONE:CRYOLITE] [PRODUCT:100:1:BAR:NO_SUBTYPE:METAL:ALUMINUM] [FUEL] ''', add_to_file=add_to_file, permit_entities=entities)
def restrictnobles_custom(raws, inclusions=None, exclusions=None): mountain = raws.get('ENTITY:MOUNTAIN') if mountain: positions = mountain.alluntil(exact_value='POSITION', until_exact_value='ENTITY') if inclusions: pydwarf.log.debug('Handling position inclusions %s...' % inclusions) for inclusion in inclusions: for position in positions: addwm(position, 'ALLOWED_CLASS:WITTY_%s' % inclusion) creature = raws.get(exact_value='CREATURE', exact_args=[inclusion]) if creature: addwm(creature, 'CREATURE_CLASS:WITTY_%s' % inclusion) else: return pydwarf.failure('Couldn\'t find CREATURE:%s.' % inclusion) if exclusions: pydwarf.log.debug('Handling position exclusions %s...' % exclusions) for exclusion in exclusions: for position in positions: addwm(position, 'REJECTED_CLASS:WITTY_%s' % exclusion) creature = raws.get(exact_value='CREATURE', exact_args=[exclusion]) if creature: addwm(creature, 'CREATURE_CLASS:WITTY_%s' % exclusion) else: return pydwarf.failure('Couldn\'t find CREATURE:%s.' % exclusion) return pydwarf.success('Restricted %d positions.' % len(positions)) else: return pydwarf.failure('Couldn\'t find ENTITY:MOUNTAIN.')
def engraving(df): if 'descriptor_shape_umiman' in df: return pydwarf.failure('File descriptor_shape_umiman already exists.') # Get the smallthings ModBase raws, which is where this data will be coming from smallraws = getsmallraws() if not smallraws: return pydwarf.failure('Failed to read smallthings raws.') # Get existing words and shapes dfwordsdict = df.objdict('WORD') dfshapesdict = df.objdict('SHAPE') # Add a new file for the new shapes dfshapesfile = df.add('raw/objects/descriptor_shape_umiman.txt') dfshapesfile.add('OBJECT:DESCRIPTOR_SHAPE') shapesadded = 0 # Add each shape smallshapes = smallraws['descriptor_shape_standard'] if smallshapes is None: return pydwarf.failure( 'Failed to find smallthings raws file named descriptor_shape_standard.' ) for smallshape in smallshapes.all(exact_value='SHAPE'): if smallshape.args[ 0] not in dfshapesdict: # Verify that the shape isn't already in the raws pydwarf.log.debug('Adding shape %s...' % smallshape) # Get the tokens describing this shape smallshapetokens = smallshape.all(until_exact_value='SHAPE') # Shapes in DF's descriptor_shape_standard all have a [WORD:X] token but these do not # To compensate, let's do our best to map each shape to a word automatically smallshapename = smallshape.get(exact_value='NAME', args_count=2) if smallshapename: useshapename = smallshapename.args[0].upper() if useshapename in shapenamedict: useshapename = shapenamedict[useshapename] shapeword = dfwordsdict.get(useshapename) else: pydwarf.log.error('Found no names for %s.' % shallshape) # Actually add the new shape to the raws dfshapesfile.add(smallshape.copy()) dfshapesfile.add(smallshapetokens.copy()) # And also add the word, provided one was found if shapeword: dfshapesfile.add( raws.token(value='WORD', args=(shapeword.args[0], ))) else: pydwarf.log.info('Found no word for %s, named %s.' % (smallshape, smallshapename)) # And on to the next iteration shapesadded += 1 # All done! return pydwarf.success('Added %s new shapes.' % shapesadded)
def orientation(df, creatures=default_creatures, mode='hetero', lover_chance=default_lover_chance): if isinstance(mode, basestring): if mode not in mode_info: return pydwarf.failure( 'Invalid mode %s. Recognized modes are these: %s.' % (mode, ', '.join(mode_tokens.keys()))) usemode = mode_info[mode] else: usemode = mode # Unpack variables for convenience disinterestsame, loversame, commitsame, disinterestother, loverother, commitother = usemode # Get tokens for all the specified creatures creatures = df.allobj(type='CREATURE', id_in=creatures) pydwarf.log.debug('Found %d applicable creatures.' % len(creatures)) # Add tokens after [FEMALE] and [MALE] tokens added = 0 for creature in creatures: pydwarf.log.debug('Applying ORIENTATION changes to %s.' % creature) # Remove any existing ORIENTATION tokens removetokens = creature.allprop(exact_value='ORIENTATION') if len(removetokens): pydwarf.log.debug( 'Removing %d existing ORIENTATION tokens from token %s.' % (len(removetokens), gendertoken)) for removetoken in removetokens: removetoken.remove() # Add the new orientation tokens gendertokens = creature.allprop(value_in=('FEMALE', 'MALE'), args_count=0) for gendertoken in gendertokens: othergender = 'FEMALE' if gendertoken.value == 'MALE' else 'MALE' gendertoken.add( raws.token(value='ORIENTATION', args=[ othergender, disinterestother, loverother, commitother ])) gendertoken.add( raws.token(value='ORIENTATION', args=[ gendertoken.value, disinterestsame, loversame, commitsame ])) added += 1 # All done! if added > 0: return pydwarf.success( 'Appended ORIENTATION tokens after %d gender tokens.' % added) else: return pydwarf.failure('Found no gender tokens to add ORIENTATION to.')
def addhack(df, auto_run, onload=True, startup=False, **kwargs): name = kwargs.get('name', kwargs.get('path', 'unnamed')) onload_path = 'raw/onLoad.init' startup_path = 'dfhack.init' if kwargs: pydwarf.log.debug('Adding new file %s.' % name) hackfile = df.add(**kwargs) else: hackfile = None if auto_run: if auto_run is True: if not hackfile: return pydwarf.failure('Failed to add lines to DFHack because auto_run was True but no file was created.') auto_run = '\n%s' % hackfile.name pydwarf.log.debug('Adding text %s to the end of dfhack.init.' % auto_run) addtext = '\n%s\n' % auto_run if onload: if onload_path not in df: init = df.add( loc = 'raw', name = 'onLoad', ext = '.init', kind = raws.binfile ) else: init = df[onload_path] init.add(addtext) if startup: if startup_path not in df: if 'dfhack.init-example' in df: pydwarf.log.info('Copying dfhack.init-example to new file dfhack.init before adding new content to the file.') init = df['dfhack.init-example'].copy().bin() init.name = startup_path df.add(file=init) else: return pydwarf.failure('Failed to locate dfhack.init or dfhack.init-example.') else: init = df[startup_path].bin() init.add(addtext) return pydwarf.success( 'Added text to %s: "%s"' % ( ' and '.join( item for item in ( onload_path if onload else None, startup_path if startup else None ) if item ), auto_run ) ) else: return pydwarf.success('Added new file %s.' % name)
def addhack(df, auto_run, onload=True, startup=False, **kwargs): name = kwargs.get('name', kwargs.get('path', 'unnamed')) onload_path = 'raw/onLoad.init' startup_path = 'dfhack.init' if kwargs: pydwarf.log.debug('Adding new file %s.' % name) hackfile = df.add(**kwargs) else: hackfile = None if auto_run: if auto_run is True: if not hackfile: return pydwarf.failure( 'Failed to add lines to DFHack because auto_run was True but no file was created.' ) auto_run = '\n%s' % hackfile.name pydwarf.log.debug('Adding text %s to the end of dfhack.init.' % auto_run) addtext = '\n%s\n' % auto_run if onload: if onload_path not in df: init = df.add(loc='raw', name='onLoad', ext='.init', kind=raws.binfile) else: init = df[onload_path] init.add(addtext) if startup: if startup_path not in df: if 'dfhack.init-example' in df: pydwarf.log.info( 'Copying dfhack.init-example to new file dfhack.init before adding new content to the file.' ) init = df['dfhack.init-example'].copy().bin() init.name = startup_path df.add(file=init) else: return pydwarf.failure( 'Failed to locate dfhack.init or dfhack.init-example.') else: init = df[startup_path].bin() init.add(addtext) return pydwarf.success( 'Added text to %s: "%s"' % (' and '.join(item for item in (onload_path if onload else None, startup_path if startup else None) if item), auto_run)) else: return pydwarf.success('Added new file %s.' % name)
def trans(dfraws, species=default_species, beards=True, frequency=500): # Add new interaction pydwarf.log.debug('Adding sterility interaction...') objinteraction = dfraws.get('OBJECT:INTERACTION') if objinteraction: objinteraction.add(pretty=add_sterile_interaction) else: return pydwarf.failure('Unable to add sterility interaction.') # Add new castes creaturetokendict = dfraws.objdict('CREATURE') castefailures = [] for creature in species: pydwarf.log.debug('Handling creature %s...' % creature) creaturetoken = creaturetokendict.get(creature) if creaturetoken: castes = creaturetoken.alluntil(exact_value='CASTE', args_count=1, until_exact_value='CREATURE') if len(castes) == 2 and ((castes[0].args[0] == 'MALE' and castes[1].args[0] == 'FEMALE') or (castes[1].args[0] == 'MALE' and castes[0].args[0] == 'FEMALE')): # Remove DESCRIPTION token from the creature and add it to each caste descriptiontoken = creaturetoken.get(exact_value='DESCRIPTION', args_count=1) if descriptiontoken: descriptiontoken.remove() for castetoken in castes: castetoken.add(token=raws.token.copy(descriptiontoken)) # Handle existing castes for caste in castes: # Add beards to dwarven women if beards and caste.args[0] == 'FEMALE': caste.add(pretty=add_beard_tokens) # Add population ratio token caste.add(raws.token(value='POP_RATIO', args=[str(frequency)])) # Add each new caste for castename, castedict in additional_castes.iteritems(): castetoken = castes[0].add(raws.token(value='CASTE', args=[castename]), reverse=True) # Every new caste gets these tokens castetoken.add(pretty=add_trans_tokens) # Add beards to new dwarf castes if beards and creature == 'DWARF': castetoken.add(pretty=add_beard_tokens) # Tokens unique to each new caste if 'addtokens' in castedict: castetoken.add(pretty=castedict['addtokens']) # Add the caste-specific description description = ' '.join((descriptiontoken.args[0], castedict['description'])) if descriptiontoken else castedict['description'] castetoken.add(raws.token(value='DESCRIPTION', args=[description])) else: pydwarf.log.error('Unexpected castes for creature %s: %s.' % (creature, castes)) castefailures.append(creature) else: pydwarf.log.error('Failed to find token for creature %s.' % creature) castefailures.append(creature) if len(castefailures) == 0: return pydwarf.success('Added new castes to %d creatures.' % len(species)) else: return pydwarf.failure('Added new castes to %d creatures, but failed to add castes to %s.' % (len(species) - len(castefailures), castefailures))
def addreaction(df, id, tokens, add_to_file='reaction_custom', permit_entities=None): if permit_entities is not None and (not addtoentity(df, permit_entities, permitted_reaction=(id,)).success): return pydwarf.failure('Failed to add permitted reactions to entites.') else: if df.getobj(type='REACTION', exact_id=id): return pydwarf.failure('Reaction %s already exists.' % id) else: rfile = df.getfile(add_to_file, create=True) rfile.add(raws.token(value='REACTION', args=[id], prefix='\n\n')).add(tokens) return pydwarf.success('Added reaction %s to file %s and entities %s.' % (id, add_to_file, permit_entities))
def engraving(df): if 'descriptor_shape_umiman' in df: return pydwarf.failure('File descriptor_shape_umiman already exists.') # Get the smallthings ModBase raws, which is where this data will be coming from smallraws = getsmallraws() if not smallraws: return pydwarf.failure('Failed to read smallthings raws.') # Get existing words and shapes dfwordsdict = df.objdict('WORD') dfshapesdict = df.objdict('SHAPE') # Add a new file for the new shapes dfshapesfile = df.add('raw/objects/descriptor_shape_umiman.txt') dfshapesfile.add('OBJECT:DESCRIPTOR_SHAPE') shapesadded = 0 # Add each shape smallshapes = smallraws['descriptor_shape_standard'] if smallshapes is None: return pydwarf.failure('Failed to find smallthings raws file named descriptor_shape_standard.') for smallshape in smallshapes.all(exact_value='SHAPE'): if smallshape.args[0] not in dfshapesdict: # Verify that the shape isn't already in the raws pydwarf.log.debug('Adding shape %s...' % smallshape) # Get the tokens describing this shape smallshapetokens = smallshape.all(until_exact_value='SHAPE') # Shapes in DF's descriptor_shape_standard all have a [WORD:X] token but these do not # To compensate, let's do our best to map each shape to a word automatically smallshapename = smallshape.get(exact_value='NAME', args_count=2) if smallshapename: useshapename = smallshapename.args[0].upper() if useshapename in shapenamedict: useshapename = shapenamedict[useshapename] shapeword = dfwordsdict.get(useshapename) else: pydwarf.log.error('Found no names for %s.' % shallshape) # Actually add the new shape to the raws dfshapesfile.add(smallshape.copy()) dfshapesfile.add(smallshapetokens.copy()) # And also add the word, provided one was found if shapeword: dfshapesfile.add(raws.token(value='WORD', args=(shapeword.args[0],))) else: pydwarf.log.info('Found no word for %s, named %s.' % (smallshape, smallshapename)) # And on to the next iteration shapesadded += 1 # All done! return pydwarf.success('Added %s new shapes.' % shapesadded)
def permitobject(df, type=None, id=None, permit_entities=None, all_entities=False, item_rarity=None): # Decide what tokens need to be added to the entities based on the object type if type == 'REACTION': tokens = raws.token(value='PERMITTED_REACTION', args=[id]) elif type.startswith('BUILDING_'): tokens = raws.token(value='PERMITTED_BUILDING', args=[id]) elif type.startswith('ITEM_'): value = type.split('_')[1] args = [id, item_rarity] if item_rarity else [id] tokens = raws.token(value=value, args=args) else: tokens = None pydwarf.log.debug('Permitting object [%s:%s] for %s entities.' % ( type, id, 'all' if all_entities == '*' else len(permit_entities) )) # Actually add those tokens if tokens is None: return pydwarf.success('Didn\'t actually permit object [%s:%s] because objects of this type cannot be permitted.' % (type, id)) elif not permit_entities: return pydwarf.failure('No entities were given for permitting.') else: response = addtoentity( df, entities = permit_entities, tokens = tokens ) if not response: return response else: return pydwarf.success('Permitted object [%s:%s] for %d entities.' % (type, id, len(permit_entities)))
def metalitems(df, metals=default_metals, items=default_item_tokens): # Handle each metal modified = 0 for inorganictoken in df.allobj('INORGANIC'): if inorganictoken.args[0] in metals: metal = inorganictoken.args[0] pydwarf.log.debug('Handling metal %s...' % metal) itemtokens = inorganictoken.allprop(value_in=items) if len(itemtokens) < len(items): pydwarf.log.debug('Adding tokens to metal %s...' % metal) # Remove existing item tokens from the list (To avoid making duplicates) for itemtoken in itemtokens: itemtoken.remove() # Add new ones templatetoken = inorganictoken.getlastprop('USE_MATERIAL_TEMPLATE') addaftertoken = templatetoken if templatetoken else inorganictoken for item in items: addaftertoken.add(item) modified += 1 else: pydwarf.log.debug('Metal %s already allows all the item types specified, skipping.' % metal) # All done if modified > 0: return pydwarf.success('Added tokens to %d metals.' % modified) else: return pydwarf.failure('No tokens were added to any metals.')
def stoneclarity(dfraws, rules=default_rules, query=default_inorganics_query, fuels=None): if rules and len(rules): groups, ids = builddicts(query, dfraws, fuels if fuels else autofuels(dfraws, pydwarf.log), pydwarf.log) applyrules(rules, groups, ids) return pydwarf.success('Finished applying %d rules to %d inorganic groups and %d inorganic ids.' % (len(rules), len(groups), len(ids))) else: return pydwarf.failure('I was given no rules to follow.')
def controllable(df, entities='*'): controllable = set() if entities == '*': # Enable all entities for entity in df.allobj('ENTITY'): entity.setprop('SITE_CONTROLLABLE') controllable.add(entity.args[0]) else: # Enable listed entities and disable others entities = set([entities]) if isinstance(entities, basestring) else set(entities) for entity in df.allobj('ENTITY'): if entity.args[0] in entities: entity.setprop('SITE_CONTROLLABLE') controllable.add(entity.args[0]) entities.remove(entity.args[0]) else: entity.removeprop('SITE_CONTROLLABLE') if entities: pydwarf.log.error( 'Nonexistent objects in controllable entities list: %s' % ', '.join(entities) ) if controllable: return pydwarf.success('Assigned %d controllable entities.' % len(controllable)) else: return pydwarf.failure('Assigned no controllable entities.')
def butcherinorganic(df, templates=default_templates): added = 0 # Apply BUTCHER_SPECIAL tokens to material templates for templatename, butcherspecial in templates.iteritems(): template = df.getobj(type='MATERIAL_TEMPLATE', exact_id=templatename) if template: pydwarf.log.debug( 'Adding BUTCHER_SPECIAL item %s to material template %s.' % (butcherspecial, templatename)) template.addprop( raws.token(value='BUTCHER_SPECIAL', args=[butcherspecial, 'NONE'])) added += 1 else: pydwarf.log.error('Unable to find template %s, skipping.' % templatename) # All done! if added > 0: return pydwarf.success( 'Added BUTCHER_SPECIAL to %d material templates.' % added) else: return pydwarf.failure( 'Added BUTCHER_SPECIAL to no material templates.')
def noaquifers(df): aquifers = df.all('AQUIFER') if len(aquifers): for aquifer in aquifers: aquifer.remove() return pydwarf.success('Removed %d AQUIFER tokens.' % len(aquifers)) else: return pydwarf.failure('Found no AQUIFER tokens.')
def permitobject(df, type=None, id=None, permit_entities=None, item_rarity=None): # Decide what tokens need to be added to the entities based on the object type if type == 'REACTION': tokens = raws.token(value='PERMITTED_REACTION', args=[id]) elif type.startswith('BUILDING_'): tokens = raws.token(value='PERMITTED_BUILDING', args=[id]) elif type.startswith('ITEM_'): value = type.split('_')[1] args = [id, item_rarity] if item_rarity else [id] tokens = raws.token(value=value, args=args) else: tokens = None pydwarf.log.debug('Permitting object [%s:%s] for %d entities.' % (type, id, len(permit_entities))) # Actually add those tokens if tokens is None: return pydwarf.success( 'Didn\'t actually permit object [%s:%s] because objects of this type cannot be permitted.' % (type, id)) elif not permit_entities: return pydwarf.failure('No entities were given for permitting.') else: response = addtoentity(df, entities=permit_entities, tokens=tokens) if not response: return response else: return pydwarf.success( 'Permitted object [%s:%s] for %d entities.' % (type, id, len(permit_entities)))
def fantastic(df, dwarves=dwarf_entities): # Add properties to various inorganics as defined by the add_properties dict errors = 0 for identifier, re_id, addprops in add_properties: additions = df.allobj(type='INORGANIC', re_id=re_id).each( lambda token: token.addprop(addprops), none=True) if len(additions): pydwarf.log.debug('Added %s properties to %d inorganics.' % (identifier, len(additions))) else: errors += 1 pydwarf.log.error( 'Failed to add %s properties because no matching inorganics were found.' % identifier) for path in add_paths: pydwarf.log.debug('Adding file at %s.' % path) df.add(path=path, loc='raw/objects') for path in patch_paths: response = pydwarf.urist.getfn('pineapple.easypatch')( df, files=path, loc='raw/objects', permit_entities=dwarves) if not response: return response if not errors: return pydwarf.success() else: return pydwarf.failure( 'Failed to add inorganic properties for %d groups.' % errors)
def objecttokens(df, object_type, token, add_to=None, remove_from=None): added, removed = 0, 0 # Remove tokens if remove_from: for objtoken in df.allobj( type=object_type, id_in=(None if remove_from == '*' else remove_from)): for removetoken in objtoken.allprop(token): removetoken.remove() removed += 1 # Add tokens if add_to: for objtoken in df.allobj(type=object_type, id_in=(None if add_to == '*' else add_to)): if not objtoken.getprop(token): objtoken.addprop(token) added += 1 # All done! if removed or added: return pydwarf.success( 'Added %d %s tokens and removed %d from object type %s.' % (added, token, removed, object_type)) else: return pydwarf.failure('Didn\'t add or remove any %s tokens.' % token)
def materialsplus(df, entities=default_entities): # Add properties to various inorganics as defined by the add_properties dict errors = 0 for identifier, re_id, addprops in add_properties: additions = df.allobj(type='INORGANIC', re_id=re_id).each( lambda token: token.addprop(addprops), none=True ) if len(additions): pydwarf.log.debug('Added %s properties to %d inorganics.' % (identifier, len(additions))) else: errors += 1 pydwarf.log.error('Failed to add %s properties because no matching inorganics were found.' % identifier) for path in add_paths: pydwarf.log.debug('Adding file at %s.' % path) df.add(path=path, loc='raw/objects') for path in patch_paths: response = pydwarf.urist.getfn('pineapple.easypatch')( df, files = path, loc = 'raw/objects', permit_entities = entities ) if not response: return response if not errors: return pydwarf.success() else: return pydwarf.failure('Failed to add inorganic properties for %d groups.' % errors)
def maxage(df, required_property=default_required_property, apply_to_creatures=None): removedfrom = [] creaturedict = df.objdict('CREATURE') # Handle by properties if required_property: remove_all = len(required_property) == 1 and required_property[0] == '*' for creaturename, creaturetoken in creaturedict.iteritems(): if remove_all or (creaturetoken.getprop(value_in=required_property) is not None): maxage = creaturetoken.getprop('MAXAGE') if maxage: maxage.remove(); removedfrom.append(creaturetoken) # Handle by creature names if apply_to_creatures: for creaturename in apply_to_creatures: creaturetoken = creaturedict.get(creaturename) if creaturetoken: maxage = creaturetoken.getprop('MAXAGE') if maxage: maxage.remove(); removedfrom.append(creaturetoken) else: pydwarf.log.error('Couldn\'t find creature %s for removal of MAXAGE token.' % creaturename) # All done! pydwarf.log.debug('Removed MAXAGE tokens from creatures: %s.' % [token.args[0] for token in removedfrom]) if len(removedfrom): return pydwarf.success('Removed MAXAGE tokens from %d creatues.' % len(removedfrom)) else: return pydwarf.failure('Found no MAXAGE tokens to remove.')
def controllable(df, entities='*'): controllable = set() if entities == '*': # Enable all entities for entity in df.allobj('ENTITY'): entity.setprop('SITE_CONTROLLABLE') controllable.add(entity.args[0]) else: # Enable listed entities and disable others entities = set([entities]) if isinstance(entities, basestring) else set(entities) for entity in df.allobj('ENTITY'): if entity.args[0] in entities: entity.setprop('SITE_CONTROLLABLE') controllable.add(entity.args[0]) entities.remove(entity.args[0]) else: entity.removeprop('SITE_CONTROLLABLE') if entities: pydwarf.log.error( 'Nonexistent objects in controllable entities list: %s' % ', '.join(entities)) if controllable: return pydwarf.success('Assigned %d controllable entities.' % len(controllable)) else: return pydwarf.failure('Assigned no controllable entities.')
def addtoentity(df, entities, tokens): if entities == '*': pydwarf.log.debug('Adding tokens to all entities.') entitytokens = df.allobj(type='ENTITY') else: if isinstance(entities, basestring): entities = (entities, ) pydwarf.log.debug('Adding tokens to entities %s.' % ', '.join(str(ent) for ent in entities)) entitytokens = df.allobj(type='ENTITY', id_in=entities) for entitytoken in entitytokens: entitytoken.addprop(tokens) if isinstance(tokens, raws.queryable): tokens = raws.helpers.copy( tokens ) # TODO: What about other iterables containing token objects, e.g. lists and tuples? if entities != '*' and len(entitytokens) != len(entities): return pydwarf.failure( 'Failed to add tokens to all given entities because only %d of %d exist.' % (len(entitytokens), len(entities))) else: return pydwarf.success('Added tokens to %d entities.' % len(entitytokens))
def noaquifers(df): # Do the removing aquifers = df.removeall('AQUIFER') # All done! if len(aquifers): return pydwarf.success('Removed %d AQUIFER tokens.' % len(aquifers)) else: return pydwarf.failure('Found no AQUIFER tokens.')
def flybears(raws): bears = raws.allobj('CREATURE', re_id='BEAR_.+') for bear in bears: bear.get('CASTE:FEMALE').add('FLIER') if len(bears): return pydwarf.success('Made %d bear species fliers.' % len(bears)) else: return pydwarf.failure('Couldn\'t find any bears to make fliers.')
def nograzers(raws): grazers = raws.all(exact_value='GRAZER') standardgrazers = raws.all('STANDARD_GRAZER') for grazer in grazers: grazer.remove() for grazer in standardgrazers: grazer.remove() if len(grazers) or len(standardgrazers): return pydwarf.success('Removed %d GRAZER and %d STANDARD_GRAZER tokens.' % (len(grazers), len(standardgrazers))) else: return pydwarf.failure('I found no grazer tokens to replace.')
def deerappear(df, creature='DEER', tile="'d'", color=['6','0','1']): # Find the first token that looks like [CREATURE:DEER] deertoken = df.getobj('CREATURE', creature) if deertoken: # Find the first token, following [CREATURE:DEER], that looks like [CREATURE_TILE:'D'] deertile = deertoken.getprop(exact_value='CREATURE_TILE', args_count=1) # Find the first token, following [CREATURE:DEER], that looks like [COLOR:6:0:0] deercolor = deertoken.getprop(exact_value='COLOR', args_count=3) if deertile and deercolor: # Change the token to look like [CREATURE_TILE:'d'] deertile.args[0] = tile # Change the token to look like [COLOR:6:0:1] deercolor.args = color return pydwarf.success() else: return pydwarf.failure('Didn\'t find CREATURE_TILE and COLOR tokens as expected.') else: return pydwarf.failure('I couldn\'t find the deer token.')
def noexotic(df): pets = df.all('PET_EXOTIC') mounts = df.all('MOUNT_EXOTIC') for token in pets: token.value = 'PET' for token in mounts: token.value = 'MOUNT' if len(pets) or len(mounts): return pydwarf.success('Replaced %d PET_EXOTIC and %d MOUNT_EXOTIC tokens.' % (len(pets), len(mounts))) else: return pydwarf.failure('I found no PET_EXOTIC or MOUNT_EXOTIC tokens to replace.')
def deerappear(raws, creature='DEER', tile="'d'", color=['6','0','1']): # Find the first token that looks like [CREATURE:DEER] deertoken = raws.getobj('CREATURE', creature) if deertoken: # Find the first token, following [CREATURE:DEER], that looks like [CREATURE_TILE:'D'] deertile = deertoken.getuntil(exact_value='CREATURE_TILE', args_count=1, until_exact_value='CREATURE') # Find the first token, following [CREATURE:DEER], that looks like [COLOR:6:0:0] deercolor = deertoken.getuntil(exact_value='COLOR', args_count=3, until_exact_value='CREATURE') if deertile and deercolor: # Change the token to look like [CREATURE_TILE:'d'] deertile.args[0] = tile # Change the token to look like [COLOR:6:0:1] deercolor.args = color return pydwarf.success() else: return pydwarf.failure('Didn\'t find CREATURE_TILE and COLOR tokens as expected.') else: return pydwarf.failure('I couldn\'t find the deer token.')
def nograzers(df): # Do the removing grazers = df.removeall('GRAZER') standardgrazers = df.removeall('STANDARD_GRAZER') # All done! if len(grazers) or len(standardgrazers): return pydwarf.success('Removed %d GRAZER and %d STANDARD_GRAZER tokens.' % (len(grazers), len(standardgrazers))) else: return pydwarf.failure('I found no grazer tokens to remove.')
def noexotic(df): # Do the removing pets = df.all('PET_EXOTIC').each(lambda token: token.setvalue('PET'), none=True) mounts = df.all('MOUNT_EXOTIC').each(lambda token: token.setvalue('MOUNT'), none=True) # All done! if len(pets) or len(mounts): return pydwarf.success('Replaced %d PET_EXOTIC and %d MOUNT_EXOTIC tokens.' % (len(pets), len(mounts))) else: return pydwarf.failure('I found no PET_EXOTIC or MOUNT_EXOTIC tokens to replace.')
def noanimalmen(df): # Do the removing removed = [removedprop for removedprop in df.allobj('CREATURE').each( lambda token: token.removeselfandprops() if token.arg().endswith('_MAN') or token.getprop('APPLY_CREATURE_VARIATION:ANIMAL_PERSON') else None ) if removedprop] # All done! if removed: return pydwarf.success('Removed %d species of animal men.' % len(removed)) else: return pydwarf.failure('Found no animal men to remove.')
def armourypack(dfraws, remove_entity_items=True, remove_attacks=('SCRATCH', 'BITE'), remove_attacks_from=('DWARF', 'HUMAN', 'ELF')): try: armouryraws = raws.dir(path=armourydir, log=pydwarf.log) except: return pydwarf.failure('Unable to load armoury raws.') additemstoraws(dfraws, armouryraws) additemstoents(dfraws, armouryraws, remove_entity_items) addreactions(dfraws, armouryraws) removeattacks(dfraws, remove_attacks, remove_attacks_from) return pydwarf.success()
def removeattacks(df, remove_attacks=('SCRATCH', 'BITE'), remove_attacks_from=('DWARF', 'HUMAN', 'ELF')): removed = 0 for creature in df.allobj(type='CREATURE', id_in=remove_attacks_from): for attack in creature.allprop(exact_value='ATTACK', arg_in=((0, remove_attacks),)): pydwarf.log.debug('Removing attack %s from creature %s.' % (attack, creature)) for token in attack.all(until_re_value='(?!ATTACK_).+'): token.remove() attack.remove() removed += 1 if removed: return pydwarf.success('Removed %d attacks from %d creatures.' % (removed, len(remove_attacks_from))) else: return pydwarf.failure('Removed no attacks from creatures.')
def flybears(df): # Get all bear creature tokens bears = df.allobj('CREATURE', re_id='BEAR_.+') # Add [FLIER] to each of them, immediately after the first CASTE:FEMALE token for bear in bears: bear.get('CASTE:FEMALE').add('FLIER') # All done! if len(bears): return pydwarf.success('Made %d bear species fliers.' % len(bears)) else: return pydwarf.failure('Couldn\'t find any bears to make fliers.')
def addtoentity(df, entities, tokens): if isinstance(entities, basestring): entities = (entities,) pydwarf.log.debug('Adding tokens to entities %s.' % ', '.join(str(ent) for ent in entities)) entitytokens = df.allobj(type='ENTITY', id_in=entities) for entitytoken in entitytokens: entitytoken.addprop(tokens) if isinstance(tokens, raws.queryable): tokens = raws.helpers.copy(tokens) # TODO: What about other iterables containing token objects, e.g. lists and tuples? if len(entitytokens) != len(entities): return pydwarf.failure('Failed to add tokens to all given entities because only %d of %d exist.' % (len(entitytokens), len(entities))) else: return pydwarf.success('Added tokens to %d entities.' % len(entitytokens))
def nograzers(raws): grazers = raws.all(exact_value='GRAZER') standardgrazers = raws.all('STANDARD_GRAZER') for grazer in grazers: grazer.remove() for grazer in standardgrazers: grazer.remove() if len(grazers) or len(standardgrazers): return pydwarf.success( 'Removed %d GRAZER and %d STANDARD_GRAZER tokens.' % (len(grazers), len(standardgrazers))) else: return pydwarf.failure('I found no grazer tokens to replace.')
def maxage(df, ages=default_ages, apply_default_age=None, output_needs_age=False): added = [] modified = [] # Handle each creature for creaturetoken in df.allobj('CREATURE'): creaturename = creaturetoken.args[0] maxage = creaturetoken.getprop('MAXAGE') # Creature is in the ages dict, give it the age specified if creaturename in ages: agetuple = ages.get(creaturename) if agetuple is not None: pydwarf.log.debug('Applying MAXAGE %s to %s...' % (agetuple, creaturetoken)) if maxage: modified.append(creaturename) maxage.args = list(agetuple) else: added.append(creaturename) creaturetoken.addprop( raws.token(value='MAXAGE', args=list(agetuple))) # Creature isn't in the ages dict, check about applying a default or simply outputting its existence elif (not maxage) and (output_needs_age or apply_default_age): props = creaturetoken.propdict() if not ('COPY_TAGS_FROM' in props or 'EQUIPMENT_WAGON' in props or 'MEGABEAST' in props or 'DOES_NOT_EXIST' in props or 'NOT_LIVING' in props): if apply_default_age is not None: pydwarf.log.debug('Applying default MAXAGE %s to %s...' % (apply_default_age, creaturetoken)) creaturetoken.addprop( raws.token(value='MAXAGE', args=list(apply_default_age))) added.append(creaturename) else: pydwarf.log.info('Creature %s has no MAXAGE.') # All done! pydwarf.log.debug('Modified MAXAGE tokens of creatures: %s.' % modified) pydwarf.log.debug('Added MAXAGE tokens to creatures: %s.' % added) if len(added) or len(modified): return pydwarf.success( 'Added %d MAXAGE tokens and modified %d existing ones.' % (len(added), len(modified))) else: return pydwarf.failure('No MAXAGE tokens affected.')
def orientation(df, creatures=default_creatures, mode='hetero', lover_chance=default_lover_chance): if isinstance(mode, basestring): if mode not in mode_info: return pydwarf.failure('Invalid mode %s. Recognized modes are these: %s.' % (mode, ', '.join(mode_tokens.keys()))) usemode = mode_info[mode] else: usemode = mode # Unpack variables for convenience disinterestsame, loversame, commitsame, disinterestother, loverother, commitother = usemode # Get tokens for all the specified creatures creatures = df.allobj(type='CREATURE', id_in=creatures) pydwarf.log.debug('Found %d applicable creatures.' % len(creatures)) # Add tokens after [FEMALE] and [MALE] tokens added = 0 for creature in creatures: pydwarf.log.debug('Applying ORIENTATION changes to %s.' % creature) # Remove any existing ORIENTATION tokens removetokens = creature.allprop(exact_value='ORIENTATION') if len(removetokens): pydwarf.log.debug('Removing %d existing ORIENTATION tokens from token %s.' % (len(removetokens), gendertoken)) for removetoken in removetokens: removetoken.remove() # Add the new orientation tokens gendertokens = creature.allprop(value_in=('FEMALE', 'MALE'), args_count=0) for gendertoken in gendertokens: othergender = 'FEMALE' if gendertoken.value == 'MALE' else 'MALE' gendertoken.add(raws.token(value='ORIENTATION', args=[othergender, disinterestother, loverother, commitother])) gendertoken.add(raws.token(value='ORIENTATION', args=[gendertoken.value, disinterestsame, loversame, commitsame])) added += 1 # All done! if added > 0: return pydwarf.success('Appended ORIENTATION tokens after %d gender tokens.' % added) else: return pydwarf.failure('Found no gender tokens to add ORIENTATION to.')
def noexotic(raws): pets = raws.all('PET_EXOTIC') mounts = raws.all('MOUNT_EXOTIC') for token in pets: token.value = 'PET' for token in mounts: token.value = 'MOUNT' if len(pets) or len(mounts): return pydwarf.success( 'Replaced %d PET_EXOTIC and %d MOUNT_EXOTIC tokens.' % (len(pets), len(mounts))) else: return pydwarf.failure( 'I found no PET_EXOTIC or MOUNT_EXOTIC tokens to replace.')
def easypatch_file(df, file, collision_fails=True, replace=False, **kwargs): if replace or str(file) not in df: df.add(file, replace=replace) objects = file.allobj() response = pydwarf.urist.getfn('pineapple.utils.permitobjects')( df, objects = objects, **kwargs ) return response elif collision_fails: return pydwarf.failure('Failed to add file because a file by the same name already exists in the dir.') else: return pydwarf.success('Didn\'t add the file because a file by the same name already exists in the dir.')
def microreduce(dfraws): mountain = dfraws.get('ENTITY:MOUNTAIN') if mountain: # Add files genericpath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Microreduce', '%s.txt') for filename in ('building_macro_fantastic', 'item_macro_fantastic', 'reaction_macro_fantastic'): rfile = dfraws.addfile(path=genericpath % filename) # Add PERMITTED_BUILDING and PERMITTED_REACTION tokens to ENTITY:MOUNTAIN for building in rfile.all(re_value='BUILDING.*', args_count=1): mountain.add(raws.token(value='PERMITTED_BUILDING', args=[building.args[0]])) for reaction in rfile.all(exact_value='REACTION', args_count=1): mountain.add(raws.token(value='REACTION', args=[reaction.args[0]])) return pydwarf.success() else: return pydwarf.failure('Couldn\'t find ENTITY:MOUNTAIN.')
def easypatch_file(df, file, collision_fails=True, replace=False, **kwargs): if replace or str(file) not in df: df.add(file, replace=replace) objects = file.allobj() response = pydwarf.urist.getfn('pineapple.utils.permitobjects')( df, objects=objects, **kwargs) return response elif collision_fails: return pydwarf.failure( 'Failed to add file because a file by the same name already exists in the dir.' ) else: return pydwarf.success( 'Didn\'t add the file because a file by the same name already exists in the dir.' )
def greensteel(df, entities=default_entities): # Add greensteel raws try: df.read(path=greendir, log=pydwarf.log) return pydwarf.urist.getfn('pineapple.utils.addtoentity')( df, entities = entities, permitted_reaction = ( 'GREEN_STEEL_MAKING_ADAMANT_PINEAPPLE', 'GREEN_STEEL_MAKING_ADMANTINE_PINEAPPLE' ) ) except: pydwarf.log.exception('Failed to add greensteel raws.') return pydwarf.failure()
def subterraneanplants(df): # Get subterranean plants subplants = [] for plant in df.allobj('PLANT'): if plant.getprop('BIOME:SUBTERRANEAN_WATER'): subplants.append(plant) if not len(subplants): return pydwarf.failure('Found no subterranean plants.') # Ensure each has all four seasons pydwarf.log.info('Found %d subterranean plants. Modifying...' % len(subplants)) modified = 0 for subplant in subplants: seasontokens = subplant.allprop(value_in=seasons) if len(seasontokens) > 0 and len(seasontokens) < len(seasons): pydwarf.log.debug('Adding season tokens to %s...' % subplant) # First remove the existing tokens (To avoid making duplicates) for seasontoken in seasontokens: seasontoken.remove() # Then add all four anew for season in seasons: subplant.add(raws.token(value=season)) modified += 1 else: pydwarf.log.debug( 'Plant %s either has no seasonal tokens or already has all of them, skipping.' % subplant) # All done if modified > 0: return pydwarf.success('Made %d subterranean plants grow year-round.' % modified) else: return pydwarf.failure( 'All subterranean plants already grew year-round.')
def noanimalmen(df): # Do the removing removed = [ removedprop for removedprop in df.allobj('CREATURE').each( lambda token: token.removeselfandprops() if (token.arg().endswith( '_MAN') or token.arg().endswith(' MAN') or token.getprop( 'APPLY_CREATURE_VARIATION:ANIMAL_PERSON')) else None) if removedprop ] # All done! if removed: return pydwarf.success('Removed %d species of animal men.' % len(removed)) else: return pydwarf.failure('Found no animal men to remove.')
def metalitems(df, metals=default_metals, items=default_item_tokens): # Turn the item names into a list of tokens itemtokens = [raws.token(value=item) for item in items] # Apply to each metal affected = df.allobj(type='INORGANIC', id_in=metals).each(lambda token: ( # Remove existing tokens first to prevent duplicates when adding token.removeallprop(value_in=items), # And now add the specified tokens token.addprop(raws.helpers.copytokens(itemtokens)))) # All done! if affected: return pydwarf.success('Affected %d metals.' % len(affected)) else: return pydwarf.failure('Affected no metals.')
def skillrust(df, creatures=default_creatures, rates=default_rates): failures = [] # Handle each creature creaturetokens = df.allobj(type='CREATURE', id_in=creatures) for creaturetoken in creaturetokens: pydwarf.log.debug('Handling skill rust for %s.' % creaturetoken) # First see about editing existing skill tokens needsnew = True editedtotal = 0 existingtokens = creaturetoken.allprop(value_in=('SKILL_RATE', 'SKILL_RUST_RATE', 'SKILL_RATES', 'SKILL_RUST_RATES')) for existingtoken in existingtokens: pydwarf.log.debug('Modifying arguments for existing token %s.' % existingtoken) edited = False if existingtoken.value in ('SKILL_RATES', 'SKILL_RUST_RATES'): needsnew = False editedtoken = edittoken(existingtoken, rates) editedtotal += editedtoken pydwarf.log.debug(( 'Modified arguments for token.') if editedtoken else ( 'Token already has no skill rust.')) # Add a new one if no token affecting all skills was found if needsnew: pydwarf.log.debug('Adding new SKILL_RUST_RATES token.') creaturetoken.addprop('SKILL_RUST_RATES:NONE:NONE:NONE') # Creature already had no skill rust; consider this a failure elif not editedtotal: pydwarf.log.error('%s already has no skill rust.' % creaturetoken) failures.append(creaturetoken) # All done! failurecount = len(failures) + len(creatures) - len(creaturetokens) if failurecount == 0: return pydwarf.success('Removed skill rust from %d creatures.' % len(creatures)) else: return pydwarf.failure( 'Failed to remove skill rust from %d creatures.' % failurecount)
def nogiantanimals(df): # Do the removing removed = [ removedprop for removedprop in df.allobj('CREATURE').each(lambda token: (token.removeselfandprops( ) if (token.arg().startswith('GIANT_') or token.arg( ).endswith(', GIANT') or token.arg().endswith('_GIANT') or token.arg( ).startswith('GIANT ') or token.arg().startswith('GIGANTIC ') or token. getprop('APPLY_CREATURE_VARIATION:GIANT')) else None)) if removedprop ] # All done! if removed: return pydwarf.success('Removed %d species of giant animals.' % len(removed)) else: return pydwarf.failure('Found no giant animals to remove.')