Compare commits

...

54 Commits

Author SHA1 Message Date
9e1166a460 Bump version: 0.21.5.1 → 0.21.5.2 2020-09-29 17:17:07 +03:00
fb0042c00d wheeloffortune url bugfix 2020-09-29 17:17:00 +03:00
bb800578e7 Bump version: 0.21.5 → 0.21.5.1 2020-09-29 15:06:39 +03:00
7025f750dc PySocks as requirement 2020-09-29 15:06:30 +03:00
bf77f21b60 MyCompanies export as dict optimised 2020-09-29 15:04:51 +03:00
6b7639d7fb Bump version: 0.21.4.8 → 0.21.5 2020-09-29 10:52:36 +03:00
3b1c1928fd Added proxy support 😉 2020-09-29 10:52:14 +03:00
2e26c2db79 Bump version: 0.21.4.7 → 0.21.4.8 2020-09-25 10:10:33 +03:00
78c055fee2 bugfix 2020-09-25 10:10:27 +03:00
fe41c4cdc6 Bump version: 0.21.4.6 → 0.21.4.7 2020-09-23 13:22:38 +03:00
123b6cf4ed Fight reporting unified and moved to Reporter.report_fighting 2020-09-23 13:22:31 +03:00
f652b02443 Fight reporting duplicate 2020-09-23 13:17:46 +03:00
73537e4742 Bump version: 0.21.4.5 → 0.21.4.6 2020-09-23 11:15:32 +03:00
955432e0d2 Check also for maintenance in BaseCitizen._errors_in_response() 2020-09-23 11:15:18 +03:00
1d93864dca Bump version: 0.21.4.4 → 0.21.4.5 2020-09-22 16:30:03 +03:00
c472d688be error logging 2020-09-22 16:29:50 +03:00
bff9a2bec9 Bump version: 0.21.4.3 → 0.21.4.4 2020-09-21 20:40:40 +03:00
973ea40e00 bugfix 2020-09-21 20:40:24 +03:00
52c85fdf28 Bump version: 0.21.4.2 → 0.21.4.3 2020-09-21 20:18:02 +03:00
a889e9efa1 bugfix 2020-09-21 20:17:56 +03:00
a9a0cdc6d5 Bump version: 0.21.4.1 → 0.21.4.2 2020-09-21 12:39:44 +03:00
1c102488b6 Test fix to not run if WC end is near 2020-09-21 12:39:27 +03:00
c38acef2a0 Bump version: 0.21.4 → 0.21.4.1 2020-09-21 11:34:59 +03:00
48b5e473aa doc generation bugfixes 2020-09-21 11:34:50 +03:00
7fadeb1a49 Bump version: 0.21.3 → 0.21.4 2020-09-21 11:26:51 +03:00
b723660f23 Fixups and type checks 2020-09-21 11:26:32 +03:00
f10eeec498 requirement update 2020-09-21 11:24:01 +03:00
230167f93d mypy bugfix 2020-09-21 11:23:43 +03:00
d5ed989e80 Bump version: 0.21.2.2 → 0.21.3 2020-08-18 16:37:27 +03:00
6fc24b8adf requirements 2020-08-18 16:37:07 +03:00
cf797f2f60 Fixes and updates 2020-08-18 13:14:41 +03:00
ad29045ace Bump version: 0.21.2.1 → 0.21.2.2 2020-07-29 11:40:41 +03:00
c919e46af5 PoliticsAPI extended and bugfixed 2020-07-29 11:40:32 +03:00
644b4d70e1 Bump version: 0.21.2 → 0.21.2.1 2020-07-29 11:23:31 +03:00
6dbbd054ba bugfix 2020-07-29 09:27:02 +03:00
0ee952e504 bugfix 2020-07-29 09:21:49 +03:00
bb9b198a53 Bump version: 0.21.1 → 0.21.2 2020-07-28 19:34:19 +03:00
cb22e631ca Merge branch 'memory-optimisation'
* memory-optimisation:
  Company cleanup optimisation
  JSON.dump sort_keys parameter throwing mysterious errors
  Fixed memory leak in Battle and MyCompanies classes
2020-07-28 19:33:52 +03:00
c43e20c8f6 Return all Non-Terrain divisions and their bh damage 2020-07-28 19:33:30 +03:00
c8f41b97af Company cleanup optimisation 2020-07-28 19:25:22 +03:00
d483bcbcb9 JSON.dump sort_keys parameter throwing mysterious errors 2020-07-28 18:29:25 +03:00
a316f277fb Fixed memory leak in Battle and MyCompanies classes 2020-07-28 18:28:03 +03:00
e8c81d17e6 Weapons kind should be singular - 'weapon' 2020-07-19 07:56:15 +03:00
edb4d8851b Bump version: 0.21.0.3 → 0.21.1 2020-07-16 11:15:04 +03:00
76edd6bb7d Update traveling to incorporate travel cooldown (1travel / 15sec) 2020-07-16 11:14:35 +03:00
8da376b852 Change variable names to be more precise if argument must be and id or instance (battle/battle_id, division/division_id) 2020-07-16 11:13:29 +03:00
b6b0be7442 Minimize error reporting locals to not duplicate instance.json data 2020-07-16 11:11:35 +03:00
ed434b605d Refactor '.format()' calls to f-strings 2020-07-16 11:08:31 +03:00
2bd311def6 Dev requirement update 2020-07-14 15:37:59 +03:00
4b437c2ba6 Update README.rst 2020-07-14 14:11:20 +03:00
cc8a1450d4 Merge pull request #3 from codacy-badger/codacy-badge
Add a Codacy badge to README.rst
2020-07-14 14:08:45 +03:00
0c9f3756ea Add Codacy badge 2020-07-14 11:07:36 +00:00
9de07950b8 Bump version: 0.21.0.2 → 0.21.0.3 2020-07-13 11:24:29 +03:00
766b7b2d95 bugfix 2020-07-12 10:45:44 +03:00
12 changed files with 541 additions and 414 deletions

View File

@ -88,9 +88,3 @@ dist: clean ## builds source and wheel package
install: clean ## install the package to the active Python's site-packages
python setup.py install
setcommit:
bash set_commit_id.sh
# commit=`git log -1 --pretty=format:%h`
# sed -i.bak -E "s|COMMIT_ID = \".+\"|COMMIT_ID = \"$(commit)\"|g" erepublik/utils.py
# mv erepublik/utils.py.bak erepublik/utils.py

View File

@ -10,6 +10,10 @@ eRepublik script
:target: https://erepublik.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://api.codacy.com/project/badge/Grade/eaa7ae43d23f4c0abab65c3bde89475a
:target: https://app.codacy.com/manual/eeriks/erepublik?utm_source=github.com&utm_medium=referral&utm_content=eeriks/erepublik&utm_campaign=Badge_Grade_Dashboard
:alt: Codacy Badge
Python package for automated eRepublik playing
@ -30,3 +34,4 @@ This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypack
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage

View File

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

View File

