Compare commits

..

7 Commits

Author SHA1 Message Date
700bd8d98e Bump version: 0.18.0 → 0.18.1 2020-01-02 22:43:01 +02:00
3599dc40fc More logging, Citizen.get_raw_surplus() fixed and moved to Citizen.my_companies.get_wam_raw_usage() 2020-01-02 22:42:40 +02:00
6ba727a781 promo spam loop 2020-01-02 18:49:38 +02:00
7f1829a5d7 Bump version: 0.17.3 → 0.18.0 2019-12-18 16:26:10 +02:00
e374aa8a54 Implemented division switching,
improved multi bomb deploy with auto traveling,
Citizen.fight() simplified battle data gathering logic -> Citizen.shoot logic improved
Citizen.all_battles are now defaultdict with default value of empty/invalid battle, for times when trying to do things with battle which is not in all_battle dict
2019-12-18 16:25:52 +02:00
7edfa3b004 Bump version: 0.17.2 → 0.17.3 2019-12-18 11:45:02 +02:00
12aee23739 Variable and method redeclaration 2019-12-18 11:44:18 +02:00
5 changed files with 222 additions and 102 deletions

View File

@ -4,7 +4,7 @@
__author__ = """Eriks Karls""" __author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv' __email__ = 'eriks@72.lv'
__version__ = '0.17.2' __version__ = '0.18.1'
from erepublik import classes, utils from erepublik import classes, utils
from erepublik.citizen import Citizen from erepublik.citizen import Citizen

View File

