Compare commits

...

14 Commits

Author SHA1 Message Date
9aae685b21 Bump version: 0.25.0.2 → 0.25.0.3 2021-07-10 00:47:51 +03:00
cae94d7aa8 requirement update 2021-07-10 00:47:40 +03:00
fae7b0fd37 Bump version: 0.25.0.1 → 0.25.0.2 2021-07-10 00:37:46 +03:00
b7771b4da2 Update 2021-07-10 00:36:22 +03:00
e3a10af101 Bump version: 0.25.0 → 0.25.0.1 2021-05-25 09:54:44 +03:00
33a5bcacf1 Backward compatability bugfix 2021-05-25 09:54:35 +03:00
342ca2e1cc Bump version: 0.24.2.4 → 0.25.0 2021-05-25 09:49:49 +03:00
580240a015 isort 2021-05-25 09:49:27 +03:00
1517103ba3 Remove deprecated eat task from examples 2021-05-25 09:48:08 +03:00
3dac8c5e74 New eating 2021-05-25 09:43:47 +03:00
8cf86fb9d3 Bump version: 0.24.2.3 → 0.24.2.4 2021-04-27 12:21:54 +03:00
cf927df6e6 bugfix 2021-04-27 12:21:50 +03:00
a6f5dbd05f Bump version: 0.24.2.2 → 0.24.2.3 2021-04-27 12:19:22 +03:00
967afa472f Rank.__str__ 2021-04-27 12:18:56 +03:00
9 changed files with 122 additions and 157 deletions

View File

@ -4,7 +4,7 @@
__author__ = """Eriks Karls""" __author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv' __email__ = 'eriks@72.lv'
__version__ = '0.24.2.2' __version__ = '0.25.0.3'
from erepublik.citizen import Citizen from erepublik.citizen import Citizen

View File

@ -144,7 +144,7 @@ class CitizenBaseAPI:
self._req.proxies = dict(http=url, https=url) self._req.proxies = dict(http=url, https=url)
def set_http_proxy(self, host: str, port: int, username: str = None, password: str = None): def set_http_proxy(self, host: str, port: int, username: str = None, password: str = None):
url = f'http://{username}:{password}@{host}:{port}' if username and password else f'socks5://{host}:{port}' url = f'http://{username}:{password}@{host}:{port}' if username and password else f'http://{host}:{port}'
self._req.proxies = dict(http=url) self._req.proxies = dict(http=url)
def _get_main_session_captcha(self) -> Response: def _get_main_session_captcha(self) -> Response:
@ -154,7 +154,8 @@ class CitizenBaseAPI:
return self.get(f'{self.url}/main/sessionUnlockPopup') return self.get(f'{self.url}/main/sessionUnlockPopup')
def _post_main_session_get_challenge(self, captcha_id: int, image_id: str = "") -> Response: def _post_main_session_get_challenge(self, captcha_id: int, image_id: str = "") -> Response:
env = dict(l=['tets', ], s=[], c=["l_chathwe", "l_chatroom"], m=0) c = [cookie.name for cookie in self._req.cookies if not cookie.has_nonstandard_attr('HttpOnly')]
env = dict(l=['tets'], s=[], c=c, m=0)
data = dict(_token=self.token, captchaId=captcha_id, env=utils.b64json(env)) data = dict(_token=self.token, captchaId=captcha_id, env=utils.b64json(env))
if image_id: if image_id:
data.update(imageId=image_id, isRefresh=True) data.update(imageId=image_id, isRefresh=True)
@ -177,6 +178,9 @@ class CitizenBaseAPI:
return self.post(f'{self.url}/main/sessionUnlock', data=data, json=data, return self.post(f'{self.url}/main/sessionUnlock', data=data, json=data,
headers={'X-Requested-With': 'XMLHttpRequest', 'Referer': 'https://www.erepublik.com/en'}) headers={'X-Requested-With': 'XMLHttpRequest', 'Referer': 'https://www.erepublik.com/en'})
def _post_energy_refill_get_inventory(self):
return self.post(f'{self.url}/economy/energyRefill-getInventory', data={'_token': self.token})
class ErepublikAnniversaryAPI(CitizenBaseAPI): class ErepublikAnniversaryAPI(CitizenBaseAPI):
def _post_main_collect_anniversary_reward(self) -> Response: def _post_main_collect_anniversary_reward(self) -> Response:

