diff --git a/erepublik/__init__.py b/erepublik/__init__.py
index 2e115d4..60730b3 100644
--- a/erepublik/__init__.py
+++ b/erepublik/__init__.py
@@ -5,9 +5,9 @@
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '0.20.3.5'
-__commit_id__ = "fc4295d"
+__commit_id__ = "81bd09e"
-from erepublik import classes, utils
+from erepublik import classes, utils, constants
from erepublik.citizen import Citizen
-__all__ = ["classes", "utils", "Citizen"]
+__all__ = ["classes", "utils", "Citizen", ]
diff --git a/erepublik/access_points.py b/erepublik/access_points.py
index 5769a2b..8efb42c 100644
--- a/erepublik/access_points.py
+++ b/erepublik/access_points.py
@@ -5,7 +5,7 @@ from typing import Any, Dict, List, Mapping, Union
from requests import Response, Session
-from erepublik import utils
+from . import constants, utils
__all__ = ['SlowRequests', 'CitizenAPI']
@@ -45,7 +45,7 @@ class SlowRequests(Session):
})
@property
- def __dict__(self):
+ def as_dict(self):
return dict(last_time=self.last_time, timeout=self.timeout, user_agent=self.headers['User-Agent'],
request_log_name=self.request_log_name, debug=self.debug)
@@ -461,13 +461,13 @@ class ErepublikPresidentAPI(CitizenBaseAPI):
def _post_new_war(self, self_country_id: int, attack_country_id: int, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate,
- countryNameConfirm=utils.COUNTRY_LINK[attack_country_id])
- return self.post("{}/{}/new-war".format(self.url, utils.COUNTRY_LINK[self_country_id]), data=data)
+ countryNameConfirm=constants.COUNTRIES[attack_country_id].link)
+ return self.post("{}/{}/new-war".format(self.url, constants.COUNTRIES[self_country_id].link), data=data)
def _post_new_donation(self, country_id: int, amount: int, org_name: str, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate, currency=1, value=amount, commit='Propose',
type_name=org_name)
- return self.post("{}/{}/new-donation".format(self.url, utils.COUNTRY_LINK[country_id]), data=data)
+ return self.post("{}/{}/new-donation".format(self.url, constants.COUNTRIES[country_id].link), data=data)
class ErepublikProfileAPI(CitizenBaseAPI):
diff --git a/erepublik/citizen.py b/erepublik/citizen.py
index 703d5bf..2eacbe1 100644
--- a/erepublik/citizen.py
+++ b/erepublik/citizen.py
@@ -10,16 +10,11 @@ from typing import Any, Callable, Dict, List, NoReturn, Optional, Set, Tuple, Un
from requests import HTTPError, RequestException, Response
-from erepublik import utils
-from erepublik.access_points import CitizenAPI
-from erepublik.classes import COUNTRIES, Battle, BattleDivision, Config, Country, Details, Energy, \
- ErepublikException, MyCompanies, MyJSONEncoder, OfferItem, Politics, Reporter, TelegramBot, Holding, BattleSide, \
- Company
-from erepublik.utils import erep_tz
+from . import utils, classes, access_points, constants
-class BaseCitizen(CitizenAPI):
- __last_full_update: datetime = utils.now().min
+class BaseCitizen(access_points.CitizenAPI):
+ _last_full_update: datetime = utils.now().min
promos: Dict[str, datetime] = None
inventory: Dict[str, int] = {'used': 0, 'total': 0}
@@ -34,13 +29,13 @@ class BaseCitizen(CitizenAPI):
eday = 0
- config: Config = None
- energy: Energy = None
- details: Details = None
- politics: Politics = None
- reporter: Reporter = None
+ config: classes.Config = None
+ energy: classes.Energy = None
+ details: classes.Details = None
+ politics: classes.Politics = None
+ reporter: classes.Reporter = None
stop_threads: Event = None
- telegram: TelegramBot = None
+ telegram: classes.TelegramBot = None
r: Response = None
name: str = "Not logged in!"
@@ -51,14 +46,14 @@ class BaseCitizen(CitizenAPI):
def __init__(self, email: str = "", password: str = ""):
super().__init__()
self.commit_id = utils.COMMIT_ID
- self.config = Config()
- self.energy = Energy()
- self.details = Details()
- self.politics = Politics()
- self.my_companies = MyCompanies(self)
- self.reporter = Reporter(self)
+ self.config = classes.Config()
+ self.energy = classes.Energy()
+ self.details = classes.Details()
+ self.politics = classes.Politics()
+ self.my_companies = classes.MyCompanies(self)
+ self.reporter = classes.Reporter(self)
self.stop_threads = Event()
- self.telegram = TelegramBot(stop_event=self.stop_threads)
+ self.telegram = classes.TelegramBot(stop_event=self.stop_threads)
self.config.email = email
self.config.password = password
@@ -85,7 +80,7 @@ class BaseCitizen(CitizenAPI):
self.token = re_login_token.group(1)
self._login()
else:
- raise ErepublikException("Something went wrong! Can't find token in page! Exiting!")
+ raise classes.ErepublikException("Something went wrong! Can't find token in page! Exiting!")
try:
self.update_citizen_info(resp.text)
except (AttributeError, utils.json.JSONDecodeError, ValueError, KeyError):
@@ -206,11 +201,12 @@ class BaseCitizen(CitizenAPI):
self.energy.recoverable = citizen.get("energyFromFoodRemaining", 0)
self.details.current_region = citizen.get("regionLocationId", 0)
- self.details.current_country = COUNTRIES.get(citizen.get("countryLocationId", 0)) # country where citizen is located
+ self.details.current_country = constants.COUNTRIES.get(
+ citizen.get("countryLocationId", 0)) # country where citizen is located
self.details.residence_region = citizen.get("residence", {}).get("regionId", 0)
- self.details.residence_country = COUNTRIES.get(citizen.get("residence", {}).get("countryId", 0))
+ self.details.residence_country = constants.COUNTRIES.get(citizen.get("residence", {}).get("countryId", 0))
self.details.citizen_id = citizen.get("citizenId", 0)
- self.details.citizenship = COUNTRIES.get(int(citizen.get("country", 0)))
+ self.details.citizenship = constants.COUNTRIES.get(int(citizen.get("country", 0)))
self.details.xp = citizen.get("currentExperiencePoints", 0)
self.details.daily_task_done = citizen.get("dailyTasksDone", False)
self.details.daily_task_reward = citizen.get("hasReward", False)
@@ -359,7 +355,7 @@ class BaseCitizen(CitizenAPI):
offers = {}
for offer in self._get_economy_my_market_offers().json():
- kind = self.get_industry_name(offer['industryId'])
+ kind = constants.INDUSTRIES[offer['industryId']]
data = dict(quality=offer.get('quality', 0), amount=offer.get('amount', 0), icon=offer.get('icon'),
kind=kind, name=kind)
data = {data['quality']: data}
@@ -373,7 +369,7 @@ class BaseCitizen(CitizenAPI):
"total": j.get("inventoryStatus").get("totalStorage")})
inventory = dict(items=dict(active=active_items, final=final_items,
raw=raw_materials, offers=offers), status=self.inventory)
- self.food["total"] = sum([self.food[q] * utils.FOOD_ENERGY[q] for q in utils.FOOD_ENERGY])
+ self.food["total"] = sum([self.food[q] * constants.FOOD_ENERGY[q] for q in constants.FOOD_ENERGY])
return inventory
def write_log(self, *args, **kwargs):
@@ -397,34 +393,14 @@ class BaseCitizen(CitizenAPI):
sleep(seconds)
def to_json(self, indent: bool = False) -> str:
- return utils.json.dumps(self.__dict__, cls=MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
+ return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
- def get_industry_id(self, industry_name: str) -> int:
- """Returns industry id
-
- :type industry_name: str
- :return: int
- """
- return self.available_industries.get(industry_name, 0)
-
- def get_industry_name(self, industry_id: int) -> str:
- """Returns industry name from industry ID
-
- :type industry_id: int
- :return: industry name
- :rtype: str
- """
- for industry_name, ind_id in self.available_industries.items():
- if ind_id == industry_id:
- return industry_name
- return ""
-
- def get_countries_with_regions(self) -> Set[Country]:
+ def get_countries_with_regions(self) -> Set[constants.Country]:
r_json = self._post_main_travel_data().json()
return_set = {*[]}
for country_data in r_json['countries'].values():
if country_data['currentRegions']:
- return_set.add(COUNTRIES[country_data['id']])
+ return_set.add(constants.COUNTRIES[country_data['id']])
return return_set
def __str__(self) -> str:
@@ -434,10 +410,16 @@ class BaseCitizen(CitizenAPI):
return self.__str__()
@property
- def __dict__(self):
- ret = super().__dict__.copy()
+ def as_dict(self):
+ ret = self.__dict__.copy()
ret.pop('stop_threads', None)
ret.pop('_CitizenMilitary__last_war_update_data', None)
+ ret.update(_properties=dict(
+ now=self.now, should_do_levelup=self.should_do_levelup, is_levelup_reachable=self.is_levelup_reachable,
+ max_time_till_full_ff=self.max_time_till_full_ff, is_levelup_close=self.is_levelup_close,
+ time_till_full_ff=self.time_till_full_ff, time_till_week_change=self.time_till_week_change,
+ next_wc_start=self.next_wc_start, next_reachable_energy=self.next_reachable_energy,
+ health_info=self.health_info))
return ret
@@ -510,27 +492,6 @@ class BaseCitizen(CitizenAPI):
can_do_max_amount_of_dmg = self.energy.recoverable + 2 * self.energy.interval >= self.energy.limit
return can_reach_next_level and can_do_max_amount_of_dmg
- @property
- def available_industries(self) -> Dict[str, int]:
- """
- Returns currently available industries as dict(name: id)
- :return: Dict[str, int]
- """
- return {"food": 1, "weapon": 2, "house": 4, "aircraft": 23,
- "foodRaw": 7, "weaponRaw": 12, "houseRaw": 17, "airplaneRaw": 24}
-
- @property
- def factories(self) -> Dict[int, str]:
- """Returns factory industries as dict(id: name)
- :return: Factory id:name dict
- :rtype: Dict[int, str]
- """
- 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", }
-
@property
def now(self) -> datetime:
"""
@@ -591,7 +552,7 @@ class BaseCitizen(CitizenAPI):
self.telegram.report_medal(f"Level *{level}*")
self.reporter.report_action("LEVEL_UP", value=level)
- def _travel(self, country: Country, region_id: int = 0) -> Response:
+ def _travel(self, country: constants.Country, region_id: int = 0) -> Response:
data = {
"toCountryId": country.id,
"inRegionId": region_id,
@@ -662,7 +623,7 @@ class BaseCitizen(CitizenAPI):
self.write_log("eRepublik servers are having internal troubles. Sleeping for 5 minutes")
self.sleep(5 * 60)
else:
- raise ErepublikException(f"HTTP {response.status_code} error!")
+ raise classes.ErepublikException(f"HTTP {response.status_code} error!")
return bool(re.search(r'body id="error"|Internal Server Error|'
r'CSRF attack detected|meta http-equiv="refresh"|not_authenticated', response.text))
@@ -676,7 +637,7 @@ class BaseCitizen(CitizenAPI):
:param msg: Message about the action
:param kwargs: Extra information regarding action
"""
- kwargs = utils.json.loads(utils.json.dumps(kwargs or {}, cls=MyJSONEncoder))
+ kwargs = utils.json.loads(utils.json.dumps(kwargs or {}, cls=classes.MyJSONEncoder))
action = action[:32]
self.write_log(msg)
if self.reporter.allowed:
@@ -730,11 +691,11 @@ class CitizenAnniversary(BaseCitizen):
class CitizenTravel(BaseCitizen):
- def _update_citizen_location(self, country: Country, region_id: int):
+ def _update_citizen_location(self, country: constants.Country, region_id: int):
self.details.current_region = region_id
self.details.current_country = country
- def get_country_travel_region(self, country: Country) -> int:
+ def get_country_travel_region(self, country: constants.Country) -> int:
regions = self.get_travel_regions(country=country)
regs = []
if regions:
@@ -763,7 +724,7 @@ class CitizenTravel(BaseCitizen):
if data.get('alreadyInRegion'):
return True
else:
- country = COUNTRIES[data.get('preselectCountryId')]
+ country = constants.COUNTRIES[data.get('preselectCountryId')]
r_json = self._travel(country, region_id).json()
if r_json.get('message', '') == 'success':
self._update_citizen_location(country, region_id)
@@ -771,7 +732,7 @@ class CitizenTravel(BaseCitizen):
return True
return False
- def travel_to_country(self, country: Country) -> bool:
+ def travel_to_country(self, country: constants.Country) -> bool:
data = self._post_main_travel_data(countryId=country.id, check="getCountryRegions").json()
regs = []
@@ -788,12 +749,12 @@ class CitizenTravel(BaseCitizen):
return True
return False
- def travel_to_holding(self, holding: Holding) -> bool:
+ def travel_to_holding(self, holding: classes.Holding) -> bool:
data = self._post_main_travel_data(holdingId=holding.id).json()
if data.get('alreadyInRegion'):
return True
else:
- country = COUNTRIES[data.get('preselectCountryId')]
+ country = constants.COUNTRIES[data.get('preselectCountryId')]
region_id = data.get('preselectRegionId')
r_json = self._travel(country, region_id).json()
if r_json.get('message', '') == 'success':
@@ -802,7 +763,7 @@ class CitizenTravel(BaseCitizen):
return True
return False
- def get_travel_regions(self, holding: Holding = None, battle: Battle = None, country: Country = None
+ def get_travel_regions(self, holding: classes.Holding = None, battle: classes.Battle = None, country: constants.Country = None
) -> Union[List[Any], Dict[str, Dict[str, Any]]]:
return self._post_main_travel_data(
holdingId=holding.id if holding else 0,
@@ -810,7 +771,7 @@ class CitizenTravel(BaseCitizen):
countryId=country.id if country else 0
).json().get('regions', [])
- def get_travel_countries(self) -> Set[Country]:
+ def get_travel_countries(self) -> Set[constants.Country]:
warnings.simplefilter('always')
warnings.warn('CitizenTravel.get_travel_countries() are being deprecated, '
'please use BaseCitizen.get_countries_with_regions()', DeprecationWarning)
@@ -833,10 +794,10 @@ class CitizenCompanies(BaseCitizen):
return ret
- def work_as_manager_in_holding(self, holding: Holding) -> Optional[Dict[str, Any]]:
+ def work_as_manager_in_holding(self, holding: classes.Holding) -> Optional[Dict[str, Any]]:
return self._work_as_manager(holding)
- def _work_as_manager(self, wam_holding: Holding = None) -> Optional[Dict[str, Any]]:
+ def _work_as_manager(self, wam_holding: classes.Holding = None) -> Optional[Dict[str, Any]]:
if self.restricted_ip:
return None
self.update_companies()
@@ -879,7 +840,7 @@ class CitizenCompanies(BaseCitizen):
self.my_companies.prepare_holdings(utils.json.loads(have_holdings.group(1)))
self.my_companies.prepare_companies(utils.json.loads(have_companies.group(1)))
- def assign_company_to_holding(self, company: Company, holding: Holding) -> Response:
+ def assign_company_to_holding(self, company: classes.Company, holding: classes.Holding) -> Response:
"""
Assigns factory to new holding
"""
@@ -1019,7 +980,7 @@ class CitizenEconomy(CitizenTravel):
return ret
def post_market_offer(self, industry: int, quality: int, amount: int, price: float) -> Response:
- if industry not in self.available_industries.values():
+ if not constants.INDUSTRIES[industry]:
self.write_log(f"Trying to sell unsupported industry {industry}")
data = {
@@ -1032,7 +993,7 @@ class CitizenEconomy(CitizenTravel):
}
ret = self._post_economy_marketplace_actions(**data)
message = (f"Posted market offer for {amount}q{quality} "
- f"{self.get_industry_name(industry)} for price {price}cc")
+ f"{constants.INDUSTRIES[industry]} for price {price}cc")
self._report_action("ECONOMY_SELL_PRODUCTS", message, kwargs=ret.json())
return ret
@@ -1048,43 +1009,46 @@ class CitizenEconomy(CitizenTravel):
self._report_action("BOUGHT_PRODUCTS", "", kwargs=json_ret)
return json_ret
- def get_market_offers(self, product_name: str, quality: int = None, country: Country = None) -> Dict[str, OfferItem]:
+ def get_market_offers(
+ self, product_name: str, quality: int = None, country: constants.Country = None
+ ) -> Dict[str, classes.OfferItem]:
raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw")
q1_industries = ["aircraft"] + list(raw_short_names.values())
- if product_name not in self.available_industries and product_name not in raw_short_names:
- self.write_log(f"Industry '{product_name}' not implemented")
- raise ErepublikException(f"Industry '{product_name}' not implemented")
- elif product_name in raw_short_names:
+ if product_name in raw_short_names:
quality = 1
product_name = raw_short_names[product_name]
+ elif not constants.INDUSTRIES[product_name]:
+ self.write_log(f"Industry '{product_name}' not implemented")
+ raise classes.ErepublikException(f"Industry '{product_name}' not implemented")
- offers: Dict[str, OfferItem] = {}
+ offers: Dict[str, classes.OfferItem] = {}
max_quality = 0
if quality:
- offers[f"q{quality}"] = OfferItem()
+ offers[f"q{quality}"] = classes.OfferItem()
else:
max_quality = 1 if product_name in q1_industries else 5 if product_name == 'house' else 7
for q in range(max_quality):
- offers[f"q{q + 1}"] = OfferItem()
+ offers[f"q{q + 1}"] = classes.OfferItem()
if country:
- countries: Set[Country] = {country}
+ countries: Set[constants.Country] = {country}
else:
- countries: Set[Country] = self.get_countries_with_regions()
+ countries: Set[constants.Country] = self.get_countries_with_regions()
start_dt = self.now
iterable = [countries, [quality] if quality else range(1, max_quality + 1)]
for country, q in product(*iterable):
- r = self._post_economy_marketplace(country, self.available_industries[product_name], q).json()
+ r = self._post_economy_marketplace(country, constants.INDUSTRIES[product_name], q).json()
obj = offers[f"q{q}"]
if not r.get("error", False):
for offer in r["offers"]:
if (obj.price > float(offer["priceWithTaxes"]) or (
obj.price == float(offer["priceWithTaxes"]) and obj.amount < int(offer["amount"])
)):
- offers[f"q{q}"] = obj = OfferItem(
- float(offer["priceWithTaxes"]), COUNTRIES[int(offer["country_id"])], int(offer["amount"]),
+ offers[f"q{q}"] = obj = classes.OfferItem(
+ float(offer["priceWithTaxes"]),
+ constants.COUNTRIES[int(offer["country_id"])], int(offer["amount"]),
int(offer["id"]), int(offer["citizen_id"])
)
self.write_log(f"Scraped market in {self.now - start_dt}!")
@@ -1095,16 +1059,17 @@ class CitizenEconomy(CitizenTravel):
hp_needed = energy_amount if energy_amount else 48 * self.energy.interval * 10 - self.food["total"]
local_offers = self.get_market_offers("food", country=self.details.current_country)
- cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1].price / utils.FOOD_ENERGY[v[0]])[0]
+ cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1].price / constants.FOOD_ENERGY[v[0]])[0]
- if cheapest.amount * utils.FOOD_ENERGY[cheapest_q] < hp_needed:
+ if cheapest.amount * constants.FOOD_ENERGY[cheapest_q] < hp_needed:
amount = cheapest.amount
else:
- amount = hp_needed // utils.FOOD_ENERGY[cheapest_q]
+ amount = hp_needed // constants.FOOD_ENERGY[cheapest_q]
if amount * cheapest.price < self.details.cc:
data = dict(offer=cheapest.offer_id, amount=amount, price=cheapest.price,
- cost=amount * cheapest.price, quality=cheapest_q, energy=amount * utils.FOOD_ENERGY[cheapest_q])
+ cost=amount * cheapest.price, quality=cheapest_q,
+ energy=amount * constants.FOOD_ENERGY[cheapest_q])
self._report_action("BUY_FOOD", "", kwargs=data)
self.buy_from_market(cheapest.offer_id, amount)
self.update_inventory()
@@ -1166,11 +1131,11 @@ class CitizenEconomy(CitizenTravel):
def donate_items(self, citizen_id: int = 1620414, amount: int = 0, industry_id: int = 1, quality: int = 1) -> int:
if amount < 1:
return 0
- ind = {v: k for k, v in self.available_industries.items()}
- self.write_log(f"Donate: {amount:4d}q{quality} {ind[industry_id]} to {citizen_id}")
+ industry = constants.INDUSTRIES[industry_id]
+ self.write_log(f"Donate: {amount:4d}q{quality} {industry} to {citizen_id}")
response = self._post_economy_donate_items_action(citizen_id, amount, industry_id, quality)
if re.search(rf"Successfully transferred {amount} item\(s\) to", response.text):
- msg = (f"Successfully donated {amount}q{quality} {self.get_industry_name(industry_id)} "
+ msg = (f"Successfully donated {amount}q{quality} {industry} "
f"to citizen with id {citizen_id}!")
self._report_action("DONATE_ITEMS", msg)
return amount
@@ -1182,19 +1147,19 @@ class CitizenEconomy(CitizenTravel):
if re.search(r'You do not have enough items in your inventory to make this donation', response.text):
self._report_action("DONATE_ITEMS",
f"Unable to donate {amount}q{quality} "
- f"{self.get_industry_name(industry_id)}, not enough left!")
+ f"{industry}, not enough left!")
return 0
available = re.search(
r'Cannot transfer the items because the user has only (\d+) free slots in (his|her) storage.',
response.text
).group(1)
self._report_action('DONATE_ITEMS',
- f'Unable to donate {amount}q{quality}{self.get_industry_name(industry_id)}'
+ f'Unable to donate {amount}q{quality}{industry}'
f', receiver has only {available} storage left!')
self.sleep(5)
return self.donate_items(citizen_id, int(available), industry_id, quality)
- def contribute_cc_to_country(self, amount, country: Country) -> bool:
+ def contribute_cc_to_country(self, amount, country: constants.Country) -> bool:
self.update_money()
amount = int(amount)
if self.details.cc < amount or amount < 20:
@@ -1209,7 +1174,7 @@ class CitizenEconomy(CitizenTravel):
f" treasury", kwargs=r.json())
return False
- def contribute_food_to_country(self, amount, quality, country: Country) -> bool:
+ def contribute_food_to_country(self, amount, quality, country: constants.Country) -> bool:
self.update_inventory()
amount = amount // 1
if self.food["q" + str(quality)] < amount or amount < 10:
@@ -1226,7 +1191,7 @@ class CitizenEconomy(CitizenTravel):
f"{country}'s treasury", kwargs=r.json())
return False
- def contribute_gold_to_country(self, amount: int, country: Country) -> bool:
+ def contribute_gold_to_country(self, amount: int, country: constants.Country) -> bool:
self.update_money()
if self.details.cc < amount:
@@ -1304,13 +1269,13 @@ class CitizenMedia(BaseCitizen):
article_id = 0
return article_id
else:
- raise ErepublikException("Article kind must be one of:\n{}\n'{}' is not supported".format(
+ raise classes.ErepublikException("Article kind must be one of:\n{}\n'{}' is not supported".format(
"\n".join(["{}: {}".format(k, v) for k, v in kinds.items()]), kind
))
class CitizenMilitary(CitizenTravel):
- all_battles: Dict[int, Battle] = None
+ all_battles: Dict[int, classes.Battle] = None
countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
__last_war_update_data = None
@@ -1344,10 +1309,10 @@ class CitizenMilitary(CitizenTravel):
if r_json.get("battles"):
all_battles = {}
for battle_data in r_json.get("battles", {}).values():
- all_battles[battle_data.get('id')] = Battle(battle_data)
+ all_battles[battle_data.get('id')] = classes.Battle(battle_data)
self.all_battles = all_battles
- def get_battle_for_war(self, war_id: int) -> Optional[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)
@@ -1375,7 +1340,7 @@ class CitizenMilitary(CitizenTravel):
def get_available_weapons(self, battle_id: int):
return self._get_military_show_weapons(battle_id).json()
- def set_default_weapon(self, battle: Battle, division: BattleDivision) -> int:
+ 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()
@@ -1390,7 +1355,7 @@ class CitizenMilitary(CitizenTravel):
pass
return self.change_weapon(battle, weapon_quality, division)
- def change_weapon(self, battle: Battle, quality: int, battle_zone: BattleDivision) -> int:
+ 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,"
@@ -1442,19 +1407,19 @@ class CitizenMilitary(CitizenTravel):
#
# self.active_fs = active_fs
- def sorted_battles(self, sort_by_time: bool = True, only_tp=False) -> List[Battle]:
- cs_battles_priority_air: List[Battle] = []
- cs_battles_priority_ground: List[Battle] = []
- cs_battles_air: List[Battle] = []
- cs_battles_ground: List[Battle] = []
- deployed_battles_air: List[Battle] = []
- deployed_battles_ground: List[Battle] = []
- ally_battles_air: List[Battle] = []
- ally_battles_ground: List[Battle] = []
- other_battles_air: List[Battle] = []
- other_battles_ground: List[Battle] = []
+ 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[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()
@@ -1520,20 +1485,22 @@ class CitizenMilitary(CitizenTravel):
ret_battles = ret_battles + cs_battles + deployed_battles + other_battles
return ret_battles
- def get_cheap_tp_divisions(self) -> Optional[BattleDivision]:
- air_divs: List[Tuple[BattleDivision, int]] = []
- ground_divs: List[Tuple[BattleDivision, int]] = []
+ def get_cheap_tp_divisions(self) -> Optional[classes.BattleDivision]:
+ air_divs: List[Tuple[classes.BattleDivision, int]] = []
+ ground_divs: List[Tuple[classes.BattleDivision, int]] = []
for battle in reversed(self.sorted_battles(True, True)):
for division in battle.div.values():
if not division.terrain:
if division.is_air:
- medal = self.get_battle_round_data(division)[self.details.citizenship == division.battle.defender.id]
+ medal = self.get_battle_round_data(division)[
+ self.details.citizenship == division.battle.defender.id]
if not medal and division.battle.start:
return division
else:
air_divs.append((division, medal.get('1').get('raw_value')))
else:
- medal = self.get_battle_round_data(division)[self.details.citizenship == division.battle.defender.id]
+ medal = self.get_battle_round_data(division)[
+ self.details.citizenship == division.battle.defender.id]
if not medal and division.battle.start:
return division
else:
@@ -1554,9 +1521,9 @@ class CitizenMilitary(CitizenTravel):
if self.should_fight()[0]:
self.write_log("Checking for battles to fight in...")
for battle in self.sorted_battles(self.config.sort_battles_time):
- if not isinstance(battle, Battle):
+ if not isinstance(battle, classes.Battle):
continue
- battle_zone: Optional[BattleDivision] = None
+ battle_zone: Optional[classes.BattleDivision] = None
for div in battle.div.values():
if div.terrain == 0:
if div.div_end:
@@ -1571,7 +1538,8 @@ class CitizenMilitary(CitizenTravel):
continue
if not battle_zone:
continue
- allies = battle.invader.deployed + battle.defender.deployed + [battle.invader.country, battle.defender.country]
+ allies = battle.invader.deployed + battle.defender.deployed + [battle.invader.country,
+ battle.defender.country]
travel_needed = self.details.current_country not in allies
@@ -1610,7 +1578,7 @@ class CitizenMilitary(CitizenTravel):
self.travel_to_residence()
break
- def fight(self, battle: Battle, division: BattleDivision, side: BattleSide = None, count: int = None) -> int:
+ def fight(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None, count: int = None) -> int:
"""Fight in a battle.
Will auto activate booster and travel if allowed to do it.
@@ -1632,7 +1600,8 @@ class CitizenMilitary(CitizenTravel):
if not division.is_air and self.config.boosters:
self.activate_dmg_booster()
if side is None:
- side = battle.defender if self.details.citizenship in battle.defender.allies + [battle.defender.country] else battle.invader
+ side = battle.defender if self.details.citizenship in battle.defender.allies + [
+ battle.defender.country] else battle.invader
error_count = 0
ok_to_fight = True
if count is None:
@@ -1657,7 +1626,7 @@ class CitizenMilitary(CitizenTravel):
air=battle.has_air, hits=total_hits))
return error_count
- def _shoot(self, battle: Battle, division: BattleDivision, side: BattleSide):
+ 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:
@@ -1679,7 +1648,8 @@ class CitizenMilitary(CitizenTravel):
elif r_json.get("message") == "NOT_ENOUGH_WEAPONS":
self.set_default_weapon(battle, division)
elif r_json.get("message") == "FIGHT_DISABLED":
- self._post_main_profile_update('options', params='{"optionName":"enable_web_deploy","optionValue":"off"}')
+ 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":
@@ -1698,7 +1668,7 @@ class CitizenMilitary(CitizenTravel):
return hits, err, damage
- def deploy_bomb(self, battle: Battle, bomb_id: int, inv_side: bool = None, count: int = 1) -> int:
+ def deploy_bomb(self, battle: classes.Battle, bomb_id: int, inv_side: bool = None, count: int = 1) -> int:
"""Deploy bombs in a battle for given side.
:param battle: Battle
@@ -1724,7 +1694,8 @@ class CitizenMilitary(CitizenTravel):
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
+ involved = [battle.invader.country,
+ battle.defender.country] + battle.invader.deployed + battle.defender.deployed
if self.details.current_country not in involved:
count = 0
errors = deployed_count = 0
@@ -1743,7 +1714,7 @@ class CitizenMilitary(CitizenTravel):
self._report_action("MILITARY_BOMB", f"Deployed {deployed_count} bombs in battle {battle.id}")
return deployed_count
- def change_division(self, battle: Battle, division: BattleDivision):
+ def change_division(self, battle: classes.Battle, division: classes.BattleDivision):
"""Change division.
:param battle: Battle
@@ -1790,7 +1761,7 @@ class CitizenMilitary(CitizenTravel):
duration = length
break
if duration:
- self._report_action("MILITARY_BOOSTER", f"Activated 50% {duration/60}h damage booster")
+ self._report_action("MILITARY_BOOSTER", f"Activated 50% {duration / 60}h damage booster")
self._post_economy_activate_booster(5, duration, "damage")
def get_active_ground_damage_booster(self):
@@ -1810,7 +1781,7 @@ class CitizenMilitary(CitizenTravel):
self._report_action('MILITARY_BOOSTER', 'Activated PrestigePoint booster')
return self._post_military_fight_activate_booster(battle_id, 1, 180, "prestige_points")
- def _rw_choose_side(self, battle: Battle, side: BattleSide) -> Response:
+ 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:
@@ -1884,7 +1855,7 @@ class CitizenMilitary(CitizenTravel):
return (count if count > 0 else 0), msg, force_fight
- def get_battle_round_data(self, division: BattleDivision) -> Tuple[Any, Any]:
+ def get_battle_round_data(self, division: classes.BattleDivision) -> Tuple[Any, Any]:
battle = division.battle
data = dict(zoneId=battle.zone_id, round_id=battle.zone_id, division=division.div,
@@ -1900,7 +1871,7 @@ class CitizenMilitary(CitizenTravel):
self.get_csrf_token()
self.launch_attack(war_id, region_id, region_name)
- def get_active_wars(self, country: Country = None) -> List[int]:
+ 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]
@@ -1917,11 +1888,11 @@ class CitizenMilitary(CitizenTravel):
self._post_wars_attack_region(war_id, region_id, region_name)
self._report_action("MILITARY_QUEUE_ATTACK", f"Battle for *{region_name}* queued")
- def travel_to_battle(self, battle: Battle, allowed_countries: List[Country]) -> bool:
+ def travel_to_battle(self, battle: classes.Battle, allowed_countries: List[constants.Country]) -> bool:
data = self.get_travel_regions(battle=battle)
regs = []
- countries: Dict[int, Country] = {c.id: c for c in allowed_countries}
+ countries: Dict[int, constants.Country] = {c.id: c for c in allowed_countries}
if data:
for region in data.values():
if region['countryId'] in countries: # Is not occupied by other country
@@ -1936,7 +1907,7 @@ class CitizenMilitary(CitizenTravel):
return True
return False
- def get_country_mus(self, country: Country) -> Dict[int, str]:
+ 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"]:
@@ -1974,7 +1945,7 @@ class CitizenMilitary(CitizenTravel):
class CitizenPolitics(BaseCitizen):
- def get_country_parties(self, country: Country = None) -> dict:
+ 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)
ret = {}
for name, id_ in re.findall(r'', r.text):
@@ -1989,13 +1960,15 @@ class CitizenPolitics(BaseCitizen):
self._report_action('POLITIC_PARTY_PRESIDENT', 'Applied for party president elections')
return self._get_candidate_party(self.politics.party_slug)
- def get_country_president_election_result(self, country: Country, year: int, month: int) -> Dict[str, int]:
- timestamp = int(erep_tz.localize(datetime(year, month, 5)).timestamp())
+ def get_country_president_election_result(self, country: constants.Country, year: int, month: int) -> Dict[str, int]:
+ timestamp = int(constants.erep_tz.localize(datetime(year, month, 5)).timestamp())
resp = self._get_presidential_elections(country.id, timestamp)
candidates = re.findall(r'class="candidate_info">(.*?)', resp.text, re.S | re.M)
ret = {}
for candidate in candidates:
- name = re.search(r'', candidate)
+ name = re.search(
+ r'',
+ candidate)
name = name.group(1)
votes = re.search(r'(\d+) votes', candidate).group(1)
ret.update({name: int(votes)})
@@ -2251,7 +2224,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
def __init__(self, email: str = "", password: str = "", auto_login: bool = True):
super().__init__(email, password)
- self.__last_full_update = utils.good_timedelta(self.now, - timedelta(minutes=5))
+ self._last_full_update = utils.good_timedelta(self.now, - timedelta(minutes=5))
self.set_debug(True)
if auto_login:
self.login()
@@ -2276,7 +2249,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
"" if self.config.telegram_chat_id or self.config.telegram_token else self.name)
self.telegram.send_message(f"*Started* {utils.now():%F %T}")
- self.__last_full_update = utils.good_timedelta(self.now, - timedelta(minutes=5))
+ self._last_full_update = utils.good_timedelta(self.now, - timedelta(minutes=5))
self.update_all(True)
def update_citizen_info(self, html: str = None):
@@ -2351,10 +2324,10 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
def update_all(self, force_update=False):
# Do full update max every 5 min
- if utils.good_timedelta(self.__last_full_update, timedelta(minutes=5)) > self.now and not force_update:
+ if utils.good_timedelta(self._last_full_update, timedelta(minutes=5)) > self.now and not force_update:
return
else:
- self.__last_full_update = self.now
+ self._last_full_update = self.now
self.update_citizen_info()
self.update_war_info()
self.update_inventory()
@@ -2467,7 +2440,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
if not amount:
inv_resp = self._get_economy_inventory_items().json()
category = "rawMaterials" if kind.endswith("Raw") else "finalProducts"
- item = "{}_{}".format(self.available_industries[kind], quality)
+ item = "{}_{}".format(constants.INDUSTRIES[kind], quality)
amount = inv_resp.get("inventoryItems").get(category).get("items").get(item).get("amount", 0)
if amount >= 1:
@@ -2478,10 +2451,10 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
else:
price = lowest_price.price - 0.01
- self.post_market_offer(industry=self.available_industries[kind], amount=int(amount),
+ self.post_market_offer(industry=constants.INDUSTRIES[kind], amount=int(amount),
quality=int(quality), price=price)
- def _wam(self, holding: Holding) -> NoReturn:
+ def _wam(self, holding: classes.Holding) -> NoReturn:
response = self.work_as_manager_in_holding(holding)
if response is None:
return
@@ -2496,7 +2469,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
elif kind.endswith("Raw"):
self.sell_produced_product(kind, 1)
else:
- raise ErepublikException("Unknown kind produced '{kind}'".format(kind=kind))
+ raise classes.ErepublikException("Unknown kind produced '{kind}'".format(kind=kind))
elif self.config.auto_buy_raw and re.search(r"not_enough_[^_]*_raw", response.get("message")):
raw_kind = re.search(r"not_enough_(\w+)_raw", response.get("message"))
if raw_kind:
@@ -2542,7 +2515,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
self.update_companies()
# Prevent messing up levelup with wam
if not (self.is_levelup_close and self.config.fight) or self.config.force_wam:
- regions: Dict[int, Holding] = {}
+ regions: Dict[int, classes.Holding] = {}
for holding in self.my_companies.holdings.values():
if holding.wam_count:
regions.update({holding.region: holding})
@@ -2570,8 +2543,8 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
self.update_companies()
return bool(self.my_companies.get_total_wam_count())
- def sorted_battles(self, sort_by_time: bool = True, only_tp=False) -> List[Battle]:
- battles: List[Battle] = self.reporter.fetch_battle_priorities(self.details.current_country)
+ def sorted_battles(self, sort_by_time: bool = True, only_tp=False) -> List[classes.Battle]:
+ battles: List[classes.Battle] = self.reporter.fetch_battle_priorities(self.details.current_country)
return battles + super().sorted_battles(sort_by_time, only_tp)
def command_central(self):
diff --git a/erepublik/classes.py b/erepublik/classes.py
index b98766d..e0afc02 100644
--- a/erepublik/classes.py
+++ b/erepublik/classes.py
@@ -6,52 +6,10 @@ from typing import Any, Dict, List, NamedTuple, Optional, Tuple, Union
from requests import Response, Session, post
-from erepublik import utils
-from erepublik.utils import json
+from . import utils, constants
-INDUSTRIES = {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", }
-
-
-class Country:
- id: int
- name: str
- link: str
- iso: str
-
- def __init__(self, country_id: int, name: str, link: str, iso: str):
- self.id = country_id
- self.name = name
- self.link = link
- self.iso = iso
-
- def __repr__(self):
- return f"Country({self.id}, '{self.name}', '{self.link}', '{self.iso}')"
-
- def __str__(self):
- return f"#{self.id} {self.name}"
-
- def __format__(self, format_spec):
- return self.iso
-
- def __int__(self):
- return self.id
-
- def __eq__(self, other):
- if isinstance(other, (int, float)):
- return self.id == int(other)
- else:
- try:
- return self.id == int(other)
- except ValueError:
- return self == other
-
- @property
- def __dict__(self):
- return dict(id=self.id, name=self.name, iso=self.iso)
+__all__ = ['Battle', 'BattleDivision', 'BattleSide', 'Company', 'Config', 'Details', 'Energy', 'ErepublikException',
+ 'Holding', 'MyCompanies', 'MyJSONEncoder', 'OfferItem', 'Politics', 'Reporter', 'TelegramBot']
class ErepublikException(Exception):
@@ -132,7 +90,7 @@ class Holding:
return str(self)
@property
- def __dict__(self):
+ def as_dict(self):
return dict(name=str(self), id=self.id, region=self.region, companies=self.companies, wam_count=self.wam_count)
@@ -229,7 +187,7 @@ class Company:
return self._sort_keys != other._sort_keys
def __str__(self):
- name = f"(#{self.id:>9d}) {INDUSTRIES[self.industry]}"
+ name = f"(#{self.id:>9d}) {constants.INDUSTRIES[self.industry]}"
if not self.is_raw:
name += f" q{self.quality}"
return name
@@ -238,7 +196,7 @@ class Company:
return str(self)
@property
- def __dict__(self):
+ def as_dict(self):
return dict(name=str(self), holding=self.holding.id, id=self.id, quality=self.quality, is_raw=self.is_raw,
raw_usage=self.raw_usage, products_made=self.products_made, wam_enabled=self.wam_enabled,
can_wam=self.can_wam, cannot_wam_reason=self.cannot_wam_reason, industry=self.industry,
@@ -328,7 +286,7 @@ class MyCompanies:
self.companies.clear()
@property
- def __dict__(self):
+ def as_dict(self):
return dict(name=str(self), work_units=self.work_units, next_ot_time=self.next_ot_time,
ff_lockdown=self.ff_lockdown, holdings=self.holdings, company_count=len(self.companies))
@@ -397,7 +355,7 @@ class Config:
self.telegram_token = ""
@property
- def __dict__(self):
+ def as_dict(self):
return dict(email=self.email, work=self.work, train=self.train, wam=self.wam, ot=self.ot,
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,
@@ -453,6 +411,13 @@ class Energy:
def available(self):
return self.recovered + self.recoverable
+ @property
+ def as_dict(self):
+ return dict(limit=self.limit, interval=self.interval, recoverable=self.recoverable, recovered=self.recovered,
+ reference_time=self.reference_time, food_fights=self.food_fights,
+ is_recoverable_full=self.is_recoverable_full, is_recovered_full=self.is_recovered_full,
+ is_energy_full=self.is_energy_full, available=self.available)
+
class Details:
xp = 0
@@ -462,11 +427,11 @@ class Details:
gold = 0
next_pp: List[int] = None
citizen_id = 0
- citizenship: Country
+ citizenship: constants.Country
current_region = 0
- current_country: Country
+ current_country: constants.Country
residence_region = 0
- residence_country: Country
+ residence_country: constants.Country
daily_task_done = False
daily_task_reward = False
mayhem_skills = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, }
@@ -500,6 +465,15 @@ class Details:
next_level_up = (1 + (self.xp // 10)) * 10
return next_level_up - self.xp
+ @property
+ def as_dict(self):
+ return dict(xp=self.xp, cc=self.cc, pp=self.pp, pin=self.pin, gold=self.gold, next_pp=self.next_pp,
+ citizen_id=self.citizen_id, citizenship=self.citizenship, current_region=self.current_region,
+ current_country=self.current_country, residence_region=self.residence_region,
+ residence_country=self.residence_country, daily_task_done=self.daily_task_done,
+ daily_task_reward=self.daily_task_reward, mayhem_skills=self.mayhem_skills,
+ xp_till_level_up=self.xp_till_level_up)
+
class Politics:
is_party_member: bool = False
@@ -510,6 +484,12 @@ class Politics:
is_congressman: bool = False
is_country_president: bool = False
+ @property
+ def as_dict(self):
+ return dict(is_party_member=self.is_party_member, party_id=self.party_id, party_slug=self.party_slug,
+ is_party_president=self.is_party_president, is_congressman=self.is_congressman,
+ is_country_president=self.is_country_president)
+
class House:
quality = None
@@ -543,7 +523,7 @@ class Reporter:
return self.citizen.details.citizen_id
@property
- def __dict__(self):
+ def as_dict(self):
return dict(name=self.name, email=self.email, citizen_id=self.citizen_id, key=self.key, allowed=self.allowed,
queue=self.__to_update)
@@ -614,7 +594,7 @@ class Reporter:
def report_promo(self, kind: str, time_until: datetime.datetime):
self._req.post(f"{self.url}/promos/add/", data=dict(kind=kind, time_untill=time_until))
- def fetch_battle_priorities(self, country: Country) -> List["Battle"]:
+ def fetch_battle_priorities(self, country: constants.Country) -> List["Battle"]:
try:
battle_response = self._req.get(f'{self.url}/api/v1/battles/{country.id}')
return [self.citizen.all_battles[bid] for bid in battle_response.json().get('battle_ids', []) if
@@ -631,7 +611,7 @@ class Reporter:
return
-class MyJSONEncoder(json.JSONEncoder):
+class MyJSONEncoder(utils.json.JSONEncoder):
def default(self, o):
from erepublik.citizen import Citizen
if isinstance(o, Decimal):
@@ -646,8 +626,8 @@ class MyJSONEncoder(json.JSONEncoder):
microseconds=o.microseconds, total_seconds=o.total_seconds())
elif isinstance(o, Response):
return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
- elif hasattr(o, '__dict__'):
- return o.__dict__
+ elif hasattr(o, 'as_dict'):
+ return o.as_dict
elif isinstance(o, set):
return list(o)
elif isinstance(o, Citizen):
@@ -660,14 +640,14 @@ class MyJSONEncoder(json.JSONEncoder):
class BattleSide:
points: int
- deployed: List[Country]
- allies: List[Country]
+ deployed: List[constants.Country]
+ allies: List[constants.Country]
battle: "Battle"
- country: Country
+ country: constants.Country
defender: bool
- def __init__(self, battle: "Battle", country: Country, points: int, allies: List[Country], deployed: List[Country],
- defender: bool):
+ def __init__(self, battle: "Battle", country: constants.Country, points: int, allies: List[constants.Country],
+ deployed: List[constants.Country], defender: bool):
self.battle = battle
self.country = country
self.points = points
@@ -691,7 +671,7 @@ class BattleSide:
return self.country.iso
@property
- def __dict__(self):
+ def as_dict(self):
return dict(points=self.points, country=self.country, defender=self.defender, allies=self.allies,
deployed=self.deployed, battle=repr(self.battle))
@@ -709,9 +689,9 @@ class BattleDivision:
battle: "Battle"
@property
- def __dict__(self):
+ def as_dict(self):
return dict(id=self.id, division=self.div, terrain=(self.terrain, self.terrain_display), wall=self.wall,
- dom_pts=self.dom_pts, epic=self.epic, battle=str(self.battle), end=self.div_end)
+ epic=self.epic, battle=str(self.battle), end=self.div_end)
@property
def is_air(self):
@@ -743,7 +723,7 @@ class BattleDivision:
@property
def terrain_display(self):
- return _TERRAINS[self.terrain]
+ return constants.TERRAINS[self.terrain]
def __str__(self):
base_name = f"Div #{self.id} d{self.div}"
@@ -771,7 +751,7 @@ class Battle:
region_name: str
@property
- def __dict__(self):
+ def as_dict(self):
return dict(id=self.id, war_id=self.war_id, divisions=self.div, zone=self.zone_id, rw=self.is_rw,
dict_lib=self.is_dict_lib, start=self.start, sides={'inv': self.invader, 'def': self.defender},
region=[self.region_id, self.region_name])
@@ -805,27 +785,28 @@ class Battle:
self.zone_id = int(battle.get('zone_id'))
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.region_id = battle.get('region', {}).get('id')
self.region_name = battle.get('region', {}).get('name')
- self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=utils.erep_tz)
+ self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=constants.erep_tz)
self.invader = BattleSide(
- self, COUNTRIES[battle.get('inv', {}).get('id')], battle.get('inv', {}).get('points'),
- [COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list')],
- [COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list') if row['deployed']], False
+ self, constants.COUNTRIES[battle.get('inv', {}).get('id')], battle.get('inv', {}).get('points'),
+ [constants.COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list')],
+ [constants.COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list') if row['deployed']], False
)
self.defender = BattleSide(
- self, COUNTRIES[battle.get('def', {}).get('id')], battle.get('def', {}).get('points'),
- [COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list')],
- [COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list') if row['deployed']], True
+ self, constants.COUNTRIES[battle.get('def', {}).get('id')], battle.get('def', {}).get('points'),
+ [constants.COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list')],
+ [constants.COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list') if row['deployed']], True
)
self.div = {}
for div, data in battle.get('div', {}).items():
div = int(div)
if data.get('end'):
- end = datetime.datetime.fromtimestamp(data.get('end'), tz=utils.erep_tz)
+ end = datetime.datetime.fromtimestamp(data.get('end'), tz=constants.erep_tz)
else:
end = utils.localize_dt(datetime.datetime.max - datetime.timedelta(days=1))
@@ -838,12 +819,12 @@ class Battle:
self.div.update({div: battle_div})
def __str__(self):
- now = utils.now()
+ time_now = utils.now()
is_started = self.start < utils.now()
if is_started:
- time_part = " {}".format(now - self.start)
+ time_part = " {}".format(time_now - self.start)
else:
- time_part = "-{}".format(self.start - now)
+ time_part = "-{}".format(self.start - time_now)
return f"Battle {self.id} for {self.region_name[:16]} | {self.invader} : {self.defender} | Round time {time_part}"
@@ -902,7 +883,7 @@ class TelegramBot:
self._next_time = utils.now()
@property
- def __dict__(self):
+ def as_dict(self):
return {'chat_id': self.chat_id, 'api_url': self.api_url, 'player': self.player_name,
'last_time': self._last_time, 'next_time': self._next_time, 'queue': self.__queue,
'initialized': self.__initialized, 'has_threads': bool(len(self._threads))}
@@ -962,54 +943,7 @@ class TelegramBot:
class OfferItem(NamedTuple):
price: float = 99_999.
- country: Country = Country(0, "", "", "")
+ country: constants.Country = constants.Country(0, "", "", "")
amount: int = 0
offer_id: int = 0
citizen_id: int = 0
-
-
-COUNTRIES: Dict[int, Country] = {
- 1: Country(1, 'Romania', 'Romania', 'ROU'), 9: Country(9, 'Brazil', 'Brazil', 'BRA'),
- 10: Country(10, 'Italy', 'Italy', 'ITA'), 11: Country(11, 'France', 'France', 'FRA'),
- 12: Country(12, 'Germany', 'Germany', 'DEU'), 13: Country(13, 'Hungary', 'Hungary', 'HUN'),
- 14: Country(14, 'China', 'China', 'CHN'), 15: Country(15, 'Spain', 'Spain', 'ESP'),
- 23: Country(23, 'Canada', 'Canada', 'CAN'), 24: Country(24, 'USA', 'USA', 'USA'),
- 26: Country(26, 'Mexico', 'Mexico', 'MEX'), 27: Country(27, 'Argentina', 'Argentina', 'ARG'),
- 28: Country(28, 'Venezuela', 'Venezuela', 'VEN'), 29: Country(29, 'United Kingdom', 'United-Kingdom', 'GBR'),
- 30: Country(30, 'Switzerland', 'Switzerland', 'CHE'), 31: Country(31, 'Netherlands', 'Netherlands', 'NLD'),
- 32: Country(32, 'Belgium', 'Belgium', 'BEL'), 33: Country(33, 'Austria', 'Austria', 'AUT'),
- 34: Country(34, 'Czech Republic', 'Czech-Republic', 'CZE'), 35: Country(35, 'Poland', 'Poland', 'POL'),
- 36: Country(36, 'Slovakia', 'Slovakia', 'SVK'), 37: Country(37, 'Norway', 'Norway', 'NOR'),
- 38: Country(38, 'Sweden', 'Sweden', 'SWE'), 39: Country(39, 'Finland', 'Finland', 'FIN'),
- 40: Country(40, 'Ukraine', 'Ukraine', 'UKR'), 41: Country(41, 'Russia', 'Russia', 'RUS'),
- 42: Country(42, 'Bulgaria', 'Bulgaria', 'BGR'), 43: Country(43, 'Turkey', 'Turkey', 'TUR'),
- 44: Country(44, 'Greece', 'Greece', 'GRC'), 45: Country(45, 'Japan', 'Japan', 'JPN'),
- 47: Country(47, 'South Korea', 'South-Korea', 'KOR'), 48: Country(48, 'India', 'India', 'IND'),
- 49: Country(49, 'Indonesia', 'Indonesia', 'IDN'), 50: Country(50, 'Australia', 'Australia', 'AUS'),
- 51: Country(51, 'South Africa', 'South Africa', 'ZAF'),
- 52: Country(52, 'Republic of Moldova', 'Republic-of-Moldova', 'MDA'),
- 53: Country(53, 'Portugal', 'Portugal', 'PRT'), 54: Country(54, 'Ireland', 'Ireland', 'IRL'),
- 55: Country(55, 'Denmark', 'Denmark', 'DNK'), 56: Country(56, 'Iran', 'Iran', 'IRN'),
- 57: Country(57, 'Pakistan', 'Pakistan', 'PAK'), 58: Country(58, 'Israel', 'Israel', 'ISR'),
- 59: Country(59, 'Thailand', 'Thailand', 'THA'), 61: Country(61, 'Slovenia', 'Slovenia', 'SVN'),
- 63: Country(63, 'Croatia', 'Croatia', 'HRV'), 64: Country(64, 'Chile', 'Chile', 'CHL'),
- 65: Country(65, 'Serbia', 'Serbia', 'SRB'), 66: Country(66, 'Malaysia', 'Malaysia', 'MYS'),
- 67: Country(67, 'Philippines', 'Philippines', 'PHL'), 68: Country(68, 'Singapore', 'Singapore', 'SGP'),
- 69: Country(69, 'Bosnia and Herzegovina', 'Bosnia-Herzegovina', 'BiH'),
- 70: Country(70, 'Estonia', 'Estonia', 'EST'), 80: Country(80, 'Montenegro', 'Montenegro', 'MNE'),
- 71: Country(71, 'Latvia', 'Latvia', 'LVA'), 72: Country(72, 'Lithuania', 'Lithuania', 'LTU'),
- 73: Country(73, 'North Korea', 'North-Korea', 'PRK'), 74: Country(74, 'Uruguay', 'Uruguay', 'URY'),
- 75: Country(75, 'Paraguay', 'Paraguay', 'PRY'), 76: Country(76, 'Bolivia', 'Bolivia', 'BOL'),
- 77: Country(77, 'Peru', 'Peru', 'PER'), 78: Country(78, 'Colombia', 'Colombia', 'COL'),
- 79: Country(79, 'Republic of Macedonia (FYROM)', 'Republic-of-Macedonia-FYROM', 'MKD'),
- 81: Country(81, 'Republic of China (Taiwan)', 'Republic-of-China-Taiwan', 'TWN'),
- 82: Country(82, 'Cyprus', 'Cyprus', 'CYP'), 167: Country(167, 'Albania', 'Albania', 'ALB'),
- 83: Country(83, 'Belarus', 'Belarus', 'BLR'), 84: Country(84, 'New Zealand', 'New-Zealand', 'NZL'),
- 164: Country(164, 'Saudi Arabia', 'Saudi-Arabia', 'SAU'), 165: Country(165, 'Egypt', 'Egypt', 'EGY'),
- 166: Country(166, 'United Arab Emirates', 'United-Arab-Emirates', 'UAE'),
- 168: Country(168, 'Georgia', 'Georgia', 'GEO'), 169: Country(169, 'Armenia', 'Armenia', 'ARM'),
- 170: Country(170, 'Nigeria', 'Nigeria', 'NGA'), 171: Country(171, 'Cuba', 'Cuba', 'CUB')
-}
-
-_TERRAINS = {0: "Standard", 1: 'Industrial', 2: 'Urban', 3: 'Suburbs', 4: 'Airport', 5: 'Plains', 6: 'Wasteland',
- 7: 'Mountains', 8: 'Beach', 9: 'Swamp', 10: 'Mud', 11: 'Hills', 12: 'Jungle', 13: 'Forest', 14: 'Desert'}
diff --git a/erepublik/constants.py b/erepublik/constants.py
new file mode 100644
index 0000000..50640b8
--- /dev/null
+++ b/erepublik/constants.py
@@ -0,0 +1,182 @@
+from typing import Dict, Optional, Union
+
+import pytz
+
+__all__ = ["erep_tz", "Country", "AIR_RANKS", "COUNTRIES", "FOOD_ENERGY", "GROUND_RANKS", "GROUND_RANK_POINTS", "INDUSTRIES", "TERRAINS"]
+
+erep_tz = pytz.timezone('US/Pacific')
+
+
+class Country:
+ id: int
+ name: str
+ link: str
+ iso: str
+
+ def __init__(self, country_id: int, name: str, link: str, iso: str):
+ self.id = country_id
+ self.name = name
+ self.link = link
+ self.iso = iso
+
+ def __repr__(self):
+ return f"Country({self.id}, '{self.name}', '{self.link}', '{self.iso}')"
+
+ def __str__(self):
+ return f"#{self.id} {self.name}"
+
+ def __format__(self, format_spec):
+ return self.iso
+
+ def __int__(self):
+ return self.id
+
+ def __eq__(self, other):
+ if isinstance(other, (int, float)):
+ return self.id == int(other)
+ else:
+ try:
+ return self.id == int(other)
+ except ValueError:
+ return self == other
+
+ @property
+ def as_dict(self):
+ return dict(id=self.id, name=self.name, iso=self.iso)
+
+
+class Industries:
+ __by_name = {'food': 1, 'weapons': 2, 'house': 4, 'aircraft': 23,
+ 'frm q1': 7, 'frm q2': 8, 'frm q3': 9, 'frm q4': 10, 'frm q5': 11,
+ 'wrm q1': 12, 'wrm q2': 13, 'wrm q3': 14, 'wrm q4': 15, 'wrm q5': 16,
+ 'hrm q1': 18, 'hrm q2': 19, 'hrm q3': 20, 'hrm q4': 21, 'hrm q5': 22,
+ 'arm q1': 24, 'arm q2': 25, 'arm q3': 26, 'arm q4': 27, 'arm q5': 28}
+ __by_id = {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 __getitem__(self, item) -> Optional[Union[int, str]]:
+ if isinstance(item, int):
+ return self.__by_id.get(item, None)
+ elif isinstance(item, str):
+ return self.__by_name.get(item.lower(), None)
+ return
+
+ def __getattr__(self, item) -> Optional[Union[int, str]]:
+ return self[item]
+
+ @property
+ def as_dict(self):
+ return dict(by_id=self.__by_id, by_name=self.__by_name)
+
+
+AIR_RANKS: Dict[int, str] = {
+ 1: "Airman", 2: "Airman 1st Class", 3: "Airman 1st Class*", 4: "Airman 1st Class**", 5: "Airman 1st Class***",
+ 6: "Airman 1st Class****", 7: "Airman 1st Class*****", 8: "Senior Airman", 9: "Senior Airman*",
+ 10: "Senior Airman**", 11: "Senior Airman***", 12: "Senior Airman****", 13: "Senior Airman*****",
+ 14: "Staff Sergeant", 15: "Staff Sergeant*", 16: "Staff Sergeant**", 17: "Staff Sergeant***",
+ 18: "Staff Sergeant****", 19: "Staff Sergeant*****", 20: "Aviator", 21: "Aviator*", 22: "Aviator**",
+ 23: "Aviator***", 24: "Aviator****", 25: "Aviator*****", 26: "Flight Lieutenant", 27: "Flight Lieutenant*",
+ 28: "Flight Lieutenant**", 29: "Flight Lieutenant***", 30: "Flight Lieutenant****", 31: "Flight Lieutenant*****",
+ 32: "Squadron Leader", 33: "Squadron Leader*", 34: "Squadron Leader**", 35: "Squadron Leader***",
+ 36: "Squadron Leader****", 37: "Squadron Leader*****", 38: "Chief Master Sergeant", 39: "Chief Master Sergeant*",
+ 40: "Chief Master Sergeant**", 41: "Chief Master Sergeant***", 42: "Chief Master Sergeant****",
+ 43: "Chief Master Sergeant*****", 44: "Wing Commander", 45: "Wing Commander*", 46: "Wing Commander**",
+ 47: "Wing Commander***", 48: "Wing Commander****", 49: "Wing Commander*****", 50: "Group Captain",
+ 51: "Group Captain*", 52: "Group Captain**", 53: "Group Captain***", 54: "Group Captain****",
+ 55: "Group Captain*****", 56: "Air Commodore", 57: "Air Commodore*", 58: "Air Commodore**", 59: "Air Commodore***",
+ 60: "Air Commodore****", 61: "Air Commodore*****",
+}
+
+COUNTRIES: Dict[int, Country] = {
+ 1: Country(1, 'Romania', 'Romania', 'ROU'), 9: Country(9, 'Brazil', 'Brazil', 'BRA'),
+ 10: Country(10, 'Italy', 'Italy', 'ITA'), 11: Country(11, 'France', 'France', 'FRA'),
+ 12: Country(12, 'Germany', 'Germany', 'DEU'), 13: Country(13, 'Hungary', 'Hungary', 'HUN'),
+ 14: Country(14, 'China', 'China', 'CHN'), 15: Country(15, 'Spain', 'Spain', 'ESP'),
+ 23: Country(23, 'Canada', 'Canada', 'CAN'), 24: Country(24, 'USA', 'USA', 'USA'),
+ 26: Country(26, 'Mexico', 'Mexico', 'MEX'), 27: Country(27, 'Argentina', 'Argentina', 'ARG'),
+ 28: Country(28, 'Venezuela', 'Venezuela', 'VEN'), 29: Country(29, 'United Kingdom', 'United-Kingdom', 'GBR'),
+ 30: Country(30, 'Switzerland', 'Switzerland', 'CHE'), 31: Country(31, 'Netherlands', 'Netherlands', 'NLD'),
+ 32: Country(32, 'Belgium', 'Belgium', 'BEL'), 33: Country(33, 'Austria', 'Austria', 'AUT'),
+ 34: Country(34, 'Czech Republic', 'Czech-Republic', 'CZE'), 35: Country(35, 'Poland', 'Poland', 'POL'),
+ 36: Country(36, 'Slovakia', 'Slovakia', 'SVK'), 37: Country(37, 'Norway', 'Norway', 'NOR'),
+ 38: Country(38, 'Sweden', 'Sweden', 'SWE'), 39: Country(39, 'Finland', 'Finland', 'FIN'),
+ 40: Country(40, 'Ukraine', 'Ukraine', 'UKR'), 41: Country(41, 'Russia', 'Russia', 'RUS'),
+ 42: Country(42, 'Bulgaria', 'Bulgaria', 'BGR'), 43: Country(43, 'Turkey', 'Turkey', 'TUR'),
+ 44: Country(44, 'Greece', 'Greece', 'GRC'), 45: Country(45, 'Japan', 'Japan', 'JPN'),
+ 47: Country(47, 'South Korea', 'South-Korea', 'KOR'), 48: Country(48, 'India', 'India', 'IND'),
+ 49: Country(49, 'Indonesia', 'Indonesia', 'IDN'), 50: Country(50, 'Australia', 'Australia', 'AUS'),
+ 51: Country(51, 'South Africa', 'South Africa', 'ZAF'),
+ 52: Country(52, 'Republic of Moldova', 'Republic-of-Moldova', 'MDA'),
+ 53: Country(53, 'Portugal', 'Portugal', 'PRT'), 54: Country(54, 'Ireland', 'Ireland', 'IRL'),
+ 55: Country(55, 'Denmark', 'Denmark', 'DNK'), 56: Country(56, 'Iran', 'Iran', 'IRN'),
+ 57: Country(57, 'Pakistan', 'Pakistan', 'PAK'), 58: Country(58, 'Israel', 'Israel', 'ISR'),
+ 59: Country(59, 'Thailand', 'Thailand', 'THA'), 61: Country(61, 'Slovenia', 'Slovenia', 'SVN'),
+ 63: Country(63, 'Croatia', 'Croatia', 'HRV'), 64: Country(64, 'Chile', 'Chile', 'CHL'),
+ 65: Country(65, 'Serbia', 'Serbia', 'SRB'), 66: Country(66, 'Malaysia', 'Malaysia', 'MYS'),
+ 67: Country(67, 'Philippines', 'Philippines', 'PHL'), 68: Country(68, 'Singapore', 'Singapore', 'SGP'),
+ 69: Country(69, 'Bosnia and Herzegovina', 'Bosnia-Herzegovina', 'BiH'),
+ 70: Country(70, 'Estonia', 'Estonia', 'EST'), 80: Country(80, 'Montenegro', 'Montenegro', 'MNE'),
+ 71: Country(71, 'Latvia', 'Latvia', 'LVA'), 72: Country(72, 'Lithuania', 'Lithuania', 'LTU'),
+ 73: Country(73, 'North Korea', 'North-Korea', 'PRK'), 74: Country(74, 'Uruguay', 'Uruguay', 'URY'),
+ 75: Country(75, 'Paraguay', 'Paraguay', 'PRY'), 76: Country(76, 'Bolivia', 'Bolivia', 'BOL'),
+ 77: Country(77, 'Peru', 'Peru', 'PER'), 78: Country(78, 'Colombia', 'Colombia', 'COL'),
+ 79: Country(79, 'Republic of Macedonia (FYROM)', 'Republic-of-Macedonia-FYROM', 'MKD'),
+ 81: Country(81, 'Republic of China (Taiwan)', 'Republic-of-China-Taiwan', 'TWN'),
+ 82: Country(82, 'Cyprus', 'Cyprus', 'CYP'), 167: Country(167, 'Albania', 'Albania', 'ALB'),
+ 83: Country(83, 'Belarus', 'Belarus', 'BLR'), 84: Country(84, 'New Zealand', 'New-Zealand', 'NZL'),
+ 164: Country(164, 'Saudi Arabia', 'Saudi-Arabia', 'SAU'), 165: Country(165, 'Egypt', 'Egypt', 'EGY'),
+ 166: Country(166, 'United Arab Emirates', 'United-Arab-Emirates', 'UAE'),
+ 168: Country(168, 'Georgia', 'Georgia', 'GEO'), 169: Country(169, 'Armenia', 'Armenia', 'ARM'),
+ 170: Country(170, 'Nigeria', 'Nigeria', 'NGA'), 171: Country(171, 'Cuba', 'Cuba', 'CUB')
+}
+
+FOOD_ENERGY: Dict[str, int] = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
+
+GROUND_RANKS: Dict[int, str] = {
+ 1: "Recruit", 2: "Private", 3: "Private*", 4: "Private**", 5: "Private***",
+ 6: "Corporal", 7: "Corporal*", 8: "Corporal**", 9: "Corporal***",
+ 10: "Sergeant", 11: "Sergeant*", 12: "Sergeant**", 13: "Sergeant***",
+ 14: "Lieutenant", 15: "Lieutenant*", 16: "Lieutenant**", 17: "Lieutenant***",
+ 18: "Captain", 19: "Captain*", 20: "Captain**", 21: "Captain***",
+ 22: "Major", 23: "Major*", 24: "Major**", 25: "Major***",
+ 26: "Commander", 27: "Commander*", 28: "Commander**", 29: "Commander***",
+ 30: "Lt Colonel", 31: "Lt Colonel*", 32: "Lt Colonel**", 33: "Lt Colonel***",
+ 34: "Colonel", 35: "Colonel*", 36: "Colonel**", 37: "Colonel***",
+ 38: "General", 39: "General*", 40: "General**", 41: "General***",
+ 42: "Field Marshal", 43: "Field Marshal*", 44: "Field Marshal**", 45: "Field Marshal***",
+ 46: "Supreme Marshal", 47: "Supreme Marshal*", 48: "Supreme Marshal**", 49: "Supreme Marshal***",
+ 50: "National Force", 51: "National Force*", 52: "National Force**", 53: "National Force***",
+ 54: "World Class Force", 55: "World Class Force*", 56: "World Class Force**", 57: "World Class Force***",
+ 58: "Legendary Force", 59: "Legendary Force*", 60: "Legendary Force**", 61: "Legendary Force***",
+ 62: "God of War", 63: "God of War*", 64: "God of War**", 65: "God of War***",
+ 66: "Titan", 67: "Titan*", 68: "Titan**", 69: "Titan***",
+ 70: "Legends I", 71: "Legends II", 72: "Legends III", 73: "Legends IV", 74: "Legends V", 75: "Legends VI",
+ 76: "Legends VII", 77: "Legends VIII", 78: "Legends IX", 79: "Legends X", 80: "Legends XI", 81: "Legends XII",
+ 82: "Legends XIII", 83: "Legends XIV", 84: "Legends XV", 85: "Legends XVI", 86: "Legends XVII", 87: "Legends XVIII",
+ 88: "Legends XIX", 89: "Legends XX",
+}
+
+GROUND_RANK_POINTS: Dict[int, int] = {
+ 1: 0, 2: 15, 3: 45, 4: 80, 5: 120, 6: 170, 7: 250, 8: 350, 9: 450, 10: 600, 11: 800, 12: 1000,
+ 13: 1400, 14: 1850, 15: 2350, 16: 3000, 17: 3750, 18: 5000, 19: 6500, 20: 9000, 21: 12000,
+ 22: 15500, 23: 20000, 24: 25000, 25: 31000, 26: 40000, 27: 52000, 28: 67000, 29: 85000,
+ 30: 110000, 31: 140000, 32: 180000, 33: 225000, 34: 285000, 35: 355000, 36: 435000, 37: 540000,
+ 38: 660000, 39: 800000, 40: 950000, 41: 1140000, 42: 1350000, 43: 1600000, 44: 1875000,
+ 45: 2185000, 46: 2550000, 47: 3000000, 48: 3500000, 49: 4150000, 50: 4900000, 51: 5800000,
+ 52: 7000000, 53: 9000000, 54: 11500000, 55: 14500000, 56: 18000000, 57: 22000000, 58: 26500000,
+ 59: 31500000, 60: 37000000, 61: 43000000, 62: 50000000, 63: 100000000, 64: 200000000,
+ 65: 500000000, 66: 1000000000, 67: 2000000000, 68: 4000000000, 69: 10000000000, 70: 20000000000,
+ 71: 30000000000, 72: 40000000000, 73: 50000000000, 74: 60000000000, 75: 70000000000,
+ 76: 80000000000, 77: 90000000000, 78: 100000000000, 79: 110000000000, 80: 120000000000,
+ 81: 130000000000, 82: 140000000000, 83: 150000000000, 84: 160000000000, 85: 170000000000,
+ 86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000
+}
+
+INDUSTRIES = Industries()
+
+TERRAINS: Dict[int, str] = {0: "Standard", 1: 'Industrial', 2: 'Urban', 3: 'Suburbs', 4: 'Airport', 5: 'Plains',
+ 6: 'Wasteland', 7: 'Mountains', 8: 'Beach', 9: 'Swamp', 10: 'Mud', 11: 'Hills',
+ 12: 'Jungle', 13: 'Forest', 14: 'Desert'}
diff --git a/erepublik/utils.py b/erepublik/utils.py
index c4e8a9f..1ecd22b 100644
--- a/erepublik/utils.py
+++ b/erepublik/utils.py
@@ -9,109 +9,47 @@ import traceback
import unicodedata
from decimal import Decimal
from pathlib import Path
-from typing import Any, Dict, List, Mapping, Optional, Union
+from typing import Any, List, Mapping, Optional, Union
-import pytz
import requests
-from . import __commit_id__, __version__
+from . import __commit_id__, __version__, constants
try:
import simplejson as json
except ImportError:
import json
-__all__ = ["FOOD_ENERGY", "COMMIT_ID", "erep_tz",
- "now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
- "get_sleep_seconds", "interactive_sleep", "silent_sleep",
- "write_silent_log", "write_interactive_log", "get_file", "write_file",
- "send_email", "normalize_html_json", "process_error", "process_warning",
- 'calculate_hit', 'get_ground_hit_dmg_value', 'get_air_hit_dmg_value']
+__all__ = ['COMMIT_ID', 'VERSION', 'calculate_hit', 'caught_error', 'date_from_eday', 'eday_from_date',
+ 'get_air_hit_dmg_value', 'get_file', 'get_ground_hit_dmg_value', 'get_sleep_seconds', 'good_timedelta',
+ 'interactive_sleep', 'json', 'localize_dt', 'localize_timestamp', 'normalize_html_json', 'now',
+ 'process_error', 'process_warning', 'send_email', 'silent_sleep', 'slugify', 'write_file',
+ 'write_interactive_log', 'write_silent_log']
if not sys.version_info >= (3, 7):
raise AssertionError('This script requires Python version 3.7 and higher\n'
'But Your version is v{}.{}.{}'.format(*sys.version_info))
-FOOD_ENERGY: Dict[str, int] = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
COMMIT_ID: str = __commit_id__
VERSION: str = __version__
-erep_tz = pytz.timezone('US/Pacific')
-AIR_RANKS: Dict[int, str] = {
- 1: "Airman", 2: "Airman 1st Class", 3: "Airman 1st Class*", 4: "Airman 1st Class**", 5: "Airman 1st Class***",
- 6: "Airman 1st Class****", 7: "Airman 1st Class*****", 8: "Senior Airman", 9: "Senior Airman*",
- 10: "Senior Airman**", 11: "Senior Airman***", 12: "Senior Airman****", 13: "Senior Airman*****",
- 14: "Staff Sergeant", 15: "Staff Sergeant*", 16: "Staff Sergeant**", 17: "Staff Sergeant***",
- 18: "Staff Sergeant****", 19: "Staff Sergeant*****", 20: "Aviator", 21: "Aviator*", 22: "Aviator**",
- 23: "Aviator***", 24: "Aviator****", 25: "Aviator*****", 26: "Flight Lieutenant", 27: "Flight Lieutenant*",
- 28: "Flight Lieutenant**", 29: "Flight Lieutenant***", 30: "Flight Lieutenant****", 31: "Flight Lieutenant*****",
- 32: "Squadron Leader", 33: "Squadron Leader*", 34: "Squadron Leader**", 35: "Squadron Leader***",
- 36: "Squadron Leader****", 37: "Squadron Leader*****", 38: "Chief Master Sergeant", 39: "Chief Master Sergeant*",
- 40: "Chief Master Sergeant**", 41: "Chief Master Sergeant***", 42: "Chief Master Sergeant****",
- 43: "Chief Master Sergeant*****", 44: "Wing Commander", 45: "Wing Commander*", 46: "Wing Commander**",
- 47: "Wing Commander***", 48: "Wing Commander****", 49: "Wing Commander*****", 50: "Group Captain",
- 51: "Group Captain*", 52: "Group Captain**", 53: "Group Captain***", 54: "Group Captain****",
- 55: "Group Captain*****", 56: "Air Commodore", 57: "Air Commodore*", 58: "Air Commodore**", 59: "Air Commodore***",
- 60: "Air Commodore****", 61: "Air Commodore*****",
-}
-
-GROUND_RANKS: Dict[int, str] = {
- 1: "Recruit", 2: "Private", 3: "Private*", 4: "Private**", 5: "Private***",
- 6: "Corporal", 7: "Corporal*", 8: "Corporal**", 9: "Corporal***",
- 10: "Sergeant", 11: "Sergeant*", 12: "Sergeant**", 13: "Sergeant***",
- 14: "Lieutenant", 15: "Lieutenant*", 16: "Lieutenant**", 17: "Lieutenant***",
- 18: "Captain", 19: "Captain*", 20: "Captain**", 21: "Captain***",
- 22: "Major", 23: "Major*", 24: "Major**", 25: "Major***",
- 26: "Commander", 27: "Commander*", 28: "Commander**", 29: "Commander***",
- 30: "Lt Colonel", 31: "Lt Colonel*", 32: "Lt Colonel**", 33: "Lt Colonel***",
- 34: "Colonel", 35: "Colonel*", 36: "Colonel**", 37: "Colonel***",
- 38: "General", 39: "General*", 40: "General**", 41: "General***",
- 42: "Field Marshal", 43: "Field Marshal*", 44: "Field Marshal**", 45: "Field Marshal***",
- 46: "Supreme Marshal", 47: "Supreme Marshal*", 48: "Supreme Marshal**", 49: "Supreme Marshal***",
- 50: "National Force", 51: "National Force*", 52: "National Force**", 53: "National Force***",
- 54: "World Class Force", 55: "World Class Force*", 56: "World Class Force**", 57: "World Class Force***",
- 58: "Legendary Force", 59: "Legendary Force*", 60: "Legendary Force**", 61: "Legendary Force***",
- 62: "God of War", 63: "God of War*", 64: "God of War**", 65: "God of War***",
- 66: "Titan", 67: "Titan*", 68: "Titan**", 69: "Titan***",
- 70: "Legends I", 71: "Legends II", 72: "Legends III", 73: "Legends IV", 74: "Legends V", 75: "Legends VI",
- 76: "Legends VII", 77: "Legends VIII", 78: "Legends IX", 79: "Legends X", 80: "Legends XI", 81: "Legends XII",
- 82: "Legends XIII", 83: "Legends XIV", 84: "Legends XV", 85: "Legends XVI", 86: "Legends XVII", 87: "Legends XVIII",
- 88: "Legends XIX", 89: "Legends XX",
-}
-
-GROUND_RANK_POINTS: Dict[int, int] = {
- 1: 0, 2: 15, 3: 45, 4: 80, 5: 120, 6: 170, 7: 250, 8: 350, 9: 450, 10: 600, 11: 800, 12: 1000,
- 13: 1400, 14: 1850, 15: 2350, 16: 3000, 17: 3750, 18: 5000, 19: 6500, 20: 9000, 21: 12000,
- 22: 15500, 23: 20000, 24: 25000, 25: 31000, 26: 40000, 27: 52000, 28: 67000, 29: 85000,
- 30: 110000, 31: 140000, 32: 180000, 33: 225000, 34: 285000, 35: 355000, 36: 435000, 37: 540000,
- 38: 660000, 39: 800000, 40: 950000, 41: 1140000, 42: 1350000, 43: 1600000, 44: 1875000,
- 45: 2185000, 46: 2550000, 47: 3000000, 48: 3500000, 49: 4150000, 50: 4900000, 51: 5800000,
- 52: 7000000, 53: 9000000, 54: 11500000, 55: 14500000, 56: 18000000, 57: 22000000, 58: 26500000,
- 59: 31500000, 60: 37000000, 61: 43000000, 62: 50000000, 63: 100000000, 64: 200000000,
- 65: 500000000, 66: 1000000000, 67: 2000000000, 68: 4000000000, 69: 10000000000, 70: 20000000000,
- 71: 30000000000, 72: 40000000000, 73: 50000000000, 74: 60000000000, 75: 70000000000,
- 76: 80000000000, 77: 90000000000, 78: 100000000000, 79: 110000000000, 80: 120000000000,
- 81: 130000000000, 82: 140000000000, 83: 150000000000, 84: 160000000000, 85: 170000000000,
- 86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000
-}
-
def now() -> datetime.datetime:
- return datetime.datetime.now(erep_tz).replace(microsecond=0)
+ return datetime.datetime.now(constants.erep_tz).replace(microsecond=0)
def localize_timestamp(timestamp: int) -> datetime.datetime:
- return datetime.datetime.fromtimestamp(timestamp, erep_tz)
+ return datetime.datetime.fromtimestamp(timestamp, constants.erep_tz)
def localize_dt(dt: Union[datetime.date, datetime.datetime]) -> datetime.datetime:
try:
try:
- return erep_tz.localize(dt)
+ return constants.erep_tz.localize(dt)
except AttributeError:
- return erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
+ return constants.erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
except ValueError:
- return dt.astimezone(erep_tz)
+ return dt.astimezone(constants.erep_tz)
def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.datetime:
@@ -124,7 +62,7 @@ def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.da
:return: datetime object with correct timezone when jumped over DST
:rtype: datetime.datetime
"""
- return erep_tz.normalize(dt + td)
+ return constants.erep_tz.normalize(dt + td)
def eday_from_date(date: Union[datetime.date, datetime.datetime] = now()) -> int: