def __init__(self, db: InvokePSQL, ctx: Ctx, series_id: int, study_instance_id: int, encounter_repetitions: int, encounter_param_dict: Dict, tracer: TraceIt): self.db = db self.ctx = ctx self.ctx.series_id = series_id self.ctx.study_instance_id = study_instance_id self.method_last_call_audit = {} self.stats = SeriesStats(study_instance_id=self.ctx.study_instance_id, series_id=self.ctx.series_id) self.logger = RpgLogging(logger_name=ctx.logger_name) self.t = tracer self.encounter_repetitions = encounter_repetitions self.encounter_param_dict = encounter_param_dict self.party_name_param = None self.heroes = [] self.hero_party_size_param = None self.opponent_party_size_param = None self.opponents = [] self.series_stats = [] self.encounter_stats = [] self.character_stats = [] self.assign_encounter_params() print(f"study_instance_id={study_instance_id} " f"series_id={self.ctx.series_id} " f"encounter_repetitions={encounter_repetitions} " f"encounter_param_dict={encounter_param_dict} ") self.run_series()
def __init__(self, ctx, sides=20, debug_ind=False): """ Randomization class :param sides: the number of sides this die will have (default: 20) :param debug_ind: log to class_eval array? (default: False) """ self.sides = sides self.debug_ind = debug_ind self.details = [] # holds rollAmount objs self.method_last_call_audit = {} # dict where method name key holds last crumb for that method self.logger = RpgLogging(logger_name=ctx.logger_name) self.ctx = ctx
def __init__(self, db, ctx: Ctx, tracer: TraceIt, app_username: str, study_name: str, study_instance_id: int = None, repetitions: int = None): self.ctx = ctx self.method_last_call_audit = {} if self.ctx.app_username == "Unknown" or self.ctx.app_username == "Study_class_init": self.ctx.app_username = app_username self.logger = RpgLogging(logger_name=ctx.logger_name) self.t = tracer self.study_name = study_name self.repititions = repetitions if study_instance_id is None: # ----- TODO ---------------- # Get study information from db and create a new record in the study_instance table # Pass the context, self.study_instance_id = 1 if self.ctx.study_instance_id == -1: self.log.debug("Updating Context for study instance id", self.ctx) self.ctx.study_instance_id = self.study_instance_id self.test_method_a(id=1) # self.log.debug("Leaving class init.", self.ctx)
out_str = '{' out_dict = self.__repr__() for key in out_dict.keys(): out_str = f"{out_str}'{key}': {out_dict[key]}, " if out_str[-2:] == ", ": out_str = f'{out_str[:-2]}' out_str = f'{out_str}}}' return out_str if __name__ == '__main__': db = InvokePSQL() logger_name = f'spell_main' ctx = Ctx(app_username='******', logger_name=logger_name) ctx.log_file_dir = os.path.expanduser('~/rpg/logs') logger = RpgLogging(logger_name=logger_name, level_threshold='debug') logger.setup_logging(log_dir=ctx.log_file_dir) try: a1 = Spell(db=db, ctx=ctx, name="Dragonborn Breath Weapon - Blue", cast_at_level=None) print(a1) except Exception as error: exc_type, exc_value, exc_traceback = sys.exc_info() print(f'Context Information:\n\t' f'App_username: {ctx.app_username}\n\t' f'Full Name: {ctx.fully_qualified}\n\t' f'Logger Name: {ctx.logger_name}\n\t' f'Trace Id: {ctx.trace_id}\n\t'
def test_method_b(self, id): self.log.debug("entering test method b", self.ctx) print(f"in test_method_b: {id}") self.test_method_c(id=3) @ctx_decorator() def test_method_c(self, id): self.log.debug("entering test method c", self.ctx) print(f"in test_method_c: {id}") if __name__ == "__main__": study_id = random.randrange(0, 100000, 2) logger_name = f'study_main_{study_id}' ctx = Ctx(app_username='******', logger_name=logger_name) logger = RpgLogging(logger_name=logger_name, level_threshold='debug') logger.setup_logging() try: db = InvokePSQL() # series_dict = { # "opponent_party_size": "4", # "opponent_candidate": "Skeleton", # "debug_ind": "1", # "party_name": "AvgJoes_5" # } t = TraceIt("study") study = Study(db=db, ctx=ctx, app_username='******', study_name='Stats Compare', tracer=t) except Exception as error:
class Die(object): @ctx_decorator def __init__(self, ctx, sides=20, debug_ind=False): """ Randomization class :param sides: the number of sides this die will have (default: 20) :param debug_ind: log to class_eval array? (default: False) """ self.sides = sides self.debug_ind = debug_ind self.details = [] # holds rollAmount objs self.method_last_call_audit = {} # dict where method name key holds last crumb for that method self.logger = RpgLogging(logger_name=ctx.logger_name) self.ctx = ctx def add_method_last_call_audit(self, audit_obj): self.method_last_call_audit[audit_obj['methodName']] = audit_obj def get_method_last_call_audit(self, method_name='ALL'): if method_name == 'ALL': return_val = self.method_last_call_audit else: return_val = self.method_last_call_audit[method_name] return return_val def get_last_detail(self): """ Return a list of the RollAmount dataclass instances """ return self.details[-1] def get_details(self): """ Return a list of the RollAmount dataclass instances """ return self.details # _perform_roll should only be used by the other methods. The "_" at # the beginning of the name is a convention Python uses for # that sort of thing (more info: Python private method convention) # This simplifies the calls being done from the other methods @ctx_decorator def _perform_roll(self, rolls, dropvalue=False, dropfrom="Low", halved=False): """ Handles the calculations for the class. :param rolls: How many rolls to do :param dropvalue: Drop a value? (default: False) :param dropfrom: If Dropping, from which end? (default: "Low") :param halved: Cut sum in half? (default: False) """ t_roll_details = RollAmount(die_used=self.sides) t_roll_details.die_rolls = rolls # print(f'adding roll id: {t_roll_details.roll_id} to {ctx.crumbs[-1]}') self.ctx.add_roll_id(t_roll_details.roll_id) if dropvalue: t_roll_details.adjustment_values["dropvalue"] = dropvalue t_roll_details.adjustment_values["dropfrom"] = dropfrom if halved: t_roll_details.adjustment_values["halved"] = halved tmp_hold = [] # list to hold all rolled values tot = 0 # variable to hold the total sum value for x in range(0, rolls): # place the roll results in the tmpHold list raw_roll = random.randint(1, self.sides) tmp_hold.append(raw_roll) t_roll_details.base_roll.append(raw_roll) # If dropping from either side, sort the array accordingly if dropvalue: if dropfrom == "High": tmp_hold.sort(reverse=True) else: tmp_hold.sort() del tmp_hold[0] # then remove the first value for y in tmp_hold: # compute the sum of all values left tot = tot + y if halved: # halve value rounding down (floor) tot = tot // 2 t_roll_details.die_total_used = tot self.details.append(t_roll_details) self.logger.info(msg='roll_audit', json_dict=t_roll_details.__dict__, ctx=self.ctx) return tot @ctx_decorator def roll(self, rolls=1, droplowest=False): """ Perform a number of standard rolls and return the sum :param rolls: How many times to roll the die (Default: 1) :param droplowest: Drop the lowest value? (Default: False) """ if droplowest: result = self._perform_roll(rolls=rolls, dropvalue=True, dropfrom="Low") else: result = self._perform_roll(rolls=rolls, dropvalue=False) return result @ctx_decorator def roll_with_advantage(self): """ Perform a single roll with advantage """ return self._perform_roll(rolls=2, dropvalue=True, dropfrom="Low") @ctx_decorator def roll_with_disadvantage(self): """ Perform a single roll with disadvantage """ return self._perform_roll(rolls=2, dropvalue=True, dropfrom="High") @ctx_decorator def roll_with_resistance(self, rolls): """ Perform rolls and return half the total sum """ return self._perform_roll(rolls=rolls, dropvalue=False, halved=True) @ctx_decorator def get_sum(self, startingval, multiplier): return startingval + self.roll(rolls=multiplier)
class Series(object): @ctx_decorator def __init__(self, db: InvokePSQL, ctx: Ctx, series_id: int, study_instance_id: int, encounter_repetitions: int, encounter_param_dict: Dict, tracer: TraceIt): self.db = db self.ctx = ctx self.ctx.series_id = series_id self.ctx.study_instance_id = study_instance_id self.method_last_call_audit = {} self.stats = SeriesStats(study_instance_id=self.ctx.study_instance_id, series_id=self.ctx.series_id) self.logger = RpgLogging(logger_name=ctx.logger_name) self.t = tracer self.encounter_repetitions = encounter_repetitions self.encounter_param_dict = encounter_param_dict self.party_name_param = None self.heroes = [] self.hero_party_size_param = None self.opponent_party_size_param = None self.opponents = [] self.series_stats = [] self.encounter_stats = [] self.character_stats = [] self.assign_encounter_params() print(f"study_instance_id={study_instance_id} " f"series_id={self.ctx.series_id} " f"encounter_repetitions={encounter_repetitions} " f"encounter_param_dict={encounter_param_dict} ") self.run_series() def add_method_last_call_audit(self, audit_obj): self.method_last_call_audit[audit_obj['methodName']] = audit_obj def get_method_last_call_audit(self, method_name='ALL'): if method_name == 'ALL': return_val = self.method_last_call_audit else: return_val = self.method_last_call_audit[method_name] return return_val @ctx_decorator def assign_encounter_params(self): if 'party_name' in self.encounter_param_dict.keys(): self.party_name_param = self.encounter_param_dict['party_name'] if 'hero_party_size' in self.encounter_param_dict.keys(): self.hero_party_size_param = self.encounter_param_dict['hero_party_size'] if 'opponent_party_size' in self.encounter_param_dict.keys(): self.opponent_party_size_param = self.encounter_param_dict['opponent_party_size'] if 'opponent_candidate' in self.encounter_param_dict.keys(): self.opponent_candidate_param = self.encounter_param_dict['opponent_candidate'] @ctx_decorator def get_named_party(self): p = [] sql = f"select count(name) from dnd_5e.party where name = '{self.party_name_param}'" res = self.db.query(sql) hero_party_size = int(res[0][0]) if hero_party_size == 0: raise Exception(f'Party {self.party_name_param} could not be found.') full_party = Party(db=self.db, ctx=self.ctx, name=self.party_name_param) for tmp_char in full_party.get_party(): p.append(tmp_char) return p @ctx_decorator def get_foes(self): f = [] for opponent_counter in range(int(self.opponent_party_size_param)): if self.opponent_candidate_param: show_counter = opponent_counter + 1 t_name = f"{self.opponent_candidate_param}({show_counter})" else: t_name = None f.append(Foe(db=self.db, ctx=self.ctx, foe_candidate=self.opponent_candidate_param, foe_name=t_name)) return f @ctx_decorator def run_series(self): for series_counter in range(self.encounter_repetitions): display_repetition = series_counter + 1 print(f"Encounter Repetition: {display_repetition}") heroes = self.get_named_party() opponents = self.get_foes() for Hero in heroes: print(f" {Hero.get_name()}") print(f"Against:") for Opponent in opponents: print(f" {Opponent.get_name()}") e = Encounter(ctx=self.ctx, heroes=heroes, opponents=opponents, tracer=self.t.tracer, encounter_id=series_counter) self.encounter_stats.append(e.get_encounter_stats()) print(f"The winning party was: {e.winning_list_name} in {self.ctx.round} rounds.") print(f"The surviving {e.winning_list_name} members:") for i in range(len(e.winning_list)): if e.winning_list[i].alive: print(f'{e.winning_list[i].get_name()}') # print(f"Character damage info:") print("------------------ Character Stats --------------------") for Hero in heroes: # t_char_stats = CharacterStats(study_instance_id=self.study_instance_id, # series_id=self.series_id, # encounter_id=series_counter, # character_id=Hero.character_id, # character_name=Hero.get_name(), # character_class=Hero.get_class(), # character_race=Hero.get_race(), # character_level=Hero.level, # attack_rolls= Hero.attack_rolls, # attack_attempts=Hero.attack_roll_count, # attack_successes=Hero.attack_success_count, # attack_nat20_count=Hero.attack_roll_nat20_count, # attack_nat1_count=Hero.attack_roll_nat1_count, # damage_dealt_dict=Hero.get_damage_dealt(), # damage_taken_dict=Hero.get_damage_taken()) # t_encounter_stats.heroes.append(t_char_stats) # t_dict = Hero.get_damage_dealt() # print(f" {Hero.get_name()} attacks: {Hero.attack_success_count}/{Hero.attack_roll_count}" # f" nat20s:{Hero.attack_roll_nat20_count} nat1s: {Hero.attack_roll_nat1_count}") # print(Hero.attack_rolls) # print(f" {Hero.get_name()} damage dealt ({t_dict['Total']}): {Hero.get_damage_dealt()}") # t_dict = Hero.get_damage_taken() # print(f" {Hero.get_name()} damage taken ({t_dict['Total']}): {Hero.get_damage_taken()}") print(fix_dict_for_json(Hero.stats.__dict__)) for Opponent in opponents: # t_char_stats = CharacterStats(study_instance_id=self.study_instance_id, # series_id=self.series_id, # encounter_id=series_counter, # character_id=-1, # character_name=Opponent.get_name(), # character_class='Foe', # character_race=Opponent.get_race(), # character_level=Opponent.level, # attack_rolls=Opponent.attack_rolls, # attack_attempts=Opponent.attack_roll_count, # attack_successes=Opponent.attack_success_count, # attack_nat20_count=Opponent.attack_roll_nat20_count, # attack_nat1_count=Opponent.attack_roll_nat1_count, # damage_dealt_dict=Opponent.get_damage_dealt(), # damage_taken_dict=Opponent.get_damage_taken() # ) # t_encounter_stats.opponents.append(t_char_stats) # t_dict = Opponent.get_damage_dealt() # print(f" {Opponent.get_name()} attacks: {Opponent.attack_success_count}/{Opponent.attack_roll_count}" # f" nat20s: {Opponent.attack_roll_nat20_count} nat1s: {Opponent.attack_roll_nat1_count}") # print(Opponent.attack_rolls) # print(f" {Opponent.get_name()} damage dealt ({t_dict['Total']}): {Opponent.get_damage_dealt()}") # t_dict = Opponent.get_damage_taken() # print(f" {Opponent.get_name()} damage taken ({t_dict['Total']}): {Opponent.get_damage_taken()}") print(fix_dict_for_json(Opponent.stats.__dict__)) # print(e.get_characters_stats()) # self.stats.update_totals() self.logger.info(ctx=self.ctx, msg='character_stats', json_dict=fix_dict_for_json(e.get_characters_stats())) print("------------------ Encounter Stats --------------------") print(fix_dict_for_json(e.stats.__dict__)) print("------------------ Series Stats --------------------") print(fix_dict_for_json(self.stats.__dict__)) self.logger.info(ctx=self.ctx, msg='series_stats', json_dict=fix_dict_for_json(self.stats.get_dict()))