def promote(self, btype): '''Backup rotation''' #First generation, promote to monthly archive td = self.dt.today() stop = td - datetime.timedelta(days=30) # TODO: mk an option for this crit = and_(Catalog.date < stop, Catalog.clean == True, Catalog.type == btype, Catalog.hierarchy == 1) s = self.sess.query( Catalog).filter(crit).order_by(Catalog.date.desc()).all() for each in groupby(s, lambda x: x.date.year * 100 + x.date.month): month, catalogs = each self.logger.debug('Promoting for month %s:' % month) self.promote_for(catalogs, 1) #If btype is Full, get incremental backups prior to the last Full and #delete them. if btype is self.Full: l = self.sess.query(Catalog).filter(and_( Catalog.type == self.Full, Catalog.job == self.Job, Catalog.hierarchy == 1, Catalog.clean == True)) l = l.order_by(Catalog.date.desc()).first() if l: s = self.sess.query(Catalog).filter(and_( Catalog.date < l.date, Catalog.type == self.Incremental, Catalog.hierarchy == 1, Catalog.clean == True)).all() for oinc in s: msg = "Deleting from %s %s generation archive %s" msg += " (useless incremental)" self.logger.debug(msg % ("fs", ordinal(oinc.hierarchy), oinc.id)) self.fs_remove(oinc.id) self.logger.debug(msg % ("db", ordinal(oinc.hierarchy), oinc.id)) self.sess.delete(oinc) self.sess.commit() #Second generation, promote to yearly archive #get all monthly archives older than a year am = self.sess.query(Catalog) am = am.filter(and_( Catalog.type == btype, Catalog.hierarchy == 2, Catalog.date < td - datetime.timedelta(days=365))) am = am.order_by(Catalog.date.desc()).all() for each in groupby(am, lambda x: x.date.year): year, catalogs = each self.logger.debug('Promoting for year %s:' % year) self.promote_for(catalogs, 2)
def __call__(self, *args, **kwargs): # Variables used to format error messages func, param = self.context.get('func', '?'), self.context.get('param', '?') if self.sig is not None: # Callable signature avaliable # Bound arguments to the callable signature bounded_args = self.sig.bind(*args, **kwargs) bounded_args.apply_defaults() args = list(bounded_args.args) param_validators = self.validator.children[:-1] if len(args) != len(param_validators): # Incorrect number of args raise ValidationError( message='{} expects {} arguments but got {} instead'. format(param, len(args), len(param_validators)), func=func) # Validate each argument for k, arg, validator in zip(count(), args, param_validators): try: args[k] = validator.validate( arg, context={ 'func': func, 'param': '{} argument of {}'.format(ordinal(k + 1), param) }) except ValidationError: raise ValidationError( message='{} argument passed to {} must be {}'.format( ordinal(k + 1), param, validator.niddle), func=func) # Invoke the callable result = CallableWrapper.__call__(self, *args) else: # Callable signature not avaliable result = CallableWrapper.__call__(self, *args, **kwargs) # Validate the result context = {'func': func, 'param': 'return value of {}'.format(param)} validator = self.validator.children[-1] try: result = validator.validate(result, context=context) except ValidationError: raise ValidationError(expected=validator.niddle, **context) # Finally return the result of the callable return result
def promote_for(self, catalogs, hierarchy): '''See if we can find a catalog (promoted or not), in the same period (month or year), newer than the first element in catalogs. If it exists promote it (if not already promoted), then delete all the other catalogs that are older than the maximum age allowed for that generation. If there's no candidate for the promotion promote the first element in catalogs, which it should be our best choice: the oldest known catalog in a period of time, as the catalogs are ordered and all of them belongs to the same period.''' catalogs = list(catalogs) cat = catalogs[0] del_extra = [] #The period will vary depending on the generation. if hierarchy == 1: #month overload if cat.date.month == 12: period = datetime.date(cat.date.year + 1, 1, 1) else: period = datetime.date(cat.date.year, cat.date.month + 1, 1) del_cond = self.dt.today() - datetime.timedelta(days=30) elif hierarchy == 2: period = datetime.date(cat.date.year + 1, 1, 1) del_cond = self.dt.today() - datetime.timedelta(days=365) else: raise RuntimeError("promote_for is not smart enough for this" " operation.") s = self.sess.query(Catalog).filter( and_(Catalog.date < period, Catalog.date > cat.date, Catalog.hierarchy >= cat.hierarchy, Catalog.type == self.Full, Catalog.job == self.Job)).order_by(Catalog.date.desc()) if s.count() > 0: del_extra = [cat] new_cat = s.first() if new_cat.hierarchy == hierarchy: self.logger.debug("Promoting %s to %s generation archive" % (new_cat.id, ordinal(new_cat.hierarchy + 1))) new_cat.promote(self.cf) else: self.logger.debug("Promoting %s to %s generation archive" % (cat.id, cat.hierarchy + 1)) cat.promote(self.cf) for each in catalogs[1:] + del_extra: if each.date < del_cond: msg = "Deleting from fs %s generation archive %s" self.logger.debug(msg % (ordinal(each.hierarchy), each.id)) self.fs_remove(each.id) msg = "Deleting from db %s generation archive %s" self.logger.debug(msg % (ordinal(each.hierarchy), each.id)) self.sess.delete(each) self.sess.commit()
def place(player, col, render=True): if self.board.place(player, col): print("Player {} places at the {} column".format( 1 if player == self.PLAYER1 else 2, ordinal(col + 1))) print(self.board.dump()) print("############################################") self.placement_counter[player] += 1 row = next(r for r in range(self.board.rows) if self.board.occupied(r, col)) if render: self.draw_checker( player, board_pos[0] + (col + 0.05) * self.cell_size, board_pos[1] + (row + 0.05) * self.cell_size, self.placement_counter[player]) self.canvas.create_text( board_pos[0] + (col + 0.5) * self.cell_size, board_pos[1] + (row + 0.5) * self.cell_size, text="{}".format(self.placement_counter[player]), fill="black", font=(None, 10), anchor="center") self.canvas.update() return self.PLAYER2 if player == self.PLAYER1 else self.PLAYER1 if player == "Human": return player raise ValueError( "Agent tried to place at a invalid column ({})".format(col))
def getPrereqs(m): prereq = [] for pre in m['prerequisite']: if 'ability' in pre: if type(pre['ability']) == list: abilityor = [] if all( next(iter(v.values())) == next( iter(pre['ability'][0].values())) for v in pre['ability']): for v in pre['ability']: for s, val in v.items(): abilityor.append(stats[s]) prereq.append("{} {} or higher".format( " or ".join(abilityor), next(iter(pre['ability'][0].values())))) else: for v in pre['ability']: for s, val in v.items(): abilityor.append("{} {} or higher".format( stats[k], val)) prereq.append(" or ".join(abilityor)) else: for k, v in pre['ability'].items(): prereq.append("{} {} or higher".format(stats[k], v)) if 'spellcasting' in pre and pre['spellcasting']: prereq.append("The ability to cast at least one spell") if 'proficiency' in pre: for prof in pre['proficiency']: for k, v in prof.items(): prereq.append("Proficiency with {} {}".format(v, k)) if 'race' in pre: for r in pre['race']: prereq.append("{}{}".format( r['name'], " ({})".format(r['subrace']) if 'subrace' in r else "").title()) if 'spell' in pre: for s in pre['spell']: if '#c' in s: prereq.append("{} cantrip".format( s.replace('#c', '').title())) else: prereq.append("The ability to cast {}".format(s.title())) if 'level' in pre: level = pre['level']['level'] prereq.append("{} level".format(utils.ordinal(level))) if 'patron' in pre: prereq.append("{} patron".format(pre['patron'])) if 'pact' in pre: prereq.append("Pact of the {}".format(pre['pact'])) if 'item' in pre: for i in pre['item']: prereq.append(i) if 'otherSummary' in pre: prereq.append(pre['otherSummary']['entrySummary']) return ", ".join(prereq)
def parseMonster(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name'] + " from " + m['_copy']['name'] + " in " + m['_copy']['source']) xtrsrc = "./data/bestiary/bestiary-" + m['_copy']['source'].lower( ) + ".json" try: with open(xtrsrc, encoding='utf-8') as f: d = json.load(f) f.close() mcpy = copy.deepcopy(m) for mn in d['monster']: if mn['name'].lower() == mcpy['_copy']['name'].lower(): if '_copy' in mn: if args.verbose: print("ANOTHER COPY: " + mn['name'] + " from " + mn['_copy']['name'] + " in " + mn['_copy']['source']) xtrsrc2 = "./data/bestiary/bestiary-" + mn['_copy'][ 'source'].lower() + ".json" with open(xtrsrc2, encoding='utf-8') as f: d2 = json.load(f) f.close() for mn2 in d2['monster']: if mn2['name'] == mn['_copy']['name']: mn = copy.deepcopy(mn2) break m = copy.deepcopy(mn) m['name'] = mcpy['name'] if 'isNpc' in mcpy: m['isNpc'] = mcpy['isNpc'] m['source'] = mcpy['source'] if "otherSources" in mcpy: m["otherSources"] = mcpy["otherSources"] elif "otherSources" in m: del m["otherSources"] if 'size' in mcpy: m['size'] = mcpy['size'] if 'hp' in mcpy: m['hp'] = mcpy['hp'] if 'original_name' in mcpy: m['original_name'] = mcpy['original_name'] if 'page' in mcpy: m['page'] = mcpy['page'] elif 'page' in m: del m['page'] if 'image' in mcpy: m['image'] = mcpy['image'] if '_mod' in mcpy['_copy']: m = utils.modifyMonster(m, mcpy['_copy']['_mod']) break if '_trait' in mcpy['_copy']: if args.verbose: print("Adding extra traits for: " + mcpy['_copy']['_trait']['name']) traits = "./data/bestiary/traits.json" with open(traits, encoding='utf-8') as f: d = json.load(f) f.close() for trait in d['trait']: if trait['name'] == mcpy['_copy']['_trait']['name']: if '_mod' in trait['apply']: m = utils.modifyMonster(m, trait['apply']['_mod']) if '_root' in trait['apply']: for key in trait['apply']['_root']: if key == "speed" and type( trait['apply']['_root'][key]) == int: for k2 in m['speed']: m['speed'][k2] = trait['apply'][ '_root'][key] else: m[key] = trait['apply']['_root'][key] except IOError as e: if args.verbose: print("Could not load additional source ({}): {}".format( e.errno, e.strerror)) return # for eachmonsters in compendium.findall('monster'): # if eachmonsters.find('name').text == m['name']: # m['name'] = "{} (DUPLICATE IN {})".format(m['name'],m['source']) monster = ET.SubElement(compendium, 'monster') id = ET.SubElement(monster, 'id') id.text = m['source'].lower() + "-" + re.sub(r'\W+', '', m['name']).lower() name = ET.SubElement(monster, 'name') name.text = m['name'] size = ET.SubElement(monster, 'size') size.text = m['size'] typ = ET.SubElement(monster, 'type') if isinstance(m['type'], dict): if 'swarmSize' in m['type']: typ.text = "swarm of {} {}s".format(utils.convertSize(m['size']), m['type']['type']) elif 'tags' in m['type']: subtypes = [] for tag in m['type']['tags']: if not isinstance(tag, dict): subtypes.append(tag) else: subtypes.append(tag['prefix'] + tag['tag']) typ.text = "{} ({})".format(m['type']['type'], ", ".join(subtypes)) else: typ.text = m['type']['type'] else: typ.text = m['type'] alignment = ET.SubElement(monster, 'alignment') if 'alignment' not in m: m['alignment'] = ['A'] alignment.text = utils.convertAlignList(m['alignment']) ac = ET.SubElement(monster, 'ac') acstr = [] for acs in m['ac']: if isinstance(acs, dict): if len(acstr) == 0: if 'ac' in acs: acstr.append(str(acs['ac'])) if 'from' in acs and 'condition' in acs: acstr.append( utils.fixTags( ", ".join(acs['from']) + " " + acs['condition'], m, True)) elif 'from' in acs: acstr.append(utils.fixTags(", ".join(acs['from']), m, True)) elif 'condition' in acs: acstr.append(utils.fixTags(acs['condition'], m, True)) if 'special' in acs: acstr.append(utils.fixTags(acs['special'], m, True)) continue acstr.append( utils.fixTags( "{}".format("{} {}".format( acs['ac'], "(" + ", ".join(acs['from']) + ") " + acs['condition'] if 'from' in acs and 'condition' in acs else "(" + ", ".join(acs['from']) + ")" if 'from' in acs else acs['condition'] ) if 'from' in acs or 'condition' in acs else acs['ac']), m, True)) else: acstr.append(str(acs)) if len(acstr) > 1: ac.text = "{} ({})".format(acstr[0], ", ".join(acstr[1:])) elif acstr[0]: ac.text = acstr[0] else: ac.text = "0" hp = ET.SubElement(monster, 'hp') if "special" in m['hp']: if args.nohtml and re.match(r'equal the .*?\'s Constitution modifier', m['hp']['special']): hp.text = str(utils.getAbilityMod(m['con'])) if 'trait' in m: m['trait'].insert(0, { "name": "Hit Points", "entries": [m['hp']['special']] }) else: m['trait'] = [{ "name": "Hit Points", "entries": [m['hp']['special']] }] elif args.nohtml: hpmatch = re.match( r'[0-9]+ ?(\([0-9]+[Dd][0-9]+( ?\+ ?[0-9]+)?\))?', m['hp']['special']) if hpmatch: hp.text = str(hpmatch.group(0)).rstrip() else: hp.text = "0" if 'trait' in m: m['trait'].insert(0, { "name": "Hit Points", "entries": [m['hp']['special']] }) else: m['trait'] = [{ "name": "Hit Points", "entries": [m['hp']['special']] }] else: hp.text = m['hp']['special'] else: hp.text = "{} ({})".format(m['hp']['average'], m['hp']['formula'].replace(' ', '')) speed = ET.SubElement(monster, 'speed') if type(m['speed']) == str: speed.text = m['speed'] elif 'choose' in m['speed']: lis = [] for key, value in m['speed'].items(): if key == "walk": lis.append("walk " + str(value) + " ft.") elif key == "choose": value['from'].insert(-1, 'or') lis.append("{} {} ft. {}".format(" ".join(value['from']), value['amount'], value['note'])) else: lis.append("{} {} ft.".format(key, value)) speed.text = ", ".join(lis) else: speed.text = ", ".join([ "{} {} ft.".format( key, value['number'] if isinstance(value, dict) else value) for key, value in m['speed'].items() if not isinstance(value, bool) ]) statstr = ET.SubElement(monster, 'str') statstr.text = str(m['str'] if 'str' in m else '0') statdex = ET.SubElement(monster, 'dex') statdex.text = str(m['dex'] if 'dex' in m else '0') statcon = ET.SubElement(monster, 'con') statcon.text = str(m['con'] if 'con' in m else '0') statint = ET.SubElement(monster, 'int') statint.text = str(m['int'] if 'int' in m else '0') statwis = ET.SubElement(monster, 'wis') statwis.text = str(m['wis'] if 'wis' in m else '0') statcha = ET.SubElement(monster, 'cha') statcha.text = str(m['cha'] if 'cha' in m else '0') if 'isNpc' in m and m['isNpc'] and not args.nohtml: npcroll = ET.SubElement(monster, 'role') npcroll.text = "ally" save = ET.SubElement(monster, 'save') savelist = ET.SubElement(monster, 'savelist') if 'save' in m: savestr = ET.SubElement(savelist, 'str') savestr.text = m['save'].get('str', '') savedex = ET.SubElement(savelist, 'dex') savedex.text = m['save'].get('dex', '') savecon = ET.SubElement(savelist, 'con') savecon.text = m['save'].get('con', '') saveint = ET.SubElement(savelist, 'int') saveint.text = m['save'].get('int', '') savewis = ET.SubElement(savelist, 'wis') savewis.text = m['save'].get('wis', '') savecha = ET.SubElement(savelist, 'cha') savecha.text = m['save'].get('cha', '') if 'save' in m: save.text = ", ".join([ "{} {}".format(str.capitalize(key), value) for key, value in m['save'].items() ]) skill = ET.SubElement(monster, 'skill') if 'skill' in m: skills = [] for key, value in m['skill'].items(): if type(value) == str: skills.append("{} {}".format(str.capitalize(key), value)) else: if key == "other": for sk in value: if "oneOf" in sk: if args.nohtml: if 'trait' not in m: m['trait'] = [] m['trait'].insert( 0, { "name": "Skills", "entries": [ "plus one of the following: " + ", ".join([ "{} {}".format( str.capitalize(ook), oov) for ook, oov in sk["oneOf"].items() ]) ] }) else: skills.append( "plus one of the following: " + ", ".join([ "{} {}".format(str.capitalize(ook), oov) for ook, oov in sk["oneOf"].items() ])) skill.text = ", ".join(skills) if 'passive' in m: passive = ET.SubElement(monster, 'passive') passive.text = str(m['passive']) languages = ET.SubElement(monster, 'languages') if 'languages' in m: languages.text = ", ".join([x for x in m['languages']]) cr = ET.SubElement(monster, 'cr') if 'cr' in m: if isinstance(m['cr'], dict): cr.text = str(m['cr']['cr']) else: if not m['cr'] == "Unknown": cr.text = str(m['cr']) resist = ET.SubElement(monster, 'resist') if 'resist' in m: resistlist = utils.parseRIV(m, 'resist') resist.text = ", ".join(resistlist) immune = ET.SubElement(monster, 'immune') if 'immune' in m: immunelist = utils.parseRIV(m, 'immune') immune.text = ", ".join(immunelist) vulnerable = ET.SubElement(monster, 'vulnerable') if 'vulnerable' in m: vulnerablelist = utils.parseRIV(m, 'vulnerable') vulnerable.text = ", ".join(vulnerablelist) conditionImmune = ET.SubElement(monster, 'conditionImmune') if 'conditionImmune' in m: conditionImmunelist = utils.parseRIV(m, 'conditionImmune') conditionImmune.text = ", ".join(conditionImmunelist) senses = ET.SubElement(monster, 'senses') if 'senses' in m: senses.text = ", ".join([x for x in m['senses']]) if 'source' in m and not args.srd: slug = slugify(m["name"]) if args.addimgs and os.path.isdir("img") and not os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".png") ) and not os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".jpg") ) and not os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".png")) and not os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".jpg")): if not os.path.isdir(os.path.join(args.tempdir, "monsters")): os.mkdir(os.path.join(args.tempdir, "monsters")) #if not os.path.isdir(os.path.join(args.tempdir,"tokens")): # os.mkdir(os.path.join(args.tempdir,"tokens")) if 'image' in m: artworkpath = m['image'] else: artworkpath = None monstername = m["original_name"] if "original_name" in m else m[ "name"] if artworkpath and os.path.isfile("./img/" + artworkpath): artworkpath = "./img/" + artworkpath elif os.path.isfile("./img/bestiary/" + m["source"] + "/" + monstername + ".jpg"): artworkpath = "./img/bestiary/" + m[ "source"] + "/" + monstername + ".jpg" elif os.path.isfile("./img/bestiary/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/bestiary/" + m[ "source"] + "/" + monstername + ".png" elif os.path.isfile("./img/vehicles/" + m["source"] + "/" + monstername + ".jpg"): artworkpath = "./img/vehicles/" + m[ "source"] + "/" + monstername + ".jpg" elif os.path.isfile("./img/vehicles/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/vehicles/" + m[ "source"] + "/" + monstername + ".png" if artworkpath is not None: ext = os.path.splitext(artworkpath)[1] copyfile(artworkpath, os.path.join(args.tempdir, "monsters", slug + ext)) imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ext if os.path.isfile("./img/" + m["source"] + "/" + monstername + ".png") or os.path.isfile("./img/" + m["source"] + "/" + monstername + ".jpg"): if os.path.isfile("./img/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/" + m[ "source"] + "/" + monstername + ".png" else: artworkpath = "./img/" + m[ "source"] + "/" + monstername + ".jpg" ext = os.path.splitext(artworkpath)[1] copyfile( artworkpath, os.path.join(args.tempdir, "monsters", "token_" + slug + ext)) imagetag = ET.SubElement(monster, 'token') imagetag.text = slug + ext elif os.path.isfile("./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".png") or os.path.isfile( "./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".jpg"): if os.path.isfile("./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/vehicles/tokens/" + m[ "source"] + "/" + monstername + ".png" else: artworkpath = "./img/vehicles/tokens/" + m[ "source"] + "/" + monstername + ".jpg" ext = os.path.splitext(artworkpath)[1] copyfile( artworkpath, os.path.join(args.tempdir, "monsters", "token_" + slug + ext)) imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ext elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".png")): imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".jpg")): imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ".jpg" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".png")): imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".jpg")): imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ".jpg" sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source'], args), m['page'] ) if 'page' in m and m['page'] != 0 else utils.getFriendlySource( m['source'], args) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: if "source" not in s: continue sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"], args), s["page"]) if 'page' in s and s[ "page"] != 0 else utils.getFriendlySource( s["source"], args) #trait = ET.SubElement(monster, 'trait') #name = ET.SubElement(trait, 'name') #name.text = "Source" #text = ET.SubElement(trait, 'text') #text.text = sourcetext if not args.nohtml: srctag = ET.SubElement(monster, 'source') srctag.text = sourcetext else: sourcetext = None if 'trait' in m: for t in m['trait']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(t['name']) if "entries" not in t: t["entries"] = [] for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(trait, 'text') text.text = e if 'action' in m and m['action'] is not None: for t in m['action']: action = ET.SubElement(monster, 'action') if 'name' in t: name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e for match in re.finditer( r'(((\+|\-)?[0-9]*) to hit.*?|DC [0-9]+ .*? saving throw.*?)\(([0-9Dd\+\- ]+)\) .*? damage', e): if match.group(4): attack = ET.SubElement(action, 'attack') attack.text = "{}|{}|{}".format( utils.remove5eShit(t['name']) if 'name' in t else "", match.group(2).replace(' ', '') if match.group(2) else "", match.group(4).replace(' ', '')) if 'reaction' in m and m['reaction'] is not None: for t in m['reaction']: action = ET.SubElement(monster, 'reaction') name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e if 'variant' in m and m['variant'] is not None: if type(m['variant']) != list: m['variant'] = [m['variant']] for t in m['variant']: action = ET.SubElement(monster, 'action') name = ET.SubElement(action, 'name') name.text = "Variant: " + utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e if 'legendary' in m: legendary = ET.SubElement(monster, 'legendary') if "legendaryHeader" in m: for h in m['legendaryHeader']: text = ET.SubElement(legendary, 'text') text.text = utils.remove5eShit(h) else: text = ET.SubElement(legendary, 'text') if "isNamedCreature" in m and m['isNamedCreature']: text.text = "{0} can take {1:d} legendary action{2}, choosing from the options below. Only one legendary action can be used at a time and only at the end of another creature's turn. {0} regains spent legendary action{2} at the start of its turn.".format( m['name'].split(' ', 1)[0], len(m['legendary']), "s" if len(m['legendary']) > 1 else "") else: text.text = "The {0} can take {1:d} legendary action{2}, choosing from the options below. Only one legendary action can be used at a time and only at the end of another creature's turn. The {0} regains spent legendary action{2} at the start of its turn.".format( m['type'] if type(m['type']) == str else "{} ({})".format( m['type']['type'], ", ".join(m['type']['tags'])) if 'tags' in m['type'] else m['type']['type'], len(m['legendary']), "s" if len(m['legendary']) > 1 else "") for t in m['legendary']: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') if 'name' not in t: t['name'] = "" name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'mythic' in m: mythic = ET.SubElement(monster, 'legendary') if "mythicHeader" in m: for h in m['mythicHeader']: name = ET.SubElement(mythic, 'name') name.text = "Mythic Actions" mythic = ET.SubElement(monster, 'legendary') text = ET.SubElement(mythic, 'text') text.text = utils.remove5eShit(h) for t in m['mythic']: mythic = ET.SubElement(monster, 'legendary') name = ET.SubElement(mythic, 'name') if 'name' not in t: t['name'] = "" name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(mythic, "text") text.text = e if 'legendaryGroup' in m: with open("./data/bestiary/legendarygroups.json", encoding='utf-8') as f: meta = json.load(f) f.close() for l in meta['legendaryGroup']: if l['name'] != m['legendaryGroup']['name']: continue if 'lairActions' in l: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = "Lair Actions" legendary = ET.SubElement(monster, 'legendary') for t in l['lairActions']: if type(t) == str: text = ET.SubElement(legendary, 'text') text.text = utils.fixTags(t, m, args.nohtml) continue if 'name' in t: name = ET.SubElement(legendary, 'name') name.text = "Lair Action: " + utils.remove5eShit( t['name']) if t['type'] == 'list': for i in t['items']: text = ET.SubElement(legendary, 'text') text.text = "• " + utils.fixTags(i, m, args.nohtml) continue for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'regionalEffects' in l: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = "Regional Effects" legendary = ET.SubElement(monster, 'legendary') for t in l['regionalEffects']: if type(t) == str: text = ET.SubElement(legendary, 'text') text.text = utils.fixTags(t, m, args.nohtml) continue if 'name' in t: name = ET.SubElement(legendary, 'name') name.text = "Regional Effect: " + utils.remove5eShit( t['name']) if t['type'] == 'list': for i in t['items']: text = ET.SubElement(legendary, 'text') text.text = "• " + utils.fixTags(i, m, args.nohtml) continue #legendary = ET.SubElement(monster, 'legendary') for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'mythicEncounter' in l: mythic = ET.SubElement(monster, 'legendary') name = ET.SubElement(mythic, 'name') name.text = "{} as a Mythic Encounter".format(m["name"]) for e in utils.getEntryString(l["mythicEncounter"], m, args).split("\n"): text = ET.SubElement(mythic, 'text') text.text = e if 'spellcasting' in m: spells = [] for s in m['spellcasting']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(s['name']) for e in s['headerEntries']: text = ET.SubElement(trait, 'text') text.text = utils.fixTags(e, m, args.nohtml) if "will" in s: text = ET.SubElement(trait, 'text') willspells = s['will'] text.text = "At will: " + \ ", ".join([utils.remove5eShit(e) for e in willspells]) for spl in willspells: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "daily" in s: for timeframe, lis in s['daily'].items(): text = ET.SubElement(trait, 'text') dailyspells = lis t = "{}/day{}: ".format( timeframe[0], " each" if len(timeframe) > 1 else "") text.text = t + \ ", ".join([utils.fixTags(e,m,args.nohtml) for e in dailyspells]) for spl in dailyspells: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "spells" in s: slots = [] for level, obj in s['spells'].items(): text = ET.SubElement(trait, 'text') spellbois = obj['spells'] t = "• {} level ({} slots): ".format( utils.ordinal(int(level)), obj['slots'] if 'slots' in obj else 0) if level != "0" else "Cantrips (at will): " if level != "0": slots.append( str(obj['slots'] if 'slots' in obj else 0)) text.text = t + \ ", ".join([utils.fixTags(e,m,args.nohtml) for e in spellbois]) for spl in spellbois: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) slotse = ET.SubElement(monster, 'slots') slotse.text = ", ".join(slots) if 'footerEntries' in s: for e in s['footerEntries']: text = ET.SubElement(trait, 'text') text.text = utils.fixTags(e, m, args.nohtml) spellse = ET.SubElement(monster, 'spells') spellse.text = ", ".join(spells) description = ET.SubElement(monster, 'description') description.text = "" if 'entries' in m and not args.srd: description.text += utils.getEntryString(m["entries"], m, args) if sourcetext: description.text += "\n<i>Source: {}</i>".format(sourcetext) if args.nohtml: description.text = re.sub('</?(i|b|spell)>', '', description.text) environment = ET.SubElement(monster, 'environment') if 'environment' in m: environment.text = ", ".join([x for x in m['environment']])
def parseMonster(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name']) return monster = ET.SubElement(compendium, 'monster') name = ET.SubElement(monster, 'name') name.text = m['name'] size = ET.SubElement(monster, 'size') size.text = m['size'] typ = ET.SubElement(monster, 'type') if isinstance(m['type'], dict): if 'swarmSize' in m['type']: typ.text = "swarm of {} {}s".format( utils.convertSize(m['size']), m['type']['type']) else: subtypes = [] for tag in m['type']['tags']: if not isinstance(tag, dict): subtypes.append(tag) else: subtypes.append(tag['prefix'] + tag['tag']) typ.text = "{} ({})".format(m['type']['type'], ", ".join(subtypes)) else: typ.text = m['type'] alignment = ET.SubElement(monster, 'alignment') alignment.text = utils.convertAlignList(m['alignment']) ac = ET.SubElement(monster, 'ac') acstr = [] for acs in m['ac']: if isinstance(acs, dict): if 'from' in acs: acstr.append("{} ({})".format( acs['ac'], utils.remove5eShit(acs['from'][0]))) elif 'condition' in acs: acstr.append("{} ({})".format( acs['ac'], utils.remove5eShit(acs['condition']))) else: acstr.append(str(acs)) ac.text = ", ".join(acstr) hp = ET.SubElement(monster, 'hp') if "special" in m['hp']: hp.text = m['hp']['special'] else: hp.text = "{} ({})".format(m['hp']['average'], m['hp']['formula']) speed = ET.SubElement(monster, 'speed') if 'choose' in m['speed']: lis = [] for key, value in m['speed'].items(): if key == "walk": lis.append(str(value) + " ft.") elif key == "choose": value['from'].insert(-1, 'or') lis.append( "{} {} ft.".format( ", ".join( value['from']), value['amount'])) else: lis.append("{} {} ft.".format(key, value)) speed.text = "; ".join(lis) else: speed.text = ", ".join( [ "{} {} ft.".format( key, value['number'] if isinstance( value, dict) else value) for key, value in m['speed'].items() if not isinstance( value, bool)]) statstr = ET.SubElement(monster, 'str') statstr.text = str(m['str']) statdex = ET.SubElement(monster, 'dex') statdex.text = str(m['dex']) statcon = ET.SubElement(monster, 'con') statcon.text = str(m['con']) statint = ET.SubElement(monster, 'int') statint.text = str(m['int']) statwis = ET.SubElement(monster, 'wis') statwis.text = str(m['wis']) statcha = ET.SubElement(monster, 'cha') statcha.text = str(m['cha']) save = ET.SubElement(monster, 'save') if 'save' in m: save.text = ", ".join(["{} {}".format(str.capitalize( key), value) for key, value in m['save'].items()]) skill = ET.SubElement(monster, 'skill') if 'skill' in m: skill.text = ", ".join(["{} {}".format(str.capitalize( key), value) for key, value in m['skill'].items()]) passive = ET.SubElement(monster, 'passive') passive.text = str(m['passive']) languages = ET.SubElement(monster, 'languages') if 'languages' in m: languages.text = ", ".join([x for x in m['languages']]) cr = ET.SubElement(monster, 'cr') if isinstance(m['cr'], dict): cr.text = str(m['cr']['cr']) else: cr.text = str(m['cr']) resist = ET.SubElement(monster, 'resist') if 'resist' in m: resistlist = utils.parseRIV(m, 'resist') resist.text = "; ".join(resistlist) immune = ET.SubElement(monster, 'immune') if 'immune' in m: immunelist = utils.parseRIV(m, 'immune') immune.text = "; ".join(immunelist) vulnerable = ET.SubElement(monster, 'vulnerable') if 'vulnerable' in m: vulnerablelist = utils.parseRIV(m, 'vulnerable') vulnerable.text = "; ".join(vulnerablelist) conditionImmune = ET.SubElement(monster, 'conditionImmune') if 'conditionImmune' in m: conditionImmunelist = utils.parseRIV(m, 'conditionImmune') conditionImmune.text = "; ".join(conditionImmunelist) senses = ET.SubElement(monster, 'senses') if 'senses' in m: senses.text = ", ".join([x for x in m['senses']]) if 'source' in m: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = "Source" text = ET.SubElement(trait, 'text') text.text = "{} p. {}".format( m['source'], m['page']) if 'page' in m and m['page'] != 0 else m['source'] if 'trait' in m: for t in m['trait']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(t['name']) for e in t['entries']: if "colLabels" in e: text = ET.SubElement(trait, 'text') text.text = " | ".join([utils.remove5eShit(x) for x in e['colLabels']]) for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.remove5eShit(r)) text = ET.SubElement(trait, 'text') text.text = " | ".join(rowthing) else: text = ET.SubElement(trait, 'text') text.text = utils.remove5eShit(e) if 'action' in m: for t in m['action']: action = ET.SubElement(monster, 'action') name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in t['entries']: if isinstance(e, dict): if "colLabels" in e: text = ET.SubElement(action, 'text') text.text = " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.remove5eShit(r)) text = ET.SubElement(action, 'text') text.text = " | ".join(rowthing) else: for i in e["items"]: text = ET.SubElement(action, 'text') if 'name' in i: text.text = "{}{}".format( i['name'] + " ", utils.remove5eShit(i['entry'])) else: text.text = "\n".join( utils.remove5eShit(x) for x in i) else: text = ET.SubElement(action, 'text') text.text = utils.remove5eShit(e) if 'legendary' in m: for t in m['legendary']: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = utils.remove5eShit(t['name']) for e in t['entries']: if isinstance(e, dict): if "colLabels" in e: text = ET.SubElement(legendary, 'text') text.text = " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.remove5eShit(r)) text = ET.SubElement(legendary, 'text') text.text = " | ".join(rowthing) else: for i in e["items"]: text = ET.SubElement(legendary, 'text') text.text = "{} {}".format( i['name'], utils.remove5eShit(i['entry'])) else: text = ET.SubElement(legendary, 'text') text.text = utils.remove5eShit(e) if 'spellcasting' in m: spells = [] for s in m['spellcasting']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(s['name']) for e in s['headerEntries']: text = ET.SubElement(trait, 'text') text.text = utils.remove5eShit(e) if "will" in s: text = ET.SubElement(trait, 'text') willspells = s['will'] text.text = "At will: " + \ ", ".join([utils.remove5eShit(e) for e in willspells]) for spl in willspells: search = re.search( r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "daily" in s: for timeframe, lis in s['daily'].items(): text = ET.SubElement(trait, 'text') dailyspells = lis t = "{}/day{}: ".format(timeframe[0], " each" if len(timeframe) > 1 else "") text.text = t + \ ", ".join([utils.remove5eShit(e) for e in dailyspells]) for spl in dailyspells: search = re.search( r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "spells" in s: slots = [] for level, obj in s['spells'].items(): text = ET.SubElement(trait, 'text') spellbois = obj['spells'] t = "• {} level ({} slots): ".format( utils.ordinal( int(level)), obj['slots'] if 'slots' in obj else 0) if level != "0" else "Cantrips (at will): " if level != "0": slots.append( str(obj['slots'] if 'slots' in obj else 0)) text.text = t + \ ", ".join([utils.remove5eShit(e) for e in spellbois]) for spl in spellbois: search = re.search( r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) slotse = ET.SubElement(monster, 'slots') slotse.text = ", ".join(slots) spellse = ET.SubElement(monster, 'spells') spellse.text = ", ".join(spells) environment = ET.SubElement(monster, 'environment') if 'environment' in m: environment.text = ", ".join([x for x in m['environment']])
def print(self) -> None: """Print select pen detail.""" print("select {0} pen.".format(utils.ordinal(self._pen_type)))
def fire(GS, p): if len(p.missles) <= 0: GS['messages'].append('red: You have no missles to shoot with!') else: rng = 4 if p.ranged_weapon: rng = p.ranged_weapon.range ms = list(filter(lambda m: utils.dist(m.pos, p.pos) <= rng and\ GS['terrain_map'].dungeon['lighted'].fov[m.pos], GS['terrain_map'].dungeon['monsters'])) ox = max(0, GS['player'].pos[0] - math.floor(WIDTH / 4)) oy = max(0, GS['player'].pos[1] - math.floor(HEIGHT / 2)) for i, m in enumerate(ms): start = (p.pos[0] - ox, p.pos[1] - oy) end = (m.pos[0] - ox, m.pos[1] - oy) draw.draw_line(GS, start, end, colors.light_blue, start_char='@', end_char=str(i)) if len(ms) > 0: key = tdl.event.wait(timeout=None, flush=True) while not ('KEY' in key.type and (key.keychar.isnumeric() or key.keychar == 'ESCAPE')): GS['messages'].append('Please type number or ESC.') draw.draw_hud_screen(GS) key = tdl.event.wait(timeout=None, flush=True) if key.keychar != 'ESCAPE': GS['messages'].append('yellow: You shoot the ' + utils.ordinal(key.keychar) + ' target!') target = ms[int(key.keychar) % len(ms)] skill = p.race.skills['range'] handicap = max(0, math.ceil(1 - skill)) + 5 tpe = '' if p.ranged_weapon: tpe = p.ranged_weapon.missle_type missle = list( filter( lambda m: not p.ranged_weapon or tpe in m.missle_type, p.missles))[-1] # Animation start = (p.pos[0] - ox, p.pos[1] - oy) end = (target.pos[0] - ox, target.pos[1] - oy) animation.FireMissleAnimation().run(GS, [missle, start, end]) cw = math.floor(p.ranged_weapon.weight / 5) * 4 if target and random.randint( 0, max(1, int(100 - p.exp * skill - handicap))) < cw + target.speed * 20 + 5: if tpe == '': target.health -= (missle.hit - 2) else: target.health -= missle.hit GS['messages'].append('yellow: You hit the ' + target.name + '.') if target.health <= 0: GS['messages'].append( 'green: Your shot hit home! The ' + target.name + ' dies.') GS['terrain_map'].dungeon['monsters'].remove(target) p.killed_monsters += 1 p.learn(GS, target) p.missles.remove(missle) missle.equipped = False GS['terrain_map'].dungeon['items'][target.pos].append( missle) else: GS['messages'].append('red: You miss the enemy.') else: GS['messages'].append('grey: Nevermind.') else: GS['messages'].append('red: There are no enemies in range.')