Compare commits

...

19 Commits

Author SHA1 Message Date
d6e161d815 Bump version: 0.15.2 → 0.15.3 2019-08-24 15:44:22 +03:00
1285e95cec Inventory usage bugfixes 2019-08-24 10:48:04 +03:00
324db2c136 Fix new division numbering 2019-08-24 10:27:31 +03:00
1c6b41e41b Inventory updates and booster usage updates 2019-08-24 10:03:52 +03:00
a52552afb7 Use MyJSONEncoder from classes 2019-08-22 14:33:45 +03:00
28bfdc7b20 Use country ids from constant in utils 2019-08-22 14:33:07 +03:00
de1b734728 Don't check levelup when eating 2019-08-22 14:32:32 +03:00
fa5646ecfd Receive daily order 2019-08-22 14:32:00 +03:00
339392cfb0 Regex bugfix 2019-08-13 15:44:07 +03:00
7ebba458cb Max time timezones 2019-08-12 14:19:52 +03:00
4f436292af Organisation account fetcher - UNSTABLE 2019-08-12 12:54:58 +03:00
416c391d21 Improved levelup energy management 2019-08-11 01:45:49 +03:00
66c53ef985 Typo 2019-08-11 01:44:45 +03:00
3fa7d097fe Found awards switch to ASCII friendlier multiplier char - ✕ -> x
Localize max div end time
2019-08-05 11:55:39 +03:00
6af9675c39 Added gameTokensMarket endpoint 2019-08-05 10:20:36 +03:00
2343a6c6c8 WeeklyChallange end energy saver tweaks 2019-08-05 10:20:19 +03:00
7e56f01a38 Added gameTokensMarket endpoint 2019-08-05 10:13:48 +03:00
e14cbc18e9 Bump version: 0.15.1 → 0.15.2 2019-08-01 17:24:07 +03:00
048ce798dd All battle div div containing dicts where reference to the same object 2019-08-01 17:23:24 +03:00
6 changed files with 210 additions and 179 deletions

View File

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

View File

