Compare commits

..

14 Commits

7 changed files with 192 additions and 97 deletions

View File

@ -1,6 +1,6 @@
* eRepublik script version: * eRepublik script version:
* Python version: * Python version:
* Operating System: * Operating System:
### Description ### Description
@ -9,7 +9,7 @@ Tell us what happened, what went wrong, and what you expected to happen.
### What I Did ### What I Did
``` ``` python
Paste the command(s) you ran and the output. Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here. If there was a crash, please include the traceback here.
``` ```

View File

@ -2,6 +2,12 @@
History History
======= =======
0.17.0 (2019-11-21)
-------------------
* 12th anniversary's endpoints added
* Telegram message queue optimisation
* WC end fighting energy bugfix * WC end fighting energy bugfix
* More strict fighting limiting before week change * More strict fighting limiting before week change
* Improved and fixed ground damage booster usage * Improved and fixed ground damage booster usage

View File

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

View File

@ -1,10 +1,9 @@
import re import re
import sys import sys
from threading import Event
from itertools import product
from datetime import datetime, timedelta from datetime import datetime, timedelta
from itertools import product
from json import loads, dumps from json import loads, dumps
from threading import Event
from time import sleep from time import sleep
from typing import Dict, List, Tuple, Any, Union, Set from typing import Dict, List, Tuple, Any, Union, Set
@ -12,7 +11,6 @@ from requests import Response, RequestException
from erepublik.classes import (CitizenAPI, Battle, Reporter, Config, Energy, Details, Politics, MyCompanies, from erepublik.classes import (CitizenAPI, Battle, Reporter, Config, Energy, Details, Politics, MyCompanies,
TelegramBot, ErepublikException, BattleDivision, MyJSONEncoder) TelegramBot, ErepublikException, BattleDivision, MyJSONEncoder)
from erepublik.utils import * from erepublik.utils import *
@ -26,9 +24,9 @@ class Citizen(CitizenAPI):
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: Dict[str, int] = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
inventory = {"used": 0, "total": 0} inventory: Dict[str, int] = {"used": 0, "total": 0}
boosters = {100: {}, 50: {}} boosters: Dict[int, Dict[int, int]] = {100: {}, 50: {}}
eb_normal = 0 eb_normal = 0
eb_double = 0 eb_double = 0
@ -38,7 +36,7 @@ class Citizen(CitizenAPI):
ot_points = 0 ot_points = 0
tg_contract = None tg_contract = None
promos = None promos: Dict[str, datetime] = None
eday = 0 eday = 0
@ -164,6 +162,13 @@ class Citizen(CitizenAPI):
self.logged_in = True self.logged_in = True
def _errors_in_response(self, response: Response): def _errors_in_response(self, response: Response):
try:
j = response.json()
if j['error'] and j["message"] == 'Too many requests':
self.write_log("Made too many requests! Sleeping for 30 seconds.")
self.sleep(30)
except:
pass
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:
@ -174,7 +179,7 @@ class Citizen(CitizenAPI):
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))
def get(self, url: str, *args, **kwargs) -> Response: def get(self, url: str, **kwargs) -> Response:
if (self.now - self._req.last_time).seconds >= 15 * 60: if (self.now - self._req.last_time).seconds >= 15 * 60:
self.get_csrf_token() self.get_csrf_token()
if "params" in kwargs: if "params" in kwargs:
@ -188,7 +193,7 @@ class Citizen(CitizenAPI):
except RequestException as e: except RequestException as e:
self.write_log("Network error while issuing GET request", e) self.write_log("Network error while issuing GET request", e)
self.sleep(60) self.sleep(60)
return self.get(url, *args, **kwargs) return self.get(url, **kwargs)
try: try:
self.update_citizen_info(html=response.text) self.update_citizen_info(html=response.text)
@ -221,7 +226,7 @@ class Citizen(CitizenAPI):
except RequestException as e: except RequestException as e:
self.write_log("Network error while issuing POST request", e) self.write_log("Network error while issuing POST request", e)
self.sleep(60) self.sleep(60)
return self.post(url, data, json, **kwargs) return self.post(url, data=data, json=json, **kwargs)
try: try:
resp_data = response.json() resp_data = response.json()
@ -254,6 +259,9 @@ class Citizen(CitizenAPI):
r"<div title=\"(.*?)\">", medal, re.M | re.S) r"<div title=\"(.*?)\">", medal, re.M | re.S)
about = info.group(1).strip() about = info.group(1).strip()
title = info.group(2).strip() title = info.group(2).strip()
award_id = re.search(r'"wall_enable_alerts_(\d+)', medal)
if award_id:
self._post_main_wall_post_automatic(**{'message': title, 'awardId': award_id.group(1)})
reward, currency = info.group(3).strip().split(" ") reward, currency = info.group(3).strip().split(" ")
while not isinstance(reward, float): while not isinstance(reward, float):
try: try:
@ -310,7 +318,11 @@ class Citizen(CitizenAPI):
return return
ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1) ugly_js = re.search(r'"promotions":\s*(\[{?.*?}?])', html).group(1)
promos = loads(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} if self.promos is None:
self.promos = {}
else:
self.promos.clear()
self.promos.update({k: v for k, v in self.promos.items() 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")
@ -367,7 +379,7 @@ class Citizen(CitizenAPI):
self._post_military_group_missions() self._post_military_group_missions()
self.details.next_pp.sort() self.details.next_pp.sort()
for id_, skill in citizen.get("mySkills", {}).items(): for skill in citizen.get("mySkills", {}).values():
self.details.mayhem_skills.update({int(skill["terrain_id"]): int(skill["skill_points"])}) self.details.mayhem_skills.update({int(skill["terrain_id"]): int(skill["skill_points"])})
if citizen.get('party', []): if citizen.get('party', []):
@ -537,10 +549,18 @@ class Citizen(CitizenAPI):
if not self.details.current_country: if not self.details.current_country:
self.update_citizen_info() self.update_citizen_info()
resp_json = self._get_military_campaigns().json() resp_json = self._get_military_campaigns_json_list().json()
if resp_json.get("countries"): if resp_json.get("countries"):
self.all_battles = {} if self.all_battles is None:
self.countries = {} self.all_battles = {}
else:
self.all_battles.clear()
if self.countries is None:
self.countries = {}
else:
self.countries.clear()
for c_id, c_data in resp_json.get("countries").items(): for c_id, c_data in resp_json.get("countries").items():
if int(c_id) not in self.countries: if int(c_id) not in self.countries:
self.countries.update({ self.countries.update({
@ -550,8 +570,8 @@ class Citizen(CitizenAPI):
self.countries[int(c_id)].update(allies=c_data.get("allies")) self.countries[int(c_id)].update(allies=c_data.get("allies"))
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_data in resp_json.get("battles", {}).values():
self.all_battles.update({int(battle_id): Battle(battle_data)}) self.all_battles.update({battle_data.get('id'): Battle(battle_data)})
def eat(self): def eat(self):
""" """
@ -583,8 +603,7 @@ class Citizen(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(
good_timedelta(self.now, good_timedelta(self.now, 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")
@ -646,8 +665,7 @@ class Citizen(CitizenAPI):
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:
errors = self.fight(battle_id, side_id=side, is_air=False, errors = self.fight(battle_id, side_id=side, count=self.energy.food_fights - 5)
count=self.energy.food_fights - 5)
if errors: if errors:
error_count += errors error_count += errors
if self.config.epic_hunt_ebs: if self.config.epic_hunt_ebs:
@ -659,7 +677,7 @@ class Citizen(CitizenAPI):
self.active_fs = active_fs self.active_fs = active_fs
def sorted_battles(self, sort_by_time: bool = False) -> List[int]: def sorted_battles(self, sort_by_time: bool = True) -> List[int]:
cs_battles_air: List[int] = [] cs_battles_air: List[int] = []
cs_battles_ground: List[int] = [] cs_battles_ground: List[int] = []
deployed_battles_air: List[int] = [] deployed_battles_air: List[int] = []
@ -670,8 +688,12 @@ class Citizen(CitizenAPI):
other_battles_ground: List[int] = [] other_battles_ground: List[int] = []
ret_battles = [] ret_battles = []
for bid, battle in sorted(self.all_battles.items(), key=lambda b: b[1].start if sort_by_time else b[0], if sort_by_time:
reverse=sort_by_time): battle_list = sorted(self.all_battles.values(), key=lambda b: b.start)
battle_list.reverse()
else:
battle_list = sorted(self.all_battles.values(), key=lambda b: b.id)
for battle in battle_list:
battle_sides = [battle.invader.id, battle.defender.id] battle_sides = [battle.invader.id, battle.defender.id]
# Previous battles # Previous battles
@ -779,15 +801,17 @@ class Citizen(CitizenAPI):
if not self.travel_to_battle(battle_id, country_ids_to_travel): if not self.travel_to_battle(battle_id, country_ids_to_travel):
break break
self.fight(battle_id, side_id, battle.is_air) self.fight(battle_id, side_id)
self.travel_to_residence() self.travel_to_residence()
self.collect_weekly_reward() self.collect_weekly_reward()
break break
def fight(self, battle_id: int, side_id: int, is_air: bool = False, count: int = None): def fight(self, battle_id: int, side_id: int, count: int = None):
if not is_air and self.config.boosters: battle = self.all_battles[battle_id]
zone_id = battle.div[11 if battle.is_air else self.division].battle_zone_id
if not battle.is_air and self.config.boosters:
self.activate_dmg_booster() self.activate_dmg_booster()
data = dict(sideId=side_id, battleId=battle_id) self.set_default_weapon(battle_id)
error_count = 0 error_count = 0
ok_to_fight = True ok_to_fight = True
if count is None: if count is None:
@ -798,7 +822,7 @@ class Citizen(CitizenAPI):
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.recovered >= 50)):
hits, error, damage = self._shoot(is_air, data) hits, error, damage = self._shoot(battle.is_air, battle_id, side_id, zone_id)
count -= hits count -= hits
total_hits += hits total_hits += hits
total_damage += damage total_damage += damage
@ -810,15 +834,15 @@ class Citizen(CitizenAPI):
ok_to_fight = False ok_to_fight = False
if total_damage: if total_damage:
self.reporter.report_action(json_val=dict(battle=battle_id, side=side_id, dmg=total_damage, self.reporter.report_action(json_val=dict(battle=battle_id, side=side_id, dmg=total_damage,
air=is_air, hits=total_hits), action="FIGHT") air=battle.is_air, hits=total_hits), action="FIGHT")
if error_count: if error_count:
return error_count return error_count
def _shoot(self, air: bool, data: dict): def _shoot(self, air: bool, battle_id: int, side_id: int, zone_id: int):
if air: if air:
response = self._post_military_fight_air(data['battleId'], data['sideId']) response = self._post_military_fight_air(battle_id, side_id, zone_id)
else: else:
response = self._post_military_fight_ground(data['battleId'], data['sideId']) response = self._post_military_fight_ground(battle_id, side_id, zone_id)
if "Zone is not meant for " in response.text: if "Zone is not meant for " in response.text:
self.sleep(5) self.sleep(5)
@ -833,9 +857,11 @@ class Citizen(CitizenAPI):
if j_resp.get("error"): if j_resp.get("error"):
if j_resp.get("message") == "SHOOT_LOCKOUT" or j_resp.get("message") == "ZONE_INACTIVE": if j_resp.get("message") == "SHOOT_LOCKOUT" or j_resp.get("message") == "ZONE_INACTIVE":
pass pass
elif j_resp.get("message") == "NOT_ENOUGH_WEAPONS":
self.set_default_weapon(battle_id)
else: else:
if j_resp.get("message") == "UNKNOWN_SIDE": if j_resp.get("message") == "UNKNOWN_SIDE":
self._rw_choose_side(data["battleId"], data["sideId"]) self._rw_choose_side(battle_id, side_id)
err = True err = True
elif j_resp.get("message") == "ENEMY_KILLED": elif j_resp.get("message") == "ENEMY_KILLED":
hits = (self.energy.recovered - j_resp["details"]["wellness"]) // 10 hits = (self.energy.recovered - j_resp["details"]["wellness"]) // 10
@ -1323,7 +1349,7 @@ class Citizen(CitizenAPI):
if not self.get_active_ground_damage_booster(): if not self.get_active_ground_damage_booster():
duration = 0 duration = 0
for length, amount in self.boosters[50].items(): for length, amount in self.boosters[50].items():
if amount > 1: if amount > 2:
duration = length duration = length
break break
if duration: if duration:
@ -1471,7 +1497,7 @@ class Citizen(CitizenAPI):
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 " log_msg = ("End for Weekly challenge is near "
f"(Recoverable until WC end {max_count}hp | want to do {count}hits)") 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
@ -1494,8 +1520,7 @@ class Citizen(CitizenAPI):
@property @property
def next_wc_start(self) -> 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 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), timedelta(days=days))
timedelta(days=days))
@property @property
def time_till_week_change(self) -> timedelta: def time_till_week_change(self) -> timedelta:
@ -1949,19 +1974,19 @@ class Citizen(CitizenAPI):
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) return {}
round_id = battle.get('zone_id') # battle = self.all_battles.get(battle_id)
division = self.division if round_id % 4 else 11 # round_id = battle.zone_id
# division = self.division if round_id % 4 else 11
resp = self._post_military_battle_console(battle_id, round_id, division).json() #
resp.pop('rounds', None) # resp = self._post_military_battle_console(battle_id, 'battleStatistics', round_id, division).json()
ret = dict() # resp.pop('rounds', None)
for country_id, data in resp.items(): # ret = dict()
ret.update({int(country_id): []}) # for country_id, data in resp.items():
for place in sorted(data.get("fighterData", {}).values(), key=lambda _: -_['raw_value']): # ret.update({int(country_id): []})
ret[int(country_id)].append((place['citizenId'], place['raw_value'])) # for place in sorted(data.get("fighterData", {}).values(), key=lambda _: -_['raw_value']):
# ret[int(country_id)].append((place['citizenId'], place['raw_value']))
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=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)
@ -2029,3 +2054,23 @@ class Citizen(CitizenAPI):
def speedup_map_quest_node(self, node_id: int): def speedup_map_quest_node(self, node_id: int):
node = self.get_anniversary_quest_data().get('cities', {}).get(str(node_id), {}) node = self.get_anniversary_quest_data().get('cities', {}).get(str(node_id), {})
return self._post_map_rewards_speedup(node_id, node.get("skipCost", 0)) return self._post_map_rewards_speedup(node_id, node.get("skipCost", 0))
def get_available_weapons(self, battle_id: int):
return self._get_military_show_weapons(battle_id).json()
def set_default_weapon(self, battle_id: int) -> int:
battle = self.all_battles[battle_id]
available_weapons = self._get_military_show_weapons(battle_id).json()
weapon_quality = -1
if not battle.is_air:
for weapon in available_weapons:
if weapon['weaponId'] == 7 and weapon['weaponQuantity'] > 30:
weapon_quality = 7
break
return self.change_weapon(battle_id, weapon_quality)
def change_weapon(self, battle_id: int, weapon_quality: int) -> int:
battle = self.all_battles[battle_id]
battle_zone = battle.div[11 if battle.is_air else self.division].battle_zone_id
r = self._post_military_change_weapon(battle_id, battle_zone, weapon_quality)
return r.json().get('weaponInfluence')

View File

@ -271,7 +271,7 @@ class Config:
work = True work = True
train = True train = True
wam = False wam = False
auto_sell: List[str] = list() auto_sell: List[str] = None
auto_sell_all = False auto_sell_all = False
employees = False employees = False
fight = False fight = False
@ -295,6 +295,9 @@ class Config:
telegram_chat_id = 0 telegram_chat_id = 0
telegram_token = "" telegram_token = ""
def __init__(self):
self.auto_sell = []
@property @property
def wt(self): def wt(self):
return self.work and self.train return self.work and self.train
@ -379,7 +382,7 @@ class Details:
pp = 0 pp = 0
pin = None pin = None
gold = 0 gold = 0
next_pp: List[int] = [] next_pp: List[int] = None
citizen_id = 0 citizen_id = 0
citizenship = 0 citizenship = 0
current_region = 0 current_region = 0
@ -390,6 +393,9 @@ class Details:
daily_task_reward = False daily_task_reward = False
mayhem_skills = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, } mayhem_skills = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, }
def __init__(self):
self.next_pp = []
@property @property
def xp_till_level_up(self): def xp_till_level_up(self):
if self.xp >= 10000: if self.xp >= 10000:
@ -452,8 +458,8 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
""" """
self._req = SlowRequests() self._req = SlowRequests()
def post(self, url: str, *args, **kwargs) -> Response: def post(self, url: str, data=None, json=None, **kwargs) -> Response:
return self._req.post(url, *args, **kwargs) return self._req.post(url, data, json, **kwargs)
def get(self, url: str, **kwargs) -> Response: def get(self, url: str, **kwargs) -> Response:
return self._req.get(url, **kwargs) return self._req.get(url, **kwargs)
@ -464,6 +470,9 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
def _get_military_battlefield_choose_side(self, battle: int, side: int) -> Response: def _get_military_battlefield_choose_side(self, battle: int, side: int) -> Response:
return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side)) return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side))
def _get_military_show_weapons(self, battle: int) -> Response:
return self.get("{}/military/show-weapons".format(self.url), params={'_token': self.token, 'battleId': battle})
def _get_candidate_party(self, party_slug: str) -> Response: def _get_candidate_party(self, party_slug: str) -> Response:
return self.post("{}/candidate/{}".format(self.url, party_slug)) return self.post("{}/candidate/{}".format(self.url, party_slug))
@ -529,6 +538,9 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
def _get_military_campaigns(self) -> Response: def _get_military_campaigns(self) -> Response:
return self.get("{}/military/campaigns-new/".format(self.url)) return self.get("{}/military/campaigns-new/".format(self.url))
def _get_military_campaigns_json_list(self) -> Response:
return self.get("{}/military/campaignsJson/list".format(self.url))
def _get_military_show_weapons(self, battle_id: int) -> Response: def _get_military_show_weapons(self, battle_id: int) -> Response:
params = {"_token": self.token, "battleId": battle_id} params = {"_token": self.token, "battleId": battle_id}
return self.get("{}/military/show-weapons".format(self.url), params=params) return self.get("{}/military/show-weapons".format(self.url), params=params)
@ -757,6 +769,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token) data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token)
return self.post("{}/military/fight-activateBooster".format(self.url), data=data) return self.post("{}/military/fight-activateBooster".format(self.url), data=data)
def _post_military_change_weapon(self, battle: int, battle_zone: int, weapon_level: int,) -> Response:
data = dict(battleId=battle, _token=self.token, battleZoneId=battle_zone, customizationLevel=weapon_level)
return self.post("{}/military/change-weapon".format(self.url), data=data)
def _post_login(self, email: str, password: str) -> Response: def _post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on') data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on')
return self.post("{}/login".format(self.url), data=data) return self.post("{}/login".format(self.url), data=data)
@ -780,21 +796,16 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data.update(page=page) data.update(page=page)
return self.post("{}/military/battle-console".format(self.url), data=data) return self.post("{}/military/battle-console".format(self.url), data=data)
def _post_military_change_weapon(self, battle_id: int, battle_zone_id: int, customization_level: int) -> Response:
data = dict(_token=self.token, battleZoneId=battle_zone_id, battleId=battle_id,
customizationLevel=customization_level)
return self.post("{}/military/change-weapon".format(self.url), data=data)
def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response: def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response:
data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token) data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token)
return self.post("{}/military/deploy-bomb".format(self.url), data=data) return self.post("{}/military/deploy-bomb".format(self.url), data=data)
def _post_military_fight_air(self, battle_id: int, side_id: int) -> Response: def _post_military_fight_air(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token) data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data) return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data)
def _post_military_fight_ground(self, battle_id: int, side_id: int) -> Response: def _post_military_fight_ground(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token) data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data) return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data)
def _post_military_group_missions(self) -> Response: def _post_military_group_missions(self) -> Response:
@ -894,6 +905,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = {"_token": self.token, "post_message": body} data = {"_token": self.token, "post_message": body}
return self.post("{}/main/wall-post/create/json".format(self.url), data=data) return self.post("{}/main/wall-post/create/json".format(self.url), data=data)
def _post_main_wall_post_automatic(self, **kwargs) -> Response:
kwargs.update(_token=self.token)
return self.post("{}/main/wall-post/create/json".format(self.url), data=kwargs)
def _post_main_wall_post_retrieve(self) -> Response: def _post_main_wall_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False} data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data) return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data)
@ -914,9 +929,19 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = {'nodeId': node_id, '_token': self.token} data = {'nodeId': node_id, '_token': self.token}
return self.post("{}/main/map-rewards-claim".format(self.url), data=data) return self.post("{}/main/map-rewards-claim".format(self.url), data=data)
def _post_new_war(self, self_country_id: int, attack_country_id: int, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate,
countryNameConfirm=utils.COUNTRY_LINK[attack_country_id])
return self.post("{}/{}/new-war".format(self.url, utils.COUNTRY_LINK[self_country_id]), data=data)
def _post_new_donation(self, country_id: int, amount: int, org_name: str, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate, currency=1, value=amount, commit='Propose',
type_name=org_name)
return self.post("{}/{}/new-donation".format(self.url, utils.COUNTRY_LINK[country_id]), data=data)
class Reporter: class Reporter:
__to_update: List[Dict[Any, Any]] = [] __to_update: List[Dict[Any, Any]] = None
name: str = "" name: str = ""
email: str = "" email: str = ""
citizen_id: int = 0 citizen_id: int = 0
@ -932,6 +957,7 @@ class Reporter:
self._req = Session() self._req = Session()
self.url = "https://api.erep.lv" self.url = "https://api.erep.lv"
self._req.headers.update({"user-agent": "Bot reporter v2"}) self._req.headers.update({"user-agent": "Bot reporter v2"})
self.__to_update = []
self.__registered: bool = False self.__registered: bool = False
def do_init(self, name: str = "", email: str = "", citizen_id: int = 0): def do_init(self, name: str = "", email: str = "", citizen_id: int = 0):
@ -1010,7 +1036,7 @@ class MyJSONEncoder(JSONEncoder):
return dict(headers=o.headers.__dict__, url=o.url, text=o.text) return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
elif hasattr(o, '__dict__'): elif hasattr(o, '__dict__'):
return o.__dict__ return o.__dict__
elif isinstance(o, deque): elif isinstance(o, (deque, set)):
return list(o) return list(o)
elif isinstance(o, Citizen): elif isinstance(o, Citizen):
return o.to_json() return o.to_json()
@ -1033,30 +1059,39 @@ class BattleSide:
class BattleDivision: class BattleDivision:
end: datetime.datetime end: datetime.datetime
epic: bool epic: bool
dom_pts: Dict[str, int] = None dom_pts: Dict[str, int]
wall: Dict[str, Union[int, float]] = None wall: Dict[str, Union[int, float]]
battle_zone_id: int
def_medal: Dict[str, int]
inv_medal: Dict[str, int]
@property @property
def div_end(self) -> bool: def div_end(self) -> bool:
return utils.now() >= self.end return utils.now() >= self.end
def __init__(self, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int, wall_for: int, wall_dom: float): def __init__(
self, div_id: int, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int,
wall_for: int, wall_dom: float, def_medal: Tuple[int, int], inv_medal: Tuple[int, int]
):
self.battle_zone_id = div_id
self.end = end self.end = end
self.epic = epic self.epic = epic
self.dom_pts = dict({"inv": inv_pts, "def": def_pts}) self.dom_pts = dict({"inv": inv_pts, "def": def_pts})
self.wall = dict({"for": wall_for, "dom": wall_dom}) self.wall = dict({"for": wall_for, "dom": wall_dom})
self.def_medal = {"id": def_medal[0], "dmg": def_medal[1]}
self.inv_medal = {"id": inv_medal[0], "dmg": inv_medal[1]}
class Battle: class Battle:
id: int = 0 id: int
war_id: int = 0 war_id: int
zone_id: int = 0 zone_id: int
is_rw: bool = False is_rw: bool
is_dict_lib: bool = False is_dict_lib: bool
start: datetime.datetime = None start: datetime.datetime
invader: BattleSide = None invader: BattleSide
defender: BattleSide = None defender: BattleSide
div: Dict[int, BattleDivision] = None div: Dict[int, BattleDivision]
@property @property
def is_air(self) -> bool: def is_air(self) -> bool:
@ -1087,11 +1122,18 @@ class Battle:
else: else:
end = utils.localize_dt(datetime.datetime.max - datetime.timedelta(days=1)) end = utils.localize_dt(datetime.datetime.max - datetime.timedelta(days=1))
battle_div = BattleDivision( if not data['stats']['def']:
end=end, epic=data.get('epic_type') in [1, 5], def_medal = (0, 0)
inv_pts=data.get('dom_pts').get("inv"), def_pts=data.get('dom_pts').get("def"), else:
wall_for=data.get('wall').get("for"), wall_dom=data.get('wall').get("dom") def_medal = (data['stats']['def']['citizenId'], data['stats']['def']['damage'])
) if not data['stats']['inv']:
inv_medal = (0, 0)
else:
inv_medal = (data['stats']['inv']['citizenId'], data['stats']['inv']['damage'])
battle_div = BattleDivision(end=end, epic=data.get('epic_type') in [1, 5], div_id=data.get('id'),
inv_pts=data.get('dom_pts').get("inv"), def_pts=data.get('dom_pts').get("def"),
wall_for=data.get('wall').get("for"), wall_dom=data.get('wall').get("dom"),
def_medal=def_medal, inv_medal=inv_medal)
self.div.update({div: battle_div}) self.div.update({div: battle_div})
@ -1141,17 +1183,19 @@ class EnergyToFight:
class TelegramBot: class TelegramBot:
__initialized = False __initialized = False
__queue: List[str] = [] __queue: List[str]
chat_id = 0 chat_id = 0
api_url = "" api_url = ""
player_name = "" player_name = ""
__thread_stopper: threading.Event = None __thread_stopper: threading.Event
_last_time: datetime.datetime = None _last_time: datetime.datetime
_last_full_energy_report: datetime.datetime = None _last_full_energy_report: datetime.datetime
_next_time: datetime.datetime = None _next_time: datetime.datetime
_threads: List[threading.Thread] = [] _threads: List[threading.Thread]
def __init__(self, stop_event: threading.Event = None): def __init__(self, stop_event: threading.Event = None):
self._threads = []
self.__queue = []
self.__thread_stopper = threading.Event() if stop_event is None else stop_event self.__thread_stopper = threading.Event() if stop_event is None else stop_event
def __dict__(self): def __dict__(self):

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.16.1 current_version = 0.17.3
commit = True commit = True
tag = True tag = True

View File

@ -42,6 +42,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.16.1', version='0.17.3',
zip_safe=False, zip_safe=False,
) )