View File

@ -13,8 +13,7 @@ from requests import HTTPError, RequestException, Response
from erepublik import _types as types from erepublik import _types as types
from erepublik import access_points, classes, constants, utils from erepublik import access_points, classes, constants, utils
from erepublik._logging import ErepublikErrorHTTTPHandler, ErepublikFileHandler, ErepublikFormatter, \ from erepublik._logging import ErepublikErrorHTTTPHandler, ErepublikFileHandler, ErepublikFormatter, ErepublikLogConsoleHandler
ErepublikLogConsoleHandler
class BaseCitizen(access_points.CitizenAPI): class BaseCitizen(access_points.CitizenAPI):
@ -78,7 +77,8 @@ class BaseCitizen(access_points.CitizenAPI):
(after 15min time of inactivity opening page in eRepublik.com redirects to home page), (after 15min time of inactivity opening page in eRepublik.com redirects to home page),
by explicitly requesting homepage. by explicitly requesting homepage.
""" """
resp = self._req.get(self.url) # Idiots have fucked up their session manager - after logging in You might be redirected to public homepage instead of authenticated
resp = self._req.get(self.url if self.logged_in else f"{self.url}/economy/myCompanies")
self.r = resp self.r = resp
if self._errors_in_response(resp): if self._errors_in_response(resp):
self.get_csrf_token() self.get_csrf_token()
@ -206,13 +206,16 @@ class BaseCitizen(access_points.CitizenAPI):
citizen_js = utils.json.loads(ugly_js) citizen_js = utils.json.loads(ugly_js)
citizen = citizen_js.get('citizen', {}) citizen = citizen_js.get('citizen', {})
self.details.citizen_id = int(citizen['citizenId'])
self.name = citizen['name']
self.eday = citizen_js.get('settings').get('eDay') self.eday = citizen_js.get('settings').get('eDay')
self.division = int(citizen.get('division', 0)) self.division = int(citizen.get('division', 0))
self.energy.interval = citizen.get('energyPerInterval', 0) self.energy.interval = citizen.get('energyPerInterval', 0)
self.energy.limit = citizen.get('energyToRecover', 0) self.energy.limit = citizen.get('energyPoolLimit', 0)
self.energy.recovered = citizen.get('energy', 0) self.energy.energy = citizen.get('energy', 0)
self.energy.recoverable = citizen.get('energyFromFoodRemaining', 0) # self.energy.set_reference_time(utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2]))))
self.details.current_region = citizen.get('regionLocationId', 0) self.details.current_region = citizen.get('regionLocationId', 0)
self.details.current_country = constants.COUNTRIES.get( self.details.current_country = constants.COUNTRIES.get(
@ -279,8 +282,19 @@ class BaseCitizen(access_points.CitizenAPI):
def refresh_captcha_image(self, captcha_id: int, image_id: str): def refresh_captcha_image(self, captcha_id: int, image_id: str):
return self._post_main_session_get_challenge(captcha_id, image_id).json() return self._post_main_session_get_challenge(captcha_id, image_id).json()
def solve_captcha(self, src: str) -> List[Dict[str, int]]: def solve_captcha(self, src: str) -> Optional[List[Dict[str, int]]]:
return [] class _API_RESULT(dict):
x: int
y: int
class _API_RETURN(dict):
status: bool
message: str
result: Optional[List[_API_RESULT]]
solve_data: _API_RETURN = self.post('https://api.erep.lv/captcha/api', data=dict(citizen_id=self.details.citizen_id, src=src, key='CaptchaDevAPI')).json()
if solve_data['status']:
return solve_data.get('result')
@property @property
def inventory(self) -> classes.Inventory: def inventory(self) -> classes.Inventory:
@ -588,11 +602,11 @@ class BaseCitizen(access_points.CitizenAPI):
def _resume_session(self): def _resume_session(self):
resp = self._req.get(self.url) resp = self._req.get(self.url)
re_name_id = re.search(r'<a data-fblog="profile_avatar" href="/en/citizen/profile/(\d+)" ' try:
r'class="user_avatar" title="(.*?)">', resp.text) self.update_citizen_info(resp.text)
if re_name_id: if not self.name:
self.name = re_name_id.group(2) raise classes.ErepublikException("Unable to find player name")
self.details.citizen_id = re_name_id.group(1)
self.write_log(f"Resumed as: {self.name}") self.write_log(f"Resumed as: {self.name}")
if re.search('<div id="accountSecurity" class="it-hurts-when-ip">', resp.text): if re.search('<div id="accountSecurity" class="it-hurts-when-ip">', resp.text):
self.restricted_ip = True self.restricted_ip = True
@ -600,7 +614,7 @@ class BaseCitizen(access_points.CitizenAPI):
self.logged_in = True self.logged_in = True
self.get_csrf_token() self.get_csrf_token()
else: except classes.ErepublikException:
self._login() self._login()
def __str__(self) -> str: def __str__(self) -> str:
@ -636,7 +650,7 @@ class BaseCitizen(access_points.CitizenAPI):
@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.energy}/{self.energy.limit}, " \
f"{self.energy.interval}hp/6m. {self.details.xp_till_level_up}xp until level up" f"{self.energy.interval}hp/6m. {self.details.xp_till_level_up}xp until level up"
return ret return ret
@ -663,10 +677,9 @@ class BaseCitizen(access_points.CitizenAPI):
@property @property
def time_till_full_ff(self) -> timedelta: def time_till_full_ff(self) -> timedelta:
energy = self.energy.recoverable + self.energy.recovered if self.energy.energy >= self.energy.limit:
if energy >= self.energy.limit * 2:
return timedelta(0) return timedelta(0)
minutes_needed = round((self.energy.limit * 2 - energy) / self.energy.interval) * 6 minutes_needed = round((self.energy.limit - self.energy.energy) / self.energy.interval) * 6
return (self.energy.reference_time - self.now) + timedelta(minutes=minutes_needed) return (self.energy.reference_time - self.now) + timedelta(minutes=minutes_needed)
@property @property
@ -675,7 +688,7 @@ class BaseCitizen(access_points.CitizenAPI):
Max required time for 0 to full energy (0/0 -> limit/limit) (last interval rounded up) Max required time for 0 to full energy (0/0 -> limit/limit) (last interval rounded up)
:return: :return:
""" """
return timedelta(minutes=round((self.energy.limit * 2 / self.energy.interval) + 0.49) * 6) return timedelta(minutes=round((self.energy.limit / self.energy.interval) + 0.49) * 6)
@property @property
def is_levelup_close(self) -> bool: def is_levelup_close(self) -> bool:
@ -699,8 +712,8 @@ class BaseCitizen(access_points.CitizenAPI):
If Energy limit >= xp till levelup * 10 If Energy limit >= xp till levelup * 10
:return: bool :return: bool
""" """
can_reach_next_level = self.energy.recovered >= self.details.xp_till_level_up * 10 can_reach_next_level = self.energy.energy >= self.details.xp_till_level_up * 10
can_do_max_amount_of_dmg = self.energy.recoverable + 2 * self.energy.interval >= self.energy.limit can_do_max_amount_of_dmg = self.energy.energy + 2 * self.energy.interval >= self.energy.limit
return can_reach_next_level and can_do_max_amount_of_dmg return can_reach_next_level and can_do_max_amount_of_dmg
@property @property
@ -774,28 +787,6 @@ class BaseCitizen(access_points.CitizenAPI):
ret.update({id_: name}) ret.update({id_: name})
return ret return ret
def _eat(self, colour: str = 'blue') -> Response:
response = self._post_eat(colour)
r_json = response.json()
for q, amount in r_json.get('units_consumed').items():
if f"q{q}" in self.food:
self.food[f"q{q}"] -= amount
elif q == '10':
self.eb_normal -= amount
elif q == '11':
self.eb_double -= amount
elif 11 < int(q) < 17:
self.eb_small -= amount
elif q == '17':
self.eb_triple -= amount
next_recovery = r_json.get('food_remaining_reset').split(":")
self.energy.set_reference_time(
utils.good_timedelta(self.now, timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
)
self.energy.recovered = r_json.get('health')
self.energy.recoverable = r_json.get('food_remaining')
return response
def _login(self): def _login(self):
# MUST BE CALLED TROUGH self.get_csrf_token() # MUST BE CALLED TROUGH self.get_csrf_token()
r = self._post_login(self.config.email, self.config.password) r = self._post_login(self.config.email, self.config.password)
@ -827,9 +818,12 @@ class BaseCitizen(access_points.CitizenAPI):
pass pass
if response.status_code >= 400: if response.status_code >= 400:
self.r = response self.r = response
if '<title>Attention Required! | Cloudflare</title>' in response.text:
self.write_warning('Cloudflare blocked request! You must inject valid CloudFlare cookie!')
raise classes.CloudFlareSessionError(f"CloudFlare session error!", response)
if response.text == 'Please verify your account.' or response.text == 'Forbidden': if response.text == 'Please verify your account.' or response.text == 'Forbidden':
self.do_captcha_challenge() self.do_captcha_challenge()
return True raise classes.CaptchaSessionError(f"CaptchaSession has expired!", response)
elif response.status_code >= 500: elif response.status_code >= 500:
if self.restricted_ip: if self.restricted_ip:
self._req.cookies.clear() self._req.cookies.clear()
@ -1931,17 +1925,14 @@ class CitizenMilitary(CitizenTravel):
error_count = total_damage = total_hits = 0 error_count = total_damage = total_hits = 0
ok_to_fight = True ok_to_fight = True
while ok_to_fight and error_count < 10 and count > 0: while ok_to_fight and error_count < 10 and count > 0:
while all((count > 0, error_count < 10, self.energy.recovered >= 50)): while all((count > 0, error_count < 10, self.energy.energy >= 50)):
hits, error, damage = self._shoot(battle, division, side) hits, error, damage = self._shoot(battle, division, side)
count -= hits count -= hits
total_hits += hits total_hits += hits
total_damage += damage total_damage += damage
error_count += error error_count += error
else: else:
self._eat('blue') if self.energy.energy < 50 or error_count >= 10 or count <= 0:
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:
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:
@ -2009,14 +2000,14 @@ class CitizenMilitary(CitizenTravel):
hits = r_json['user']['earnedXp'] hits = r_json['user']['earnedXp']
# InfantryKit player # InfantryKit player
# The almost always safe way (breaks on levelup hit) # The almost always safe way (breaks on levelup hit)
elif self.energy.recovered >= r_json['details']['wellness']: # Haven't reached levelup elif self.energy.energy >= r_json['details']['wellness']: # Haven't reached levelup
hits = (self.energy.recovered - r_json['details']['wellness']) // 10 hits = (self.energy.energy - r_json['details']['wellness']) // 10
else: else:
hits = r_json['hits'] hits = r_json['hits']
if r_json['user']['epicBattle']: if r_json['user']['epicBattle']:
hits /= 1 + r_json['user']['epicBattle'] hits /= 1 + r_json['user']['epicBattle']
self.energy.recovered = r_json['details']['wellness'] self.energy.energy = r_json['details']['wellness']
self.details.xp = int(r_json['details']['points']) self.details.xp = int(r_json['details']['points'])
damage = r_json['user']['givenDamage'] * (1.1 if r_json['oldEnemy']['isNatural'] else 1) damage = r_json['user']['givenDamage'] * (1.1 if r_json['oldEnemy']['isNatural'] else 1)
else: else:
@ -2179,7 +2170,7 @@ class CitizenMilitary(CitizenTravel):
elif self.next_reachable_energy and self.config.next_energy: elif self.next_reachable_energy and self.config.next_energy:
ret = True ret = True
# 1h worth of energy # 1h worth of energy
elif self.energy.available + self.energy.interval * 3 >= self.energy.limit * 2: elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit:
ret = True ret = True
return ret return ret
@ -2218,7 +2209,7 @@ class CitizenMilitary(CitizenTravel):
msg = 'Continuing to fight in previous battle' msg = 'Continuing to fight in previous battle'
# All-in (type = all-in and full ff) # All-in (type = all-in and full ff)
elif self.config.all_in and self.energy.available + self.energy.interval * 3 >= self.energy.limit * 2: elif self.config.all_in and self.energy.energy + self.energy.interval * 3 >= self.energy.limit:
count = self.energy.food_fights count = self.energy.food_fights
msg = "Fighting all-in. Doing %i hits" % count msg = "Fighting all-in. Doing %i hits" % count
@ -2228,7 +2219,7 @@ class CitizenMilitary(CitizenTravel):
msg = "Fighting for +1 energy. Doing %i hits" % count msg = "Fighting for +1 energy. Doing %i hits" % count
# 1h worth of energy # 1h worth of energy
elif self.energy.available + self.energy.interval * 3 >= self.energy.limit * 2: elif self.energy.energy + self.energy.interval * 3 >= self.energy.limit:
count = self.energy.interval count = self.energy.interval
msg = "Fighting for 1h energy. Doing %i hits" % count msg = "Fighting for 1h energy. Doing %i hits" % count
force_fight = True force_fight = True
@ -2551,10 +2542,6 @@ class CitizenTasks(CitizenEconomy):
d.update(tg_contract=self.tg_contract, ot_points=self.ot_points, next_ot_time=self.next_ot_time) d.update(tg_contract=self.tg_contract, ot_points=self.ot_points, next_ot_time=self.next_ot_time)
return d return d
def eat(self):
""" Eat food """
self._eat('blue')
def work(self): def work(self):
if self.energy.food_fights >= 1: if self.energy.food_fights >= 1:
response = self._post_economy_work('work') response = self._post_economy_work('work')
@ -2571,12 +2558,10 @@ class CitizenTasks(CitizenEconomy):
else: else:
self.reporter.report_action('WORK', json_val=js) self.reporter.report_action('WORK', json_val=js)
else: else:
self._eat('blue')
if self.energy.food_fights < 1: if self.energy.food_fights < 1:
seconds = (self.energy.reference_time - self.now).total_seconds() seconds = (self.energy.reference_time - self.now).total_seconds()
self.write_warning(f"I don't have energy to work. Will sleep for {seconds}s") self.write_warning(f"I don't have energy to work. Will sleep for {seconds}s")
self.sleep(seconds) self.sleep(seconds)
self._eat('blue')
self.work() self.work()
def train(self): def train(self):
@ -2600,13 +2585,11 @@ class CitizenTasks(CitizenEconomy):
else: else:
self.reporter.report_action('TRAIN', response.json()) self.reporter.report_action('TRAIN', response.json())
else: else:
self._eat('blue')
if self.energy.food_fights < len(tgs): if self.energy.food_fights < len(tgs):
large = max(self.energy.reference_time, self.now) large = max(self.energy.reference_time, self.now)
sleep_seconds = utils.get_sleep_seconds(large) sleep_seconds = utils.get_sleep_seconds(large)
self.write_warning(f"I don't have energy to train. Will sleep for {sleep_seconds} seconds") self.write_warning(f"I don't have energy to train. Will sleep for {sleep_seconds} seconds")
self.sleep(sleep_seconds) self.sleep(sleep_seconds)
self._eat('blue')
self.train() self.train()
def work_ot(self): def work_ot(self):
@ -2624,13 +2607,11 @@ class CitizenTasks(CitizenEconomy):
self.buy_food(120) self.buy_food(120)
self.reporter.report_action('WORK_OT', r.json()) self.reporter.report_action('WORK_OT', r.json())
elif self.energy.food_fights < 1 and self.ot_points >= 24: elif self.energy.food_fights < 1 and self.ot_points >= 24:
self._eat('blue')
if self.energy.food_fights < 1: if self.energy.food_fights < 1:
large = max(self.energy.reference_time, self.now) large = max(self.energy.reference_time, self.now)
sleep_seconds = utils.get_sleep_seconds(large) sleep_seconds = utils.get_sleep_seconds(large)
self.write_warning(f"I don't have energy to work OT. Will sleep for {sleep_seconds}s") self.write_warning(f"I don't have energy to work OT. Will sleep for {sleep_seconds}s")
self.sleep(sleep_seconds) self.sleep(sleep_seconds)
self._eat('blue')
self.work_ot() self.work_ot()
def resign_from_employer(self) -> bool: def resign_from_employer(self) -> bool:
@ -2694,14 +2675,6 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
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():
@ -2720,9 +2693,10 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
self.config.telegram_token, self.config.telegram_token,
self.name) self.name)
self.telegram.send_message(f"*Started* {utils.now():%F %T}") self.telegram.send_message(f"*Started* {utils.now():%F %T}")
self.init_logger() self.init_logger()
self.update_all(True)
if self.logged_in:
self.update_all(True)
def update_citizen_info(self, html: str = None): def update_citizen_info(self, html: str = None):
""" """
@ -2743,7 +2717,7 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
self.write_warning('Training ground contract active but ' self.write_warning('Training ground contract active but '
f"don't have enough gold ({self.details.gold}g {self.details.cc}cc)") f"don't have enough gold ({self.details.gold}g {self.details.cc}cc)")
if self.energy.is_energy_full and self.config.telegram: if self.energy.is_energy_full and self.config.telegram:
self.telegram.report_full_energy(self.energy.available, self.energy.limit, self.energy.interval) self.telegram.report_full_energy(self.energy.energy, self.energy.limit, self.energy.interval)
def check_for_notification_medals(self): def check_for_notification_medals(self):
notifications = self._get_main_citizen_daily_assistant().json() notifications = self._get_main_citizen_daily_assistant().json()
@ -2880,7 +2854,7 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
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,
hp_interval=self.energy.interval, hp_available=self.energy.available, food=self.food['total'], ) hp_interval=self.energy.interval, hp_available=self.energy.energy, 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):
@ -2889,31 +2863,6 @@ class _Citizen(CitizenAnniversary, CitizenCompanies, CitizenLeaderBoard,
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)
def eat(self):
"""
Try to eat food
"""
self._eat('blue')
if self.food['total'] > self.energy.interval:
if self.energy.limit - self.energy.recovered > self.energy.interval or not self.energy.recoverable % 2:
super().eat()
else:
self.logger.debug("I don't want to eat right now!")
else:
self.write_warning(f"I'm out of food! But I'll try to buy some!\n{self.food}")
self.buy_food()
if self.food['total'] > self.energy.interval:
super().eat()
else:
self.write_warning('I failed to buy food')
def eat_eb(self):
self.write_warning('Eating energy bar')
if self.energy.recoverable:
self._eat('blue')
self._eat('orange')
self.write_log(self.health_info)
def sell_produced_product(self, kind: str, quality: int = 1, amount: int = 0): def sell_produced_product(self, kind: str, quality: int = 1, amount: int = 0):
if not amount: if not amount:
inv_resp = self._get_economy_inventory_items().json() inv_resp = self._get_economy_inventory_items().json()

