Module blaseball_mike.models.player
Expand source code
import math
import random
import uuid
import warnings
from dateutil.parser import parse
from .base import Base
from .item import Item
from .modification import Modification
from .. import database, chronicler, reference
class Player(Base):
"""
Represents a blaseball player.
"""
@classmethod
def _get_fields(cls):
p = cls.load_one("766dfd1e-11c3-42b6-a167-9b2d568b5dc0")
return [cls._from_api_conversion(x) for x in p.fields]
@classmethod
def load(cls, *ids, time=None):
"""
Load one or more players by ID.
Returns a dictionary of players keyed by Player ID.
"""
if time is None:
players = database.get_player(list(ids))
return {
id_: cls(player) for (id_, player) in players.items()
}
else:
if isinstance(time, str):
time = parse(time)
players = chronicler.get_entities("player", id_=list(ids), at=time)
return {
player["entityId"]: cls(dict(player["data"], timestamp=time)) for player in players
}
@classmethod
def load_one(cls, id_, time=None):
"""
Load single player by ID.
"""
return cls.load(id_, time=time).get(id_)
@classmethod
def load_one_at_time(cls, id_, time):
"""
Load single player by ID with historical stats at the provided IRL datetime.
"""
return cls.load_one(id_, time=time)
@classmethod
def load_all(cls, time=None):
"""
Load all players
"""
players = chronicler.get_entities("player", at=time)
result = {}
for player in players:
if time is not None:
player["data"]["timestamp"] = time
result[player["entityId"]] = cls(player["data"])
return result
@classmethod
def load_history(cls, id_, order='desc', count=None):
"""
Returns array of Player stat changes with most recent first.
"""
players = chronicler.get_versions("player", id_=id_, order=order, count=count)
return [cls(dict(p['data'], timestamp=p['validFrom'])) for p in players]
@classmethod
def load_all_by_gameday(cls, season, day):
"""
Returns dict of all players and their fk stats on the given season/day. 1-indexed.
"""
players = reference.get_all_players_for_gameday(season, day)
return {
player['player_id']: cls(player) for player in players
}
@classmethod
def load_by_gameday(cls, id_, season, day):
"""
Returns one player and their fk stats on the given season/day. 1-indexed.
"""
return cls.load_all_by_gameday(season, day).get(id_)
@classmethod
def find_by_name(cls, name):
"""
Try to find the player by their name (case sensitive) or return None.
"""
ids = reference.get_player_ids_by_name(name)
if not ids:
return None
return cls.load_one(ids[0])
@classmethod
def make_random(cls, name="Random Player", seed=None):
"""
Generate a completely random player.
"""
rng = random.Random(seed)
if seed:
id_ = uuid.uuid3(uuid.NAMESPACE_X500, name=str(seed))
else:
id_ = uuid.uuid4()
return Player({
'name': name,
'id': str(id_),
'baseThirst': rng.random(),
'continuation': rng.random(),
'groundFriction': rng.random(),
'indulgence': rng.random(),
'laserlikeness': rng.random(),
'divinity': rng.random(),
'martyrdom': rng.random(),
'moxie': rng.random(),
'musclitude': rng.random(),
'patheticism': rng.random(),
'thwackability': rng.random(),
'tragicness': rng.random(),
'anticapitalism': rng.random(),
'chasiness': rng.random(),
'omniscience': rng.random(),
'tenaciousness': rng.random(),
'watchfulness': rng.random(),
'coldness': rng.random(),
'overpowerment': rng.random(),
'ruthlessness': rng.random(),
'shakespearianism': rng.random(),
'unthwackability': rng.random(),
'suppression': rng.random(),
'buoyancy': rng.random(),
'cinnamon': rng.random(),
'deceased': False,
'peanutAllergy': rng.random() > .25,
'pressurization': rng.random(),
'soul': rng.randint(2, 9),
'totalFingers': rng.randint(9, 42),
'fate': rng.randint(1, 99),
})
def get_name(self, unscatter=True):
name = None
if unscatter and getattr(self, "state", None) is not None:
name = self.state.get("unscatteredName", None)
if name is not None:
return name
return self.name
@Base.lazy_load("_hitting_rating", use_default=False)
def hitting_rating(self):
if getattr(self, "_hitting_rating", None) is not None:
return self._hitting_rating
return (((1 - self.tragicness) ** 0.01) * ((1 - self.patheticism) ** 0.05) *
((self.thwackability * self.divinity) ** 0.35) *
((self.moxie * self.musclitude) ** 0.075) * (self.martyrdom ** 0.02))
def get_hitting_rating(self, include_items=True):
item_rating = 0
if include_items and getattr(self, "items", None) is not None:
item_rating = sum([x.hitting_rating for x in self.items])
return item_rating + self.hitting_rating
batting_rating = hitting_rating
@Base.lazy_load("_pitching_rating", use_default=False)
def pitching_rating(self):
if getattr(self, "_pitching_rating", None) is not None:
return self._pitching_rating
return ((self.unthwackability ** 0.5) * (self.ruthlessness ** 0.4) *
(self.overpowerment ** 0.15) * (self.shakespearianism ** 0.1) * (self.coldness ** 0.025))
def get_pitching_rating(self, include_items=True):
item_rating = 0
if include_items and getattr(self, "items", None) is not None:
item_rating = sum([x.pitching_rating for x in self.items])
return item_rating + self.pitching_rating
@Base.lazy_load("_baserunning_rating", use_default=False)
def baserunning_rating(self):
if getattr(self, "_baserunning_rating", None) is not None:
return self._baserunning_rating
return ((self.laserlikeness**0.5) *
((self.continuation * self.base_thirst * self.indulgence * self.ground_friction) ** 0.1))
def get_baserunning_rating(self, include_items=True):
item_rating = 0
if include_items and getattr(self, "items", None) is not None:
item_rating = sum([x.baserunning_rating for x in self.items])
return item_rating + self.baserunning_rating
@Base.lazy_load("_defense_rating", use_default=False)
def defense_rating(self):
if getattr(self, "_defense_rating", None) is not None:
return self._defense_rating
return (((self.omniscience * self.tenaciousness) ** 0.2) *
((self.watchfulness * self.anticapitalism * self.chasiness) ** 0.1))
def get_defense_rating(self, include_items=True):
item_rating = 0
if include_items and getattr(self, "items", None) is not None:
item_rating = sum([x.defense_rating for x in self.items])
return item_rating + self.defense_rating
@staticmethod
def _rating_to_stars_discipline(val):
return 0.5 * (round(val * 10))
@staticmethod
def _rating_to_stars(val):
return round(val * 5, 1)
@property
def hitting_stars(self):
warnings.warn("instead of .hitting_stars, use .get_hitting_stars()",
DeprecationWarning, stacklevel=2)
return self._rating_to_stars_discipline(self.hitting_rating)
@property
def batting_stars(self):
warnings.warn("instead of .batting_stars, use .get_hitting_stars()",
DeprecationWarning, stacklevel=2)
return self.hitting_stars
@property
def pitching_stars(self):
warnings.warn("instead of .pitching_stars, use .get_pitching_stars()",
DeprecationWarning, stacklevel=2)
return self._rating_to_stars_discipline(self.pitching_rating)
@property
def baserunning_stars(self):
warnings.warn("instead of .baserunning_stars, use .get_baserunning_stars()",
DeprecationWarning, stacklevel=2)
return self._rating_to_stars_discipline(self.baserunning_rating)
@property
def defense_stars(self):
warnings.warn("instead of .defense_stars, use .get_defense_stars()",
DeprecationWarning, stacklevel=2)
return self._rating_to_stars_discipline(self.defense_rating)
def get_hitting_stars(self, include_items=True, round_stars=False):
rate = self.get_hitting_rating(include_items=include_items)
if round_stars:
return self._rating_to_stars_discipline(rate)
return self._rating_to_stars(rate)
def get_pitching_stars(self, include_items=True, round_stars=False):
rate = self.get_pitching_rating(include_items=include_items)
if round_stars:
return self._rating_to_stars_discipline(rate)
return self._rating_to_stars(rate)
def get_baserunning_stars(self, include_items=True, round_stars=False):
rate = self.get_baserunning_rating(include_items=include_items)
if round_stars:
return self._rating_to_stars_discipline(rate)
return self._rating_to_stars(rate)
def get_defense_stars(self, include_items=True, round_stars=False):
rate = self.get_defense_rating(include_items=include_items)
if round_stars:
return self._rating_to_stars_discipline(rate)
return self._rating_to_stars(rate)
def get_vibe(self, day):
"""
Get Player vibes for day. Day is 1-indexed
"""
if not getattr(self, "pressurization", None) or not getattr(self, "cinnamon", None) \
or not getattr(self, "buoyancy", None):
return None
return 0.5 * ((self.pressurization + self.cinnamon) *
math.sin(math.pi * (2 / (6 + round(10 * self.buoyancy)) * (day - 1) + 0.5)) -
self.pressurization + self.cinnamon)
@property
def soulscream(self):
return self.get_soulscream()
def get_soulscream(self, collapse=True):
letters = ["A", "E", "I", "O", "U", "X", "H", "A", "E", "I"]
stats = [self.pressurization, self.divinity, self.tragicness, self.shakespearianism, self.ruthlessness]
scream = []
if collapse:
soul_max = min(self.soul, 300)
else:
soul_max = self.soul
for r in range(soul_max):
sub_scream = []
i = 10 ** -r
for s in stats:
try:
c = math.floor((s % i) / i * 10)
sub_scream.append(letters[c])
except ZeroDivisionError:
sub_scream.append("undefined")
scream.extend(sub_scream + sub_scream + [sub_scream[0]])
scream = ''.join(scream)
if collapse and self.soul > 300:
scream += f"... (CONT. FOR {self.soul - 300} SOUL)"
return scream
@Base.lazy_load("_blood_id", cache_name="_blood", use_default=False)
def blood(self):
if isinstance(getattr(self, "_blood_id", None), str):
return self._blood_id
return database.get_blood(getattr(self, "_blood_id", None))[0]
@Base.lazy_load("_coffee_id", cache_name="_coffee", use_default=False)
def coffee(self):
if isinstance(getattr(self, "_coffee_id", None), str):
return self._coffee_id
return database.get_coffee(getattr(self, "_coffee_id", None))[0]
@Base.lazy_load("_bat_id", cache_name="_bat", use_default=False)
def bat(self):
return Item.load_one_discipline(getattr(self, "_bat_id", None))
@Base.lazy_load("_armor_id", cache_name="_armor", use_default=False)
def armor(self):
return Item.load_one_discipline(getattr(self, "_armor_id", None))
@Base.lazy_load("_items", default_value=list())
def items(self):
return [Item(x) for x in self._items]
@Base.lazy_load("_perm_attr_ids", cache_name="_perm_attr", default_value=list())
def perm_attr(self):
return Modification.load(*self._perm_attr_ids)
@Base.lazy_load("_seas_attr_ids", cache_name="_seas_attr", default_value=list())
def seas_attr(self):
return Modification.load(*self._seas_attr_ids)
@Base.lazy_load("_week_attr_ids", cache_name="_week_attr", default_value=list())
def week_attr(self):
return Modification.load(*self._week_attr_ids)
@Base.lazy_load("_game_attr_ids", cache_name="_game_attr", default_value=list())
def game_attr(self):
return Modification.load(*self._game_attr_ids)
@Base.lazy_load("_item_attr_ids", cache_name="_item_attr", default_value=list())
def item_attr(self):
return Modification.load(*self._item_attr_ids)
@Base.lazy_load("_league_team_id", cache_name="_league_team")
def league_team_id(self):
from .team import Team
return Team.load(self._league_team_id)
@property
def league_team(self):
# alias to league_team_id
return self.league_team_id
@Base.lazy_load("_tournament_team_id", cache_name="_tournament_team")
def tournament_team_id(self):
from .team import Team
return Team.load(self._tournament_team_id)
@property
def tournament_team(self):
# alias to tournament_team_id
return self.tournament_team_id
def simulated_copy(self, overrides=None, multipliers=None, buffs=None, reroll=None):
"""
Return a copy of this player with adjusted stats (ie to simulate blessings)
`overrides` is a dict where the key specifies an attribute to completely overwrite with new value.
`multipliers` is a dict where key specifies attr to multiply by value
`buffs` is a dict where key specifies attr to add value
`reroll` is a dict where the key specifies attr to reroll (value is unused)
`batting_rating`, `pitching_rating`, `baserunning_rating`, `defense_rating`, and `overall_rating`
can additionally be passed to `multipliers`, `buffs`, and `reroll` to automatically multiply the
appropriate related stats.
"""
overrides = overrides or {}
multipliers = multipliers or {}
buffs = buffs or {}
reroll = reroll or {}
original_json = self.json()
if not original_json.get("baseThirst") and original_json.get("base_thirst"):
original_json["baseThirst"] = original_json["base_thirst"]
if not original_json.get("groundFriction") and original_json.get("ground_friction"):
original_json["groundFriction"] = original_json["ground_friction"]
for override_key, override_value in overrides.items():
original_json[override_key] = override_value
for m_key, m_val in multipliers.items():
if m_key in ('batting_rating', 'overall_rating'):
original_json['buoyancy'] *= (1.0 - m_val)
original_json['tragicness'] *= (1.0 - m_val)
original_json['patheticism'] *= (1.0 - m_val)
original_json['thwackability'] *= (1.0 + m_val)
original_json['divinity'] *= (1.0 + m_val)
original_json['moxie'] *= (1.0 + m_val)
original_json['musclitude'] *= (1.0 + m_val)
original_json['martyrdom'] *= (1.0 + m_val)
if m_key in ('pitching_rating', 'overall_rating'):
original_json['unthwackability'] *= (1.0 + m_val)
original_json['ruthlessness'] *= (1.0 + m_val)
original_json['overpowerment'] *= (1.0 + m_val)
original_json['shakespearianism'] *= (1.0 + m_val)
original_json['coldness'] *= (1.0 + m_val)
original_json['suppression'] *= (1.0 + m_val)
if m_key in ('baserunning_rating', 'overall_rating'):
original_json['laserlikeness'] *= (1.0 + m_val)
original_json['continuation'] *= (1.0 + m_val)
original_json['baseThirst'] *= (1.0 + m_val)
original_json['indulgence'] *= (1.0 + m_val)
original_json['groundFriction'] *= (1.0 + m_val)
if m_key in ('defense_rating', 'overall_rating'):
original_json['omniscience'] *= (1.0 + m_val)
original_json['tenaciousness'] *= (1.0 + m_val)
original_json['watchfulness'] *= (1.0 + m_val)
original_json['anticapitalism'] *= (1.0 + m_val)
original_json['chasiness'] *= (1.0 + m_val)
if m_key in ('tragicness', 'patheticism'):
original_json[m_key] *= (1.0 - m_val)
elif m_key in original_json:
original_json[m_key] *= (1.0 + m_val)
for b_key, b_val in buffs.items():
if b_key in ('batting_rating', 'overall_rating'):
original_json['tragicness'] = min(0.99, max(0.01, original_json['tragicness'] - b_val))
original_json['patheticism'] = min(0.99, max(0.01, original_json['patheticism'] - b_val))
original_json['buoyancy'] = max(0.01, original_json['buoyancy'] + b_val)
original_json['thwackability'] = max(0.01, original_json['thwackability'] + b_val)
original_json['divinity'] = max(0.01, original_json['divinity'] + b_val)
original_json['moxie'] = max(0.01, original_json['moxie'] + b_val)
original_json['musclitude'] = max(0.01, original_json['musclitude'] + b_val)
original_json['martyrdom'] = max(0.01, original_json['martyrdom'] + b_val)
if b_key in ('pitching_rating', 'overall_rating'):
original_json['unthwackability'] = max(0.01, original_json['unthwackability'] + b_val)
original_json['ruthlessness'] = max(0.01, original_json['ruthlessness'] + b_val)
original_json['overpowerment'] = max(0.01, original_json['overpowerment'] + b_val)
original_json['shakespearianism'] = max(0.01, original_json['shakespearianism'] + b_val)
original_json['coldness'] = max(0.01, original_json['coldness'] + b_val)
original_json['suppression'] = max(0.01, original_json['suppression'] + b_val)
if b_key in ('baserunning_rating', 'overall_rating'):
original_json['laserlikeness'] = max(0.01, original_json['laserlikeness'] + b_val)
original_json['continuation'] = max(0.01, original_json['continuation'] + b_val)
original_json['baseThirst'] = max(0.01, original_json['baseThirst'] + b_val)
original_json['indulgence'] = max(0.01, original_json['indulgence'] + b_val)
original_json['groundFriction'] = max(0.01, original_json['groundFriction'] + b_val)
if b_key in ('defense_rating', 'overall_rating'):
original_json['omniscience'] = max(0.01, original_json['omniscience'] + b_val)
original_json['tenaciousness'] = max(0.01, original_json['tenaciousness'] + b_val)
original_json['watchfulness'] = max(0.01, original_json['watchfulness'] + b_val)
original_json['anticapitalism'] = max(0.01, original_json['anticapitalism'] + b_val)
original_json['chasiness'] = max(0.01, original_json['chasiness'] + b_val)
if b_key in ('tragicness', 'patheticism'):
original_json[b_key] = min(0.99, max(0.01, original_json[b_key] - b_val))
elif b_key in original_json:
original_json[b_key] = max(0.01, original_json[b_key] + b_val)
for r_key, _ in reroll.items():
if r_key in ('batting_rating', 'overall_rating'):
original_json['buoyancy'] = random.uniform(0.01, 0.99)
original_json['tragicness'] = random.uniform(0.01, 0.99)
original_json['patheticism'] = random.uniform(0.01, 0.99)
original_json['thwackability'] = random.uniform(0.01, 0.99)
original_json['divinity'] = random.uniform(0.01, 0.99)
original_json['moxie'] = random.uniform(0.01, 0.99)
original_json['musclitude'] = random.uniform(0.01, 0.99)
original_json['martyrdom'] = random.uniform(0.01, 0.99)
if r_key in ('pitching_rating', 'overall_rating'):
original_json['unthwackability'] = random.uniform(0.01, 0.99)
original_json['ruthlessness'] = random.uniform(0.01, 0.99)
original_json['overpowerment'] = random.uniform(0.01, 0.99)
original_json['shakespearianism'] = random.uniform(0.01, 0.99)
original_json['coldness'] = random.uniform(0.01, 0.99)
original_json['suppression'] = random.uniform(0.01, 0.99)
if r_key in ('baserunning_rating', 'overall_rating'):
original_json['laserlikeness'] = random.uniform(0.01, 0.99)
original_json['continuation'] = random.uniform(0.01, 0.99)
original_json['baseThirst'] = random.uniform(0.01, 0.99)
original_json['indulgence'] = random.uniform(0.01, 0.99)
original_json['groundFriction'] = random.uniform(0.01, 0.99)
if r_key in ('defense_rating', 'overall_rating'):
original_json['omniscience'] = random.uniform(0.01, 0.99)
original_json['tenaciousness'] = random.uniform(0.01, 0.99)
original_json['watchfulness'] = random.uniform(0.01, 0.99)
original_json['anticapitalism'] = random.uniform(0.01, 0.99)
original_json['chasiness'] = random.uniform(0.01, 0.99)
if r_key in ('tragicness', 'patheticism'):
original_json[r_key] = random.uniform(0.01, 0.99)
elif r_key in original_json:
original_json[r_key] = random.uniform(0.01, 0.99)
# Clear database-provided ratings to force a recalculation
original_json['hittingRating'] = None
original_json['pitchingRating'] = None
original_json['baserunningRating'] = None
original_json['defenseRating'] = None
return Player(original_json)
@property
def player_name(self):
return self.name
@player_name.setter
def player_name(self, v):
self.name = v
@property
def player_id(self):
return self.id
@player_id.setter
def player_id(self, v):
self.id = v
Classes
class Player (data, strict=False)
-
Represents a blaseball player.
Expand source code
class Player(Base): """ Represents a blaseball player. """ @classmethod def _get_fields(cls): p = cls.load_one("766dfd1e-11c3-42b6-a167-9b2d568b5dc0") return [cls._from_api_conversion(x) for x in p.fields] @classmethod def load(cls, *ids, time=None): """ Load one or more players by ID. Returns a dictionary of players keyed by Player ID. """ if time is None: players = database.get_player(list(ids)) return { id_: cls(player) for (id_, player) in players.items() } else: if isinstance(time, str): time = parse(time) players = chronicler.get_entities("player", id_=list(ids), at=time) return { player["entityId"]: cls(dict(player["data"], timestamp=time)) for player in players } @classmethod def load_one(cls, id_, time=None): """ Load single player by ID. """ return cls.load(id_, time=time).get(id_) @classmethod def load_one_at_time(cls, id_, time): """ Load single player by ID with historical stats at the provided IRL datetime. """ return cls.load_one(id_, time=time) @classmethod def load_all(cls, time=None): """ Load all players """ players = chronicler.get_entities("player", at=time) result = {} for player in players: if time is not None: player["data"]["timestamp"] = time result[player["entityId"]] = cls(player["data"]) return result @classmethod def load_history(cls, id_, order='desc', count=None): """ Returns array of Player stat changes with most recent first. """ players = chronicler.get_versions("player", id_=id_, order=order, count=count) return [cls(dict(p['data'], timestamp=p['validFrom'])) for p in players] @classmethod def load_all_by_gameday(cls, season, day): """ Returns dict of all players and their fk stats on the given season/day. 1-indexed. """ players = reference.get_all_players_for_gameday(season, day) return { player['player_id']: cls(player) for player in players } @classmethod def load_by_gameday(cls, id_, season, day): """ Returns one player and their fk stats on the given season/day. 1-indexed. """ return cls.load_all_by_gameday(season, day).get(id_) @classmethod def find_by_name(cls, name): """ Try to find the player by their name (case sensitive) or return None. """ ids = reference.get_player_ids_by_name(name) if not ids: return None return cls.load_one(ids[0]) @classmethod def make_random(cls, name="Random Player", seed=None): """ Generate a completely random player. """ rng = random.Random(seed) if seed: id_ = uuid.uuid3(uuid.NAMESPACE_X500, name=str(seed)) else: id_ = uuid.uuid4() return Player({ 'name': name, 'id': str(id_), 'baseThirst': rng.random(), 'continuation': rng.random(), 'groundFriction': rng.random(), 'indulgence': rng.random(), 'laserlikeness': rng.random(), 'divinity': rng.random(), 'martyrdom': rng.random(), 'moxie': rng.random(), 'musclitude': rng.random(), 'patheticism': rng.random(), 'thwackability': rng.random(), 'tragicness': rng.random(), 'anticapitalism': rng.random(), 'chasiness': rng.random(), 'omniscience': rng.random(), 'tenaciousness': rng.random(), 'watchfulness': rng.random(), 'coldness': rng.random(), 'overpowerment': rng.random(), 'ruthlessness': rng.random(), 'shakespearianism': rng.random(), 'unthwackability': rng.random(), 'suppression': rng.random(), 'buoyancy': rng.random(), 'cinnamon': rng.random(), 'deceased': False, 'peanutAllergy': rng.random() > .25, 'pressurization': rng.random(), 'soul': rng.randint(2, 9), 'totalFingers': rng.randint(9, 42), 'fate': rng.randint(1, 99), }) def get_name(self, unscatter=True): name = None if unscatter and getattr(self, "state", None) is not None: name = self.state.get("unscatteredName", None) if name is not None: return name return self.name @Base.lazy_load("_hitting_rating", use_default=False) def hitting_rating(self): if getattr(self, "_hitting_rating", None) is not None: return self._hitting_rating return (((1 - self.tragicness) ** 0.01) * ((1 - self.patheticism) ** 0.05) * ((self.thwackability * self.divinity) ** 0.35) * ((self.moxie * self.musclitude) ** 0.075) * (self.martyrdom ** 0.02)) def get_hitting_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.hitting_rating for x in self.items]) return item_rating + self.hitting_rating batting_rating = hitting_rating @Base.lazy_load("_pitching_rating", use_default=False) def pitching_rating(self): if getattr(self, "_pitching_rating", None) is not None: return self._pitching_rating return ((self.unthwackability ** 0.5) * (self.ruthlessness ** 0.4) * (self.overpowerment ** 0.15) * (self.shakespearianism ** 0.1) * (self.coldness ** 0.025)) def get_pitching_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.pitching_rating for x in self.items]) return item_rating + self.pitching_rating @Base.lazy_load("_baserunning_rating", use_default=False) def baserunning_rating(self): if getattr(self, "_baserunning_rating", None) is not None: return self._baserunning_rating return ((self.laserlikeness**0.5) * ((self.continuation * self.base_thirst * self.indulgence * self.ground_friction) ** 0.1)) def get_baserunning_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.baserunning_rating for x in self.items]) return item_rating + self.baserunning_rating @Base.lazy_load("_defense_rating", use_default=False) def defense_rating(self): if getattr(self, "_defense_rating", None) is not None: return self._defense_rating return (((self.omniscience * self.tenaciousness) ** 0.2) * ((self.watchfulness * self.anticapitalism * self.chasiness) ** 0.1)) def get_defense_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.defense_rating for x in self.items]) return item_rating + self.defense_rating @staticmethod def _rating_to_stars_discipline(val): return 0.5 * (round(val * 10)) @staticmethod def _rating_to_stars(val): return round(val * 5, 1) @property def hitting_stars(self): warnings.warn("instead of .hitting_stars, use .get_hitting_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.hitting_rating) @property def batting_stars(self): warnings.warn("instead of .batting_stars, use .get_hitting_stars()", DeprecationWarning, stacklevel=2) return self.hitting_stars @property def pitching_stars(self): warnings.warn("instead of .pitching_stars, use .get_pitching_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.pitching_rating) @property def baserunning_stars(self): warnings.warn("instead of .baserunning_stars, use .get_baserunning_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.baserunning_rating) @property def defense_stars(self): warnings.warn("instead of .defense_stars, use .get_defense_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.defense_rating) def get_hitting_stars(self, include_items=True, round_stars=False): rate = self.get_hitting_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate) def get_pitching_stars(self, include_items=True, round_stars=False): rate = self.get_pitching_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate) def get_baserunning_stars(self, include_items=True, round_stars=False): rate = self.get_baserunning_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate) def get_defense_stars(self, include_items=True, round_stars=False): rate = self.get_defense_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate) def get_vibe(self, day): """ Get Player vibes for day. Day is 1-indexed """ if not getattr(self, "pressurization", None) or not getattr(self, "cinnamon", None) \ or not getattr(self, "buoyancy", None): return None return 0.5 * ((self.pressurization + self.cinnamon) * math.sin(math.pi * (2 / (6 + round(10 * self.buoyancy)) * (day - 1) + 0.5)) - self.pressurization + self.cinnamon) @property def soulscream(self): return self.get_soulscream() def get_soulscream(self, collapse=True): letters = ["A", "E", "I", "O", "U", "X", "H", "A", "E", "I"] stats = [self.pressurization, self.divinity, self.tragicness, self.shakespearianism, self.ruthlessness] scream = [] if collapse: soul_max = min(self.soul, 300) else: soul_max = self.soul for r in range(soul_max): sub_scream = [] i = 10 ** -r for s in stats: try: c = math.floor((s % i) / i * 10) sub_scream.append(letters[c]) except ZeroDivisionError: sub_scream.append("undefined") scream.extend(sub_scream + sub_scream + [sub_scream[0]]) scream = ''.join(scream) if collapse and self.soul > 300: scream += f"... (CONT. FOR {self.soul - 300} SOUL)" return scream @Base.lazy_load("_blood_id", cache_name="_blood", use_default=False) def blood(self): if isinstance(getattr(self, "_blood_id", None), str): return self._blood_id return database.get_blood(getattr(self, "_blood_id", None))[0] @Base.lazy_load("_coffee_id", cache_name="_coffee", use_default=False) def coffee(self): if isinstance(getattr(self, "_coffee_id", None), str): return self._coffee_id return database.get_coffee(getattr(self, "_coffee_id", None))[0] @Base.lazy_load("_bat_id", cache_name="_bat", use_default=False) def bat(self): return Item.load_one_discipline(getattr(self, "_bat_id", None)) @Base.lazy_load("_armor_id", cache_name="_armor", use_default=False) def armor(self): return Item.load_one_discipline(getattr(self, "_armor_id", None)) @Base.lazy_load("_items", default_value=list()) def items(self): return [Item(x) for x in self._items] @Base.lazy_load("_perm_attr_ids", cache_name="_perm_attr", default_value=list()) def perm_attr(self): return Modification.load(*self._perm_attr_ids) @Base.lazy_load("_seas_attr_ids", cache_name="_seas_attr", default_value=list()) def seas_attr(self): return Modification.load(*self._seas_attr_ids) @Base.lazy_load("_week_attr_ids", cache_name="_week_attr", default_value=list()) def week_attr(self): return Modification.load(*self._week_attr_ids) @Base.lazy_load("_game_attr_ids", cache_name="_game_attr", default_value=list()) def game_attr(self): return Modification.load(*self._game_attr_ids) @Base.lazy_load("_item_attr_ids", cache_name="_item_attr", default_value=list()) def item_attr(self): return Modification.load(*self._item_attr_ids) @Base.lazy_load("_league_team_id", cache_name="_league_team") def league_team_id(self): from .team import Team return Team.load(self._league_team_id) @property def league_team(self): # alias to league_team_id return self.league_team_id @Base.lazy_load("_tournament_team_id", cache_name="_tournament_team") def tournament_team_id(self): from .team import Team return Team.load(self._tournament_team_id) @property def tournament_team(self): # alias to tournament_team_id return self.tournament_team_id def simulated_copy(self, overrides=None, multipliers=None, buffs=None, reroll=None): """ Return a copy of this player with adjusted stats (ie to simulate blessings) `overrides` is a dict where the key specifies an attribute to completely overwrite with new value. `multipliers` is a dict where key specifies attr to multiply by value `buffs` is a dict where key specifies attr to add value `reroll` is a dict where the key specifies attr to reroll (value is unused) `batting_rating`, `pitching_rating`, `baserunning_rating`, `defense_rating`, and `overall_rating` can additionally be passed to `multipliers`, `buffs`, and `reroll` to automatically multiply the appropriate related stats. """ overrides = overrides or {} multipliers = multipliers or {} buffs = buffs or {} reroll = reroll or {} original_json = self.json() if not original_json.get("baseThirst") and original_json.get("base_thirst"): original_json["baseThirst"] = original_json["base_thirst"] if not original_json.get("groundFriction") and original_json.get("ground_friction"): original_json["groundFriction"] = original_json["ground_friction"] for override_key, override_value in overrides.items(): original_json[override_key] = override_value for m_key, m_val in multipliers.items(): if m_key in ('batting_rating', 'overall_rating'): original_json['buoyancy'] *= (1.0 - m_val) original_json['tragicness'] *= (1.0 - m_val) original_json['patheticism'] *= (1.0 - m_val) original_json['thwackability'] *= (1.0 + m_val) original_json['divinity'] *= (1.0 + m_val) original_json['moxie'] *= (1.0 + m_val) original_json['musclitude'] *= (1.0 + m_val) original_json['martyrdom'] *= (1.0 + m_val) if m_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] *= (1.0 + m_val) original_json['ruthlessness'] *= (1.0 + m_val) original_json['overpowerment'] *= (1.0 + m_val) original_json['shakespearianism'] *= (1.0 + m_val) original_json['coldness'] *= (1.0 + m_val) original_json['suppression'] *= (1.0 + m_val) if m_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] *= (1.0 + m_val) original_json['continuation'] *= (1.0 + m_val) original_json['baseThirst'] *= (1.0 + m_val) original_json['indulgence'] *= (1.0 + m_val) original_json['groundFriction'] *= (1.0 + m_val) if m_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] *= (1.0 + m_val) original_json['tenaciousness'] *= (1.0 + m_val) original_json['watchfulness'] *= (1.0 + m_val) original_json['anticapitalism'] *= (1.0 + m_val) original_json['chasiness'] *= (1.0 + m_val) if m_key in ('tragicness', 'patheticism'): original_json[m_key] *= (1.0 - m_val) elif m_key in original_json: original_json[m_key] *= (1.0 + m_val) for b_key, b_val in buffs.items(): if b_key in ('batting_rating', 'overall_rating'): original_json['tragicness'] = min(0.99, max(0.01, original_json['tragicness'] - b_val)) original_json['patheticism'] = min(0.99, max(0.01, original_json['patheticism'] - b_val)) original_json['buoyancy'] = max(0.01, original_json['buoyancy'] + b_val) original_json['thwackability'] = max(0.01, original_json['thwackability'] + b_val) original_json['divinity'] = max(0.01, original_json['divinity'] + b_val) original_json['moxie'] = max(0.01, original_json['moxie'] + b_val) original_json['musclitude'] = max(0.01, original_json['musclitude'] + b_val) original_json['martyrdom'] = max(0.01, original_json['martyrdom'] + b_val) if b_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] = max(0.01, original_json['unthwackability'] + b_val) original_json['ruthlessness'] = max(0.01, original_json['ruthlessness'] + b_val) original_json['overpowerment'] = max(0.01, original_json['overpowerment'] + b_val) original_json['shakespearianism'] = max(0.01, original_json['shakespearianism'] + b_val) original_json['coldness'] = max(0.01, original_json['coldness'] + b_val) original_json['suppression'] = max(0.01, original_json['suppression'] + b_val) if b_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] = max(0.01, original_json['laserlikeness'] + b_val) original_json['continuation'] = max(0.01, original_json['continuation'] + b_val) original_json['baseThirst'] = max(0.01, original_json['baseThirst'] + b_val) original_json['indulgence'] = max(0.01, original_json['indulgence'] + b_val) original_json['groundFriction'] = max(0.01, original_json['groundFriction'] + b_val) if b_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] = max(0.01, original_json['omniscience'] + b_val) original_json['tenaciousness'] = max(0.01, original_json['tenaciousness'] + b_val) original_json['watchfulness'] = max(0.01, original_json['watchfulness'] + b_val) original_json['anticapitalism'] = max(0.01, original_json['anticapitalism'] + b_val) original_json['chasiness'] = max(0.01, original_json['chasiness'] + b_val) if b_key in ('tragicness', 'patheticism'): original_json[b_key] = min(0.99, max(0.01, original_json[b_key] - b_val)) elif b_key in original_json: original_json[b_key] = max(0.01, original_json[b_key] + b_val) for r_key, _ in reroll.items(): if r_key in ('batting_rating', 'overall_rating'): original_json['buoyancy'] = random.uniform(0.01, 0.99) original_json['tragicness'] = random.uniform(0.01, 0.99) original_json['patheticism'] = random.uniform(0.01, 0.99) original_json['thwackability'] = random.uniform(0.01, 0.99) original_json['divinity'] = random.uniform(0.01, 0.99) original_json['moxie'] = random.uniform(0.01, 0.99) original_json['musclitude'] = random.uniform(0.01, 0.99) original_json['martyrdom'] = random.uniform(0.01, 0.99) if r_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] = random.uniform(0.01, 0.99) original_json['ruthlessness'] = random.uniform(0.01, 0.99) original_json['overpowerment'] = random.uniform(0.01, 0.99) original_json['shakespearianism'] = random.uniform(0.01, 0.99) original_json['coldness'] = random.uniform(0.01, 0.99) original_json['suppression'] = random.uniform(0.01, 0.99) if r_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] = random.uniform(0.01, 0.99) original_json['continuation'] = random.uniform(0.01, 0.99) original_json['baseThirst'] = random.uniform(0.01, 0.99) original_json['indulgence'] = random.uniform(0.01, 0.99) original_json['groundFriction'] = random.uniform(0.01, 0.99) if r_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] = random.uniform(0.01, 0.99) original_json['tenaciousness'] = random.uniform(0.01, 0.99) original_json['watchfulness'] = random.uniform(0.01, 0.99) original_json['anticapitalism'] = random.uniform(0.01, 0.99) original_json['chasiness'] = random.uniform(0.01, 0.99) if r_key in ('tragicness', 'patheticism'): original_json[r_key] = random.uniform(0.01, 0.99) elif r_key in original_json: original_json[r_key] = random.uniform(0.01, 0.99) # Clear database-provided ratings to force a recalculation original_json['hittingRating'] = None original_json['pitchingRating'] = None original_json['baserunningRating'] = None original_json['defenseRating'] = None return Player(original_json) @property def player_name(self): return self.name @player_name.setter def player_name(self, v): self.name = v @property def player_id(self): return self.id @player_id.setter def player_id(self, v): self.id = v
Ancestors
- Base
- abc.ABC
Static methods
def find_by_name(name)
-
Try to find the player by their name (case sensitive) or return None.
Expand source code
@classmethod def find_by_name(cls, name): """ Try to find the player by their name (case sensitive) or return None. """ ids = reference.get_player_ids_by_name(name) if not ids: return None return cls.load_one(ids[0])
def load(*ids, time=None)
-
Load one or more players by ID.
Returns a dictionary of players keyed by Player ID.
Expand source code
@classmethod def load(cls, *ids, time=None): """ Load one or more players by ID. Returns a dictionary of players keyed by Player ID. """ if time is None: players = database.get_player(list(ids)) return { id_: cls(player) for (id_, player) in players.items() } else: if isinstance(time, str): time = parse(time) players = chronicler.get_entities("player", id_=list(ids), at=time) return { player["entityId"]: cls(dict(player["data"], timestamp=time)) for player in players }
def load_all(time=None)
-
Load all players
Expand source code
@classmethod def load_all(cls, time=None): """ Load all players """ players = chronicler.get_entities("player", at=time) result = {} for player in players: if time is not None: player["data"]["timestamp"] = time result[player["entityId"]] = cls(player["data"]) return result
def load_all_by_gameday(season, day)
-
Returns dict of all players and their fk stats on the given season/day. 1-indexed.
Expand source code
@classmethod def load_all_by_gameday(cls, season, day): """ Returns dict of all players and their fk stats on the given season/day. 1-indexed. """ players = reference.get_all_players_for_gameday(season, day) return { player['player_id']: cls(player) for player in players }
def load_by_gameday(id_, season, day)
-
Returns one player and their fk stats on the given season/day. 1-indexed.
Expand source code
@classmethod def load_by_gameday(cls, id_, season, day): """ Returns one player and their fk stats on the given season/day. 1-indexed. """ return cls.load_all_by_gameday(season, day).get(id_)
def load_history(id_, order='desc', count=None)
-
Returns array of Player stat changes with most recent first.
Expand source code
@classmethod def load_history(cls, id_, order='desc', count=None): """ Returns array of Player stat changes with most recent first. """ players = chronicler.get_versions("player", id_=id_, order=order, count=count) return [cls(dict(p['data'], timestamp=p['validFrom'])) for p in players]
def load_one(id_, time=None)
-
Load single player by ID.
Expand source code
@classmethod def load_one(cls, id_, time=None): """ Load single player by ID. """ return cls.load(id_, time=time).get(id_)
def load_one_at_time(id_, time)
-
Load single player by ID with historical stats at the provided IRL datetime.
Expand source code
@classmethod def load_one_at_time(cls, id_, time): """ Load single player by ID with historical stats at the provided IRL datetime. """ return cls.load_one(id_, time=time)
def make_random(name='Random Player', seed=None)
-
Generate a completely random player.
Expand source code
@classmethod def make_random(cls, name="Random Player", seed=None): """ Generate a completely random player. """ rng = random.Random(seed) if seed: id_ = uuid.uuid3(uuid.NAMESPACE_X500, name=str(seed)) else: id_ = uuid.uuid4() return Player({ 'name': name, 'id': str(id_), 'baseThirst': rng.random(), 'continuation': rng.random(), 'groundFriction': rng.random(), 'indulgence': rng.random(), 'laserlikeness': rng.random(), 'divinity': rng.random(), 'martyrdom': rng.random(), 'moxie': rng.random(), 'musclitude': rng.random(), 'patheticism': rng.random(), 'thwackability': rng.random(), 'tragicness': rng.random(), 'anticapitalism': rng.random(), 'chasiness': rng.random(), 'omniscience': rng.random(), 'tenaciousness': rng.random(), 'watchfulness': rng.random(), 'coldness': rng.random(), 'overpowerment': rng.random(), 'ruthlessness': rng.random(), 'shakespearianism': rng.random(), 'unthwackability': rng.random(), 'suppression': rng.random(), 'buoyancy': rng.random(), 'cinnamon': rng.random(), 'deceased': False, 'peanutAllergy': rng.random() > .25, 'pressurization': rng.random(), 'soul': rng.randint(2, 9), 'totalFingers': rng.randint(9, 42), 'fate': rng.randint(1, 99), })
Instance variables
var anticapitalism
var base_thirst
var baserunning_rating
var baserunning_stars
-
Expand source code
@property def baserunning_stars(self): warnings.warn("instead of .baserunning_stars, use .get_baserunning_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.baserunning_rating)
var batting_stars
-
Expand source code
@property def batting_stars(self): warnings.warn("instead of .batting_stars, use .get_hitting_stars()", DeprecationWarning, stacklevel=2) return self.hitting_stars
var blood
var buoyancy
var chasiness
var cinnamon
var coffee
var coldness
var consecutive_hits
var continuation
var deceased
var defense_rating
var defense_stars
-
Expand source code
@property def defense_stars(self): warnings.warn("instead of .defense_stars, use .get_defense_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.defense_rating)
var divinity
var e_density
var evolution
var fate
var game_attr
var ground_friction
var hit_streak
var hitting_rating
var hitting_stars
-
Expand source code
@property def hitting_stars(self): warnings.warn("instead of .hitting_stars, use .get_hitting_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.hitting_rating)
var id
var indulgence
var item_attr
var items
var laserlikeness
var league_team
-
Expand source code
@property def league_team(self): # alias to league_team_id return self.league_team_id
var league_team_id
var martyrdom
var moxie
var musclitude
var name
var omniscience
var overpowerment
var patheticism
var peanut_allergy
var perm_attr
var pitching_rating
var pitching_stars
-
Expand source code
@property def pitching_stars(self): warnings.warn("instead of .pitching_stars, use .get_pitching_stars()", DeprecationWarning, stacklevel=2) return self._rating_to_stars_discipline(self.pitching_rating)
var player_id
-
Expand source code
@property def player_id(self): return self.id
var player_name
-
Expand source code
@property def player_name(self): return self.name
var pressurization
var ritual
var ruthlessness
var seas_attr
var shakespearianism
var soul
var soulscream
-
Expand source code
@property def soulscream(self): return self.get_soulscream()
var state
var suppression
var tenaciousness
var thwackability
var total_fingers
var tournament_team
-
Expand source code
@property def tournament_team(self): # alias to tournament_team_id return self.tournament_team_id
var tournament_team_id
var tragicness
var unthwackability
var watchfulness
var week_attr
Methods
def armor(self)
-
Expand source code
@Base.lazy_load("_armor_id", cache_name="_armor", use_default=False) def armor(self): return Item.load_one_discipline(getattr(self, "_armor_id", None))
def bat(self)
-
Expand source code
@Base.lazy_load("_bat_id", cache_name="_bat", use_default=False) def bat(self): return Item.load_one_discipline(getattr(self, "_bat_id", None))
def batting_rating(self)
-
Expand source code
@Base.lazy_load("_hitting_rating", use_default=False) def hitting_rating(self): if getattr(self, "_hitting_rating", None) is not None: return self._hitting_rating return (((1 - self.tragicness) ** 0.01) * ((1 - self.patheticism) ** 0.05) * ((self.thwackability * self.divinity) ** 0.35) * ((self.moxie * self.musclitude) ** 0.075) * (self.martyrdom ** 0.02))
def get_baserunning_rating(self, include_items=True)
-
Expand source code
def get_baserunning_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.baserunning_rating for x in self.items]) return item_rating + self.baserunning_rating
def get_baserunning_stars(self, include_items=True, round_stars=False)
-
Expand source code
def get_baserunning_stars(self, include_items=True, round_stars=False): rate = self.get_baserunning_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate)
def get_defense_rating(self, include_items=True)
-
Expand source code
def get_defense_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.defense_rating for x in self.items]) return item_rating + self.defense_rating
def get_defense_stars(self, include_items=True, round_stars=False)
-
Expand source code
def get_defense_stars(self, include_items=True, round_stars=False): rate = self.get_defense_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate)
def get_hitting_rating(self, include_items=True)
-
Expand source code
def get_hitting_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.hitting_rating for x in self.items]) return item_rating + self.hitting_rating
def get_hitting_stars(self, include_items=True, round_stars=False)
-
Expand source code
def get_hitting_stars(self, include_items=True, round_stars=False): rate = self.get_hitting_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate)
def get_name(self, unscatter=True)
-
Expand source code
def get_name(self, unscatter=True): name = None if unscatter and getattr(self, "state", None) is not None: name = self.state.get("unscatteredName", None) if name is not None: return name return self.name
def get_pitching_rating(self, include_items=True)
-
Expand source code
def get_pitching_rating(self, include_items=True): item_rating = 0 if include_items and getattr(self, "items", None) is not None: item_rating = sum([x.pitching_rating for x in self.items]) return item_rating + self.pitching_rating
def get_pitching_stars(self, include_items=True, round_stars=False)
-
Expand source code
def get_pitching_stars(self, include_items=True, round_stars=False): rate = self.get_pitching_rating(include_items=include_items) if round_stars: return self._rating_to_stars_discipline(rate) return self._rating_to_stars(rate)
def get_soulscream(self, collapse=True)
-
Expand source code
def get_soulscream(self, collapse=True): letters = ["A", "E", "I", "O", "U", "X", "H", "A", "E", "I"] stats = [self.pressurization, self.divinity, self.tragicness, self.shakespearianism, self.ruthlessness] scream = [] if collapse: soul_max = min(self.soul, 300) else: soul_max = self.soul for r in range(soul_max): sub_scream = [] i = 10 ** -r for s in stats: try: c = math.floor((s % i) / i * 10) sub_scream.append(letters[c]) except ZeroDivisionError: sub_scream.append("undefined") scream.extend(sub_scream + sub_scream + [sub_scream[0]]) scream = ''.join(scream) if collapse and self.soul > 300: scream += f"... (CONT. FOR {self.soul - 300} SOUL)" return scream
def get_vibe(self, day)
-
Get Player vibes for day. Day is 1-indexed
Expand source code
def get_vibe(self, day): """ Get Player vibes for day. Day is 1-indexed """ if not getattr(self, "pressurization", None) or not getattr(self, "cinnamon", None) \ or not getattr(self, "buoyancy", None): return None return 0.5 * ((self.pressurization + self.cinnamon) * math.sin(math.pi * (2 / (6 + round(10 * self.buoyancy)) * (day - 1) + 0.5)) - self.pressurization + self.cinnamon)
def simulated_copy(self, overrides=None, multipliers=None, buffs=None, reroll=None)
-
Return a copy of this player with adjusted stats (ie to simulate blessings)
overrides
is a dict where the key specifies an attribute to completely overwrite with new value.multipliers
is a dict where key specifies attr to multiply by valuebuffs
is a dict where key specifies attr to add valuereroll
is a dict where the key specifies attr to reroll (value is unused)batting_rating
,pitching_rating
,baserunning_rating
,defense_rating
, andoverall_rating
can additionally be passed tomultipliers
,buffs
, andreroll
to automatically multiply the appropriate related stats.Expand source code
def simulated_copy(self, overrides=None, multipliers=None, buffs=None, reroll=None): """ Return a copy of this player with adjusted stats (ie to simulate blessings) `overrides` is a dict where the key specifies an attribute to completely overwrite with new value. `multipliers` is a dict where key specifies attr to multiply by value `buffs` is a dict where key specifies attr to add value `reroll` is a dict where the key specifies attr to reroll (value is unused) `batting_rating`, `pitching_rating`, `baserunning_rating`, `defense_rating`, and `overall_rating` can additionally be passed to `multipliers`, `buffs`, and `reroll` to automatically multiply the appropriate related stats. """ overrides = overrides or {} multipliers = multipliers or {} buffs = buffs or {} reroll = reroll or {} original_json = self.json() if not original_json.get("baseThirst") and original_json.get("base_thirst"): original_json["baseThirst"] = original_json["base_thirst"] if not original_json.get("groundFriction") and original_json.get("ground_friction"): original_json["groundFriction"] = original_json["ground_friction"] for override_key, override_value in overrides.items(): original_json[override_key] = override_value for m_key, m_val in multipliers.items(): if m_key in ('batting_rating', 'overall_rating'): original_json['buoyancy'] *= (1.0 - m_val) original_json['tragicness'] *= (1.0 - m_val) original_json['patheticism'] *= (1.0 - m_val) original_json['thwackability'] *= (1.0 + m_val) original_json['divinity'] *= (1.0 + m_val) original_json['moxie'] *= (1.0 + m_val) original_json['musclitude'] *= (1.0 + m_val) original_json['martyrdom'] *= (1.0 + m_val) if m_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] *= (1.0 + m_val) original_json['ruthlessness'] *= (1.0 + m_val) original_json['overpowerment'] *= (1.0 + m_val) original_json['shakespearianism'] *= (1.0 + m_val) original_json['coldness'] *= (1.0 + m_val) original_json['suppression'] *= (1.0 + m_val) if m_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] *= (1.0 + m_val) original_json['continuation'] *= (1.0 + m_val) original_json['baseThirst'] *= (1.0 + m_val) original_json['indulgence'] *= (1.0 + m_val) original_json['groundFriction'] *= (1.0 + m_val) if m_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] *= (1.0 + m_val) original_json['tenaciousness'] *= (1.0 + m_val) original_json['watchfulness'] *= (1.0 + m_val) original_json['anticapitalism'] *= (1.0 + m_val) original_json['chasiness'] *= (1.0 + m_val) if m_key in ('tragicness', 'patheticism'): original_json[m_key] *= (1.0 - m_val) elif m_key in original_json: original_json[m_key] *= (1.0 + m_val) for b_key, b_val in buffs.items(): if b_key in ('batting_rating', 'overall_rating'): original_json['tragicness'] = min(0.99, max(0.01, original_json['tragicness'] - b_val)) original_json['patheticism'] = min(0.99, max(0.01, original_json['patheticism'] - b_val)) original_json['buoyancy'] = max(0.01, original_json['buoyancy'] + b_val) original_json['thwackability'] = max(0.01, original_json['thwackability'] + b_val) original_json['divinity'] = max(0.01, original_json['divinity'] + b_val) original_json['moxie'] = max(0.01, original_json['moxie'] + b_val) original_json['musclitude'] = max(0.01, original_json['musclitude'] + b_val) original_json['martyrdom'] = max(0.01, original_json['martyrdom'] + b_val) if b_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] = max(0.01, original_json['unthwackability'] + b_val) original_json['ruthlessness'] = max(0.01, original_json['ruthlessness'] + b_val) original_json['overpowerment'] = max(0.01, original_json['overpowerment'] + b_val) original_json['shakespearianism'] = max(0.01, original_json['shakespearianism'] + b_val) original_json['coldness'] = max(0.01, original_json['coldness'] + b_val) original_json['suppression'] = max(0.01, original_json['suppression'] + b_val) if b_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] = max(0.01, original_json['laserlikeness'] + b_val) original_json['continuation'] = max(0.01, original_json['continuation'] + b_val) original_json['baseThirst'] = max(0.01, original_json['baseThirst'] + b_val) original_json['indulgence'] = max(0.01, original_json['indulgence'] + b_val) original_json['groundFriction'] = max(0.01, original_json['groundFriction'] + b_val) if b_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] = max(0.01, original_json['omniscience'] + b_val) original_json['tenaciousness'] = max(0.01, original_json['tenaciousness'] + b_val) original_json['watchfulness'] = max(0.01, original_json['watchfulness'] + b_val) original_json['anticapitalism'] = max(0.01, original_json['anticapitalism'] + b_val) original_json['chasiness'] = max(0.01, original_json['chasiness'] + b_val) if b_key in ('tragicness', 'patheticism'): original_json[b_key] = min(0.99, max(0.01, original_json[b_key] - b_val)) elif b_key in original_json: original_json[b_key] = max(0.01, original_json[b_key] + b_val) for r_key, _ in reroll.items(): if r_key in ('batting_rating', 'overall_rating'): original_json['buoyancy'] = random.uniform(0.01, 0.99) original_json['tragicness'] = random.uniform(0.01, 0.99) original_json['patheticism'] = random.uniform(0.01, 0.99) original_json['thwackability'] = random.uniform(0.01, 0.99) original_json['divinity'] = random.uniform(0.01, 0.99) original_json['moxie'] = random.uniform(0.01, 0.99) original_json['musclitude'] = random.uniform(0.01, 0.99) original_json['martyrdom'] = random.uniform(0.01, 0.99) if r_key in ('pitching_rating', 'overall_rating'): original_json['unthwackability'] = random.uniform(0.01, 0.99) original_json['ruthlessness'] = random.uniform(0.01, 0.99) original_json['overpowerment'] = random.uniform(0.01, 0.99) original_json['shakespearianism'] = random.uniform(0.01, 0.99) original_json['coldness'] = random.uniform(0.01, 0.99) original_json['suppression'] = random.uniform(0.01, 0.99) if r_key in ('baserunning_rating', 'overall_rating'): original_json['laserlikeness'] = random.uniform(0.01, 0.99) original_json['continuation'] = random.uniform(0.01, 0.99) original_json['baseThirst'] = random.uniform(0.01, 0.99) original_json['indulgence'] = random.uniform(0.01, 0.99) original_json['groundFriction'] = random.uniform(0.01, 0.99) if r_key in ('defense_rating', 'overall_rating'): original_json['omniscience'] = random.uniform(0.01, 0.99) original_json['tenaciousness'] = random.uniform(0.01, 0.99) original_json['watchfulness'] = random.uniform(0.01, 0.99) original_json['anticapitalism'] = random.uniform(0.01, 0.99) original_json['chasiness'] = random.uniform(0.01, 0.99) if r_key in ('tragicness', 'patheticism'): original_json[r_key] = random.uniform(0.01, 0.99) elif r_key in original_json: original_json[r_key] = random.uniform(0.01, 0.99) # Clear database-provided ratings to force a recalculation original_json['hittingRating'] = None original_json['pitchingRating'] = None original_json['baserunningRating'] = None original_json['defenseRating'] = None return Player(original_json)