diff --git a/erepublik/Fighting b/erepublik/Fighting new file mode 100644 index 0000000..a916225 --- /dev/null +++ b/erepublik/Fighting @@ -0,0 +1,859 @@ + + + +# TODO: Fix fighting and reimplement CitizenMilitary module +# class CitizenMilitary(CitizenTravel): +# all_battles: Dict[int, classes.Battle] = None +# __last_war_update_data = None +# +# active_fs: bool = False +# +# @property +# def as_dict(self): +# d = super().as_dict +# d.update(active_fs=self.active_fs, all_battles=self.all_battles) +# return d +# def update_all(): +# super().update_all() +# self.update_war_info() +# +# def update_war_info(self): +# if ( +# self.__last_war_update_data +# and self.__last_war_update_data.get("last_updated", 0) + 30 > self.now.timestamp() +# ): +# r_json = self.__last_war_update_data +# else: +# r_json = self._get_military_campaigns_json_list().json() +# if r_json.get("countries"): +# if self.all_battles is None: +# self.all_battles = {} +# self.__last_war_update_data = r_json +# if r_json.get("battles"): +# all_battles = {} +# for battle_data in r_json.get("battles", {}).values(): +# all_battles[battle_data.get("id")] = classes.Battle(battle_data) +# # old_all_battles = self.all_battles +# self.all_battles = all_battles +# # for battle in old_all_battles.values(): +# # utils._clear_up_battle_memory(battle) +# +# def get_battle_for_war(self, war_id: int) -> Optional[classes.Battle]: +# self.update_war_info() +# war_info = self.get_war_status(war_id) +# return self.all_battles.get(war_info.get("battle_id"), None) +# +# def get_war_status(self, war_id: int) -> Dict[str, Union[bool, Dict[int, str]]]: +# r = self._get_wars_show(war_id) +# html = r.text +# ret = {} +# reg_re = re.compile(fr'data-war-id="{war_id}" data-region-id="(\d+)" data-region-name="([- \w]+)"') +# if reg_re.findall(html): +# ret.update(regions={}, can_attack=True) +# for reg in reg_re.findall(html): +# ret["regions"].update({int(reg[0]): reg[1]}) +# elif re.search( +# r'Join', +# html, +# ): +# battle_id = re.search( +# r'Join', +# html, +# ).group(1) +# ret.update(can_attack=False, battle_id=int(battle_id)) +# elif re.search(r"This war is no longer active.", html): +# ret.update(can_attack=False, ended=True) +# else: +# ret.update(can_attack=False) +# return ret +# +# def get_available_weapons(self, battle_id: int): +# return self._get_military_show_weapons(battle_id).json() +# +# def set_default_weapon(self, battle: classes.Battle, division: classes.BattleDivision) -> int: +# available_weapons = self._get_military_show_weapons(battle.id).json() +# while not isinstance(available_weapons, list): +# available_weapons = self._get_military_show_weapons(battle.id).json() +# weapon_quality = -1 +# weapon_damage = 0 +# if not division.is_air: +# for weapon in available_weapons: +# try: +# if weapon["weaponQuantity"] > 30 and weapon["weaponInfluence"] > weapon_damage: +# weapon_quality = int(weapon["weaponId"]) +# weapon_damage = weapon["weaponInfluence"] +# except ValueError: +# pass +# return self.change_weapon(battle, weapon_quality, division) +# +# def change_weapon(self, battle: classes.Battle, quality: int, battle_zone: classes.BattleDivision) -> int: +# r = self._post_military_change_weapon(battle.id, battle_zone.id, quality) +# influence = r.json().get("weaponInfluence") +# self._report_action( +# "MILITARY_WEAPON", f"Switched to q{quality} weapon," f" new influence {influence}", kwargs=r.json() +# ) +# return influence +# +# def sorted_battles(self, sort_by_time: bool = True, only_tp=False) -> List[classes.Battle]: +# cs_battles_priority_air: List[classes.Battle] = [] +# cs_battles_priority_ground: List[classes.Battle] = [] +# cs_battles_air: List[classes.Battle] = [] +# cs_battles_ground: List[classes.Battle] = [] +# deployed_battles_air: List[classes.Battle] = [] +# deployed_battles_ground: List[classes.Battle] = [] +# ally_battles_air: List[classes.Battle] = [] +# ally_battles_ground: List[classes.Battle] = [] +# other_battles_air: List[classes.Battle] = [] +# other_battles_ground: List[classes.Battle] = [] +# +# ret_battles: List[classes.Battle] = [] +# if sort_by_time: +# battle_list = sorted(self.all_battles.values(), key=lambda b: b.start) +# battle_list.reverse() +# else: +# battle_list = sorted(self.all_battles.values(), key=lambda b: b.id) +# +# contribution_json = self._get_military_campaigns_json_citizen().json() +# contributions: List[Dict[str, int]] = contribution_json.get("contributions") or [] +# contributions.sort(key=lambda b: -b.get("damage")) +# +# for contribution_battle in contributions: +# if contribution_battle.get("battle_id") and contribution_battle.get("battle_id") in self.all_battles: +# ret_battles.append(self.all_battles[contribution_battle.get("battle_id")]) +# +# for battle in battle_list: +# battle_sides = [battle.invader.country, battle.defender.country] +# if battle.id in ret_battles: +# continue +# # CS Battles +# elif self.details.citizenship in battle_sides: +# if battle.has_air: +# if battle.defender.id == self.details.citizenship: +# cs_battles_priority_air.append(battle) +# else: +# cs_battles_air.append(battle) +# else: +# if battle.defender.id == self.details.citizenship: +# cs_battles_priority_ground.append(battle) +# else: +# cs_battles_ground.append(battle) +# +# # Current location battles: +# elif self.details.current_country in battle_sides: +# if battle.has_air: +# deployed_battles_air.append(battle) +# else: +# deployed_battles_ground.append(battle) +# +# # Deployed battles and allied battles: +# elif self.details.current_country in battle.invader.allies + battle.defender.allies + battle_sides: +# if self.details.current_country in battle.invader.deployed + battle.defender.deployed: +# if battle.has_air: +# deployed_battles_air.append(battle) +# else: +# deployed_battles_ground.append(battle) +# # Allied battles: +# else: +# if battle.has_air: +# ally_battles_air.append(battle) +# else: +# ally_battles_ground.append(battle) +# else: +# if battle.has_air: +# other_battles_air.append(battle) +# else: +# other_battles_ground.append(battle) +# +# cs_battles = cs_battles_priority_air + cs_battles_priority_ground + cs_battles_air + cs_battles_ground +# if only_tp: +# return cs_battles +# deployed_battles = deployed_battles_air + deployed_battles_ground +# other_battles = ally_battles_air + ally_battles_ground + other_battles_air + other_battles_ground +# ret_battles = ret_battles + cs_battles + deployed_battles + other_battles +# return ret_battles +# +# def get_cheap_tp_divisions(self) -> Dict[str, List[Tuple[int, classes.BattleDivision]]]: +# air_divs: List[Tuple[int, classes.BattleDivision]] = [] +# ground_divs: List[Tuple[int, classes.BattleDivision]] = [] +# check_maverick = self.maverick and self.config.maverick +# for battle in reversed(self.sorted_battles(True, True)): +# for division in battle.div.values(): +# is_start_ok = utils.good_timedelta(division.battle.start, timedelta(minutes=-1)) < self.now +# if not division.terrain and is_start_ok and not division.div_end: +# if division.is_air and self.config.air: +# division_medals = self.get_battle_round_data(division) +# medal = division_medals[self.details.citizenship == division.battle.defender.country] +# if not medal: +# air_divs.append((0, division)) +# else: +# air_divs.append((medal.get("1").get("raw_value"), division)) +# elif not division.is_air and self.config.ground: +# if not division.div == self.division and not check_maverick: +# continue +# division_medals = self.get_battle_round_data(division) +# medal = division_medals[self.details.citizenship == division.battle.defender.country] +# if not medal: +# ground_divs.append((0, division)) +# else: +# ground_divs.append((medal.get("1").get("raw_value"), division)) +# +# air_divs.sort(key=lambda z: (z[0], z[1].battle.start)) +# ground_divs.sort(key=lambda z: (z[0], z[1].battle.start)) +# return {"air": air_divs, "ground": ground_divs} +# +# @property +# def has_battle_contribution(self): +# return bool(self.__last_war_update_data.get("citizen_contribution", [])) +# +# def find_battle_to_fight( +# self, silent: bool = False +# ) -> Tuple[classes.Battle, classes.BattleDivision, classes.BattleSide]: +# self.update_war_info() +# for battle in self.sorted_battles(self.config.sort_battles_time): +# if not isinstance(battle, classes.Battle): +# continue +# if battle.is_dict_lib: +# continue +# battle_zone: Optional[classes.BattleDivision] = None +# for div in battle.div.values(): +# if div.terrain == 0: +# if div.div_end: +# continue +# maverick_ok = self.maverick and self.config.maverick +# if self.config.air and div.is_air: +# battle_zone = div +# break +# elif self.config.ground and not div.is_air and (div.div == self.division or maverick_ok): +# battle_zone = div +# break +# else: +# continue +# if not battle_zone: +# continue +# allies = ( +# battle.invader.deployed + battle.defender.deployed + [battle.invader.country, battle.defender.country] +# ) +# +# travel_needed = self.details.current_country not in allies +# +# if battle.is_rw: +# side = battle.defender if self.config.rw_def_side else battle.invader +# else: +# defender_side = self.details.current_country in battle.defender.allies + [ +# battle.defender.country, +# ] +# side = battle.defender if defender_side else battle.invader +# +# if not silent: +# self.write_log(str(battle)) +# +# travel = ( +# (self.config.travel_to_fight and self.should_travel_to_fight() or self.config.force_travel) +# if travel_needed +# else True +# ) +# +# if not travel: +# continue +# yield battle, battle_zone, side +# +# def find_battle_and_fight(self): +# count = self.should_fight()[0] +# if count: +# self.write_log("Checking for battles to fight in...") +# for battle, division, side in self.find_battle_to_fight(): +# +# allies = ( +# battle.invader.deployed +# + battle.defender.deployed +# + [battle.invader.country, battle.defender.country] +# ) +# +# travel_needed = self.details.current_country not in allies +# +# if battle.start > self.now: +# self.sleep(utils.get_sleep_seconds(battle.start)) +# +# if travel_needed and not self.change_division(battle, division, side): +# break +# +# if self.change_division(battle, division): +# self.set_default_weapon(battle, division) +# self.fight(battle, division, side, count) +# self.travel_to_residence() +# break +# +# def fight( +# self, +# battle: classes.Battle, +# division: classes.BattleDivision, +# side: classes.BattleSide = None, +# count: int = None, +# ) -> Optional[int]: +# """Fight in a battle. +# +# Will auto activate booster and travel if allowed to do it. +# :param battle: Battle battle to fight in +# :type battle: Battle +# :param division: Division number to fight in available choices +# :type division: BattleDivision +# :param side: BattleSide or None. Battle side to fight in, If side not == invader id or not in invader deployed +# allies list, then defender's side is chosen +# :type side: BattleSide +# :param count: How many hits to do, if not specified self.should_fight() is called. +# :type count: int +# :param use_ebs: Should use energy bars if count > 0 and not enough food_fights +# :type use_ebs: bool +# :return: None if no errors while fighting, otherwise error count. +# :rtype: int +# """ +# if self.restricted_ip: +# self.write_warning("Fighting is not allowed from restricted IP!") +# self._report_action("IP_BLACKLISTED", "Fighting is not allowed from restricted IP!") +# return 1 +# if not division.is_air and self.config.boosters: +# self.activate_damage_booster(not division.is_air) +# if side is None: +# side = ( +# battle.defender +# if self.details.citizenship in battle.defender.allies + [battle.defender.country] +# else battle.invader +# ) +# if count is None: +# count = self.should_fight()[0] +# +# self.write_log(f"Fighting in battle for {battle.region_name} on {side} side in d{division.div}") +# +# if self.now < utils.localize_dt(datetime(2021, 2, 8)): +# error_count = total_damage = total_hits = 0 +# ok_to_fight = True +# while ok_to_fight and error_count < 10 and count > 0: +# while all((count > 0, error_count < 10, self.energy.energy >= 50)): +# hits, error, damage = self._shoot(battle, division, side) +# count -= hits +# total_hits += hits +# total_damage += damage +# error_count += error +# else: +# if self.energy.energy < 50 or error_count >= 10 or count <= 0: +# self.write_log(f"Hits: {total_hits:>4} | Damage: {total_damage}") +# ok_to_fight = False +# if total_damage: +# self.report_fighting(battle, not side.is_defender, division, total_damage, total_hits) +# return error_count +# else: +# deployment_id = self.deploy(division, side, count * 10) +# self.sleep(count // 3) # TODO: connect to eRepublik's WS and get from there when deploy ends +# energy_used = 0 +# if deployment_id: +# self.write_warning( +# "If eRepublik responds with HTTP 500 Internal Error, " +# "it is kind of ok, because deployment has not finished yet." +# ) +# deployment_data = self._post_military_fight_deploy_deploy_report_data(deployment_id).json() +# if not deployment_data.get("error"): +# data = deployment_data["data"] +# total_damage = int(data["damage"].replace(",", "")) +# energy_used = int(data["energySpent"].replace(",", "")) +# self.details.pp += int(data["rewards"]["prestigePoints"].replace(",", "")) +# self.report_fighting(battle, not side.is_defender, division, total_damage, energy_used // 10) +# return energy_used +# +# def _shoot(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide): +# if division.is_air: +# response = self._post_military_fight_air(battle.id, side.id, division.id) +# else: +# response = self._post_military_fight_ground(battle.id, side.id, division.id) +# +# if "Zone is not meant for " in response.text: +# self.sleep(5) +# return 0, 1, 0 +# try: +# r_json = response.json() +# except (ValueError, HTTPError, RequestException): +# return 0, 10, 0 +# hits = 0 +# damage = 0 +# err = False +# if r_json.get("error"): +# if r_json.get("message") == "SHOOT_LOCKOUT": +# pass +# elif r_json.get("message") == "NOT_ENOUGH_WEAPONS": +# self.set_default_weapon(battle, division) +# elif r_json.get("message") == "Cannot activate a zone with a non-native division": +# self.write_warning("Wrong division!!") +# return 0, 10, 0 +# elif r_json.get("message") == "ZONE_INACTIVE": +# self.write_warning("Wrong division!!") +# return 0, 10, 0 +# elif r_json.get("message") == "NON_BELLIGERENT": +# self.write_warning("Dictatorship/Liberation wars are not supported!") +# return 0, 10, 0 +# elif r_json.get("message") in ["FIGHT_DISABLED", "DEPLOYMENT_MODE"]: +# self._post_main_profile_update( +# "options", params='{"optionName":"enable_web_deploy","optionValue":"off"}' +# ) +# self.set_default_weapon(battle, division) +# else: +# if r_json.get("message") == "UNKNOWN_SIDE": +# self._rw_choose_side(battle, side) +# elif r_json.get("message") == "CHANGE_LOCATION": +# countries = [side.country] + side.deployed +# self.travel_to_battle(battle, countries) +# err = True +# elif r_json.get("message") == "ENEMY_KILLED": +# # Non-InfantryKit players +# if r_json["user"]["earnedXp"]: +# hits = r_json["user"]["earnedXp"] +# # InfantryKit player +# # The almost always safe way (breaks on levelup hit) +# elif self.energy.energy >= r_json["details"]["wellness"]: # Haven't reached levelup +# hits = (self.energy.energy - r_json["details"]["wellness"]) // 10 +# else: +# hits = r_json["hits"] +# if r_json["user"]["epicBattle"]: +# hits /= 1 + r_json["user"]["epicBattle"] +# +# self.energy.energy = r_json["details"]["wellness"] +# self.details.xp = int(r_json["details"]["points"]) +# damage = r_json["user"]["givenDamage"] * (1.1 if r_json["oldEnemy"]["isNatural"] else 1) +# else: +# err = True +# +# return hits, err, damage +# +# def deploy_bomb( +# self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool, count: int = 1 +# ) -> Optional[int]: +# """Deploy bombs in a battle for given side. +# +# :param battle: Battle +# :type battle: classes.Battle +# :param division: BattleDivision +# :type division: classes.BattleDivision +# :param bomb_id: int bomb id +# :type bomb_id: int +# :param inv_side: should deploy on invader side +# :type inv_side: bool +# :param count: how many bombs to deploy +# :type count: int +# :return: Deployed count +# :rtype: int +# """ +# +# if not isinstance(count, int) or count < 1: +# count = 1 +# has_traveled = False +# if battle.is_rw: +# has_traveled = self.travel_to_battle(battle, [battle.defender.country]) +# self._rw_choose_side(battle, battle.invader if inv_side else battle.defender) +# if inv_side: +# good_countries = [battle.invader.country] + battle.invader.deployed +# if self.details.current_country not in good_countries: +# has_traveled = self.travel_to_battle(battle, good_countries) +# else: +# involved = ( +# [battle.invader.country, battle.defender.country] + battle.invader.deployed + battle.defender.deployed +# ) +# if self.details.current_country not in involved: +# count = 0 +# side = battle.invader if inv_side else battle.defender +# errors = deployed_count = 0 +# while (not deployed_count == count) and errors < 10: +# r = self._post_military_deploy_bomb(battle.id, division.id, side.id, bomb_id).json() +# if not r.get("error"): +# deployed_count += 1 +# self.sleep(0.5) +# elif r.get("message") == "LOCKED": +# self.sleep(0.5) +# elif r.get("message") == "INVALID_BOMB": +# errors = 10 +# else: +# errors += 1 +# +# if has_traveled: +# self.travel_to_residence() +# +# self._report_action("MILITARY_BOMB", f"Deployed {deployed_count} bombs in battle {battle.id}") +# return deployed_count +# +# def change_division( +# self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None +# ) -> bool: +# """Change division. +# +# :param battle: classes.Battle +# :type battle: classes.Battle +# :param division: int target division to switch to +# :type division: classes.BattleDivision +# :param side: Side to choose +# :type side: classes.BattleSide +# :return: +# """ +# resp = self._post_main_battlefield_change_division(battle.id, division.id, side.id if side else None) +# if resp.json().get("error"): +# self.write_warning(resp.json().get("message")) +# return False +# self._report_action( +# "MILITARY_DIV_SWITCH", f"Switched to d{division.div} in battle {battle.id}", kwargs=resp.json() +# ) +# return True +# +# def get_ground_hit_dmg_value( +# self, +# rang: int = None, +# strength: float = None, +# elite: bool = None, +# ne: bool = False, +# booster_50: bool = False, +# booster_100: bool = False, +# tp: bool = True, +# ) -> Decimal: +# if not rang or not strength or elite is None: +# r = self._get_main_citizen_profile_json(self.details.citizen_id).json() +# if not rang: +# rang = r["military"]["militaryData"]["ground"]["rankNumber"] +# if not strength: +# strength = r["military"]["militaryData"]["ground"]["strength"] +# if elite is None: +# elite = r["citizenAttributes"]["level"] > 100 +# if ne: +# tp = True +# +# return utils.calculate_hit(strength, rang, tp, elite, ne, 50 if booster_50 else 100 if booster_100 else 0) +# +# def get_air_hit_dmg_value( +# self, rang: int = None, elite: bool = None, ne: bool = False, weapon: bool = False +# ) -> Decimal: +# if not rang or elite is None: +# r = self._get_main_citizen_profile_json(self.details.citizen_id).json() +# if not rang: +# rang = r["military"]["militaryData"]["aircraft"]["rankNumber"] +# if elite is None: +# elite = r["citizenAttributes"]["level"] > 100 +# +# return utils.calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0) +# +# def activate_damage_booster(self, ground: bool = True) -> int: +# kind = "damage" if ground else "aircraftDamage" +# if self.config.boosters and not self.get_active_damage_booster(ground): +# booster: Optional[types.InvFinalItem] = None +# for quality, data in sorted(self.inventory.boosters.get(kind, {}).items(), key=lambda x: x[0]): +# for _duration, _booster in sorted(data.items(), key=lambda y: y[0]): +# critical_amount = 2 if quality < 10 and ground else 10 +# if _booster.get("amount") > critical_amount: +# booster = _booster +# break +# break +# if booster: +# kind = "damage" if ground else "air_damage" +# self._report_action("MILITARY_BOOSTER", f"Activated {booster['name']}") +# resp = self._post_economy_activate_booster(booster["quality"], booster["durability"], kind).json() +# self._update_inventory_data(resp) +# return self.get_active_damage_booster(ground) +# +# def get_active_damage_booster(self, ground: bool = True) -> int: +# kind = "damage" if ground else "aircraftDamage" +# boosters = self.inventory.active.get(kind, {}) +# quality = 0 +# for q, boost in boosters.items(): +# if boost["quality"] * 10 > quality: +# quality = boost["quality"] * 10 +# return quality +# +# def get_active_ground_damage_booster(self) -> int: +# return self.get_active_damage_booster(True) +# +# def get_active_air_damage_booster(self) -> int: +# return self.get_active_damage_booster(False) +# +# def activate_battle_effect(self, battle_id: int, kind: str) -> bool: +# self._report_action("MILITARY_BOOSTER", f"Activated {kind} booster") +# resp = self._post_main_activate_battle_effect(battle_id, kind, self.details.citizen_id).json() +# return not resp.get("error") +# +# def activate_pp_booster(self, pp_item: types.InvFinalItem) -> bool: +# self._report_action("MILITARY_BOOSTER", f'Activated {pp_item["name"]}') +# resp = self._post_economy_activate_booster( +# pp_item["quality"], pp_item["durability"], "prestige_points" +# ).json() +# self._update_inventory_data(resp) +# return pp_item.get("kind") in self.inventory.active +# +# def _rw_choose_side(self, battle: classes.Battle, side: classes.BattleSide) -> Response: +# return self._post_main_battlefield_travel(side.id, battle.id) +# +# def should_travel_to_fight(self) -> bool: +# ret = False +# if self.config.always_travel: +# ret = True +# elif self.should_do_levelup: # Do levelup +# ret = True +# # Get to next Energy +1 +# elif self.next_reachable_energy and self.config.next_energy: +# ret = True +# # 1h worth of energy +# elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit: +# ret = True +# return ret +# +# def should_fight(self) -> Tuple[int, str, bool]: +# """Checks if citizen should fight at this moment +# :rtype: Tuple[int, str, bool] +# """ +# count = 0 +# force_fight = False +# msg = "Fighting not allowed!" +# if not self.config.fight: +# return count, msg, force_fight +# +# # Do levelup +# if self.is_levelup_reachable: +# msg = "Level up" +# if self.should_do_levelup: +# count = (self.energy.limit * 3) // 10 +# force_fight = True +# else: +# self.write_log("Waiting for fully recovered energy before leveling up.") +# +# # Levelup reachable +# elif self.is_levelup_close: +# count = self.details.xp_till_level_up - (self.energy.limit // 10) + 5 +# msg = "Fighting for close Levelup. Doing %i hits" % count +# force_fight = True +# +# elif self.details.pp < 75: +# count = 75 - self.details.pp +# msg = "Obligatory fighting for at least 75pp" +# force_fight = True +# +# elif self.config.continuous_fighting and self.has_battle_contribution: +# count = self.energy.food_fights +# msg = "Continuing to fight in previous battle" +# +# # All-in (type = all-in and full ff) +# elif self.config.all_in and self.energy.energy + self.energy.interval * 3 >= self.energy.limit: +# count = self.energy.food_fights +# msg = "Fighting all-in. Doing %i hits" % count +# +# # Get to next Energy +1 +# elif self.config.next_energy and self.next_reachable_energy: +# count = self.next_reachable_energy +# msg = "Fighting for +1 energy. Doing %i hits" % count +# +# # 1h worth of energy +# elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit: +# count = self.energy.interval +# msg = "Fighting for 1h energy. Doing %i hits" % count +# force_fight = True +# +# return (count if count > 0 else 0), msg, force_fight +# +# def get_battle_round_data(self, division: classes.BattleDivision) -> Tuple[Any, Any]: +# battle = division.battle +# +# r = self._post_military_battle_console( +# battle.id, +# "battleStatistics", +# 1, +# zoneId=battle.zone_id, +# round_id=battle.zone_id, +# division=division.div, +# battleZoneId=division.id, +# type="damage", +# ) +# r_json = r.json() +# return r_json.get(str(battle.invader.id)).get("fighterData"), r_json.get(str(battle.defender.id)).get( +# "fighterData" +# ) +# +# def get_battle_division_stats(self, division: classes.BattleDivision) -> Dict[str, Any]: +# battle = division.battle +# r = self._get_military_battle_stats(battle.id, division.div, division.id) +# return r.json() +# +# def get_division_max_hit(self, division: classes.BattleDivision) -> int: +# """Returns max hit in division for current side (if not on either side returns 0) +# +# :param division: BattleDivision for which to get max hit value +# :type division: classes.BattleDivision +# :return: max hit value +# :rtype: int +# """ +# return self.get_battle_division_stats(division).get("maxHit", -1) +# +# def schedule_attack(self, war_id: int, region_id: int, region_name: str, at_time: datetime): +# if at_time: +# self.sleep(utils.get_sleep_seconds(at_time)) +# self.get_csrf_token() +# self.launch_attack(war_id, region_id, region_name) +# +# def get_active_wars(self, country: constants.Country = None) -> List[int]: +# r = self._get_country_military(country.link if country else self.details.citizenship.link) +# all_war_ids = re.findall(r'//www\.erepublik\.com/en/wars/show/(\d+)"', r.text) +# return [int(wid) for wid in all_war_ids] +# +# def get_last_battle_of_war_end_time(self, war_id: int) -> datetime: +# r = self._get_wars_show(war_id) +# html = r.text +# last_battle_id = int(re.search( +# r'', html +# ).group(1)) +# console = self._post_military_battle_console(last_battle_id, "warList", 1).json() +# battle = console.get("list")[0] +# return utils.localize_dt(datetime.strptime(battle.get("result").get("end"), "%Y-%m-%d %H:%M:%S")) +# +# def launch_attack(self, war_id: int, region_id: int, region_name: str): +# self._post_wars_attack_region(war_id, region_id, region_name) +# self._report_action("MILITARY_QUEUE_ATTACK", f"Battle for *{region_name}* queued") +# +# def get_country_mus(self, country: constants.Country) -> Dict[int, str]: +# ret = {} +# r = self._get_main_leaderboards_damage_rankings(country.id) +# for data in r.json()["mu_filter"]: +# if data["id"]: +# ret.update({data["id"]: data["name"]}) +# r = self._get_main_leaderboards_damage_aircraft_rankings(country.id) +# for data in r.json()["mu_filter"]: +# if data["id"]: +# ret.update({data["id"]: data["name"]}) +# return ret +# +# def get_mu_members(self, mu_id: int) -> Dict[int, str]: +# ret = {} +# r = self._get_military_unit_data(mu_id) +# +# for page in range(int(r.json()["panelContents"]["pages"])): +# r = self._get_military_unit_data(mu_id, currentPage=page + 1) +# for user in r.json()["panelContents"]["members"]: +# if not user["isDead"]: +# ret.update({user["citizenId"]: user["name"]}) +# return ret +# +# def get_citizen_weekly_daily_orders_done(self, citizen_id: int = None, weeks_ago: int = 0) -> int: +# if citizen_id is None: +# citizen_id = self.details.citizen_id +# profile = self._get_main_citizen_profile_json(citizen_id).json() +# mu_id = profile.get("military", {}).get("militaryUnit", {}).get("id", 0) +# if mu_id: +# name = profile.get("citizen", {}).get("name") +# member = self._get_military_unit_data( +# mu_id, +# currentPage=1, +# panel="members", +# sortBy="dailyOrdersCompleted", +# weekFilter=f"week{weeks_ago}", +# search=name, +# ).json() +# return member.get("panelContents", {}).get("members", [{}])[0].get("dailyOrdersCompleted") +# return 0 +# +# def get_possibly_empty_medals(self): +# self.update_war_info() +# for battle in self.all_battles.values(): +# for division in battle.div.values(): +# if division.wall["dom"] == 50 or division.wall["dom"] > 98: +# yield division, division.wall["for"] == battle.invader.country.id +# +# def report_fighting( +# self, battle: classes.Battle, invader: bool, division: classes.BattleDivision, damage: float, hits: int +# ): +# self.reporter.report_fighting(battle, invader, division, damage, hits) +# if self.config.telegram: +# self.telegram.report_fight(battle, invader, division, damage, hits) +# +# def get_deploy_inventory(self, division: classes.BattleDivision, side: classes.BattleSide): +# ret = self._post_fight_deploy_get_inventory(division.battle.id, side.id, division.id).json() +# # if ret.get('recoverableEnergyBuyFood'): +# # self.buy_food() +# # return self.get_deploy_inventory(division, side) +# if ret.get("captcha"): +# self.do_captcha_challenge() +# if ret.get("error"): +# if ret.get("message") == "Deployment disabled.": +# self._post_main_profile_update( +# "options", params='{"optionName":"enable_web_deploy","optionValue":"on"}' +# ) +# return self.get_deploy_inventory(division, side) +# else: +# self.report_error(f"Unable to get deployment inventory because: {ret.get('message')}") +# return ret +# +# def deploy(self, division: classes.BattleDivision, side: classes.BattleSide, energy: int, _retry=0) -> int: +# _energy = int(energy) +# deploy_inv = self.get_deploy_inventory(division, side) +# if not deploy_inv["minEnergy"] <= energy <= deploy_inv["maxEnergy"]: +# return 0 +# energy_sources = {} +# source_idx = 0 +# recoverable = deploy_inv["recoverableEnergy"] +# for source in reversed(sorted(deploy_inv["energySources"], key=lambda s: (s["type"], s.get("quality", 0)))): +# if source["type"] == "pool": +# _energy -= source["energy"] +# elif source["type"] in ["food", "energy_bar"]: +# recovers = source["energy"] // source["amount"] +# amount = (recoverable if source["type"] == "food" else _energy) // recovers +# amount = amount if amount < source["amount"] else source["amount"] +# if amount > 0: +# energy_sources.update({f"energySources[{source_idx}][quality]": source["quality"]}) +# energy_sources.update({f"energySources[{source_idx}][amount]": amount}) +# source_idx += 1 +# used_energy = amount * recovers +# recoverable -= used_energy +# _energy -= used_energy +# if _energy <= 0: +# break +# if _energy > 0: +# energy -= _energy +# weapon_q = -1 +# weapon_strength = 0 +# if not division.is_air: +# for weapon in sorted(deploy_inv["weapons"], key=lambda w: w["damageperHit"]): +# if (weapon["damageperHit"] or 0) > weapon_strength and (weapon["amount"] or 0) > 50: +# weapon_q = weapon["quality"] +# r = self._post_fight_deploy_start_deploy( +# division.battle.id, side.id, division.id, energy, weapon_q, **energy_sources +# ).json() +# if r.get("error"): +# self.report_error(f"Deploy failed: '{r.get('message')}'") +# if r.get("message") == "Deployment disabled.": +# self._post_main_profile_update( +# "options", params='{"optionName":"enable_web_deploy","optionValue":"on"}' +# ) +# if _retry < 5: +# return self.deploy(division, side, energy, _retry + 1) +# else: +# self.report_error("Unable to deploy 5 times!") +# return 0 +# return r.get("deploymentId") + + # def should_fight(self, silent: bool = True) -> Tuple[int, str, bool]: + # if not hasattr(super, "should_fight"): + # return 0, "Unable to fight", False + # count, log_msg, force_fight = super().should_fight() + # + # if count > 0 and not force_fight: + # if self.energy.food_fights - self.my_companies.ff_lockdown < count: + # log_msg = ( + # f"Fight count modified (old count: {count} | FF: {self.energy.food_fights} | " + # f"WAM ff_lockdown: {self.my_companies.ff_lockdown} |" + # f" New count: {count - self.my_companies.ff_lockdown})" + # ) + # count -= self.my_companies.ff_lockdown + # if count <= 0: + # count = 0 + # log_msg = f"Not fighting because WAM needs {self.my_companies.ff_lockdown} food fights" + # + # if self.max_time_till_full_ff > self.time_till_week_change: + # max_count = (int(self.time_till_week_change.total_seconds()) // 360 * self.energy.interval) // 10 + # log_msg = ( + # f"End for Weekly challenge is near (Recoverable until WC end {max_count}hp | want to do {count}hits)" + # ) + # count = count if max_count > count else max_count + # + # if not silent: + # self.write_log(log_msg) + # + # return count, log_msg, force_fight diff --git a/erepublik/citizen.py b/erepublik/citizen.py index 5458097..8b3ae9c 100644 --- a/erepublik/citizen.py +++ b/erepublik/citizen.py @@ -218,8 +218,6 @@ class BaseCitizen(access_points.CitizenAPI): self.energy.interval = citizen.get("energyPerInterval", 0) self.energy.limit = citizen.get("energyToRecover", 0) self.energy.energy = citizen.get("energy", 0) - # self.energy.set_reference_time(utils.good_timedelta(self.now, - # timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))) self.details.current_region = citizen.get("regionLocationId", 0) self.details.current_country = constants.COUNTRIES.get( @@ -1777,835 +1775,6 @@ class CitizenMedia(BaseCitizen): self.write_warning(f"Unable to delete article (#{article_id})!") -# TODO: Fix fighting and reimplement CitizenMilitary module -# class CitizenMilitary(CitizenTravel): -# all_battles: Dict[int, classes.Battle] = None -# __last_war_update_data = None -# -# active_fs: bool = False -# -# @property -# def as_dict(self): -# d = super().as_dict -# d.update(active_fs=self.active_fs, all_battles=self.all_battles) -# return d -# def update_all(): -# super().update_all() -# self.update_war_info() -# -# def update_war_info(self): -# if ( -# self.__last_war_update_data -# and self.__last_war_update_data.get("last_updated", 0) + 30 > self.now.timestamp() -# ): -# r_json = self.__last_war_update_data -# else: -# r_json = self._get_military_campaigns_json_list().json() -# if r_json.get("countries"): -# if self.all_battles is None: -# self.all_battles = {} -# self.__last_war_update_data = r_json -# if r_json.get("battles"): -# all_battles = {} -# for battle_data in r_json.get("battles", {}).values(): -# all_battles[battle_data.get("id")] = classes.Battle(battle_data) -# # old_all_battles = self.all_battles -# self.all_battles = all_battles -# # for battle in old_all_battles.values(): -# # utils._clear_up_battle_memory(battle) -# -# def get_battle_for_war(self, war_id: int) -> Optional[classes.Battle]: -# self.update_war_info() -# war_info = self.get_war_status(war_id) -# return self.all_battles.get(war_info.get("battle_id"), None) -# -# def get_war_status(self, war_id: int) -> Dict[str, Union[bool, Dict[int, str]]]: -# r = self._get_wars_show(war_id) -# html = r.text -# ret = {} -# reg_re = re.compile(fr'data-war-id="{war_id}" data-region-id="(\d+)" data-region-name="([- \w]+)"') -# if reg_re.findall(html): -# ret.update(regions={}, can_attack=True) -# for reg in reg_re.findall(html): -# ret["regions"].update({int(reg[0]): reg[1]}) -# elif re.search( -# r'Join', -# html, -# ): -# battle_id = re.search( -# r'Join', -# html, -# ).group(1) -# ret.update(can_attack=False, battle_id=int(battle_id)) -# elif re.search(r"This war is no longer active.", html): -# ret.update(can_attack=False, ended=True) -# else: -# ret.update(can_attack=False) -# return ret -# -# def get_available_weapons(self, battle_id: int): -# return self._get_military_show_weapons(battle_id).json() -# -# def set_default_weapon(self, battle: classes.Battle, division: classes.BattleDivision) -> int: -# available_weapons = self._get_military_show_weapons(battle.id).json() -# while not isinstance(available_weapons, list): -# available_weapons = self._get_military_show_weapons(battle.id).json() -# weapon_quality = -1 -# weapon_damage = 0 -# if not division.is_air: -# for weapon in available_weapons: -# try: -# if weapon["weaponQuantity"] > 30 and weapon["weaponInfluence"] > weapon_damage: -# weapon_quality = int(weapon["weaponId"]) -# weapon_damage = weapon["weaponInfluence"] -# except ValueError: -# pass -# return self.change_weapon(battle, weapon_quality, division) -# -# def change_weapon(self, battle: classes.Battle, quality: int, battle_zone: classes.BattleDivision) -> int: -# r = self._post_military_change_weapon(battle.id, battle_zone.id, quality) -# influence = r.json().get("weaponInfluence") -# self._report_action( -# "MILITARY_WEAPON", f"Switched to q{quality} weapon," f" new influence {influence}", kwargs=r.json() -# ) -# return influence -# -# def sorted_battles(self, sort_by_time: bool = True, only_tp=False) -> List[classes.Battle]: -# cs_battles_priority_air: List[classes.Battle] = [] -# cs_battles_priority_ground: List[classes.Battle] = [] -# cs_battles_air: List[classes.Battle] = [] -# cs_battles_ground: List[classes.Battle] = [] -# deployed_battles_air: List[classes.Battle] = [] -# deployed_battles_ground: List[classes.Battle] = [] -# ally_battles_air: List[classes.Battle] = [] -# ally_battles_ground: List[classes.Battle] = [] -# other_battles_air: List[classes.Battle] = [] -# other_battles_ground: List[classes.Battle] = [] -# -# ret_battles: List[classes.Battle] = [] -# if sort_by_time: -# battle_list = sorted(self.all_battles.values(), key=lambda b: b.start) -# battle_list.reverse() -# else: -# battle_list = sorted(self.all_battles.values(), key=lambda b: b.id) -# -# contribution_json = self._get_military_campaigns_json_citizen().json() -# contributions: List[Dict[str, int]] = contribution_json.get("contributions") or [] -# contributions.sort(key=lambda b: -b.get("damage")) -# -# for contribution_battle in contributions: -# if contribution_battle.get("battle_id") and contribution_battle.get("battle_id") in self.all_battles: -# ret_battles.append(self.all_battles[contribution_battle.get("battle_id")]) -# -# for battle in battle_list: -# battle_sides = [battle.invader.country, battle.defender.country] -# if battle.id in ret_battles: -# continue -# # CS Battles -# elif self.details.citizenship in battle_sides: -# if battle.has_air: -# if battle.defender.id == self.details.citizenship: -# cs_battles_priority_air.append(battle) -# else: -# cs_battles_air.append(battle) -# else: -# if battle.defender.id == self.details.citizenship: -# cs_battles_priority_ground.append(battle) -# else: -# cs_battles_ground.append(battle) -# -# # Current location battles: -# elif self.details.current_country in battle_sides: -# if battle.has_air: -# deployed_battles_air.append(battle) -# else: -# deployed_battles_ground.append(battle) -# -# # Deployed battles and allied battles: -# elif self.details.current_country in battle.invader.allies + battle.defender.allies + battle_sides: -# if self.details.current_country in battle.invader.deployed + battle.defender.deployed: -# if battle.has_air: -# deployed_battles_air.append(battle) -# else: -# deployed_battles_ground.append(battle) -# # Allied battles: -# else: -# if battle.has_air: -# ally_battles_air.append(battle) -# else: -# ally_battles_ground.append(battle) -# else: -# if battle.has_air: -# other_battles_air.append(battle) -# else: -# other_battles_ground.append(battle) -# -# cs_battles = cs_battles_priority_air + cs_battles_priority_ground + cs_battles_air + cs_battles_ground -# if only_tp: -# return cs_battles -# deployed_battles = deployed_battles_air + deployed_battles_ground -# other_battles = ally_battles_air + ally_battles_ground + other_battles_air + other_battles_ground -# ret_battles = ret_battles + cs_battles + deployed_battles + other_battles -# return ret_battles -# -# def get_cheap_tp_divisions(self) -> Dict[str, List[Tuple[int, classes.BattleDivision]]]: -# air_divs: List[Tuple[int, classes.BattleDivision]] = [] -# ground_divs: List[Tuple[int, classes.BattleDivision]] = [] -# check_maverick = self.maverick and self.config.maverick -# for battle in reversed(self.sorted_battles(True, True)): -# for division in battle.div.values(): -# is_start_ok = utils.good_timedelta(division.battle.start, timedelta(minutes=-1)) < self.now -# if not division.terrain and is_start_ok and not division.div_end: -# if division.is_air and self.config.air: -# division_medals = self.get_battle_round_data(division) -# medal = division_medals[self.details.citizenship == division.battle.defender.country] -# if not medal: -# air_divs.append((0, division)) -# else: -# air_divs.append((medal.get("1").get("raw_value"), division)) -# elif not division.is_air and self.config.ground: -# if not division.div == self.division and not check_maverick: -# continue -# division_medals = self.get_battle_round_data(division) -# medal = division_medals[self.details.citizenship == division.battle.defender.country] -# if not medal: -# ground_divs.append((0, division)) -# else: -# ground_divs.append((medal.get("1").get("raw_value"), division)) -# -# air_divs.sort(key=lambda z: (z[0], z[1].battle.start)) -# ground_divs.sort(key=lambda z: (z[0], z[1].battle.start)) -# return {"air": air_divs, "ground": ground_divs} -# -# @property -# def has_battle_contribution(self): -# return bool(self.__last_war_update_data.get("citizen_contribution", [])) -# -# def find_battle_to_fight( -# self, silent: bool = False -# ) -> Tuple[classes.Battle, classes.BattleDivision, classes.BattleSide]: -# self.update_war_info() -# for battle in self.sorted_battles(self.config.sort_battles_time): -# if not isinstance(battle, classes.Battle): -# continue -# if battle.is_dict_lib: -# continue -# battle_zone: Optional[classes.BattleDivision] = None -# for div in battle.div.values(): -# if div.terrain == 0: -# if div.div_end: -# continue -# maverick_ok = self.maverick and self.config.maverick -# if self.config.air and div.is_air: -# battle_zone = div -# break -# elif self.config.ground and not div.is_air and (div.div == self.division or maverick_ok): -# battle_zone = div -# break -# else: -# continue -# if not battle_zone: -# continue -# allies = ( -# battle.invader.deployed + battle.defender.deployed + [battle.invader.country, battle.defender.country] -# ) -# -# travel_needed = self.details.current_country not in allies -# -# if battle.is_rw: -# side = battle.defender if self.config.rw_def_side else battle.invader -# else: -# defender_side = self.details.current_country in battle.defender.allies + [ -# battle.defender.country, -# ] -# side = battle.defender if defender_side else battle.invader -# -# if not silent: -# self.write_log(str(battle)) -# -# travel = ( -# (self.config.travel_to_fight and self.should_travel_to_fight() or self.config.force_travel) -# if travel_needed -# else True -# ) -# -# if not travel: -# continue -# yield battle, battle_zone, side -# -# def find_battle_and_fight(self): -# count = self.should_fight()[0] -# if count: -# self.write_log("Checking for battles to fight in...") -# for battle, division, side in self.find_battle_to_fight(): -# -# allies = ( -# battle.invader.deployed -# + battle.defender.deployed -# + [battle.invader.country, battle.defender.country] -# ) -# -# travel_needed = self.details.current_country not in allies -# -# if battle.start > self.now: -# self.sleep(utils.get_sleep_seconds(battle.start)) -# -# if travel_needed and not self.change_division(battle, division, side): -# break -# -# if self.change_division(battle, division): -# self.set_default_weapon(battle, division) -# self.fight(battle, division, side, count) -# self.travel_to_residence() -# break -# -# def fight( -# self, -# battle: classes.Battle, -# division: classes.BattleDivision, -# side: classes.BattleSide = None, -# count: int = None, -# ) -> Optional[int]: -# """Fight in a battle. -# -# Will auto activate booster and travel if allowed to do it. -# :param battle: Battle battle to fight in -# :type battle: Battle -# :param division: Division number to fight in available choices -# :type division: BattleDivision -# :param side: BattleSide or None. Battle side to fight in, If side not == invader id or not in invader deployed -# allies list, then defender's side is chosen -# :type side: BattleSide -# :param count: How many hits to do, if not specified self.should_fight() is called. -# :type count: int -# :param use_ebs: Should use energy bars if count > 0 and not enough food_fights -# :type use_ebs: bool -# :return: None if no errors while fighting, otherwise error count. -# :rtype: int -# """ -# if self.restricted_ip: -# self.write_warning("Fighting is not allowed from restricted IP!") -# self._report_action("IP_BLACKLISTED", "Fighting is not allowed from restricted IP!") -# return 1 -# if not division.is_air and self.config.boosters: -# self.activate_damage_booster(not division.is_air) -# if side is None: -# side = ( -# battle.defender -# if self.details.citizenship in battle.defender.allies + [battle.defender.country] -# else battle.invader -# ) -# if count is None: -# count = self.should_fight()[0] -# -# self.write_log(f"Fighting in battle for {battle.region_name} on {side} side in d{division.div}") -# -# if self.now < utils.localize_dt(datetime(2021, 2, 8)): -# error_count = total_damage = total_hits = 0 -# ok_to_fight = True -# while ok_to_fight and error_count < 10 and count > 0: -# while all((count > 0, error_count < 10, self.energy.energy >= 50)): -# hits, error, damage = self._shoot(battle, division, side) -# count -= hits -# total_hits += hits -# total_damage += damage -# error_count += error -# else: -# if self.energy.energy < 50 or error_count >= 10 or count <= 0: -# self.write_log(f"Hits: {total_hits:>4} | Damage: {total_damage}") -# ok_to_fight = False -# if total_damage: -# self.report_fighting(battle, not side.is_defender, division, total_damage, total_hits) -# return error_count -# else: -# deployment_id = self.deploy(division, side, count * 10) -# self.sleep(count // 3) # TODO: connect to eRepublik's WS and get from there when deploy ends -# energy_used = 0 -# if deployment_id: -# self.write_warning( -# "If eRepublik responds with HTTP 500 Internal Error, " -# "it is kind of ok, because deployment has not finished yet." -# ) -# deployment_data = self._post_military_fight_deploy_deploy_report_data(deployment_id).json() -# if not deployment_data.get("error"): -# data = deployment_data["data"] -# total_damage = int(data["damage"].replace(",", "")) -# energy_used = int(data["energySpent"].replace(",", "")) -# self.details.pp += int(data["rewards"]["prestigePoints"].replace(",", "")) -# self.report_fighting(battle, not side.is_defender, division, total_damage, energy_used // 10) -# return energy_used -# -# def _shoot(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide): -# if division.is_air: -# response = self._post_military_fight_air(battle.id, side.id, division.id) -# else: -# response = self._post_military_fight_ground(battle.id, side.id, division.id) -# -# if "Zone is not meant for " in response.text: -# self.sleep(5) -# return 0, 1, 0 -# try: -# r_json = response.json() -# except (ValueError, HTTPError, RequestException): -# return 0, 10, 0 -# hits = 0 -# damage = 0 -# err = False -# if r_json.get("error"): -# if r_json.get("message") == "SHOOT_LOCKOUT": -# pass -# elif r_json.get("message") == "NOT_ENOUGH_WEAPONS": -# self.set_default_weapon(battle, division) -# elif r_json.get("message") == "Cannot activate a zone with a non-native division": -# self.write_warning("Wrong division!!") -# return 0, 10, 0 -# elif r_json.get("message") == "ZONE_INACTIVE": -# self.write_warning("Wrong division!!") -# return 0, 10, 0 -# elif r_json.get("message") == "NON_BELLIGERENT": -# self.write_warning("Dictatorship/Liberation wars are not supported!") -# return 0, 10, 0 -# elif r_json.get("message") in ["FIGHT_DISABLED", "DEPLOYMENT_MODE"]: -# self._post_main_profile_update( -# "options", params='{"optionName":"enable_web_deploy","optionValue":"off"}' -# ) -# self.set_default_weapon(battle, division) -# else: -# if r_json.get("message") == "UNKNOWN_SIDE": -# self._rw_choose_side(battle, side) -# elif r_json.get("message") == "CHANGE_LOCATION": -# countries = [side.country] + side.deployed -# self.travel_to_battle(battle, countries) -# err = True -# elif r_json.get("message") == "ENEMY_KILLED": -# # Non-InfantryKit players -# if r_json["user"]["earnedXp"]: -# hits = r_json["user"]["earnedXp"] -# # InfantryKit player -# # The almost always safe way (breaks on levelup hit) -# elif self.energy.energy >= r_json["details"]["wellness"]: # Haven't reached levelup -# hits = (self.energy.energy - r_json["details"]["wellness"]) // 10 -# else: -# hits = r_json["hits"] -# if r_json["user"]["epicBattle"]: -# hits /= 1 + r_json["user"]["epicBattle"] -# -# self.energy.energy = r_json["details"]["wellness"] -# self.details.xp = int(r_json["details"]["points"]) -# damage = r_json["user"]["givenDamage"] * (1.1 if r_json["oldEnemy"]["isNatural"] else 1) -# else: -# err = True -# -# return hits, err, damage -# -# def deploy_bomb( -# self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool, count: int = 1 -# ) -> Optional[int]: -# """Deploy bombs in a battle for given side. -# -# :param battle: Battle -# :type battle: classes.Battle -# :param division: BattleDivision -# :type division: classes.BattleDivision -# :param bomb_id: int bomb id -# :type bomb_id: int -# :param inv_side: should deploy on invader side -# :type inv_side: bool -# :param count: how many bombs to deploy -# :type count: int -# :return: Deployed count -# :rtype: int -# """ -# -# if not isinstance(count, int) or count < 1: -# count = 1 -# has_traveled = False -# if battle.is_rw: -# has_traveled = self.travel_to_battle(battle, [battle.defender.country]) -# self._rw_choose_side(battle, battle.invader if inv_side else battle.defender) -# if inv_side: -# good_countries = [battle.invader.country] + battle.invader.deployed -# if self.details.current_country not in good_countries: -# has_traveled = self.travel_to_battle(battle, good_countries) -# else: -# involved = ( -# [battle.invader.country, battle.defender.country] + battle.invader.deployed + battle.defender.deployed -# ) -# if self.details.current_country not in involved: -# count = 0 -# side = battle.invader if inv_side else battle.defender -# errors = deployed_count = 0 -# while (not deployed_count == count) and errors < 10: -# r = self._post_military_deploy_bomb(battle.id, division.id, side.id, bomb_id).json() -# if not r.get("error"): -# deployed_count += 1 -# self.sleep(0.5) -# elif r.get("message") == "LOCKED": -# self.sleep(0.5) -# elif r.get("message") == "INVALID_BOMB": -# errors = 10 -# else: -# errors += 1 -# -# if has_traveled: -# self.travel_to_residence() -# -# self._report_action("MILITARY_BOMB", f"Deployed {deployed_count} bombs in battle {battle.id}") -# return deployed_count -# -# def change_division( -# self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None -# ) -> bool: -# """Change division. -# -# :param battle: classes.Battle -# :type battle: classes.Battle -# :param division: int target division to switch to -# :type division: classes.BattleDivision -# :param side: Side to choose -# :type side: classes.BattleSide -# :return: -# """ -# resp = self._post_main_battlefield_change_division(battle.id, division.id, side.id if side else None) -# if resp.json().get("error"): -# self.write_warning(resp.json().get("message")) -# return False -# self._report_action( -# "MILITARY_DIV_SWITCH", f"Switched to d{division.div} in battle {battle.id}", kwargs=resp.json() -# ) -# return True -# -# def get_ground_hit_dmg_value( -# self, -# rang: int = None, -# strength: float = None, -# elite: bool = None, -# ne: bool = False, -# booster_50: bool = False, -# booster_100: bool = False, -# tp: bool = True, -# ) -> Decimal: -# if not rang or not strength or elite is None: -# r = self._get_main_citizen_profile_json(self.details.citizen_id).json() -# if not rang: -# rang = r["military"]["militaryData"]["ground"]["rankNumber"] -# if not strength: -# strength = r["military"]["militaryData"]["ground"]["strength"] -# if elite is None: -# elite = r["citizenAttributes"]["level"] > 100 -# if ne: -# tp = True -# -# return utils.calculate_hit(strength, rang, tp, elite, ne, 50 if booster_50 else 100 if booster_100 else 0) -# -# def get_air_hit_dmg_value( -# self, rang: int = None, elite: bool = None, ne: bool = False, weapon: bool = False -# ) -> Decimal: -# if not rang or elite is None: -# r = self._get_main_citizen_profile_json(self.details.citizen_id).json() -# if not rang: -# rang = r["military"]["militaryData"]["aircraft"]["rankNumber"] -# if elite is None: -# elite = r["citizenAttributes"]["level"] > 100 -# -# return utils.calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0) -# -# def activate_damage_booster(self, ground: bool = True) -> int: -# kind = "damage" if ground else "aircraftDamage" -# if self.config.boosters and not self.get_active_damage_booster(ground): -# booster: Optional[types.InvFinalItem] = None -# for quality, data in sorted(self.inventory.boosters.get(kind, {}).items(), key=lambda x: x[0]): -# for _duration, _booster in sorted(data.items(), key=lambda y: y[0]): -# critical_amount = 2 if quality < 10 and ground else 10 -# if _booster.get("amount") > critical_amount: -# booster = _booster -# break -# break -# if booster: -# kind = "damage" if ground else "air_damage" -# self._report_action("MILITARY_BOOSTER", f"Activated {booster['name']}") -# resp = self._post_economy_activate_booster(booster["quality"], booster["durability"], kind).json() -# self._update_inventory_data(resp) -# return self.get_active_damage_booster(ground) -# -# def get_active_damage_booster(self, ground: bool = True) -> int: -# kind = "damage" if ground else "aircraftDamage" -# boosters = self.inventory.active.get(kind, {}) -# quality = 0 -# for q, boost in boosters.items(): -# if boost["quality"] * 10 > quality: -# quality = boost["quality"] * 10 -# return quality -# -# def get_active_ground_damage_booster(self) -> int: -# return self.get_active_damage_booster(True) -# -# def get_active_air_damage_booster(self) -> int: -# return self.get_active_damage_booster(False) -# -# def activate_battle_effect(self, battle_id: int, kind: str) -> bool: -# self._report_action("MILITARY_BOOSTER", f"Activated {kind} booster") -# resp = self._post_main_activate_battle_effect(battle_id, kind, self.details.citizen_id).json() -# return not resp.get("error") -# -# def activate_pp_booster(self, pp_item: types.InvFinalItem) -> bool: -# self._report_action("MILITARY_BOOSTER", f'Activated {pp_item["name"]}') -# resp = self._post_economy_activate_booster( -# pp_item["quality"], pp_item["durability"], "prestige_points" -# ).json() -# self._update_inventory_data(resp) -# return pp_item.get("kind") in self.inventory.active -# -# def _rw_choose_side(self, battle: classes.Battle, side: classes.BattleSide) -> Response: -# return self._post_main_battlefield_travel(side.id, battle.id) -# -# def should_travel_to_fight(self) -> bool: -# ret = False -# if self.config.always_travel: -# ret = True -# elif self.should_do_levelup: # Do levelup -# ret = True -# # Get to next Energy +1 -# elif self.next_reachable_energy and self.config.next_energy: -# ret = True -# # 1h worth of energy -# elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit: -# ret = True -# return ret -# -# def should_fight(self) -> Tuple[int, str, bool]: -# """Checks if citizen should fight at this moment -# :rtype: Tuple[int, str, bool] -# """ -# count = 0 -# force_fight = False -# msg = "Fighting not allowed!" -# if not self.config.fight: -# return count, msg, force_fight -# -# # Do levelup -# if self.is_levelup_reachable: -# msg = "Level up" -# if self.should_do_levelup: -# count = (self.energy.limit * 3) // 10 -# force_fight = True -# else: -# self.write_log("Waiting for fully recovered energy before leveling up.") -# -# # Levelup reachable -# elif self.is_levelup_close: -# count = self.details.xp_till_level_up - (self.energy.limit // 10) + 5 -# msg = "Fighting for close Levelup. Doing %i hits" % count -# force_fight = True -# -# elif self.details.pp < 75: -# count = 75 - self.details.pp -# msg = "Obligatory fighting for at least 75pp" -# force_fight = True -# -# elif self.config.continuous_fighting and self.has_battle_contribution: -# count = self.energy.food_fights -# msg = "Continuing to fight in previous battle" -# -# # All-in (type = all-in and full ff) -# elif self.config.all_in and self.energy.energy + self.energy.interval * 3 >= self.energy.limit: -# count = self.energy.food_fights -# msg = "Fighting all-in. Doing %i hits" % count -# -# # Get to next Energy +1 -# elif self.config.next_energy and self.next_reachable_energy: -# count = self.next_reachable_energy -# msg = "Fighting for +1 energy. Doing %i hits" % count -# -# # 1h worth of energy -# elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit: -# count = self.energy.interval -# msg = "Fighting for 1h energy. Doing %i hits" % count -# force_fight = True -# -# return (count if count > 0 else 0), msg, force_fight -# -# def get_battle_round_data(self, division: classes.BattleDivision) -> Tuple[Any, Any]: -# battle = division.battle -# -# r = self._post_military_battle_console( -# battle.id, -# "battleStatistics", -# 1, -# zoneId=battle.zone_id, -# round_id=battle.zone_id, -# division=division.div, -# battleZoneId=division.id, -# type="damage", -# ) -# r_json = r.json() -# return r_json.get(str(battle.invader.id)).get("fighterData"), r_json.get(str(battle.defender.id)).get( -# "fighterData" -# ) -# -# def get_battle_division_stats(self, division: classes.BattleDivision) -> Dict[str, Any]: -# battle = division.battle -# r = self._get_military_battle_stats(battle.id, division.div, division.id) -# return r.json() -# -# def get_division_max_hit(self, division: classes.BattleDivision) -> int: -# """Returns max hit in division for current side (if not on either side returns 0) -# -# :param division: BattleDivision for which to get max hit value -# :type division: classes.BattleDivision -# :return: max hit value -# :rtype: int -# """ -# return self.get_battle_division_stats(division).get("maxHit", -1) -# -# def schedule_attack(self, war_id: int, region_id: int, region_name: str, at_time: datetime): -# if at_time: -# self.sleep(utils.get_sleep_seconds(at_time)) -# self.get_csrf_token() -# self.launch_attack(war_id, region_id, region_name) -# -# def get_active_wars(self, country: constants.Country = None) -> List[int]: -# r = self._get_country_military(country.link if country else self.details.citizenship.link) -# all_war_ids = re.findall(r'//www\.erepublik\.com/en/wars/show/(\d+)"', r.text) -# return [int(wid) for wid in all_war_ids] -# -# def get_last_battle_of_war_end_time(self, war_id: int) -> datetime: -# r = self._get_wars_show(war_id) -# html = r.text -# last_battle_id = int(re.search( -# r'', html -# ).group(1)) -# console = self._post_military_battle_console(last_battle_id, "warList", 1).json() -# battle = console.get("list")[0] -# return utils.localize_dt(datetime.strptime(battle.get("result").get("end"), "%Y-%m-%d %H:%M:%S")) -# -# def launch_attack(self, war_id: int, region_id: int, region_name: str): -# self._post_wars_attack_region(war_id, region_id, region_name) -# self._report_action("MILITARY_QUEUE_ATTACK", f"Battle for *{region_name}* queued") -# -# def get_country_mus(self, country: constants.Country) -> Dict[int, str]: -# ret = {} -# r = self._get_main_leaderboards_damage_rankings(country.id) -# for data in r.json()["mu_filter"]: -# if data["id"]: -# ret.update({data["id"]: data["name"]}) -# r = self._get_main_leaderboards_damage_aircraft_rankings(country.id) -# for data in r.json()["mu_filter"]: -# if data["id"]: -# ret.update({data["id"]: data["name"]}) -# return ret -# -# def get_mu_members(self, mu_id: int) -> Dict[int, str]: -# ret = {} -# r = self._get_military_unit_data(mu_id) -# -# for page in range(int(r.json()["panelContents"]["pages"])): -# r = self._get_military_unit_data(mu_id, currentPage=page + 1) -# for user in r.json()["panelContents"]["members"]: -# if not user["isDead"]: -# ret.update({user["citizenId"]: user["name"]}) -# return ret -# -# def get_citizen_weekly_daily_orders_done(self, citizen_id: int = None, weeks_ago: int = 0) -> int: -# if citizen_id is None: -# citizen_id = self.details.citizen_id -# profile = self._get_main_citizen_profile_json(citizen_id).json() -# mu_id = profile.get("military", {}).get("militaryUnit", {}).get("id", 0) -# if mu_id: -# name = profile.get("citizen", {}).get("name") -# member = self._get_military_unit_data( -# mu_id, -# currentPage=1, -# panel="members", -# sortBy="dailyOrdersCompleted", -# weekFilter=f"week{weeks_ago}", -# search=name, -# ).json() -# return member.get("panelContents", {}).get("members", [{}])[0].get("dailyOrdersCompleted") -# return 0 -# -# def get_possibly_empty_medals(self): -# self.update_war_info() -# for battle in self.all_battles.values(): -# for division in battle.div.values(): -# if division.wall["dom"] == 50 or division.wall["dom"] > 98: -# yield division, division.wall["for"] == battle.invader.country.id -# -# def report_fighting( -# self, battle: classes.Battle, invader: bool, division: classes.BattleDivision, damage: float, hits: int -# ): -# self.reporter.report_fighting(battle, invader, division, damage, hits) -# if self.config.telegram: -# self.telegram.report_fight(battle, invader, division, damage, hits) -# -# def get_deploy_inventory(self, division: classes.BattleDivision, side: classes.BattleSide): -# ret = self._post_fight_deploy_get_inventory(division.battle.id, side.id, division.id).json() -# # if ret.get('recoverableEnergyBuyFood'): -# # self.buy_food() -# # return self.get_deploy_inventory(division, side) -# if ret.get("captcha"): -# self.do_captcha_challenge() -# if ret.get("error"): -# if ret.get("message") == "Deployment disabled.": -# self._post_main_profile_update( -# "options", params='{"optionName":"enable_web_deploy","optionValue":"on"}' -# ) -# return self.get_deploy_inventory(division, side) -# else: -# self.report_error(f"Unable to get deployment inventory because: {ret.get('message')}") -# return ret -# -# def deploy(self, division: classes.BattleDivision, side: classes.BattleSide, energy: int, _retry=0) -> int: -# _energy = int(energy) -# deploy_inv = self.get_deploy_inventory(division, side) -# if not deploy_inv["minEnergy"] <= energy <= deploy_inv["maxEnergy"]: -# return 0 -# energy_sources = {} -# source_idx = 0 -# recoverable = deploy_inv["recoverableEnergy"] -# for source in reversed(sorted(deploy_inv["energySources"], key=lambda s: (s["type"], s.get("quality", 0)))): -# if source["type"] == "pool": -# _energy -= source["energy"] -# elif source["type"] in ["food", "energy_bar"]: -# recovers = source["energy"] // source["amount"] -# amount = (recoverable if source["type"] == "food" else _energy) // recovers -# amount = amount if amount < source["amount"] else source["amount"] -# if amount > 0: -# energy_sources.update({f"energySources[{source_idx}][quality]": source["quality"]}) -# energy_sources.update({f"energySources[{source_idx}][amount]": amount}) -# source_idx += 1 -# used_energy = amount * recovers -# recoverable -= used_energy -# _energy -= used_energy -# if _energy <= 0: -# break -# if _energy > 0: -# energy -= _energy -# weapon_q = -1 -# weapon_strength = 0 -# if not division.is_air: -# for weapon in sorted(deploy_inv["weapons"], key=lambda w: w["damageperHit"]): -# if (weapon["damageperHit"] or 0) > weapon_strength and (weapon["amount"] or 0) > 50: -# weapon_q = weapon["quality"] -# r = self._post_fight_deploy_start_deploy( -# division.battle.id, side.id, division.id, energy, weapon_q, **energy_sources -# ).json() -# if r.get("error"): -# self.report_error(f"Deploy failed: '{r.get('message')}'") -# if r.get("message") == "Deployment disabled.": -# self._post_main_profile_update( -# "options", params='{"optionName":"enable_web_deploy","optionValue":"on"}' -# ) -# if _retry < 5: -# return self.deploy(division, side, energy, _retry + 1) -# else: -# self.report_error("Unable to deploy 5 times!") -# return 0 -# return r.get("deploymentId") - - class CitizenPolitics(BaseCitizen): def get_country_parties(self, country: constants.Country = None) -> dict: r = self._get_main_rankings_parties(country.id if country else self.details.citizenship.id) @@ -3030,35 +2199,6 @@ class _Citizen( if should_collect: self._post_main_weekly_challenge_collect_all(max_collectable_id) - # def should_fight(self, silent: bool = True) -> Tuple[int, str, bool]: - # if not hasattr(super, "should_fight"): - # return 0, "Unable to fight", False - # count, log_msg, force_fight = super().should_fight() - # - # if count > 0 and not force_fight: - # if self.energy.food_fights - self.my_companies.ff_lockdown < count: - # log_msg = ( - # f"Fight count modified (old count: {count} | FF: {self.energy.food_fights} | " - # f"WAM ff_lockdown: {self.my_companies.ff_lockdown} |" - # f" New count: {count - self.my_companies.ff_lockdown})" - # ) - # count -= self.my_companies.ff_lockdown - # if count <= 0: - # count = 0 - # log_msg = f"Not fighting because WAM needs {self.my_companies.ff_lockdown} food fights" - # - # if self.max_time_till_full_ff > self.time_till_week_change: - # max_count = (int(self.time_till_week_change.total_seconds()) // 360 * self.energy.interval) // 10 - # log_msg = ( - # f"End for Weekly challenge is near (Recoverable until WC end {max_count}hp | want to do {count}hits)" - # ) - # count = count if max_count > count else max_count - # - # if not silent: - # self.write_log(log_msg) - # - # return count, log_msg, force_fight - def collect_daily_task(self): self.update_citizen_info() if self.details.daily_task_done and not self.details.daily_task_reward: diff --git a/erepublik/classes.py b/erepublik/classes.py index 4f1e86b..6bea502 100644 --- a/erepublik/classes.py +++ b/erepublik/classes.py @@ -416,27 +416,27 @@ class Config: auto_sell: List[str] = None auto_sell_all = False employees = False - fight = False - air = False - ground = False - all_in = False - next_energy = False - boosters = False - travel_to_fight = False - always_travel = False - epic_hunt = False - epic_hunt_ebs = False - rw_def_side = False - interactive = True - continuous_fighting = False + # fight = False + # air = False + # ground = False + # all_in = False + # next_energy = False + # boosters = False + # travel_to_fight = False + # always_travel = False + # epic_hunt = False + # epic_hunt_ebs = False + # rw_def_side = False + # interactive = True + # continuous_fighting = False auto_buy_raw = False force_wam = False - sort_battles_time = True - force_travel = False + # sort_battles_time = True + # force_travel = False telegram = True telegram_chat_id = 0 telegram_token = "" - maverick = False + # maverick = False spin_wheel_of_fortune = False def __init__(self): @@ -450,27 +450,27 @@ class Config: self.auto_sell = list() self.auto_sell_all = False self.employees = False - self.fight = False - self.air = False - self.ground = False - self.all_in = False - self.next_energy = False - self.boosters = False - self.travel_to_fight = False - self.always_travel = False - self.epic_hunt = False - self.epic_hunt_ebs = False - self.rw_def_side = False - self.interactive = True - self.continuous_fighting = False + # self.fight = False + # self.air = False + # self.ground = False + # self.all_in = False + # self.next_energy = False + # self.boosters = False + # self.travel_to_fight = False + # self.always_travel = False + # self.epic_hunt = False + # self.epic_hunt_ebs = False + # self.rw_def_side = False + # self.interactive = True + # self.continuous_fighting = False self.auto_buy_raw = False self.force_wam = False - self.sort_battles_time = True - self.force_travel = False + # self.sort_battles_time = True + # self.force_travel = False self.telegram = True self.telegram_chat_id = 0 self.telegram_token = "" - self.maverick = False + # self.maverick = False self.spin_wheel_of_fortune = False @property @@ -484,23 +484,23 @@ class Config: auto_sell=self.auto_sell, auto_sell_all=self.auto_sell_all, employees=self.employees, - fight=self.fight, - air=self.air, - ground=self.ground, - all_in=self.all_in, - next_energy=self.next_energy, - travel_to_fight=self.travel_to_fight, - always_travel=self.always_travel, - epic_hunt=self.epic_hunt, - epic_hunt_ebs=self.epic_hunt_ebs, - rw_def_side=self.rw_def_side, - interactive=self.interactive, - maverick=self.maverick, - continuous_fighting=self.continuous_fighting, + # fight=self.fight, + # air=self.air, + # ground=self.ground, + # all_in=self.all_in, + # next_energy=self.next_energy, + # travel_to_fight=self.travel_to_fight, + # always_travel=self.always_travel, + # epic_hunt=self.epic_hunt, + # epic_hunt_ebs=self.epic_hunt_ebs, + # rw_def_side=self.rw_def_side, + # interactive=self.interactive, + # maverick=self.maverick, + # continuous_fighting=self.continuous_fighting, auto_buy_raw=self.auto_buy_raw, force_wam=self.force_wam, - sort_battles_time=self.sort_battles_time, - force_travel=self.force_travel, + # sort_battles_time=self.sort_battles_time, + # force_travel=self.force_travel, telegram=self.telegram, telegram_chat_id=self.telegram_chat_id, telegram_token=self.telegram_token,