@ -12,32 +12,36 @@ __all__ = ['SlowRequests', 'CitizenAPI']
class SlowRequests(Session):
last_time: datetime.datetime
timeout = datetime.timedelta(milliseconds=500)
uas = [
timeout: datetime.timedelta = datetime.timedelta(milliseconds=500)
uas: List[str] = [
# Chrome
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36', # noqa
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', # noqa
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36', # noqa
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', # noqa
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', # noqa
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
# FireFox
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:82.0) Gecko/20100101 Firefox/82.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0',
]
debug = False
debug: bool = False
def __init__(self):
def __init__(self, proxies: Dict[str, str] = None):
super().__init__()
if proxies:
self.proxies = proxies
self.request_log_name = utils.get_file(utils.now().strftime("debug/requests_%Y-%m-%d.log"))
self.last_time = utils.now()
self.headers.update({
@ -113,12 +117,13 @@ class SlowRequests(Session):
class CitizenBaseAPI:
url: str = "https://www.erepublik.com/en"
_req: SlowRequests = None
token: str = ""
_req: SlowRequests
token: str
def __init__(self):
""" Class for unifying eRepublik known endpoints and their required/optional parameters """
self._req = SlowRequests()
self.token = ""
def post(self, url: str, data=None, json=None, **kwargs) -> Response:
return self._req.post(url, data, json, **kwargs)
@ -129,82 +134,90 @@ class CitizenBaseAPI:
def _get_main(self) -> Response:
return self.get(self.url)
def set_socks_proxy(self, host: str, port: int, username: str = None, password: str = None):
url = f'socks5://{username}:{password}@{host}:{port}' if username and password else f'socks5://{host}:{port}'
self._req.proxies = dict(http=url, https=url)
def set_http_proxy(self, host: str, port: int, username: str = None, password: str = None):
url = f'http://{username}:{password}@{host}:{port}' if username and password else f'socks5://{host}:{port}'
self._req.proxies = dict(http=url)
class ErepublikAnniversaryAPI(CitizenBaseAPI):
def _post_main_collect_anniversary_reward(self) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token})
return self.post(f"{self.url}/main/collect-anniversary-reward", data={"_token": self.token})
# 12th anniversary endpoints
def _get_anniversary_quest_data(self) -> Response:
return self.get("{}/main/anniversaryQuestData".format(self.url))
return self.get(f"{self.url}/main/anniversaryQuestData")
def _post_map_rewards_unlock(self, node_id: int) -> Response:
data = {'nodeId': node_id, '_token': self.token}
return self.post("{}/main/map-rewards-unlock".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-unlock", data=data)
def _post_map_rewards_speedup(self, node_id: int, currency_amount: int) -> Response:
data = {'nodeId': node_id, '_token': self.token, "currencyCost": currency_amount}
return self.post("{}/main/map-rewards-speedup".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-speedup", data=data)
def _post_map_rewards_claim(self, node_id: int) -> Response:
data = {'nodeId': node_id, '_token': self.token}
return self.post("{}/main/map-rewards-claim".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-claim", data=data)
def _post_main_wheel_of_fortune_spin(self, cost) -> Response:
return self.post(f"{self.url}/wheeloffortune-spin", data={'_token': self.token, "cost": cost})
return self.post(f"{self.url}/main/wheeloffortune-spin", data={'_token': self.token, "cost": cost})
def _post_main_wheel_of_fortune_build(self) -> Response:
return self.post(f"{self.url}/wheeloffortune-build", data={'_token': self.token})
return self.post(f"{self.url}/main/wheeloffortune-build", data={'_token': self.token})
class ErepublikArticleAPI(CitizenBaseAPI):
def _get_main_article_json(self, article_id: int) -> Response:
return self.get("{}/main/articleJson/{}".format(self.url, article_id))
return self.get(f"{self.url}/main/articleJson/{article_id}")
def _post_main_article_comments(self, article_id: int, page: int = 1) -> Response:
data = dict(_token=self.token, articleId=article_id, page=page)
if page:
data.update({'page': page})
return self.post("{}/main/articleComments".format(self.url), data=data)
return self.post(f"{self.url}/main/articleComments", data=data)
def _post_main_article_comments_create(self, message: str, article_id: int, parent: int = 0) -> Response:
data = dict(_token=self.token, message=message, articleId=article_id)
if parent:
data.update({"parentId": parent})
return self.post("{}/main/articleComments/create".format(self.url), data=data)
return self.post(f"{self.url}/main/articleComments/create", data=data)
def _post_main_donate_article(self, article_id: int, amount: int) -> Response:
data = dict(_token=self.token, articleId=article_id, amount=amount)
return self.post("{}/main/donate-article".format(self.url), data=data)
return self.post(f"{self.url}/main/donate-article", data=data)
def _post_main_write_article(self, title: str, content: str, country_id: int, kind_id: int) -> Response:
data = dict(_token=self.token, article_name=title, article_body=content, article_location=country_id,
article_category=kind_id)
return self.post("{}/main/write-article".format(self.url), data=data)
return self.post(f"{self.url}/main/write-article", data=data)
def _post_main_vote_article(self, article_id: int) -> Response:
data = dict(_token=self.token, articleId=article_id)
return self.post("{}/main/vote-article".format(self.url), data=data)
return self.post(f"{self.url}/main/vote-article", data=data)
class ErepublikCompanyAPI(CitizenBaseAPI):
def _post_economy_assign_to_holding(self, factory_id: int, holding_id: int) -> Response:
data = dict(_token=self.token, factoryId=factory_id, action="assign", holdingCompanyId=holding_id)
return self.post("{}/economy/assign-to-holding".format(self.url), data=data)
return self.post(f"{self.url}/economy/assign-to-holding", data=data)
def _post_economy_create_company(self, industry_id: int, building_type: int = 1) -> Response:
data = {"_token": self.token, "company[industry_id]": industry_id, "company[building_type]": building_type}
return self.post("{}/economy/create-company".format(self.url), data=data,
headers={"Referer": "{}/economy/create-company".format(self.url)})
return self.post(f"{self.url}/economy/create-company", data=data,
headers={"Referer": f"{self.url}/economy/create-company"})
def _get_economy_inventory_items(self) -> Response:
return self.get("{}/economy/inventory-items/".format(self.url))
return self.get(f"{self.url}/economy/inventory-items/")
def _get_economy_job_market_json(self, country: int) -> Response:
return self.get("{}/economy/job-market-json/{}/1/desc".format(self.url, country))
def _get_economy_job_market_json(self, country_id: int) -> Response:
return self.get(f"{self.url}/economy/job-market-json/{country_id}/1/desc")
def _get_economy_my_companies(self) -> Response:
return self.get("{}/economy/myCompanies".format(self.url))
return self.get(f"{self.url}/economy/myCompanies")
def _post_economy_train(self, tg_ids: List[int]) -> Response:
data: Dict[str, Union[int, str]] = {}
@ -213,11 +226,11 @@ class ErepublikCompanyAPI(CitizenBaseAPI):
data["grounds[%i][train]" % idx] = 1
if data:
data['_token'] = self.token
return self.post("{}/economy/train".format(self.url), data=data)
return self.post(f"{self.url}/economy/train", data=data)
def _post_economy_upgrade_company(self, factory: int, level: int, pin: str = None) -> Response:
data = dict(_token=self.token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin)
return self.post("{}/economy/upgrade-company".format(self.url), data=data)
return self.post(f"{self.url}/economy/upgrade-company", data=data)
def _post_economy_work(self, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None) -> Response:
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=self.token)
@ -241,174 +254,169 @@ class ErepublikCompanyAPI(CitizenBaseAPI):
f"companies[{max_idx}][own_work]": 0
})
max_idx += 1
return self.post("{}/economy/work".format(self.url), data=data)
return self.post(f"{self.url}/economy/work", data=data)
def _post_economy_work_overtime(self) -> Response:
data = dict(action_type="workOvertime", _token=self.token)
return self.post("{}/economy/workOvertime".format(self.url), data=data)
return self.post(f"{self.url}/economy/workOvertime", data=data)
def _post_economy_job_market_apply(self, citizen: int, salary: float) -> Response:
data = dict(_token=self.token, citizenId=citizen, salary=salary)
return self.post("{}/economy/job-market-apply".format(self.url), data=data)
def _post_economy_job_market_apply(self, citizen_id: int, salary: float) -> Response:
data = dict(_token=self.token, citizenId=citizen_id, salary=salary)
return self.post(f"{self.url}/economy/job-market-apply", data=data)
def _post_economy_resign(self) -> Response:
return self.post("{}/economy/resign".format(self.url),
return self.post(f"{self.url}/economy/resign",
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={"_token": self.token, "action_type": "resign"})
def _post_economy_sell_company(self, factory: int, pin: int = None, sell: bool = True) -> Response:
def _post_economy_sell_company(self, factory_id: int, pin: int = None, sell: bool = True) -> Response:
data = dict(_token=self.token, pin="" if pin is None else pin)
if sell:
data.update({"sell": "sell"})
else:
data.update({"dissolve": factory})
return self.post("{}/economy/sell-company/{}".format(self.url, factory),
data.update({"dissolve": factory_id})
return self.post(f"{self.url}/economy/sell-company/{factory_id}",
data=data, headers={"Referer": self.url})
class ErepublikCountryAPI(CitizenBaseAPI):
def _get_country_military(self, country: str) -> Response:
return self.get("{}/country/military/{}".format(self.url, country))
def _get_country_military(self, country_name: str) -> Response:
return self.get(f"{self.url}/country/military/{country_name}")
def _post_main_country_donate(self, country: int, action: str, value: Union[int, float],
def _post_main_country_donate(self, country_id: int, action: str, value: Union[int, float],
quality: int = None) -> Response:
json = dict(countryId=country, action=action, _token=self.token, value=value, quality=quality)
return self.post("{}/main/country-donate".format(self.url), data=json,
headers={"Referer": "{}/country/economy/Latvia".format(self.url)})
data = dict(countryId=country_id, action=action, _token=self.token, value=value, quality=quality)
return self.post(f"{self.url}/main/country-donate", data=data,
headers={"Referer": f"{self.url}/country/economy/Latvia"})
class ErepublikEconomyAPI(CitizenBaseAPI):
def _get_economy_citizen_accounts(self, organisation_id: int) -> Response:
return self.get("{}/economy/citizen-accounts/{}".format(self.url, organisation_id))
return self.get(f"{self.url}/economy/citizen-accounts/{organisation_id}")
def _get_economy_my_market_offers(self) -> Response:
return self.get("{}/economy/myMarketOffers".format(self.url))
return self.get(f"{self.url}/economy/myMarketOffers")
def _get_main_job_data(self) -> Response:
return self.get("{}/main/job-data".format(self.url))
return self.get(f"{self.url}/main/job-data")
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)
return self.post("{}/main/buyGoldItems".format(self.url), data=data)
return self.post(f"{self.url}/main/buyGoldItems", data=data)
def _post_economy_activate_booster(self, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, fromInventory=True)
return self.post("{}/economy/activateBooster".format(self.url), data=data)
return self.post(f"{self.url}/economy/activateBooster", data=data)
def _post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
return self.post("{}/economy/activateHouse".format(self.url), data=data)
return self.post(f"{self.url}/economy/activateHouse", data=data)
def _post_economy_donate_items_action(self, citizen: int, amount: int, industry: int,
def _post_economy_donate_items_action(self, citizen_id: int, amount: int, industry: int,
quality: int) -> Response:
data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post("{}/economy/donate-items-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-items/{}".format(self.url, citizen)})
data = dict(citizen_id=citizen_id, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post(f"{self.url}/economy/donate-items-action", data=data,
headers={"Referer": f"{self.url}/economy/donate-items/{citizen_id}"})
def _post_economy_donate_money_action(self, citizen: int, amount: float = 0.0,
def _post_economy_donate_money_action(self, citizen_id: int, amount: float = 0.0,
currency: int = 62) -> Response:
data = dict(citizen_id=citizen, _token=self.token, currency_id=currency, amount=amount)
return self.post("{}/economy/donate-money-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-money/{}".format(self.url, citizen)})
data = dict(citizen_id=citizen_id, _token=self.token, currency_id=currency, amount=amount)
return self.post(f"{self.url}/economy/donate-money-action", data=data,
headers={"Referer": f"{self.url}/economy/donate-money/{citizen_id}"})
def _post_economy_exchange_purchase(self, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=self.token, amount=amount, currencyId=currency, offerId=offer)
return self.post("{}/economy/exchange/purchase/".format(self.url), data=data)
return self.post(f"{self.url}/economy/exchange/purchase/", data=data)
def _post_economy_exchange_retrieve(self, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=self.token, personalOffers=int(personal), page=page, currencyId=currency)
return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data)
return self.post(f"{self.url}/economy/exchange/retrieve/", data=data)
def _post_economy_game_tokens_market(self, action: str) -> Response:
assert action in ['retrieve', ]
data = dict(_token=self.token, action=action)
return self.post("{}/economy/gameTokensMarketAjax".format(self.url), data=data)
return self.post(f"{self.url}/economy/gameTokensMarketAjax", data=data)
def _post_economy_marketplace(self, country: int, industry: int, quality: int,
order_asc: bool = True) -> Response:
data = dict(countryId=country, industryId=industry, quality=quality, ajaxMarket=1,
orderBy="price_asc" if order_asc else "price_desc", _token=self.token)
return self.post("{}/economy/marketplaceAjax".format(self.url), data=data)
return self.post(f"{self.url}/economy/marketplaceAjax", data=data)
def _post_economy_marketplace_actions(self, amount: int, buy: bool = False, **kwargs) -> Response:
if buy:
data = dict(_token=self.token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1,
buyAction=1)
else:
data = dict(_token=self.token, countryId=kwargs["country"], price=kwargs["price"],
data = dict(_token=self.token, countryId=kwargs["country_id"], price=kwargs["price"],
industryId=kwargs["industry"], quality=kwargs["quality"], amount=amount, sellAction='postOffer')
return self.post("{}/economy/marketplaceActions".format(self.url), data=data)
return self.post(f"{self.url}/economy/marketplaceActions", data=data)
class ErepublikLeaderBoardAPI(CitizenBaseAPI):
def _get_main_leaderboards_damage_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu)
return self.get("{}/main/leaderboards-damage-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def _get_main_leaderboards_damage_aircraft_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-damage-aircraft-rankings/{country_id}/{weeks}/{mu_id}/0")
def _get_main_leaderboards_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0,
div: int = 0) -> Response:
data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-damage-rankings/{}/{}/{}/{}".format(self.url, *data))
def _get_main_leaderboards_damage_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0, div: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-damage-rankings/{country_id}/{weeks}/{mu_id}/{div}")
def _get_main_leaderboards_kills_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu)
return self.get("{}/main/leaderboards-kills-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def _get_main_leaderboards_kills_aircraft_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-kills-aircraft-rankings/{country_id}/{weeks}/{mu_id}/0")
def _get_main_leaderboards_kills_rankings(self, country: int, weeks: int = 0, mu: int = 0,
div: int = 0) -> Response:
data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-kills-rankings/{}/{}/{}/{}".format(self.url, *data))
def _get_main_leaderboards_kills_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0, div: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-kills-rankings/{country_id}/{weeks}/{mu_id}/{div}")
class ErepublikLocationAPI(CitizenBaseAPI):
def _get_main_city_data_residents(self, city: int, page: int = 1, params: Mapping[str, Any] = None) -> Response:
def _get_main_city_data_residents(self, city_id: int, page: int = 1, params: Mapping[str, Any] = None) -> Response:
if params is None:
params = {}
return self.get("{}/main/city-data/{}/residents".format(self.url, city), params={"currentPage": page, **params})
return self.get(f"{self.url}/main/city-data/{city_id}/residents", params={"currentPage": page, **params})
class ErepublikMilitaryAPI(CitizenBaseAPI):
def _get_military_battlefield_choose_side(self, battle: int, side: int) -> Response:
return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side))
def _get_military_battlefield_choose_side(self, battle_id: int, side_id: int) -> Response:
return self.get(f"{self.url}/military/battlefield-choose-side/{battle_id}/{side_id}")
def _get_military_show_weapons(self, battle: int) -> Response:
return self.get("{}/military/show-weapons".format(self.url), params={'_token': self.token, 'battleId': battle})
def _get_military_show_weapons(self, battle_id: int) -> Response:
return self.get(f"{self.url}/military/show-weapons", params={'_token': self.token, 'battleId': battle_id})
def _get_military_campaigns(self) -> Response:
return self.get("{}/military/campaigns-new/".format(self.url))
return self.get(f"{self.url}/military/campaigns-new/")
def _get_military_campaigns_json_list(self) -> Response:
return self.get("{}/military/campaignsJson/list".format(self.url))
return self.get(f"{self.url}/military/campaignsJson/list")
def _get_military_campaigns_json_citizen(self) -> Response:
return self.get("{}/military/campaignsJson/citizen".format(self.url))
return self.get(f"{self.url}/military/campaignsJson/citizen")
def _get_military_unit_data(self, unit_id: int, **kwargs) -> Response:
params = {"groupId": unit_id, "panel": "members", **kwargs}
return self.get("{}/military/military-unit-data/".format(self.url), params=params)
return self.get(f"{self.url}/military/military-unit-data/", params=params)
def _post_main_activate_battle_effect(self, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=self.token)
return self.post("{}/main/fight-activateBattleEffect".format(self.url), data=data)
def _post_main_activate_battle_effect(self, battle_id: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle_id, citizenId=citizen_id, type=kind, _token=self.token)
return self.post(f"{self.url}/main/fight-activateBattleEffect", data=data)
def _post_main_battlefield_travel(self, side_id: int, battle_id: int) -> Response:
data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id)
return self.post("{}/main/battlefieldTravel".format(self.url), data=data)
return self.post(f"{self.url}/main/battlefieldTravel", 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)
return self.post(f"{self.url}/main/battlefieldTravel", data=data)
def _get_wars_show(self, war_id: int) -> Response:
return self.get("{}/wars/show/{}".format(self.url, war_id))
return self.get(f"{self.url}/wars/show/{war_id}")
def _post_military_fight_activate_booster(self, battle: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token)
return self.post("{}/military/fight-activateBooster".format(self.url), data=data)
def _post_military_fight_activate_booster(self, battle_id: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle_id, _token=self.token)
return self.post(f"{self.url}/military/fight-activateBooster", data=data)
def _post_military_change_weapon(self, battle: int, battle_zone: int, weapon_level: int, ) -> Response:
data = dict(battleId=battle, _token=self.token, battleZoneId=battle_zone, customizationLevel=weapon_level)
return self.post("{}/military/change-weapon".format(self.url), data=data)
def _post_military_change_weapon(self, battle_id: int, battle_zone: int, weapon_level: int, ) -> Response:
data = dict(battleId=battle_id, _token=self.token, battleZoneId=battle_zone, customizationLevel=weapon_level)
return self.post(f"{self.url}/military/change-weapon", data=data)
def _post_military_battle_console(self, battle_id: int, action: str, page: int = 1, **kwargs) -> Response:
data = dict(battleId=battle_id, action=action, _token=self.token)
@ -417,19 +425,19 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
division=kwargs["division"], type=kwargs.get("type", 'damage'), )
elif action == "warList":
data.update(page=page)
return self.post("{}/military/battle-console".format(self.url), data=data)
return self.post(f"{self.url}/military/battle-console", data=data)
def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response:
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(f"{self.url}/military/deploy-bomb", data=data)
def _post_military_fight_air(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data)
return self.post(f"{self.url}/military/fight-shoooot/{battle_id}", data=data)
def _post_military_fight_ground(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data)
return self.post(f"{self.url}/military/fight-shooot/{battle_id}", data=data)
def _post_fight_deploy_deploy_report_data(self, deployment_id: int):
data = dict(_token=self.token, deploymentId=deployment_id)
@ -438,21 +446,28 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
class ErepublikPoliticsAPI(CitizenBaseAPI):
def _get_candidate_party(self, party_slug: str) -> Response:
return self.post("{}/candidate/{}".format(self.url, party_slug))
return self.get(f"{self.url}/candidate/{party_slug}")
def _get_main_party_members(self, party: int) -> Response:
return self.get("{}/main/party-members/{}".format(self.url, party))
def _get_main_party_members(self, party_id: int) -> Response:
return self.get(f"{self.url}/main/party-members/{party_id}")
def _get_main_rankings_parties(self, country: int) -> Response:
return self.get("{}/main/rankings-parties/1/{}".format(self.url, country))
def _get_main_rankings_parties(self, country_id: int) -> Response:
return self.get(f"{self.url}/main/rankings-parties/1/{country_id}")
def _post_candidate_for_congress(self, presentation: str = "") -> Response:
data = dict(_token=self.token, presentation=presentation)
return self.post("{}/candidate-for-congress".format(self.url), data=data)
return self.post(f"{self.url}/candidate-for-congress", data=data)
def _get_presidential_elections(self, country_id: int, timestamp: int) -> Response:
return self.get(f"{self.url}/main/presidential-elections/{country_id}/{timestamp}")
def _post_propose_president_candidate(self, party_slug: str, citizen_id: int) -> Response:
return self.post(f"{self.url}/propose-president-candidate/{party_slug}",
data=dict(_token=self.token, citizen=citizen_id))
def _get_auto_propose_president_candidate(self, party_slug: str) -> Response:
return self.get(f"{self.url}/auto-propose-president-candidate/{party_slug}")
class ErepublikPresidentAPI(CitizenBaseAPI):
def _post_wars_attack_region(self, war_id: int, region_id: int, region_name: str) -> Response:
@ -462,50 +477,50 @@ 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=constants.COUNTRIES[attack_country_id].link)
return self.post("{}/{}/new-war".format(self.url, constants.COUNTRIES[self_country_id].link), data=data)
return self.post(f"{self.url}/{constants.COUNTRIES[self_country_id].link}/new-war", 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, constants.COUNTRIES[country_id].link), data=data)
return self.post(f"{self.url}/{constants.COUNTRIES[country_id].link}/new-donation", data=data)
class ErepublikProfileAPI(CitizenBaseAPI):
def _get_main_citizen_hovercard(self, citizen: int) -> Response:
return self.get("{}/main/citizen-hovercard/{}".format(self.url, citizen))
def _get_main_citizen_hovercard(self, citizen_id: int) -> Response:
return self.get(f"{self.url}/main/citizen-hovercard/{citizen_id}")
def _get_main_citizen_profile_json(self, player_id: int) -> Response:
return self.get("{}/main/citizen-profile-json/{}".format(self.url, player_id))
def _get_main_citizen_profile_json(self, citizen_id: int) -> Response:
return self.get(f"{self.url}/main/citizen-profile-json/{citizen_id}")
def _get_main_citizen_notifications(self) -> Response:
return self.get("{}/main/citizenDailyAssistant".format(self.url))
return self.get(f"{self.url}/main/citizenDailyAssistant")
def _get_main_citizen_daily_assistant(self) -> Response:
return self.get("{}/main/citizenNotifications".format(self.url))
return self.get(f"{self.url}/main/citizenNotifications")
def _get_main_messages_paginated(self, page: int = 1) -> Response:
return self.get("{}/main/messages-paginated/{}".format(self.url, page))
return self.get(f"{self.url}/main/messages-paginated/{page}")
def _get_main_money_donation_accept(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": self.token})
return self.get(f"{self.url}/main/money-donation/accept/{donation_id}", params={"_token": self.token})
def _get_main_money_donation_reject(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": self.token})
return self.get(f"{self.url}/main/money-donation/reject/{donation_id}", params={"_token": self.token})
def _get_main_notifications_ajax_community(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/community/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/community/{page}")
def _get_main_notifications_ajax_system(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/system/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/system/{page}")
def _get_main_notifications_ajax_report(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/report/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/report/{page}")
def _get_main_training_grounds_json(self) -> Response:
return self.get("{}/main/training-grounds-json".format(self.url))
return self.get(f"{self.url}/main/training-grounds-json")
def _get_main_weekly_challenge_data(self) -> Response:
return self.get("{}/main/weekly-challenge-data".format(self.url))
return self.get(f"{self.url}/main/weekly-challenge-data")
def _post_main_citizen_add_remove_friend(self, citizen: int, add: bool) -> Response:
data = dict(_token=self.token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend")
@ -513,60 +528,60 @@ class ErepublikProfileAPI(CitizenBaseAPI):
data.update({"action": "addFriend"})
else:
data.update({"action": "removeFriend"})
return self.post("{}/main/citizen-addRemoveFriend".format(self.url), data=data)
return self.post(f"{self.url}/main/citizen-addRemoveFriend", data=data)
def _post_main_daily_task_reward(self) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token))
return self.post(f"{self.url}/main/daily-tasks-reward", data=dict(_token=self.token))
def _post_delete_message(self, msg_id: list) -> Response:
data = {"_token": self.token, "delete_message[]": msg_id}
return self.post("{}/main/messages-delete".format(self.url), data)
return self.post(f"{self.url}/main/messages-delete", data)
def _post_eat(self, color: str) -> Response:
data = dict(_token=self.token, buttonColor=color)
return self.post("{}/main/eat".format(self.url), params=data)
return self.post(f"{self.url}/main/eat", params=data)
def _post_main_global_alerts_close(self, alert_id: int) -> Response:
data = dict(_token=self.token, alert_id=alert_id)
return self.post("{}/main/global-alerts/close".format(self.url), data=data)
return self.post(f"{self.url}/main/global-alerts/close", data=data)
def _post_forgot_password(self, email: str) -> Response:
data = dict(_token=self.token, email=email, commit="Reset password")
return self.post("{}/forgot-password".format(self.url), data=data)
return self.post(f"{self.url}/forgot-password", data=data)
def _post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on')
return self.post("{}/login".format(self.url), data=data)
return self.post(f"{self.url}/login", data=data)
def _post_main_messages_alert(self, notification_ids: List[int]) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"}
return self.post("{}/main/messages-alerts/1".format(self.url), data=data)
return self.post(f"{self.url}/main/messages-alerts/1", data=data)
def _post_main_notifications_ajax_community(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/community/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/community/{page}", data=data)
def _post_main_notifications_ajax_system(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/system/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/system/{page}", data=data)
def _post_main_notifications_ajax_report(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/report/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/report/{page}", data=data)
def _post_main_messages_compose(self, subject: str, body: str, citizens: List[int]) -> Response:
url_pk = 0 if len(citizens) > 1 else str(citizens[0])
data = dict(citizen_name=",".join([str(x) for x in citizens]),
citizen_subject=subject, _token=self.token, citizen_message=body)
return self.post("{}/main/messages-compose/{}".format(self.url, url_pk), data=data)
return self.post(f"{self.url}/main/messages-compose/{url_pk}", data=data)
def _post_military_group_missions(self) -> Response:
data = dict(action="check", _token=self.token)
return self.post("{}/military/group-missions".format(self.url), data=data)
return self.post(f"{self.url}/military/group-missions", data=data)
def _post_main_weekly_challenge_reward(self, reward_id: int) -> Response:
data = dict(_token=self.token, rewardId=reward_id)
return self.post("{}/main/weekly-challenge-collect-reward".format(self.url), data=data)
return self.post(f"{self.url}/main/weekly-challenge-collect-reward", data=data)
def _post_main_profile_update(self, action: str, params: str):
data = {"action": action, "params": params, "_token": self.token}
@ -576,10 +591,10 @@ class ErepublikProfileAPI(CitizenBaseAPI):
class ErepublikTravelAPI(CitizenBaseAPI):
def _post_main_travel(self, check: str, **kwargs) -> Response:
data = dict(_token=self.token, check=check, **kwargs)
return self.post("{}/main/travel".format(self.url), data=data)
return self.post(f"{self.url}/main/travel", data=data)
def _post_main_travel_data(self, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs))
return self.post(f"{self.url}/main/travelData", data=dict(_token=self.token, **kwargs))
class ErepublikWallPostAPI(CitizenBaseAPI):
@ -587,78 +602,78 @@ class ErepublikWallPostAPI(CitizenBaseAPI):
def _post_main_country_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/country-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-comment/retrieve/json", data=data)
def _post_main_country_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/country-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-comment/create/json", data=data)
def _post_main_country_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/country-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-post/create/json", data=data)
def _post_main_country_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/country-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-post/retrieve/json", data=data)
# ## Military Unit
def _post_main_military_unit_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/military-unit-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-comment/retrieve/json", data=data)
def _post_main_military_unit_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/military-unit-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-comment/create/json", data=data)
def _post_main_military_unit_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/military-unit-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-post/create/json", data=data)
def _post_main_military_unit_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/military-unit-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-post/retrieve/json", data=data)
# ## Party
def _post_main_party_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/party-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-comment/retrieve/json", data=data)
def _post_main_party_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/party-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-comment/create/json", data=data)
def _post_main_party_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/party-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-post/create/json", data=data)
def _post_main_party_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/party-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-post/retrieve/json", data=data)
# ## Friend's Wall
def _post_main_wall_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/wall-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-comment/retrieve/json", data=data)
def _post_main_wall_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/wall-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-comment/create/json", data=data)
def _post_main_wall_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/wall-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-post/create/json", data=data)
def _post_main_wall_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-post/retrieve/json", data=data)
# ## Medal posting
def _post_main_wall_post_automatic(self, message: str, achievement_id: int) -> Response:
return self.post("{}/main/wall-post/automatic".format(self.url), data=dict(_token=self.token, message=message,
achievementId=achievement_id))
return self.post(f"{self.url}/main/wall-post/automatic", data=dict(_token=self.token, message=message,
achievementId=achievement_id))
class CitizenAPI(

View File

@ -393,7 +393,7 @@ class BaseCitizen(access_points.CitizenAPI):
sleep(seconds)
def to_json(self, indent: bool = False) -> str:
return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None)
def get_countries_with_regions(self) -> Set[constants.Country]:
r_json = self._post_main_travel_data().json()
@ -624,8 +624,16 @@ class BaseCitizen(access_points.CitizenAPI):
self.sleep(5 * 60)
else:
raise classes.ErepublikException(f"HTTP {response.status_code} error!")
if re.search(r'Occasionally there are a couple of things which we need to check or to implement in order make '
r'your experience in eRepublik more pleasant. <strong>Don\'t worry about ongoing battles, timer '
r'will be stopped during maintenance.</strong>', response.text):
self.write_log("eRepublik ss having maintenance. Sleeping for 5 minutes")
self.sleep(5 * 60)
return True
return bool(re.search(r'body id="error"|Internal Server Error|'
r'CSRF attack detected|meta http-equiv="refresh"|not_authenticated', response.text))
r'CSRF attack detected|meta http-equiv="refresh"|'
r'not_authenticated', response.text))
def _report_action(self, action: str, msg: str, **kwargs: Optional[Dict[str, Any]]):
""" Report action to all available reporting channels
@ -695,6 +703,17 @@ class CitizenTravel(BaseCitizen):
self.details.current_region = region_id
self.details.current_country = country
def _travel(self, country: constants.Country, region_id: int = 0) -> bool:
r_json = super()._travel(country, region_id).json()
if not bool(r_json.get('error')):
self._update_citizen_location(country, region_id)
return True
else:
if "Travelling too fast." in r_json.get('message'):
self.sleep(1)
return self._travel(country, region_id)
return False
def get_country_travel_region(self, country: constants.Country) -> int:
regions = self.get_travel_regions(country=country)
regs = []
@ -711,12 +730,12 @@ class CitizenTravel(BaseCitizen):
self.update_citizen_info()
res_r = self.details.residence_region
if self.details.residence_country and res_r and not res_r == self.details.current_region:
r_json = self._travel(self.details.residence_country, self.details.residence_region).json()
if r_json.get('message', '') == 'success':
self._update_citizen_location(self.details.residence_country, self.details.current_region)
self._report_action("TRAVEL", "Traveled to residence", response=r_json)
if self._travel(self.details.residence_country, self.details.residence_region):
self._report_action("TRAVEL", "Traveled to residence")
return True
return False
else:
self._report_action("TRAVEL", "Unable to travel to residence!")
return False
return True
def travel_to_region(self, region_id: int) -> bool:
@ -725,12 +744,14 @@ class CitizenTravel(BaseCitizen):
return True
else:
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)
self._report_action("TRAVEL", "Traveled to region", response=r_json)
if self._travel(country, region_id):
self._report_action("TRAVEL", "Traveled to region")
return True
return False
else:
self._report_action("TRAVEL", "Unable to travel to region!")
return False
def travel_to_country(self, country: constants.Country) -> bool:
data = self._post_main_travel_data(countryId=country.id, check="getCountryRegions").json()
@ -742,11 +763,13 @@ class CitizenTravel(BaseCitizen):
regs.append((region['id'], region['distanceInKm']))
if regs:
region_id = min(regs, key=lambda _: int(_[1]))[0]
r_json = self._travel(country, region_id).json()
if r_json.get('message', '') == 'success':
self._update_citizen_location(country, region_id)
self._report_action("TRAVEL", f"Traveled to {country.name}", response=r_json)
if self._travel(country, region_id):
self._report_action("TRAVEL", f"Traveled to {country.name}")
return True
else:
self._report_action("TRAVEL", f"Unable to travel to {country.name}!")
return False
def travel_to_holding(self, holding: classes.Holding) -> bool:
@ -756,15 +779,36 @@ class CitizenTravel(BaseCitizen):
else:
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':
self._update_citizen_location(country, region_id)
self._report_action("TRAVEL", f"Traveled to holding {holding}", response=r_json)
return True
return False
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]]]:
if self._travel(country, region_id):
self._report_action("TRAVEL", f"Traveled to {holding}")
return True
else:
self._report_action("TRAVEL", f"Unable to travel to {holding}!")
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, 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
regs.append((region['distanceInKm'], region['id'], countries[region['countryId']]))
if regs:
reg = min(regs, key=lambda _: int(_[0]))
region_id = reg[1]
country = reg[2]
if self._travel(country, region_id):
self._report_action("TRAVEL", f"Traveled to {battle}")
return True
else:
self._report_action("TRAVEL", f"Unable to travel to {battle}!")
return False
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,
battleId=battle.id if battle else 0,
@ -797,23 +841,21 @@ class CitizenCompanies(BaseCitizen):
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: classes.Holding = None) -> Optional[Dict[str, Any]]:
def _work_as_manager(self, wam_holding: classes.Holding) -> Optional[Dict[str, Any]]:
if self.restricted_ip:
return None
self.update_companies()
self.update_inventory()
data = {"action_type": "production"}
extra = {}
wam_list = []
if wam_holding:
raw_factories = wam_holding.get_wam_companies(raw_factory=True)
fin_factories = wam_holding.get_wam_companies(raw_factory=False)
raw_factories = wam_holding.get_wam_companies(raw_factory=True)
fin_factories = wam_holding.get_wam_companies(raw_factory=False)
free_inventory = self.inventory["total"] - self.inventory["used"]
wam_list = raw_factories + fin_factories
wam_list = wam_list[:self.energy.food_fights]
while wam_list and free_inventory < self.my_companies.get_needed_inventory_usage(wam_list):
wam_list.pop(-1)
free_inventory = self.inventory["total"] - self.inventory["used"]
wam_list = raw_factories + fin_factories
wam_list = wam_list[:self.energy.food_fights]
while wam_list and free_inventory < self.my_companies.get_needed_inventory_usage(wam_list):
wam_list.pop(-1)
if wam_list:
data.update(extra)
@ -840,6 +882,8 @@ 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)))
self.reporter.report_action('COMPANIES', json_val=self.my_companies.as_dict)
def assign_company_to_holding(self, company: classes.Company, holding: classes.Holding) -> Response:
"""
Assigns factory to new holding
@ -980,7 +1024,7 @@ class CitizenEconomy(CitizenTravel):
self.write_log(f"Trying to sell unsupported industry {industry}")
data = {
"country": self.details.citizenship,
"country_id": self.details.citizenship.id,
"industry": industry,
"quality": quality,
"amount": amount,
@ -1035,7 +1079,7 @@ class CitizenEconomy(CitizenTravel):
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, constants.INDUSTRIES[product_name], q).json()
r = self._post_economy_marketplace(country.id, constants.INDUSTRIES[product_name], q).json()
obj = offers[f"q{q}"]
if not r.get("error", False):
for offer in r["offers"]:
@ -1104,7 +1148,6 @@ class CitizenEconomy(CitizenTravel):
self.details.gold = float(response.json().get("gold").get("value"))
if response.json().get('error'):
self._report_action("BUY_GOLD", "Unable to buy gold!", kwargs=response.json())
self.stop_threads.wait()
return False
else:
self._report_action('BUY_GOLD', f'New amount {self.details.cc}cc, {self.details.gold}g',
@ -1161,9 +1204,9 @@ class CitizenEconomy(CitizenTravel):
if self.details.cc < amount or amount < 20:
return False
data = dict(country=country.id, action='currency', value=amount)
r = self._post_main_country_donate(**data)
r = self._post_main_country_donate(country.id, 'currency', amount)
if r.json().get('status') or not r.json().get('error'):
self._report_action("CONTRIBUTE_CC", f'Contributed {amount}cc to {country}\'s treasury')
self._report_action("CONTRIBUTE_CC", f'Contributed {amount}cc to {country}\'s treasury', kwargs=data)
return True
else:
self._report_action("CONTRIBUTE_CC", f"Unable to contribute {amount}cc to {country}'s"
@ -1176,11 +1219,11 @@ class CitizenEconomy(CitizenTravel):
if self.food["q" + str(quality)] < amount or amount < 10:
return False
data = dict(country=country.id, action='food', value=amount, quality=quality)
r = self._post_main_country_donate(**data)
r = self._post_main_country_donate(country.id, 'currency', amount, quality)
if r.json().get('status') or not r.json().get('error'):
self._report_action("CONTRIBUTE_FOOD", f"Contributed {amount}q{quality} food to "
f"{country}'s treasury")
f"{country}'s treasury", kwargs=data)
return True
else:
self._report_action("CONTRIBUTE_FOOD", f"Unable to contribute {amount}q{quality} food to "
@ -1193,11 +1236,10 @@ class CitizenEconomy(CitizenTravel):
if self.details.cc < amount:
return False
data = dict(country=country.id, action='gold', value=amount)
self.reporter.report_action("CONTRIBUTE_GOLD", data, str(amount))
r = self._post_main_country_donate(**data)
r = self._post_main_country_donate(country.id, 'gold', amount)
if r.json().get('status') or not r.json().get('error'):
self._report_action("CONTRIBUTE_GOLD", f"Contributed {amount}g to {country}'s treasury")
self._report_action("CONTRIBUTE_GOLD", f"Contributed {amount}g to {country}'s treasury", kwargs=data)
return True
else:
self._report_action("CONTRIBUTE_GOLD", f"Unable to contribute {amount}g to {country}'s"
@ -1279,9 +1321,6 @@ class CitizenMilitary(CitizenTravel):
boosters: Dict[int, Dict[int, int]] = {100: {}, 50: {}}
def update_war_info(self):
if not self.details.current_country:
self.update_citizen_info()
if self.__last_war_update_data and self.__last_war_update_data.get('last_updated',
0) + 30 > self.now.timestamp():
r_json = self.__last_war_update_data
@ -1306,7 +1345,10 @@ class CitizenMilitary(CitizenTravel):
all_battles = {}
for battle_data in r_json.get("battles", {}).values():
all_battles[battle_data.get('id')] = classes.Battle(battle_data)
old_all_battles = self.all_battles
self.all_battles = all_battles
for battle in old_all_battles.values():
utils._clear_up_battle_memory(battle)
def get_battle_for_war(self, war_id: int) -> Optional[classes.Battle]:
self.update_war_info()
@ -1481,35 +1523,33 @@ class CitizenMilitary(CitizenTravel):
ret_battles = ret_battles + cs_battles + deployed_battles + other_battles
return ret_battles
def get_cheap_tp_divisions(self) -> Optional[classes.BattleDivision]:
air_divs: List[Tuple[classes.BattleDivision, int]] = []
ground_divs: List[Tuple[classes.BattleDivision, int]] = []
def get_cheap_tp_divisions(self) -> Dict[str, List[Tuple[int, classes.BattleDivision]]]:
air_divs: List[Tuple[int, classes.BattleDivision]] = []
ground_divs: List[Tuple[int, classes.BattleDivision]] = []
for battle in reversed(self.sorted_battles(True, True)):
for division in battle.div.values():
if not division.terrain:
is_start_ok = utils.good_timedelta(division.battle.start, timedelta(minutes=-1)) < self.now
if not division.terrain and is_start_ok and not division.div_end:
if division.is_air and self.config.air:
medal = self.get_battle_round_data(division)[
self.details.citizenship == division.battle.defender.id]
if not medal and division.battle.start:
return division
division_medals = self.get_battle_round_data(division)
medal = division_medals[self.details.citizenship == division.battle.defender.country]
if not medal:
air_divs.append((0, division))
else:
air_divs.append((division, medal.get('1').get('raw_value')))
elif self.config.ground:
air_divs.append((medal.get('1').get('raw_value'), division))
elif not division.is_air and self.config.ground:
if not division.div == self.division and not self.maverick:
continue
division_medals = self.get_battle_round_data(division)
medal = division_medals[self.details.citizenship == division.battle.defender.country]
if not medal and division.battle.start:
return division
if not medal:
ground_divs.append((0, division))
else:
ground_divs.append((division, medal.get('1').get('raw_value')))
ground_divs.append((medal.get('1').get('raw_value'), division))
if self.config.air:
return min(air_divs, key=lambda x: x[1])[0]
elif self.config.ground:
return min(ground_divs, key=lambda x: x[1])[0]
else:
return
air_divs.sort(key=lambda z: (z[0], z[1].battle.start))
ground_divs.sort(key=lambda z: (z[0], z[1].battle.start))
return {'air': air_divs, 'ground': ground_divs}
@property
def has_battle_contribution(self):
@ -1576,14 +1616,15 @@ class CitizenMilitary(CitizenTravel):
self.travel_to_residence()
break
def fight(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.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.
:param battle: Battle battle to fight in
:type battle: Battle
:param side: BattleSide or None. Battle side to fight in, If side not == invader id or not in invader deployed
allies list, then defender's side is chosen
allies list, then defender's side is chosen
:type side: BattleSide
:param count: How many hits to do, if not specified self.should_fight() is called.
:type count: int
@ -1622,8 +1663,11 @@ class CitizenMilitary(CitizenTravel):
self.write_log("Hits: {:>4} | Damage: {}".format(total_hits, total_damage))
ok_to_fight = False
if total_damage:
self.reporter.report_action("FIGHT", dict(battle=battle, side=side, dmg=total_damage,
air=battle.has_air, hits=total_hits))
self.reporter.report_fighting(battle, not side.is_defender, division, total_damage, total_hits)
# self.reporter.report_action('FIGHT', dict(battle_id=battle.id, side=side, dmg=total_damage,
# air=battle.has_air, hits=total_hits,
# round=battle.zone_id,
# extra=dict(battle=battle, side=side)))
return error_count
def _shoot(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide):
@ -1730,7 +1774,8 @@ class CitizenMilitary(CitizenTravel):
if resp.json().get('error'):
self.write_log(resp.json().get('message'))
return False
self._report_action("MILITARY_DIV_SWITCH", f"Switched to d{division.div} in battle {battle.id}", kwargs=resp.json())
self._report_action("MILITARY_DIV_SWITCH", f"Switched to d{division.div} in battle {battle.id}",
kwargs=resp.json())
return True
def get_ground_hit_dmg_value(self, rang: int = None, strength: float = None, elite: bool = None, ne: bool = False,
@ -1865,9 +1910,9 @@ class CitizenMilitary(CitizenTravel):
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,
battleZoneId=division.id, type="damage")
r = self._post_military_battle_console(battle.id, "battleStatistics", 1, **data)
r = self._post_military_battle_console(battle.id, "battleStatistics", 1,
zoneId=battle.zone_id, round_id=battle.zone_id, division=division.div,
battleZoneId=division.id, type="damage")
r_json = r.json()
return (r_json.get(str(battle.invader.id)).get("fighterData"),
r_json.get(str(battle.defender.id)).get("fighterData"))
@ -1895,25 +1940,6 @@ 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: classes.Battle, allowed_countries: List[constants.Country]) -> bool:
data = self.get_travel_regions(battle=battle)
regs = []
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
regs.append((region['distanceInKm'], region['id'], countries[region['countryId']]))
if regs:
reg = min(regs, key=lambda _: int(_[0]))
region_id = reg[1]
country = reg[2]
r = self._travel(country, region_id).json()
if r.get('message', '') == 'success':
self._update_citizen_location(country, region_id)
return True
return False
def get_country_mus(self, country: constants.Country) -> Dict[int, str]:
ret = {}
r = self._get_main_leaderboards_damage_rankings(country.id)
@ -1944,12 +1970,18 @@ class CitizenMilitary(CitizenTravel):
mu_id = profile.get('military', {}).get('militaryUnit', {}).get('id', 0)
if mu_id:
name = profile.get('citizen', {}).get('name')
params = dict(currentPage=1, panel="members", sortBy="dailyOrdersCompleted",
weekFilter=f"week{weeks_ago}", search=name)
member = self._get_military_unit_data(mu_id, **params).json()
member = self._get_military_unit_data(mu_id, currentPage=1, panel="members", sortBy="dailyOrdersCompleted",
weekFilter=f"week{weeks_ago}", search=name).json()
return member.get('panelContents', {}).get('members', [{}])[0].get('dailyOrdersCompleted')
return 0
def get_possibly_empty_medals(self):
self.update_war_info()
for battle in self.all_battles.values():
for division in battle.div.values():
if division.wall['dom'] == 50 or division.wall['dom'] > 98:
yield division, division.wall['for'] == battle.invader.country.id
class CitizenPolitics(BaseCitizen):
def get_country_parties(self, country: constants.Country = None) -> dict:
@ -2195,20 +2227,19 @@ class CitizenTasks(BaseCitizen):
self._report_action('ECONOMY_TG_CONTRACT', 'Bought TG Contract', kwargs=extra)
return ret
def find_new_job(self) -> Response:
def find_new_job(self) -> bool:
r = self._get_economy_job_market_json(self.details.current_country.id)
jobs = r.json().get("jobs")
data = dict(citizen=0, salary=10)
data = dict(citizen_id=0, salary=10)
for posting in jobs:
salary = posting.get("salary")
limit = posting.get("salaryLimit", 0)
citizen_id = posting.get("citizen").get("id")
if (not limit or salary * 3 < limit) and salary > data["salary"]:
data.update({"citizen": citizen_id, "salary": salary})
data.update(citizen_id=citizen_id, salary=salary)
self._report_action("ECONOMY_APPLY_FOR_JOB", f"I'm working now for {str(data['citizen'])}", kwargs=r.json())
return self._post_economy_job_market_apply(**data)
return self.apply_to_employer(data['citizen_id'], data['salary'])
def apply_to_employer(self, employer_id: int, salary: float) -> bool:
data = dict(citizenId=employer_id, salary=salary)
@ -2323,11 +2354,11 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
self.reporter.report_action("NEW_MEDAL", info)
def set_debug(self, debug: bool):
self.debug = debug
self._req.debug = debug
self.debug = bool(debug)
self._req.debug = bool(debug)
def set_pin(self, pin: int):
self.details.pin = pin
self.details.pin = int(pin)
def update_all(self, force_update=False):
# Do full update max every 5 min
@ -2500,7 +2531,8 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
else:
if not start_place == (self.details.current_country, self.details.current_region):
self.travel_to_holding(holding)
return self._wam(holding)
self._wam(holding)
return
elif response.get("message") == "not_enough_health_food":
self.buy_food()
self._wam(holding)
@ -2516,7 +2548,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
:rtype: bool
"""
if self.restricted_ip:
self._report_action("IP_BLACKLISTED", "Fighting is not allowed from restricted IP!")
self._report_action("IP_BLACKLISTED", "Work as manager is not allowed from restricted IP!")
return False
self.update_citizen_info()
self.update_companies()
@ -2533,6 +2565,10 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
self.update_companies()
for holding in regions.values():
raw_usage = holding.get_wam_raw_usage()
if (raw_usage['frm'] + raw_usage['wrm']) * 100 + self.inventory['used'] > self.inventory['total']:
self._report_action('WAM_UNAVAILABLE', 'Not enough storage!')
continue
self.travel_to_holding(holding)
self._wam(holding)
self.update_companies()

View File

@ -1,8 +1,9 @@
import datetime
import hashlib
import threading
import weakref
from decimal import Decimal
from typing import Any, Dict, List, NamedTuple, Optional, Tuple, Union
from typing import Any, Dict, List, NamedTuple, Optional, Tuple, Union, NoReturn
from requests import Response, Session, post
@ -27,12 +28,23 @@ class Holding:
id: int
region: int
companies: List["Company"]
name: str
_citizen = weakref.ReferenceType
def __init__(self, _id: int, region: int, citizen):
self.citizen = citizen
def __init__(self, _id: int, region: int, citizen, name: str = None):
self._citizen = weakref.ref(citizen)
self.id: int = _id
self.region: int = region
self.companies: List["Company"] = list()
if name:
self.name = name
else:
name = f"Holding (#{self.id}) with {len(self.companies)} "
if len(self.companies) == 1:
name += "company"
else:
name += "companies"
self.name = name
@property
def wam_count(self) -> int:
@ -46,7 +58,7 @@ class Holding:
def employable_companies(self) -> List["Company"]:
return [company for company in self.companies if company.preset_works]
def add_company(self, company: "Company"):
def add_company(self, company: "Company") -> NoReturn:
self.companies.append(company)
self.companies.sort()
@ -60,7 +72,7 @@ class Holding:
wrm += company.raw_usage
return dict(frm=frm, wrm=wrm)
def get_wam_companies(self, raw_factory: bool = None):
def get_wam_companies(self, raw_factory: bool = None) -> Optional[List["Company"]]:
raw = []
factory = []
for company in self.wam_companies:
@ -78,7 +90,7 @@ class Holding:
else:
raise ErepublikException("raw_factory should be True/False/None")
def __str__(self):
def __str__(self) -> str:
name = f"Holding (#{self.id}) with {len(self.companies)} "
if len(self.companies) % 10 == 1:
name += "company"
@ -90,11 +102,17 @@ class Holding:
return str(self)
@property
def as_dict(self):
return dict(name=str(self), id=self.id, region=self.region, companies=self.companies, wam_count=self.wam_count)
def as_dict(self) -> Dict[str, Union[str, int, List[Dict[str, Union[str, int, bool, float, Decimal]]]]]:
return dict(name=self.name, id=self.id, region=self.region,
companies=[c.as_dict for c in self.companies], wam_count=self.wam_count)
@property
def citizen(self):
return self._citizen()
class Company:
_holding: weakref.ReferenceType
holding: Holding
id: int
quality: int
@ -113,7 +131,7 @@ class Company:
base_production: Decimal, wam_enabled: bool, can_wam: bool, cannot_wam_reason: str, industry: int,
already_worked: bool, preset_works: int
):
self.holding: Holding = holding
self._holding = weakref.ref(holding)
self.id: int = _id
self.industry: int = industry
self.quality: int = self._get_real_quality(quality)
@ -196,7 +214,7 @@ class Company:
return str(self)
@property
def as_dict(self):
def as_dict(self) -> Dict[str, Union[str, int, bool, float, Decimal]]:
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,
@ -211,6 +229,10 @@ class Company:
# noinspection PyProtectedMember
return self.holding.citizen._post_economy_upgrade_company(self.id, level, self.holding.citizen.details.pin)
@property
def holding(self) -> Holding:
return self._holding()
class MyCompanies:
work_units: int = 0
@ -218,13 +240,13 @@ class MyCompanies:
ff_lockdown: int = 0
holdings: Dict[int, Holding]
companies: List[Company]
companies: weakref.WeakSet
_citizen: weakref.ReferenceType
def __init__(self, citizen):
from erepublik import Citizen
self.citizen: Citizen = citizen
self._citizen = weakref.ref(citizen)
self.holdings: Dict[int, Holding] = dict()
self.companies: List[Company] = list()
self.companies: weakref.WeakSet = weakref.WeakSet()
self.next_ot_time = utils.now()
def prepare_holdings(self, holdings: Dict[str, Dict[str, Any]]):
@ -233,10 +255,11 @@ class MyCompanies:
"""
for holding in holdings.values():
if holding.get('id') not in self.holdings:
self.holdings.update(
{int(holding.get('id')): Holding(holding['id'], holding['region_id'], self.citizen)})
self.holdings.update({
int(holding.get('id')): Holding(holding['id'], holding['region_id'], self.citizen, holding['name'])
})
if not self.holdings.get(0):
self.holdings.update({0: Holding(0, 0, self.citizen)}) # unassigned
self.holdings.update({0: Holding(0, 0, self.citizen, 'Unassigned')}) # unassigned
def prepare_companies(self, companies: Dict[str, Dict[str, Any]]):
"""
@ -258,7 +281,7 @@ class MyCompanies:
company_dict.get('can_work_as_manager'), company_dict.get('cannot_work_as_manager_reason'),
company_dict.get('industry_id'), company_dict.get('already_worked'), company_dict.get('preset_works')
)
self.companies.append(company)
self.companies.add(company)
holding.add_company(company)
def get_employable_factories(self) -> Dict[int, int]:
@ -282,13 +305,21 @@ class MyCompanies:
def __clear_data(self):
for holding in self.holdings.values():
for company in holding.companies: # noqa
del company
holding.companies.clear()
self.companies.clear()
@property
def as_dict(self):
def as_dict(self) -> Dict[str, Union[str, int, datetime.datetime, Dict[str, Dict[str, Union[str, int, List[Dict[str, Union[str, int, bool, float, Decimal]]]]]]]]:
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))
ff_lockdown=self.ff_lockdown,
holdings={str(hi): h.as_dict for hi, h in self.holdings.items()},
company_count=len(self.companies))
@property
def citizen(self):
return self._citizen()
class Config:
@ -528,10 +559,13 @@ class Reporter:
queue=self.__to_update)
def __init__(self, citizen):
self.citizen = citizen
self._citizen = weakref.ref(citizen)
self._req = Session()
self.url = "https://api.erep.lv"
self._req.headers.update({"user-agent": "Bot reporter v2"})
self._req.headers.update({"user-agent": "eRepublik Script Reporter v3",
'erep-version': utils.__version__,
'erep-user-id': str(self.citizen_id),
'erep-user-name': self.citizen.name})
self.__to_update = []
self.__registered: bool = False
@ -541,6 +575,10 @@ class Reporter:
self.register_account()
self.allowed = True
@property
def citizen(self):
return self._citizen()
def __update_key(self):
self.key = hashlib.md5(bytes(f"{self.name}:{self.email}", encoding="UTF-8")).hexdigest()
@ -548,10 +586,10 @@ class Reporter:
if self.__to_update:
for unreported_data in self.__to_update:
unreported_data.update(player_id=self.citizen_id, key=self.key)
unreported_data = utils.json.load(utils.json.dumps(unreported_data, cls=MyJSONEncoder, sort_keys=True))
unreported_data = utils.json.loads(utils.json.dumps(unreported_data, cls=MyJSONEncoder))
self._req.post("{}/bot/update".format(self.url), json=unreported_data)
self.__to_update.clear()
data = utils.json.loads(utils.json.dumps(data, cls=MyJSONEncoder, sort_keys=True))
data = utils.json.loads(utils.json.dumps(data, cls=MyJSONEncoder))
r = self._req.post("{}/bot/update".format(self.url), json=data)
return r
@ -593,6 +631,12 @@ class Reporter:
else:
self.__to_update.append(json_data)
def report_fighting(self, battle: "Battle", invader: bool, division: "BattleDivision", damage: float, hits: int):
side = battle.invader if invader else battle.defender
self.report_action('FIGHT', dict(battle_id=battle.id, side=side, dmg=damage,
air=battle.has_air, hits=hits,
round=battle.zone_id, extra=dict(battle=battle, side=side, division=division)))
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))
@ -604,13 +648,13 @@ class Reporter:
except: # noqa
return []
def fetch_tasks(self) -> Optional[Tuple[str, Tuple[Any]]]:
def fetch_tasks(self) -> List[Union[str, Tuple[Any]]]:
try:
task_response = self._req.get(f'{self.url}/api/v1/command',
params=dict(citizen=self.citizen_id, key=self.key))
return task_response.json().get('task_collection')
except: # noqa
return
return []
class MyJSONEncoder(utils.json.JSONEncoder):
@ -645,28 +689,29 @@ class BattleSide:
deployed: List[constants.Country]
allies: List[constants.Country]
battle: "Battle"
_battle: weakref.ReferenceType
country: constants.Country
defender: bool
is_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._battle = weakref.ref(battle)
self.country = country
self.points = points
self.allies = allies
self.deployed = deployed
self.defender = defender
self.is_defender = defender
@property
def id(self) -> int:
return self.country.id
def __repr__(self):
side_text = "Defender" if self.defender else "Invader "
side_text = "Defender" if self.is_defender else "Invader "
return f"<BattleSide: {side_text} {self.country.name}|{self.points:02d}p>"
def __str__(self):
side_text = "Defender" if self.defender else "Invader "
side_text = "Defender" if self.is_defender else "Invader "
return f"{side_text} {self.country.name} - {self.points:02d} points"
def __format__(self, format_spec):
@ -674,8 +719,12 @@ class BattleSide:
@property
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))
return dict(points=self.points, country=self.country, is_defender=self.is_defender, allies=self.allies,
deployed=self.deployed)
@property
def battle(self):
return self._battle()
class BattleDivision:
@ -689,11 +738,12 @@ class BattleDivision:
terrain: int
div: int
battle: "Battle"
_battle: weakref.ReferenceType
@property
def as_dict(self):
return dict(id=self.id, division=self.div, terrain=(self.terrain, self.terrain_display), wall=self.wall,
epic=self.epic, battle=str(self.battle), end=self.div_end)
epic=self.epic, end=self.div_end)
@property
def is_air(self):
@ -715,7 +765,7 @@ class BattleDivision:
:type wall_for: int
:type wall_dom: float
"""
self.battle = battle
self._battle = weakref.ref(battle)
self.id = div_id
self.end = end
self.epic = epic
@ -738,6 +788,10 @@ class BattleDivision:
def __repr__(self):
return f"<BattleDivision #{self.id} (battle #{self.battle.id})>"
@property
def battle(self):
return self._battle()
class Battle:
id: int
@ -756,7 +810,7 @@ class Battle:
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])
region=[self.region_id, self.region_name], link=self.link)
@property
def has_air(self) -> bool:
@ -765,6 +819,10 @@ class Battle:
return True
return not bool(self.zone_id % 4)
@property
def has_started(self) -> bool:
return self.start <= utils.now()
@property
def has_ground(self) -> bool:
for div in self.div.values():
@ -888,7 +946,7 @@ class TelegramBot:
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))}
'initialized': self.__initialized, 'has_threads': not self._threads}
def do_init(self, chat_id: int, token: str, player_name: str = ""):
self.chat_id = chat_id

