no message
This commit is contained in:
parent
c48af9a891
commit
ef27960ff1
@ -1,35 +1,34 @@
|
|||||||
import datetime
|
|
||||||
import itertools
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import threading
|
from threading import Event
|
||||||
import time
|
|
||||||
from json import loads, dumps
|
from itertools import product
|
||||||
from typing import Dict, List, Tuple, Any, Union
|
from datetime import datetime, timedelta
|
||||||
|
from json import loads, dumps
|
||||||
|
from time import sleep
|
||||||
|
from typing import Dict, List, Tuple, Any, Union, Set
|
||||||
|
|
||||||
import requests
|
|
||||||
from requests import Response, RequestException
|
from requests import Response, RequestException
|
||||||
|
|
||||||
from erepublik import classes, utils
|
from erepublik.classes import (CitizenAPI, Battle, Reporter, Config, Energy, Details, Politics, MyCompanies,
|
||||||
|
TelegramBot, ErepublikException, BattleDivision, MyJSONEncoder)
|
||||||
|
|
||||||
|
from erepublik.utils import *
|
||||||
|
|
||||||
|
|
||||||
class Citizen(classes.CitizenAPI):
|
class Citizen(CitizenAPI):
|
||||||
division = 0
|
division = 0
|
||||||
|
|
||||||
all_battles: Dict[int, classes.Battle] = None
|
all_battles: Dict[int, Battle] = None
|
||||||
countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
|
countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
|
||||||
__last_war_update_data = None
|
__last_war_update_data = None
|
||||||
__last_full_update: datetime.datetime = utils.now().min
|
__last_full_update: datetime = now().min
|
||||||
|
|
||||||
active_fs: bool = False
|
active_fs: bool = False
|
||||||
|
|
||||||
food = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
|
food = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
|
||||||
inventory = {"used": 0, "total": 0}
|
inventory = {"used": 0, "total": 0}
|
||||||
boosters = {
|
boosters = {100: {}, 50: {}}
|
||||||
100: {
|
|
||||||
}, 50: {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eb_normal = 0
|
eb_normal = 0
|
||||||
eb_double = 0
|
eb_double = 0
|
||||||
@ -43,28 +42,26 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
eday = 0
|
eday = 0
|
||||||
|
|
||||||
r: requests.Response
|
r: Response
|
||||||
reporter: classes.Reporter
|
|
||||||
name = "Not logged in!"
|
name = "Not logged in!"
|
||||||
debug = False
|
debug = False
|
||||||
__registered = False
|
__registered = False
|
||||||
logged_in = False
|
logged_in = False
|
||||||
telegram = None
|
|
||||||
|
|
||||||
def __init__(self, email: str = "", password: str = "", auto_login: bool = True):
|
def __init__(self, email: str = "", password: str = "", auto_login: bool = True):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.commit_id = utils.COMMIT_ID
|
self.commit_id = COMMIT_ID
|
||||||
self.config = classes.Config()
|
self.config = Config()
|
||||||
self.config.email = email
|
self.config.email = email
|
||||||
self.config.password = password
|
self.config.password = password
|
||||||
self.energy = classes.Energy()
|
self.energy = Energy()
|
||||||
self.details = classes.Details()
|
self.details = Details()
|
||||||
self.politics = classes.Politics()
|
self.politics = Politics()
|
||||||
self.my_companies = classes.MyCompanies()
|
self.my_companies = MyCompanies()
|
||||||
self.set_debug(True)
|
self.set_debug(True)
|
||||||
self.reporter = classes.Reporter()
|
self.reporter = Reporter()
|
||||||
self.stop_threads = threading.Event()
|
self.stop_threads = Event()
|
||||||
self.telegram = classes.TelegramBot(stop_event=self.stop_threads)
|
self.telegram = TelegramBot(stop_event=self.stop_threads)
|
||||||
if auto_login:
|
if auto_login:
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
@ -85,27 +82,26 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.telegram.do_init(self.config.telegram_chat_id or 620981703,
|
self.telegram.do_init(self.config.telegram_chat_id or 620981703,
|
||||||
self.config.telegram_token or "864251270:AAFzZZdjspI-kIgJVk4gF3TViGFoHnf8H4o",
|
self.config.telegram_token or "864251270:AAFzZZdjspI-kIgJVk4gF3TViGFoHnf8H4o",
|
||||||
"" if self.config.telegram_chat_id or self.config.telegram_token else self.name)
|
"" if self.config.telegram_chat_id or self.config.telegram_token else self.name)
|
||||||
self.telegram.send_message("*Started* {:%F %T}".format(utils.now()))
|
self.telegram.send_message(f"*Started* {now():%F %T}")
|
||||||
self.__last_full_update = utils.good_timedelta(self.now, - datetime.timedelta(minutes=5))
|
self.__last_full_update = good_timedelta(self.now, - timedelta(minutes=5))
|
||||||
|
|
||||||
def write_log(self, *args, **kwargs):
|
def write_log(self, *args, **kwargs):
|
||||||
if self.config.interactive:
|
if self.config.interactive:
|
||||||
utils.write_interactive_log(*args, **kwargs)
|
write_interactive_log(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
utils.write_silent_log(*args, **kwargs)
|
write_silent_log(*args, **kwargs)
|
||||||
|
|
||||||
def sleep(self, seconds: int):
|
def sleep(self, seconds: int):
|
||||||
if seconds < 0:
|
if seconds < 0:
|
||||||
seconds = 0
|
seconds = 0
|
||||||
if self.config.interactive:
|
if self.config.interactive:
|
||||||
utils.interactive_sleep(seconds)
|
interactive_sleep(seconds)
|
||||||
else:
|
else:
|
||||||
time.sleep(seconds)
|
sleep(seconds)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return "Citizen {}".format(self.name)
|
return f"Citizen {self.name}"
|
||||||
|
|
||||||
@property
|
|
||||||
def __dict__(self):
|
def __dict__(self):
|
||||||
ret = super().__dict__.copy()
|
ret = super().__dict__.copy()
|
||||||
ret.pop('stop_threads', None)
|
ret.pop('stop_threads', None)
|
||||||
@ -142,7 +138,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.token = re_login_token.group(1)
|
self.token = re_login_token.group(1)
|
||||||
self._login()
|
self._login()
|
||||||
else:
|
else:
|
||||||
raise classes.ErepublikException("Something went wrong! Can't find token in page! Exiting!")
|
raise ErepublikException("Something went wrong! Can't find token in page! Exiting!")
|
||||||
try:
|
try:
|
||||||
self.update_citizen_info(resp.text)
|
self.update_citizen_info(resp.text)
|
||||||
except:
|
except:
|
||||||
@ -153,7 +149,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
r = self._post_login(self.config.email, self.config.password)
|
r = self._post_login(self.config.email, self.config.password)
|
||||||
self.r = r
|
self.r = r
|
||||||
|
|
||||||
if r.url == "{}/login".format(self.url):
|
if r.url == f"{self.url}/login":
|
||||||
self.write_log("Citizen email and/or password is incorrect!")
|
self.write_log("Citizen email and/or password is incorrect!")
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
else:
|
else:
|
||||||
@ -162,18 +158,18 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.name = re_name_id.group(2)
|
self.name = re_name_id.group(2)
|
||||||
self.details.citizen_id = re_name_id.group(1)
|
self.details.citizen_id = re_name_id.group(1)
|
||||||
|
|
||||||
self.write_log("Logged in as: {}".format(self.name))
|
self.write_log(f"Logged in as: {self.name}")
|
||||||
self.get_csrf_token()
|
self.get_csrf_token()
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
|
|
||||||
def _errors_in_response(self, response: requests.Response):
|
def _errors_in_response(self, response: Response):
|
||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
self.r = response
|
self.r = response
|
||||||
if response.status_code >= 500:
|
if response.status_code >= 500:
|
||||||
self.write_log("eRepublik servers are having internal troubles. Sleeping for 5 minutes")
|
self.write_log("eRepublik servers are having internal troubles. Sleeping for 5 minutes")
|
||||||
self.sleep(5 * 60)
|
self.sleep(5 * 60)
|
||||||
else:
|
else:
|
||||||
raise classes.ErepublikException("HTTP {} error!".format(response.status_code))
|
raise ErepublikException(f"HTTP {response.status_code} error!")
|
||||||
return bool(re.search(r'body id="error"|Internal Server Error|'
|
return bool(re.search(r'body id="error"|Internal Server Error|'
|
||||||
r'CSRF attack detected|meta http-equiv="refresh"|not_authenticated', response.text))
|
r'CSRF attack detected|meta http-equiv="refresh"|not_authenticated', response.text))
|
||||||
|
|
||||||
@ -229,7 +225,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
try:
|
try:
|
||||||
resp_data = response.json()
|
resp_data = response.json()
|
||||||
if (resp_data.get("error") or not resp_data.get("status")) and resp_data.get("message", "") == "captcha":
|
if (resp_data.get("error") or not resp_data.get("status")) and resp_data.get("message", "") == "captcha":
|
||||||
utils.send_email(self.name, [response.text, ], player=self, captcha=True)
|
send_email(self.name, [response.text, ], player=self, captcha=True)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -278,21 +274,21 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
msgs = "\n".join(msgs)
|
msgs = "\n".join(msgs)
|
||||||
self.telegram.report_medal(msgs)
|
self.telegram.report_medal(msgs)
|
||||||
self.write_log("Found awards:\n{}".format(msgs))
|
self.write_log(f"Found awards:\n{msgs}")
|
||||||
for info in data.values():
|
for info in data.values():
|
||||||
self.reporter.report_action("NEW_MEDAL", info)
|
self.reporter.report_action("NEW_MEDAL", info)
|
||||||
|
|
||||||
levelup = re.search(r"<p>Congratulations, you have reached experience <strong>level (\d+)</strong></p>", html)
|
levelup = re.search(r"<p>Congratulations, you have reached experience <strong>level (\d+)</strong></p>", html)
|
||||||
if levelup:
|
if levelup:
|
||||||
level = levelup.group(1)
|
level = levelup.group(1)
|
||||||
msg = "Level up! Current level {}".format(level)
|
msg = f"Level up! Current level {level}"
|
||||||
self.write_log(msg)
|
self.write_log(msg)
|
||||||
self.telegram.report_medal(f"Level *{level}*")
|
self.telegram.report_medal(f"Level *{level}*")
|
||||||
self.reporter.report_action("LEVEL_UP", value=level)
|
self.reporter.report_action("LEVEL_UP", value=level)
|
||||||
|
|
||||||
def update_all(self, force_update=False):
|
def update_all(self, force_update=False):
|
||||||
# Do full update max every 5 min
|
# Do full update max every 5 min
|
||||||
if utils.good_timedelta(self.__last_full_update, datetime.timedelta(minutes=5)) > self.now and not force_update:
|
if good_timedelta(self.__last_full_update, timedelta(minutes=5)) > self.now and not force_update:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.__last_full_update = self.now
|
self.__last_full_update = self.now
|
||||||
@ -312,12 +308,12 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self._get_main()
|
self._get_main()
|
||||||
return
|
return
|
||||||
ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1)
|
ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1)
|
||||||
promos = loads(utils.normalize_html_json(ugly_js))
|
promos = loads(normalize_html_json(ugly_js))
|
||||||
self.promos = {k: v for k, v in (self.promos.items() if self.promos else {}) if v > self.now}
|
self.promos = {k: v for k, v in (self.promos.items() if self.promos else {}) if v > self.now}
|
||||||
send_mail = False
|
send_mail = False
|
||||||
for promo in promos:
|
for promo in promos:
|
||||||
promo_name = promo.get("id")
|
promo_name = promo.get("id")
|
||||||
expire = utils.localize_timestamp(int(promo.get("expiresAt")))
|
expire = localize_timestamp(int(promo.get("expiresAt")))
|
||||||
if promo_name not in self.promos:
|
if promo_name not in self.promos:
|
||||||
send_mail = True
|
send_mail = True
|
||||||
self.promos.update({promo_name: expire})
|
self.promos.update({promo_name: expire})
|
||||||
@ -328,20 +324,19 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if self.details.gold >= 54:
|
if self.details.gold >= 54:
|
||||||
self.buy_tg_contract()
|
self.buy_tg_contract()
|
||||||
else:
|
else:
|
||||||
self.write_log("Training ground contract active but don't have enough gold ({}g {}cc)".format(
|
self.write_log(f"Training ground contract active but "
|
||||||
self.details.gold, self.details.cc
|
f"don't have enough gold ({self.details.gold}g {self.details.cc}cc)")
|
||||||
))
|
|
||||||
if send_mail:
|
if send_mail:
|
||||||
active_promos = []
|
active_promos = []
|
||||||
for kind, time_until in self.promos.items():
|
for kind, time_until in self.promos.items():
|
||||||
active_promos.append(f"{kind} active until {time_until}")
|
active_promos.append(f"{kind} active until {time_until}")
|
||||||
utils.report_promo(kind, time_until)
|
report_promo(kind, time_until)
|
||||||
utils.send_email(self.name, active_promos, player=self, promo=True)
|
send_email(self.name, active_promos, player=self, promo=True)
|
||||||
|
|
||||||
new_date = re.search(r"var new_date = '(\d*)';", html)
|
new_date = re.search(r"var new_date = '(\d*)';", html)
|
||||||
if new_date:
|
if new_date:
|
||||||
self.energy.set_reference_time(
|
self.energy.set_reference_time(
|
||||||
utils.good_timedelta(self.now, datetime.timedelta(seconds=int(new_date.group(1))))
|
good_timedelta(self.now, timedelta(seconds=int(new_date.group(1))))
|
||||||
)
|
)
|
||||||
|
|
||||||
ugly_js = re.search(r"var erepublik = ({.*}),\s+", html).group(1)
|
ugly_js = re.search(r"var erepublik = ({.*}),\s+", html).group(1)
|
||||||
@ -379,7 +374,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.politics.is_party_member = True
|
self.politics.is_party_member = True
|
||||||
self.politics.party_id = party.get('party_id')
|
self.politics.party_id = party.get('party_id')
|
||||||
self.politics.is_party_president = bool(party.get('is_party_president'))
|
self.politics.is_party_president = bool(party.get('is_party_president'))
|
||||||
self.politics.party_slug = "{}-{}".format(party.get("stripped_title"), party.get('party_id'))
|
self.politics.party_slug = f"{party.get('stripped_title')}-{party.get('party_id')}"
|
||||||
|
|
||||||
def update_money(self, page: int = 0, currency: int = 62) -> Dict[str, Any]:
|
def update_money(self, page: int = 0, currency: int = 62) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@ -396,7 +391,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
def update_job_info(self):
|
def update_job_info(self):
|
||||||
ot = self._get_main_job_data().json().get("overTime", {})
|
ot = self._get_main_job_data().json().get("overTime", {})
|
||||||
if ot:
|
if ot:
|
||||||
self.my_companies.next_ot_time = utils.localize_timestamp(int(ot.get("nextOverTime", 0)))
|
self.my_companies.next_ot_time = localize_timestamp(int(ot.get("nextOverTime", 0)))
|
||||||
self.ot_points = ot.get("points", 0)
|
self.ot_points = ot.get("points", 0)
|
||||||
|
|
||||||
def update_companies(self):
|
def update_companies(self):
|
||||||
@ -447,7 +442,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
if item.get('type'):
|
if item.get('type'):
|
||||||
if item.get('type') in ['damageBoosters', "aircraftDamageBoosters"]:
|
if item.get('type') in ['damageBoosters', "aircraftDamageBoosters"]:
|
||||||
kind = "{}{}".format(item['type'], item['quality'])
|
kind = f"{item['type']}{item['quality']}"
|
||||||
if item['quality'] == 5:
|
if item['quality'] == 5:
|
||||||
self.boosters[50].update({item['duration']: item['amount']})
|
self.boosters[50].update({item['duration']: item['amount']})
|
||||||
elif item['quality'] == 10:
|
elif item['quality'] == 10:
|
||||||
@ -518,7 +513,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.inventory.update({"used": j.get("inventoryStatus").get("usedStorage"),
|
self.inventory.update({"used": j.get("inventoryStatus").get("usedStorage"),
|
||||||
"total": j.get("inventoryStatus").get("totalStorage")})
|
"total": j.get("inventoryStatus").get("totalStorage")})
|
||||||
inventory = dict(items=dict(active=active_items, final=final_items, raw=raw_materials), status=self.inventory)
|
inventory = dict(items=dict(active=active_items, final=final_items, raw=raw_materials), status=self.inventory)
|
||||||
self.food["total"] = sum([self.food[q] * utils.FOOD_ENERGY[q] for q in utils.FOOD_ENERGY])
|
self.food["total"] = sum([self.food[q] * FOOD_ENERGY[q] for q in FOOD_ENERGY])
|
||||||
return inventory
|
return inventory
|
||||||
|
|
||||||
def update_weekly_challenge(self):
|
def update_weekly_challenge(self):
|
||||||
@ -555,7 +550,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.__last_war_update_data = resp_json
|
self.__last_war_update_data = resp_json
|
||||||
if resp_json.get("battles"):
|
if resp_json.get("battles"):
|
||||||
for battle_id, battle_data in resp_json.get("battles", {}).items():
|
for battle_id, battle_data in resp_json.get("battles", {}).items():
|
||||||
self.all_battles.update({int(battle_id): classes.Battle(battle_data)})
|
self.all_battles.update({int(battle_id): Battle(battle_data)})
|
||||||
|
|
||||||
def eat(self):
|
def eat(self):
|
||||||
"""
|
"""
|
||||||
@ -567,7 +562,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
else:
|
else:
|
||||||
self.write_log("I don't want to eat right now!")
|
self.write_log("I don't want to eat right now!")
|
||||||
else:
|
else:
|
||||||
self.write_log("I'm out of food! But I'll try to buy some!\n{}".format(self.food))
|
self.write_log(f"I'm out of food! But I'll try to buy some!\n{self.food}")
|
||||||
self.buy_food()
|
self.buy_food()
|
||||||
if self.food["total"] > self.energy.interval:
|
if self.food["total"] > self.energy.interval:
|
||||||
self.eat()
|
self.eat()
|
||||||
@ -587,14 +582,14 @@ class Citizen(classes.CitizenAPI):
|
|||||||
r_json = response.json()
|
r_json = response.json()
|
||||||
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,
|
good_timedelta(self.now,
|
||||||
datetime.timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
|
timedelta(seconds=int(next_recovery[1]) * 60 + int(next_recovery[2])))
|
||||||
)
|
)
|
||||||
self.energy.recovered = r_json.get("health")
|
self.energy.recovered = r_json.get("health")
|
||||||
self.energy.recoverable = r_json.get("food_remaining")
|
self.energy.recoverable = r_json.get("food_remaining")
|
||||||
for q, amount in r_json.get("units_consumed").items():
|
for q, amount in r_json.get("units_consumed").items():
|
||||||
if "q{}".format(q) in self.food:
|
if f"q{q}" in self.food:
|
||||||
self.food["q{}".format(q)] -= amount
|
self.food[f"q{q}"] -= amount
|
||||||
elif q == "10":
|
elif q == "10":
|
||||||
self.eb_normal -= amount
|
self.eb_normal -= amount
|
||||||
elif q == "11":
|
elif q == "11":
|
||||||
@ -605,29 +600,24 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def health_info(self):
|
def health_info(self):
|
||||||
ret = "{}/{} + {}, {}hp/6m. {}xp until level up".format(
|
ret = f"{self.energy.recovered}/{self.energy.limit} + {self.energy.recoverable}, " \
|
||||||
self.energy.recovered,
|
f"{self.energy.interval}hp/6m. {self.details.xp_till_level_up}xp until level up"
|
||||||
self.energy.limit,
|
|
||||||
self.energy.recoverable,
|
|
||||||
self.energy.interval,
|
|
||||||
self.details.xp_till_level_up
|
|
||||||
)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def now(self) -> datetime.datetime:
|
def now(self) -> datetime:
|
||||||
"""
|
"""
|
||||||
Returns aware datetime object localized to US/Pacific (eRepublik time)
|
Returns aware datetime object localized to US/Pacific (eRepublik time)
|
||||||
:return: datetime.datetime
|
:return: datetime.datetime
|
||||||
"""
|
"""
|
||||||
return utils.now()
|
return now()
|
||||||
|
|
||||||
def check_epic_battles(self):
|
def check_epic_battles(self):
|
||||||
active_fs = False
|
active_fs = False
|
||||||
for battle_id in self.sorted_battles(self.config.sort_battles_time):
|
for battle_id in self.sorted_battles(self.config.sort_battles_time):
|
||||||
battle = self.all_battles.get(battle_id)
|
battle = self.all_battles.get(battle_id)
|
||||||
if not battle.is_air:
|
if not battle.is_air:
|
||||||
my_div: classes.BattleDivision = battle.div.get(self.division)
|
my_div: BattleDivision = battle.div.get(self.division)
|
||||||
if my_div.epic and my_div.end > self.now:
|
if my_div.epic and my_div.end > self.now:
|
||||||
if self.energy.food_fights > 50:
|
if self.energy.food_fights > 50:
|
||||||
inv_allies = battle.invader.deployed + [battle.invader.id]
|
inv_allies = battle.invader.deployed + [battle.invader.id]
|
||||||
@ -650,9 +640,8 @@ class Citizen(classes.CitizenAPI):
|
|||||||
side = battle.defender.id
|
side = battle.defender.id
|
||||||
else:
|
else:
|
||||||
self.write_log(
|
self.write_log(
|
||||||
"Country {} not in all allies list ({}) and also not in inv allies ({}) nor def "
|
f"Country {self.details.current_country} not in all allies list ({all_allies}) and "
|
||||||
"allies ({})".format(self.details.current_country, all_allies,
|
f"also not in inv allies ({inv_allies}) nor def allies ({def_allies})")
|
||||||
inv_allies, def_allies))
|
|
||||||
break
|
break
|
||||||
error_count = 0
|
error_count = 0
|
||||||
while self.energy.food_fights > 5 and error_count < 20:
|
while self.energy.food_fights > 5 and error_count < 20:
|
||||||
@ -737,6 +726,8 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.write_log("Checking for battles to fight in...")
|
self.write_log("Checking for battles to fight in...")
|
||||||
for battle_id in self.sorted_battles(self.config.sort_battles_time):
|
for battle_id in self.sorted_battles(self.config.sort_battles_time):
|
||||||
battle = self.all_battles.get(battle_id)
|
battle = self.all_battles.get(battle_id)
|
||||||
|
if not isinstance(battle, Battle):
|
||||||
|
continue
|
||||||
div = 11 if battle.is_air else self.division
|
div = 11 if battle.is_air else self.division
|
||||||
|
|
||||||
allies = battle.invader.deployed + battle.defender.deployed + [battle.invader.id, battle.defender.id]
|
allies = battle.invader.deployed + battle.defender.deployed + [battle.invader.id, battle.defender.id]
|
||||||
@ -762,8 +753,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
"inv": inv_points,
|
"inv": inv_points,
|
||||||
"travel": "(TRAVEL)" if travel_needed else "",
|
"travel": "(TRAVEL)" if travel_needed else "",
|
||||||
}
|
}
|
||||||
self.write_log("Battle {bid}, type: {air:6}, rw: {rw:5}, "
|
self.write_log(battle)
|
||||||
"points: {def:4}:{inv:<4} {travel}".format(**kwargs))
|
|
||||||
|
|
||||||
points = def_points <= 1700 and inv_points <= 1700
|
points = def_points <= 1700 and inv_points <= 1700
|
||||||
b_type = battle.is_air and self.config.air or not battle.is_air and self.config.ground
|
b_type = battle.is_air and self.config.air or not battle.is_air and self.config.ground
|
||||||
@ -774,7 +764,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if battle.start > self.now:
|
if battle.start > self.now:
|
||||||
self.sleep(utils.get_sleep_seconds(battle.start))
|
self.sleep(get_sleep_seconds(battle.start))
|
||||||
|
|
||||||
if travel_needed:
|
if travel_needed:
|
||||||
if battle.is_rw:
|
if battle.is_rw:
|
||||||
@ -1034,7 +1024,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.sell_produced_product(kind, 1)
|
self.sell_produced_product(kind, 1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise classes.ErepublikException("Unknown kind produced '{kind}'".format(kind=kind))
|
raise ErepublikException("Unknown kind produced '{kind}'".format(kind=kind))
|
||||||
elif self.config.auto_buy_raw and re.search(r"not_enough_[^_]*_raw", response.get("message")):
|
elif self.config.auto_buy_raw and re.search(r"not_enough_[^_]*_raw", response.get("message")):
|
||||||
raw_kind = re.search(r"not_enough_(\w+)_raw", response.get("message"))
|
raw_kind = re.search(r"not_enough_(\w+)_raw", response.get("message"))
|
||||||
if raw_kind:
|
if raw_kind:
|
||||||
@ -1074,7 +1064,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
if amount >= 1:
|
if amount >= 1:
|
||||||
lowest_price = self.get_market_offers(country_id=self.details.citizenship,
|
lowest_price = self.get_market_offers(country_id=self.details.citizenship,
|
||||||
product=kind, quality=int(quality))
|
product_name=kind, quality=int(quality))
|
||||||
|
|
||||||
if lowest_price["citizen_id"] == self.details.citizen_id:
|
if lowest_price["citizen_id"] == self.details.citizen_id:
|
||||||
price = lowest_price["price"]
|
price = lowest_price["price"]
|
||||||
@ -1179,12 +1169,12 @@ class Citizen(classes.CitizenAPI):
|
|||||||
d = self._post_main_travel_data(holdingId=holding_id, battleId=battle_id, countryId=country_id).json()
|
d = self._post_main_travel_data(holdingId=holding_id, battleId=battle_id, countryId=country_id).json()
|
||||||
return d.get('regions', [])
|
return d.get('regions', [])
|
||||||
|
|
||||||
def get_travel_countries(self) -> List[int]:
|
def get_travel_countries(self) -> Set[int]:
|
||||||
response_json = self._post_main_travel_data().json()
|
response_json = self._post_main_travel_data().json()
|
||||||
return_list = []
|
return_list = {*[]}
|
||||||
for country_data in response_json['countries'].values():
|
for country_data in response_json['countries'].values():
|
||||||
if country_data['currentRegions']:
|
if country_data['currentRegions']:
|
||||||
return_list.append(country_data['id'])
|
return_list.add(country_data['id'])
|
||||||
return return_list
|
return return_list
|
||||||
|
|
||||||
def parse_notifications(self, page: int = 1) -> list:
|
def parse_notifications(self, page: int = 1) -> list:
|
||||||
@ -1219,19 +1209,19 @@ class Citizen(classes.CitizenAPI):
|
|||||||
r"id=\"delete_message_(\d+)\" name=\"delete_message\[]\">", self.r.text).group(1)
|
r"id=\"delete_message_(\d+)\" name=\"delete_message\[]\">", self.r.text).group(1)
|
||||||
self._post_delete_message([msg_id])
|
self._post_delete_message([msg_id])
|
||||||
|
|
||||||
def get_market_offers(self, country_id: int = None, product: str = None, quality: int = None) -> dict:
|
def get_market_offers(self, country_id: int = None, product_name: str = None, quality: int = None) -> dict:
|
||||||
raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw")
|
raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw")
|
||||||
q1_industries = ["aircraft"] + list(raw_short_names.values())
|
q1_industries = ["aircraft"] + list(raw_short_names.values())
|
||||||
if product:
|
if product_name:
|
||||||
if product not in self.available_industries and product not in raw_short_names:
|
if product_name not in self.available_industries and product_name not in raw_short_names:
|
||||||
self.write_log("Industry '{}' not implemented".format(product))
|
self.write_log(f"Industry '{product_name}' not implemented")
|
||||||
raise classes.ErepublikException("Industry '{}' not implemented".format(product))
|
raise ErepublikException(f"Industry '{product_name}' not implemented")
|
||||||
elif product in raw_short_names:
|
elif product_name in raw_short_names:
|
||||||
quality = 1
|
quality = 1
|
||||||
product = raw_short_names.get(product)
|
product_name = raw_short_names[product_name]
|
||||||
product = [product]
|
product_name = [product_name]
|
||||||
elif quality:
|
elif quality:
|
||||||
raise classes.ErepublikException("Quality without product not allowed")
|
raise ErepublikException("Quality without product not allowed")
|
||||||
|
|
||||||
item_data = dict(price=999999., country=0, amount=0, offer_id=0, citizen_id=0)
|
item_data = dict(price=999999., country=0, amount=0, offer_id=0, citizen_id=0)
|
||||||
|
|
||||||
@ -1247,19 +1237,16 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if country_id:
|
if country_id:
|
||||||
countries = [country_id]
|
countries = [country_id]
|
||||||
else:
|
else:
|
||||||
good_countries = self.get_travel_countries()
|
countries = self.get_travel_countries()
|
||||||
countries = {cid for cid in utils.COUNTRIES.keys() if cid in good_countries}
|
|
||||||
|
|
||||||
start_dt = self.now
|
start_dt = self.now
|
||||||
iterable = [countries, product or items, [quality] if quality else range(1, 8)]
|
iterable = [countries, product_name or items, [quality] if quality else range(1, 8)]
|
||||||
for country, industry, q in itertools.product(*iterable):
|
for country, industry, q in product(*iterable):
|
||||||
if (q > 1 and industry in q1_industries) or (q > 5 and industry == "house"):
|
if (q > 1 and industry in q1_industries) or (q > 5 and industry == "house"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
str_q = "q%i" % q
|
|
||||||
|
|
||||||
r = self._post_economy_marketplace(country, self.available_industries[industry], q).json()
|
r = self._post_economy_marketplace(country, self.available_industries[industry], q).json()
|
||||||
obj = items[industry][str_q]
|
obj = items[industry][f"q{q}"]
|
||||||
if not r.get("error", False):
|
if not r.get("error", False):
|
||||||
for offer in r["offers"]:
|
for offer in r["offers"]:
|
||||||
if obj["price"] > float(offer["priceWithTaxes"]):
|
if obj["price"] > float(offer["priceWithTaxes"]):
|
||||||
@ -1272,15 +1259,15 @@ class Citizen(classes.CitizenAPI):
|
|||||||
obj["country"] = int(offer["country_id"])
|
obj["country"] = int(offer["country_id"])
|
||||||
obj["amount"] = int(offer["amount"])
|
obj["amount"] = int(offer["amount"])
|
||||||
obj["offer_id"] = int(offer["id"])
|
obj["offer_id"] = int(offer["id"])
|
||||||
self.write_log("Scraped market in {}!".format(self.now - start_dt))
|
self.write_log(f"Scraped market in {self.now - start_dt}!")
|
||||||
|
|
||||||
if quality:
|
if quality:
|
||||||
ret = items[product[0]]["q%i" % quality]
|
ret = items[product_name[0]]["q%i" % quality]
|
||||||
elif product:
|
elif product_name:
|
||||||
if product[0] in raw_short_names.values():
|
if product_name[0] in raw_short_names.values():
|
||||||
ret = items[product[0]]["q1"]
|
ret = items[product_name[0]]["q1"]
|
||||||
else:
|
else:
|
||||||
ret = items[product[0]]
|
ret = items[product_name[0]]
|
||||||
else:
|
else:
|
||||||
ret = items
|
ret = items
|
||||||
return ret
|
return ret
|
||||||
@ -1288,7 +1275,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
def buy_food(self):
|
def buy_food(self):
|
||||||
hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20}
|
hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20}
|
||||||
hp_needed = 48 * self.energy.interval * 10 - self.food["total"]
|
hp_needed = 48 * self.energy.interval * 10 - self.food["total"]
|
||||||
local_offers = self.get_market_offers(country_id=self.details.current_country, product="food")
|
local_offers = self.get_market_offers(country_id=self.details.current_country, product_name="food")
|
||||||
|
|
||||||
cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1]["price"] / hp_per_quality[v[0]])[0]
|
cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1]["price"] / hp_per_quality[v[0]])[0]
|
||||||
|
|
||||||
@ -1304,7 +1291,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.buy_from_market(cheapest["offer_id"], amount)
|
self.buy_from_market(cheapest["offer_id"], amount)
|
||||||
self.update_inventory()
|
self.update_inventory()
|
||||||
else:
|
else:
|
||||||
s = "Don't have enough money! Needed: {}cc, Have: {}cc".format(amount * cheapest["price"], self.details.cc)
|
s = f"Don't have enough money! Needed: {amount * cheapest['price']}cc, Have: {self.details.cc}cc"
|
||||||
self.write_log(s)
|
self.write_log(s)
|
||||||
self.reporter.report_action("BUY_FOOD", value=s)
|
self.reporter.report_action("BUY_FOOD", value=s)
|
||||||
|
|
||||||
@ -1327,7 +1314,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.details.cc = float(response.json().get("ecash").get("value"))
|
self.details.cc = float(response.json().get("ecash").get("value"))
|
||||||
self.details.gold = float(response.json().get("gold").get("value"))
|
self.details.gold = float(response.json().get("gold").get("value"))
|
||||||
self.reporter.report_action("BUY_GOLD", json_val=response.json(),
|
self.reporter.report_action("BUY_GOLD", json_val=response.json(),
|
||||||
value="New amount {o.cc}cc, {o.gold}g".format(o=self.details))
|
value=f"New amount {self.details.cc}cc, {self.details.gold}g")
|
||||||
return not response.json().get("error", False)
|
return not response.json().get("error", False)
|
||||||
|
|
||||||
def activate_dmg_booster(self):
|
def activate_dmg_booster(self):
|
||||||
@ -1366,7 +1353,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if amount < 1:
|
if amount < 1:
|
||||||
return 0
|
return 0
|
||||||
ind = {v: k for k, v in self.available_industries.items()}
|
ind = {v: k for k, v in self.available_industries.items()}
|
||||||
self.write_log("D,{},q{},{},{}".format(amount, quality, ind[industry_id], citizen_id))
|
self.write_log(f"Donate: {amount:4d}q{quality} {ind[industry_id]} to {citizen_id}")
|
||||||
response = self._post_economy_donate_items_action(citizen_id, amount, industry_id, quality)
|
response = self._post_economy_donate_items_action(citizen_id, amount, industry_id, quality)
|
||||||
if re.search(rf"Successfully transferred {amount} item\(s\) to", response.text):
|
if re.search(rf"Successfully transferred {amount} item\(s\) to", response.text):
|
||||||
return amount
|
return amount
|
||||||
@ -1479,12 +1466,12 @@ class Citizen(classes.CitizenAPI):
|
|||||||
count -= self.my_companies.ff_lockdown
|
count -= self.my_companies.ff_lockdown
|
||||||
if count <= 0:
|
if count <= 0:
|
||||||
count = 0
|
count = 0
|
||||||
log_msg = "Not fighting because WAM needs {} food fights".format(self.my_companies.ff_lockdown)
|
log_msg = f"Not fighting because WAM needs {self.my_companies.ff_lockdown} food fights"
|
||||||
|
|
||||||
if self.max_time_till_full_ff > self.time_till_week_change:
|
if self.max_time_till_full_ff > self.time_till_week_change:
|
||||||
max_count = (int(self.time_till_week_change.total_seconds()) // 360 * self.energy.interval) // 10
|
max_count = (int(self.time_till_week_change.total_seconds()) // 360 * self.energy.interval) // 10
|
||||||
log_msg = "End for Weekly challenge is near (Recoverable until WC end {}hp | want to do {}hits)".format(
|
log_msg = ("End for Weekly challenge is near "
|
||||||
max_count, count)
|
f"(Recoverable until WC end {max_count}hp | want to do {count}hits)")
|
||||||
count = count if max_count > count else max_count
|
count = count if max_count > count else max_count
|
||||||
|
|
||||||
self.write_log(log_msg, False)
|
self.write_log(log_msg, False)
|
||||||
@ -1504,30 +1491,30 @@ class Citizen(classes.CitizenAPI):
|
|||||||
return max_pp - self.details.pp if max_pp else 0
|
return max_pp - self.details.pp if max_pp else 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_wc_start(self) -> datetime.datetime:
|
def next_wc_start(self) -> datetime:
|
||||||
days = 1 - self.now.weekday() if 1 - self.now.weekday() > 0 else 1 - self.now.weekday() + 7
|
days = 1 - self.now.weekday() if 1 - self.now.weekday() > 0 else 1 - self.now.weekday() + 7
|
||||||
return utils.good_timedelta(self.now.replace(hour=0, minute=0, second=0, microsecond=0),
|
return good_timedelta(self.now.replace(hour=0, minute=0, second=0, microsecond=0),
|
||||||
datetime.timedelta(days=days))
|
timedelta(days=days))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def time_till_week_change(self) -> datetime.timedelta:
|
def time_till_week_change(self) -> timedelta:
|
||||||
return self.next_wc_start - self.now
|
return self.next_wc_start - self.now
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def time_till_full_ff(self) -> datetime.timedelta:
|
def time_till_full_ff(self) -> timedelta:
|
||||||
energy = self.energy.recoverable + self.energy.recovered
|
energy = self.energy.recoverable + self.energy.recovered
|
||||||
if energy >= self.energy.limit * 2:
|
if energy >= self.energy.limit * 2:
|
||||||
return datetime.timedelta(0)
|
return timedelta(0)
|
||||||
minutes_needed = round((self.energy.limit * 2 - energy) / self.energy.interval) * 6
|
minutes_needed = round((self.energy.limit * 2 - energy) / self.energy.interval) * 6
|
||||||
return (self.energy.reference_time - self.now) + datetime.timedelta(minutes=minutes_needed)
|
return (self.energy.reference_time - self.now) + timedelta(minutes=minutes_needed)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_time_till_full_ff(self) -> datetime.timedelta:
|
def max_time_till_full_ff(self) -> timedelta:
|
||||||
"""
|
"""
|
||||||
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 datetime.timedelta(minutes=round((self.energy.limit * 2 / self.energy.interval) + 0.49) * 6)
|
return timedelta(minutes=round((self.energy.limit * 2 / self.energy.interval) + 0.49) * 6)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_levelup_close(self) -> bool:
|
def is_levelup_close(self) -> bool:
|
||||||
@ -1577,7 +1564,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if kind in kinds:
|
if kind in kinds:
|
||||||
return self._post_main_write_article(title, content, self.details.citizenship, kind)
|
return self._post_main_write_article(title, content, self.details.citizenship, kind)
|
||||||
else:
|
else:
|
||||||
raise classes.ErepublikException(
|
raise ErepublikException(
|
||||||
"Article kind must be one of:\n{}\n'{}' is not supported".format(
|
"Article kind must be one of:\n{}\n'{}' is not supported".format(
|
||||||
"\n".join(["{}: {}".format(k, v) for k, v in kinds.items()]),
|
"\n".join(["{}: {}".format(k, v) for k, v in kinds.items()]),
|
||||||
kind
|
kind
|
||||||
@ -1586,7 +1573,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
def post_market_offer(self, industry: int, quality: int, amount: int, price: float) -> Response:
|
def post_market_offer(self, industry: int, quality: int, amount: int, price: float) -> Response:
|
||||||
if industry not in self.available_industries.values():
|
if industry not in self.available_industries.values():
|
||||||
self.write_log("Trying to sell unsupported industry {}".format(industry))
|
self.write_log(f"Trying to sell unsupported industry {industry}")
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"country": self.details.citizenship,
|
"country": self.details.citizenship,
|
||||||
@ -1706,7 +1693,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
rjson = resp.json()
|
rjson = resp.json()
|
||||||
if not any([rjson["isBanned"], rjson["isDead"], rjson["isFriend"], rjson["isOrg"], rjson["isSelf"]]):
|
if not any([rjson["isBanned"], rjson["isDead"], rjson["isFriend"], rjson["isOrg"], rjson["isSelf"]]):
|
||||||
r = self._post_main_citizen_add_remove_friend(int(player_id), True)
|
r = self._post_main_citizen_add_remove_friend(int(player_id), True)
|
||||||
self.write_log("{:<64} (id:{:>11}) added as friend".format(rjson["name"], player_id))
|
self.write_log(f"{rjson['name']:<64} (id:{player_id:>11}) added as friend")
|
||||||
return r
|
return r
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@ -1767,7 +1754,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
|
|
||||||
cities.sort(key=int)
|
cities.sort(key=int)
|
||||||
for city_id in cities:
|
for city_id in cities:
|
||||||
self.write_log("Adding friends from {} (id: {})".format(cities_dict[city_id], city_id))
|
self.write_log(f"Adding friends from {cities_dict[city_id]} (id: {city_id})")
|
||||||
resp = self._get_main_city_data_residents(city_id).json()
|
resp = self._get_main_city_data_residents(city_id).json()
|
||||||
for resident in resp["widgets"]["residents"]["residents"]:
|
for resident in resp["widgets"]["residents"]["residents"]:
|
||||||
self.add_friend(resident["citizenId"])
|
self.add_friend(resident["citizenId"])
|
||||||
@ -1777,14 +1764,14 @@ class Citizen(classes.CitizenAPI):
|
|||||||
for resident in resp["widgets"]["residents"]["residents"]:
|
for resident in resp["widgets"]["residents"]["residents"]:
|
||||||
self.add_friend(resident["citizenId"])
|
self.add_friend(resident["citizenId"])
|
||||||
|
|
||||||
def schedule_attack(self, war_id: int, region_id: int, region_name: str, at_time: datetime) -> None:
|
def schedule_attack(self, war_id: int, region_id: int, region_name: str, at_time: datetime):
|
||||||
if at_time:
|
if at_time:
|
||||||
self.sleep(utils.get_sleep_seconds(at_time))
|
self.sleep(get_sleep_seconds(at_time))
|
||||||
self.get_csrf_token()
|
self.get_csrf_token()
|
||||||
self.launch_attack(war_id, region_id, region_name)
|
self.launch_attack(war_id, region_id, region_name)
|
||||||
|
|
||||||
def get_active_wars(self, country_id: int = None) -> List[int]:
|
def get_active_wars(self, country_id: int = None) -> List[int]:
|
||||||
r = self._get_country_military(utils.COUNTRY_LINK.get(country_id or self.details.citizenship))
|
r = self._get_country_military(COUNTRY_LINK.get(country_id or self.details.citizenship))
|
||||||
all_war_ids = re.findall(r'//www\.erepublik\.com/en/wars/show/(\d+)"', r.text)
|
all_war_ids = re.findall(r'//www\.erepublik\.com/en/wars/show/(\d+)"', r.text)
|
||||||
return [int(wid) for wid in all_war_ids]
|
return [int(wid) for wid in all_war_ids]
|
||||||
|
|
||||||
@ -1814,7 +1801,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
last_battle_id = int(re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)">', html).group(1))
|
last_battle_id = int(re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)">', html).group(1))
|
||||||
console = self._post_military_battle_console(last_battle_id, 'warList', 1).json()
|
console = self._post_military_battle_console(last_battle_id, 'warList', 1).json()
|
||||||
battle = console.get('list')[0]
|
battle = console.get('list')[0]
|
||||||
return utils.localize_dt(datetime.datetime.strptime(battle.get('result').get('end'), "%Y-%m-%d %H:%M:%S"))
|
return localize_dt(datetime.strptime(battle.get('result').get('end'), "%Y-%m-%d %H:%M:%S"))
|
||||||
|
|
||||||
def launch_attack(self, war_id: int, region_id: int, region_name: str):
|
def launch_attack(self, war_id: int, region_id: int, region_name: str):
|
||||||
self._post_wars_attack_region(war_id, region_id, region_name)
|
self._post_wars_attack_region(war_id, region_id, region_name)
|
||||||
@ -1826,10 +1813,10 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if start_time.minute <= 30:
|
if start_time.minute <= 30:
|
||||||
start_time = start_time.replace(minute=30)
|
start_time = start_time.replace(minute=30)
|
||||||
else:
|
else:
|
||||||
start_time = start_time.replace(minute=0)
|
start_time = 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()
|
self.update_citizen_info()
|
||||||
start_time = utils.good_timedelta(start_time, datetime.timedelta(minutes=30))
|
start_time = good_timedelta(start_time, timedelta(minutes=30))
|
||||||
self.send_state_update()
|
self.send_state_update()
|
||||||
self.send_inventory_update()
|
self.send_inventory_update()
|
||||||
sleep_seconds = (start_time - self.now).total_seconds()
|
sleep_seconds = (start_time - self.now).total_seconds()
|
||||||
@ -1847,15 +1834,15 @@ class Citizen(classes.CitizenAPI):
|
|||||||
to_report = self.update_inventory()
|
to_report = self.update_inventory()
|
||||||
self.reporter.report_action("INVENTORY", json_val=to_report)
|
self.reporter.report_action("INVENTORY", json_val=to_report)
|
||||||
|
|
||||||
def check_house_durability(self) -> Dict[int, datetime.datetime]:
|
def check_house_durability(self) -> Dict[int, datetime]:
|
||||||
ret = {}
|
ret = {}
|
||||||
inv = self.update_inventory()
|
inv = self.update_inventory()
|
||||||
for house_quality, active_house in inv['items']['active'].get('house', {}).items():
|
for house_quality, active_house in inv['items']['active'].get('house', {}).items():
|
||||||
till = utils.good_timedelta(self.now, datetime.timedelta(seconds=active_house['time_left']))
|
till = good_timedelta(self.now, timedelta(seconds=active_house['time_left']))
|
||||||
ret.update({house_quality: till})
|
ret.update({house_quality: till})
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def buy_and_activate_house(self, q: int) -> Dict[int, datetime.datetime]:
|
def buy_and_activate_house(self, q: int) -> Dict[int, datetime]:
|
||||||
inventory = self.update_inventory()
|
inventory = self.update_inventory()
|
||||||
ok_to_activate = False
|
ok_to_activate = False
|
||||||
if not [h for h in inventory['items']['final'].get('house', []) if h['quality'] == q]:
|
if not [h for h in inventory['items']['final'].get('house', []) if h['quality'] == q]:
|
||||||
@ -1865,7 +1852,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
countries.append(self.details.current_country)
|
countries.append(self.details.current_country)
|
||||||
for country in countries:
|
for country in countries:
|
||||||
offers += [self.get_market_offers(country, "house", q)]
|
offers += [self.get_market_offers(country, "house", q)]
|
||||||
global_cheapest = self.get_market_offers(product="house", quality=q)
|
global_cheapest = self.get_market_offers(product_name="house", quality=q)
|
||||||
cheapest_offer = sorted(offers, key=lambda o: o["price"])[0]
|
cheapest_offer = sorted(offers, key=lambda o: o["price"])[0]
|
||||||
region = self.get_country_travel_region(global_cheapest['country'])
|
region = self.get_country_travel_region(global_cheapest['country'])
|
||||||
if global_cheapest['price'] + 200 < cheapest_offer['price'] and region:
|
if global_cheapest['price'] + 200 < cheapest_offer['price'] and region:
|
||||||
@ -1874,7 +1861,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
else:
|
else:
|
||||||
buy = self.buy_from_market(cheapest_offer['offer_id'], 1)
|
buy = self.buy_from_market(cheapest_offer['offer_id'], 1)
|
||||||
if buy["error"]:
|
if buy["error"]:
|
||||||
msg = "Unable to buy q{} house! \n{}".format(q, buy['message'])
|
msg = f"Unable to buy q{q} house! \n{buy['message']}"
|
||||||
self.write_log(msg)
|
self.write_log(msg)
|
||||||
else:
|
else:
|
||||||
ok_to_activate = True
|
ok_to_activate = True
|
||||||
@ -1884,7 +1871,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
self.activate_house(q)
|
self.activate_house(q)
|
||||||
return self.check_house_durability()
|
return self.check_house_durability()
|
||||||
|
|
||||||
def renew_houses(self, forced: bool = False) -> Dict[int, datetime.datetime]:
|
def renew_houses(self, forced: bool = False) -> Dict[int, datetime]:
|
||||||
"""
|
"""
|
||||||
Renew all houses which endtime is in next 48h
|
Renew all houses which endtime is in next 48h
|
||||||
:param forced: if true - renew all houses
|
:param forced: if true - renew all houses
|
||||||
@ -1892,17 +1879,17 @@ class Citizen(classes.CitizenAPI):
|
|||||||
"""
|
"""
|
||||||
house_durability = self.check_house_durability()
|
house_durability = self.check_house_durability()
|
||||||
for q, active_till in house_durability.items():
|
for q, active_till in house_durability.items():
|
||||||
if utils.good_timedelta(active_till, - datetime.timedelta(hours=48)) <= self.now or forced:
|
if good_timedelta(active_till, - timedelta(hours=48)) <= self.now or forced:
|
||||||
house_durability = self.buy_and_activate_house(q)
|
house_durability = self.buy_and_activate_house(q)
|
||||||
self.travel_to_residence()
|
self.travel_to_residence()
|
||||||
return house_durability
|
return house_durability
|
||||||
|
|
||||||
def activate_house(self, quality: int) -> datetime.datetime:
|
def activate_house(self, quality: int) -> datetime:
|
||||||
active_until = self.now
|
active_until = self.now
|
||||||
r = self._post_economy_activate_house(quality)
|
r = self._post_economy_activate_house(quality)
|
||||||
if r.json().get("status") and not r.json().get("error"):
|
if r.json().get("status") and not r.json().get("error"):
|
||||||
house = r.json()["inventoryItems"]["activeEnhancements"]["items"]["4_%i_active" % quality]
|
house = r.json()["inventoryItems"]["activeEnhancements"]["items"]["4_%i_active" % quality]
|
||||||
active_until = utils.good_timedelta(active_until, datetime.timedelta(seconds=house["active"]["time_left"]))
|
active_until = good_timedelta(active_until, timedelta(seconds=house["active"]["time_left"]))
|
||||||
return active_until
|
return active_until
|
||||||
|
|
||||||
def collect_anniversary_reward(self) -> Response:
|
def collect_anniversary_reward(self) -> Response:
|
||||||
@ -1925,7 +1912,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if self.details.cc < amount or amount < 20:
|
if self.details.cc < amount or amount < 20:
|
||||||
return False
|
return False
|
||||||
data = dict(country=71, action='currency', value=amount)
|
data = dict(country=71, action='currency', value=amount)
|
||||||
self.telegram.send_message(f"Donated {amount}cc to {utils.COUNTRIES[71]}")
|
self.telegram.send_message(f"Donated {amount}cc to {COUNTRIES[71]}")
|
||||||
self.reporter.report_action("CONTRIBUTE_CC", data)
|
self.reporter.report_action("CONTRIBUTE_CC", data)
|
||||||
r = self._post_main_country_donate(**data)
|
r = self._post_main_country_donate(**data)
|
||||||
return r.json().get('status') or not r.json().get('error')
|
return r.json().get('status') or not r.json().get('error')
|
||||||
@ -1958,7 +1945,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def report_error(self, msg: str = ""):
|
def report_error(self, msg: str = ""):
|
||||||
utils.process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False)
|
process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False)
|
||||||
|
|
||||||
def get_battle_top_10(self, battle_id: int) -> Dict[int, List[Tuple[int, int]]]:
|
def get_battle_top_10(self, battle_id: int) -> Dict[int, List[Tuple[int, int]]]:
|
||||||
battle = self.all_battles.get(battle_id)
|
battle = self.all_battles.get(battle_id)
|
||||||
@ -1976,7 +1963,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def to_json(self, indent: bool = False) -> str:
|
def to_json(self, indent: bool = False) -> str:
|
||||||
return dumps(self.__dict__, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
|
return dumps(self.__dict__, cls=MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
|
||||||
|
|
||||||
def get_game_token_offers(self):
|
def get_game_token_offers(self):
|
||||||
r = self._post_economy_game_tokens_market('retrieve').json()
|
r = self._post_economy_game_tokens_market('retrieve').json()
|
||||||
@ -2005,7 +1992,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if ne:
|
if ne:
|
||||||
tp = True
|
tp = True
|
||||||
|
|
||||||
return utils.calculate_hit(strength, rang, tp, elite, ne, 50 if booster_50 else 100 if booster_100 else 0)
|
return calculate_hit(strength, rang, tp, elite, ne, 50 if booster_50 else 100 if booster_100 else 0)
|
||||||
|
|
||||||
def get_air_hit_dmg_value(self, rang: int = None, elite: bool = None, ne: bool = False,
|
def get_air_hit_dmg_value(self, rang: int = None, elite: bool = None, ne: bool = False,
|
||||||
weapon: bool = False) -> float:
|
weapon: bool = False) -> float:
|
||||||
@ -2016,7 +2003,7 @@ class Citizen(classes.CitizenAPI):
|
|||||||
if elite is None:
|
if elite is None:
|
||||||
elite = r['citizenAttributes']['level'] > 100
|
elite = r['citizenAttributes']['level'] > 100
|
||||||
|
|
||||||
return utils.calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0)
|
return calculate_hit(0, rang, True, elite, ne, 0, 20 if weapon else 0)
|
||||||
|
|
||||||
def endorse_article(self, article_id: int, amount: int) -> bool:
|
def endorse_article(self, article_id: int, amount: int) -> bool:
|
||||||
if amount in (5, 50, 100):
|
if amount in (5, 50, 100):
|
||||||
|
@ -18,7 +18,7 @@ class ErepublikException(Exception):
|
|||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
|
|
||||||
class ErepublikNetworkException(Exception):
|
class ErepublikNetworkException(ErepublikException):
|
||||||
def __init__(self, message, request):
|
def __init__(self, message, request):
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
self.request = request
|
self.request = request
|
||||||
@ -373,7 +373,7 @@ class Energy:
|
|||||||
return self.recovered + self.recoverable
|
return self.recovered + self.recoverable
|
||||||
|
|
||||||
|
|
||||||
class Details(object):
|
class Details:
|
||||||
xp = 0
|
xp = 0
|
||||||
cc = 0
|
cc = 0
|
||||||
pp = 0
|
pp = 0
|
||||||
@ -427,7 +427,7 @@ class Politics:
|
|||||||
is_country_president: bool = False
|
is_country_president: bool = False
|
||||||
|
|
||||||
|
|
||||||
class House(object):
|
class House:
|
||||||
quality = None
|
quality = None
|
||||||
unactivated_count = 0
|
unactivated_count = 0
|
||||||
active_untill = utils.good_timedelta(utils.now(), -datetime.timedelta(days=1))
|
active_untill = utils.good_timedelta(utils.now(), -datetime.timedelta(days=1))
|
||||||
@ -1031,7 +1031,7 @@ class BattleDivision:
|
|||||||
self.wall = dict({"for": wall_for, "dom": wall_dom})
|
self.wall = dict({"for": wall_for, "dom": wall_dom})
|
||||||
|
|
||||||
|
|
||||||
class Battle(object):
|
class Battle:
|
||||||
id: int = 0
|
id: int = 0
|
||||||
war_id: int = 0
|
war_id: int = 0
|
||||||
zone_id: int = 0
|
zone_id: int = 0
|
||||||
@ -1086,9 +1086,10 @@ class Battle(object):
|
|||||||
time_part = "{}".format(now - self.start)
|
time_part = "{}".format(now - self.start)
|
||||||
else:
|
else:
|
||||||
time_part = "- {}".format(self.start - now)
|
time_part = "- {}".format(self.start - now)
|
||||||
return "Battle {} | {:>21.21}:{:<21.21} | Round {:2} | Start {}".format(
|
return f"Battle {self.id} | " \
|
||||||
self.id, utils.COUNTRIES[self.invader.id], utils.COUNTRIES[self.defender.id], self.zone_id, time_part
|
f"{utils.COUNTRIES[self.invader.id]:>21.21}:{utils.COUNTRIES[self.defender.id]:<21.21} | " \
|
||||||
)
|
f"Round {self.zone_id:2} | " \
|
||||||
|
f"Time since start {time_part}"
|
||||||
|
|
||||||
|
|
||||||
class EnergyToFight:
|
class EnergyToFight:
|
||||||
|
@ -13,11 +13,11 @@ from typing import Union, Any, List, NoReturn, Mapping
|
|||||||
import pytz
|
import pytz
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
|
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz", 'COUNTRY_LINK',
|
||||||
"now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
|
"now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
|
||||||
"get_sleep_seconds", "interactive_sleep", "silent_sleep",
|
"get_sleep_seconds", "interactive_sleep", "silent_sleep",
|
||||||
"write_silent_log", "write_interactive_log", "get_file", "write_file",
|
"write_silent_log", "write_interactive_log", "get_file", "write_file",
|
||||||
"send_email", "normalize_html_json", "process_error", ]
|
"send_email", "normalize_html_json", "process_error", 'report_promo', 'calculate_hit']
|
||||||
|
|
||||||
FOOD_ENERGY = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
|
FOOD_ENERGY = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
|
||||||
COMMIT_ID = "7b92e19"
|
COMMIT_ID = "7b92e19"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user