@ -5,7 +5,7 @@ import sys
import threading
import time
from json import loads, dumps
from typing import Dict, List, Tuple, Any, Union, Mapping
from typing import Dict, List, Tuple, Any, Union
import requests
from requests import Response, RequestException
@ -18,9 +18,9 @@ class Citizen(classes.CitizenAPI):
division = 0
all_battles: Dict[int, classes.Battle] = dict()
countries: Dict[int, Dict[str, Union[str, List[int]]]] = dict()
__last_war_update_data = {}
all_battles: Dict[int, classes.Battle] = None
countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
__last_war_update_data = None
__last_full_update: datetime.datetime = utils.now().min
active_fs: bool = False
@ -28,24 +28,20 @@ class Citizen(classes.CitizenAPI):
food = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
inventory = {"used": 0, "total": 0}
boosters = {
"100_damageBoosters_5_7200": 0, # 2h × 60min × 60sec, +50%
"100_damageBoosters_5_28800": 0, # 8h × 60min × 60sec, +50%
"100_damageBoosters_5_86400": 0, # 1d × 24h × 60min × 60sec, +50%
"100_speedBoosters_1_180": 0, # 3min × 60sec, ×2 kills
"100_speedBoosters_2_600": 0, # 10min × 60sec, ×5 kills
"100_catchupBoosters_30_60": 0, # 60sec, +30%
100: {
}, 50: {
}
}
candies_normal = 0
candies_double = 0
candies_small = 0
tickets = 0
eb_normal = 0
eb_double = 0
eb_small = 0
work_units = 0
ot_points = 0
tg_contract = {}
promos = {}
tg_contract = None
promos = None
eday = 0
@ -82,6 +78,8 @@ class Citizen(classes.CitizenAPI):
utils.write_silent_log(*args, **kwargs)
def sleep(self, seconds: int):
if seconds < 0:
seconds = 0
if self.config.interactive:
utils.interactive_sleep(seconds)
else:
@ -256,7 +254,7 @@ class Citizen(classes.CitizenAPI):
continue
if data:
msgs = ["{count} {kind}, totaling {} {currency}\n"
msgs = ["{count} x {kind}, totaling {} {currency}\n"
"{about}".format(d["count"] * d["reward"], **d) for d in data.values()]
self.write_log("Found awards: {}".format("\n".join(msgs)))
@ -293,7 +291,7 @@ class Citizen(classes.CitizenAPI):
html = self.r.text
ugly_js = re.search(r"promotions: (\[{?.*}?]),\s+", html).group(1)
promos = loads(utils.normalize_html_json(ugly_js))
self.promos = {k: v for k, v in self.promos.items() 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
for promo in promos:
promo_name = promo.get("id")
@ -345,9 +343,8 @@ class Citizen(classes.CitizenAPI):
self.details.xp = citizen.get("currentExperiencePoints", 0)
self.details.daily_task_done = citizen.get("dailyTasksDone", False)
self.details.daily_task_reward = citizen.get("hasReward", False)
# if citizen.get("dailyOrderDone", False) and not citizen.get("hasDailyOrderReward", False):
# self.post_military_group_missions(self.token)
# self.get_citizen_daily_assistant()
if citizen.get("dailyOrderDone", False) and not citizen.get("hasDailyOrderReward", False):
self._post_military_group_missions()
self.details.next_pp.sort()
for id_, skill in citizen.get("mySkills", {}).items():
@ -391,36 +388,65 @@ class Citizen(classes.CitizenAPI):
self.my_companies.update_holding_companies()
def update_inventory(self) -> dict:
self.food.update({"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0})
self.eb_small = 0
j = self._get_economy_inventory_items().json()
active_items = {}
for item in j.get("inventoryItems", {}).get("activeEnhancements", {}).get("items", {}).values():
active_items.update({item['name']: item['active']['time_left']})
final_items = {}
for item in j.get("inventoryItems", {}).get("finalProducts", {}).get("items", {}).values():
name = item['name']
if item.get('type') == 'damageBoosters':
if item['quality'] == 5:
self.boosters[50].update({item['duration']: item['amount']})
elif item['quality'] == 10:
self.boosters[100].update({item['duration']: item['amount']})
delta = item['duration']
if delta // 3600:
name += f" {delta // 3600}h"
if delta // 60 % 60:
name += f" {delta // 60 % 60}m"
if delta % 60:
name += f" {delta % 60}s"
elif item['industryId'] == 1:
amount = item['amount']
q = item['quality']
if 1 <= q <= 7:
self.food.update({f"q{q}": item['amount']})
else:
if q == 10:
self.eb_normal = amount
elif q == 11:
self.eb_double = amount
elif q == 13:
self.eb_small += amount
elif q == 14:
self.eb_small += amount
elif item['industryId'] == 3 and item['quality'] == 5:
self.ot_points = item['amount']
elif item['industryId'] == 4 and item['quality'] == 100:
self.ot_points = item['amount']
if item['amount']:
final_items.update({name: item['amount']})
raw_materials = {}
for item in j.get("inventoryItems", {}).get("rawMaterials", {}).get("items", {}).values():
name = item['name']
if item['isPartial']:
continue
if item['amount']:
raw_materials.update({name: item['amount']})
self.inventory.update({"used": j.get("inventoryStatus").get("usedStorage"),
"total": j.get("inventoryStatus").get("totalStorage")})
final = j.get("inventoryItems").get("finalProducts").get("items")
self.food.update({
"q1": final.get("1_1", {"amount": 0}).get("amount", 0),
"q2": final.get("1_2", {"amount": 0}).get("amount", 0),
"q3": final.get("1_3", {"amount": 0}).get("amount", 0),
"q4": final.get("1_4", {"amount": 0}).get("amount", 0),
"q5": final.get("1_5", {"amount": 0}).get("amount", 0),
"q6": final.get("1_6", {"amount": 0}).get("amount", 0),
"q7": final.get("1_7", {"amount": 0}).get("amount", 0),
})
self.boosters.update({
"100_damageBoosters_5_7200": final.get("100_damageBoosters_5_7200", {"amount": 0}).get("amount", 0),
"100_damageBoosters_5_28800": final.get("100_damageBoosters_5_28800", {"amount": 0}).get("amount", 0),
"100_damageBoosters_5_86400": final.get("100_damageBoosters_5_86400", {"amount": 0}).get("amount", 0),
"100_speedBoosters_1_180": final.get("100_speedBoosters_1_180", {"amount": 0}).get("amount", 0),
"100_speedBoosters_2_600": final.get("100_speedBoosters_2_600", {"amount": 0}).get("amount", 0),
"100_catchupBoosters_30_60": final.get("100_catchupBoosters_30_60", {"amount": 0}).get("amount", 0),
})
self.candies_normal = final.get("1_10", {"amount": 0}).get("amount", 0)
self.candies_double = final.get("1_11", {"amount": 0}).get("amount", 0)
self.candies_small = final.get("1_12", {"amount": 0}).get("amount", 0)
self.ot_points = final.get("4_100", {"amount": 0}).get("amount", 0)
self.tickets = final.get("3_5", {"amount": 0}).get("amount", 0)
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])
return j
return inventory
def update_weekly_challenge(self):
data = self._get_weekly_challenge_data().json()
@ -443,8 +469,9 @@ class Citizen(classes.CitizenAPI):
self.update_citizen_info()
resp_json = self._get_military_campaigns().json()
self.all_battles = {}
if resp_json.get("countries"):
self.all_battles = {}
self.countries = {}
for c_id, c_data in resp_json.get("countries").items():
if int(c_id) not in self.countries:
self.countries.update({
@ -463,27 +490,23 @@ class Citizen(classes.CitizenAPI):
"""
self.update_citizen_info()
self.update_inventory()
if self.details.xp_till_level_up > (self.energy.recovered - 50) // 10:
if self.food["total"] > self.energy.interval:
if self.energy.limit - self.energy.recovered > self.energy.interval or not self.energy.recoverable % 2:
self._eat("blue")
else:
self.write_log("I don't want to eat right now!")
if self.food["total"] > self.energy.interval:
if self.energy.limit - self.energy.recovered > self.energy.interval or not self.energy.recoverable % 2:
self._eat("blue")
else:
self.write_log("I'm out of food! But I'll try to buy some!\n{}".format(self.food))
self.buy_food()
self.update_inventory()
if self.food["total"] > self.energy.interval:
self.eat()
else:
self.write_log("I failed to buy food")
self.write_log("I don't want to eat right now!")
else:
self.write_log("I'm not allowed to eat because I have levelup coming up!")
self.write_log("I'm out of food! But I'll try to buy some!\n{}".format(self.food))
self.buy_food()
self.update_inventory()
if self.food["total"] > self.energy.interval:
self.eat()
else:
self.write_log("I failed to buy food")
self.write_log(self.health_info)
def eat_ebs(self):
self.write_log("Eating energy bar")
self.update_citizen_info()
if self.energy.recoverable:
self._eat("blue")
self._eat("orange")
@ -503,11 +526,11 @@ class Citizen(classes.CitizenAPI):
if "q{}".format(q) in self.food:
self.food["q{}".format(q)] -= amount
elif q == "10":
self.candies_normal -= amount
self.eb_normal -= amount
elif q == "11":
self.candies_double -= amount
self.eb_double -= amount
elif q == "12":
self.candies_small -= amount
self.eb_small -= amount
return response
@property
@ -700,6 +723,8 @@ class Citizen(classes.CitizenAPI):
break
def fight(self, battle_id: int, side_id: int, is_air: bool = False, count: int = None):
if not is_air and self.config.boosters:
self.activate_dmg_booster()
data = dict(sideId=side_id, battleId=battle_id)
error_count = 0
ok_to_fight = True
@ -796,10 +821,9 @@ class Citizen(classes.CitizenAPI):
else:
self._eat("blue")
if self.energy.food_fights < 1:
large = max(self.energy.reference_time, self.now)
small = min(self.energy.reference_time, self.now)
self.write_log("I don't have energy to work. Will sleep for {}s".format((large - small).seconds))
self.sleep(int((large - small).total_seconds()))
seconds = (self.energy.reference_time - self.now).total_seconds()
self.write_log("I don't have energy to work. Will sleep for {}s".format(seconds))
self.sleep(seconds)
self._eat("blue")
self.work()
@ -807,7 +831,7 @@ class Citizen(classes.CitizenAPI):
r = self._get_training_grounds_json()
tg_json = r.json()
self.details.gold = tg_json["page_details"]["gold"]
self.tg_contract.update({"free_train": tg_json["hasFreeTrain"]})
self.tg_contract = {"free_train": tg_json["hasFreeTrain"]}
if tg_json["contracts"]:
self.tg_contract.update(**tg_json["contracts"][0])
@ -965,7 +989,7 @@ class Citizen(classes.CitizenAPI):
def sell_produced_product(self, kind: str, quality: int = 1, amount: int = 0):
if not amount:
inv_resp = self.update_inventory()
inv_resp = self._get_economy_inventory_items().json()
category = "rawMaterials" if kind.endswith("Raw") else "finalProducts"
item = "{}_{}".format(self.available_industries[kind], quality)
amount = inv_resp.get("inventoryItems").get(category).get("items").get(item).get("amount", 0)
@ -1146,7 +1170,7 @@ class Citizen(classes.CitizenAPI):
countries = [country_id]
else:
good_countries = self.get_travel_countries()
countries = {cid for cid in self.countries.keys() if cid in good_countries}
countries = {cid for cid in utils.COUNTRIES.keys() if cid in good_countries}
start_dt = self.now
iterable = [countries, product or items, [quality] if quality else range(1, 8)]
@ -1228,18 +1252,17 @@ class Citizen(classes.CitizenAPI):
value="New amount {o.cc}cc, {o.gold}g".format(o=self.details))
return not response.json().get("error", False)
def activate_dmg_booster(self, battle_id: int):
def activate_dmg_booster(self):
if self.config.boosters:
duration = 0
if self.boosters.get("100_damageBoosters_5_600", 0) > 0:
duration = 600
elif self.boosters.get("100_damageBoosters_5_7200", 0) > 1:
duration = 7200
elif self.boosters.get("100_damageBoosters_5_28800", 0) > 2:
duration = 28800
elif self.boosters.get("100_damageBoosters_5_86400", 0) > 2:
duration = 86400
self._post_fight_activate_booster(battle_id, 5, duration, "damage")
inventory = self.update_inventory()
if not ("+100% Damage" in inventory['items']['active'] or "+50% Damage" in inventory['items']['active']):
duration = 0
for length, amount in self.boosters[50].items():
if amount > 1:
duration = length
break
if duration:
self._post_economy_activate_booster(5, duration, "damage")
def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
return self._post_activate_battle_effect(battle_id, kind, self.details.citizen_id)
@ -1289,8 +1312,8 @@ class Citizen(classes.CitizenAPI):
def should_travel_to_fight(self) -> bool:
ret = False
if self.config.always_travel:
return True
if self.should_do_levelup: # Do levelup
ret = True
elif self.should_do_levelup: # Do levelup
ret = True
elif self.config.all_in and self.energy.available > self.energy.limit * 2 - self.energy.interval * 3:
ret = True
@ -1312,7 +1335,7 @@ class Citizen(classes.CitizenAPI):
if self.is_levelup_reachable:
log_msg = "Level up"
if self.should_do_levelup:
count = (self.energy.limit * 3) // 10
count = (self.energy.available + self.energy.limit) // 10
force_fight = True
else:
self.write_log("Waiting for fully recovered energy before leveling up.", False)
@ -1355,7 +1378,7 @@ class Citizen(classes.CitizenAPI):
if count > 0 and not force_fight:
if self.my_companies.ff_lockdown and self.details.pp > 75:
if count - self.my_companies.ff_lockdown > 0:
if self.energy.food_fights - self.my_companies.ff_lockdown < count:
log_msg = ("Fight count modified (old count: {} | FF: {} | "
"WAM ff_lockdown: {} | New count: {})").format(
count, self.energy.food_fights, self.my_companies.ff_lockdown,
@ -1367,9 +1390,12 @@ class Citizen(classes.CitizenAPI):
log_msg = "Not fighting because WAM needs {} food fights".format(self.my_companies.ff_lockdown)
if self.max_time_till_full_ff > self.time_till_week_change:
max_count = int((self.time_till_week_change - self.time_till_full_ff).total_seconds()) // 60
log_msg = "End for Weekly challenge is near ({} | {})".format(max_count, count)
count = count if max_count > count else max_count
max_count = int((self.time_till_week_change -
self.time_till_full_ff).total_seconds()) // 360 * self.energy.interval
log_msg = "End for Weekly challenge is near (Recoverable until WC end {}hp | want to do {}hits)".format(
max_count, count)
max_usable_energy = max_count - self.energy.limit * 2
count = count if max_usable_energy > count * 10 else max_usable_energy // 10
if not silent:
self.write_log(log_msg, False)
@ -1436,14 +1462,8 @@ class Citizen(classes.CitizenAPI):
If Energy limit >= xp till levelup * 10
:return: bool
"""
if self.energy.limit - self.energy.interval <= self.energy.recoverable:
if self.is_levelup_reachable:
# 45xp till levelup, 50hp/6min, 500+500/500 energy = 500+450 >= 1000
# 40xp till levelup, 50hp/6min, 450+500/500 energy = 500+400 >= 950
# 25xp till levelup, 50hp/6min, 300+500/500 energy = 500+250 >= 800
# 25xp till levelup, 50hp/6min, 300+200/500 energy = 500+250 >= 500
return self.energy.limit + self.details.xp_till_level_up * 10 <= self.energy.available
return False
return (self.energy.recovered >= self.details.xp_till_level_up * 10 and # can reach next level
self.energy.recoverable + 2 * self.energy.interval >= self.energy.limit) # can do max amount of dmg
def get_article_comments(self, article_id: int = 2645676, page_id: int = 1) -> Response:
return self._post_article_comments(article_id, page_id)
@ -1733,52 +1753,23 @@ class Citizen(classes.CitizenAPI):
self.reporter.send_state_update(**data)
def send_inventory_update(self):
j = self.update_inventory()
active_items = {}
for item in j.get("inventoryItems", {}).get("activeEnhancements", {}).get("items", {}).values():
active_items.update({item['name']: item['active']['time_left']})
final_items = {}
for item in j.get("inventoryItems", {}).get("finalProducts", {}).get("items", {}).values():
name = item['name']
if item.get('type') == 'damageBoosters':
delta = item['duration']
if delta // 3600:
name += f" {delta // 3600}h"
if delta // 60 % 60:
name += f" {delta // 60 % 60}m"
if delta % 60:
name += f" {delta % 60}s"
if item['amount']:
final_items.update({name: item['amount']})
raw_materials = {}
for item in j.get("inventoryItems", {}).get("rawMaterials", {}).get("items", {}).values():
name = item['name']
if item['isPartial']:
continue
if item['amount']:
raw_materials.update({name: item['amount']})
to_report = dict(items=dict(active=active_items, final=final_items, raw=raw_materials), status=self.inventory)
to_report = self.update_inventory()
self.reporter.report_action("INVENTORY", json_val=to_report)
def check_house_durability(self) -> Dict[int, datetime.datetime]:
ret = {}
inv = self.update_inventory()
if "activeEnhancements" in inv.get("inventoryItems", {}):
active = inv.get("inventoryItems", {}).get("activeEnhancements", {}).get("items", {})
for q in range(1, 6):
if "4_%i_active" % q in active:
till = utils.good_timedelta(self.now, datetime.timedelta(
seconds=active["4_%i_active" % q]["active"]["time_left"]))
ret.update({q: till})
active = inv["items"]['active']
for q in range(1, 6):
if f"House Q{q}" in active:
till = utils.good_timedelta(self.now, datetime.timedelta(seconds=active[f"House Q{q}"]))
ret.update({q: till})
return ret
def buy_and_activate_house(self, q: int) -> Dict[int, datetime.datetime]:
inventory = self.update_inventory()
ok_to_activate = False
if not inventory.get("inventoryItems").get("finalProducts", {}).get("items", {}).get("4_{}".format(q)):
if not inventory["items"]["final"].get("House Q{}".format(q)):
offers = []
countries = [self.details.citizenship, ]
if self.details.current_country != self.details.citizenship:
@ -1868,7 +1859,7 @@ class Citizen(classes.CitizenAPI):
def write_on_country_wall(self, message: str) -> bool:
self._get_main()
post_to_wall_as = re.findall(r"""id="post_to_country_as".*?<option value="(\d?)">.*?</option>.*</select>""",
post_to_wall_as = re.findall(r'id="post_to_country_as".*?<option value="(\d?)">.*?</option>.*</select>',
self.r.text, re.S | re.M)
r = self._post_country_post_create(message, max(post_to_wall_as, key=int) if post_to_wall_as else 0)
return r.json()
@ -1892,4 +1883,53 @@ class Citizen(classes.CitizenAPI):
return ret
def to_json(self, indent: bool = False) -> str:
return dumps(self.__dict__, cls=utils.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
return dumps(self.__dict__, cls=classes.MyJSONEncoder, indent=4 if indent else None, sort_keys=True)
def get_game_token_offers(self):
r = self._post_economy_game_tokens_market('retrieve').json()
return {v.get('id'): dict(amount=v.get('amount'), price=v.get('price')) for v in r.get("topOffers")}
def fetch_organisation_account(self, org_id: int):
r = self._get_economy_citizen_accounts(org_id)
table = re.search(r'(<table class="holder racc" .*</table>)', r.text, re.I | re.M | re.S)
if table:
account = re.findall(r'>\s*(\d+.\d+)\s*</td>', table.group(1))
if account:
return {"gold": account[0], "cc": account[1], 'ok': True}
return {"gold": 0, "cc": 0, 'ok': False}
def get_ground_hit_dmg_value(self, rang: int = None, strength: float = None, elite: bool = None, ne: bool = False,
booster_50: bool = False, booster_100: bool = False, tp: bool = True) -> float:
if not rang or strength or elite is None:
r = self._get_citizen_profile(self.details.citizen_id).json()
if not rang:
rang = r['military']['militaryData']['ground']['rankNumber']
if not strength:
strength = r['military']['militaryData']['ground']['strength']
if elite is None:
elite = r['citizenAttributes']['level'] > 100
if ne:
tp = True
dmg = int(10 * (1 + strength / 400) * (1 + rang / 5) * 3)
booster = 1.5 if booster_50 else 2 if booster_100 else 1
elite = 1.1 if elite else 1
dmg = int(dmg * booster * elite)
legend = 1 if (not tp or rang < 70) else 1 + (rang - 69) / 10
dmg = int(dmg * legend)
return dmg * (1.1 if ne else 1)
def get_air_hit_dmg_value(self, rang: int = None, elite: bool = None, ne: bool = False,
weapon: bool = False) -> float:
if not rang or elite is None:
r = self._get_citizen_profile(self.details.citizen_id).json()
if not rang:
rang = r['military']['militaryData']['air']['rankNumber']
if elite is None:
elite = r['citizenAttributes']['level'] > 100
dmg = int(10 * (1 + rang / 5) * (1.2 if weapon else 1))
elite = 1.1 if elite else 1
dmg = int(dmg * elite)
return dmg * (1.1 if ne else 1.)

View File

@ -26,11 +26,13 @@ class ErepublikNetworkException(Exception):
class MyCompanies:
work_units: int = 0
next_ot_time: datetime.datetime
holdings: Dict[int, Dict] = dict()
companies: Dict[int, Dict] = dict()
holdings: Dict[int, Dict] = None
companies: Dict[int, Dict] = None
ff_lockdown: int = 0
def __init__(self):
self.holdings = dict()
self.companies = dict()
self.next_ot_time = utils.now()
def prepare_holdings(self, holdings: dict):
@ -478,6 +480,9 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
def _get_country_military(self, country: str) -> Response:
return self.get("{}/country/military/{}".format(self.url, country))
def _get_economy_citizen_accounts(self, organisation_id: int) -> Response:
return self.get("{}/economy/citizen-accounts/{}".format(self.url, organisation_id))
def _get_economy_inventory_items(self) -> Response:
return self.get("{}/economy/inventory-items/".format(self.url))
@ -615,6 +620,10 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = dict(_token=self.token, buttonColor=color)
return self.post("{}/main/eat".format(self.url), params=data)
def _post_economy_activate_booster(self, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, fromInventory=True)
return self.post("{}/economy/activateBooster".format(self.url), data=data)
def _post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
return self.post("{}/economy/activateHouse".format(self.url), data=data)
@ -648,6 +657,11 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
data = dict(_token=self.token, personalOffers=int(personal), page=page, currencyId=currency)
return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data)
def _post_economy_game_tokens_market(self, action: str) -> Response:
assert action in ['retrieve', ]
data = dict(_token=self.token, action=action)
return self.post("{}/economy/gameTokensMarketAjax".format(self.url), data=data)
def _post_economy_job_market_apply(self, citizen: int, salary: int) -> Response:
data = dict(_token=self.token, citizenId=citizen, salary=salary)
return self.post("{}/economy/job-market-apply".format(self.url), data=data)
@ -748,7 +762,7 @@ Class for unifying eRepublik known endpoints and their required/optional paramet
url_pk = 0 if len(citizens) > 1 else str(citizens[0])
data = dict(citizen_name=",".join([str(x) for x in citizens]),
citizen_subject=subject, _token=self.token, citizen_message=body)
return self.post("{}/main/messages-compose/{}}".format(self.url, url_pk), data=data)
return self.post("{}/main/messages-compose/{}".format(self.url, url_pk), data=data)
def _post_military_battle_console(self, battle_id: int, action: str, page: int = 1, **kwargs) -> Response:
data = dict(battleId=battle_id, action=action, _token=self.token)
@ -970,8 +984,8 @@ class MyJSONEncoder(JSONEncoder):
class BattleSide:
id: int
points: int
deployed: List[int] = list()
allies: List[int] = list()
deployed: List[int] = None
allies: List[int] = None
def __init__(self, country_id: int, points: int, allies: List[int], deployed: List[int]):
self.id = country_id
@ -983,8 +997,8 @@ class BattleSide:
class BattleDivision:
end: datetime.datetime
epic: bool
dom_pts: Dict[str, int] = dict()
wall: Dict[str, Union[int, float]] = dict()
dom_pts: Dict[str, int] = None
wall: Dict[str, Union[int, float]] = None
@property
def div_end(self) -> bool:
@ -993,8 +1007,8 @@ class BattleDivision:
def __init__(self, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int, wall_for: int, wall_dom: float):
self.end = end
self.epic = epic
self.dom_pts.update({"inv": inv_pts, "def": def_pts})
self.wall.update({"for": wall_for, "dom": wall_dom})
self.dom_pts = dict({"inv": inv_pts, "def": def_pts})
self.wall = dict({"for": wall_for, "dom": wall_dom})
class Battle(object):
@ -1006,13 +1020,13 @@ class Battle(object):
start: datetime.datetime = None
invader: BattleSide = None
defender: BattleSide = None
div: Dict[int, BattleDivision] = dict()
div: Dict[int, BattleDivision] = None
@property
def is_air(self) -> bool:
return not bool(self.zone_id % 4)
def __init__(self, battle: dict):
def __init__(self, battle: Dict[str, Any]):
self.id = int(battle.get('id', 0))
self.war_id = int(battle.get('war_id', 0))
self.zone_id = int(battle.get('zone_id', 0))
@ -1029,12 +1043,13 @@ class Battle(object):
[row.get('id') for row in battle.get('def', {}).get('ally_list')],
[row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']])
self.div = {}
for div, data in battle.get('div', {}).items():
div = int(div)
div = int(data.get('div'))
if data.get('end'):
end = datetime.datetime.fromtimestamp(data.get('end'), tz=utils.erep_tz)
else:
end = datetime.datetime.max
end = utils.localize_dt(datetime.datetime.max - datetime.timedelta(days=1))
battle_div = BattleDivision(
end=end, epic=data.get('epic_type') in [1, 5],

View File

@ -7,15 +7,11 @@ import sys
import time
import traceback
import unicodedata
from collections import deque
from decimal import Decimal
from json import JSONEncoder
from pathlib import Path
from typing import Union, Any, List, NoReturn, Mapping
import pytz
import requests
from requests import Response
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
"now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
@ -23,7 +19,6 @@ __all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
"write_silent_log", "write_interactive_log", "get_file", "write_file",
"send_email", "normalize_html_json", "process_error", ]
FOOD_ENERGY = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
COMMIT_ID = "7b92e19"
@ -86,7 +81,8 @@ COUNTRIES = {1: 'Romania', 9: 'Brazil', 10: 'Italy', 11: 'France', 12: 'Germany'
COUNTRY_LINK = {1: 'Romania', 9: 'Brazil', 11: 'France', 12: 'Germany', 13: 'Hungary', 82: 'Cyprus', 168: 'Georgia',
15: 'Spain', 23: 'Canada', 26: 'Mexico', 27: 'Argentina', 28: 'Venezuela', 80: 'Montenegro', 24: 'USA',
29: 'United-Kingdom', 50: 'Australia', 47: 'South-Korea',171: 'Cuba', 79: 'Republic-of-Macedonia-FYROM',
29: 'United-Kingdom', 50: 'Australia', 47: 'South-Korea', 171: 'Cuba',
79: 'Republic-of-Macedonia-FYROM',
30: 'Switzerland', 31: 'Netherlands', 32: 'Belgium', 33: 'Austria', 34: 'Czech-Republic', 35: 'Poland',
36: 'Slovakia', 37: 'Norway', 38: 'Sweden', 39: 'Finland', 40: 'Ukraine', 41: 'Russia', 42: 'Bulgaria',
43: 'Turkey', 44: 'Greece', 45: 'Japan', 48: 'India', 49: 'Indonesia', 78: 'Colombia', 68: 'Singapore',
@ -98,27 +94,6 @@ COUNTRY_LINK = {1: 'Romania', 9: 'Brazil', 11: 'France', 12: 'Germany', 13: 'Hun
169: 'Armenia', 83: 'Belarus', 84: 'New-Zealand', 164: 'Saudi-Arabia', 170: 'Nigeria', }
class MyJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, Decimal):
return float("{:.02f}".format(o))
elif isinstance(o, datetime.datetime):
return dict(__type__='datetime', year=o.year, month=o.month, day=o.day, hour=o.hour, minute=o.minute,
second=o.second, microsecond=o.microsecond)
elif isinstance(o, datetime.date):
return dict(__type__='date', year=o.year, month=o.month, day=o.day)
elif isinstance(o, datetime.timedelta):
return dict(__type__='timedelta', days=o.days, seconds=o.seconds,
microseconds=o.microseconds, total_seconds=o.total_seconds())
elif isinstance(o, Response):
return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
elif hasattr(o, '__dict__'):
return o.__dict__
elif isinstance(o, deque):
return list(o)
return super().default(o)
def now() -> datetime.datetime:
return datetime.datetime.now(erep_tz).replace(microsecond=0)
@ -296,6 +271,7 @@ def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[A
if local_vars:
if "state_thread" in local_vars:
local_vars.pop('state_thread', None)
from erepublik.classes import MyJSONEncoder
files.append(('file', ("local_vars.json", json.dumps(local_vars, indent=2,
cls=MyJSONEncoder, sort_keys=True), "application/json")))
if isinstance(player, Citizen):

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.15.1
current_version = 0.15.3
commit = True
tag = True

View File

@ -42,6 +42,6 @@ setup(
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/eeriks/erepublik_script',
version='0.15.1',
version='0.15.3',
zip_safe=False,
)