View File

@ -1,6 +1,7 @@
import datetime import datetime
import hashlib import hashlib
import threading import threading
import warnings
import weakref import weakref
from decimal import Decimal from decimal import Decimal
from io import BytesIO from io import BytesIO
@ -27,6 +28,14 @@ class ErepublikNetworkException(ErepublikException):
self.request = request self.request = request
class CloudFlareSessionError(ErepublikNetworkException):
pass
class CaptchaSessionError(ErepublikNetworkException):
pass
class Holding: class Holding:
id: int id: int
region: int region: int
@ -414,26 +423,35 @@ class Config:
class Energy: class Energy:
limit = 500 # energyToRecover limit = 500 # energyToRecover
interval = 10 # energyPerInterval interval = 10 # energyPerInterval
recoverable = 0 # energyFromFoodRemaining energy = 0 # energy
recovered = 0 # energy
_recovery_time = None _recovery_time = None
def __init__(self): def __init__(self):
self._recovery_time = utils.now() self._recovery_time = utils.now()
def __repr__(self): def __repr__(self):
return f"{self.recovered:4}/{self.limit:4} + {self.recoverable:4}, {self.interval:3}hp/6min" return f"{self.energy:4}/{self.limit:4}, {self.interval:3}hp/6min"
@property
def recovered(self):
warnings.warn('Deprecated since auto auto-eat! Will be removed soon. Use Energy.energy', DeprecationWarning)
return self.energy
@property
def recoverable(self):
warnings.warn('Deprecated since auto auto-eat! Will be removed soon. Use Energy.energy', DeprecationWarning)
return 0
def set_reference_time(self, recovery_time: datetime.datetime): def set_reference_time(self, recovery_time: datetime.datetime):
self._recovery_time = recovery_time.replace(microsecond=0) self._recovery_time = recovery_time.replace(microsecond=0)
@property @property
def food_fights(self): def food_fights(self):
return self.available // 10 return self.energy // 10
@property @property
def reference_time(self): def reference_time(self):
if self.is_recovered_full or self._recovery_time < utils.now(): if self.is_energy_full or self._recovery_time < utils.now():
ret = utils.now() ret = utils.now()
else: else:
ret = self._recovery_time ret = self._recovery_time
@ -441,26 +459,28 @@ class Energy:
@property @property
def is_recoverable_full(self): def is_recoverable_full(self):
return self.recoverable >= self.limit - 5 * self.interval warnings.warn('Deprecated since auto auto-eat! Will be removed soon. Use Energy.is_energy_full', DeprecationWarning)
return self.is_energy_full
@property @property
def is_recovered_full(self): def is_recovered_full(self):
return self.recovered >= self.limit - self.interval warnings.warn('Deprecated since auto auto-eat! Will be removed soon. Use Energy.is_energy_full', DeprecationWarning)
return self.is_energy_full
@property @property
def is_energy_full(self): def is_energy_full(self):
return self.is_recoverable_full and self.is_recovered_full return self.energy >= self.limit - self.interval
@property @property
def available(self): def available(self):
return self.recovered + self.recoverable warnings.warn('Deprecated since auto auto-eat! Will be removed soon. Use Energy.energy', DeprecationWarning)
return self.energy
@property @property
def as_dict(self) -> Dict[str, Union[int, datetime.datetime, bool]]: 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, energy=self.energy,
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_energy_full=self.is_energy_full)
is_energy_full=self.is_energy_full, available=self.available)
class Details: class Details:

