Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
ee3eca9658 | |||
0e8680daca | |||
8e3606f1a3 | |||
bd0bcc9ac7 | |||
c6f2226e64 | |||
308807d800 | |||
91565d840e | |||
b4a9dd88f8 | |||
8435aa23ba | |||
09cd275a69 | |||
e23a67231e | |||
6a03d99abf | |||
2e344749a6 | |||
5aecefbd9d | |||
8b9ee5042d | |||
1e93006c3d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -102,5 +102,4 @@ ENV/
|
|||||||
|
|
||||||
debug/
|
debug/
|
||||||
log/
|
log/
|
||||||
docs/
|
|
||||||
*dump.json
|
*dump.json
|
||||||
|
13
.pre-commit-config.yaml
Normal file
13
.pre-commit-config.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v3.2.0
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-added-large-files
|
||||||
|
|
||||||
|
default_language_version:
|
||||||
|
python: python3.7
|
21
HISTORY.rst
21
HISTORY.rst
@ -2,6 +2,25 @@
|
|||||||
History
|
History
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
0.23.4 (2021-01-05)
|
||||||
|
-------------------
|
||||||
|
* Added expiration data to inventory items
|
||||||
|
* Inventory is now based on `classes.Inventory`
|
||||||
|
* Requirement update to make them more flexible regarding versions required
|
||||||
|
* Restructured inventory
|
||||||
|
|
||||||
|
0.23.3 (2020-12-17)
|
||||||
|
-------------------
|
||||||
|
* Fixed carpet bombing
|
||||||
|
* Fixed hits done amount when fighting on ground
|
||||||
|
* Minor requirement updates
|
||||||
|
* Minor tweaks to method signatures
|
||||||
|
* Fixed buy food if unable to work or train because not enough energy and not enough food
|
||||||
|
* Fixed applications for party presidency and congress if not a party member
|
||||||
|
* Removed tox
|
||||||
|
* Updates to github.io config generator
|
||||||
|
* Fixed `Citizen.concurrency_available` stuck in unset state if exception is being raised while doing concurrency task
|
||||||
|
|
||||||
0.23.2 (2020-12-01)
|
0.23.2 (2020-12-01)
|
||||||
-------------------
|
-------------------
|
||||||
* Added concurrency checks to guard against simultaneous fighting/wam'ing/traveling
|
* Added concurrency checks to guard against simultaneous fighting/wam'ing/traveling
|
||||||
@ -17,7 +36,7 @@ History
|
|||||||
|
|
||||||
0.23.0 (2020-11-26)
|
0.23.0 (2020-11-26)
|
||||||
-------------------
|
-------------------
|
||||||
* ***0.23 - last supported version for Python 3.7.***
|
* ***0.23 - last officially supported version for Python 3.7.***
|
||||||
* Added `Config.maverick` switch, to allow/deny automated fighting in non native divisions if the player has MaverickPack
|
* Added `Config.maverick` switch, to allow/deny automated fighting in non native divisions if the player has MaverickPack
|
||||||
* Added `CitizenMedia.get_article(article_id:int)` method to get article data
|
* Added `CitizenMedia.get_article(article_id:int)` method to get article data
|
||||||
* Added `CitizenMedia.delete_article(article_id:int)` method to delete article
|
* Added `CitizenMedia.delete_article(article_id:int)` method to delete article
|
||||||
|
1
LICENSE
1
LICENSE
@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
1
Makefile
1
Makefile
@ -76,7 +76,6 @@ servedocs: docs ## compile the docs watching for changes
|
|||||||
|
|
||||||
release: dist ## package and upload a release
|
release: dist ## package and upload a release
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
clean
|
|
||||||
|
|
||||||
dist: clean ## builds source and wheel package
|
dist: clean ## builds source and wheel package
|
||||||
python setup.py sdist
|
python setup.py sdist
|
||||||
|
@ -34,4 +34,3 @@ This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypack
|
|||||||
|
|
||||||
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
|
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
|
||||||
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
|
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
|
||||||
|
|
||||||
|
61
docs/erepublik.rst
Normal file
61
docs/erepublik.rst
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
erepublik package
|
||||||
|
=================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
erepublik.access\_points module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.access_points
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
erepublik.citizen module
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.citizen
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
erepublik.classes module
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.classes
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
erepublik.constants module
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.constants
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
erepublik.types module
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.types
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
erepublik.utils module
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik.utils
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: erepublik
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
@ -393,7 +393,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
config.air = air.checked;
|
config.air = air.checked;
|
||||||
config.ground = ground.cehcked;
|
config.ground = ground.checked;
|
||||||
config.boosters = boosters.checked;
|
config.boosters = boosters.checked;
|
||||||
config.continuous_fighting = continuous_fighting.checked;
|
config.continuous_fighting = continuous_fighting.checked;
|
||||||
config.next_energy = next_energy.checked;
|
config.next_energy = next_energy.checked;
|
||||||
@ -402,10 +402,9 @@
|
|||||||
config.travel_to_fight = travel_to_fight.checked;
|
config.travel_to_fight = travel_to_fight.checked;
|
||||||
config.epic_hunt = epic_hunt.checked;
|
config.epic_hunt = epic_hunt.checked;
|
||||||
config.epic_hunt_ebs = config.epic_hunt ? epic_hunt_ebs.checked : config.epic_hunt;
|
config.epic_hunt_ebs = config.epic_hunt ? epic_hunt_ebs.checked : config.epic_hunt;
|
||||||
|
config.maverick = false;
|
||||||
|
|
||||||
// Advanced
|
// Advanced
|
||||||
|
|
||||||
|
|
||||||
let telegram = document.getElementById('telegram'); // Generated
|
let telegram = document.getElementById('telegram'); // Generated
|
||||||
config.telegram = telegram.checked;
|
config.telegram = telegram.checked;
|
||||||
let telegram_chat_id = document.getElementById('telegram_chat_id'); // Generated
|
let telegram_chat_id = document.getElementById('telegram_chat_id'); // Generated
|
||||||
|
7
docs/modules.rst
Normal file
7
docs/modules.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
erepublik
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
erepublik
|
@ -7,4 +7,3 @@ To use eRepublik script in a project::
|
|||||||
from erepublik import Citizen
|
from erepublik import Citizen
|
||||||
player = Citizen('email@domain.com', 'password')
|
player = Citizen('email@domain.com', 'password')
|
||||||
player.update_all()
|
player.update_all()
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
__author__ = """Eriks Karls"""
|
__author__ = """Eriks Karls"""
|
||||||
__email__ = 'eriks@72.lv'
|
__email__ = 'eriks@72.lv'
|
||||||
__version__ = '0.23.3.4'
|
__version__ = '0.23.4.4'
|
||||||
|
|
||||||
from erepublik import classes, constants, utils
|
from erepublik import classes, constants, utils
|
||||||
from erepublik.citizen import Citizen
|
from erepublik.citizen import Citizen
|
||||||
|
@ -595,6 +595,10 @@ class ErepublikProfileAPI(CitizenBaseAPI):
|
|||||||
data = dict(_token=self.token, rewardId=reward_id)
|
data = dict(_token=self.token, rewardId=reward_id)
|
||||||
return self.post(f"{self.url}/main/weekly-challenge-collect-reward", data=data)
|
return self.post(f"{self.url}/main/weekly-challenge-collect-reward", data=data)
|
||||||
|
|
||||||
|
def _post_main_weekly_challenge_collect_all(self, max_reward_id: int) -> Response:
|
||||||
|
data = dict(_token=self.token, maxRewardId=max_reward_id)
|
||||||
|
return self.post(f"{self.url}/main/weekly-challenge-collect-all", data=data)
|
||||||
|
|
||||||
def _post_main_profile_update(self, action: str, params: str):
|
def _post_main_profile_update(self, action: str, params: str):
|
||||||
data = {"action": action, "params": params, "_token": self.token}
|
data = {"action": action, "params": params, "_token": self.token}
|
||||||
return self.post(f"{self.url}/main/profile-update", data=data)
|
return self.post(f"{self.url}/main/profile-update", data=data)
|
||||||
|
@ -2,7 +2,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import weakref
|
import weakref
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, time, timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from itertools import product
|
from itertools import product
|
||||||
from threading import Event
|
from threading import Event
|
||||||
@ -11,7 +11,7 @@ from typing import Any, Dict, List, NoReturn, Optional, Set, Tuple, Union
|
|||||||
|
|
||||||
from requests import HTTPError, RequestException, Response
|
from requests import HTTPError, RequestException, Response
|
||||||
|
|
||||||
from . import access_points, classes, constants, utils
|
from . import access_points, classes, constants, types, utils
|
||||||
from .classes import OfferItem
|
from .classes import OfferItem
|
||||||
|
|
||||||
|
|
||||||
@ -20,9 +20,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
_last_inventory_update: datetime = constants.min_datetime
|
_last_inventory_update: datetime = constants.min_datetime
|
||||||
|
|
||||||
promos: Dict[str, datetime] = None
|
promos: Dict[str, datetime] = None
|
||||||
inventory: Dict[str, Dict[str, Dict[int, Dict[str, Union[str, int, float]]]]]
|
_inventory: classes.Inventory
|
||||||
inventory_status: Dict[str, int]
|
|
||||||
boosters: Dict[int, Dict[int, int]] = {50: {}, 100: {}}
|
|
||||||
ot_points: int = 0
|
ot_points: int = 0
|
||||||
|
|
||||||
food: Dict[str, int] = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
|
food: Dict[str, int] = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
|
||||||
@ -65,8 +63,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
|
|
||||||
self.config.email = email
|
self.config.email = email
|
||||||
self.config.password = password
|
self.config.password = password
|
||||||
self.inventory = {}
|
self._inventory = classes.Inventory()
|
||||||
self.inventory_status = dict(used=0, total=0)
|
|
||||||
self.wheel_of_fortune = False
|
self.wheel_of_fortune = False
|
||||||
|
|
||||||
def get_csrf_token(self):
|
def get_csrf_token(self):
|
||||||
@ -248,26 +245,38 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
"""
|
"""
|
||||||
self._update_inventory_data(self._get_economy_inventory_items().json())
|
self._update_inventory_data(self._get_economy_inventory_items().json())
|
||||||
|
|
||||||
def get_inventory(self, force: bool = False):
|
@property
|
||||||
|
def inventory(self) -> classes.Inventory:
|
||||||
|
return self.get_inventory()
|
||||||
|
|
||||||
|
def get_inventory(self, force: bool = False) -> classes.Inventory:
|
||||||
if utils.good_timedelta(self._last_inventory_update, timedelta(minutes=2)) < self.now or force:
|
if utils.good_timedelta(self._last_inventory_update, timedelta(minutes=2)) < self.now or force:
|
||||||
self.update_inventory()
|
self.update_inventory()
|
||||||
return self.inventory
|
return self._inventory
|
||||||
|
|
||||||
def _update_inventory_data(self, inv_data: Dict[str, Any]):
|
def _update_inventory_data(self, inv_data: Dict[str, Any]):
|
||||||
if not isinstance(inv_data, dict):
|
if not isinstance(inv_data, dict):
|
||||||
raise TypeError("Parameter `inv_data` must be dict not '{type(data)}'!")
|
raise TypeError("Parameter `inv_data` must be dict not '{type(data)}'!")
|
||||||
|
|
||||||
|
def _expire_value_to_python(_expire_value: str) -> Dict[str, Union[int, datetime]]:
|
||||||
|
_data = re.search(
|
||||||
|
r'((?P<amount>\d+) item\(s\) )?[eE]xpires? on Day (?P<eday>\d,\d{3}), (?P<time>\d\d:\d\d)',
|
||||||
|
_expire_value).groupdict()
|
||||||
|
eday = utils.date_from_eday(int(_data['eday'].replace(',', '')))
|
||||||
|
dt = constants.erep_tz.localize(datetime.combine(eday, time(*[int(_) for _ in _data['time'].split(':')])))
|
||||||
|
return {'amount': _data.get('amount'), 'expiration': dt}
|
||||||
|
|
||||||
status = inv_data.get("inventoryStatus", {})
|
status = inv_data.get("inventoryStatus", {})
|
||||||
if status:
|
if status:
|
||||||
self.inventory_status.clear()
|
self._inventory.used = status.get("usedStorage")
|
||||||
self.inventory_status.update(used=status.get("usedStorage"), total=status.get("totalStorage"))
|
self._inventory.total = status.get("totalStorage")
|
||||||
data = inv_data.get('inventoryItems', {})
|
data = inv_data.get('inventoryItems', {})
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
self._last_inventory_update = self.now
|
self._last_inventory_update = self.now
|
||||||
self.food.update({"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0})
|
self.food.update({"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0})
|
||||||
self.eb_small = self.eb_double = self.eb_normal = 0
|
self.eb_small = self.eb_double = self.eb_normal = 0
|
||||||
active_items: Dict[str, Dict[int, Dict[str, Union[str, int]]]] = {}
|
active_items: types.InvFinal = {}
|
||||||
if data.get("activeEnhancements", {}).get("items", {}):
|
if data.get("activeEnhancements", {}).get("items", {}):
|
||||||
for item_data in data.get("activeEnhancements", {}).get("items", {}).values():
|
for item_data in data.get("activeEnhancements", {}).get("items", {}).values():
|
||||||
if item_data.get('token'):
|
if item_data.get('token'):
|
||||||
@ -278,29 +287,34 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
kind = constants.INDUSTRIES[constants.INDUSTRIES[kind]]
|
kind = constants.INDUSTRIES[constants.INDUSTRIES[kind]]
|
||||||
if kind not in active_items:
|
if kind not in active_items:
|
||||||
active_items[kind] = {}
|
active_items[kind] = {}
|
||||||
|
expiration_info = []
|
||||||
|
if item_data.get('attributes').get('expirationInfo'):
|
||||||
|
expire_info = item_data.get('attributes').get('expirationInfo')
|
||||||
|
expiration_info = [_expire_value_to_python(v) for v in expire_info['value']]
|
||||||
icon = item_data['icon'] if item_data[
|
icon = item_data['icon'] if item_data[
|
||||||
'icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
'icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
||||||
item_data = dict(name=item_data.get("name"), time_left=item_data['active']['time_left'], icon=icon,
|
inv_item: types.InvFinalItem = dict(
|
||||||
kind=kind,
|
name=item_data.get("name"), time_left=item_data['active']['time_left'], icon=icon,
|
||||||
quality=item_data.get("quality", 0))
|
kind=kind, expiration=expiration_info, quality=item_data.get("quality", 0)
|
||||||
|
)
|
||||||
|
|
||||||
if item_data.get('isPackBooster'):
|
if item_data.get('isPackBooster'):
|
||||||
active_items[kind].update({0: item_data})
|
active_items[kind].update({0: inv_item})
|
||||||
else:
|
else:
|
||||||
active_items[kind].update({item_data.get("quality"): item_data})
|
active_items[kind].update({inv_item.get("quality"): inv_item})
|
||||||
|
|
||||||
final_items: Dict[str, Dict[int, Dict[str, Union[str, int]]]] = {}
|
final_items: types.InvFinal = {}
|
||||||
|
boosters: types.InvBooster = {}
|
||||||
if data.get("finalProducts", {}).get("items", {}):
|
if data.get("finalProducts", {}).get("items", {}):
|
||||||
for item_data in data.get("finalProducts", {}).get("items", {}).values():
|
for item_data in data.get("finalProducts", {}).get("items", {}).values():
|
||||||
|
is_booster: bool = False
|
||||||
name = item_data['name']
|
name = item_data['name']
|
||||||
|
|
||||||
if item_data.get('type'):
|
if item_data.get('type'):
|
||||||
if item_data.get('type') in ['damageBoosters', "aircraftDamageBoosters"]:
|
# in ['damageBoosters', "aircraftDamageBoosters", 'prestigePointsBoosters']
|
||||||
kind = f"{item_data['type']}{item_data['quality']}"
|
if item_data.get('isBooster'):
|
||||||
if item_data['quality'] == 5:
|
is_booster = True
|
||||||
self.boosters[50].update({item_data['duration']: item_data['amount']})
|
kind = item_data['type']
|
||||||
elif item_data['quality'] == 10:
|
|
||||||
self.boosters[100].update({item_data['duration']: item_data['amount']})
|
|
||||||
|
|
||||||
delta = item_data['duration']
|
delta = item_data['duration']
|
||||||
if delta // 3600:
|
if delta // 3600:
|
||||||
@ -337,6 +351,12 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
if constants.INDUSTRIES[kind]:
|
if constants.INDUSTRIES[kind]:
|
||||||
kind = constants.INDUSTRIES[constants.INDUSTRIES[kind]]
|
kind = constants.INDUSTRIES[constants.INDUSTRIES[kind]]
|
||||||
|
|
||||||
|
if is_booster:
|
||||||
|
if kind not in boosters:
|
||||||
|
boosters[kind] = {}
|
||||||
|
if item_data.get('quality', 0) not in boosters[kind]:
|
||||||
|
boosters[kind][item_data['quality']] = {}
|
||||||
|
else:
|
||||||
if kind not in final_items:
|
if kind not in final_items:
|
||||||
final_items[kind] = {}
|
final_items[kind] = {}
|
||||||
|
|
||||||
@ -355,10 +375,23 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
icon = "/images/modules/pvp/ghost_boosters/icon_booster_30_60.png"
|
icon = "/images/modules/pvp/ghost_boosters/icon_booster_30_60.png"
|
||||||
else:
|
else:
|
||||||
icon = "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
icon = "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
||||||
_item_data = dict(kind=kind, quality=item_data.get('quality', 0), amount=item_data.get('amount', 0),
|
|
||||||
durability=item_data.get('duration', 0), icon=icon, name=name)
|
expiration_info = []
|
||||||
if item_data.get('type') in ('damageBoosters', "aircraftDamageBoosters"):
|
if item_data.get('attributes'):
|
||||||
_item_data = {_item_data['durability']: _item_data}
|
if item_data.get('attributes').get('expirationInfo'):
|
||||||
|
expire_info = item_data.get('attributes').get('expirationInfo')
|
||||||
|
expiration_info = [_expire_value_to_python(v) for v in expire_info['value']]
|
||||||
|
elif item_data.get('attributes').get('expiration'):
|
||||||
|
_exp = item_data.get('attributes').get('expiration')
|
||||||
|
exp_dt = (utils.date_from_eday(int(_exp['value'].replace(',', ''))))
|
||||||
|
expiration_info = [{'amount': item_data.get('amount'), 'expiration': exp_dt}]
|
||||||
|
_inv_item: Dict[int, types.InvFinalItem]
|
||||||
|
inv_item: types.InvFinalItem = dict(
|
||||||
|
kind=kind, quality=item_data.get('quality', 0), icon=icon, expiration=expiration_info,
|
||||||
|
amount=item_data.get('amount'), durability=item_data.get('duration', 0), name=name
|
||||||
|
)
|
||||||
|
if is_booster:
|
||||||
|
_inv_item = {inv_item['durability']: inv_item}
|
||||||
else:
|
else:
|
||||||
if item_data.get('type') == 'bomb':
|
if item_data.get('type') == 'bomb':
|
||||||
firepower = 0
|
firepower = 0
|
||||||
@ -367,11 +400,14 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
_item_data.update(fire_power=firepower)
|
inv_item.update(fire_power=firepower)
|
||||||
_item_data = {_item_data['quality']: _item_data}
|
_inv_item = {inv_item['quality']: inv_item}
|
||||||
final_items[kind].update(_item_data)
|
if is_booster:
|
||||||
|
boosters[kind][inv_item['quality']].update(_inv_item)
|
||||||
|
else:
|
||||||
|
final_items[kind].update(_inv_item)
|
||||||
|
|
||||||
raw_materials: Dict[str, Dict[int, Dict[str, Union[str, int]]]] = {}
|
raw_materials: types.InvRaw = {}
|
||||||
if data.get("rawMaterials", {}).get("items", {}):
|
if data.get("rawMaterials", {}).get("items", {}):
|
||||||
for item_data in data.get("rawMaterials", {}).get("items", {}).values():
|
for item_data in data.get("rawMaterials", {}).get("items", {}).values():
|
||||||
if item_data['isPartial']:
|
if item_data['isPartial']:
|
||||||
@ -401,8 +437,11 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
offers[kind] = {}
|
offers[kind] = {}
|
||||||
|
|
||||||
offers[kind].update(offer_data)
|
offers[kind].update(offer_data)
|
||||||
self.inventory.clear()
|
self._inventory.active = active_items
|
||||||
self.inventory.update(active=active_items, final=final_items, raw=raw_materials, offers=offers)
|
self._inventory.final = final_items
|
||||||
|
self._inventory.boosters = boosters
|
||||||
|
self._inventory.raw = raw_materials
|
||||||
|
self._inventory.offers = offers
|
||||||
self.food["total"] = sum([self.food[q] * constants.FOOD_ENERGY[q] for q in constants.FOOD_ENERGY])
|
self.food["total"] = sum([self.food[q] * constants.FOOD_ENERGY[q] for q in constants.FOOD_ENERGY])
|
||||||
|
|
||||||
def write_log(self, *args, **kwargs):
|
def write_log(self, *args, **kwargs):
|
||||||
@ -946,13 +985,13 @@ class CitizenCompanies(BaseCitizen):
|
|||||||
raw_factories = wam_holding.get_wam_companies(raw_factory=True)
|
raw_factories = wam_holding.get_wam_companies(raw_factory=True)
|
||||||
fin_factories = wam_holding.get_wam_companies(raw_factory=False)
|
fin_factories = wam_holding.get_wam_companies(raw_factory=False)
|
||||||
|
|
||||||
free_inventory = self.inventory_status["total"] - self.inventory_status["used"]
|
free_inventory = self.inventory.total - self.inventory.used
|
||||||
wam_list = raw_factories + fin_factories
|
wam_list = raw_factories + fin_factories
|
||||||
wam_list = wam_list[:self.energy.food_fights]
|
wam_list = wam_list[:self.energy.food_fights]
|
||||||
|
|
||||||
if int(free_inventory * 0.75) < self.my_companies.get_needed_inventory_usage(wam_list):
|
if int(free_inventory * 0.75) < self.my_companies.get_needed_inventory_usage(wam_list):
|
||||||
self.update_inventory()
|
self.update_inventory()
|
||||||
free_inventory = self.inventory_status["total"] - self.inventory_status["used"]
|
free_inventory = self.inventory.total - self.inventory.used
|
||||||
|
|
||||||
while wam_list and free_inventory < self.my_companies.get_needed_inventory_usage(wam_list):
|
while wam_list and free_inventory < self.my_companies.get_needed_inventory_usage(wam_list):
|
||||||
wam_list.pop(-1)
|
wam_list.pop(-1)
|
||||||
@ -1020,8 +1059,8 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
|
|
||||||
def check_house_durability(self) -> Dict[int, datetime]:
|
def check_house_durability(self) -> Dict[int, datetime]:
|
||||||
ret = {}
|
ret = {}
|
||||||
inv = self.get_inventory()
|
inv = self.inventory
|
||||||
for house_quality, active_house in inv['active'].get('House', {}).items():
|
for house_quality, active_house in inv.active.get('House', {}).items():
|
||||||
till = utils.good_timedelta(self.now, timedelta(seconds=active_house['time_left']))
|
till = utils.good_timedelta(self.now, timedelta(seconds=active_house['time_left']))
|
||||||
ret.update({house_quality: till})
|
ret.update({house_quality: till})
|
||||||
return ret
|
return ret
|
||||||
@ -1029,8 +1068,8 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
def buy_and_activate_house(self, q: int) -> Optional[Dict[int, datetime]]:
|
def buy_and_activate_house(self, q: int) -> Optional[Dict[int, datetime]]:
|
||||||
original_region = self.details.current_country, self.details.current_region
|
original_region = self.details.current_country, self.details.current_region
|
||||||
ok_to_activate = False
|
ok_to_activate = False
|
||||||
inv = self.get_inventory()
|
inv = self.inventory
|
||||||
if not inv['final'].get('House', {}).get(q, {}):
|
if not inv.final.get('House', {}).get(q, {}):
|
||||||
countries = [self.details.citizenship, ]
|
countries = [self.details.citizenship, ]
|
||||||
if self.details.current_country != self.details.citizenship:
|
if self.details.current_country != self.details.citizenship:
|
||||||
countries.append(self.details.current_country)
|
countries.append(self.details.current_country)
|
||||||
@ -1084,7 +1123,7 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
r: Dict[str, Any] = self._post_economy_activate_house(quality).json()
|
r: Dict[str, Any] = self._post_economy_activate_house(quality).json()
|
||||||
self._update_inventory_data(r)
|
self._update_inventory_data(r)
|
||||||
if r.get("status") and not r.get("error"):
|
if r.get("status") and not r.get("error"):
|
||||||
house: Dict[str, Union[int, str]] = self.get_inventory()['active']['House'][quality]
|
house = self.inventory.active.get('House', {}).get(quality)
|
||||||
time_left = timedelta(seconds=house["time_left"])
|
time_left = timedelta(seconds=house["time_left"])
|
||||||
active_until = utils.good_timedelta(self.now, time_left)
|
active_until = utils.good_timedelta(self.now, time_left)
|
||||||
self._report_action(
|
self._report_action(
|
||||||
@ -1164,12 +1203,13 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
self.write_log(f"Trying to sell unsupported industry {industry}")
|
self.write_log(f"Trying to sell unsupported industry {industry}")
|
||||||
|
|
||||||
_inv_qlt = quality if industry in [1, 2, 3, 4, 23] else 0
|
_inv_qlt = quality if industry in [1, 2, 3, 4, 23] else 0
|
||||||
_kind = 'final' if industry in [1, 2, 4, 23] else 'raw'
|
final_kind = industry in [1, 2, 4, 23]
|
||||||
inventory = self.get_inventory()
|
items = (self.inventory.final if final_kind else self.inventory.raw).get(constants.INDUSTRIES[industry],
|
||||||
items = inventory[_kind].get(constants.INDUSTRIES[industry], {_inv_qlt: {'amount': 0}})
|
{_inv_qlt: {'amount': 0}})
|
||||||
if items[_inv_qlt]['amount'] < amount:
|
if items[_inv_qlt]['amount'] < amount:
|
||||||
inventory = self.get_inventory(True)
|
self.get_inventory(True)
|
||||||
items = inventory[_kind].get(constants.INDUSTRIES[industry], {_inv_qlt: {'amount': 0}})
|
items = (self.inventory.final if final_kind else self.inventory.raw).get(constants.INDUSTRIES[industry],
|
||||||
|
{_inv_qlt: {'amount': 0}})
|
||||||
if items[_inv_qlt]['amount'] < amount:
|
if items[_inv_qlt]['amount'] < amount:
|
||||||
self._report_action("ECONOMY_SELL_PRODUCTS", "Unable to sell! Not enough items in storage!",
|
self._report_action("ECONOMY_SELL_PRODUCTS", "Unable to sell! Not enough items in storage!",
|
||||||
kwargs=dict(inventory=items[_inv_qlt], amount=amount))
|
kwargs=dict(inventory=items[_inv_qlt], amount=amount))
|
||||||
@ -1788,7 +1828,7 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
self._report_action("IP_BLACKLISTED", "Fighting is not allowed from restricted IP!")
|
self._report_action("IP_BLACKLISTED", "Fighting is not allowed from restricted IP!")
|
||||||
return 1
|
return 1
|
||||||
if not division.is_air and self.config.boosters:
|
if not division.is_air and self.config.boosters:
|
||||||
self.activate_dmg_booster()
|
self.activate_damage_booster(not division.is_air)
|
||||||
if side is None:
|
if side is None:
|
||||||
side = battle.defender if self.details.citizenship in battle.defender.allies + [
|
side = battle.defender if self.details.citizenship in battle.defender.allies + [
|
||||||
battle.defender.country] else battle.invader
|
battle.defender.country] else battle.invader
|
||||||
@ -1884,7 +1924,8 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
return hits, err, damage
|
return hits, err, damage
|
||||||
|
|
||||||
@utils.wait_for_lock
|
@utils.wait_for_lock
|
||||||
def deploy_bomb(self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool, count: int = 1) -> Optional[int]:
|
def deploy_bomb(self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool,
|
||||||
|
count: int = 1) -> Optional[int]:
|
||||||
"""Deploy bombs in a battle for given side.
|
"""Deploy bombs in a battle for given side.
|
||||||
|
|
||||||
:param battle: Battle
|
:param battle: Battle
|
||||||
@ -1979,34 +2020,44 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
|
|
||||||
return utils.calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0)
|
return utils.calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0)
|
||||||
|
|
||||||
def activate_dmg_booster(self):
|
def activate_damage_booster(self, ground: bool = True):
|
||||||
if self.config.boosters:
|
kind = 'damageBoosters' if ground else 'aircraftDamageBoosters'
|
||||||
if not self.get_active_ground_damage_booster():
|
if self.config.boosters and not self.get_active_damage_booster(ground):
|
||||||
duration = 0
|
booster: Optional[types.InvFinalItem] = None
|
||||||
for length, amount in self.boosters[50].items():
|
for quality, data in sorted(self.inventory.boosters.get(kind, {}).items(), key=lambda x: x[0]):
|
||||||
if amount > 2:
|
for _duration, _booster in sorted(data.items(), key=lambda y: y[0]):
|
||||||
duration = length
|
critical_amount = 2 if quality < 10 and ground else 10
|
||||||
|
if _booster.get('amount') > critical_amount:
|
||||||
|
booster = _booster
|
||||||
break
|
break
|
||||||
if duration:
|
break
|
||||||
self._report_action("MILITARY_BOOSTER", f"Activated 50% {duration / 60}h damage booster")
|
if booster:
|
||||||
self._post_economy_activate_booster(5, duration, "damage")
|
self._report_action("MILITARY_BOOSTER", f"Activated {booster['name']}")
|
||||||
|
self._post_economy_activate_booster(booster['quality'], booster['durability'],
|
||||||
|
'damage' if ground else 'air_damage')
|
||||||
|
|
||||||
|
def get_active_damage_booster(self, ground: bool = True) -> int:
|
||||||
|
kind = 'damageBoosters' if ground else 'aircraftDamageBoosters'
|
||||||
|
boosters = self.inventory.active.get(kind, {})
|
||||||
|
quality = 0
|
||||||
|
for q, boost in boosters.items():
|
||||||
|
if boost['quality'] * 10 > quality:
|
||||||
|
quality = boost['quality'] * 10
|
||||||
|
return quality
|
||||||
|
|
||||||
def get_active_ground_damage_booster(self) -> int:
|
def get_active_ground_damage_booster(self) -> int:
|
||||||
inventory = self.get_inventory()
|
return self.get_active_damage_booster(True)
|
||||||
quality = 0
|
|
||||||
if inventory['active'].get('damageBoosters', {}).get(10):
|
def get_active_air_damage_booster(self) -> int:
|
||||||
quality = 100
|
return self.get_active_damage_booster(False)
|
||||||
elif inventory['active'].get('damageBoosters', {}).get(5):
|
|
||||||
quality = 50
|
|
||||||
return quality
|
|
||||||
|
|
||||||
def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
|
def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
|
||||||
self._report_action('MILITARY_BOOSTER', f'Activated {kind} booster')
|
self._report_action('MILITARY_BOOSTER', f'Activated {kind} booster')
|
||||||
return self._post_main_activate_battle_effect(battle_id, kind, self.details.citizen_id)
|
return self._post_main_activate_battle_effect(battle_id, kind, self.details.citizen_id)
|
||||||
|
|
||||||
def activate_pp_booster(self, battle_id: int) -> Response:
|
def activate_pp_booster(self, pp_item: types.InvFinalItem) -> Response:
|
||||||
self._report_action('MILITARY_BOOSTER', 'Activated PrestigePoint booster')
|
self._report_action('MILITARY_BOOSTER', f'Activated {pp_item["name"]}')
|
||||||
return self._post_military_fight_activate_booster(battle_id, 1, 180, "prestige_points")
|
return self._post_economy_activate_booster(pp_item['quality'], pp_item['durability'], 'prestige_points')
|
||||||
|
|
||||||
def _rw_choose_side(self, battle: classes.Battle, side: classes.BattleSide) -> Response:
|
def _rw_choose_side(self, battle: classes.Battle, side: classes.BattleSide) -> Response:
|
||||||
return self._post_main_battlefield_travel(side.id, battle.id)
|
return self._post_main_battlefield_travel(side.id, battle.id)
|
||||||
@ -2181,7 +2232,8 @@ class CitizenPolitics(BaseCitizen):
|
|||||||
self._report_action('POLITIC_PARTY_PRESIDENT', 'Applied for party president elections')
|
self._report_action('POLITIC_PARTY_PRESIDENT', 'Applied for party president elections')
|
||||||
return self._get_candidate_party(self.politics.party_slug)
|
return self._get_candidate_party(self.politics.party_slug)
|
||||||
else:
|
else:
|
||||||
self._report_action('POLITIC_CONGRESS', 'Unable to apply for party president elections - not a party member')
|
self._report_action('POLITIC_CONGRESS',
|
||||||
|
'Unable to apply for party president elections - not a party member')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def candidate_for_congress(self, presentation: str = "") -> Optional[Response]:
|
def candidate_for_congress(self, presentation: str = "") -> Optional[Response]:
|
||||||
@ -2565,17 +2617,21 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
data = self._get_main_weekly_challenge_data().json()
|
data = self._get_main_weekly_challenge_data().json()
|
||||||
self.details.pp = data.get("player", {}).get("prestigePoints", 0)
|
self.details.pp = data.get("player", {}).get("prestigePoints", 0)
|
||||||
self.details.next_pp.clear()
|
self.details.next_pp.clear()
|
||||||
|
max_collectable_id = data.get('maxRewardId')
|
||||||
|
should_collect = False
|
||||||
for reward in data.get("rewards", {}).get("normal", {}):
|
for reward in data.get("rewards", {}).get("normal", {}):
|
||||||
status = reward.get("status", "")
|
status = reward.get("status", "")
|
||||||
if status == "rewarded":
|
if status == "rewarded":
|
||||||
continue
|
continue
|
||||||
elif status == "completed":
|
elif status == "completed":
|
||||||
self._post_main_weekly_challenge_reward(reward.get("id", 0))
|
should_collect = True
|
||||||
elif reward.get("icon", "") == "energy_booster":
|
elif reward.get("icon", "") == "energy_booster":
|
||||||
pps = re.search(r"Reach (\d+) Prestige Points to unlock the following reward: \+1 Energy",
|
pps = re.search(r"Reach (\d+) Prestige Points to unlock the following reward: \+1 Energy",
|
||||||
reward.get("tooltip", ""))
|
reward.get("tooltip", ""))
|
||||||
if pps:
|
if pps:
|
||||||
self.details.next_pp.append(int(pps.group(1)))
|
self.details.next_pp.append(int(pps.group(1)))
|
||||||
|
if should_collect:
|
||||||
|
self._post_main_weekly_challenge_collect_all(max_collectable_id)
|
||||||
|
|
||||||
def should_fight(self, silent: bool = True) -> Tuple[int, str, bool]:
|
def should_fight(self, silent: bool = True) -> Tuple[int, str, bool]:
|
||||||
count, log_msg, force_fight = super().should_fight()
|
count, log_msg, force_fight = super().should_fight()
|
||||||
@ -2630,13 +2686,13 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
|
|
||||||
def send_state_update(self):
|
def send_state_update(self):
|
||||||
data = dict(xp=self.details.xp, cc=self.details.cc, gold=self.details.gold, pp=self.details.pp,
|
data = dict(xp=self.details.xp, cc=self.details.cc, gold=self.details.gold, pp=self.details.pp,
|
||||||
inv_total=self.inventory_status['total'], inv=self.inventory_status['used'],
|
inv_total=self.inventory.total, inv=self.inventory.used,
|
||||||
hp_limit=self.energy.limit,
|
hp_limit=self.energy.limit,
|
||||||
hp_interval=self.energy.interval, hp_available=self.energy.available, food=self.food['total'], )
|
hp_interval=self.energy.interval, hp_available=self.energy.available, food=self.food['total'], )
|
||||||
self.reporter.send_state_update(**data)
|
self.reporter.send_state_update(**data)
|
||||||
|
|
||||||
def send_inventory_update(self):
|
def send_inventory_update(self):
|
||||||
self.reporter.report_action("INVENTORY", json_val=self.get_inventory(True))
|
self.reporter.report_action("INVENTORY", json_val=self.inventory.as_dict)
|
||||||
|
|
||||||
def send_my_companies_update(self):
|
def send_my_companies_update(self):
|
||||||
self.reporter.report_action('COMPANIES', json_val=self.my_companies.as_dict)
|
self.reporter.report_action('COMPANIES', json_val=self.my_companies.as_dict)
|
||||||
@ -2774,7 +2830,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
|
|
||||||
for holding in regions.values():
|
for holding in regions.values():
|
||||||
raw_usage = holding.get_wam_raw_usage()
|
raw_usage = holding.get_wam_raw_usage()
|
||||||
free_storage = self.inventory_status['total'] - self.inventory_status['used']
|
free_storage = self.inventory.total - self.inventory.used
|
||||||
if (raw_usage['frm'] + raw_usage['wrm']) * 100 > free_storage:
|
if (raw_usage['frm'] + raw_usage['wrm']) * 100 > free_storage:
|
||||||
self._report_action('WAM_UNAVAILABLE', 'Not enough storage!')
|
self._report_action('WAM_UNAVAILABLE', 'Not enough storage!')
|
||||||
continue
|
continue
|
||||||
|
@ -7,11 +7,12 @@ from typing import Any, Dict, Generator, Iterable, List, NamedTuple, NoReturn, T
|
|||||||
|
|
||||||
from requests import Response, Session, post
|
from requests import Response, Session, post
|
||||||
|
|
||||||
from . import constants, utils
|
from . import constants, types, utils
|
||||||
|
|
||||||
__all__ = ['Battle', 'BattleDivision', 'BattleSide', 'Company', 'Config', 'Details', 'Energy', 'ErepublikException',
|
__all__ = ['Battle', 'BattleDivision', 'BattleSide', 'Company', 'Config', 'Details', 'Energy', 'ErepublikException',
|
||||||
'ErepublikNetworkException', 'EnergyToFight',
|
'ErepublikNetworkException', 'EnergyToFight',
|
||||||
'Holding', 'MyCompanies', 'MyJSONEncoder', 'OfferItem', 'Politics', 'Reporter', 'TelegramReporter']
|
'Holding', 'MyCompanies', 'MyJSONEncoder', 'OfferItem', 'Politics', 'Reporter', 'TelegramReporter',
|
||||||
|
'Inventory']
|
||||||
|
|
||||||
|
|
||||||
class ErepublikException(Exception):
|
class ErepublikException(Exception):
|
||||||
@ -396,11 +397,11 @@ class Config:
|
|||||||
self.spin_wheel_of_fortune = False
|
self.spin_wheel_of_fortune = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[bool, int, str, List[str]]]:
|
||||||
return dict(email=self.email, work=self.work, train=self.train, wam=self.wam, ot=self.ot,
|
return dict(email=self.email, work=self.work, train=self.train, wam=self.wam, ot=self.ot,
|
||||||
auto_sell=self.auto_sell, auto_sell_all=self.auto_sell_all, employees=self.employees,
|
auto_sell=self.auto_sell, auto_sell_all=self.auto_sell_all, employees=self.employees,
|
||||||
fight=self.fight, air=self.air, ground=self.ground, all_in=self.all_in,
|
fight=self.fight, air=self.air, ground=self.ground, all_in=self.all_in,
|
||||||
next_energy=self.next_energy, boosters=self.boosters, travel_to_fight=self.travel_to_fight,
|
next_energy=self.next_energy, travel_to_fight=self.travel_to_fight,
|
||||||
always_travel=self.always_travel, epic_hunt=self.epic_hunt, epic_hunt_ebs=self.epic_hunt_ebs,
|
always_travel=self.always_travel, epic_hunt=self.epic_hunt, epic_hunt_ebs=self.epic_hunt_ebs,
|
||||||
rw_def_side=self.rw_def_side, interactive=self.interactive, maverick=self.maverick,
|
rw_def_side=self.rw_def_side, interactive=self.interactive, maverick=self.maverick,
|
||||||
continuous_fighting=self.continuous_fighting, auto_buy_raw=self.auto_buy_raw,
|
continuous_fighting=self.continuous_fighting, auto_buy_raw=self.auto_buy_raw,
|
||||||
@ -454,7 +455,7 @@ class Energy:
|
|||||||
return self.recovered + self.recoverable
|
return self.recovered + self.recoverable
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[int, datetime.datetime, bool]]:
|
||||||
return dict(limit=self.limit, interval=self.interval, recoverable=self.recoverable, recovered=self.recovered,
|
return dict(limit=self.limit, interval=self.interval, recoverable=self.recoverable, recovered=self.recovered,
|
||||||
reference_time=self.reference_time, food_fights=self.food_fights,
|
reference_time=self.reference_time, food_fights=self.food_fights,
|
||||||
is_recoverable_full=self.is_recoverable_full, is_recovered_full=self.is_recovered_full,
|
is_recoverable_full=self.is_recoverable_full, is_recovered_full=self.is_recovered_full,
|
||||||
@ -509,7 +510,7 @@ class Details:
|
|||||||
return next_level_up - self.xp
|
return next_level_up - self.xp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[int, float, str, constants.Country, bool]]:
|
||||||
return dict(xp=self.xp, cc=self.cc, pp=self.pp, pin=self.pin, gold=self.gold, next_pp=self.next_pp,
|
return dict(xp=self.xp, cc=self.cc, pp=self.pp, pin=self.pin, gold=self.gold, next_pp=self.next_pp,
|
||||||
citizen_id=self.citizen_id, citizenship=self.citizenship, current_region=self.current_region,
|
citizen_id=self.citizen_id, citizenship=self.citizenship, current_region=self.current_region,
|
||||||
current_country=self.current_country, residence_region=self.residence_region,
|
current_country=self.current_country, residence_region=self.residence_region,
|
||||||
@ -528,7 +529,7 @@ class Politics:
|
|||||||
is_country_president: bool = False
|
is_country_president: bool = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[bool, int, str]]:
|
||||||
return dict(is_party_member=self.is_party_member, party_id=self.party_id, party_slug=self.party_slug,
|
return dict(is_party_member=self.is_party_member, party_id=self.party_id, party_slug=self.party_slug,
|
||||||
is_party_president=self.is_party_president, is_congressman=self.is_congressman,
|
is_party_president=self.is_party_president, is_congressman=self.is_congressman,
|
||||||
is_country_president=self.is_country_president)
|
is_country_president=self.is_country_president)
|
||||||
@ -566,7 +567,7 @@ class Reporter:
|
|||||||
return self.citizen.details.citizen_id
|
return self.citizen.details.citizen_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[bool, int, str, List[Dict[Any, Any]]]]:
|
||||||
return dict(name=self.name, email=self.email, citizen_id=self.citizen_id, key=self.key, allowed=self.allowed,
|
return dict(name=self.name, email=self.email, citizen_id=self.citizen_id, key=self.key, allowed=self.allowed,
|
||||||
queue=self.__to_update)
|
queue=self.__to_update)
|
||||||
|
|
||||||
@ -730,7 +731,7 @@ class BattleSide:
|
|||||||
return self.country.iso
|
return self.country.iso
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self) -> Dict[str, Union[int, constants.Country, bool, List[constants.Country]]]:
|
||||||
return dict(points=self.points, country=self.country, is_defender=self.is_defender, allies=self.allies,
|
return dict(points=self.points, country=self.country, is_defender=self.is_defender, allies=self.allies,
|
||||||
deployed=self.deployed)
|
deployed=self.deployed)
|
||||||
|
|
||||||
@ -1024,3 +1025,27 @@ class OfferItem(NamedTuple):
|
|||||||
amount: int = 0
|
amount: int = 0
|
||||||
offer_id: int = 0
|
offer_id: int = 0
|
||||||
citizen_id: int = 0
|
citizen_id: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class Inventory:
|
||||||
|
final: types.InvFinal
|
||||||
|
active: types.InvFinal
|
||||||
|
boosters: types.InvBooster
|
||||||
|
raw: types.InvRaw
|
||||||
|
market: types.InvRaw
|
||||||
|
used: int
|
||||||
|
total: int
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.active = {}
|
||||||
|
self.final = {}
|
||||||
|
self.boosters = {}
|
||||||
|
self.raw = {}
|
||||||
|
self.offers = {}
|
||||||
|
self.used = 0
|
||||||
|
self.total = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_dict(self) -> Dict[str, Union[types.InvFinal, types.InvRaw, int]]:
|
||||||
|
return dict(active=self.active, final=self.final, boosters=self.boosters, raw=self.raw, offers=self.offers,
|
||||||
|
total=self.total, used=self.used)
|
||||||
|
7
erepublik/types.py
Normal file
7
erepublik/types.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Union
|
||||||
|
|
||||||
|
InvFinalItem = Dict[str, Union[str, int, List[Dict[str, Union[int, datetime]]]]]
|
||||||
|
InvBooster = Dict[str, Dict[int, Dict[int, InvFinalItem]]]
|
||||||
|
InvFinal = Dict[str, Dict[int, InvFinalItem]]
|
||||||
|
InvRaw = Dict[str, Dict[int, Dict[str, Union[str, int]]]]
|
@ -10,7 +10,7 @@ import unicodedata
|
|||||||
import warnings
|
import warnings
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@ -64,7 +64,9 @@ def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.da
|
|||||||
return constants.erep_tz.normalize(dt + td)
|
return constants.erep_tz.normalize(dt + td)
|
||||||
|
|
||||||
|
|
||||||
def eday_from_date(date: Union[datetime.date, datetime.datetime] = now()) -> int:
|
def eday_from_date(date: Union[datetime.date, datetime.datetime] = None) -> int:
|
||||||
|
if date is None:
|
||||||
|
date = now()
|
||||||
if isinstance(date, datetime.date):
|
if isinstance(date, datetime.date):
|
||||||
date = datetime.datetime.combine(date, datetime.time(0, 0, 0))
|
date = datetime.datetime.combine(date, datetime.time(0, 0, 0))
|
||||||
return (date - datetime.datetime(2007, 11, 20, 0, 0, 0)).days
|
return (date - datetime.datetime(2007, 11, 20, 0, 0, 0)).days
|
||||||
@ -253,7 +255,7 @@ def caught_error(e: Exception):
|
|||||||
|
|
||||||
|
|
||||||
def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commit_id: str = None,
|
def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commit_id: str = None,
|
||||||
interactive: Optional[bool] = None):
|
interactive: bool = None):
|
||||||
"""
|
"""
|
||||||
Process error logging and email sending to developer
|
Process error logging and email sending to developer
|
||||||
:param interactive: Should print interactively
|
:param interactive: Should print interactively
|
||||||
@ -377,6 +379,7 @@ def get_final_hit_dmg(base_dmg: Union[Decimal, float, str], rang: int,
|
|||||||
dmg = dmg * 11 / 10
|
dmg = dmg * 11 / 10
|
||||||
return Decimal(dmg)
|
return Decimal(dmg)
|
||||||
|
|
||||||
|
|
||||||
# def _clear_up_battle_memory(battle):
|
# def _clear_up_battle_memory(battle):
|
||||||
# del battle.invader._battle, battle.defender._battle
|
# del battle.invader._battle, battle.defender._battle
|
||||||
# for div_id, division in battle.div.items():
|
# for div_id, division in battle.div.items():
|
||||||
@ -404,4 +407,5 @@ def wait_for_lock(function):
|
|||||||
raise e
|
raise e
|
||||||
instance.concurrency_available.set()
|
instance.concurrency_available.set()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
bump2version==1.0.1
|
bump2version==1.0.1
|
||||||
coverage==5.3
|
coverage==5.3.1
|
||||||
edx-sphinx-theme==1.5.0
|
edx-sphinx-theme==1.6.0
|
||||||
flake8==3.8.4
|
flake8==3.8.4
|
||||||
ipython>=7.19.0
|
ipython>=7.19.0
|
||||||
isort==5.6.4
|
isort==5.7.0
|
||||||
pip==20.3.3
|
pip==20.3.3
|
||||||
PyInstaller==4.1
|
pre-commit==2.9.3
|
||||||
pytz==2020.4
|
|
||||||
pytest==6.2.1
|
|
||||||
responses==0.12.1
|
|
||||||
setuptools==51.0.0
|
|
||||||
Sphinx==3.3.1
|
|
||||||
requests>=2.24.0,<2.26.0
|
|
||||||
PySocks==1.7.1
|
|
||||||
twine==3.2.0
|
|
||||||
wheel==0.36.2
|
|
||||||
pur==5.3.0
|
pur==5.3.0
|
||||||
|
PyInstaller==4.1
|
||||||
|
PySocks==1.7.1
|
||||||
|
pytest==6.2.1
|
||||||
|
pytz>=2020.5
|
||||||
|
requests>=2.25.1
|
||||||
|
responses==0.12.1
|
||||||
|
setuptools==51.1.1
|
||||||
|
Sphinx==3.4.2
|
||||||
|
twine==3.3.0
|
||||||
|
wheel==0.36.2
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.23.3.4
|
current_version = 0.23.4.4
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?
|
||||||
@ -37,4 +37,3 @@ warn_unused_configs = True
|
|||||||
[isort]
|
[isort]
|
||||||
multi_line_output = 2
|
multi_line_output = 2
|
||||||
line_length = 120
|
line_length = 120
|
||||||
not_skip = __init__.py
|
|
||||||
|
4
setup.py
4
setup.py
@ -12,7 +12,7 @@ with open('HISTORY.rst') as history_file:
|
|||||||
history = history_file.read()
|
history = history_file.read()
|
||||||
|
|
||||||
requirements = [
|
requirements = [
|
||||||
'pytz==2020.4',
|
'pytz>=2020.0',
|
||||||
'requests>=2.24.0,<2.26.0',
|
'requests>=2.24.0,<2.26.0',
|
||||||
'PySocks==1.7.1'
|
'PySocks==1.7.1'
|
||||||
]
|
]
|
||||||
@ -50,6 +50,6 @@ setup(
|
|||||||
test_suite='tests',
|
test_suite='tests',
|
||||||
tests_require=test_requirements,
|
tests_require=test_requirements,
|
||||||
url='https://github.com/eeriks/erepublik/',
|
url='https://github.com/eeriks/erepublik/',
|
||||||
version='0.23.3.4',
|
version='0.23.4.4',
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user