View File

@ -49,16 +49,16 @@ class Country:
class Industries:
__by_name = {'food': 1, 'weapons': 2, 'house': 4, 'aircraft': 23,
'foodRaw': 7, 'weaponRaw': 12, 'weaponsRaw': 12, 'houseRaw': 18, 'aircraftRaw': 24,
__by_name = {'food': 1, 'weapon': 2, 'house': 4, 'aircraft': 23,
'foodraw': 7, 'weaponraw': 12, 'houseraw': 18, 'aircraftraw': 24,
'frm': 7, 'wrm': 12, 'hrm': 18, 'arm': 24,
'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",
__by_id = {1: "Food", 2: "Weapon", 4: "House", 23: "Aircraft",
7: "foodRaw", 8: "FRM q2", 9: "FRM q3", 10: "FRM q4", 11: "FRM q5",
12: "weaponsRaw", 13: "WRM q2", 14: "WRM q3", 15: "WRM q4", 16: "WRM q5",
12: "weaponRaw", 13: "WRM q2", 14: "WRM q3", 15: "WRM q4", 16: "WRM q5",
18: "houseRaw", 19: "HRM q2", 20: "HRM q3", 21: "HRM q4", 22: "HRM q5",
24: "aircraftRaw", 25: "ARM q2", 26: "ARM q3", 27: "ARM q4", 28: "ARM q5"}

View File

@ -9,7 +9,7 @@ import traceback
import unicodedata
from decimal import Decimal
from pathlib import Path
from typing import Any, List, Mapping, Optional, Union
from typing import Any, List, Optional, Union, Dict
import requests
@ -42,12 +42,11 @@ def localize_timestamp(timestamp: int) -> datetime.datetime:
def localize_dt(dt: Union[datetime.date, datetime.datetime]) -> datetime.datetime:
try:
try:
return constants.erep_tz.localize(dt)
except AttributeError:
return constants.erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
except ValueError:
if isinstance(dt, datetime.datetime):
return constants.erep_tz.localize(dt)
elif isinstance(dt, datetime.date):
return constants.erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
else:
return dt.astimezone(constants.erep_tz)
@ -116,10 +115,12 @@ def _write_log(msg, timestamp: bool = True, should_print: bool = False):
def write_interactive_log(*args, **kwargs):
kwargs.pop("should_print", None)
_write_log(should_print=True, *args, **kwargs)
def write_silent_log(*args, **kwargs):
kwargs.pop("should_print", None)
_write_log(should_print=False, *args, **kwargs)
@ -177,7 +178,7 @@ def write_request(response: requests.Response, is_error: bool = False):
"mimetype": "application/json" if ext == "json" else "text/html"}
def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[Any, Any] = None,
def send_email(name: str, content: List[Any], player=None, local_vars: Dict[str, Any] = None,
promo: bool = False, captcha: bool = False):
if local_vars is None:
local_vars = {}
@ -220,8 +221,16 @@ def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[A
if local_vars:
if "state_thread" in local_vars:
local_vars.pop('state_thread', None)
if isinstance(local_vars.get('self'), Citizen):
local_vars['self'] = repr(local_vars['self'])
if isinstance(local_vars.get('player'), Citizen):
local_vars['player'] = repr(local_vars['player'])
if isinstance(local_vars.get('citizen'), Citizen):
local_vars['citizen'] = repr(local_vars['citizen'])
from erepublik.classes import MyJSONEncoder
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=MyJSONEncoder, sort_keys=True),
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=MyJSONEncoder),
"application/json")))
if isinstance(player, Citizen):
files.append(('file', ("instance.json", player.to_json(indent=True), "application/json")))
@ -270,15 +279,15 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
write_silent_log(log_info)
trace = inspect.trace()
if trace:
trace = trace[-1][0].f_locals
if trace.get('__name__') == '__main__':
trace = {'commit_id': trace.get('COMMIT_ID'),
'interactive': trace.get('INTERACTIVE'),
'version': trace.get('__version__'),
'config': trace.get('CONFIG')}
local_vars = trace[-1][0].f_locals
if local_vars.get('__name__') == '__main__':
local_vars.update({'commit_id': local_vars.get('COMMIT_ID'),
'interactive': local_vars.get('INTERACTIVE'),
'version': local_vars.get('__version__'),
'config': local_vars.get('CONFIG')})
else:
trace = dict()
send_email(name, content, citizen, local_vars=trace)
local_vars = dict()
send_email(name, content, citizen, local_vars=local_vars)
def process_warning(log_info: str, name: str, exc_info: tuple, citizen=None, commit_id: str = None):
@ -298,10 +307,10 @@ def process_warning(log_info: str, name: str, exc_info: tuple, citizen=None, com
trace = inspect.trace()
if trace:
trace = trace[-1][0].f_locals
local_vars = trace[-1][0].f_locals
else:
trace = dict()
send_email(name, content, citizen, local_vars=trace)
local_vars = dict()
send_email(name, content, citizen, local_vars=local_vars)
def slugify(value, allow_unicode=False) -> str:
@ -359,3 +368,9 @@ def get_air_hit_dmg_value(citizen_id: int, natural_enemy: bool = False, true_pat
rang = r['military']['militaryData']['aircraft']['rankNumber']
elite = r['citizenAttributes']['level'] > 100
return calculate_hit(0, rang, true_patriot, elite, natural_enemy, booster, weapon_power)
def _clear_up_battle_memory(battle):
del battle.invader._battle, battle.defender._battle
for div_id, division in battle.div.items():
del division._battle

View File

@ -1,17 +1,19 @@
bump2version==1.0.0
coverage==5.1
coverage==5.3
edx-sphinx-theme==1.5.0
flake8==3.8.3
ipython==7.15.0
isort==4.3.21
pip==20.1.1
PyInstaller==3.6
ipython==7.18.1
isort==5.5.3
pip==20.2.3
PyInstaller==4.0
pytz==2020.1
requests==2.23.0
responses==0.10.15
setuptools==47.1.1
Sphinx==3.1.1
tox==3.15.2
twine==3.1.1
watchdog==0.10.2
wheel==0.34.2
pytest==6.1.0
responses==0.12.0
setuptools==50.3.0
Sphinx==3.2.1
requests==2.24.0
PySocks==1.7.1
tox==3.20.0
twine==3.2.0
watchdog==0.10.3
wheel==0.35.1

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.21.0.2
current_version = 0.21.5.2
commit = True
tag = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?
@ -33,7 +33,6 @@ ignore_missing_imports = False
warn_unused_ignores = True
warn_redundant_casts = True
warn_unused_configs = True
plugins = mypy_django_plugin.main
[isort]
multi_line_output = 2

View File

@ -11,7 +11,7 @@ with open('README.rst') as readme_file:
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = ['pytz==2020.1', 'requests==2.24.0']
requirements = ['pytz==2020.1', 'requests==2.24.0', 'PySocks==1.7.1']
setup_requirements = []
@ -43,6 +43,6 @@ setup(
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/eeriks/erepublik/',
version='0.21.0.2',
version='0.21.5.2',
zip_safe=False,
)

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
"""Tests for `erepublik` package."""
from typing import Callable
from erepublik import Citizen
@ -65,6 +66,7 @@ class TestErepublik(unittest.TestCase):
self.assertEqual(self.citizen.next_reachable_energy, 0)
def test_should_fight(self):
is_wc_close: Callable[[], bool] = lambda: self.citizen.max_time_till_full_ff > self.citizen.time_till_week_change
self.citizen.config.fight = False
self.assertEqual(self.citizen.should_fight(), (0, "Fighting not allowed!", False))
@ -73,62 +75,63 @@ class TestErepublik(unittest.TestCase):
# Level up
self.citizen.energy.limit = 3000
self.citizen.details.xp = 24705
self.assertEqual(self.citizen.should_fight(), (0, 'Level up', False))
if not is_wc_close:
self.assertEqual(self.citizen.should_fight(), (0, 'Level up', False))
self.citizen.energy.recovered = 3000
self.citizen.energy.recoverable = 2950
self.citizen.energy.interval = 30
self.assertEqual(self.citizen.should_fight(), (900, 'Level up', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (900, 'Level up', True))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.energy.recovered = 3000
self.citizen.energy.recoverable = 2950
self.citizen.energy.interval = 30
self.assertEqual(self.citizen.should_fight(), (900, 'Level up', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (900, 'Level up', True))
self.citizen.my_companies.ff_lockdown = 0
# Level up reachable
self.citizen.details.xp = 24400
self.assertEqual(self.citizen.should_fight(), (305, 'Fighting for close Levelup. Doing 305 hits', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (305, 'Fighting for close Levelup. Doing 305 hits', True))
self.citizen.my_companies.ff_lockdown = 0
# Level up reachable
self.citizen.details.xp = 24400
self.assertEqual(self.citizen.should_fight(), (305, 'Fighting for close Levelup. Doing 305 hits', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (305, 'Fighting for close Levelup. Doing 305 hits', True))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.details.xp = 21000
self.assertEqual(self.citizen.should_fight(), (75, 'Obligatory fighting for at least 75pp', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (75, 'Obligatory fighting for at least 75pp', True))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.details.pp = 80
self.citizen.details.xp = 21000
self.assertEqual(self.citizen.should_fight(), (75, 'Obligatory fighting for at least 75pp', True))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (75, 'Obligatory fighting for at least 75pp', True))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.details.pp = 80
# All-in (type = all-in and full ff)
self.citizen.config.all_in = True
self.assertEqual(self.citizen.should_fight(), (595, 'Fighting all-in. Doing 595 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
435, 'Fight count modified (old count: 595 | FF: 595 | WAM ff_lockdown: 160 | New count: 435)', False
))
self.citizen.my_companies.ff_lockdown = 0
# All-in (type = all-in and full ff)
self.citizen.config.all_in = True
self.assertEqual(self.citizen.should_fight(), (595, 'Fighting all-in. Doing 595 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
435, 'Fight count modified (old count: 595 | FF: 595 | WAM ff_lockdown: 160 | New count: 435)', False
))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.config.air = True
self.citizen.energy.recoverable = 1000
self.assertEqual(self.citizen.should_fight(), (400, 'Fighting all-in in AIR. Doing 400 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
240, 'Fight count modified (old count: 400 | FF: 400 | WAM ff_lockdown: 160 | New count: 240)', False
))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.config.all_in = False
self.citizen.config.air = True
self.citizen.energy.recoverable = 1000
self.assertEqual(self.citizen.should_fight(), (400, 'Fighting all-in in AIR. Doing 400 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
240, 'Fight count modified (old count: 400 | FF: 400 | WAM ff_lockdown: 160 | New count: 240)', False
))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.config.all_in = False
self.citizen.config.next_energy = True
self.citizen.energy.limit = 5000
self.citizen.details.next_pp = [100, 150, 250, 400, 500]
self.assertEqual(self.citizen.should_fight(), (320, 'Fighting for +1 energy. Doing 320 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
160, 'Fight count modified (old count: 320 | FF: 400 | WAM ff_lockdown: 160 | New count: 160)', False
))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.energy.limit = 3000
self.citizen.details.next_pp = [19250, 20000]
self.citizen.config.next_energy = False
self.citizen.config.next_energy = True
self.citizen.energy.limit = 5000
self.citizen.details.next_pp = [100, 150, 250, 400, 500]
self.assertEqual(self.citizen.should_fight(), (320, 'Fighting for +1 energy. Doing 320 hits', False))
self.citizen.my_companies.ff_lockdown = 160
self.assertEqual(self.citizen.should_fight(), (
160, 'Fight count modified (old count: 320 | FF: 400 | WAM ff_lockdown: 160 | New count: 160)', False
))
self.citizen.my_companies.ff_lockdown = 0
self.citizen.energy.limit = 3000
self.citizen.details.next_pp = [19250, 20000]
self.citizen.config.next_energy = False
# 1h worth of energy
self.citizen.energy.recoverable = 2910
self.assertEqual(self.citizen.should_fight(), (30, 'Fighting for 1h energy. Doing 30 hits', True))
# 1h worth of energy
self.citizen.energy.recoverable = 2910
self.assertEqual(self.citizen.should_fight(), (30, 'Fighting for 1h energy. Doing 30 hits', True))