def get_damage_dealt(battle, split_msg, next_messages): move_name = normalize_name(split_msg[3]) critical_hit = False if is_opponent(battle, split_msg): attacking_side = battle.opponent defending_side = battle.user else: attacking_side = battle.user defending_side = battle.opponent for line in next_messages: next_line_split = line.split('|') # if one of these strings appears in index 1 then # exit out since we are done with this pokemon's move if len(next_line_split) < 2 or next_line_split[1] in MOVE_END_STRINGS: break elif next_line_split[1] == '-crit': critical_hit = True # if '-damage' appears, we want to parse the percentage damage dealt elif next_line_split[1] == '-damage' and defending_side.name in next_line_split[2]: final_health, maxhp, _ = get_pokemon_info_from_condition(next_line_split[3]) # maxhp can be 0 if the targetted pokemon fainted # the message would be: "0 fnt" if maxhp == 0: maxhp = defending_side.active.max_hp damage_dealt = (defending_side.active.hp / defending_side.active.max_hp)*maxhp - final_health damage_percentage = round(damage_dealt / maxhp, 4) logger.debug("{} did {}% damage to {} with {}".format(attacking_side.active.name, damage_percentage * 100, defending_side.active.name, move_name)) return DamageDealt(attacker=attacking_side.active.name, defender=defending_side.active.name, move=move_name, percent_damage=damage_percentage, crit=critical_hit)
def from_json(self, user_json, first_turn=False): # user_json does not track boosts or volatile statuses # they must be taken from the current battle if first_turn: existing_conditions = (None, None, None) else: existing_conditions = (self.active.name, self.active.boosts, self.active.volatile_statuses) try: trapped = user_json[constants.ACTIVE][0].get( constants.TRAPPED, False) maybe_trapped = user_json[constants.ACTIVE][0].get( constants.MAYBE_TRAPPED, False) self.trapped = trapped or maybe_trapped except KeyError: self.trapped = False self.name = user_json[constants.SIDE][constants.ID] self.reserve.clear() for index, pkmn_dict in enumerate( user_json[constants.SIDE][constants.POKEMON]): pkmn = Pokemon.from_switch_string(pkmn_dict[constants.DETAILS]) pkmn.ability = pkmn_dict[constants.REQUEST_DICT_ABILITY] pkmn.index = index + 1 pkmn.hp, pkmn.max_hp, pkmn.status = get_pokemon_info_from_condition( pkmn_dict[constants.CONDITION]) for stat, number in pkmn_dict[constants.STATS].items(): pkmn.stats[constants.STAT_ABBREVIATION_LOOKUPS[stat]] = number pkmn.item = pkmn_dict[constants.ITEM] if pkmn_dict[ constants.ITEM] else None if pkmn_dict[constants.ACTIVE]: self.active = pkmn if existing_conditions[0] == pkmn.name: pkmn.boosts = existing_conditions[1] pkmn.volatile_statuses = existing_conditions[2] else: self.reserve.append(pkmn) for move_name in pkmn_dict[constants.MOVES]: pkmn.add_move(move_name) # if there is no active pokemon, we do not want to look through it's moves if constants.ACTIVE not in user_json: return try: self.active.can_mega_evo = user_json[constants.ACTIVE][0][ constants.CAN_MEGA_EVO] except KeyError: self.active.can_mega_evo = False try: self.active.can_ultra_burst = user_json[constants.ACTIVE][0][ constants.CAN_ULTRA_BURST] except KeyError: self.active.can_ultra_burst = False try: self.active.can_dynamax = user_json[constants.ACTIVE][0][ constants.CAN_DYNAMAX] except KeyError: self.active.can_dynamax = False # clear the active moves so they can be reset by the options available self.active.moves.clear() # update the active pokemon's moves to show disabled status/pp remaining # this assumes that there is only one active pokemon (single-battle) for index, move in enumerate( user_json[constants.ACTIVE][0][constants.MOVES]): # hidden power's ID is always 'hiddenpower' regardless of the type # the type needs to be parsed separately from the 'move' attribute if move[constants.ID] == constants.HIDDEN_POWER: self.active.add_move('{}{}'.format( constants.HIDDEN_POWER, move['move'].split()[ constants.HIDDEN_POWER_TYPE_STRING_INDEX].lower())) else: self.active.add_move(move[constants.ID]) self.active.moves[-1].disabled = move.get(constants.DISABLED, False) self.active.moves[-1].current_pp = move.get(constants.PP, 1) try: self.active.moves[index].can_z = user_json[ constants.ACTIVE][0][constants.CAN_Z_MOVE][index] except KeyError: pass
def test_fainted_case(self): condition_string = '0/100 fnt' self.assertEqual(0, get_pokemon_info_from_condition(condition_string)[0])
def test_poisoned_case(self): condition_string = '121/403 psn' expected_results = 121, 403, 'psn' self.assertEqual(expected_results, get_pokemon_info_from_condition(condition_string))
def test_burned_case(self): condition_string = '100/100 brn' expected_results = 100, 100, 'brn' self.assertEqual(expected_results, get_pokemon_info_from_condition(condition_string))
def test_basic_case(self): condition_string = '100/100' expected_results = 100, 100, None self.assertEqual(expected_results, get_pokemon_info_from_condition(condition_string))
def from_json(self, user_json, first_turn=False): if first_turn: existing_conditions = (None, None, None) else: existing_conditions = (self.active.name, self.active.boosts, self.active.volatile_statuses) try: trapped = user_json[constants.ACTIVE][0].get( constants.TRAPPED, False) maybe_trapped = user_json[constants.ACTIVE][0].get( constants.MAYBE_TRAPPED, False) self.trapped = trapped or maybe_trapped except KeyError: self.trapped = False try: can_mega_evo = user_json[constants.ACTIVE][0][ constants.CAN_MEGA_EVO] except KeyError: can_mega_evo = False try: can_ultra_burst = user_json[constants.ACTIVE][0][ constants.CAN_ULTRA_BURST] except KeyError: can_ultra_burst = False try: can_z_move = [] for m in user_json[constants.ACTIVE][0][constants.CAN_Z_MOVE]: if m is not None: can_z_move.append(True) else: can_z_move.append(False) except KeyError: can_z_move = [False, False, False, False] self.name = user_json[constants.SIDE][constants.ID] self.reserve.clear() for index, pkmn_dict in enumerate( user_json[constants.SIDE][constants.POKEMON]): pkmn = Pokemon.from_switch_string(pkmn_dict[constants.DETAILS]) pkmn.ability = pkmn_dict[constants.REQUEST_DICT_ABILITY] pkmn.index = index + 1 pkmn.hp, pkmn.status = get_pokemon_info_from_condition( pkmn_dict[constants.CONDITION]) pkmn.item = pkmn_dict[constants.ITEM] if pkmn_dict[ constants.ITEM] else None if pkmn_dict[constants.ACTIVE]: self.active = pkmn if existing_conditions[0] == pkmn.name: pkmn.boosts = existing_conditions[1] pkmn.volatile_statuses = existing_conditions[2] else: self.reserve.append(pkmn) for move_name in pkmn_dict[constants.MOVES]: if move_name.startswith(constants.HIDDEN_POWER): pkmn.add_move('{}{}'.format( move_name, constants. HIDDEN_POWER_RESERVE_MOVE_BASE_DAMAGE_STRING)) else: pkmn.add_move(move_name) # if there is no active pokemon, we do not want to look through it's moves if constants.ACTIVE not in user_json: return self.active.can_mega_evo = can_mega_evo self.active.can_ultra_burst = can_ultra_burst # clear the active moves so they can be reset by the options available self.active.moves.clear() # update the active pokemon's moves to show disabled status/pp remaining # this assumes that there is only one active pokemon (single-battle) for index, move in enumerate( user_json[constants.ACTIVE][0][constants.MOVES]): if move[constants.ID] == constants.HIDDEN_POWER: self.active.add_move('{}{}{}'.format( constants.HIDDEN_POWER, move['move'].split()[ constants.HIDDEN_POWER_TYPE_STRING_INDEX].lower(), constants.HIDDEN_POWER_ACTIVE_MOVE_BASE_DAMAGE_STRING)) else: self.active.add_move(move[constants.ID]) self.active.moves[-1].disabled = move.get(constants.DISABLED, False) self.active.moves[-1].current_pp = move.get(constants.PP, 1) if can_z_move[index]: self.active.moves[index].can_z = True