Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
7edfa3b004 | |||
12aee23739 | |||
b7f8182ef5 | |||
39093accd0 | |||
aba8c15fd3 | |||
f294506a2d | |||
fd56c6c389 | |||
4f613ee5ac | |||
a7dd528597 | |||
24c755d414 | |||
13b639dc5a | |||
ec1141a46e | |||
77170433c2 | |||
4736f70203 |
8
.github/ISSUE_TEMPLATE.md
vendored
8
.github/ISSUE_TEMPLATE.md
vendored
@ -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.
|
||||||
```
|
```
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.16.1
|
current_version = 0.17.3
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@ -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,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user