Compare commits
36 Commits
v0.23.4.1
...
v0.23.4.11
Author | SHA1 | Date | |
---|---|---|---|
3fba1d6b3d | |||
88c8d5a9a0 | |||
382749a8d8 | |||
0c877e315b | |||
c95f642fee | |||
da0276f9a6 | |||
f89f91e969 | |||
56c2ca1b6e | |||
3cee2d1f0f | |||
0ed03877ce | |||
491c9f5efe | |||
8445b556e7 | |||
d02c5c2969 | |||
bff4183cb6 | |||
47f5142837 | |||
a32fd039dd | |||
311e684c0c | |||
52038a86d5 | |||
c35a107641 | |||
b53b2f0fae | |||
8da9b6221a | |||
caa41c85f6 | |||
da3b5d5768 | |||
f96d0233f9 | |||
c693a5182e | |||
0dfba6a9ff | |||
ee3eca9658 | |||
0e8680daca | |||
8e3606f1a3 | |||
bd0bcc9ac7 | |||
c6f2226e64 | |||
308807d800 | |||
91565d840e | |||
b4a9dd88f8 | |||
8435aa23ba | |||
09cd275a69 |
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
|
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.4.1'
|
__version__ = '0.23.4.11'
|
||||||
|
|
||||||
from erepublik import classes, constants, utils
|
from erepublik import classes, constants, utils
|
||||||
from erepublik.citizen import Citizen
|
from erepublik.citizen import Citizen
|
||||||
|
@ -120,6 +120,10 @@ class CitizenBaseAPI:
|
|||||||
self._req = SlowRequests()
|
self._req = SlowRequests()
|
||||||
self.token = ""
|
self.token = ""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_dict(self):
|
||||||
|
return dict(url=self.url, request=self._req.as_dict, token=self.token)
|
||||||
|
|
||||||
def post(self, url: str, data=None, json=None, **kwargs) -> Response:
|
def post(self, url: str, data=None, json=None, **kwargs) -> Response:
|
||||||
return self._req.post(url, data, json, **kwargs)
|
return self._req.post(url, data, json, **kwargs)
|
||||||
|
|
||||||
@ -305,11 +309,11 @@ class ErepublikEconomyAPI(CitizenBaseAPI):
|
|||||||
return self.post(f"{self.url}/main/buyGoldItems", 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:
|
def _post_economy_activate_booster(self, quality: int, duration: int, kind: str) -> Response:
|
||||||
data = dict(type=kind, quality=quality, duration=duration, fromInventory=True)
|
data = dict(type=kind, quality=quality, duration=duration, fromInventory=True, _token=self.token)
|
||||||
return self.post(f"{self.url}/economy/activateBooster", data=data)
|
return self.post(f"{self.url}/economy/activateBooster", data=data)
|
||||||
|
|
||||||
def _post_economy_activate_house(self, quality: int) -> Response:
|
def _post_economy_activate_house(self, quality: int) -> Response:
|
||||||
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
|
data = dict(action="activate", quality=quality, type="house", _token=self.token)
|
||||||
return self.post(f"{self.url}/economy/activateHouse", data=data)
|
return self.post(f"{self.url}/economy/activateHouse", data=data)
|
||||||
|
|
||||||
def _post_economy_donate_items_action(self, citizen_id: int, amount: int, industry: int,
|
def _post_economy_donate_items_action(self, citizen_id: int, amount: int, industry: int,
|
||||||
@ -595,6 +599,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, time
|
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, types
|
from . import access_points, classes, constants, types, utils
|
||||||
from .classes import OfferItem
|
from .classes import OfferItem
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +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: classes.Inventory
|
_inventory: classes.Inventory
|
||||||
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}
|
||||||
@ -38,9 +38,9 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
energy: classes.Energy = None
|
energy: classes.Energy = None
|
||||||
details: classes.Details = None
|
details: classes.Details = None
|
||||||
politics: classes.Politics = None
|
politics: classes.Politics = None
|
||||||
|
my_companies: classes.MyCompanies = None
|
||||||
reporter: classes.Reporter = None
|
reporter: classes.Reporter = None
|
||||||
stop_threads: Event = None
|
stop_threads: Event = None
|
||||||
concurrency_available: Event = None
|
|
||||||
telegram: classes.TelegramReporter = None
|
telegram: classes.TelegramReporter = None
|
||||||
|
|
||||||
r: Response = None
|
r: Response = None
|
||||||
@ -57,13 +57,11 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
self.my_companies = classes.MyCompanies(self)
|
self.my_companies = classes.MyCompanies(self)
|
||||||
self.reporter = classes.Reporter(self)
|
self.reporter = classes.Reporter(self)
|
||||||
self.stop_threads = Event()
|
self.stop_threads = Event()
|
||||||
self.concurrency_available = Event()
|
|
||||||
self.concurrency_available.set()
|
|
||||||
self.telegram = classes.TelegramReporter(stop_event=self.stop_threads)
|
self.telegram = classes.TelegramReporter(stop_event=self.stop_threads)
|
||||||
|
|
||||||
self.config.email = email
|
self.config.email = email
|
||||||
self.config.password = password
|
self.config.password = password
|
||||||
self.inventory = classes.Inventory()
|
self._inventory = classes.Inventory()
|
||||||
self.wheel_of_fortune = False
|
self.wheel_of_fortune = False
|
||||||
|
|
||||||
def get_csrf_token(self):
|
def get_csrf_token(self):
|
||||||
@ -238,17 +236,18 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
|
|
||||||
def update_inventory(self):
|
def update_inventory(self):
|
||||||
"""
|
"""
|
||||||
Updates class properties and returns structured inventory.
|
Updates citizen inventory
|
||||||
Return structure: {status: {used: int, total: int}, items: {active/final/raw: {item_token:{quality: data}}}
|
|
||||||
If item kind is damageBoosters or aircraftDamageBoosters then kind is renamed to kind+quality and duration is
|
|
||||||
used as quality.
|
|
||||||
"""
|
"""
|
||||||
self._update_inventory_data(self._get_economy_inventory_items().json())
|
self._update_inventory_data(self._get_economy_inventory_items().json())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def inventory(self) -> classes.Inventory:
|
||||||
|
return self.get_inventory()
|
||||||
|
|
||||||
def get_inventory(self, force: bool = False) -> classes.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):
|
||||||
@ -264,8 +263,8 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
|
|
||||||
status = inv_data.get("inventoryStatus", {})
|
status = inv_data.get("inventoryStatus", {})
|
||||||
if status:
|
if status:
|
||||||
self.inventory.used = status.get("usedStorage")
|
self._inventory.used = status.get("usedStorage")
|
||||||
self.inventory.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
|
||||||
@ -287,8 +286,9 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
if item_data.get('attributes').get('expirationInfo'):
|
if item_data.get('attributes').get('expirationInfo'):
|
||||||
expire_info = 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']]
|
expiration_info = [_expire_value_to_python(v) for v in expire_info['value']]
|
||||||
icon = item_data['icon'] if item_data[
|
if not item_data.get('icon') and item_data.get('isPackBooster'):
|
||||||
'icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
item_data['icon'] = f"//www.erepublik.com/images/icons/boosters/52px/{item_data.get('type')}.png"
|
||||||
|
icon = item_data['icon'] if item_data['icon'] else "//www.erepublik.net/images/modules/manager/tab_storage.png"
|
||||||
inv_item: types.InvFinalItem = dict(
|
inv_item: types.InvFinalItem = dict(
|
||||||
name=item_data.get("name"), time_left=item_data['active']['time_left'], icon=icon,
|
name=item_data.get("name"), time_left=item_data['active']['time_left'], icon=icon,
|
||||||
kind=kind, expiration=expiration_info, quality=item_data.get("quality", 0)
|
kind=kind, expiration=expiration_info, quality=item_data.get("quality", 0)
|
||||||
@ -308,7 +308,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
|
|
||||||
if item_data.get('type'):
|
if item_data.get('type'):
|
||||||
# in ['damageBoosters', "aircraftDamageBoosters", 'prestigePointsBoosters']
|
# in ['damageBoosters', "aircraftDamageBoosters", 'prestigePointsBoosters']
|
||||||
if item_data.get('type').endswith('Boosters'):
|
if item_data.get('isBooster'):
|
||||||
is_booster = True
|
is_booster = True
|
||||||
kind = item_data['type']
|
kind = item_data['type']
|
||||||
|
|
||||||
@ -339,6 +339,9 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
elif q == 15:
|
elif q == 15:
|
||||||
self.eb_small += amount
|
self.eb_small += amount
|
||||||
item_data.update(token='energy_bar')
|
item_data.update(token='energy_bar')
|
||||||
|
elif q == 16:
|
||||||
|
self.eb_small += amount
|
||||||
|
item_data.update(token='energy_bar')
|
||||||
kind = re.sub(r'_q\d\d*', "", item_data.get('token'))
|
kind = re.sub(r'_q\d\d*', "", item_data.get('token'))
|
||||||
|
|
||||||
if item_data.get('token', "") == "house_q100":
|
if item_data.get('token', "") == "house_q100":
|
||||||
@ -433,11 +436,11 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
offers[kind] = {}
|
offers[kind] = {}
|
||||||
|
|
||||||
offers[kind].update(offer_data)
|
offers[kind].update(offer_data)
|
||||||
self.inventory.active = active_items
|
self._inventory.active = active_items
|
||||||
self.inventory.final = final_items
|
self._inventory.final = final_items
|
||||||
self.inventory.boosters = boosters
|
self._inventory.boosters = boosters
|
||||||
self.inventory.raw = raw_materials
|
self._inventory.raw = raw_materials
|
||||||
self.inventory.offers = offers
|
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):
|
||||||
@ -465,7 +468,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
self._req.debug = bool(debug)
|
self._req.debug = bool(debug)
|
||||||
|
|
||||||
def to_json(self, indent: bool = False) -> str:
|
def to_json(self, indent: bool = False) -> str:
|
||||||
return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None)
|
return utils.json.dumps(self, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
|
||||||
|
|
||||||
def get_countries_with_regions(self) -> Set[constants.Country]:
|
def get_countries_with_regions(self) -> Set[constants.Country]:
|
||||||
r_json = self._post_main_travel_data().json()
|
r_json = self._post_main_travel_data().json()
|
||||||
@ -520,18 +523,29 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
ret = self.__dict__.copy()
|
ret = super().as_dict
|
||||||
ret.pop('stop_threads', None)
|
ret.update(
|
||||||
ret.pop('_CitizenMilitary__last_war_update_data', None)
|
name=self.name, __str__=self.__str__(),
|
||||||
ret.update(_properties=dict(
|
ebs=dict(normal=self.eb_normal, double=self.eb_double, small=self.eb_small),
|
||||||
now=self.now, should_do_levelup=self.should_do_levelup, is_levelup_reachable=self.is_levelup_reachable,
|
promos=self.promos, inventory=self._inventory.as_dict, ot_points=self.ot_points, food=self.food,
|
||||||
max_time_till_full_ff=self.max_time_till_full_ff, is_levelup_close=self.is_levelup_close,
|
division=self.division, maveric=self.maverick, eday=self.eday, wheel_of_fortune=self.wheel_of_fortune,
|
||||||
time_till_full_ff=self.time_till_full_ff, time_till_week_change=self.time_till_week_change,
|
debug=self.debug,
|
||||||
next_wc_start=self.next_wc_start, next_reachable_energy=self.next_reachable_energy,
|
logged_in=self.logged_in, restricted_ip=self.restricted_ip, _properties=dict(
|
||||||
health_info=self.health_info))
|
now=self.now, should_do_levelup=self.should_do_levelup, is_levelup_reachable=self.is_levelup_reachable,
|
||||||
|
max_time_till_full_ff=self.max_time_till_full_ff, is_levelup_close=self.is_levelup_close,
|
||||||
|
time_till_full_ff=self.time_till_full_ff, time_till_week_change=self.time_till_week_change,
|
||||||
|
next_wc_start=self.next_wc_start, next_reachable_energy=self.next_reachable_energy,
|
||||||
|
health_info=self.health_info),
|
||||||
|
_last_full_update=self._last_full_update, _last_inventory_update=self._last_inventory_update,
|
||||||
|
config=self.config.as_dict, energy=self.energy.as_dict, details=self.details.as_dict,
|
||||||
|
politics=self.politics.as_dict, my_companies=self.my_companies.as_dict, reporter=self.reporter.as_dict,
|
||||||
|
telegram=self.telegram.as_dict, stop_threads=self.stop_threads.is_set(), response=self.r,
|
||||||
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def set_locks(self):
|
||||||
|
self.stop_threads.set()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def health_info(self):
|
def health_info(self):
|
||||||
ret = f"{self.energy.recovered}/{self.energy.limit} + {self.energy.recoverable}, " \
|
ret = f"{self.energy.recovered}/{self.energy.limit} + {self.energy.recoverable}, " \
|
||||||
@ -688,6 +702,10 @@ class BaseCitizen(access_points.CitizenAPI):
|
|||||||
self.eb_double -= amount
|
self.eb_double -= amount
|
||||||
elif q == "12":
|
elif q == "12":
|
||||||
self.eb_small -= amount
|
self.eb_small -= amount
|
||||||
|
elif q == "15":
|
||||||
|
self.eb_small -= amount
|
||||||
|
elif q == "16":
|
||||||
|
self.eb_small -= amount
|
||||||
next_recovery = r_json.get("food_remaining_reset").split(":")
|
next_recovery = r_json.get("food_remaining_reset").split(":")
|
||||||
self.energy.set_reference_time(
|
self.energy.set_reference_time(
|
||||||
utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
|
utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
|
||||||
@ -971,7 +989,6 @@ class CitizenCompanies(BaseCitizen):
|
|||||||
def work_as_manager_in_holding(self, holding: classes.Holding) -> Optional[Dict[str, Any]]:
|
def work_as_manager_in_holding(self, holding: classes.Holding) -> Optional[Dict[str, Any]]:
|
||||||
return self._work_as_manager(holding)
|
return self._work_as_manager(holding)
|
||||||
|
|
||||||
@utils.wait_for_lock
|
|
||||||
def _work_as_manager(self, wam_holding: classes.Holding) -> Optional[Dict[str, Any]]:
|
def _work_as_manager(self, wam_holding: classes.Holding) -> Optional[Dict[str, Any]]:
|
||||||
if self.restricted_ip:
|
if self.restricted_ip:
|
||||||
return None
|
return None
|
||||||
@ -1041,7 +1058,7 @@ class CitizenCompanies(BaseCitizen):
|
|||||||
|
|
||||||
|
|
||||||
class CitizenEconomy(CitizenTravel):
|
class CitizenEconomy(CitizenTravel):
|
||||||
def update_money(self, page: int = 0, currency: int = 62) -> Dict[str, Any]:
|
def update_money(self, page: int = 0, currency: int = 62):
|
||||||
"""
|
"""
|
||||||
Gets monetary market offers to get exact amount of CC and Gold available
|
Gets monetary market offers to get exact amount of CC and Gold available
|
||||||
"""
|
"""
|
||||||
@ -1051,11 +1068,10 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
resp_data = resp.json()
|
resp_data = resp.json()
|
||||||
self.details.cc = float(resp_data.get("ecash").get("value"))
|
self.details.cc = float(resp_data.get("ecash").get("value"))
|
||||||
self.details.gold = float(resp_data.get("gold").get("value"))
|
self.details.gold = float(resp_data.get("gold").get("value"))
|
||||||
return resp_data
|
|
||||||
|
|
||||||
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})
|
||||||
@ -1064,7 +1080,7 @@ 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:
|
||||||
@ -1073,7 +1089,7 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
local_cheapest = sorted(offers, key=lambda o: o.price)[0]
|
local_cheapest = sorted(offers, key=lambda o: o.price)[0]
|
||||||
|
|
||||||
global_cheapest = self.get_market_offers("House", q)[f"q{q}"]
|
global_cheapest = self.get_market_offers("House", q)[f"q{q}"]
|
||||||
if global_cheapest.price + 200 < local_cheapest.price:
|
if global_cheapest.price + 2000 < local_cheapest.price:
|
||||||
if global_cheapest.price + 2000 < self.details.cc:
|
if global_cheapest.price + 2000 < self.details.cc:
|
||||||
if self.travel_to_country(global_cheapest.country):
|
if self.travel_to_country(global_cheapest.country):
|
||||||
buy = self.buy_market_offer(global_cheapest, 1)
|
buy = self.buy_market_offer(global_cheapest, 1)
|
||||||
@ -1119,8 +1135,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"):
|
||||||
inventory = self.get_inventory()
|
house = self.inventory.active.get('House', {}).get(quality)
|
||||||
house = 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(
|
||||||
@ -1201,13 +1216,12 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
|
|
||||||
_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
|
||||||
final_kind = industry in [1, 2, 4, 23]
|
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.final if final_kind else inventory.raw).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.update_inventory()
|
||||||
items = (inventory.final if final_kind else inventory.raw).get(constants.INDUSTRIES[industry],
|
items = (self.inventory.final if final_kind else self.inventory.raw).get(constants.INDUSTRIES[industry],
|
||||||
{_inv_qlt: {'amount': 0}})
|
{_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))
|
||||||
@ -1237,7 +1251,6 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
self._report_action("BOUGHT_PRODUCTS", json_ret.get('message'), kwargs=json_ret)
|
self._report_action("BOUGHT_PRODUCTS", json_ret.get('message'), kwargs=json_ret)
|
||||||
return json_ret
|
return json_ret
|
||||||
|
|
||||||
@utils.wait_for_lock
|
|
||||||
def buy_market_offer(self, offer: OfferItem, amount: int = None) -> Optional[Dict[str, Any]]:
|
def buy_market_offer(self, offer: OfferItem, amount: int = None) -> Optional[Dict[str, Any]]:
|
||||||
if amount is None or amount > offer.amount:
|
if amount is None or amount > offer.amount:
|
||||||
amount = offer.amount
|
amount = offer.amount
|
||||||
@ -1364,7 +1377,7 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
self.update_money()
|
self.update_money()
|
||||||
cur = "g" if currency == 62 else "cc"
|
cur = "g" if currency == 62 else "cc"
|
||||||
if success:
|
if success:
|
||||||
self._report_action("DONATE_MONEY", f"Successfully donated {amount}{cur} to citizen with id {citizen_id}!")
|
self.report_money_donation(citizen_id, amount, currency == 1)
|
||||||
else:
|
else:
|
||||||
self._report_action("DONATE_MONEY", f"Unable to donate {amount}{cur}!")
|
self._report_action("DONATE_MONEY", f"Unable to donate {amount}{cur}!")
|
||||||
return success
|
return success
|
||||||
@ -1448,6 +1461,16 @@ class CitizenEconomy(CitizenTravel):
|
|||||||
f" treasury", kwargs=r.json())
|
f" treasury", kwargs=r.json())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def report_money_donation(self, citizen_id: int, amount: float, is_currency: bool = True):
|
||||||
|
self.reporter.report_money_donation(citizen_id, amount, is_currency)
|
||||||
|
if self.config.telegram:
|
||||||
|
self.telegram.report_money_donation(citizen_id, amount, is_currency)
|
||||||
|
|
||||||
|
def report_item_donation(self, citizen_id: int, amount: float, quality: int, industry: str):
|
||||||
|
self.reporter.report_item_donation(citizen_id, amount, quality, industry)
|
||||||
|
if self.config.telegram:
|
||||||
|
self.telegram.report_item_donation(citizen_id, amount, f"{industry} q{quality}")
|
||||||
|
|
||||||
|
|
||||||
class CitizenLeaderBoard(BaseCitizen):
|
class CitizenLeaderBoard(BaseCitizen):
|
||||||
def get_aircraft_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Dict[str, any]:
|
def get_aircraft_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Dict[str, any]:
|
||||||
@ -1528,11 +1551,15 @@ class CitizenMedia(BaseCitizen):
|
|||||||
|
|
||||||
class CitizenMilitary(CitizenTravel):
|
class CitizenMilitary(CitizenTravel):
|
||||||
all_battles: Dict[int, classes.Battle] = None
|
all_battles: Dict[int, classes.Battle] = None
|
||||||
countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
|
|
||||||
__last_war_update_data = None
|
__last_war_update_data = None
|
||||||
|
|
||||||
active_fs: bool = False
|
active_fs: bool = False
|
||||||
boosters: Dict[int, Dict[int, int]] = {100: {}, 50: {}}
|
|
||||||
|
@property
|
||||||
|
def as_dict(self):
|
||||||
|
d = super().as_dict
|
||||||
|
d.update(active_fs=self.active_fs, all_battles=self.all_battles)
|
||||||
|
return d
|
||||||
|
|
||||||
def update_war_info(self):
|
def update_war_info(self):
|
||||||
if self.__last_war_update_data and self.__last_war_update_data.get('last_updated',
|
if self.__last_war_update_data and self.__last_war_update_data.get('last_updated',
|
||||||
@ -1543,17 +1570,6 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
if r_json.get("countries"):
|
if r_json.get("countries"):
|
||||||
if self.all_battles is None:
|
if self.all_battles is None:
|
||||||
self.all_battles = {}
|
self.all_battles = {}
|
||||||
if self.countries is None:
|
|
||||||
self.countries = {}
|
|
||||||
countries = {}
|
|
||||||
for c_id, c_data in r_json.get("countries").items():
|
|
||||||
if int(c_id) not in countries:
|
|
||||||
countries.update({
|
|
||||||
int(c_id): {"name": c_data.get("name"), "allies": c_data.get("allies")}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
countries[int(c_id)].update(allies=c_data.get("allies"))
|
|
||||||
self.countries = countries
|
|
||||||
self.__last_war_update_data = r_json
|
self.__last_war_update_data = r_json
|
||||||
if r_json.get("battles"):
|
if r_json.get("battles"):
|
||||||
all_battles = {}
|
all_battles = {}
|
||||||
@ -1773,7 +1789,8 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
yield battle, battle_zone, side
|
yield battle, battle_zone, side
|
||||||
|
|
||||||
def find_battle_and_fight(self):
|
def find_battle_and_fight(self):
|
||||||
if self.should_fight()[0]:
|
count = self.should_fight()[0]
|
||||||
|
if count:
|
||||||
self.write_log("Checking for battles to fight in...")
|
self.write_log("Checking for battles to fight in...")
|
||||||
for battle, division, side in self.find_battle_to_fight():
|
for battle, division, side in self.find_battle_to_fight():
|
||||||
|
|
||||||
@ -1800,25 +1817,26 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
|
|
||||||
if self.change_division(battle, division):
|
if self.change_division(battle, division):
|
||||||
self.set_default_weapon(battle, division)
|
self.set_default_weapon(battle, division)
|
||||||
self.fight(battle, division, side)
|
self.fight(battle, division, side, count)
|
||||||
self.travel_to_residence()
|
self.travel_to_residence()
|
||||||
break
|
break
|
||||||
|
|
||||||
@utils.wait_for_lock
|
|
||||||
def fight(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None,
|
def fight(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None,
|
||||||
count: int = None) -> Optional[int]:
|
count: int = None, use_ebs: bool = False) -> Optional[int]:
|
||||||
"""Fight in a battle.
|
"""Fight in a battle.
|
||||||
|
|
||||||
Will auto activate booster and travel if allowed to do it.
|
Will auto activate booster and travel if allowed to do it.
|
||||||
:param battle: Battle battle to fight in
|
:param battle: Battle battle to fight in
|
||||||
:type battle: Battle
|
:type battle: Battle
|
||||||
|
:param division: Division number to fight in available choices
|
||||||
|
:type division: BattleDivision
|
||||||
:param side: BattleSide or None. Battle side to fight in, If side not == invader id or not in invader deployed
|
: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
|
:type side: BattleSide
|
||||||
:param count: How many hits to do, if not specified self.should_fight() is called.
|
:param count: How many hits to do, if not specified self.should_fight() is called.
|
||||||
:type count: int
|
:type count: int
|
||||||
:param division: Division number to fight in available choices
|
:param use_ebs: Should use energy bars if count > 0 and not enough food_fights
|
||||||
:type division: BattleDivision
|
:type use_ebs: bool
|
||||||
:return: None if no errors while fighting, otherwise error count.
|
:return: None if no errors while fighting, otherwise error count.
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
@ -1848,15 +1866,13 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
error_count += error
|
error_count += error
|
||||||
else:
|
else:
|
||||||
self._eat('blue')
|
self._eat('blue')
|
||||||
|
if count > 0 and self.energy.recovered < 50 and use_ebs:
|
||||||
|
self._eat('orange')
|
||||||
if self.energy.recovered < 50 or error_count >= 10 or count <= 0:
|
if self.energy.recovered < 50 or error_count >= 10 or count <= 0:
|
||||||
self.write_log(f"Hits: {total_hits:>4} | Damage: {total_damage}")
|
self.write_log(f"Hits: {total_hits:>4} | Damage: {total_damage}")
|
||||||
ok_to_fight = False
|
ok_to_fight = False
|
||||||
if total_damage:
|
if total_damage:
|
||||||
self.reporter.report_fighting(battle, not side.is_defender, division, total_damage, total_hits)
|
self.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
|
return error_count
|
||||||
|
|
||||||
def _shoot(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide):
|
def _shoot(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide):
|
||||||
@ -1921,7 +1937,6 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
|
|
||||||
return hits, err, damage
|
return hits, err, damage
|
||||||
|
|
||||||
@utils.wait_for_lock
|
|
||||||
def deploy_bomb(self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool,
|
def deploy_bomb(self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool,
|
||||||
count: int = 1) -> Optional[int]:
|
count: int = 1) -> Optional[int]:
|
||||||
"""Deploy bombs in a battle for given side.
|
"""Deploy bombs in a battle for given side.
|
||||||
@ -2018,8 +2033,8 @@ 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_damage_booster(self, ground: bool = True):
|
def activate_damage_booster(self, ground: bool = True) -> int:
|
||||||
kind = 'damageBoosters' if ground else 'aircraftDamageBoosters'
|
kind = 'damage' if ground else 'aircraftDamage'
|
||||||
if self.config.boosters and not self.get_active_damage_booster(ground):
|
if self.config.boosters and not self.get_active_damage_booster(ground):
|
||||||
booster: Optional[types.InvFinalItem] = None
|
booster: Optional[types.InvFinalItem] = None
|
||||||
for quality, data in sorted(self.inventory.boosters.get(kind, {}).items(), key=lambda x: x[0]):
|
for quality, data in sorted(self.inventory.boosters.get(kind, {}).items(), key=lambda x: x[0]):
|
||||||
@ -2030,14 +2045,15 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
break
|
break
|
||||||
break
|
break
|
||||||
if booster:
|
if booster:
|
||||||
|
kind = 'damage' if ground else 'air_damage'
|
||||||
self._report_action("MILITARY_BOOSTER", f"Activated {booster['name']}")
|
self._report_action("MILITARY_BOOSTER", f"Activated {booster['name']}")
|
||||||
self._post_economy_activate_booster(booster['quality'], booster['durability'],
|
resp = self._post_economy_activate_booster(booster['quality'], booster['durability'], kind).json()
|
||||||
'damage' if ground else 'air_damage')
|
self._update_inventory_data(resp)
|
||||||
|
return self.get_active_damage_booster(ground)
|
||||||
|
|
||||||
def get_active_damage_booster(self, ground: bool = True) -> int:
|
def get_active_damage_booster(self, ground: bool = True) -> int:
|
||||||
kind = 'damageBoosters' if ground else 'aircraftDamageBoosters'
|
kind = 'damage' if ground else 'aircraftDamage'
|
||||||
inventory = self.get_inventory()
|
boosters = self.inventory.active.get(kind, {})
|
||||||
boosters = inventory.active.get(kind, {})
|
|
||||||
quality = 0
|
quality = 0
|
||||||
for q, boost in boosters.items():
|
for q, boost in boosters.items():
|
||||||
if boost['quality'] * 10 > quality:
|
if boost['quality'] * 10 > quality:
|
||||||
@ -2050,13 +2066,16 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
def get_active_air_damage_booster(self) -> int:
|
def get_active_air_damage_booster(self) -> int:
|
||||||
return self.get_active_damage_booster(False)
|
return self.get_active_damage_booster(False)
|
||||||
|
|
||||||
def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
|
def activate_battle_effect(self, battle_id: int, kind: str) -> bool:
|
||||||
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)
|
resp = self._post_main_activate_battle_effect(battle_id, kind, self.details.citizen_id).json()
|
||||||
|
return not resp.get('error')
|
||||||
|
|
||||||
def activate_pp_booster(self, pp_item: types.InvFinalItem) -> Response:
|
def activate_pp_booster(self, pp_item: types.InvFinalItem) -> bool:
|
||||||
self._report_action('MILITARY_BOOSTER', f'Activated {pp_item["name"]}')
|
self._report_action('MILITARY_BOOSTER', f'Activated {pp_item["name"]}')
|
||||||
return self._post_economy_activate_booster(pp_item['quality'], pp_item['durability'], 'prestige_points')
|
resp = self._post_economy_activate_booster(pp_item['quality'], pp_item['durability'], 'prestige_points').json()
|
||||||
|
self._update_inventory_data(resp)
|
||||||
|
return pp_item.get('kind') in self.inventory.active
|
||||||
|
|
||||||
def _rw_choose_side(self, battle: classes.Battle, side: classes.BattleSide) -> Response:
|
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)
|
||||||
@ -2217,6 +2236,11 @@ class CitizenMilitary(CitizenTravel):
|
|||||||
if division.wall['dom'] == 50 or division.wall['dom'] > 98:
|
if division.wall['dom'] == 50 or division.wall['dom'] > 98:
|
||||||
yield division, division.wall['for'] == battle.invader.country.id
|
yield division, division.wall['for'] == battle.invader.country.id
|
||||||
|
|
||||||
|
def report_fighting(self, battle: classes.Battle, invader: bool, division: classes.BattleDivision, damage: float, hits: int):
|
||||||
|
self.reporter.report_fighting(battle, invader, division, damage, hits)
|
||||||
|
if self.config.telegram:
|
||||||
|
self.telegram.report_fight(battle, invader, division, damage, hits)
|
||||||
|
|
||||||
|
|
||||||
class CitizenPolitics(BaseCitizen):
|
class CitizenPolitics(BaseCitizen):
|
||||||
def get_country_parties(self, country: constants.Country = None) -> dict:
|
def get_country_parties(self, country: constants.Country = None) -> dict:
|
||||||
@ -2370,6 +2394,12 @@ class CitizenTasks(CitizenEconomy):
|
|||||||
ot_points: int = 0
|
ot_points: int = 0
|
||||||
next_ot_time: datetime = None
|
next_ot_time: datetime = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_dict(self):
|
||||||
|
d = super().as_dict
|
||||||
|
d.update(tg_contract=self.tg_contract, ot_points=self.ot_points, next_ot_time=self.next_ot_time)
|
||||||
|
return d
|
||||||
|
|
||||||
def eat(self):
|
def eat(self):
|
||||||
""" Eat food """
|
""" Eat food """
|
||||||
self._eat("blue")
|
self._eat("blue")
|
||||||
@ -2497,8 +2527,8 @@ class CitizenTasks(CitizenEconomy):
|
|||||||
self.ot_points = ot.get("points", 0)
|
self.ot_points = ot.get("points", 0)
|
||||||
|
|
||||||
|
|
||||||
class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
||||||
CitizenMedia, CitizenPolitics, CitizenSocial, CitizenMilitary, CitizenTasks):
|
CitizenMedia, CitizenPolitics, CitizenSocial, CitizenMilitary, CitizenTasks):
|
||||||
def __init__(self, email: str = "", password: str = "", auto_login: bool = False):
|
def __init__(self, email: str = "", password: str = "", auto_login: bool = False):
|
||||||
super().__init__(email, password)
|
super().__init__(email, password)
|
||||||
self._last_full_update = constants.min_datetime
|
self._last_full_update = constants.min_datetime
|
||||||
@ -2509,10 +2539,18 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load_from_dump(cls, dump_name: str = ""):
|
def load_from_dump(cls, dump_name: str = ""):
|
||||||
filename = dump_name if dump_name else f"{cls.__name__}__dump.json"
|
filename = dump_name if dump_name else f"{cls.__name__}__dump.json"
|
||||||
player: Citizen = super().load_from_dump(filename) # noqa
|
player: _Citizen = super().load_from_dump(filename) # noqa
|
||||||
player.login()
|
player.login()
|
||||||
return player
|
return player
|
||||||
|
|
||||||
|
def _eat(self, colour: str = "blue") -> Response:
|
||||||
|
resp = super()._eat(colour)
|
||||||
|
if not any([resp.json().get("units_consumed").values()]):
|
||||||
|
if colour == 'orange' and resp.json().get('food_remaining'):
|
||||||
|
self.eat()
|
||||||
|
return self._eat(colour)
|
||||||
|
return resp
|
||||||
|
|
||||||
def config_setup(self, **kwargs):
|
def config_setup(self, **kwargs):
|
||||||
self.config.reset()
|
self.config.reset()
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
@ -2616,17 +2654,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()
|
||||||
@ -2669,10 +2711,12 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
else:
|
else:
|
||||||
start_time = utils.good_timedelta(start_time.replace(minute=0), timedelta(hours=1))
|
start_time = utils.good_timedelta(start_time.replace(minute=0), timedelta(hours=1))
|
||||||
while not self.stop_threads.is_set():
|
while not self.stop_threads.is_set():
|
||||||
self.update_citizen_info()
|
|
||||||
start_time = utils.good_timedelta(start_time, timedelta(minutes=30))
|
start_time = utils.good_timedelta(start_time, timedelta(minutes=30))
|
||||||
|
self.update_citizen_info()
|
||||||
|
self.update_weekly_challenge()
|
||||||
self.send_state_update()
|
self.send_state_update()
|
||||||
self.send_inventory_update()
|
self.send_inventory_update()
|
||||||
|
self.update_companies()
|
||||||
self.send_my_companies_update()
|
self.send_my_companies_update()
|
||||||
sleep_seconds = (start_time - self.now).total_seconds()
|
sleep_seconds = (start_time - self.now).total_seconds()
|
||||||
self.stop_threads.wait(sleep_seconds if sleep_seconds > 0 else 0)
|
self.stop_threads.wait(sleep_seconds if sleep_seconds > 0 else 0)
|
||||||
@ -2687,7 +2731,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
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).as_dict)
|
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)
|
||||||
@ -2864,3 +2908,161 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
|
|||||||
self.stop_threads.wait(90)
|
self.stop_threads.wait(90)
|
||||||
except: # noqa
|
except: # noqa
|
||||||
self.report_error('Command central is broken')
|
self.report_error('Command central is broken')
|
||||||
|
|
||||||
|
|
||||||
|
class Citizen(_Citizen):
|
||||||
|
_concurrency_lock: Event
|
||||||
|
_update_lock: Event
|
||||||
|
_update_timeout: int = 10
|
||||||
|
_concurrency_timeout: int = 600
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._concurrency_lock = Event()
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
self._update_lock = Event()
|
||||||
|
self._update_lock.set()
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def update_weekly_challenge(self):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_weekly_challenge()
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def update_companies(self):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_companies()
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def update_war_info(self):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_war_info()
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def update_job_info(self):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_job_info()
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def update_money(self, page: int = 0, currency: int = 62):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_money(page, currency)
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def update_inventory(self):
|
||||||
|
if not self._update_lock.wait(self._update_timeout):
|
||||||
|
e = f'Update concurrency not freed in {self._update_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._update_lock.clear()
|
||||||
|
super().update_inventory()
|
||||||
|
finally:
|
||||||
|
self._update_lock.set()
|
||||||
|
|
||||||
|
def _work_as_manager(self, wam_holding: classes.Holding) -> Optional[Dict[str, Any]]:
|
||||||
|
if not self._concurrency_lock.wait(self._concurrency_timeout):
|
||||||
|
e = f'Concurrency not freed in {self._concurrency_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._concurrency_lock.clear()
|
||||||
|
return super()._work_as_manager(wam_holding)
|
||||||
|
finally:
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
|
||||||
|
def fight(self, battle: classes.Battle, division: classes.BattleDivision, side: classes.BattleSide = None,
|
||||||
|
count: int = None, use_ebs: bool = False) -> Optional[int]:
|
||||||
|
if not self._concurrency_lock.wait(self._concurrency_timeout):
|
||||||
|
e = f'Concurrency not freed in {self._concurrency_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._concurrency_lock.clear()
|
||||||
|
return super().fight(battle, division, side, count, use_ebs)
|
||||||
|
finally:
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
|
||||||
|
def deploy_bomb(self, battle: classes.Battle, division: classes.BattleDivision, bomb_id: int, inv_side: bool,
|
||||||
|
count: int = 1) -> Optional[int]:
|
||||||
|
if not self._concurrency_lock.wait(self._concurrency_timeout):
|
||||||
|
e = f'Concurrency not freed in {self._concurrency_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._concurrency_lock.clear()
|
||||||
|
return super().deploy_bomb(battle, division, bomb_id, inv_side, count)
|
||||||
|
finally:
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
|
||||||
|
def buy_market_offer(self, offer: OfferItem, amount: int = None) -> Optional[Dict[str, Any]]:
|
||||||
|
if not self._concurrency_lock.wait(self._concurrency_timeout):
|
||||||
|
e = f'Concurrency not freed in {self._concurrency_timeout}sec!'
|
||||||
|
self.write_log(e)
|
||||||
|
if self.debug:
|
||||||
|
self.report_error(e)
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
self._concurrency_lock.clear()
|
||||||
|
return super().buy_market_offer(offer, amount)
|
||||||
|
finally:
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_dict(self):
|
||||||
|
d = super().as_dict
|
||||||
|
d.update(locks=dict(concurrency_lock=self._concurrency_lock.is_set(), update_lock=self._update_lock.is_set(),
|
||||||
|
concurrency_timeout=self._concurrency_timeout, update_timeout=self._update_timeout))
|
||||||
|
return d
|
||||||
|
|
||||||
|
def set_locks(self):
|
||||||
|
super().set_locks()
|
||||||
|
self._concurrency_lock.set()
|
||||||
|
self._update_lock.set()
|
||||||
|
@ -7,7 +7,7 @@ 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, types
|
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',
|
||||||
@ -650,6 +650,16 @@ class Reporter:
|
|||||||
air=battle.has_air, hits=hits,
|
air=battle.has_air, hits=hits,
|
||||||
round=battle.zone_id, extra=dict(battle=battle, side=side, division=division)))
|
round=battle.zone_id, extra=dict(battle=battle, side=side, division=division)))
|
||||||
|
|
||||||
|
def report_money_donation(self, citizen_id: int, amount: float, is_currency: bool = True):
|
||||||
|
cur = 'cc' if is_currency else 'gold'
|
||||||
|
self.report_action('DONATE_MONEY', dict(citizen_id=citizen_id, amount=amount, currency=cur),
|
||||||
|
f"Successfully donated {amount}{cur} to citizen with id {citizen_id}!")
|
||||||
|
|
||||||
|
def report_item_donation(self, citizen_id: int, amount: float, quality: int, industry: str):
|
||||||
|
self.report_action('DONATE_ITEMS',
|
||||||
|
dict(citizen_id=citizen_id, amount=amount, quality=quality, industry=industry),
|
||||||
|
f"Successfully donated {amount} x {industry} q{quality} to citizen with id {citizen_id}!")
|
||||||
|
|
||||||
def report_promo(self, kind: str, time_until: datetime.datetime):
|
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))
|
self._req.post(f"{self.url}/promos/add/", data=dict(kind=kind, time_untill=time_until))
|
||||||
|
|
||||||
@ -974,7 +984,7 @@ class TelegramReporter:
|
|||||||
self._last_time = utils.good_timedelta(utils.now(), datetime.timedelta(minutes=-5))
|
self._last_time = utils.good_timedelta(utils.now(), datetime.timedelta(minutes=-5))
|
||||||
self._last_full_energy_report = utils.good_timedelta(utils.now(), datetime.timedelta(minutes=-30))
|
self._last_full_energy_report = utils.good_timedelta(utils.now(), datetime.timedelta(minutes=-30))
|
||||||
if self.__queue:
|
if self.__queue:
|
||||||
self.send_message("\n\n––––––––––––––––––––––\n\n".join(self.__queue))
|
self.send_message("Telegram initialized")
|
||||||
|
|
||||||
def send_message(self, message: str) -> bool:
|
def send_message(self, message: str) -> bool:
|
||||||
self.__queue.append(message)
|
self.__queue.append(message)
|
||||||
@ -1002,15 +1012,29 @@ class TelegramReporter:
|
|||||||
new_line = '\n' if multiple else ''
|
new_line = '\n' if multiple else ''
|
||||||
self.send_message(f"New award: {new_line}*{msg}*")
|
self.send_message(f"New award: {new_line}*{msg}*")
|
||||||
|
|
||||||
|
def report_fight(self, battle: "Battle", invader: bool, division: "BattleDivision", damage: float, hits: int):
|
||||||
|
side_txt = (battle.invader if invader else battle.defender).country.iso
|
||||||
|
self.send_message(f"*Fight report*:\n{int(damage):,d} dmg ({hits} hits) in"
|
||||||
|
f" [battle {battle.id} for {battle.region_name[:16]}]({battle.link}) in d{division.div} on "
|
||||||
|
f"{side_txt} side")
|
||||||
|
|
||||||
|
def report_item_donation(self, citizen_id: int, amount: float, product: str):
|
||||||
|
self.send_message(f"*Donation*: {amount} x {product} to citizen "
|
||||||
|
f"[{citizen_id}](https://www.erepublik.com/en/citizen/profile/{citizen_id})")
|
||||||
|
|
||||||
|
def report_money_donation(self, citizen_id: int, amount: float, is_currency: bool = True):
|
||||||
|
self.send_message(f"*Donation*: {amount}{'cc' if is_currency else 'gold'} to citizen "
|
||||||
|
f"[{citizen_id}](https://www.erepublik.com/en/citizen/profile/{citizen_id})")
|
||||||
|
|
||||||
def __send_messages(self):
|
def __send_messages(self):
|
||||||
while self._next_time > utils.now():
|
while self._next_time > utils.now():
|
||||||
if self.__thread_stopper.is_set():
|
if self.__thread_stopper.is_set():
|
||||||
break
|
break
|
||||||
self.__thread_stopper.wait(utils.get_sleep_seconds(self._next_time))
|
self.__thread_stopper.wait(utils.get_sleep_seconds(self._next_time))
|
||||||
|
|
||||||
message = "\n\n––––––––––––––––––––––\n\n".join(self.__queue)
|
message = "\n\n".join(self.__queue)
|
||||||
if self.player_name:
|
if self.player_name:
|
||||||
message = f"Player *{self.player_name}*\n" + message
|
message = f"Player *{self.player_name}*\n\n" + message
|
||||||
response = post(self.api_url, json=dict(chat_id=self.chat_id, text=message, parse_mode="Markdown"))
|
response = post(self.api_url, json=dict(chat_id=self.chat_id, text=message, parse_mode="Markdown"))
|
||||||
self._last_time = utils.now()
|
self._last_time = utils.now()
|
||||||
if response.json().get('ok'):
|
if response.json().get('ok'):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, Union, List
|
from typing import Dict, List, Union
|
||||||
|
|
||||||
InvFinalItem = Dict[str, Union[str, int, List[Dict[str, Union[int, datetime]]]]]
|
InvFinalItem = Dict[str, Union[str, int, List[Dict[str, Union[int, datetime]]]]]
|
||||||
InvBooster = Dict[str, Dict[int, Dict[int, InvFinalItem]]]
|
InvBooster = Dict[str, Dict[int, Dict[int, InvFinalItem]]]
|
||||||
|
@ -5,14 +5,15 @@ flake8==3.8.4
|
|||||||
ipython>=7.19.0
|
ipython>=7.19.0
|
||||||
isort==5.7.0
|
isort==5.7.0
|
||||||
pip==20.3.3
|
pip==20.3.3
|
||||||
|
pre-commit==2.9.3
|
||||||
|
pur==5.3.0
|
||||||
PyInstaller==4.1
|
PyInstaller==4.1
|
||||||
pytz>=2020.0
|
|
||||||
pytest==6.2.1
|
|
||||||
responses==0.12.1
|
|
||||||
setuptools==51.1.1
|
|
||||||
Sphinx==3.4.2
|
|
||||||
requests>=2.24.0,<2.26.0
|
|
||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
|
pytest==6.2.1
|
||||||
|
pytz>=2020.5
|
||||||
|
requests>=2.25.1
|
||||||
|
responses==0.12.1
|
||||||
|
setuptools==51.1.2
|
||||||
|
Sphinx==3.4.3
|
||||||
twine==3.3.0
|
twine==3.3.0
|
||||||
wheel==0.36.2
|
wheel==0.36.2
|
||||||
pur==5.3.0
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.23.4.1
|
current_version = 0.23.4.11
|
||||||
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
|
|
||||||
|
2
setup.py
2
setup.py
@ -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.4.1',
|
version='0.23.4.11',
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user