@ -1,10 +1,10 @@
import re import re
import sys import sys
from threading import Event from collections import defaultdict
from itertools import product
from datetime import datetime, timedelta from datetime import datetime, timedelta
from itertools import product
from json import loads, dumps from json import loads, dumps
from threading import Event
from time import sleep from time import sleep
from typing import Dict, List, Tuple, Any, Union, Set from typing import Dict, List, Tuple, Any, Union, Set
@ -12,7 +12,6 @@ from requests import Response, RequestException
from erepublik.classes import (CitizenAPI, Battle, Reporter, Config, Energy, Details, Politics, MyCompanies, from erepublik.classes import (CitizenAPI, Battle, Reporter, Config, Energy, Details, Politics, MyCompanies,
TelegramBot, ErepublikException, BattleDivision, MyJSONEncoder) TelegramBot, ErepublikException, BattleDivision, MyJSONEncoder)
from erepublik.utils import * from erepublik.utils import *
@ -38,10 +37,18 @@ class Citizen(CitizenAPI):
ot_points = 0 ot_points = 0
tg_contract = None tg_contract = None
promos = None promos: Dict[str, datetime] = None
eday = 0 eday = 0
energy: Energy
details: Details
politics: Politics
my_companies: MyCompanies
reporter: Reporter
stop_threads: Event
telegram: TelegramBot
r: Response r: Response
name = "Not logged in!" name = "Not logged in!"
debug = False debug = False
@ -320,7 +327,10 @@ class Citizen(CitizenAPI):
return return
ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1) ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1)
promos = loads(normalize_html_json(ugly_js)) promos = loads(normalize_html_json(ugly_js))
self.promos = {k: v for k, v in (self.promos.items() if self.promos else {}) if v > self.now} if self.promos is None:
self.promos = {}
else:
self.promos = {k: v for k, v in self.promos.items() if v > self.now}
send_mail = False send_mail = False
for promo in promos: for promo in promos:
promo_name = promo.get("id") promo_name = promo.get("id")
@ -549,8 +559,16 @@ class Citizen(CitizenAPI):
resp_json = self._get_military_campaigns_json_list().json() resp_json = self._get_military_campaigns_json_list().json()
if resp_json.get("countries"): if resp_json.get("countries"):
self.all_battles = {} if self.all_battles is None:
self.countries = {} self.all_battles = defaultdict(Battle)
else:
self.all_battles.clear()
if self.countries is None:
self.countries = {}
else:
self.countries.clear()
for c_id, c_data in resp_json.get("countries").items(): for c_id, c_data in resp_json.get("countries").items():
if int(c_id) not in self.countries: if int(c_id) not in self.countries:
self.countries.update({ self.countries.update({
@ -561,7 +579,7 @@ class Citizen(CitizenAPI):
self.__last_war_update_data = resp_json self.__last_war_update_data = resp_json
if resp_json.get("battles"): if resp_json.get("battles"):
for battle_data in resp_json.get("battles", {}).values(): for battle_data in resp_json.get("battles", {}).values():
self.all_battles.update({battle_data.get('id'): Battle(battle_data)}) self.all_battles[battle_data.get('id')] = Battle(battle_data)
def eat(self): def eat(self):
""" """
@ -593,8 +611,7 @@ class Citizen(CitizenAPI):
r_json = response.json() r_json = response.json()
next_recovery = r_json.get("food_remaining_reset").split(":") next_recovery = r_json.get("food_remaining_reset").split(":")
self.energy.set_reference_time( self.energy.set_reference_time(
good_timedelta(self.now, good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
) )
self.energy.recovered = r_json.get("health") self.energy.recovered = r_json.get("health")
self.energy.recoverable = r_json.get("food_remaining") self.energy.recoverable = r_json.get("food_remaining")
@ -797,7 +814,16 @@ class Citizen(CitizenAPI):
self.collect_weekly_reward() self.collect_weekly_reward()
break break
def fight(self, battle_id: int, side_id: int, count: int = None): def fight(self, battle_id: int, side_id: int = None, count: int = None):
"""Fight in a battle.
Will auto activate booster and travel if allowed to do it and
in the beginning will switch to default weapon (air - bare hands, ground - q7, if count > 30, else bare hands.
:param battle_id: int BattleId - battle to fight in
:param side_id: int or None. Battle side to fight in, If side_id not == invader id or not in invader deployed allies list, then defender's side is chosen
:param count: How many hits to do, if not specified self.should_fight() is called.
:return: None if no errors while fighting, otherwise error count.
"""
battle = self.all_battles[battle_id] battle = self.all_battles[battle_id]
zone_id = battle.div[11 if battle.is_air else self.division].battle_zone_id zone_id = battle.div[11 if battle.is_air else self.division].battle_zone_id
if not battle.is_air and self.config.boosters: if not battle.is_air and self.config.boosters:
@ -810,10 +836,10 @@ class Citizen(CitizenAPI):
total_damage = 0 total_damage = 0
total_hits = 0 total_hits = 0
side = battle.invader.id == side_id or side_id in battle.invader.deployed
while ok_to_fight and error_count < 10 and count > 0: while ok_to_fight and error_count < 10 and count > 0:
while all((count > 0, error_count < 10, self.energy.recovered >= 50)): while all((count > 0, error_count < 10, self.energy.recovered >= 50)):
hits, error, damage = self._shoot(battle.is_air, battle_id, side_id, zone_id) hits, error, damage = self._shoot(battle_id, side, zone_id)
count -= hits count -= hits
total_hits += hits total_hits += hits
total_damage += damage total_damage += damage
@ -824,13 +850,15 @@ class Citizen(CitizenAPI):
self.write_log("Hits: {:>4} | Damage: {}".format(total_hits, total_damage)) self.write_log("Hits: {:>4} | Damage: {}".format(total_hits, total_damage))
ok_to_fight = False ok_to_fight = False
if total_damage: if total_damage:
self.reporter.report_action(json_val=dict(battle=battle_id, side=side_id, dmg=total_damage, self.reporter.report_action("FIGHT", dict(battle=battle_id, side=side_id, dmg=total_damage,
air=battle.is_air, hits=total_hits), action="FIGHT") air=battle.is_air, hits=total_hits))
if error_count: if error_count:
return error_count return error_count
def _shoot(self, air: bool, battle_id: int, side_id: int, zone_id: int): def _shoot(self, battle_id: int, inv_side: bool, zone_id: int):
if air: battle = self.all_battles[battle_id]
side_id = battle.invader.id if inv_side else battle.defender.id
if battle.is_air:
response = self._post_military_fight_air(battle_id, side_id, zone_id) response = self._post_military_fight_air(battle_id, side_id, zone_id)
else: else:
response = self._post_military_fight_ground(battle_id, side_id, zone_id) response = self._post_military_fight_ground(battle_id, side_id, zone_id)
@ -853,6 +881,9 @@ class Citizen(CitizenAPI):
else: else:
if j_resp.get("message") == "UNKNOWN_SIDE": if j_resp.get("message") == "UNKNOWN_SIDE":
self._rw_choose_side(battle_id, side_id) self._rw_choose_side(battle_id, side_id)
elif j_resp.get("message") == "CHANGE_LOCATION":
countries = [side_id] + battle.invader.deployed if inv_side else battle.defender.deployed
self.travel_to_battle(battle_id, countries)
err = True err = True
elif j_resp.get("message") == "ENEMY_KILLED": elif j_resp.get("message") == "ENEMY_KILLED":
hits = (self.energy.recovered - j_resp["details"]["wellness"]) // 10 hits = (self.energy.recovered - j_resp["details"]["wellness"]) // 10
@ -864,9 +895,53 @@ class Citizen(CitizenAPI):
return hits, err, damage return hits, err, damage
def deploy_bomb(self, battle_id: int, bomb_id: int): def deploy_bomb(self, battle_id: int, bomb_id: int, inv_side: bool = None, count: int = 1) -> int:
r = self._post_military_deploy_bomb(battle_id, bomb_id).json() """Deploy bombs in a battle for given side.
return not r.get('error')
:param battle_id: int battle id
:param bomb_id: int bomb id
:param inv_side: should deploy on invader side, if None then will deploy in currently available side
:param count: int how many bombs to deploy
:return: Deployed count
:rtype: int
"""
if not isinstance(count, int) or count < 1:
count = 1
has_traveled = False
battle = self.all_battles[battle_id]
if inv_side:
good_countries = [battle.invader.id] + battle.invader.deployed
if self.details.current_country not in good_countries:
has_traveled = self.travel_to_battle(battle_id, good_countries)
elif inv_side is not None:
good_countries = [battle.defender.id] + battle.defender.deployed
if self.details.current_country not in good_countries:
has_traveled = self.travel_to_battle(battle_id, good_countries)
else:
involved = [battle.invader.id, battle.defender.id] + battle.invader.deployed + battle.defender.deployed
if self.details.current_country not in involved:
count = 0
errors = deployed_count = 0
while (not deployed_count == count) and errors < 10:
r = self._post_military_deploy_bomb(battle_id, bomb_id).json()
if not r.get('error'):
deployed_count += 1
elif r.get('message') == 'LOCKED':
sleep(0.5)
if has_traveled:
self.travel_to_residence()
return deployed_count
def change_division(self, battle_id: int, division_to: int):
"""Change division.
:param battle_id: int battle id
:param division_to: int target division to switch to
:return:
"""
battle = self.all_battles[battle_id]
self._post_main_battlefield_change_division(battle_id, battle.div[division_to].battle_zone_id)
def work_ot(self): def work_ot(self):
# I"m not checking for 1h cooldown. Beware of nightshift work, if calling more than once every 60min # I"m not checking for 1h cooldown. Beware of nightshift work, if calling more than once every 60min
@ -1029,8 +1104,8 @@ class Citizen(CitizenAPI):
if not self.travel_to_region(wam_holding['region_id']): if not self.travel_to_region(wam_holding['region_id']):
return False return False
response = self._post_economy_work("production", wam=wam_list, employ=employee_companies).json() response = self._post_economy_work("production", wam=wam_list, employ=employee_companies).json()
self.reporter.report_action("WORK_WAM_EMPLOYEES", response)
if response.get("status"): if response.get("status"):
self.reporter.report_action("WORK_WAM_EMPLOYEES", response)
if self.config.auto_sell: if self.config.auto_sell:
for kind, data in response.get("result", {}).get("production", {}).items(): for kind, data in response.get("result", {}).get("production", {}).items():
if kind in self.config.auto_sell and data: if kind in self.config.auto_sell and data:
@ -1066,7 +1141,9 @@ class Citizen(CitizenAPI):
self.buy_food() self.buy_food()
return self._do_wam_and_employee_work(wam_holding_id, employee_companies) return self._do_wam_and_employee_work(wam_holding_id, employee_companies)
else: else:
self.write_log("I was not able to wam and or employ because:\n{}".format(response)) msg = "I was not able to wam and or employ because:\n{}".format(response)
self.reporter.report_action("WORK_WAM_EMPLOYEES", value=msg)
self.write_log(msg)
wam_count = self.my_companies.get_total_wam_count() wam_count = self.my_companies.get_total_wam_count()
if wam_count: if wam_count:
self.write_log("Wam ff lockdown is now {}, was {}".format(wam_count, self.my_companies.ff_lockdown)) self.write_log("Wam ff lockdown is now {}, was {}".format(wam_count, self.my_companies.ff_lockdown))
@ -1488,7 +1565,7 @@ class Citizen(CitizenAPI):
if self.max_time_till_full_ff > self.time_till_week_change: 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 max_count = (int(self.time_till_week_change.total_seconds()) // 360 * self.energy.interval) // 10
log_msg = ("End for Weekly challenge is near " log_msg = ("End for Weekly challenge is near "
f"(Recoverable until WC end {max_count}hp | want to do {count}hits)") f"(Recoverable until WC end {max_count}hp | want to do {count}hits)")
count = count if max_count > count else max_count count = count if max_count > count else max_count
@ -1511,8 +1588,7 @@ class Citizen(CitizenAPI):
@property @property
def next_wc_start(self) -> datetime: def next_wc_start(self) -> datetime:
days = 1 - self.now.weekday() if 1 - self.now.weekday() > 0 else 1 - self.now.weekday() + 7 days = 1 - self.now.weekday() if 1 - self.now.weekday() > 0 else 1 - self.now.weekday() + 7
return good_timedelta(self.now.replace(hour=0, minute=0, second=0, microsecond=0), return good_timedelta(self.now.replace(hour=0, minute=0, second=0, microsecond=0), timedelta(days=days))
timedelta(days=days))
@property @property
def time_till_week_change(self) -> timedelta: def time_till_week_change(self) -> timedelta:
@ -1582,12 +1658,9 @@ class Citizen(CitizenAPI):
if kind in kinds: if kind in kinds:
return self._post_main_write_article(title, content, self.details.citizenship, kind) return self._post_main_write_article(title, content, self.details.citizenship, kind)
else: else:
raise ErepublikException( raise ErepublikException("Article kind must be one of:\n{}\n'{}' is not supported".format(
"Article kind must be one of:\n{}\n'{}' is not supported".format( "\n".join(["{}: {}".format(k, v) for k, v in kinds.items()]), kind
"\n".join(["{}: {}".format(k, v) for k, v in kinds.items()]), ))
kind
)
)
def post_market_offer(self, industry: int, quality: int, amount: int, price: float) -> Response: def post_market_offer(self, industry: int, quality: int, amount: int, price: float) -> Response:
if industry not in self.available_industries.values(): if industry not in self.available_industries.values():
@ -1618,32 +1691,15 @@ class Citizen(CitizenAPI):
self.reporter.report_action("BUY_PRODUCT", ret.json()) self.reporter.report_action("BUY_PRODUCT", ret.json())
return json_ret return json_ret
def get_raw_surplus(self) -> (float, float):
frm = 0.00
wrm = 0.00
for cdata in sorted(self.my_companies.companies.values()):
if cdata["industry_token"] == "FOOD":
raw = frm
elif cdata["industry_token"] == "WEAPON":
raw = wrm
else:
continue
effective_bonus = cdata["effective_bonus"]
base_prod = float(cdata["base_production"])
if cdata["is_raw"]:
raw += base_prod * effective_bonus / 100
else:
raw -= effective_bonus / 100 * base_prod * cdata["upgrades"][str(cdata["quality"])]["raw_usage"]
if cdata["industry_token"] == "FOOD":
frm = raw
elif cdata["industry_token"] == "WEAPON":
wrm = raw
return frm, wrm
def assign_factory_to_holding(self, factory_id: int, holding_id: int) -> Response: def assign_factory_to_holding(self, factory_id: int, holding_id: int) -> Response:
""" """
Assigns factory to new holding Assigns factory to new holding
""" """
company = self.my_companies.companies[factory_id]
company_name = self.factories[company['industry_id']]
if not company['is_raw']:
company_name += f" q{company['quality']}"
self.write_log(f"{company_name} moved to {holding_id}")
return self._post_economy_assign_to_holding(factory_id, holding_id) return self._post_economy_assign_to_holding(factory_id, holding_id)
def upgrade_factory(self, factory_id: int, level: int) -> Response: def upgrade_factory(self, factory_id: int, level: int) -> Response:
@ -1657,9 +1713,18 @@ class Citizen(CitizenAPI):
Storage={1000: 1, 2000: 2} <- Building_type 2 Storage={1000: 1, 2000: 2} <- Building_type 2
""" """
company_name = self.factories[industry_id]
if building_type == 2:
company_name = f"Storage"
self.write_log(f"{company_name} created!")
return self._post_economy_create_company(industry_id, building_type) return self._post_economy_create_company(industry_id, building_type)
def dissolve_factory(self, factory_id: int) -> Response: def dissolve_factory(self, factory_id: int) -> Response:
company = self.my_companies.companies[factory_id]
company_name = self.factories[company['industry_id']]
if not company['is_raw']:
company_name += f" q{company['quality']}"
self.write_log(f"{company_name} dissolved!")
return self._post_economy_sell_company(factory_id, self.details.pin, sell=False) return self._post_economy_sell_company(factory_id, self.details.pin, sell=False)
@property @property
@ -1671,6 +1736,17 @@ class Citizen(CitizenAPI):
return {"food": 1, "weapon": 2, "house": 4, "aircraft": 23, return {"food": 1, "weapon": 2, "house": 4, "aircraft": 23,
"foodRaw": 7, "weaponRaw": 12, "houseRaw": 17, "airplaneRaw": 24} "foodRaw": 7, "weaponRaw": 12, "houseRaw": 17, "airplaneRaw": 24}
@property
def factories(self) -> Dict[int, str]:
"""Returns factory industries as dict(id: name)
:return: dict
"""
return {1: "Food", 2: "Weapons", 4: "House", 23: "Aircraft",
7: "FRM q1", 8: "FRM q2", 9: "FRM q3", 10: "FRM q4", 11: "FRM q5",
12: "WRM q1", 13: "WRM q2", 14: "WRM q3", 15: "WRM q4", 16: "WRM q5",
18: "HRM q1", 19: "HRM q2", 20: "HRM q3", 21: "HRM q4", 22: "HRM q5",
24: "ARM q1", 25: "ARM q2", 26: "ARM q3", 27: "ARM q4", 28: "ARM q5", }
def get_industry_id(self, industry_name: str) -> int: def get_industry_id(self, industry_name: str) -> int:
""" """
Returns industry id Returns industry id
@ -1801,7 +1877,7 @@ class Citizen(CitizenAPI):
if reg_re.findall(html): if reg_re.findall(html):
ret.update(regions={}, can_attack=True) ret.update(regions={}, can_attack=True)
for reg in reg_re.findall(html): for reg in reg_re.findall(html):
ret["regions"].update({str(reg[0]): reg[1]}) ret["regions"].update({int(reg[0]): reg[1]})
elif re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" ' elif re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" '
r'class="join" title="Join"><span>Join</span></a>', html): r'class="join" title="Join"><span>Join</span></a>', html):
battle_id = re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" ' battle_id = re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" '
@ -1931,7 +2007,7 @@ class Citizen(CitizenAPI):
return False return False
data = dict(country=71, action='currency', value=amount) data = dict(country=71, action='currency', value=amount)
self.telegram.send_message(f"Donated {amount}cc to {COUNTRIES[71]}") self.telegram.send_message(f"Donated {amount}cc to {COUNTRIES[71]}")
self.reporter.report_action("CONTRIBUTE_CC", data) self.reporter.report_action("CONTRIBUTE_CC", data, str(amount))
r = self._post_main_country_donate(**data) r = self._post_main_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
@ -1941,7 +2017,7 @@ class Citizen(CitizenAPI):
if self.food["q" + str(quality)] < amount or amount < 10: if self.food["q" + str(quality)] < amount or amount < 10:
return False return False
data = dict(country=71, action='food', value=amount, quality=quality) data = dict(country=71, action='food', value=amount, quality=quality)
self.reporter.report_action("CONTRIBUTE_FOOD", data) self.reporter.report_action("CONTRIBUTE_FOOD", data, FOOD_ENERGY[quality] * amount)
r = self._post_main_country_donate(**data) r = self._post_main_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
@ -1951,7 +2027,7 @@ class Citizen(CitizenAPI):
if self.details.cc < amount: if self.details.cc < amount:
return False return False
data = dict(country=71, action='gold', value=amount) data = dict(country=71, action='gold', value=amount)
self.reporter.report_action("CONTRIBUTE_GOLD", data) self.reporter.report_action("CONTRIBUTE_GOLD", data, str(amount))
r = self._post_main_country_donate(**data) r = self._post_main_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
@ -1966,19 +2042,19 @@ class Citizen(CitizenAPI):
process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False) process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False)
def get_battle_top_10(self, battle_id: int) -> Dict[int, List[Tuple[int, int]]]: def get_battle_top_10(self, battle_id: int) -> Dict[int, List[Tuple[int, int]]]:
battle = self.all_battles.get(battle_id) return {}
round_id = battle.get('zone_id') # battle = self.all_battles.get(battle_id)
division = self.division if round_id % 4 else 11 # round_id = battle.zone_id
# division = self.division if round_id % 4 else 11
resp = self._post_military_battle_console(battle_id, round_id, division).json() #
resp.pop('rounds', None) # resp = self._post_military_battle_console(battle_id, 'battleStatistics', round_id, division).json()
ret = dict() # resp.pop('rounds', None)
for country_id, data in resp.items(): # ret = dict()
ret.update({int(country_id): []}) # for country_id, data in resp.items():
for place in sorted(data.get("fighterData", {}).values(), key=lambda _: -_['raw_value']): # ret.update({int(country_id): []})
ret[int(country_id)].append((place['citizenId'], place['raw_value'])) # for place in sorted(data.get("fighterData", {}).values(), key=lambda _: -_['raw_value']):
# ret[int(country_id)].append((place['citizenId'], place['raw_value']))
return ret # return ret
def to_json(self, indent: bool = False) -> str: def to_json(self, indent: bool = False) -> str:
return dumps(self.__dict__, cls=MyJSONEncoder, indent=4 if indent else None, sort_keys=True) return dumps(self.__dict__, cls=MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
@ -2052,7 +2128,6 @@ class Citizen(CitizenAPI):
def set_default_weapon(self, battle_id: int) -> int: def set_default_weapon(self, battle_id: int) -> int:
battle = self.all_battles[battle_id] battle = self.all_battles[battle_id]
battle_zone = battle.div[11 if battle.is_air else self.division].battle_zone_id
available_weapons = self._get_military_show_weapons(battle_id).json() available_weapons = self._get_military_show_weapons(battle_id).json()
weapon_quality = -1 weapon_quality = -1
if not battle.is_air: if not battle.is_air:

View File

@ -40,7 +40,7 @@ class MyCompanies:
""" """
:param holdings: Parsed JSON to dict from en/economy/myCompanies :param holdings: Parsed JSON to dict from en/economy/myCompanies
""" """
self.holdings = {} self.holdings.clear()
template = dict(id=0, num_factories=0, region_id=0, companies=[]) template = dict(id=0, num_factories=0, region_id=0, companies=[])
for holding_id, holding in holdings.items(): for holding_id, holding in holdings.items():
@ -57,18 +57,20 @@ class MyCompanies:
""" """
:param companies: Parsed JSON to dict from en/economy/myCompanies :param companies: Parsed JSON to dict from en/economy/myCompanies
""" """
self.companies = {} self.companies.clear()
template = dict(id=None, quality=0, is_raw=False, resource_bonus=0, effective_bonus=0, raw_usage=0, template = dict(id=None, quality=0, is_raw=False, resource_bonus=0, effective_bonus=0, raw_usage=0,
production=0, base_production=0, wam_enabled=False, can_work_as_manager=False, base_production=0, wam_enabled=False, can_work_as_manager=False, industry_id=0, todays_works=0,
preset_own_work=0, already_worked=False, can_assign_employees=False, preset_works=0, preset_own_work=0, already_worked=False, can_assign_employees=False, preset_works=0,
todays_works=0, holding_company_id=None, is_assigned_to_holding=False, holding_company_id=None, is_assigned_to_holding=False, cannot_work_as_manager_reason=False)
cannot_work_as_manager_reason=False, industry_id=0)
for c_id, company in companies.items(): for c_id, company in companies.items():
tmp = {} tmp = {}
for key in template.keys(): for key in template.keys():
if key in ['id', 'holding_company_id']: if key in ['id', 'holding_company_id']:
company[key] = int(company[key]) company[key] = int(company[key])
elif key == "raw_usage":
if not company.get("is_raw") and company.get('upgrades'):
company[key] = company.get('upgrades').get(str(company["quality"])).get('raw_usage')
tmp.update({key: company[key]}) tmp.update({key: company[key]})
self.companies.update({int(c_id): tmp}) self.companies.update({int(c_id): tmp})
@ -76,9 +78,8 @@ class MyCompanies:
for company_id, company_data in self.companies.items(): for company_id, company_data in self.companies.items():
if company_id not in self.holdings[company_data['holding_company_id']]['companies']: if company_id not in self.holdings[company_data['holding_company_id']]['companies']:
self.holdings[company_data['holding_company_id']]['companies'].append(company_id) self.holdings[company_data['holding_company_id']]['companies'].append(company_id)
else: for holding_id in self.holdings:
for holding_id in self.holdings: self.holdings[holding_id]['companies'].sort()
self.holdings[holding_id]['companies'].sort()
def get_employable_factories(self) -> Dict[int, int]: def get_employable_factories(self) -> Dict[int, int]:
ret = {} ret = {}
@ -160,6 +161,31 @@ class MyCompanies:
raise ErepublikException("Wrong function call") raise ErepublikException("Wrong function call")
def get_wam_raw_usage(self) -> Dict[str, float]:
frm = 0.00
wrm = 0.00
for company in self.companies.values():
if company['wam_enabled']:
effective_bonus = float(company["effective_bonus"])
base_prod = float(company["base_production"])
raw = base_prod * effective_bonus / 100
if not company["is_raw"]:
raw *= -company["raw_usage"]
if company["industry_id"] in [1, 7, 8, 9, 10, 11]:
frm += raw
elif company["industry_id"] in [2, 12, 13, 14, 15, 16]:
wrm += raw
return {'frm': int(frm * 1000) / 1000, 'wrm': int(wrm * 1000) / 1000}
def __str__(self):
name = []
for holding_id in sorted(self.holdings.keys()):
if not holding_id:
name.append(f"Unassigned - {len(self.holdings[0]['companies'])}")
else:
name.append(f"{holding_id} - {len(self.holdings[holding_id]['companies'])}")
return " | ".join(name)
# @property # @property
# def __dict__(self): # def __dict__(self):
# ret = {} # ret = {}
@ -599,6 +625,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id) data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id)
return self.post("{}/main/battlefieldTravel".format(self.url), data=data) return self.post("{}/main/battlefieldTravel".format(self.url), data=data)
def _post_main_battlefield_change_division(self, battle_id: int, division_id: int) -> Response:
data = dict(_token=self.token, battleZoneId=division_id, battleId=battle_id)
return self.post("{}/main/battlefieldTravel".format(self.url), data=data)
def _post_main_buy_gold_items(self, currency: str, item: str, amount: int) -> Response: def _post_main_buy_gold_items(self, currency: str, item: str, amount: int) -> Response:
data = dict(itemId=item, currency=currency, amount=amount, _token=self.token) data = dict(itemId=item, currency=currency, amount=amount, _token=self.token)
return self.post("{}/main/buyGoldItems".format(self.url), data=data) return self.post("{}/main/buyGoldItems".format(self.url), data=data)
@ -796,11 +826,6 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data.update(page=page) data.update(page=page)
return self.post("{}/military/battle-console".format(self.url), data=data) return self.post("{}/military/battle-console".format(self.url), data=data)
def _post_military_change_weapon(self, battle_id: int, battle_zone_id: int, customization_level: int) -> Response:
data = dict(_token=self.token, battleZoneId=battle_zone_id, battleId=battle_id,
customizationLevel=customization_level)
return self.post("{}/military/change-weapon".format(self.url), data=data)
def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response: def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response:
data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token) data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token)
return self.post("{}/military/deploy-bomb".format(self.url), data=data) return self.post("{}/military/deploy-bomb".format(self.url), data=data)
@ -1102,22 +1127,42 @@ class Battle:
def is_air(self) -> bool: def is_air(self) -> bool:
return not bool(self.zone_id % 4) return not bool(self.zone_id % 4)
def __init__(self, battle: Dict[str, Any]): def __init__(self, battle: Dict[str, Any] = None):
self.id = int(battle.get('id', 0)) """Object representing eRepublik battle.
self.war_id = int(battle.get('war_id', 0))
self.zone_id = int(battle.get('zone_id', 0))
self.is_rw = bool(battle.get('is_rw'))
self.is_as = bool(battle.get('is_as'))
self.is_dict_lib = bool(battle.get('is_dict')) or bool(battle.get('is_lib'))
self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=utils.erep_tz)
self.invader = BattleSide(battle.get('inv', {}).get('id'), battle.get('inv', {}).get('points'), :param battle: Dict object for single battle from '/military/campaignsJson/list' response's 'battles' object
[row.get('id') for row in battle.get('inv', {}).get('ally_list')], """
[row.get('id') for row in battle.get('inv', {}).get('ally_list') if row['deployed']]) if battle is None:
battle = {}
self.id = 0
self.war_id = 0
self.zone_id = 0
self.is_rw = False
self.is_as = False
self.is_dict_lib = False
self.start = utils.now().min
self.invader = BattleSide(0, 0, [], [])
self.defender = BattleSide(0, 0, [], [])
else:
self.id = int(battle.get('id', 0))
self.war_id = int(battle.get('war_id', 0))
self.zone_id = int(battle.get('zone_id', 0))
self.is_rw = bool(battle.get('is_rw'))
self.is_as = bool(battle.get('is_as'))
self.is_dict_lib = bool(battle.get('is_dict')) or bool(battle.get('is_lib'))
self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=utils.erep_tz)
self.defender = BattleSide(battle.get('def', {}).get('id'), battle.get('def', {}).get('points'), self.invader = BattleSide(
[row.get('id') for row in battle.get('def', {}).get('ally_list')], battle.get('inv', {}).get('id'), battle.get('inv', {}).get('points'),
[row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']]) [row.get('id') for row in battle.get('inv', {}).get('ally_list')],
[row.get('id') for row in battle.get('inv', {}).get('ally_list') if row['deployed']]
)
self.defender = BattleSide(
battle.get('def', {}).get('id'), battle.get('def', {}).get('points'),
[row.get('id') for row in battle.get('def', {}).get('ally_list')],
[row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']]
)
self.div = {} self.div = {}
for div, data in battle.get('div', {}).items(): for div, data in battle.get('div', {}).items():

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.17.2 current_version = 0.18.1
commit = True commit = True
tag = True tag = True

View File

@ -42,6 +42,6 @@ setup(
test_suite='tests', test_suite='tests',
tests_require=test_requirements, tests_require=test_requirements,
url='https://github.com/eeriks/erepublik/', url='https://github.com/eeriks/erepublik/',
version='0.17.2', version='0.18.1',
zip_safe=False, zip_safe=False,
) )