View File

@ -136,6 +136,12 @@ class Rank:
def as_dict(self): def as_dict(self):
return dict(id=self.id, name=self.name, rank_points=self.rank_points, is_air=self.is_air) return dict(id=self.id, name=self.name, rank_points=self.rank_points, is_air=self.is_air)
def __str__(self):
return f"{'Air' if self.is_air else 'Ground'}Rank<#{self.id} {self.name}>"
def __repr__(self):
return str(self)
AIR_RANK_NAMES: Dict[int, str] = { AIR_RANK_NAMES: Dict[int, str] = {
1: 'Airman', 2: 'Airman 1st Class', 3: 'Airman 1st Class*', 4: 'Airman 1st Class**', 5: 'Airman 1st Class***', 6: 'Airman 1st Class****', 7: 'Airman 1st Class*****', 1: 'Airman', 2: 'Airman 1st Class', 3: 'Airman 1st Class*', 4: 'Airman 1st Class**', 5: 'Airman 1st Class***', 6: 'Airman 1st Class****', 7: 'Airman 1st Class*****',
@ -238,7 +244,7 @@ GROUND_RANK_POINTS: Dict[int, int] = {
86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000 86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000
} }
GROUND_RANKS: Dict[int, Rank] = {i: Rank(i, GROUND_RANK_NAMES[i], GROUND_RANK_POINTS[i], True) for i in range(1, 90)} GROUND_RANKS: Dict[int, Rank] = {i: Rank(i, GROUND_RANK_NAMES[i], GROUND_RANK_POINTS[i], False) for i in range(1, 90)}
INDUSTRIES = Industries() INDUSTRIES = Industries()

View File

@ -26,9 +26,7 @@ def main():
player.login() player.login()
now = player.now.replace(second=0, microsecond=0) now = player.now.replace(second=0, microsecond=0)
dt_max = constants.max_datetime dt_max = constants.max_datetime
tasks = { tasks = {}
'eat': now,
}
if player.config.work: if player.config.work:
tasks.update({'work': now}) tasks.update({'work': now})
if player.config.train: if player.config.train:
@ -61,7 +59,6 @@ def main():
if tasks.get('wam', dt_max) <= now: if tasks.get('wam', dt_max) <= now:
player.write_log("Doing task: Work as manager") player.write_log("Doing task: Work as manager")
success = player.work_as_manager() success = player.work_as_manager()
player.eat()
if success: if success:
next_time = utils.good_timedelta(now.replace(hour=14, minute=0, second=0, microsecond=0), next_time = utils.good_timedelta(now.replace(hour=14, minute=0, second=0, microsecond=0),
timedelta(days=1)) timedelta(days=1))
@ -70,19 +67,8 @@ def main():
tasks.update({'wam': next_time}) tasks.update({'wam': next_time})
if tasks.get('eat', dt_max) <= now:
player.write_log("Doing task: eat")
player.eat()
if player.energy.food_fights > player.energy.limit // 10:
next_minutes = 12
else:
next_minutes = (player.energy.limit - 5 * player.energy.interval) // player.energy.interval * 6
next_time = player.energy.reference_time + timedelta(minutes=next_minutes)
tasks.update({'eat': next_time})
if tasks.get('ot', dt_max) <= now: if tasks.get('ot', dt_max) <= now:
player.update_job_info()
player.write_log("Doing task: work overtime") player.write_log("Doing task: work overtime")
if now > player.my_companies.next_ot_time: if now > player.my_companies.next_ot_time:
player.work_ot() player.work_ot()

View File

@ -1,21 +1,21 @@
bump2version==1.0.1 bump2version==1.0.1
coverage==5.5 coverage==5.5
edx-sphinx-theme==2.0.0 edx-sphinx-theme==3.0.0
flake8==3.8.4 flake8==3.9.2
ipython>=7.21.0 ipython>=7.25.0
jedi!=0.18.0 jedi!=0.18.0
isort==5.7.0 isort==5.9.2
pip==21.0.1 pip==21.1.3
pre-commit==2.10.1 pre-commit==2.13.0
pur==5.3.0 pur==5.4.2
PyInstaller==4.2 PyInstaller==4.3
PySocks==1.7.1 PySocks==1.7.1
pytest==6.2.2 pytest==6.2.4
pytz==2021.1 pytz==2021.1
requests==2.25.1 requests==2.25.1
requests-toolbelt==0.9.1 requests-toolbelt==0.9.1
responses==0.12.1 responses==0.13.3
setuptools==54.0.0 setuptools==57.1.0
Sphinx==3.5.1 Sphinx==4.0.3
twine==3.3.0 twine==3.4.1
wheel==0.36.2 wheel==0.36.2

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.24.2.2 current_version = 0.25.0.3
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+)?

