Compare commits

...

14 Commits

Author SHA1 Message Date
8da9b6221a Bump version: 0.23.4.4 → 0.23.4.5 2021-01-07 15:36:33 +02:00
caa41c85f6 minor tweaks 2021-01-07 15:36:27 +02:00
da3b5d5768 Update inventory on booster activation 2021-01-07 15:31:46 +02:00
f96d0233f9 CSRF bugfix 2021-01-07 15:31:10 +02:00
c693a5182e Merge branch 'master' of github.com:eeriks/erepublik 2021-01-07 15:14:17 +02:00
0dfba6a9ff Find battle and fight - reuse already calculated hit count 2021-01-07 15:14:11 +02:00
ee3eca9658 Bump version: 0.23.4.3 → 0.23.4.4 2021-01-06 23:37:05 +02:00
0e8680daca bugfix 2021-01-06 23:35:25 +02:00
8e3606f1a3 Doc update 2021-01-05 19:47:43 +02:00
bd0bcc9ac7 Bump version: 0.23.4.2 → 0.23.4.3 2021-01-05 19:35:00 +02:00
c6f2226e64 . 2021-01-05 19:34:43 +02:00
308807d800 isort, pre-commit 2021-01-05 19:29:20 +02:00
91565d840e Added endpoint for collect all WC rewards 2021-01-05 19:18:20 +02:00
b4a9dd88f8 config generator bugdix 2021-01-05 19:17:50 +02:00
16 changed files with 125 additions and 38 deletions

1
.gitignore vendored
View File

@ -102,5 +102,4 @@ ENV/
debug/ debug/
log/ log/
docs/
*dump.json *dump.json

13
.pre-commit-config.yaml Normal file
View 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

View File

@ -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.

View File

@ -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
View 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:

View File

@ -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
View File

@ -0,0 +1,7 @@
erepublik
=========
.. toctree::
:maxdepth: 4
erepublik

View File

@ -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()

View File

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

View File

@ -305,11 +305,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 +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)

View File

@ -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
@ -238,10 +238,7 @@ 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())
@ -312,7 +309,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']
@ -1207,7 +1204,7 @@ class CitizenEconomy(CitizenTravel):
items = (self.inventory.final if final_kind else self.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.get_inventory(True) self.update_inventory()
items = (self.inventory.final if final_kind else self.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:
@ -1775,7 +1772,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():
@ -1802,7 +1800,7 @@ 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
@ -2020,7 +2018,7 @@ 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 = 'damageBoosters' if ground else 'aircraftDamageBoosters'
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
@ -2032,9 +2030,11 @@ 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 = 'damageBoosters' if ground else 'aircraftDamageBoosters'
@ -2051,13 +2051,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)
@ -2617,17 +2620,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()
@ -2670,7 +2677,6 @@ 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.send_state_update() self.send_state_update()
self.send_inventory_update() self.send_inventory_update()
@ -2681,6 +2687,7 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
self.report_error("State updater crashed") self.report_error("State updater crashed")
def send_state_update(self): def send_state_update(self):
self.update_all(True)
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.total, inv=self.inventory.used, inv_total=self.inventory.total, inv=self.inventory.used,
hp_limit=self.energy.limit, hp_limit=self.energy.limit,

View File

@ -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',

View File

@ -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]]]

View File

@ -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 PySocks==1.7.1
pytest==6.2.1 pytest==6.2.1
pytz>=2020.5
requests>=2.25.1
responses==0.12.1 responses==0.12.1
setuptools==51.1.1 setuptools==51.1.1
Sphinx==3.4.2 Sphinx==3.4.2
requests>=2.24.0,<2.26.0
PySocks==1.7.1
twine==3.3.0 twine==3.3.0
wheel==0.36.2 wheel==0.36.2
pur==5.3.0

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.23.4.2 current_version = 0.23.4.5
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

View File

@ -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.2', version='0.23.4.5',
zip_safe=False, zip_safe=False,
) )