View File

@ -12,17 +12,17 @@ with open('HISTORY.rst') as history_file:
history = history_file.read() history = history_file.read()
requirements = [ requirements = [
'PySocks==1.7.1', 'PySocks>=1.7.1',
'pytz==2021.1', 'pytz>=2021.1',
'requests==2.25.1', 'requests>=2.25.0',
'requests-toolbelt==0.9.1', 'requests-toolbelt>=0.9.0',
] ]
setup_requirements = [] setup_requirements = []
test_requirements = [ test_requirements = [
"pytest==6.1.2", "pytest==6.2.4",
"responses==0.12.1" "responses==0.13.3"
] ]
setup( setup(
@ -34,8 +34,8 @@ setup(
'License :: OSI Approved :: MIT License', 'License :: OSI Approved :: MIT License',
'Natural Language :: English', 'Natural Language :: English',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
], ],
description="Python package for automated eRepublik playing", description="Python package for automated eRepublik playing",
entry_points={}, entry_points={},
@ -46,11 +46,11 @@ setup(
keywords='erepublik', keywords='erepublik',
name='eRepublik', name='eRepublik',
packages=find_packages(include=['erepublik']), packages=find_packages(include=['erepublik']),
python_requires='>=3.7, <4', python_requires='>=3.8, <4',
setup_requires=setup_requirements, setup_requires=setup_requirements,
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.24.2.2', version='0.25.0.3',
zip_safe=False, zip_safe=False,
) )